Merge tag 'pm-5.12-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6-microblaze.git] / kernel / sched / membarrier.c
index e23e74d..08ae45a 100644 (file)
@@ -6,6 +6,134 @@
  */
 #include "sched.h"
 
+/*
+ * For documentation purposes, here are some membarrier ordering
+ * scenarios to keep in mind:
+ *
+ * A) Userspace thread execution after IPI vs membarrier's memory
+ *    barrier before sending the IPI
+ *
+ * Userspace variables:
+ *
+ * int x = 0, y = 0;
+ *
+ * The memory barrier at the start of membarrier() on CPU0 is necessary in
+ * order to enforce the guarantee that any writes occurring on CPU0 before
+ * the membarrier() is executed will be visible to any code executing on
+ * CPU1 after the IPI-induced memory barrier:
+ *
+ *         CPU0                              CPU1
+ *
+ *         x = 1
+ *         membarrier():
+ *           a: smp_mb()
+ *           b: send IPI                       IPI-induced mb
+ *           c: smp_mb()
+ *         r2 = y
+ *                                           y = 1
+ *                                           barrier()
+ *                                           r1 = x
+ *
+ *                     BUG_ON(r1 == 0 && r2 == 0)
+ *
+ * The write to y and load from x by CPU1 are unordered by the hardware,
+ * so it's possible to have "r1 = x" reordered before "y = 1" at any
+ * point after (b).  If the memory barrier at (a) is omitted, then "x = 1"
+ * can be reordered after (a) (although not after (c)), so we get r1 == 0
+ * and r2 == 0.  This violates the guarantee that membarrier() is
+ * supposed by provide.
+ *
+ * The timing of the memory barrier at (a) has to ensure that it executes
+ * before the IPI-induced memory barrier on CPU1.
+ *
+ * B) Userspace thread execution before IPI vs membarrier's memory
+ *    barrier after completing the IPI
+ *
+ * Userspace variables:
+ *
+ * int x = 0, y = 0;
+ *
+ * The memory barrier at the end of membarrier() on CPU0 is necessary in
+ * order to enforce the guarantee that any writes occurring on CPU1 before
+ * the membarrier() is executed will be visible to any code executing on
+ * CPU0 after the membarrier():
+ *
+ *         CPU0                              CPU1
+ *
+ *                                           x = 1
+ *                                           barrier()
+ *                                           y = 1
+ *         r2 = y
+ *         membarrier():
+ *           a: smp_mb()
+ *           b: send IPI                       IPI-induced mb
+ *           c: smp_mb()
+ *         r1 = x
+ *         BUG_ON(r1 == 0 && r2 == 1)
+ *
+ * The writes to x and y are unordered by the hardware, so it's possible to
+ * have "r2 = 1" even though the write to x doesn't execute until (b).  If
+ * the memory barrier at (c) is omitted then "r1 = x" can be reordered
+ * before (b) (although not before (a)), so we get "r1 = 0".  This violates
+ * the guarantee that membarrier() is supposed to provide.
+ *
+ * The timing of the memory barrier at (c) has to ensure that it executes
+ * after the IPI-induced memory barrier on CPU1.
+ *
+ * C) Scheduling userspace thread -> kthread -> userspace thread vs membarrier
+ *
+ *           CPU0                            CPU1
+ *
+ *           membarrier():
+ *           a: smp_mb()
+ *                                           d: switch to kthread (includes mb)
+ *           b: read rq->curr->mm == NULL
+ *                                           e: switch to user (includes mb)
+ *           c: smp_mb()
+ *
+ * Using the scenario from (A), we can show that (a) needs to be paired
+ * with (e). Using the scenario from (B), we can show that (c) needs to
+ * be paired with (d).
+ *
+ * D) exit_mm vs membarrier
+ *
+ * Two thread groups are created, A and B.  Thread group B is created by
+ * issuing clone from group A with flag CLONE_VM set, but not CLONE_THREAD.
+ * Let's assume we have a single thread within each thread group (Thread A
+ * and Thread B).  Thread A runs on CPU0, Thread B runs on CPU1.
+ *
+ *           CPU0                            CPU1
+ *
+ *           membarrier():
+ *             a: smp_mb()
+ *                                           exit_mm():
+ *                                             d: smp_mb()
+ *                                             e: current->mm = NULL
+ *             b: read rq->curr->mm == NULL
+ *             c: smp_mb()
+ *
+ * Using scenario (B), we can show that (c) needs to be paired with (d).
+ *
+ * E) kthread_{use,unuse}_mm vs membarrier
+ *
+ *           CPU0                            CPU1
+ *
+ *           membarrier():
+ *           a: smp_mb()
+ *                                           kthread_unuse_mm()
+ *                                             d: smp_mb()
+ *                                             e: current->mm = NULL
+ *           b: read rq->curr->mm == NULL
+ *                                           kthread_use_mm()
+ *                                             f: current->mm = mm
+ *                                             g: smp_mb()
+ *           c: smp_mb()
+ *
+ * Using the scenario from (A), we can show that (a) needs to be paired
+ * with (g). Using the scenario from (B), we can show that (c) needs to
+ * be paired with (d).
+ */
+
 /*
  * Bitmask made from a "or" of all commands within enum membarrier_cmd,
  * except MEMBARRIER_CMD_QUERY.
@@ -38,8 +166,33 @@ static void ipi_mb(void *info)
        smp_mb();       /* IPIs should be serializing but paranoid. */
 }
 
+static void ipi_sync_core(void *info)
+{
+       /*
+        * The smp_mb() in membarrier after all the IPIs is supposed to
+        * ensure that memory on remote CPUs that occur before the IPI
+        * become visible to membarrier()'s caller -- see scenario B in
+        * the big comment at the top of this file.
+        *
+        * A sync_core() would provide this guarantee, but
+        * sync_core_before_usermode() might end up being deferred until
+        * after membarrier()'s smp_mb().
+        */
+       smp_mb();       /* IPIs should be serializing but paranoid. */
+
+       sync_core_before_usermode();
+}
+
 static void ipi_rseq(void *info)
 {
+       /*
+        * Ensure that all stores done by the calling thread are visible
+        * to the current task before the current task resumes.  We could
+        * probably optimize this away on most architectures, but by the
+        * time we've already sent an IPI, the cost of the extra smp_mb()
+        * is negligible.
+        */
+       smp_mb();
        rseq_preempt(current);
 }
 
@@ -76,6 +229,18 @@ void membarrier_exec_mmap(struct mm_struct *mm)
        this_cpu_write(runqueues.membarrier_state, 0);
 }
 
+void membarrier_update_current_mm(struct mm_struct *next_mm)
+{
+       struct rq *rq = this_rq();
+       int membarrier_state = 0;
+
+       if (next_mm)
+               membarrier_state = atomic_read(&next_mm->membarrier_state);
+       if (READ_ONCE(rq->membarrier_state) == membarrier_state)
+               return;
+       WRITE_ONCE(rq->membarrier_state, membarrier_state);
+}
+
 static int membarrier_global_expedited(void)
 {
        int cpu;
@@ -114,12 +279,11 @@ static int membarrier_global_expedited(void)
                        continue;
 
                /*
-                * Skip the CPU if it runs a kernel thread. The scheduler
-                * leaves the prior task mm in place as an optimization when
-                * scheduling a kthread.
+                * Skip the CPU if it runs a kernel thread which is not using
+                * a task mm.
                 */
                p = rcu_dereference(cpu_rq(cpu)->curr);
-               if (p->flags & PF_KTHREAD)
+               if (!p->mm)
                        continue;
 
                __cpumask_set_cpu(cpu, tmpmask);
@@ -154,6 +318,7 @@ static int membarrier_private_expedited(int flags, int cpu_id)
                if (!(atomic_read(&mm->membarrier_state) &
                      MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY))
                        return -EPERM;
+               ipi_func = ipi_sync_core;
        } else if (flags == MEMBARRIER_FLAG_RSEQ) {
                if (!IS_ENABLED(CONFIG_RSEQ))
                        return -EINVAL;
@@ -168,7 +333,8 @@ static int membarrier_private_expedited(int flags, int cpu_id)
                        return -EPERM;
        }
 
-       if (atomic_read(&mm->mm_users) == 1 || num_online_cpus() == 1)
+       if (flags != MEMBARRIER_FLAG_SYNC_CORE &&
+           (atomic_read(&mm->mm_users) == 1 || num_online_cpus() == 1))
                return 0;
 
        /*
@@ -187,8 +353,6 @@ static int membarrier_private_expedited(int flags, int cpu_id)
 
                if (cpu_id >= nr_cpu_ids || !cpu_online(cpu_id))
                        goto out;
-               if (cpu_id == raw_smp_processor_id())
-                       goto out;
                rcu_read_lock();
                p = rcu_dereference(cpu_rq(cpu_id)->curr);
                if (!p || p->mm != mm) {
@@ -203,16 +367,6 @@ static int membarrier_private_expedited(int flags, int cpu_id)
                for_each_online_cpu(cpu) {
                        struct task_struct *p;
 
-                       /*
-                        * Skipping the current CPU is OK even through we can be
-                        * migrated at any point. The current CPU, at the point
-                        * where we read raw_smp_processor_id(), is ensured to
-                        * be in program order with respect to the caller
-                        * thread. Therefore, we can skip this CPU from the
-                        * iteration.
-                        */
-                       if (cpu == raw_smp_processor_id())
-                               continue;
                        p = rcu_dereference(cpu_rq(cpu)->curr);
                        if (p && p->mm == mm)
                                __cpumask_set_cpu(cpu, tmpmask);
@@ -220,12 +374,38 @@ static int membarrier_private_expedited(int flags, int cpu_id)
                rcu_read_unlock();
        }
 
-       preempt_disable();
-       if (cpu_id >= 0)
+       if (cpu_id >= 0) {
+               /*
+                * smp_call_function_single() will call ipi_func() if cpu_id
+                * is the calling CPU.
+                */
                smp_call_function_single(cpu_id, ipi_func, NULL, 1);
-       else
-               smp_call_function_many(tmpmask, ipi_func, NULL, 1);
-       preempt_enable();
+       } else {
+               /*
+                * For regular membarrier, we can save a few cycles by
+                * skipping the current cpu -- we're about to do smp_mb()
+                * below, and if we migrate to a different cpu, this cpu
+                * and the new cpu will execute a full barrier in the
+                * scheduler.
+                *
+                * For SYNC_CORE, we do need a barrier on the current cpu --
+                * otherwise, if we are migrated and replaced by a different
+                * task in the same mm just before, during, or after
+                * membarrier, we will end up with some thread in the mm
+                * running without a core sync.
+                *
+                * For RSEQ, don't rseq_preempt() the caller.  User code
+                * is not supposed to issue syscalls at all from inside an
+                * rseq critical section.
+                */
+               if (flags != MEMBARRIER_FLAG_SYNC_CORE) {
+                       preempt_disable();
+                       smp_call_function_many(tmpmask, ipi_func, NULL, true);
+                       preempt_enable();
+               } else {
+                       on_each_cpu_mask(tmpmask, ipi_func, NULL, true);
+               }
+       }
 
 out:
        if (cpu_id < 0)