···661661 * Tracepoint for _rcu_barrier() execution. The string "s" describes662662 * the _rcu_barrier phase:663663 * "Begin": _rcu_barrier() started.664664- * "Check": _rcu_barrier() checking for piggybacking.665664 * "EarlyExit": _rcu_barrier() piggybacked, thus early exit.666665 * "Inc1": _rcu_barrier() piggyback check counter incremented.667666 * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU
+19-53
kernel/rcu/tree.c
···35683568 struct rcu_state *rsp = rdp->rsp;3569356935703570 if (atomic_dec_and_test(&rsp->barrier_cpu_count)) {35713571- _rcu_barrier_trace(rsp, "LastCB", -1, rsp->n_barrier_done);35713571+ _rcu_barrier_trace(rsp, "LastCB", -1, rsp->barrier_sequence);35723572 complete(&rsp->barrier_completion);35733573 } else {35743574- _rcu_barrier_trace(rsp, "CB", -1, rsp->n_barrier_done);35743574+ _rcu_barrier_trace(rsp, "CB", -1, rsp->barrier_sequence);35753575 }35763576}35773577···35833583 struct rcu_state *rsp = type;35843584 struct rcu_data *rdp = raw_cpu_ptr(rsp->rda);3585358535863586- _rcu_barrier_trace(rsp, "IRQ", -1, rsp->n_barrier_done);35863586+ _rcu_barrier_trace(rsp, "IRQ", -1, rsp->barrier_sequence);35873587 atomic_inc(&rsp->barrier_cpu_count);35883588 rsp->call(&rdp->barrier_head, rcu_barrier_callback);35893589}···35963596{35973597 int cpu;35983598 struct rcu_data *rdp;35993599- unsigned long snap = READ_ONCE(rsp->n_barrier_done);36003600- unsigned long snap_done;35993599+ unsigned long s = rcu_seq_snap(&rsp->barrier_sequence);3601360036023602- _rcu_barrier_trace(rsp, "Begin", -1, snap);36013601+ _rcu_barrier_trace(rsp, "Begin", -1, s);3603360236043603 /* Take mutex to serialize concurrent rcu_barrier() requests. */36053604 mutex_lock(&rsp->barrier_mutex);3606360536073607- /*36083608- * Ensure that all prior references, including to ->n_barrier_done,36093609- * are ordered before the _rcu_barrier() machinery.36103610- */36113611- smp_mb(); /* See above block comment. */36123612-36133613- /*36143614- * Recheck ->n_barrier_done to see if others did our work for us.36153615- * This means checking ->n_barrier_done for an even-to-odd-to-even36163616- * transition. The "if" expression below therefore rounds the old36173617- * value up to the next even number and adds two before comparing.36183618- */36193619- snap_done = rsp->n_barrier_done;36203620- _rcu_barrier_trace(rsp, "Check", -1, snap_done);36213621-36223622- /*36233623- * If the value in snap is odd, we needed to wait for the current36243624- * rcu_barrier() to complete, then wait for the next one, in other36253625- * words, we need the value of snap_done to be three larger than36263626- * the value of snap. On the other hand, if the value in snap is36273627- * even, we only had to wait for the next rcu_barrier() to complete,36283628- * in other words, we need the value of snap_done to be only two36293629- * greater than the value of snap. The "(snap + 3) & ~0x1" computes36303630- * this for us (thank you, Linus!).36313631- */36323632- if (ULONG_CMP_GE(snap_done, (snap + 3) & ~0x1)) {36333633- _rcu_barrier_trace(rsp, "EarlyExit", -1, snap_done);36063606+ /* Did someone else do our work for us? */36073607+ if (rcu_seq_done(&rsp->barrier_sequence, s)) {36083608+ _rcu_barrier_trace(rsp, "EarlyExit", -1, rsp->barrier_sequence);36343609 smp_mb(); /* caller's subsequent code after above check. */36353610 mutex_unlock(&rsp->barrier_mutex);36363611 return;36373612 }3638361336393639- /*36403640- * Increment ->n_barrier_done to avoid duplicate work. Use36413641- * WRITE_ONCE() to prevent the compiler from speculating36423642- * the increment to precede the early-exit check.36433643- */36443644- WRITE_ONCE(rsp->n_barrier_done, rsp->n_barrier_done + 1);36453645- WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 1);36463646- _rcu_barrier_trace(rsp, "Inc1", -1, rsp->n_barrier_done);36473647- smp_mb(); /* Order ->n_barrier_done increment with below mechanism. */36143614+ /* Mark the start of the barrier operation. */36153615+ rcu_seq_start(&rsp->barrier_sequence);36163616+ _rcu_barrier_trace(rsp, "Inc1", -1, rsp->barrier_sequence);3648361736493618 /*36503619 * Initialize the count to one rather than to zero in order to···36373668 if (rcu_is_nocb_cpu(cpu)) {36383669 if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) {36393670 _rcu_barrier_trace(rsp, "OfflineNoCB", cpu,36403640- rsp->n_barrier_done);36713671+ rsp->barrier_sequence);36413672 } else {36423673 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,36433643- rsp->n_barrier_done);36743674+ rsp->barrier_sequence);36443675 smp_mb__before_atomic();36453676 atomic_inc(&rsp->barrier_cpu_count);36463677 __call_rcu(&rdp->barrier_head,···36483679 }36493680 } else if (READ_ONCE(rdp->qlen)) {36503681 _rcu_barrier_trace(rsp, "OnlineQ", cpu,36513651- rsp->n_barrier_done);36823682+ rsp->barrier_sequence);36523683 smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);36533684 } else {36543685 _rcu_barrier_trace(rsp, "OnlineNQ", cpu,36553655- rsp->n_barrier_done);36863686+ rsp->barrier_sequence);36563687 }36573688 }36583689 put_online_cpus();···36643695 if (atomic_dec_and_test(&rsp->barrier_cpu_count))36653696 complete(&rsp->barrier_completion);3666369736673667- /* Increment ->n_barrier_done to prevent duplicate work. */36683668- smp_mb(); /* Keep increment after above mechanism. */36693669- WRITE_ONCE(rsp->n_barrier_done, rsp->n_barrier_done + 1);36703670- WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 0);36713671- _rcu_barrier_trace(rsp, "Inc2", -1, rsp->n_barrier_done);36723672- smp_mb(); /* Keep increment before caller's subsequent code. */36733673-36743698 /* Wait for all rcu_barrier_callback() callbacks to be invoked. */36753699 wait_for_completion(&rsp->barrier_completion);37003700+37013701+ /* Mark the end of the barrier operation. */37023702+ _rcu_barrier_trace(rsp, "Inc2", -1, rsp->barrier_sequence);37033703+ rcu_seq_end(&rsp->barrier_sequence);3676370436773705 /* Other rcu_barrier() invocations can now safely proceed. */36783706 mutex_unlock(&rsp->barrier_mutex);
+1-1
kernel/rcu/tree.h
···486486 struct mutex barrier_mutex; /* Guards barrier fields. */487487 atomic_t barrier_cpu_count; /* # CPUs waiting on. */488488 struct completion barrier_completion; /* Wake at barrier end. */489489- unsigned long n_barrier_done; /* ++ at start and end of */489489+ unsigned long barrier_sequence; /* ++ at start and end of */490490 /* _rcu_barrier(). */491491 /* End of fields guarded by barrier_mutex. */492492