@@ -52,6 +52,11 @@ struct debug_percpu_free {
52
52
int obj_free ;
53
53
};
54
54
55
+ struct obj_pool {
56
+ struct hlist_head objects ;
57
+ unsigned int cnt ;
58
+ } ____cacheline_aligned ;
59
+
55
60
static DEFINE_PER_CPU (struct debug_percpu_free , percpu_obj_pool ) ;
56
61
57
62
static struct debug_bucket obj_hash [ODEBUG_HASH_SIZE ];
@@ -60,8 +65,8 @@ static struct debug_obj obj_static_pool[ODEBUG_POOL_SIZE] __initdata;
60
65
61
66
static DEFINE_RAW_SPINLOCK (pool_lock );
62
67
63
- static HLIST_HEAD ( obj_pool ) ;
64
- static HLIST_HEAD ( obj_to_free ) ;
68
+ static struct obj_pool pool_global ;
69
+ static struct obj_pool pool_to_free ;
65
70
66
71
/*
67
72
* Because of the presence of percpu free pools, obj_pool_free will
@@ -71,12 +76,9 @@ static HLIST_HEAD(obj_to_free);
71
76
* can be off.
72
77
*/
73
78
static int __data_racy obj_pool_min_free = ODEBUG_POOL_SIZE ;
74
- static int __data_racy obj_pool_free = ODEBUG_POOL_SIZE ;
75
79
static int obj_pool_used ;
76
80
static int __data_racy obj_pool_max_used ;
77
81
static bool obj_freeing ;
78
- /* The number of objs on the global free list */
79
- static int obj_nr_tofree ;
80
82
81
83
static int __data_racy debug_objects_maxchain __read_mostly ;
82
84
static int __data_racy __maybe_unused debug_objects_maxchecked __read_mostly ;
@@ -124,6 +126,21 @@ static const char *obj_states[ODEBUG_STATE_MAX] = {
124
126
[ODEBUG_STATE_NOTAVAILABLE ] = "not available" ,
125
127
};
126
128
129
+ static __always_inline unsigned int pool_count (struct obj_pool * pool )
130
+ {
131
+ return READ_ONCE (pool -> cnt );
132
+ }
133
+
134
+ static inline bool pool_global_should_refill (void )
135
+ {
136
+ return READ_ONCE (pool_global .cnt ) < debug_objects_pool_min_level ;
137
+ }
138
+
139
+ static inline bool pool_global_must_refill (void )
140
+ {
141
+ return READ_ONCE (pool_global .cnt ) < (debug_objects_pool_min_level / 2 );
142
+ }
143
+
127
144
static void free_object_list (struct hlist_head * head )
128
145
{
129
146
struct hlist_node * tmp ;
@@ -146,11 +163,8 @@ static void fill_pool_from_freelist(void)
146
163
/*
147
164
* Reuse objs from the global obj_to_free list; they will be
148
165
* reinitialized when allocating.
149
- *
150
- * obj_nr_tofree is checked locklessly; the READ_ONCE() pairs with
151
- * the WRITE_ONCE() in pool_lock critical sections.
152
166
*/
153
- if (!READ_ONCE ( obj_nr_tofree ))
167
+ if (!pool_count ( & pool_to_free ))
154
168
return ;
155
169
156
170
/*
@@ -171,12 +185,12 @@ static void fill_pool_from_freelist(void)
171
185
* Recheck with the lock held as the worker thread might have
172
186
* won the race and freed the global free list already.
173
187
*/
174
- while (obj_nr_tofree && (obj_pool_free < debug_objects_pool_min_level )) {
175
- obj = hlist_entry (obj_to_free .first , typeof (* obj ), node );
188
+ while (pool_to_free . cnt && (pool_global . cnt < debug_objects_pool_min_level )) {
189
+ obj = hlist_entry (pool_to_free . objects .first , typeof (* obj ), node );
176
190
hlist_del (& obj -> node );
177
- WRITE_ONCE (obj_nr_tofree , obj_nr_tofree - 1 );
178
- hlist_add_head (& obj -> node , & obj_pool );
179
- WRITE_ONCE (obj_pool_free , obj_pool_free + 1 );
191
+ WRITE_ONCE (pool_to_free . cnt , pool_to_free . cnt - 1 );
192
+ hlist_add_head (& obj -> node , & pool_global . objects );
193
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt + 1 );
180
194
}
181
195
clear_bit (0 , & state );
182
196
}
@@ -190,12 +204,11 @@ static void fill_pool(void)
190
204
* - One other CPU is already allocating
191
205
* - the global pool has not reached the critical level yet
192
206
*/
193
- if (READ_ONCE (obj_pool_free ) > (debug_objects_pool_min_level / 2 ) &&
194
- atomic_read (& cpus_allocating ))
207
+ if (!pool_global_must_refill () && atomic_read (& cpus_allocating ))
195
208
return ;
196
209
197
210
atomic_inc (& cpus_allocating );
198
- while (READ_ONCE ( obj_pool_free ) < debug_objects_pool_min_level ) {
211
+ while (pool_global_should_refill () ) {
199
212
struct debug_obj * new , * last = NULL ;
200
213
HLIST_HEAD (head );
201
214
int cnt ;
@@ -212,9 +225,9 @@ static void fill_pool(void)
212
225
break ;
213
226
214
227
guard (raw_spinlock_irqsave )(& pool_lock );
215
- hlist_splice_init (& head , & last -> node , & obj_pool );
228
+ hlist_splice_init (& head , & last -> node , & pool_global . objects );
216
229
debug_objects_allocated += cnt ;
217
- WRITE_ONCE (obj_pool_free , obj_pool_free + cnt );
230
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt + cnt );
218
231
}
219
232
atomic_dec (& cpus_allocating );
220
233
}
@@ -268,10 +281,10 @@ alloc_object(void *addr, struct debug_bucket *b, const struct debug_obj_descr *d
268
281
}
269
282
270
283
raw_spin_lock (& pool_lock );
271
- obj = __alloc_object (& obj_pool );
284
+ obj = __alloc_object (& pool_global . objects );
272
285
if (obj ) {
273
286
obj_pool_used ++ ;
274
- WRITE_ONCE (obj_pool_free , obj_pool_free - 1 );
287
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt - 1 );
275
288
276
289
/*
277
290
* Looking ahead, allocate one batch of debug objects and
@@ -283,22 +296,21 @@ alloc_object(void *addr, struct debug_bucket *b, const struct debug_obj_descr *d
283
296
for (i = 0 ; i < ODEBUG_BATCH_SIZE ; i ++ ) {
284
297
struct debug_obj * obj2 ;
285
298
286
- obj2 = __alloc_object (& obj_pool );
299
+ obj2 = __alloc_object (& pool_global . objects );
287
300
if (!obj2 )
288
301
break ;
289
- hlist_add_head (& obj2 -> node ,
290
- & percpu_pool -> free_objs );
302
+ hlist_add_head (& obj2 -> node , & percpu_pool -> free_objs );
291
303
percpu_pool -> obj_free ++ ;
292
304
obj_pool_used ++ ;
293
- WRITE_ONCE (obj_pool_free , obj_pool_free - 1 );
305
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt - 1 );
294
306
}
295
307
}
296
308
297
309
if (obj_pool_used > obj_pool_max_used )
298
310
obj_pool_max_used = obj_pool_used ;
299
311
300
- if (obj_pool_free < obj_pool_min_free )
301
- obj_pool_min_free = obj_pool_free ;
312
+ if (pool_global . cnt < obj_pool_min_free )
313
+ obj_pool_min_free = pool_global . cnt ;
302
314
}
303
315
raw_spin_unlock (& pool_lock );
304
316
@@ -329,7 +341,7 @@ static void free_obj_work(struct work_struct *work)
329
341
if (!raw_spin_trylock_irqsave (& pool_lock , flags ))
330
342
return ;
331
343
332
- if (obj_pool_free >= debug_objects_pool_size )
344
+ if (pool_global . cnt >= debug_objects_pool_size )
333
345
goto free_objs ;
334
346
335
347
/*
@@ -339,12 +351,12 @@ static void free_obj_work(struct work_struct *work)
339
351
* may be gearing up to use more and more objects, don't free any
340
352
* of them until the next round.
341
353
*/
342
- while (obj_nr_tofree && obj_pool_free < debug_objects_pool_size ) {
343
- obj = hlist_entry (obj_to_free .first , typeof (* obj ), node );
354
+ while (pool_to_free . cnt && pool_global . cnt < debug_objects_pool_size ) {
355
+ obj = hlist_entry (pool_to_free . objects .first , typeof (* obj ), node );
344
356
hlist_del (& obj -> node );
345
- hlist_add_head (& obj -> node , & obj_pool );
346
- WRITE_ONCE (obj_pool_free , obj_pool_free + 1 );
347
- WRITE_ONCE (obj_nr_tofree , obj_nr_tofree - 1 );
357
+ hlist_add_head (& obj -> node , & pool_global . objects );
358
+ WRITE_ONCE (pool_to_free . cnt , pool_to_free . cnt - 1 );
359
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt + 1 );
348
360
}
349
361
raw_spin_unlock_irqrestore (& pool_lock , flags );
350
362
return ;
@@ -355,9 +367,9 @@ static void free_obj_work(struct work_struct *work)
355
367
* list. Move remaining free objs to a temporary list to free the
356
368
* memory outside the pool_lock held region.
357
369
*/
358
- if (obj_nr_tofree ) {
359
- hlist_move_list (& obj_to_free , & tofree );
360
- WRITE_ONCE (obj_nr_tofree , 0 );
370
+ if (pool_to_free . cnt ) {
371
+ hlist_move_list (& pool_to_free . objects , & tofree );
372
+ WRITE_ONCE (pool_to_free . cnt , 0 );
361
373
}
362
374
raw_spin_unlock_irqrestore (& pool_lock , flags );
363
375
@@ -400,45 +412,45 @@ static void __free_object(struct debug_obj *obj)
400
412
401
413
free_to_obj_pool :
402
414
raw_spin_lock (& pool_lock );
403
- work = (obj_pool_free > debug_objects_pool_size ) && obj_cache &&
404
- (obj_nr_tofree < ODEBUG_FREE_WORK_MAX );
415
+ work = (pool_global . cnt > debug_objects_pool_size ) && obj_cache &&
416
+ (pool_to_free . cnt < ODEBUG_FREE_WORK_MAX );
405
417
obj_pool_used -- ;
406
418
407
419
if (work ) {
408
- WRITE_ONCE (obj_nr_tofree , obj_nr_tofree + 1 );
409
- hlist_add_head (& obj -> node , & obj_to_free );
420
+ WRITE_ONCE (pool_to_free . cnt , pool_to_free . cnt + 1 );
421
+ hlist_add_head (& obj -> node , & pool_to_free . objects );
410
422
if (lookahead_count ) {
411
- WRITE_ONCE (obj_nr_tofree , obj_nr_tofree + lookahead_count );
423
+ WRITE_ONCE (pool_to_free . cnt , pool_to_free . cnt + lookahead_count );
412
424
obj_pool_used -= lookahead_count ;
413
425
while (lookahead_count ) {
414
426
hlist_add_head (& objs [-- lookahead_count ]-> node ,
415
- & obj_to_free );
427
+ & pool_to_free . objects );
416
428
}
417
429
}
418
430
419
- if ((obj_pool_free > debug_objects_pool_size ) &&
420
- (obj_nr_tofree < ODEBUG_FREE_WORK_MAX )) {
431
+ if ((pool_global . cnt > debug_objects_pool_size ) &&
432
+ (pool_to_free . cnt < ODEBUG_FREE_WORK_MAX )) {
421
433
int i ;
422
434
423
435
/*
424
436
* Free one more batch of objects from obj_pool.
425
437
*/
426
438
for (i = 0 ; i < ODEBUG_BATCH_SIZE ; i ++ ) {
427
- obj = __alloc_object (& obj_pool );
428
- hlist_add_head (& obj -> node , & obj_to_free );
429
- WRITE_ONCE (obj_pool_free , obj_pool_free - 1 );
430
- WRITE_ONCE (obj_nr_tofree , obj_nr_tofree + 1 );
439
+ obj = __alloc_object (& pool_global . objects );
440
+ hlist_add_head (& obj -> node , & pool_to_free . objects );
441
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt - 1 );
442
+ WRITE_ONCE (pool_to_free . cnt , pool_to_free . cnt + 1 );
431
443
}
432
444
}
433
445
} else {
434
- WRITE_ONCE (obj_pool_free , obj_pool_free + 1 );
435
- hlist_add_head (& obj -> node , & obj_pool );
446
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt + 1 );
447
+ hlist_add_head (& obj -> node , & pool_global . objects );
436
448
if (lookahead_count ) {
437
- WRITE_ONCE (obj_pool_free , obj_pool_free + lookahead_count );
449
+ WRITE_ONCE (pool_global . cnt , pool_global . cnt + lookahead_count );
438
450
obj_pool_used -= lookahead_count ;
439
451
while (lookahead_count ) {
440
452
hlist_add_head (& objs [-- lookahead_count ]-> node ,
441
- & obj_pool );
453
+ & pool_global . objects );
442
454
}
443
455
}
444
456
}
@@ -453,7 +465,7 @@ static void __free_object(struct debug_obj *obj)
453
465
static void free_object (struct debug_obj * obj )
454
466
{
455
467
__free_object (obj );
456
- if (!READ_ONCE (obj_freeing ) && READ_ONCE ( obj_nr_tofree )) {
468
+ if (!READ_ONCE (obj_freeing ) && pool_count ( & pool_to_free )) {
457
469
WRITE_ONCE (obj_freeing , true);
458
470
schedule_delayed_work (& debug_obj_work , ODEBUG_FREE_WORK_DELAY );
459
471
}
@@ -622,13 +634,13 @@ static void debug_objects_fill_pool(void)
622
634
if (unlikely (!obj_cache ))
623
635
return ;
624
636
625
- if (likely (READ_ONCE ( obj_pool_free ) >= debug_objects_pool_min_level ))
637
+ if (likely (! pool_global_should_refill () ))
626
638
return ;
627
639
628
640
/* Try reusing objects from obj_to_free_list */
629
641
fill_pool_from_freelist ();
630
642
631
- if (likely (READ_ONCE ( obj_pool_free ) >= debug_objects_pool_min_level ))
643
+ if (likely (! pool_global_should_refill () ))
632
644
return ;
633
645
634
646
/*
@@ -1040,7 +1052,7 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
1040
1052
debug_objects_maxchecked = objs_checked ;
1041
1053
1042
1054
/* Schedule work to actually kmem_cache_free() objects */
1043
- if (!READ_ONCE (obj_freeing ) && READ_ONCE ( obj_nr_tofree )) {
1055
+ if (!READ_ONCE (obj_freeing ) && pool_count ( & pool_to_free )) {
1044
1056
WRITE_ONCE (obj_freeing , true);
1045
1057
schedule_delayed_work (& debug_obj_work , ODEBUG_FREE_WORK_DELAY );
1046
1058
}
@@ -1066,12 +1078,12 @@ static int debug_stats_show(struct seq_file *m, void *v)
1066
1078
seq_printf (m , "max_checked :%d\n" , debug_objects_maxchecked );
1067
1079
seq_printf (m , "warnings :%d\n" , debug_objects_warnings );
1068
1080
seq_printf (m , "fixups :%d\n" , debug_objects_fixups );
1069
- seq_printf (m , "pool_free :%d\n" , READ_ONCE ( obj_pool_free ) + obj_percpu_free );
1081
+ seq_printf (m , "pool_free :%d\n" , pool_count ( & pool_global ) + obj_percpu_free );
1070
1082
seq_printf (m , "pool_pcp_free :%d\n" , obj_percpu_free );
1071
1083
seq_printf (m , "pool_min_free :%d\n" , obj_pool_min_free );
1072
1084
seq_printf (m , "pool_used :%d\n" , obj_pool_used - obj_percpu_free );
1073
1085
seq_printf (m , "pool_max_used :%d\n" , obj_pool_max_used );
1074
- seq_printf (m , "on_free_list :%d\n" , READ_ONCE ( obj_nr_tofree ));
1086
+ seq_printf (m , "on_free_list :%d\n" , pool_count ( & pool_to_free ));
1075
1087
seq_printf (m , "objs_allocated:%d\n" , debug_objects_allocated );
1076
1088
seq_printf (m , "objs_freed :%d\n" , debug_objects_freed );
1077
1089
return 0 ;
@@ -1330,7 +1342,9 @@ void __init debug_objects_early_init(void)
1330
1342
raw_spin_lock_init (& obj_hash [i ].lock );
1331
1343
1332
1344
for (i = 0 ; i < ODEBUG_POOL_SIZE ; i ++ )
1333
- hlist_add_head (& obj_static_pool [i ].node , & obj_pool );
1345
+ hlist_add_head (& obj_static_pool [i ].node , & pool_global .objects );
1346
+
1347
+ pool_global .cnt = ODEBUG_POOL_SIZE ;
1334
1348
}
1335
1349
1336
1350
/*
@@ -1354,21 +1368,23 @@ static bool __init debug_objects_replace_static_objects(struct kmem_cache *cache
1354
1368
hlist_add_head (& obj -> node , & objects );
1355
1369
}
1356
1370
1357
- debug_objects_allocated += i ;
1371
+ debug_objects_allocated = ODEBUG_POOL_SIZE ;
1372
+ pool_global .cnt = ODEBUG_POOL_SIZE ;
1358
1373
1359
1374
/*
1360
1375
* Replace the statically allocated objects list with the allocated
1361
1376
* objects list.
1362
1377
*/
1363
- hlist_move_list (& objects , & obj_pool );
1378
+ hlist_move_list (& objects , & pool_global . objects );
1364
1379
1365
1380
/* Replace the active object references */
1366
1381
for (i = 0 ; i < ODEBUG_HASH_SIZE ; i ++ , db ++ ) {
1367
1382
hlist_move_list (& db -> list , & objects );
1368
1383
1369
1384
hlist_for_each_entry (obj , & objects , node ) {
1370
- new = hlist_entry (obj_pool .first , typeof (* obj ), node );
1385
+ new = hlist_entry (pool_global . objects .first , typeof (* obj ), node );
1371
1386
hlist_del (& new -> node );
1387
+ pool_global .cnt -- ;
1372
1388
/* copy object data */
1373
1389
* new = * obj ;
1374
1390
hlist_add_head (& new -> node , & db -> list );
0 commit comments