Skip to content

Commit 534b0a8

Browse files
committed
Merge tag 'core-debugobjects-2020-01-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull debugobjects update from Thomas Gleixner: "A single commit for debug objects which fixes a pile of potential data races detected by KCSAN" * tag 'core-debugobjects-2020-01-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: debugobjects: Fix various data races
2 parents b11c89a + 35fd7a6 commit 534b0a8

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

lib/debugobjects.c

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,18 @@ static void fill_pool(void)
132132
struct debug_obj *obj;
133133
unsigned long flags;
134134

135-
if (likely(obj_pool_free >= debug_objects_pool_min_level))
135+
if (likely(READ_ONCE(obj_pool_free) >= debug_objects_pool_min_level))
136136
return;
137137

138138
/*
139139
* Reuse objs from the global free list; they will be reinitialized
140140
* when allocating.
141+
*
142+
* Both obj_nr_tofree and obj_pool_free are checked locklessly; the
143+
* READ_ONCE()s pair with the WRITE_ONCE()s in pool_lock critical
144+
* sections.
141145
*/
142-
while (obj_nr_tofree && (obj_pool_free < obj_pool_min_free)) {
146+
while (READ_ONCE(obj_nr_tofree) && (READ_ONCE(obj_pool_free) < obj_pool_min_free)) {
143147
raw_spin_lock_irqsave(&pool_lock, flags);
144148
/*
145149
* Recheck with the lock held as the worker thread might have
@@ -148,17 +152,17 @@ static void fill_pool(void)
148152
while (obj_nr_tofree && (obj_pool_free < obj_pool_min_free)) {
149153
obj = hlist_entry(obj_to_free.first, typeof(*obj), node);
150154
hlist_del(&obj->node);
151-
obj_nr_tofree--;
155+
WRITE_ONCE(obj_nr_tofree, obj_nr_tofree - 1);
152156
hlist_add_head(&obj->node, &obj_pool);
153-
obj_pool_free++;
157+
WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
154158
}
155159
raw_spin_unlock_irqrestore(&pool_lock, flags);
156160
}
157161

158162
if (unlikely(!obj_cache))
159163
return;
160164

161-
while (obj_pool_free < debug_objects_pool_min_level) {
165+
while (READ_ONCE(obj_pool_free) < debug_objects_pool_min_level) {
162166
struct debug_obj *new[ODEBUG_BATCH_SIZE];
163167
int cnt;
164168

@@ -174,7 +178,7 @@ static void fill_pool(void)
174178
while (cnt) {
175179
hlist_add_head(&new[--cnt]->node, &obj_pool);
176180
debug_objects_allocated++;
177-
obj_pool_free++;
181+
WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
178182
}
179183
raw_spin_unlock_irqrestore(&pool_lock, flags);
180184
}
@@ -236,7 +240,7 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
236240
obj = __alloc_object(&obj_pool);
237241
if (obj) {
238242
obj_pool_used++;
239-
obj_pool_free--;
243+
WRITE_ONCE(obj_pool_free, obj_pool_free - 1);
240244

241245
/*
242246
* Looking ahead, allocate one batch of debug objects and
@@ -255,7 +259,7 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
255259
&percpu_pool->free_objs);
256260
percpu_pool->obj_free++;
257261
obj_pool_used++;
258-
obj_pool_free--;
262+
WRITE_ONCE(obj_pool_free, obj_pool_free - 1);
259263
}
260264
}
261265

@@ -309,8 +313,8 @@ static void free_obj_work(struct work_struct *work)
309313
obj = hlist_entry(obj_to_free.first, typeof(*obj), node);
310314
hlist_del(&obj->node);
311315
hlist_add_head(&obj->node, &obj_pool);
312-
obj_pool_free++;
313-
obj_nr_tofree--;
316+
WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
317+
WRITE_ONCE(obj_nr_tofree, obj_nr_tofree - 1);
314318
}
315319
raw_spin_unlock_irqrestore(&pool_lock, flags);
316320
return;
@@ -324,7 +328,7 @@ static void free_obj_work(struct work_struct *work)
324328
if (obj_nr_tofree) {
325329
hlist_move_list(&obj_to_free, &tofree);
326330
debug_objects_freed += obj_nr_tofree;
327-
obj_nr_tofree = 0;
331+
WRITE_ONCE(obj_nr_tofree, 0);
328332
}
329333
raw_spin_unlock_irqrestore(&pool_lock, flags);
330334

@@ -375,10 +379,10 @@ static void __free_object(struct debug_obj *obj)
375379
obj_pool_used--;
376380

377381
if (work) {
378-
obj_nr_tofree++;
382+
WRITE_ONCE(obj_nr_tofree, obj_nr_tofree + 1);
379383
hlist_add_head(&obj->node, &obj_to_free);
380384
if (lookahead_count) {
381-
obj_nr_tofree += lookahead_count;
385+
WRITE_ONCE(obj_nr_tofree, obj_nr_tofree + lookahead_count);
382386
obj_pool_used -= lookahead_count;
383387
while (lookahead_count) {
384388
hlist_add_head(&objs[--lookahead_count]->node,
@@ -396,15 +400,15 @@ static void __free_object(struct debug_obj *obj)
396400
for (i = 0; i < ODEBUG_BATCH_SIZE; i++) {
397401
obj = __alloc_object(&obj_pool);
398402
hlist_add_head(&obj->node, &obj_to_free);
399-
obj_pool_free--;
400-
obj_nr_tofree++;
403+
WRITE_ONCE(obj_pool_free, obj_pool_free - 1);
404+
WRITE_ONCE(obj_nr_tofree, obj_nr_tofree + 1);
401405
}
402406
}
403407
} else {
404-
obj_pool_free++;
408+
WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
405409
hlist_add_head(&obj->node, &obj_pool);
406410
if (lookahead_count) {
407-
obj_pool_free += lookahead_count;
411+
WRITE_ONCE(obj_pool_free, obj_pool_free + lookahead_count);
408412
obj_pool_used -= lookahead_count;
409413
while (lookahead_count) {
410414
hlist_add_head(&objs[--lookahead_count]->node,
@@ -423,7 +427,7 @@ static void __free_object(struct debug_obj *obj)
423427
static void free_object(struct debug_obj *obj)
424428
{
425429
__free_object(obj);
426-
if (!obj_freeing && obj_nr_tofree) {
430+
if (!READ_ONCE(obj_freeing) && READ_ONCE(obj_nr_tofree)) {
427431
WRITE_ONCE(obj_freeing, true);
428432
schedule_delayed_work(&debug_obj_work, ODEBUG_FREE_WORK_DELAY);
429433
}
@@ -982,7 +986,7 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
982986
debug_objects_maxchecked = objs_checked;
983987

984988
/* Schedule work to actually kmem_cache_free() objects */
985-
if (!obj_freeing && obj_nr_tofree) {
989+
if (!READ_ONCE(obj_freeing) && READ_ONCE(obj_nr_tofree)) {
986990
WRITE_ONCE(obj_freeing, true);
987991
schedule_delayed_work(&debug_obj_work, ODEBUG_FREE_WORK_DELAY);
988992
}
@@ -1008,12 +1012,12 @@ static int debug_stats_show(struct seq_file *m, void *v)
10081012
seq_printf(m, "max_checked :%d\n", debug_objects_maxchecked);
10091013
seq_printf(m, "warnings :%d\n", debug_objects_warnings);
10101014
seq_printf(m, "fixups :%d\n", debug_objects_fixups);
1011-
seq_printf(m, "pool_free :%d\n", obj_pool_free + obj_percpu_free);
1015+
seq_printf(m, "pool_free :%d\n", READ_ONCE(obj_pool_free) + obj_percpu_free);
10121016
seq_printf(m, "pool_pcp_free :%d\n", obj_percpu_free);
10131017
seq_printf(m, "pool_min_free :%d\n", obj_pool_min_free);
10141018
seq_printf(m, "pool_used :%d\n", obj_pool_used - obj_percpu_free);
10151019
seq_printf(m, "pool_max_used :%d\n", obj_pool_max_used);
1016-
seq_printf(m, "on_free_list :%d\n", obj_nr_tofree);
1020+
seq_printf(m, "on_free_list :%d\n", READ_ONCE(obj_nr_tofree));
10171021
seq_printf(m, "objs_allocated:%d\n", debug_objects_allocated);
10181022
seq_printf(m, "objs_freed :%d\n", debug_objects_freed);
10191023
return 0;

0 commit comments

Comments
 (0)