srcu: Use static init for statically allocated in-module srcu_struct
authorPaul E. McKenney <paulmck@kernel.org>
Fri, 17 Mar 2023 20:28:04 +0000 (13:28 -0700)
committerPaul E. McKenney <paulmck@kernel.org>
Tue, 4 Apr 2023 15:35:28 +0000 (08:35 -0700)
Further shrinking the srcu_struct structure is eased by requiring
that in-module srcu_struct structures rely more heavily on static
initialization.  In particular, this preserves the property that
a module-load-time srcu_struct initialization can fail only due
to memory-allocation failure of the per-CPU srcu_data structures.
It might also slightly improve robustness by keeping the number of memory
allocations that must succeed down percpu_alloc() call.

This is in preparation for splitting an srcu_usage structure out
of the srcu_struct structure.

[ paulmck: Fold in qiang1.zhang@intel.com feedback. ]

Cc: Christoph Hellwig <hch@lst.de>
Tested-by: Sachin Sant <sachinp@linux.ibm.com>
Tested-by: "Zhang, Qiang1" <qiang1.zhang@intel.com>
Tested-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
include/linux/srcutree.h
kernel/rcu/srcutree.c

index 488d0e5d1ba3e47882df81fbd511a7b11d7ea297..3ce6deee1dbec096c8f12b9c3f36543876750c66 100644 (file)
@@ -108,15 +108,24 @@ struct srcu_struct {
 #define SRCU_STATE_SCAN1       1
 #define SRCU_STATE_SCAN2       2
 
-#define __SRCU_STRUCT_INIT(name, pcpu_name)                                                    \
-{                                                                                              \
-       .sda = &pcpu_name,                                                                      \
+#define __SRCU_STRUCT_INIT_COMMON(name)                                                                \
        .lock = __SPIN_LOCK_UNLOCKED(name.lock),                                                \
        .srcu_gp_seq_needed = -1UL,                                                             \
        .work = __DELAYED_WORK_INITIALIZER(name.work, NULL, 0),                                 \
-       __SRCU_DEP_MAP_INIT(name)                                                               \
+       __SRCU_DEP_MAP_INIT(name)
+
+#define __SRCU_STRUCT_INIT_MODULE(name)                                                                \
+{                                                                                              \
+       __SRCU_STRUCT_INIT_COMMON(name)                                                         \
 }
 
+#define __SRCU_STRUCT_INIT(name, pcpu_name)                                                    \
+{                                                                                              \
+       .sda = &pcpu_name,                                                                      \
+       __SRCU_STRUCT_INIT_COMMON(name)                                                         \
+}
+
+
 /*
  * Define and initialize a srcu struct at build time.
  * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it.
@@ -138,7 +147,7 @@ struct srcu_struct {
  */
 #ifdef MODULE
 # define __DEFINE_SRCU(name, is_static)                                                                \
-       is_static struct srcu_struct name;                                                      \
+       is_static struct srcu_struct name = __SRCU_STRUCT_INIT_MODULE(name);                    \
        extern struct srcu_struct * const __srcu_struct_##name;                                 \
        struct srcu_struct * const __srcu_struct_##name                                         \
                __section("___srcu_struct_ptrs") = &name
index ab4ee58af84bfcfaf6890a6650b40117be09bfb0..7e6e7dfb1a877d186239d2a7d8544b574efae3f1 100644 (file)
@@ -1873,13 +1873,14 @@ void __init srcu_init(void)
 static int srcu_module_coming(struct module *mod)
 {
        int i;
+       struct srcu_struct *ssp;
        struct srcu_struct **sspp = mod->srcu_struct_ptrs;
-       int ret;
 
        for (i = 0; i < mod->num_srcu_structs; i++) {
-               ret = init_srcu_struct(*(sspp++));
-               if (WARN_ON_ONCE(ret))
-                       return ret;
+               ssp = *(sspp++);
+               ssp->sda = alloc_percpu(struct srcu_data);
+               if (WARN_ON_ONCE(!ssp->sda))
+                       return -ENOMEM;
        }
        return 0;
 }
@@ -1888,10 +1889,16 @@ static int srcu_module_coming(struct module *mod)
 static void srcu_module_going(struct module *mod)
 {
        int i;
+       struct srcu_struct *ssp;
        struct srcu_struct **sspp = mod->srcu_struct_ptrs;
 
-       for (i = 0; i < mod->num_srcu_structs; i++)
-               cleanup_srcu_struct(*(sspp++));
+       for (i = 0; i < mod->num_srcu_structs; i++) {
+               ssp = *(sspp++);
+               if (!rcu_seq_state(smp_load_acquire(&ssp->srcu_gp_seq_needed)) &&
+                   !WARN_ON_ONCE(!ssp->sda_is_static))
+                       cleanup_srcu_struct(ssp);
+               free_percpu(ssp->sda);
+       }
 }
 
 /* Handle one module, either coming or going. */