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.

Merge tag 'scftorture.2024.11.16a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull scftorture updates from Paul McKenney:

- Avoid divide operation

- Fix cleanup code waiting for IPI handlers

- Move memory allocations out of preempt-disable region of code for
PREEMPT_RT compatibility

- Use a lockless list to avoid freeing memory while interrupts are
disabled, again for PREEMPT_RT compatibility

- Make lockless list scf_add_to_free_list() correctly handle freeing a
NULL pointer

* tag 'scftorture.2024.11.16a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu:
scftorture: Handle NULL argument passed to scf_add_to_free_list().
scftorture: Use a lock-less list to free memory.
scftorture: Move memory allocation outside of preempt_disable region.
scftorture: Wait until scf_cleanup_handler() completes.
scftorture: Avoid additional div operation.

+44 -10
+44 -10
kernel/scftorture.c
··· 97 97 static struct scf_statistics *scf_stats_p; 98 98 static struct task_struct *scf_torture_stats_task; 99 99 static DEFINE_PER_CPU(long long, scf_invoked_count); 100 + static DEFINE_PER_CPU(struct llist_head, scf_free_pool); 100 101 101 102 // Data for random primitive selection 102 103 #define SCF_PRIM_RESCHED 0 ··· 134 133 bool scfc_wait; 135 134 bool scfc_rpc; 136 135 struct completion scfc_completion; 136 + struct llist_node scf_node; 137 137 }; 138 138 139 139 // Use to wait for all threads to start. ··· 149 147 static DEFINE_TORTURE_RANDOM_PERCPU(scf_torture_rand); 150 148 151 149 extern void resched_cpu(int cpu); // An alternative IPI vector. 150 + 151 + static void scf_add_to_free_list(struct scf_check *scfcp) 152 + { 153 + struct llist_head *pool; 154 + unsigned int cpu; 155 + 156 + if (!scfcp) 157 + return; 158 + cpu = raw_smp_processor_id() % nthreads; 159 + pool = &per_cpu(scf_free_pool, cpu); 160 + llist_add(&scfcp->scf_node, pool); 161 + } 162 + 163 + static void scf_cleanup_free_list(unsigned int cpu) 164 + { 165 + struct llist_head *pool; 166 + struct llist_node *node; 167 + struct scf_check *scfcp; 168 + 169 + pool = &per_cpu(scf_free_pool, cpu); 170 + node = llist_del_all(pool); 171 + while (node) { 172 + scfcp = llist_entry(node, struct scf_check, scf_node); 173 + node = node->next; 174 + kfree(scfcp); 175 + } 176 + } 152 177 153 178 // Print torture statistics. Caller must ensure serialization. 154 179 static void scf_torture_stats_print(void) ··· 325 296 if (scfcp->scfc_rpc) 326 297 complete(&scfcp->scfc_completion); 327 298 } else { 328 - kfree(scfcp); 299 + scf_add_to_free_list(scfcp); 329 300 } 330 301 } 331 302 ··· 349 320 struct scf_check *scfcp = NULL; 350 321 struct scf_selector *scfsp = scf_sel_rand(trsp); 351 322 352 - if (use_cpus_read_lock) 353 - cpus_read_lock(); 354 - else 355 - preempt_disable(); 356 323 if (scfsp->scfs_prim == SCF_PRIM_SINGLE || scfsp->scfs_wait) { 357 324 scfcp = kmalloc(sizeof(*scfcp), GFP_ATOMIC); 358 325 if (!scfcp) { ··· 362 337 scfcp->scfc_rpc = false; 363 338 } 364 339 } 340 + if (use_cpus_read_lock) 341 + cpus_read_lock(); 342 + else 343 + preempt_disable(); 365 344 switch (scfsp->scfs_prim) { 366 345 case SCF_PRIM_RESCHED: 367 346 if (IS_BUILTIN(CONFIG_SCF_TORTURE_TEST)) { ··· 392 363 scfp->n_single_wait_ofl++; 393 364 else 394 365 scfp->n_single_ofl++; 395 - kfree(scfcp); 366 + scf_add_to_free_list(scfcp); 396 367 scfcp = NULL; 397 368 } 398 369 break; ··· 420 391 preempt_disable(); 421 392 } else { 422 393 scfp->n_single_rpc_ofl++; 423 - kfree(scfcp); 394 + scf_add_to_free_list(scfcp); 424 395 scfcp = NULL; 425 396 } 426 397 break; ··· 457 428 pr_warn("%s: Memory-ordering failure, scfs_prim: %d.\n", __func__, scfsp->scfs_prim); 458 429 atomic_inc(&n_mb_out_errs); // Leak rather than trash! 459 430 } else { 460 - kfree(scfcp); 431 + scf_add_to_free_list(scfcp); 461 432 } 462 433 barrier(); // Prevent race-reduction compiler optimizations. 463 434 } ··· 492 463 493 464 // Make sure that the CPU is affinitized appropriately during testing. 494 465 curcpu = raw_smp_processor_id(); 495 - WARN_ONCE(curcpu != scfp->cpu % nr_cpu_ids, 466 + WARN_ONCE(curcpu != cpu, 496 467 "%s: Wanted CPU %d, running on %d, nr_cpu_ids = %d\n", 497 468 __func__, scfp->cpu, curcpu, nr_cpu_ids); 498 469 ··· 508 479 VERBOSE_SCFTORTOUT("scftorture_invoker %d started", scfp->cpu); 509 480 510 481 do { 482 + scf_cleanup_free_list(cpu); 483 + 511 484 scftorture_invoke_one(scfp, &rand); 512 485 while (cpu_is_offline(cpu) && !torture_must_stop()) { 513 486 schedule_timeout_interruptible(HZ / 5); ··· 554 523 torture_stop_kthread("scftorture_invoker", scf_stats_p[i].task); 555 524 else 556 525 goto end; 557 - smp_call_function(scf_cleanup_handler, NULL, 0); 526 + smp_call_function(scf_cleanup_handler, NULL, 1); 558 527 torture_stop_kthread(scf_torture_stats, scf_torture_stats_task); 559 528 scf_torture_stats_print(); // -After- the stats thread is stopped! 560 529 kfree(scf_stats_p); // -After- the last stats print has completed! 561 530 scf_stats_p = NULL; 531 + 532 + for (i = 0; i < nr_cpu_ids; i++) 533 + scf_cleanup_free_list(i); 562 534 563 535 if (atomic_read(&n_errs) || atomic_read(&n_mb_in_errs) || atomic_read(&n_mb_out_errs)) 564 536 scftorture_print_module_parms("End of test: FAILURE");