History

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.

Thomas Gleixner committed 2 years ago

Commit 55fb4121 parent 813fd071 file · +35 −33Browse files

Showing the changes to lib/debugobjects.c (1 of 1 file). Show all

Unified · Split

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