@@ -132,14 +132,18 @@ static void fill_pool(void)
132
132
struct debug_obj * obj ;
133
133
unsigned long flags ;
134
134
135
- if (likely (obj_pool_free >= debug_objects_pool_min_level ))
135
+ if (likely (READ_ONCE ( obj_pool_free ) >= debug_objects_pool_min_level ))
136
136
return ;
137
137
138
138
/*
139
139
* Reuse objs from the global free list; they will be reinitialized
140
140
* 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.
141
145
*/
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 )) {
143
147
raw_spin_lock_irqsave (& pool_lock , flags );
144
148
/*
145
149
* Recheck with the lock held as the worker thread might have
@@ -148,17 +152,17 @@ static void fill_pool(void)
148
152
while (obj_nr_tofree && (obj_pool_free < obj_pool_min_free )) {
149
153
obj = hlist_entry (obj_to_free .first , typeof (* obj ), node );
150
154
hlist_del (& obj -> node );
151
- obj_nr_tofree -- ;
155
+ WRITE_ONCE ( obj_nr_tofree , obj_nr_tofree - 1 ) ;
152
156
hlist_add_head (& obj -> node , & obj_pool );
153
- obj_pool_free ++ ;
157
+ WRITE_ONCE ( obj_pool_free , obj_pool_free + 1 ) ;
154
158
}
155
159
raw_spin_unlock_irqrestore (& pool_lock , flags );
156
160
}
157
161
158
162
if (unlikely (!obj_cache ))
159
163
return ;
160
164
161
- while (obj_pool_free < debug_objects_pool_min_level ) {
165
+ while (READ_ONCE ( obj_pool_free ) < debug_objects_pool_min_level ) {
162
166
struct debug_obj * new [ODEBUG_BATCH_SIZE ];
163
167
int cnt ;
164
168
@@ -174,7 +178,7 @@ static void fill_pool(void)
174
178
while (cnt ) {
175
179
hlist_add_head (& new [-- cnt ]-> node , & obj_pool );
176
180
debug_objects_allocated ++ ;
177
- obj_pool_free ++ ;
181
+ WRITE_ONCE ( obj_pool_free , obj_pool_free + 1 ) ;
178
182
}
179
183
raw_spin_unlock_irqrestore (& pool_lock , flags );
180
184
}
@@ -236,7 +240,7 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
236
240
obj = __alloc_object (& obj_pool );
237
241
if (obj ) {
238
242
obj_pool_used ++ ;
239
- obj_pool_free -- ;
243
+ WRITE_ONCE ( obj_pool_free , obj_pool_free - 1 ) ;
240
244
241
245
/*
242
246
* 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)
255
259
& percpu_pool -> free_objs );
256
260
percpu_pool -> obj_free ++ ;
257
261
obj_pool_used ++ ;
258
- obj_pool_free -- ;
262
+ WRITE_ONCE ( obj_pool_free , obj_pool_free - 1 ) ;
259
263
}
260
264
}
261
265
@@ -309,8 +313,8 @@ static void free_obj_work(struct work_struct *work)
309
313
obj = hlist_entry (obj_to_free .first , typeof (* obj ), node );
310
314
hlist_del (& obj -> node );
311
315
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 ) ;
314
318
}
315
319
raw_spin_unlock_irqrestore (& pool_lock , flags );
316
320
return ;
@@ -324,7 +328,7 @@ static void free_obj_work(struct work_struct *work)
324
328
if (obj_nr_tofree ) {
325
329
hlist_move_list (& obj_to_free , & tofree );
326
330
debug_objects_freed += obj_nr_tofree ;
327
- obj_nr_tofree = 0 ;
331
+ WRITE_ONCE ( obj_nr_tofree , 0 ) ;
328
332
}
329
333
raw_spin_unlock_irqrestore (& pool_lock , flags );
330
334
@@ -375,10 +379,10 @@ static void __free_object(struct debug_obj *obj)
375
379
obj_pool_used -- ;
376
380
377
381
if (work ) {
378
- obj_nr_tofree ++ ;
382
+ WRITE_ONCE ( obj_nr_tofree , obj_nr_tofree + 1 ) ;
379
383
hlist_add_head (& obj -> node , & obj_to_free );
380
384
if (lookahead_count ) {
381
- obj_nr_tofree += lookahead_count ;
385
+ WRITE_ONCE ( obj_nr_tofree , obj_nr_tofree + lookahead_count ) ;
382
386
obj_pool_used -= lookahead_count ;
383
387
while (lookahead_count ) {
384
388
hlist_add_head (& objs [-- lookahead_count ]-> node ,
@@ -396,15 +400,15 @@ static void __free_object(struct debug_obj *obj)
396
400
for (i = 0 ; i < ODEBUG_BATCH_SIZE ; i ++ ) {
397
401
obj = __alloc_object (& obj_pool );
398
402
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 ) ;
401
405
}
402
406
}
403
407
} else {
404
- obj_pool_free ++ ;
408
+ WRITE_ONCE ( obj_pool_free , obj_pool_free + 1 ) ;
405
409
hlist_add_head (& obj -> node , & obj_pool );
406
410
if (lookahead_count ) {
407
- obj_pool_free += lookahead_count ;
411
+ WRITE_ONCE ( obj_pool_free , obj_pool_free + lookahead_count ) ;
408
412
obj_pool_used -= lookahead_count ;
409
413
while (lookahead_count ) {
410
414
hlist_add_head (& objs [-- lookahead_count ]-> node ,
@@ -423,7 +427,7 @@ static void __free_object(struct debug_obj *obj)
423
427
static void free_object (struct debug_obj * obj )
424
428
{
425
429
__free_object (obj );
426
- if (!obj_freeing && obj_nr_tofree ) {
430
+ if (!READ_ONCE ( obj_freeing ) && READ_ONCE ( obj_nr_tofree ) ) {
427
431
WRITE_ONCE (obj_freeing , true);
428
432
schedule_delayed_work (& debug_obj_work , ODEBUG_FREE_WORK_DELAY );
429
433
}
@@ -982,7 +986,7 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
982
986
debug_objects_maxchecked = objs_checked ;
983
987
984
988
/* 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 ) ) {
986
990
WRITE_ONCE (obj_freeing , true);
987
991
schedule_delayed_work (& debug_obj_work , ODEBUG_FREE_WORK_DELAY );
988
992
}
@@ -1008,12 +1012,12 @@ static int debug_stats_show(struct seq_file *m, void *v)
1008
1012
seq_printf (m , "max_checked :%d\n" , debug_objects_maxchecked );
1009
1013
seq_printf (m , "warnings :%d\n" , debug_objects_warnings );
1010
1014
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 );
1012
1016
seq_printf (m , "pool_pcp_free :%d\n" , obj_percpu_free );
1013
1017
seq_printf (m , "pool_min_free :%d\n" , obj_pool_min_free );
1014
1018
seq_printf (m , "pool_used :%d\n" , obj_pool_used - obj_percpu_free );
1015
1019
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 ) );
1017
1021
seq_printf (m , "objs_allocated:%d\n" , debug_objects_allocated );
1018
1022
seq_printf (m , "objs_freed :%d\n" , debug_objects_freed );
1019
1023
return 0 ;
0 commit comments