1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <linux/export.h>
3 #include <linux/ref_tracker.h>
4 #include <linux/slab.h>
5 #include <linux/stacktrace.h>
6 #include <linux/stackdepot.h>
8 #define REF_TRACKER_STACK_ENTRIES 16
11 struct list_head head
; /* anchor into dir->list or dir->quarantine */
13 depot_stack_handle_t alloc_stack_handle
;
14 depot_stack_handle_t free_stack_handle
;
17 void ref_tracker_dir_exit(struct ref_tracker_dir
*dir
)
19 struct ref_tracker
*tracker
, *n
;
24 spin_lock_irqsave(&dir
->lock
, flags
);
25 list_for_each_entry_safe(tracker
, n
, &dir
->quarantine
, head
) {
26 list_del(&tracker
->head
);
28 dir
->quarantine_avail
++;
30 list_for_each_entry_safe(tracker
, n
, &dir
->list
, head
) {
31 pr_err("leaked reference.\n");
32 if (tracker
->alloc_stack_handle
)
33 stack_depot_print(tracker
->alloc_stack_handle
);
35 list_del(&tracker
->head
);
38 spin_unlock_irqrestore(&dir
->lock
, flags
);
40 WARN_ON_ONCE(refcount_read(&dir
->untracked
) != 1);
41 WARN_ON_ONCE(refcount_read(&dir
->no_tracker
) != 1);
43 EXPORT_SYMBOL(ref_tracker_dir_exit
);
45 void ref_tracker_dir_print(struct ref_tracker_dir
*dir
,
46 unsigned int display_limit
)
48 struct ref_tracker
*tracker
;
52 spin_lock_irqsave(&dir
->lock
, flags
);
53 list_for_each_entry(tracker
, &dir
->list
, head
) {
54 if (i
< display_limit
) {
55 pr_err("leaked reference.\n");
56 if (tracker
->alloc_stack_handle
)
57 stack_depot_print(tracker
->alloc_stack_handle
);
63 spin_unlock_irqrestore(&dir
->lock
, flags
);
65 EXPORT_SYMBOL(ref_tracker_dir_print
);
67 int ref_tracker_alloc(struct ref_tracker_dir
*dir
,
68 struct ref_tracker
**trackerp
,
71 unsigned long entries
[REF_TRACKER_STACK_ENTRIES
];
72 struct ref_tracker
*tracker
;
73 unsigned int nr_entries
;
77 WARN_ON_ONCE(dir
->dead
);
80 refcount_inc(&dir
->no_tracker
);
83 if (gfp
& __GFP_DIRECT_RECLAIM
)
84 gfp_mask
|= __GFP_NOFAIL
;
85 *trackerp
= tracker
= kzalloc(sizeof(*tracker
), gfp_mask
);
86 if (unlikely(!tracker
)) {
87 pr_err_once("memory allocation failure, unreliable refcount tracker.\n");
88 refcount_inc(&dir
->untracked
);
91 nr_entries
= stack_trace_save(entries
, ARRAY_SIZE(entries
), 1);
92 tracker
->alloc_stack_handle
= stack_depot_save(entries
, nr_entries
, gfp
);
94 spin_lock_irqsave(&dir
->lock
, flags
);
95 list_add(&tracker
->head
, &dir
->list
);
96 spin_unlock_irqrestore(&dir
->lock
, flags
);
99 EXPORT_SYMBOL_GPL(ref_tracker_alloc
);
101 int ref_tracker_free(struct ref_tracker_dir
*dir
,
102 struct ref_tracker
**trackerp
)
104 unsigned long entries
[REF_TRACKER_STACK_ENTRIES
];
105 depot_stack_handle_t stack_handle
;
106 struct ref_tracker
*tracker
;
107 unsigned int nr_entries
;
110 WARN_ON_ONCE(dir
->dead
);
113 refcount_dec(&dir
->no_tracker
);
118 refcount_dec(&dir
->untracked
);
121 nr_entries
= stack_trace_save(entries
, ARRAY_SIZE(entries
), 1);
122 stack_handle
= stack_depot_save(entries
, nr_entries
, GFP_ATOMIC
);
124 spin_lock_irqsave(&dir
->lock
, flags
);
126 pr_err("reference already released.\n");
127 if (tracker
->alloc_stack_handle
) {
128 pr_err("allocated in:\n");
129 stack_depot_print(tracker
->alloc_stack_handle
);
131 if (tracker
->free_stack_handle
) {
132 pr_err("freed in:\n");
133 stack_depot_print(tracker
->free_stack_handle
);
135 spin_unlock_irqrestore(&dir
->lock
, flags
);
139 tracker
->dead
= true;
141 tracker
->free_stack_handle
= stack_handle
;
143 list_move_tail(&tracker
->head
, &dir
->quarantine
);
144 if (!dir
->quarantine_avail
) {
145 tracker
= list_first_entry(&dir
->quarantine
, struct ref_tracker
, head
);
146 list_del(&tracker
->head
);
148 dir
->quarantine_avail
--;
151 spin_unlock_irqrestore(&dir
->lock
, flags
);
156 EXPORT_SYMBOL_GPL(ref_tracker_free
);