mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
b6d7c0eb2d
In case the library is tracking busy subsystem, simply printing stack for every active reference will spam log with long, hard to read, redundant stack traces. To improve readabilty following changes have been made: - reports are printed per stack_handle - log is more compact, - added display name for ref_tracker_dir - it will differentiate multiple subsystems, - stack trace is printed indented, in the same printk call, - info about dropped references is printed as well. Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com> Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
115 lines
3.1 KiB
C
115 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Referrence tracker self test.
|
|
*
|
|
* Copyright (c) 2021 Eric Dumazet <edumazet@google.com>
|
|
*/
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/ref_tracker.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/timer.h>
|
|
|
|
static struct ref_tracker_dir ref_dir;
|
|
static struct ref_tracker *tracker[20];
|
|
|
|
#define TRT_ALLOC(X) static noinline void \
|
|
alloctest_ref_tracker_alloc##X(struct ref_tracker_dir *dir, \
|
|
struct ref_tracker **trackerp) \
|
|
{ \
|
|
ref_tracker_alloc(dir, trackerp, GFP_KERNEL); \
|
|
}
|
|
|
|
TRT_ALLOC(1)
|
|
TRT_ALLOC(2)
|
|
TRT_ALLOC(3)
|
|
TRT_ALLOC(4)
|
|
TRT_ALLOC(5)
|
|
TRT_ALLOC(6)
|
|
TRT_ALLOC(7)
|
|
TRT_ALLOC(8)
|
|
TRT_ALLOC(9)
|
|
TRT_ALLOC(10)
|
|
TRT_ALLOC(11)
|
|
TRT_ALLOC(12)
|
|
TRT_ALLOC(13)
|
|
TRT_ALLOC(14)
|
|
TRT_ALLOC(15)
|
|
TRT_ALLOC(16)
|
|
TRT_ALLOC(17)
|
|
TRT_ALLOC(18)
|
|
TRT_ALLOC(19)
|
|
|
|
#undef TRT_ALLOC
|
|
|
|
static noinline void
|
|
alloctest_ref_tracker_free(struct ref_tracker_dir *dir,
|
|
struct ref_tracker **trackerp)
|
|
{
|
|
ref_tracker_free(dir, trackerp);
|
|
}
|
|
|
|
|
|
static struct timer_list test_ref_tracker_timer;
|
|
static atomic_t test_ref_timer_done = ATOMIC_INIT(0);
|
|
|
|
static void test_ref_tracker_timer_func(struct timer_list *t)
|
|
{
|
|
ref_tracker_alloc(&ref_dir, &tracker[0], GFP_ATOMIC);
|
|
atomic_set(&test_ref_timer_done, 1);
|
|
}
|
|
|
|
static int __init test_ref_tracker_init(void)
|
|
{
|
|
int i;
|
|
|
|
ref_tracker_dir_init(&ref_dir, 100, "selftest");
|
|
|
|
timer_setup(&test_ref_tracker_timer, test_ref_tracker_timer_func, 0);
|
|
mod_timer(&test_ref_tracker_timer, jiffies + 1);
|
|
|
|
alloctest_ref_tracker_alloc1(&ref_dir, &tracker[1]);
|
|
alloctest_ref_tracker_alloc2(&ref_dir, &tracker[2]);
|
|
alloctest_ref_tracker_alloc3(&ref_dir, &tracker[3]);
|
|
alloctest_ref_tracker_alloc4(&ref_dir, &tracker[4]);
|
|
alloctest_ref_tracker_alloc5(&ref_dir, &tracker[5]);
|
|
alloctest_ref_tracker_alloc6(&ref_dir, &tracker[6]);
|
|
alloctest_ref_tracker_alloc7(&ref_dir, &tracker[7]);
|
|
alloctest_ref_tracker_alloc8(&ref_dir, &tracker[8]);
|
|
alloctest_ref_tracker_alloc9(&ref_dir, &tracker[9]);
|
|
alloctest_ref_tracker_alloc10(&ref_dir, &tracker[10]);
|
|
alloctest_ref_tracker_alloc11(&ref_dir, &tracker[11]);
|
|
alloctest_ref_tracker_alloc12(&ref_dir, &tracker[12]);
|
|
alloctest_ref_tracker_alloc13(&ref_dir, &tracker[13]);
|
|
alloctest_ref_tracker_alloc14(&ref_dir, &tracker[14]);
|
|
alloctest_ref_tracker_alloc15(&ref_dir, &tracker[15]);
|
|
alloctest_ref_tracker_alloc16(&ref_dir, &tracker[16]);
|
|
alloctest_ref_tracker_alloc17(&ref_dir, &tracker[17]);
|
|
alloctest_ref_tracker_alloc18(&ref_dir, &tracker[18]);
|
|
alloctest_ref_tracker_alloc19(&ref_dir, &tracker[19]);
|
|
|
|
/* free all trackers but first 0 and 1. */
|
|
for (i = 2; i < ARRAY_SIZE(tracker); i++)
|
|
alloctest_ref_tracker_free(&ref_dir, &tracker[i]);
|
|
|
|
/* Attempt to free an already freed tracker. */
|
|
alloctest_ref_tracker_free(&ref_dir, &tracker[2]);
|
|
|
|
while (!atomic_read(&test_ref_timer_done))
|
|
msleep(1);
|
|
|
|
/* This should warn about tracker[0] & tracker[1] being not freed. */
|
|
ref_tracker_dir_exit(&ref_dir);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit test_ref_tracker_exit(void)
|
|
{
|
|
}
|
|
|
|
module_init(test_ref_tracker_init);
|
|
module_exit(test_ref_tracker_exit);
|
|
|
|
MODULE_LICENSE("GPL v2");
|