Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

debugobjects: Dont destroy kmem cache in init()

debug_objects_mem_init() is invoked from mm_core_init() before work queues
are available. If debug_objects_mem_init() destroys the kmem cache in the
error path it causes an Oops in __queue_work():

Oops: Oops: 0000 [#1] PREEMPT SMP PTI
RIP: 0010:__queue_work+0x35/0x6a0
queue_work_on+0x66/0x70
flush_all_cpus_locked+0xdf/0x1a0
__kmem_cache_shutdown+0x2f/0x340
kmem_cache_destroy+0x4e/0x150
mm_core_init+0x9e/0x120
start_kernel+0x298/0x800
x86_64_start_reservations+0x18/0x30
x86_64_start_kernel+0xc5/0xe0
common_startup_64+0x12c/0x138

Further the object cache pointer is used in various places to check for
early boot operation. It is exposed before the replacments for the static
boot time objects are allocated and the self test operates on it.

This can be avoided by:

1) Running the self test with the static boot objects

2) Exposing it only after the replacement objects have been added to
the pool.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20241007164913.137021337@linutronix.de

+36 -34
+36 -34
lib/debugobjects.c
··· 1211 1211 1212 1212 static __initdata struct self_test obj = { .static_init = 0 }; 1213 1213 1214 - static void __init debug_objects_selftest(void) 1214 + static bool __init debug_objects_selftest(void) 1215 1215 { 1216 1216 int fixups, oldfixups, warnings, oldwarnings; 1217 1217 unsigned long flags; ··· 1280 1280 descr_test = NULL; 1281 1281 1282 1282 local_irq_restore(flags); 1283 + return !!debug_objects_enabled; 1283 1284 } 1284 1285 #else 1285 - static inline void debug_objects_selftest(void) { } 1286 + static inline bool debug_objects_selftest(void) { return true; } 1286 1287 #endif 1287 1288 1288 1289 /* ··· 1303 1302 } 1304 1303 1305 1304 /* 1306 - * Convert the statically allocated objects to dynamic ones: 1305 + * Convert the statically allocated objects to dynamic ones. 1306 + * debug_objects_mem_init() is called early so only one CPU is up and 1307 + * interrupts are disabled, which means it is safe to replace the active 1308 + * object references. 1307 1309 */ 1308 - static int __init debug_objects_replace_static_objects(void) 1310 + static bool __init debug_objects_replace_static_objects(struct kmem_cache *cache) 1309 1311 { 1310 1312 struct debug_bucket *db = obj_hash; 1311 - struct hlist_node *tmp; 1312 1313 struct debug_obj *obj, *new; 1314 + struct hlist_node *tmp; 1313 1315 HLIST_HEAD(objects); 1314 1316 int i, cnt = 0; 1315 1317 1316 1318 for (i = 0; i < ODEBUG_POOL_SIZE; i++) { 1317 - obj = kmem_cache_zalloc(obj_cache, GFP_KERNEL); 1319 + obj = kmem_cache_zalloc(cache, GFP_KERNEL); 1318 1320 if (!obj) 1319 1321 goto free; 1320 1322 hlist_add_head(&obj->node, &objects); 1321 1323 } 1322 1324 1323 1325 debug_objects_allocated += i; 1324 - 1325 - /* 1326 - * debug_objects_mem_init() is now called early that only one CPU is up 1327 - * and interrupts have been disabled, so it is safe to replace the 1328 - * active object references. 1329 - */ 1330 1326 1331 1327 /* 1332 1328 * Replace the statically allocated objects list with the allocated ··· 1345 1347 } 1346 1348 } 1347 1349 1348 - pr_debug("%d of %d active objects replaced\n", 1349 - cnt, obj_pool_used); 1350 - return 0; 1350 + pr_debug("%d of %d active objects replaced\n", cnt, obj_pool_used); 1351 + return true; 1351 1352 free: 1352 1353 hlist_for_each_entry_safe(obj, tmp, &objects, node) { 1353 1354 hlist_del(&obj->node); 1354 - kmem_cache_free(obj_cache, obj); 1355 + kmem_cache_free(cache, obj); 1355 1356 } 1356 - return -ENOMEM; 1357 + return false; 1357 1358 } 1358 1359 1359 1360 /* ··· 1363 1366 */ 1364 1367 void __init debug_objects_mem_init(void) 1365 1368 { 1369 + struct kmem_cache *cache; 1366 1370 int cpu, extras; 1367 1371 1368 1372 if (!debug_objects_enabled) ··· 1378 1380 for_each_possible_cpu(cpu) 1379 1381 INIT_HLIST_HEAD(&per_cpu(percpu_obj_pool.free_objs, cpu)); 1380 1382 1381 - obj_cache = kmem_cache_create("debug_objects_cache", 1382 - sizeof (struct debug_obj), 0, 1383 - SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE, 1384 - NULL); 1385 - 1386 - if (!obj_cache || debug_objects_replace_static_objects()) { 1387 - debug_objects_enabled = 0; 1388 - kmem_cache_destroy(obj_cache); 1389 - pr_warn("out of memory.\n"); 1383 + if (!debug_objects_selftest()) 1390 1384 return; 1391 - } else 1392 - debug_objects_selftest(); 1393 1385 1394 - #ifdef CONFIG_HOTPLUG_CPU 1395 - cpuhp_setup_state_nocalls(CPUHP_DEBUG_OBJ_DEAD, "object:offline", NULL, 1396 - object_cpu_offline); 1397 - #endif 1386 + cache = kmem_cache_create("debug_objects_cache", sizeof (struct debug_obj), 0, 1387 + SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE, NULL); 1388 + 1389 + if (!cache || !debug_objects_replace_static_objects(cache)) { 1390 + debug_objects_enabled = 0; 1391 + pr_warn("Out of memory.\n"); 1392 + return; 1393 + } 1398 1394 1399 1395 /* 1400 - * Increase the thresholds for allocating and freeing objects 1401 - * according to the number of possible CPUs available in the system. 1396 + * Adjust the thresholds for allocating and freeing objects 1397 + * according to the number of possible CPUs available in the 1398 + * system. 1402 1399 */ 1403 1400 extras = num_possible_cpus() * ODEBUG_BATCH_SIZE; 1404 1401 debug_objects_pool_size += extras; 1405 1402 debug_objects_pool_min_level += extras; 1403 + 1404 + /* Everything worked. Expose the cache */ 1405 + obj_cache = cache; 1406 + 1407 + #ifdef CONFIG_HOTPLUG_CPU 1408 + cpuhp_setup_state_nocalls(CPUHP_DEBUG_OBJ_DEAD, "object:offline", NULL, 1409 + object_cpu_offline); 1410 + #endif 1411 + return; 1406 1412 }