History

srcu: Use invalid initial value for srcu_node GP sequence numbers

Currently, tree SRCU relies on the srcu_node structures being initialized at the same time that the srcu_struct itself is initialized, and thus use the initial grace-period sequence number as the initial value for the srcu_node structure's ->srcu_have_cbs[] and ->srcu_gp_seq_needed_exp fields. Although this has a high probability of also working when the srcu_node array is allocated and initialized at some random later time, it would be better to avoid leaving such things to chance. This commit therefore initializes these fields with 0x2, which is a recognizable invalid value. It then adds the required checks for this invalid value in order to avoid confusion on long-running kernels (especially those on 32-bit systems) that allocate and initialize srcu_node arrays late in life.

Paul E. McKenney committed 4 years ago

Commit cbdc98e1 parent aeb9b391 file · +27 −9Browse files

Unified · Split

kernel/rcu/srcutree.c+27−9
@@ -107,6 +107,18 @@ static void init_srcu_struct_data(struct srcu_struct *ssp) · 106 unmodified lines
107 }107 }
108}108}
109 109
110/* Invalid seq state, used during snp node initialization */
111#define SRCU_SNP_INIT_SEQ 0x2
112
113/*
114 * Check whether sequence number corresponding to snp node,
115 * is invalid.
116 */
117static inline bool srcu_invl_snp_seq(unsigned long s)
118{
119 return rcu_seq_state(s) == SRCU_SNP_INIT_SEQ;
120}
121
110/*122/*
111 * Allocated and initialize SRCU combining tree. Returns @true if123 * Allocated and initialize SRCU combining tree. Returns @true if
112 * allocation succeeded and @false otherwise.124 * allocation succeeded and @false otherwise.
@@ -139,10 +151,10 @@ static bool init_srcu_struct_nodes(struct srcu_struct *ssp) · 26 unmodified lines
139 WARN_ON_ONCE(ARRAY_SIZE(snp->srcu_have_cbs) !=151 WARN_ON_ONCE(ARRAY_SIZE(snp->srcu_have_cbs) !=
140 ARRAY_SIZE(snp->srcu_data_have_cbs));152 ARRAY_SIZE(snp->srcu_data_have_cbs));
141 for (i = 0; i < ARRAY_SIZE(snp->srcu_have_cbs); i++) {153 for (i = 0; i < ARRAY_SIZE(snp->srcu_have_cbs); i++) {
142 snp->srcu_have_cbs[i] = 0;154 snp->srcu_have_cbs[i] = SRCU_SNP_INIT_SEQ;
143 snp->srcu_data_have_cbs[i] = 0;155 snp->srcu_data_have_cbs[i] = 0;
144 }156 }
145 snp->srcu_gp_seq_needed_exp = 0;157 snp->srcu_gp_seq_needed_exp = SRCU_SNP_INIT_SEQ;
146 snp->grplo = -1;158 snp->grplo = -1;
147 snp->grphi = -1;159 snp->grphi = -1;
148 if (snp == &ssp->node[0]) {160 if (snp == &ssp->node[0]) {
@@ -386,8 +398,7 @@ static bool srcu_readers_active(struct srcu_struct *ssp) · 237 unmodified lines
386 */398 */
387static unsigned long srcu_get_delay(struct srcu_struct *ssp)399static unsigned long srcu_get_delay(struct srcu_struct *ssp)
388{400{
389 if (ULONG_CMP_LT(READ_ONCE(ssp->srcu_gp_seq),401 if (ULONG_CMP_LT(READ_ONCE(ssp->srcu_gp_seq), READ_ONCE(ssp->srcu_gp_seq_needed_exp)))
390 READ_ONCE(ssp->srcu_gp_seq_needed_exp)))
391 return 0;402 return 0;
392 return SRCU_INTERVAL;403 return SRCU_INTERVAL;
393}404}
@@ -561,6 +572,7 @@ static void srcu_gp_end(struct srcu_struct *ssp) · 167 unmodified lines
561 int idx;572 int idx;
562 unsigned long mask;573 unsigned long mask;
563 struct srcu_data *sdp;574 struct srcu_data *sdp;
575 unsigned long sgsne;
564 struct srcu_node *snp;576 struct srcu_node *snp;
565 int ss_state;577 int ss_state;
566 578
@@ -594,7 +606,8 @@ static void srcu_gp_end(struct srcu_struct *ssp) · 27 unmodified lines
594 cbs = snp->srcu_have_cbs[idx] == gpseq;606 cbs = snp->srcu_have_cbs[idx] == gpseq;
595 snp->srcu_have_cbs[idx] = gpseq;607 snp->srcu_have_cbs[idx] = gpseq;
596 rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1);608 rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1);
597 if (ULONG_CMP_LT(snp->srcu_gp_seq_needed_exp, gpseq))609 sgsne = snp->srcu_gp_seq_needed_exp;
610 if (srcu_invl_snp_seq(sgsne) || ULONG_CMP_LT(sgsne, gpseq))
598 WRITE_ONCE(snp->srcu_gp_seq_needed_exp, gpseq);611 WRITE_ONCE(snp->srcu_gp_seq_needed_exp, gpseq);
599 mask = snp->srcu_data_have_cbs[idx];612 mask = snp->srcu_data_have_cbs[idx];
600 snp->srcu_data_have_cbs[idx] = 0;613 snp->srcu_data_have_cbs[idx] = 0;
@@ -652,14 +665,17 @@ static void srcu_funnel_exp_start(struct srcu_struct *ssp, struct srcu_node *snp · 51 unmodified lines
652 unsigned long s)665 unsigned long s)
653{666{
654 unsigned long flags;667 unsigned long flags;
668 unsigned long sgsne;
655 669
656 if (snp)670 if (snp)
657 for (; snp != NULL; snp = snp->srcu_parent) {671 for (; snp != NULL; snp = snp->srcu_parent) {
672 sgsne = READ_ONCE(snp->srcu_gp_seq_needed_exp);
658 if (rcu_seq_done(&ssp->srcu_gp_seq, s) ||673 if (rcu_seq_done(&ssp->srcu_gp_seq, s) ||
659 ULONG_CMP_GE(READ_ONCE(snp->srcu_gp_seq_needed_exp), s))674 (!srcu_invl_snp_seq(sgsne) && ULONG_CMP_GE(sgsne, s)))
660 return;675 return;
661 spin_lock_irqsave_rcu_node(snp, flags);676 spin_lock_irqsave_rcu_node(snp, flags);
662 if (ULONG_CMP_GE(snp->srcu_gp_seq_needed_exp, s)) {677 sgsne = snp->srcu_gp_seq_needed_exp;
678 if (!srcu_invl_snp_seq(sgsne) && ULONG_CMP_GE(sgsne, s)) {
663 spin_unlock_irqrestore_rcu_node(snp, flags);679 spin_unlock_irqrestore_rcu_node(snp, flags);
664 return;680 return;
665 }681 }
@@ -687,6 +703,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp, · 21 unmodified lines
687{703{
688 unsigned long flags;704 unsigned long flags;
689 int idx = rcu_seq_ctr(s) % ARRAY_SIZE(sdp->mynode->srcu_have_cbs);705 int idx = rcu_seq_ctr(s) % ARRAY_SIZE(sdp->mynode->srcu_have_cbs);
706 unsigned long sgsne;
690 struct srcu_node *snp;707 struct srcu_node *snp;
691 struct srcu_node *snp_leaf = smp_load_acquire(&sdp->mynode);708 struct srcu_node *snp_leaf = smp_load_acquire(&sdp->mynode);
692 unsigned long snp_seq;709 unsigned long snp_seq;
@@ -698,7 +715,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp, · 5 unmodified lines
698 return; /* GP already done and CBs recorded. */715 return; /* GP already done and CBs recorded. */
699 spin_lock_irqsave_rcu_node(snp, flags);716 spin_lock_irqsave_rcu_node(snp, flags);
700 snp_seq = snp->srcu_have_cbs[idx];717 snp_seq = snp->srcu_have_cbs[idx];
701 if (ULONG_CMP_GE(snp_seq, s)) {718 if (!srcu_invl_snp_seq(snp_seq) && ULONG_CMP_GE(snp_seq, s)) {
702 if (snp == snp_leaf && snp_seq == s)719 if (snp == snp_leaf && snp_seq == s)
703 snp->srcu_data_have_cbs[idx] |= sdp->grpmask;720 snp->srcu_data_have_cbs[idx] |= sdp->grpmask;
704 spin_unlock_irqrestore_rcu_node(snp, flags);721 spin_unlock_irqrestore_rcu_node(snp, flags);
@@ -713,7 +730,8 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp, · 8 unmodified lines
713 snp->srcu_have_cbs[idx] = s;730 snp->srcu_have_cbs[idx] = s;
714 if (snp == snp_leaf)731 if (snp == snp_leaf)
715 snp->srcu_data_have_cbs[idx] |= sdp->grpmask;732 snp->srcu_data_have_cbs[idx] |= sdp->grpmask;
716 if (!do_norm && ULONG_CMP_LT(snp->srcu_gp_seq_needed_exp, s))733 sgsne = snp->srcu_gp_seq_needed_exp;
734 if (!do_norm && (srcu_invl_snp_seq(sgsne) || ULONG_CMP_LT(sgsne, s)))
717 WRITE_ONCE(snp->srcu_gp_seq_needed_exp, s);735 WRITE_ONCE(snp->srcu_gp_seq_needed_exp, s);
718 spin_unlock_irqrestore_rcu_node(snp, flags);736 spin_unlock_irqrestore_rcu_node(snp, flags);
719 }737 }