]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Jul 2015 17:49:25 +0000 (10:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Jul 2015 17:49:25 +0000 (10:49 -0700)
Pull module updates from Rusty Russell:
 "Main excitement here is Peter Zijlstra's lockless rbtree optimization
  to speed module address lookup.  He found some abusers of the module
  lock doing that too.

  A little bit of parameter work here too; including Dan Streetman's
  breaking up the big param mutex so writing a parameter can load
  another module (yeah, really).  Unfortunately that broke the usual
  suspects, !CONFIG_MODULES and !CONFIG_SYSFS, so those fixes were
  appended too"

* tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (26 commits)
  modules: only use mod->param_lock if CONFIG_MODULES
  param: fix module param locks when !CONFIG_SYSFS.
  rcu: merge fix for Convert ACCESS_ONCE() to READ_ONCE() and WRITE_ONCE()
  module: add per-module param_lock
  module: make perm const
  params: suppress unused variable error, warn once just in case code changes.
  modules: clarify CONFIG_MODULE_COMPRESS help, suggest 'N'.
  kernel/module.c: avoid ifdefs for sig_enforce declaration
  kernel/workqueue.c: remove ifdefs over wq_power_efficient
  kernel/params.c: export param_ops_bool_enable_only
  kernel/params.c: generalize bool_enable_only
  kernel/module.c: use generic module param operaters for sig_enforce
  kernel/params: constify struct kernel_param_ops uses
  sysfs: tightened sysfs permission checks
  module: Rework module_addr_{min,max}
  module: Use __module_address() for module_address_lookup()
  module: Make the mod_tree stuff conditional on PERF_EVENTS || TRACING
  module: Optimize __module_address() using a latched RB-tree
  rbtree: Implement generic latch_tree
  seqlock: Introduce raw_read_seqcount_latch()
  ...

22 files changed:
1  2 
arch/x86/kvm/mmu_audit.c
drivers/block/null_blk.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/mouse/psmouse-base.c
drivers/mtd/ubi/block.c
drivers/net/wireless/ath/wil6210/main.c
drivers/thermal/intel_powerclamp.c
drivers/tty/sysrq.c
include/linux/compiler.h
include/linux/kernel.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/rcupdate.h
include/linux/seqlock.h
init/Kconfig
kernel/module.c
kernel/params.c
kernel/time/timekeeping.c
kernel/workqueue.c
net/mac80211/rate.c
security/apparmor/lsm.c
sound/pci/hda/hda_intel.c

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 486e685a226a82d5cb841e61fb2ebf1562c5adb7,890c7ef709d5f3cc83873a1492cbdcebad6c0926..e0582106ef4faba81db1ff7912246623c3f7f1c2
@@@ -233,50 -234,87 +234,128 @@@ static inline void raw_write_seqcount_e
        s->sequence++;
  }
  
- /*
 +/**
 + * raw_write_seqcount_barrier - do a seq write barrier
 + * @s: pointer to seqcount_t
 + *
 + * This can be used to provide an ordering guarantee instead of the
 + * usual consistency guarantee. It is one wmb cheaper, because we can
 + * collapse the two back-to-back wmb()s.
 + *
 + *      seqcount_t seq;
 + *      bool X = true, Y = false;
 + *
 + *      void read(void)
 + *      {
 + *              bool x, y;
 + *
 + *              do {
 + *                      int s = read_seqcount_begin(&seq);
 + *
 + *                      x = X; y = Y;
 + *
 + *              } while (read_seqcount_retry(&seq, s));
 + *
 + *              BUG_ON(!x && !y);
 + *      }
 + *
 + *      void write(void)
 + *      {
 + *              Y = true;
 + *
 + *              raw_write_seqcount_barrier(seq);
 + *
 + *              X = false;
 + *      }
 + */
 +static inline void raw_write_seqcount_barrier(seqcount_t *s)
 +{
 +      s->sequence++;
 +      smp_wmb();
 +      s->sequence++;
 +}
 +
+ static inline int raw_read_seqcount_latch(seqcount_t *s)
+ {
+       return lockless_dereference(s->sequence);
+ }
+ /**
   * raw_write_seqcount_latch - redirect readers to even/odd copy
   * @s: pointer to seqcount_t
+  *
+  * The latch technique is a multiversion concurrency control method that allows
+  * queries during non-atomic modifications. If you can guarantee queries never
+  * interrupt the modification -- e.g. the concurrency is strictly between CPUs
+  * -- you most likely do not need this.
+  *
+  * Where the traditional RCU/lockless data structures rely on atomic
+  * modifications to ensure queries observe either the old or the new state the
+  * latch allows the same for non-atomic updates. The trade-off is doubling the
+  * cost of storage; we have to maintain two copies of the entire data
+  * structure.
+  *
+  * Very simply put: we first modify one copy and then the other. This ensures
+  * there is always one copy in a stable state, ready to give us an answer.
+  *
+  * The basic form is a data structure like:
+  *
+  * struct latch_struct {
+  *    seqcount_t              seq;
+  *    struct data_struct      data[2];
+  * };
+  *
+  * Where a modification, which is assumed to be externally serialized, does the
+  * following:
+  *
+  * void latch_modify(struct latch_struct *latch, ...)
+  * {
+  *    smp_wmb();      <- Ensure that the last data[1] update is visible
+  *    latch->seq++;
+  *    smp_wmb();      <- Ensure that the seqcount update is visible
+  *
+  *    modify(latch->data[0], ...);
+  *
+  *    smp_wmb();      <- Ensure that the data[0] update is visible
+  *    latch->seq++;
+  *    smp_wmb();      <- Ensure that the seqcount update is visible
+  *
+  *    modify(latch->data[1], ...);
+  * }
+  *
+  * The query will have a form like:
+  *
+  * struct entry *latch_query(struct latch_struct *latch, ...)
+  * {
+  *    struct entry *entry;
+  *    unsigned seq, idx;
+  *
+  *    do {
+  *            seq = lockless_dereference(latch->seq);
+  *
+  *            idx = seq & 0x01;
+  *            entry = data_query(latch->data[idx], ...);
+  *
+  *            smp_rmb();
+  *    } while (seq != latch->seq);
+  *
+  *    return entry;
+  * }
+  *
+  * So during the modification, queries are first redirected to data[1]. Then we
+  * modify data[0]. When that is complete, we redirect queries back to data[0]
+  * and we can modify data[1].
+  *
+  * NOTE: The non-requirement for atomic modifications does _NOT_ include
+  *       the publishing of new entries in the case where data is a dynamic
+  *       data structure.
+  *
+  *       An iteration might start in data[0] and get suspended long enough
+  *       to miss an entire modification sequence, once it resumes it might
+  *       observe the new entry.
+  *
+  * NOTE: When data is a dynamic data structure; one should use regular RCU
+  *       patterns to manage the lifetimes of the objects within.
   */
  static inline void raw_write_seqcount_latch(seqcount_t *s)
  {
diff --cc init/Kconfig
Simple merge
diff --cc kernel/module.c
Simple merge
diff --cc kernel/params.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge