This commit adds a kthread to release deferred hazard pointers, which
will be used to test acquiring a hazard pointer in one task and releasing
it in another.

Signed-off-by: Paul E. McKenney <[email protected]>
---
 kernel/rcu/hazptrtorture.c | 90 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/kernel/rcu/hazptrtorture.c b/kernel/rcu/hazptrtorture.c
index 3d559cfb85816d..de2b4e45d9599a 100644
--- a/kernel/rcu/hazptrtorture.c
+++ b/kernel/rcu/hazptrtorture.c
@@ -30,6 +30,8 @@ MODULE_DESCRIPTION("Hazard-pointer module-based torture test 
facility");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <[email protected]>");
 
+torture_param(int, kthread_do_pending_ms, -1,
+             "Delay between cleanups for deferred hazard pointers (ms), zero 
to disable");
 torture_param(int, nreaders, -1, "Number of hazard-pointer reader threads");
 torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs 
(s)");
 torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (jiffies), 
0=disable");
@@ -50,6 +52,7 @@ static int nrealreaders;
 static struct task_struct *writer_task;
 static struct task_struct *preempt_task;
 static struct task_struct **reader_tasks;
+static struct task_struct *do_pending_task;
 static struct task_struct *stats_task;
 
 #define HAZPTR_TORTURE_PIPE_LEN 10
@@ -74,6 +77,14 @@ static atomic_t n_hazptr_torture_free;
 static atomic_t n_hazptr_torture_error;
 static struct list_head hazptr_torture_removed;
 
+// State for a deferred (AKA pending) hazard pointer
+struct hazptr_pending {
+       struct llist_node hpp_node;
+       struct hazptr_ctx hpp_hc;
+       struct hazptr_torture *hpp_htp;
+};
+static DEFINE_PER_CPU(struct llist_head, hazptr_pending);
+
 static int hazptr_torture_writer_state;
 #define HTWS_FIXED_DELAY       0
 #define HTWS_DELAY             1
@@ -416,6 +427,76 @@ static int hazptr_torture_reader(void *arg)
        return 0;
 }
 
+/*
+ * Release the specified CPU's set of deferred/pending hazard pointers.
+ */
+static void hazptr_torture_do_one_pending(int cpu, struct torture_random_state 
*trsp)
+{
+       struct hazptr_pending *hppp;
+       struct hazptr_pending *hppp1;
+       struct llist_head *llhp;
+       struct llist_node *llnp;
+
+       llhp = per_cpu_ptr(&hazptr_pending, cpu);
+       llnp = llist_del_all(llhp);
+       if (!llnp)
+               return;
+       llist_for_each_entry_safe(hppp, hppp1, llnp, hpp_node) {
+               hazptr_torture_reader_tail(&hppp->hpp_hc, hppp->hpp_htp, trsp);
+               kfree(hppp);
+       }
+}
+
+/*
+ * Hazard-pointer release of deferred/pending hazard pointers.
+ */
+static int hazptr_torture_do_pending(void *arg)
+{
+       int cpu = 0;
+       DEFINE_TORTURE_RANDOM(rand);
+
+       VERBOSE_TOROUT_STRING("hazptr_torture_do_pending task started");
+       do {
+               if (stutter_will_wait()) {
+                       for_each_possible_cpu(cpu)
+                               hazptr_torture_do_one_pending(cpu, &rand);
+               } else {
+                       cpu = cpumask_next_wrap(cpu, cpu_possible_mask);
+                       hazptr_torture_do_one_pending(cpu, &rand);
+               }
+               if (torture_must_stop())
+                       torture_hrtimeout_ms(kthread_do_pending_ms, 
USEC_PER_MSEC, &rand);
+               // Omit stutter_wait() because this function needs to do 
cleanup.
+       } while (!torture_must_stop());
+       torture_kthread_stopping("hazptr_torture_do_pending");
+       return 0;
+}
+
+/*
+ * Spawn hazptr_torture_do_pending() if there is something for it to do.
+ */
+static int hazptr_torture_do_pending_init(void)
+{
+       if (kthread_do_pending_ms == -1)
+               kthread_do_pending_ms = cur_ops->onstack_ctx ? 0 : 3;
+       if (kthread_do_pending_ms < 0) {
+               pr_alert("Cannot have negative kthread_do_pending_ms, disabling 
deferral.\n");
+               goto err_out;
+       }
+       if (cur_ops->onstack_ctx && kthread_do_pending_ms) {
+               pr_alert("Cannot defer onstack hazptr_ctx, disabling 
deferral.\n");
+               goto err_out;
+       }
+       if (!kthread_do_pending_ms)
+               return 0;
+       return torture_create_kthread(hazptr_torture_do_pending, NULL, 
do_pending_task);
+
+err_out:
+       WARN_ON(IS_BUILTIN(CONFIG_HAZPTR_TORTURE_TEST));
+       kthread_do_pending_ms = 0;
+       return 0;
+}
+
 /*
  * Print torture statistics.  Caller must ensure that there is only one
  * call to this function at a given time!!!  This is normally accomplished
@@ -525,12 +606,14 @@ hazptr_torture_print_module_parms(struct 
hazptr_torture_ops *cur_ops, const char
 {
        pr_alert("%s" TORTURE_FLAG
                 "--- %s: nreaders=%d "
+                "kthread_do_pending_ms=%d "
                 "onoff_interval=%d onoff_holdoff=%d "
                 "preempt_duration=%d preempt_interval=%d "
                 "reader_sleep_us=%d "
                 "shuffle_interval=%d shutdown_secs=%d stat_interval=%d 
stutter=%d "
                 "verbose=%d\n",
                 torture_type, tag, nrealreaders,
+                kthread_do_pending_ms,
                 onoff_interval, onoff_holdoff,
                 preempt_duration, preempt_interval,
                 reader_sleep_us,
@@ -579,6 +662,7 @@ hazptr_torture_cleanup(void)
                return;
        }
 
+       torture_stop_kthread(hazptr_torture_do_pending, do_pending_task);
        torture_stop_kthread(hazptr_torture_preempt, preempt_task);
        torture_stop_kthread(hazptr_torture_writer, writer_task);
 
@@ -667,6 +751,12 @@ static int __init hazptr_torture_init(void)
 
        /* Start up the kthreads. */
 
+       // This must be before the readers in order to set up the module
+       // parameters used by the readers.
+       firsterr = hazptr_torture_do_pending_init();
+       if (torture_init_error(firsterr))
+               goto unwind;
+
        reader_tasks = kzalloc_objs(reader_tasks[0], nrealreaders);
        for (i = 0; i < nrealreaders; i++) {
                firsterr = torture_create_kthread(hazptr_torture_reader, (void 
*)i,
-- 
2.40.1


Reply via email to