rcu: suppress GP start to simplify force_quiescent_state()
cover rcu: suppress GP start to simplify force_quiescent_state()
Hello!
This patch series makes a sequence of changes that prevent a new RCU grace period from starting while force_quiescent_state() is the the process of trying to cause the prior grace period to complete. This simplifies the code and eliminates numerous painful race conditions.
Thanx, Paul
b/include/linux/rcutiny.h | 12 +++ b/include/linux/rcutree.h | 3 b/kernel/rcutorture.c | 80 +++++++++++++++++++++++- b/kernel/rcutree.c | 28 +++++--- b/kernel/rcutree.h | 3 b/kernel/rcutree_plugin.h | 20 +++++- kernel/rcutree.c | 153 +++++++++++++++++++++------------------------- kernel/rcutree.h | 15 ++-- 8 files changed, 211 insertions(+), 103 deletions(-)
PATCH 1/11 rcu: adjust force_quiescent_state() locking, step 1
This causes rnp->lock to be held on entry to force_quiescent_state()'s switch statement. This is a first step towards prohibiting starting grace periods while force_quiescent_state() is executing, which will reduce the number and complexity of races that force_quiescent_state() is involved in.
--- kernel/rcutree.c | 27 ++++++++++++++++++--------- 1 files changed, 18 insertions(+), 9 deletions(-)
kernel/rcutree.c +18 -9
@@ -1204,7 +1204,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) }if (relaxed && (long )(rsp->jiffies_force_qs - jiffies) >=0 ) - goto unlock_ret;/* no emergency and done recently. */ + goto unlock_fqs_ret;/* no emergency and done recently. */ rsp->n_force_qs++;spin_lock (&rnp->lock); lastcomp = rsp->gpnum -1 ;
@@ -1213,31 +1213,32 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++;spin_unlock (&rnp->lock); - goto unlock_ret;/* no GP in progress, time updated. */ + goto unlock_fqs_ret;/* no GP in progress, time updated. */ } -spin_unlock (&rnp->lock);switch (signaled) {case RCU_GP_IDLE :case RCU_GP_INIT : +spin_unlock (&rnp->lock);break ;/* grace period idle or initializing, ignore. */ case RCU_SAVE_DYNTICK : +spin_unlock (&rnp->lock);if (RCU_SIGNAL_INIT !=RCU_SAVE_DYNTICK )break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ if (rcu_process_dyntick (rsp, lastcomp, dyntick_save_progress_counter)) - goto unlock_ret; + goto unlock_fqs_ret; +spin_lock (&rnp->lock);/* fall into next case. */ case RCU_SAVE_COMPLETED :/* Update state, record completion counter. */ forcenow =0 ; -spin_lock (&rnp->lock);if (lastcomp +1 == rsp->gpnum && lastcomp == rsp->completed && rsp->signaled == signaled) {
@@ -1245,23 +1246,31 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->completed_fqs = lastcomp; forcenow = signaled ==RCU_SAVE_COMPLETED ; } -spin_unlock (&rnp->lock); -if (!forcenow) +if (!forcenow) { +spin_unlock (&rnp->lock);break ; + }/* fall into next case. */ case RCU_FORCE_QS :/* Check dyntick-idle state, send IPI to laggarts. */ +spin_unlock (&rnp->lock);if (rcu_process_dyntick (rsp, rsp->completed_fqs, rcu_implicit_dynticks_qs)) - goto unlock_ret; + goto unlock_fqs_ret;/* Leave state in case more forcing is required. */ break ; + +default : + +spin_unlock (&rnp->lock); +WARN_ON_ONCE (1 ); +break ; } -unlock_ret: +unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags); }
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Adjust force_quiescent_state() locking, step 1
Commit-ID: f96e9232e04856c781d4f71923a46dd3f7b429fa Gitweb: http://git.kernel.org/tip/f96e9232e04856c781d4f71923a46dd3f7b429fa Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:00 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:01 +0100
rcu: Adjust force_quiescent_state() locking, step 1
This causes rnp->lock to be held on entry to force_quiescent_state()'s switch statement. This is a first step towards prohibiting starting grace periods while force_quiescent_state() is executing, which will reduce the number and complexity of races that force_quiescent_state() is involved in.
LKML-Reference: <12626465501455-git-send-email->
--- kernel/rcutree.c | 27 ++++++++++++++++++--------- 1 files changed, 18 insertions(+), 9 deletions(-)
kernel/rcutree.c +18 -9
@@ -1204,7 +1204,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) }if (relaxed && (long )(rsp->jiffies_force_qs - jiffies) >=0 ) - goto unlock_ret;/* no emergency and done recently. */ + goto unlock_fqs_ret;/* no emergency and done recently. */ rsp->n_force_qs++;spin_lock (&rnp->lock); lastcomp = rsp->gpnum -1 ;
@@ -1213,31 +1213,32 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++;spin_unlock (&rnp->lock); - goto unlock_ret;/* no GP in progress, time updated. */ + goto unlock_fqs_ret;/* no GP in progress, time updated. */ } -spin_unlock (&rnp->lock);switch (signaled) {case RCU_GP_IDLE :case RCU_GP_INIT : +spin_unlock (&rnp->lock);break ;/* grace period idle or initializing, ignore. */ case RCU_SAVE_DYNTICK : +spin_unlock (&rnp->lock);if (RCU_SIGNAL_INIT !=RCU_SAVE_DYNTICK )break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ if (rcu_process_dyntick (rsp, lastcomp, dyntick_save_progress_counter)) - goto unlock_ret; + goto unlock_fqs_ret; +spin_lock (&rnp->lock);/* fall into next case. */ case RCU_SAVE_COMPLETED :/* Update state, record completion counter. */ forcenow =0 ; -spin_lock (&rnp->lock);if (lastcomp +1 == rsp->gpnum && lastcomp == rsp->completed && rsp->signaled == signaled) {
@@ -1245,23 +1246,31 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->completed_fqs = lastcomp; forcenow = signaled ==RCU_SAVE_COMPLETED ; } -spin_unlock (&rnp->lock); -if (!forcenow) +if (!forcenow) { +spin_unlock (&rnp->lock);break ; + }/* fall into next case. */ case RCU_FORCE_QS :/* Check dyntick-idle state, send IPI to laggarts. */ +spin_unlock (&rnp->lock);if (rcu_process_dyntick (rsp, rsp->completed_fqs, rcu_implicit_dynticks_qs)) - goto unlock_ret; + goto unlock_fqs_ret;/* Leave state in case more forcing is required. */ break ; + +default : + +spin_unlock (&rnp->lock); +WARN_ON_ONCE (1 ); +break ; } -unlock_ret: +unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags); }
PATCH 2/11 rcu: adjust force_quiescent_state() locking, step 2
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
This patch releases rnp->lock after the end of force_quiescent_state()'s switch statement. This is a second step towards prohibiting starting grace periods while force_quiescent_state() is executing, which will reduce the number and complexity of races that force_quiescent_state() is involved in.
--- kernel/rcutree.c | 13 +++---------- 1 files changed, 3 insertions(+), 10 deletions(-)
kernel/rcutree.c +3 -10
@@ -1219,7 +1219,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)case RCU_GP_IDLE :case RCU_GP_INIT : -spin_unlock (&rnp->lock);break ;/* grace period idle or initializing, ignore. */ case RCU_SAVE_DYNTICK :
@@ -1246,10 +1245,8 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->completed_fqs = lastcomp; forcenow = signaled ==RCU_SAVE_COMPLETED ; } -if (!forcenow) { -spin_unlock (&rnp->lock); +if (!forcenow)break ; - }/* fall into next case. */ case RCU_FORCE_QS :
@@ -1262,14 +1259,10 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Leave state in case more forcing is required. */ -break ; - -default : - -spin_unlock (&rnp->lock); -WARN_ON_ONCE (1 ); +spin_lock (&rnp->lock);break ; } +spin_unlock (&rnp->lock); unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags); }
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Adjust force_quiescent_state() locking, step 2
Commit-ID: 559569acf94f538b56bd6eead80b439d6a78cdff Gitweb: http://git.kernel.org/tip/559569acf94f538b56bd6eead80b439d6a78cdff Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:01 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:01 +0100
rcu: Adjust force_quiescent_state() locking, step 2
This patch releases rnp->lock after the end of force_quiescent_state()'s switch statement. This is a second step towards prohibiting starting grace periods while force_quiescent_state() is executing, which will reduce the number and complexity of races that force_quiescent_state() is involved in.
LKML-Reference: <12626465501994-git-send-email->
--- kernel/rcutree.c | 13 +++---------- 1 files changed, 3 insertions(+), 10 deletions(-)
kernel/rcutree.c +3 -10
@@ -1219,7 +1219,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)case RCU_GP_IDLE :case RCU_GP_INIT : -spin_unlock (&rnp->lock);break ;/* grace period idle or initializing, ignore. */ case RCU_SAVE_DYNTICK :
@@ -1246,10 +1245,8 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->completed_fqs = lastcomp; forcenow = signaled ==RCU_SAVE_COMPLETED ; } -if (!forcenow) { -spin_unlock (&rnp->lock); +if (!forcenow)break ; - }/* fall into next case. */ case RCU_FORCE_QS :
@@ -1262,14 +1259,10 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Leave state in case more forcing is required. */ -break ; - -default : - -spin_unlock (&rnp->lock); -WARN_ON_ONCE (1 ); +spin_lock (&rnp->lock);break ; } +spin_unlock (&rnp->lock); unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags); }
PATCH 3/11 rcu: prohibit starting new grace periods while forcing quiescent states
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
Reduce the number and variety of race conditions by prohibiting the start of a new grace period while force_quiescent_state() is active. A new fqs_active flag in the rcu_state structure is used to trace whether or not force_quiescent_state() is active, and this new flag is tested by rcu_start_gp(). If the CPU that closed out the last grace period needs another grace period, this new grace period may be delayed up to one scheduling-clock tick, but it will eventually get started.
--- kernel/rcutree.c | 31 +++++++++++++++++-------------- kernel/rcutree.h | 2 ++ 2 files changed, 19 insertions(+), 14 deletions(-)
kernel/rcutree.c +17 -14
@@ -659,7 +659,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)struct rcu_data *rdp = rsp->rda[smp_processor_id ()];struct rcu_node *rnp =rcu_get_root (rsp); -if (!cpu_needs_another_gp (rsp, rdp)) { +if (!cpu_needs_another_gp (rsp, rdp) || rsp->fqs_active) {if (rnp->completed == rsp->completed) {spin_unlock_irqrestore (&rnp->lock, flags);return ;
@@ -1195,6 +1195,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)struct rcu_node *rnp =rcu_get_root (rsp);u8 signaled;u8 forcenow; +u8 gpdone;if (!rcu_gp_in_progress (rsp))return ;/* No grace period in progress, nothing to force. */
@@ -1206,15 +1207,16 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) (long)(rsp->jiffies_force_qs - jiffies) >= 0) goto unlock_fqs_ret;/* no emergency and done recently. */ rsp->n_force_qs++; -spin_lock (&rnp->lock); +spin_lock (&rnp->lock);/* irqs already disabled */ lastcomp = rsp->gpnum -1 ; signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies +RCU_JIFFIES_TILL_FORCE_QS ;if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++; -spin_unlock (&rnp->lock); +spin_unlock (&rnp->lock);/* irqs remain disabled */ goto unlock_fqs_ret;/* no GP in progress, time updated. */ } + rsp->fqs_active =1 ;switch (signaled) {case RCU_GP_IDLE :case RCU_GP_INIT :
@@ -1223,15 +1225,16 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)case RCU_SAVE_DYNTICK : -spin_unlock (&rnp->lock); +spin_unlock (&rnp->lock);/* irqs remain disabled */ if (RCU_SIGNAL_INIT !=RCU_SAVE_DYNTICK )break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ -if (rcu_process_dyntick (rsp, lastcomp, - dyntick_save_progress_counter)) - goto unlock_fqs_ret; -spin_lock (&rnp->lock); + gpdone =rcu_process_dyntick (rsp, lastcomp, + dyntick_save_progress_counter); +spin_lock (&rnp->lock);/* irqs already disabled */ +if (gpdone) +break ;/* fall into next case. */ case RCU_SAVE_COMPLETED :
@@ -1252,17 +1255,17 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)case RCU_FORCE_QS :/* Check dyntick-idle state, send IPI to laggarts. */ -spin_unlock (&rnp->lock); -if (rcu_process_dyntick (rsp, rsp->completed_fqs, - rcu_implicit_dynticks_qs)) - goto unlock_fqs_ret; +spin_unlock (&rnp->lock);/* irqs remain disabled */ + gpdone =rcu_process_dyntick (rsp, rsp->completed_fqs, + rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */ -spin_lock (&rnp->lock); +spin_lock (&rnp->lock);/* irqs already disabled */ break ; } -spin_unlock (&rnp->lock); + rsp->fqs_active =0 ; +spin_unlock (&rnp->lock);/* irqs remain disabled */ unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags); }
kernel/rcutree.h +2 -0
@@ -277,6 +277,8 @@ struct rcu_state {u8 signaled____cacheline_internodealigned_in_smp ;/* Force QS state. */ +u8 fqs_active;/* force_quiescent_state() */ +/* is running. */ long gpnum;/* Current gp number. */ long completed;/* # of last completed gp. */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Prohibit starting new grace periods while forcing quiescent states
Commit-ID: 07079d5357a4d53c2b13126c4a38fb40e6e04966 Gitweb: http://git.kernel.org/tip/07079d5357a4d53c2b13126c4a38fb40e6e04966 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:02 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:02 +0100
rcu: Prohibit starting new grace periods while forcing quiescent states
Reduce the number and variety of race conditions by prohibiting the start of a new grace period while force_quiescent_state() is active. A new fqs_active flag in the rcu_state structure is used to trace whether or not force_quiescent_state() is active, and this new flag is tested by rcu_start_gp(). If the CPU that closed out the last grace period needs another grace period, this new grace period may be delayed up to one scheduling-clock tick, but it will eventually get started.
LKML-Reference: <126264655052-git-send-email->
--- kernel/rcutree.c | 31 +++++++++++++++++-------------- kernel/rcutree.h | 2 ++ 2 files changed, 19 insertions(+), 14 deletions(-)
kernel/rcutree.c +17 -14
@@ -659,7 +659,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)struct rcu_data *rdp = rsp->rda[smp_processor_id ()];struct rcu_node *rnp =rcu_get_root (rsp); -if (!cpu_needs_another_gp (rsp, rdp)) { +if (!cpu_needs_another_gp (rsp, rdp) || rsp->fqs_active) {if (rnp->completed == rsp->completed) {spin_unlock_irqrestore (&rnp->lock, flags);return ;
@@ -1195,6 +1195,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)struct rcu_node *rnp =rcu_get_root (rsp);u8 signaled;u8 forcenow; +u8 gpdone;if (!rcu_gp_in_progress (rsp))return ;/* No grace period in progress, nothing to force. */
@@ -1206,15 +1207,16 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) (long)(rsp->jiffies_force_qs - jiffies) >= 0) goto unlock_fqs_ret;/* no emergency and done recently. */ rsp->n_force_qs++; -spin_lock (&rnp->lock); +spin_lock (&rnp->lock);/* irqs already disabled */ lastcomp = rsp->gpnum -1 ; signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies +RCU_JIFFIES_TILL_FORCE_QS ;if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++; -spin_unlock (&rnp->lock); +spin_unlock (&rnp->lock);/* irqs remain disabled */ goto unlock_fqs_ret;/* no GP in progress, time updated. */ } + rsp->fqs_active =1 ;switch (signaled) {case RCU_GP_IDLE :case RCU_GP_INIT :
@@ -1223,15 +1225,16 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)case RCU_SAVE_DYNTICK : -spin_unlock (&rnp->lock); +spin_unlock (&rnp->lock);/* irqs remain disabled */ if (RCU_SIGNAL_INIT !=RCU_SAVE_DYNTICK )break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ -if (rcu_process_dyntick (rsp, lastcomp, - dyntick_save_progress_counter)) - goto unlock_fqs_ret; -spin_lock (&rnp->lock); + gpdone =rcu_process_dyntick (rsp, lastcomp, + dyntick_save_progress_counter); +spin_lock (&rnp->lock);/* irqs already disabled */ +if (gpdone) +break ;/* fall into next case. */ case RCU_SAVE_COMPLETED :
@@ -1252,17 +1255,17 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)case RCU_FORCE_QS :/* Check dyntick-idle state, send IPI to laggarts. */ -spin_unlock (&rnp->lock); -if (rcu_process_dyntick (rsp, rsp->completed_fqs, - rcu_implicit_dynticks_qs)) - goto unlock_fqs_ret; +spin_unlock (&rnp->lock);/* irqs remain disabled */ + gpdone =rcu_process_dyntick (rsp, rsp->completed_fqs, + rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */ -spin_lock (&rnp->lock); +spin_lock (&rnp->lock);/* irqs already disabled */ break ; } -spin_unlock (&rnp->lock); + rsp->fqs_active =0 ; +spin_unlock (&rnp->lock);/* irqs remain disabled */ unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags); }
kernel/rcutree.h +2 -0
@@ -277,6 +277,8 @@ struct rcu_state {u8 signaled____cacheline_internodealigned_in_smp ;/* Force QS state. */ +u8 fqs_active;/* force_quiescent_state() */ +/* is running. */ long gpnum;/* Current gp number. */ long completed;/* # of last completed gp. */
PATCH 4/11 rcu: eliminate local variable signaled from force_quiescent_state()
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
Because the root rcu_node lock is held across entry to the switch statement in force_quiescent_state(), it is no longer necessary to snapshot rsp->signaled to a local variable. Eliminate both the snapshotting and the local variable.
--- kernel/rcutree.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
kernel/rcutree.c +3 -6
@@ -1193,7 +1193,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)unsigned long flags;long lastcomp;struct rcu_node *rnp =rcu_get_root (rsp); -u8 signaled;u8 forcenow;u8 gpdone;
@@ -1209,7 +1208,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->n_force_qs++;spin_lock (&rnp->lock);/* irqs already disabled */ lastcomp = rsp->gpnum -1 ; - signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies +RCU_JIFFIES_TILL_FORCE_QS ;if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++;
@@ -1217,7 +1215,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_fqs_ret;/* no GP in progress, time updated. */ } rsp->fqs_active =1 ; -switch (signaled) { +switch (rsp->signaled) {case RCU_GP_IDLE :case RCU_GP_INIT :
@@ -1242,11 +1240,10 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Update state, record completion counter. */ forcenow =0 ;if (lastcomp +1 == rsp->gpnum && - lastcomp == rsp->completed && - rsp->signaled == signaled) { + lastcomp == rsp->completed) { + forcenow = rsp->signaled ==RCU_SAVE_COMPLETED ; rsp->signaled =RCU_FORCE_QS ; rsp->completed_fqs = lastcomp; - forcenow = signaled ==RCU_SAVE_COMPLETED ; }if (!forcenow)break ;
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Eliminate local variable signaled from force_quiescent_state()
Commit-ID: f3a8b5c6aa543bd87764418d63632eb65b80e2f6 Gitweb: http://git.kernel.org/tip/f3a8b5c6aa543bd87764418d63632eb65b80e2f6 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:03 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:02 +0100
rcu: Eliminate local variable signaled from force_quiescent_state()
Because the root rcu_node lock is held across entry to the switch statement in force_quiescent_state(), it is no longer necessary to snapshot rsp->signaled to a local variable. Eliminate both the snapshotting and the local variable.
LKML-Reference: <1262646550602-git-send-email->
--- kernel/rcutree.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
kernel/rcutree.c +3 -6
@@ -1193,7 +1193,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)unsigned long flags;long lastcomp;struct rcu_node *rnp =rcu_get_root (rsp); -u8 signaled;u8 forcenow;u8 gpdone;
@@ -1209,7 +1208,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->n_force_qs++;spin_lock (&rnp->lock);/* irqs already disabled */ lastcomp = rsp->gpnum -1 ; - signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies +RCU_JIFFIES_TILL_FORCE_QS ;if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++;
@@ -1217,7 +1215,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_fqs_ret;/* no GP in progress, time updated. */ } rsp->fqs_active =1 ; -switch (signaled) { +switch (rsp->signaled) {case RCU_GP_IDLE :case RCU_GP_INIT :
@@ -1242,11 +1240,10 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Update state, record completion counter. */ forcenow =0 ;if (lastcomp +1 == rsp->gpnum && - lastcomp == rsp->completed && - rsp->signaled == signaled) { + lastcomp == rsp->completed) { + forcenow = rsp->signaled ==RCU_SAVE_COMPLETED ; rsp->signaled =RCU_FORCE_QS ; rsp->completed_fqs = lastcomp; - forcenow = signaled ==RCU_SAVE_COMPLETED ; }if (!forcenow)break ;
PATCH 5/11 rcu: eliminate local variable lastcomp from force_quiescent_state()
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
Because rsp->fqs_active is set to 1 across force_quiescent_state()'s switch statement, rcu_start_gp() will refrain from starting a new grace period during this time. Therefore, rsp->gpnum is constant, and can be propagated to all uses of lastcomp, eliminating this local variable.
--- kernel/rcutree.c | 10 +++------- kernel/rcutree.h | 2 -- 2 files changed, 3 insertions(+), 9 deletions(-)
kernel/rcutree.c +3 -7
@@ -1191,7 +1191,6 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,static void force_quiescent_state (struct rcu_state *rsp,int relaxed) {unsigned long flags; -long lastcomp;struct rcu_node *rnp =rcu_get_root (rsp);u8 forcenow;u8 gpdone;
@@ -1207,7 +1206,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_fqs_ret;/* no emergency and done recently. */ rsp->n_force_qs++;spin_lock (&rnp->lock);/* irqs already disabled */ - lastcomp = rsp->gpnum -1 ; rsp->jiffies_force_qs = jiffies +RCU_JIFFIES_TILL_FORCE_QS ;if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++;
@@ -1228,7 +1226,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone =rcu_process_dyntick (rsp, lastcomp, + gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ if (gpdone)
@@ -1239,11 +1237,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Update state, record completion counter. */ forcenow =0 ; -if (lastcomp +1 == rsp->gpnum && - lastcomp == rsp->completed) { +if (rsp->gpnum -1 == rsp->completed) { forcenow = rsp->signaled ==RCU_SAVE_COMPLETED ; rsp->signaled =RCU_FORCE_QS ; - rsp->completed_fqs = lastcomp; }if (!forcenow)break ;
@@ -1253,7 +1249,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ - gpdone =rcu_process_dyntick (rsp, rsp->completed_fqs, + gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
kernel/rcutree.h +0 -2
@@ -296,8 +296,6 @@ struct rcu_state {long orphan_qlen;/* Number of orphaned cbs. */ spinlock_t fqslock;/* Only one task forcing */ /* quiescent states. */ -long completed_fqs;/* Value of completed @ snap. */ -/* Protected by fqslock. */ unsigned long jiffies_force_qs;/* Time at which to invoke */ /* force_quiescent_state(). */ unsigned long n_force_qs;/* Number of calls to */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Eliminate local variable lastcomp from force_quiescent_state()
Commit-ID: 39c0bbfc07c6e28db7346d0e11106f2d045d3035 Gitweb: http://git.kernel.org/tip/39c0bbfc07c6e28db7346d0e11106f2d045d3035 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:04 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:03 +0100
rcu: Eliminate local variable lastcomp from force_quiescent_state()
Because rsp->fqs_active is set to 1 across force_quiescent_state()'s switch statement, rcu_start_gp() will refrain from starting a new grace period during this time. Therefore, rsp->gpnum is constant, and can be propagated to all uses of lastcomp, eliminating this local variable.
LKML-Reference: <12626465502985-git-send-email->
--- kernel/rcutree.c | 10 +++------- kernel/rcutree.h | 2 -- 2 files changed, 3 insertions(+), 9 deletions(-)
kernel/rcutree.c +3 -7
@@ -1191,7 +1191,6 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,static void force_quiescent_state (struct rcu_state *rsp,int relaxed) {unsigned long flags; -long lastcomp;struct rcu_node *rnp =rcu_get_root (rsp);u8 forcenow;u8 gpdone;
@@ -1207,7 +1206,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_fqs_ret;/* no emergency and done recently. */ rsp->n_force_qs++;spin_lock (&rnp->lock);/* irqs already disabled */ - lastcomp = rsp->gpnum -1 ; rsp->jiffies_force_qs = jiffies +RCU_JIFFIES_TILL_FORCE_QS ;if (!rcu_gp_in_progress (rsp)) { rsp->n_force_qs_ngp++;
@@ -1228,7 +1226,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone =rcu_process_dyntick (rsp, lastcomp, + gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ if (gpdone)
@@ -1239,11 +1237,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Update state, record completion counter. */ forcenow =0 ; -if (lastcomp +1 == rsp->gpnum && - lastcomp == rsp->completed) { +if (rsp->gpnum -1 == rsp->completed) { forcenow = rsp->signaled ==RCU_SAVE_COMPLETED ; rsp->signaled =RCU_FORCE_QS ; - rsp->completed_fqs = lastcomp; }if (!forcenow)break ;
@@ -1253,7 +1249,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ - gpdone =rcu_process_dyntick (rsp, rsp->completed_fqs, + gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
kernel/rcutree.h +0 -2
@@ -296,8 +296,6 @@ struct rcu_state {long orphan_qlen;/* Number of orphaned cbs. */ spinlock_t fqslock;/* Only one task forcing */ /* quiescent states. */ -long completed_fqs;/* Value of completed @ snap. */ -/* Protected by fqslock. */ unsigned long jiffies_force_qs;/* Time at which to invoke */ /* force_quiescent_state(). */ unsigned long n_force_qs;/* Number of calls to */
PATCH 6/11 rcu: eliminate second argument of rcu_process_dyntick()
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
At this point, the second argument to all calls to rcu_process_dyntick() is a function of the same field of the structure passed in as the first argument, namely, rsp->gpnum-1. So propagate rsp->gpnum-1 to all uses of the second argument within rcu_process_dyntick() and then eliminate the second argument.
--- kernel/rcutree.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-)
kernel/rcutree.c +5 -6
@@ -1147,7 +1147,7 @@ void rcu_check_callbacks(int cpu, int user)* Returns 1 if the current grace period ends while scanning (possibly * because we made it end). */ -static int rcu_process_dyntick (struct rcu_state *rsp,long lastcomp, +static int rcu_process_dyntick (struct rcu_state *rsp,int (*f)(struct rcu_data *)) {unsigned long bit;
@@ -1159,7 +1159,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,rcu_for_each_leaf_node (rsp, rnp) { mask =0 ;spin_lock_irqsave (&rnp->lock, flags); -if (rnp->completed != lastcomp) { +if (rnp->completed != rsp->gpnum -1 ) {spin_unlock_irqrestore (&rnp->lock, flags);return 1 ; }
@@ -1173,7 +1173,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,if ((rnp->qsmask & bit) !=0 &&f (rsp->rda[cpu])) mask |= bit; } -if (mask !=0 && rnp->completed == lastcomp) { +if (mask !=0 && rnp->completed == rsp->gpnum -1 ) {/* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp (mask, rsp, rnp, flags);
@@ -1226,7 +1226,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , + gpdone =rcu_process_dyntick (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ if (gpdone)
@@ -1249,8 +1249,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ - gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , - rcu_implicit_dynticks_qs); + gpdone =rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Eliminate second argument of rcu_process_dyntick()
Commit-ID: eb1ba45f1e7f6e626fefc063b340c7cbec9bd8c7 Gitweb: http://git.kernel.org/tip/eb1ba45f1e7f6e626fefc063b340c7cbec9bd8c7 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:05 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:03 +0100
rcu: Eliminate second argument of rcu_process_dyntick()
At this point, the second argument to all calls to rcu_process_dyntick() is a function of the same field of the structure passed in as the first argument, namely, rsp->gpnum-1.
So propagate rsp->gpnum-1 to all uses of the second argument
within rcu_process_dyntick() and then eliminate the second argument.
LKML-Reference: <12626465503786-git-send-email->
--- kernel/rcutree.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-)
kernel/rcutree.c +5 -6
@@ -1147,7 +1147,7 @@ void rcu_check_callbacks(int cpu, int user)* Returns 1 if the current grace period ends while scanning (possibly * because we made it end). */ -static int rcu_process_dyntick (struct rcu_state *rsp,long lastcomp, +static int rcu_process_dyntick (struct rcu_state *rsp,int (*f)(struct rcu_data *)) {unsigned long bit;
@@ -1159,7 +1159,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,rcu_for_each_leaf_node (rsp, rnp) { mask =0 ;spin_lock_irqsave (&rnp->lock, flags); -if (rnp->completed != lastcomp) { +if (rnp->completed != rsp->gpnum -1 ) {spin_unlock_irqrestore (&rnp->lock, flags);return 1 ; }
@@ -1173,7 +1173,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,if ((rnp->qsmask & bit) !=0 &&f (rsp->rda[cpu])) mask |= bit; } -if (mask !=0 && rnp->completed == lastcomp) { +if (mask !=0 && rnp->completed == rsp->gpnum -1 ) {/* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp (mask, rsp, rnp, flags);
@@ -1226,7 +1226,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , + gpdone =rcu_process_dyntick (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ if (gpdone)
@@ -1249,8 +1249,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ - gpdone =rcu_process_dyntick (rsp, rsp->gpnum -1 , - rcu_implicit_dynticks_qs); + gpdone =rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
PATCH 7/11 rcu: eliminate rcu_process_dyntick() return value
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
Because a new grace period cannot start while we are executing within the force_quiescent_state() function's switch statement, if any test within that switch statement or within any function called from that switch statement shows that the current grace period has ended, we can safely re-do that test any time before we leave the switch statement. This means that we no longer need a return value from rcu_process_dyntick(), as we can simply invoke rcu_gp_in_progress() to check whether the old grace period has finished -- there is no longer any need to worry about whether or not a new grace period has been started.
--- kernel/rcutree.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-)
kernel/rcutree.c +6 -11
@@ -1144,11 +1144,9 @@ void rcu_check_callbacks(int cpu, int user)/* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. -* Returns 1 if the current grace period ends while scanning (possibly -* because we made it end). */ -static int rcu_process_dyntick (struct rcu_state *rsp, -int (*f)(struct rcu_data *)) +static void rcu_process_dyntick (struct rcu_state *rsp, +int (*f)(struct rcu_data *)) {unsigned long bit;int cpu;
@@ -1161,7 +1159,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp,spin_lock_irqsave (&rnp->lock, flags);if (rnp->completed != rsp->gpnum -1 ) {spin_unlock_irqrestore (&rnp->lock, flags); -return 1 ; +return ; }if (rnp->qsmask ==0 ) {spin_unlock_irqrestore (&rnp->lock, flags);
@@ -1181,7 +1179,6 @@ static int rcu_process_dyntick(struct rcu_state *rsp, }spin_unlock_irqrestore (&rnp->lock, flags); } -return 0 ; }/*
@@ -1193,7 +1190,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)unsigned long flags;struct rcu_node *rnp =rcu_get_root (rsp);u8 forcenow; -u8 gpdone;if (!rcu_gp_in_progress (rsp))return ;/* No grace period in progress, nothing to force. */
@@ -1226,10 +1222,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone =rcu_process_dyntick (rsp, - dyntick_save_progress_counter); +rcu_process_dyntick (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ -if (gpdone) +if (!rcu_gp_in_progress (rsp))break ;/* fall into next case. */
@@ -1249,7 +1244,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ - gpdone =rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs); +rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Eliminate rcu_process_dyntick() return value
Commit-ID: 0f10dc826646134dce3e5751512b87d30f3903e4 Gitweb: http://git.kernel.org/tip/0f10dc826646134dce3e5751512b87d30f3903e4 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:06 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:03 +0100
rcu: Eliminate rcu_process_dyntick() return value
Because a new grace period cannot start while we are executing within the force_quiescent_state() function's switch statement, if any test within that switch statement or within any function called from that switch statement shows that the current grace period has ended, we can safely re-do that test any time before we leave the switch statement. This means that we no longer need a return value from rcu_process_dyntick(), as we can simply invoke rcu_gp_in_progress() to check whether the old grace period has finished -- there is no longer any need to worry about whether or not a new grace period has been started.
LKML-Reference: <12626465501857-git-send-email->
--- kernel/rcutree.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-)
kernel/rcutree.c +6 -11
@@ -1144,11 +1144,9 @@ void rcu_check_callbacks(int cpu, int user)/* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. -* Returns 1 if the current grace period ends while scanning (possibly -* because we made it end). */ -static int rcu_process_dyntick (struct rcu_state *rsp, -int (*f)(struct rcu_data *)) +static void rcu_process_dyntick (struct rcu_state *rsp, +int (*f)(struct rcu_data *)) {unsigned long bit;int cpu;
@@ -1161,7 +1159,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp,spin_lock_irqsave (&rnp->lock, flags);if (rnp->completed != rsp->gpnum -1 ) {spin_unlock_irqrestore (&rnp->lock, flags); -return 1 ; +return ; }if (rnp->qsmask ==0 ) {spin_unlock_irqrestore (&rnp->lock, flags);
@@ -1181,7 +1179,6 @@ static int rcu_process_dyntick(struct rcu_state *rsp, }spin_unlock_irqrestore (&rnp->lock, flags); } -return 0 ; }/*
@@ -1193,7 +1190,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)unsigned long flags;struct rcu_node *rnp =rcu_get_root (rsp);u8 forcenow; -u8 gpdone;if (!rcu_gp_in_progress (rsp))return ;/* No grace period in progress, nothing to force. */
@@ -1226,10 +1222,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone =rcu_process_dyntick (rsp, - dyntick_save_progress_counter); +rcu_process_dyntick (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ -if (gpdone) +if (!rcu_gp_in_progress (rsp))break ;/* fall into next case. */
@@ -1249,7 +1244,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ - gpdone =rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs); +rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
PATCH 8/11 rcu: remove leg of force_quiescent_state() switch statement
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
The comparisons of rsp->gpnum nad rsp->completed in rcu_process_dyntick() and force_quiescent_state() can be replaced by the much more clear rcu_gp_in_progress() predicate function. After doing this, it becomes clear that the RCU_SAVE_COMPLETED leg of the force_quiescent_state() function's switch statement is almost completely a no-op. A small change to the RCU_SAVE_DYNTICK leg renders it a complete no-op, after which it can be removed. Doing so also eliminates the forcenow local variable from force_quiescent_state().
--- kernel/rcutree.c | 22 +++++----------------- kernel/rcutree.h | 5 ++--- 2 files changed, 7 insertions(+), 20 deletions(-)
kernel/rcutree.c +5 -17
@@ -1144,6 +1144,7 @@ void rcu_check_callbacks(int cpu, int user)/* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. +* The caller must have suppressed start of new grace periods. */ static void rcu_process_dyntick (struct rcu_state *rsp,int (*f)(struct rcu_data *))
@@ -1157,7 +1158,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp,rcu_for_each_leaf_node (rsp, rnp) { mask =0 ;spin_lock_irqsave (&rnp->lock, flags); -if (rnp->completed != rsp->gpnum -1 ) { +if (!rcu_gp_in_progress (rsp)) {spin_unlock_irqrestore (&rnp->lock, flags);return ; }
@@ -1171,7 +1172,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp,if ((rnp->qsmask & bit) !=0 &&f (rsp->rda[cpu])) mask |= bit; } -if (mask !=0 && rnp->completed == rsp->gpnum -1 ) { +if (mask !=0 &&rcu_gp_in_progress (rsp)) {/* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp (mask, rsp, rnp, flags);
@@ -1189,7 +1190,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) {unsigned long flags;struct rcu_node *rnp =rcu_get_root (rsp); -u8 forcenow;if (!rcu_gp_in_progress (rsp))return ;/* No grace period in progress, nothing to force. */
@@ -1224,21 +1224,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Record dyntick-idle state. */ rcu_process_dyntick (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ -if (!rcu_gp_in_progress (rsp)) -break ; -/* fall into next case. */ - -case RCU_SAVE_COMPLETED : - -/* Update state, record completion counter. */ - forcenow =0 ; -if (rsp->gpnum -1 == rsp->completed) { - forcenow = rsp->signaled ==RCU_SAVE_COMPLETED ; +if (rcu_gp_in_progress (rsp)) rsp->signaled =RCU_FORCE_QS ; - } -if (!forcenow) -break ; -/* fall into next case. */ +break ;case RCU_FORCE_QS :
kernel/rcutree.h +2 -3
@@ -237,12 +237,11 @@ struct rcu_data {#define RCU_GP_IDLE 0/* No grace period in progress. */ #define RCU_GP_INIT 1/* Grace period being initialized. */ #define RCU_SAVE_DYNTICK 2/* Need to scan dyntick state. */ -#define RCU_SAVE_COMPLETED 3/* Need to save rsp->completed. */ -#define RCU_FORCE_QS 4/* Need to force quiescent state. */ +#define RCU_FORCE_QS 3/* Need to force quiescent state. */ #ifdef CONFIG_NO_HZ #define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK#else /* #ifdef CONFIG_NO_HZ */ -#define RCU_SIGNAL_INIT RCU_SAVE_COMPLETED +#define RCU_SIGNAL_INIT RCU_FORCE_QS#endif /* #else #ifdef CONFIG_NO_HZ */ #define RCU_JIFFIES_TILL_FORCE_QS 3/* for rsp->jiffies_force_qs */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Remove leg of force_quiescent_state() switch statement
Commit-ID: ee47eb9f4da6f44af965d6d049e77ee8c8a4b822 Gitweb: http://git.kernel.org/tip/ee47eb9f4da6f44af965d6d049e77ee8c8a4b822 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:07 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:04 +0100
rcu: Remove leg of force_quiescent_state() switch statement
The comparisons of rsp->gpnum nad rsp->completed in rcu_process_dyntick() and force_quiescent_state() can be replaced by the much more clear rcu_gp_in_progress() predicate function. After doing this, it becomes clear that the RCU_SAVE_COMPLETED leg of the force_quiescent_state() function's switch statement is almost completely a no-op. A small change to the RCU_SAVE_DYNTICK leg renders it a complete no-op, after which it can be removed. Doing so also eliminates the forcenow local variable from force_quiescent_state().
LKML-Reference: <12626465501781-git-send-email->
--- kernel/rcutree.c | 22 +++++----------------- kernel/rcutree.h | 5 ++--- 2 files changed, 7 insertions(+), 20 deletions(-)
kernel/rcutree.c +5 -17
@@ -1144,6 +1144,7 @@ void rcu_check_callbacks(int cpu, int user)/* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. +* The caller must have suppressed start of new grace periods. */ static void rcu_process_dyntick (struct rcu_state *rsp,int (*f)(struct rcu_data *))
@@ -1157,7 +1158,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp,rcu_for_each_leaf_node (rsp, rnp) { mask =0 ;spin_lock_irqsave (&rnp->lock, flags); -if (rnp->completed != rsp->gpnum -1 ) { +if (!rcu_gp_in_progress (rsp)) {spin_unlock_irqrestore (&rnp->lock, flags);return ; }
@@ -1171,7 +1172,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp,if ((rnp->qsmask & bit) !=0 &&f (rsp->rda[cpu])) mask |= bit; } -if (mask !=0 && rnp->completed == rsp->gpnum -1 ) { +if (mask !=0 &&rcu_gp_in_progress (rsp)) {/* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp (mask, rsp, rnp, flags);
@@ -1189,7 +1190,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) {unsigned long flags;struct rcu_node *rnp =rcu_get_root (rsp); -u8 forcenow;if (!rcu_gp_in_progress (rsp))return ;/* No grace period in progress, nothing to force. */
@@ -1224,21 +1224,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Record dyntick-idle state. */ rcu_process_dyntick (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ -if (!rcu_gp_in_progress (rsp)) -break ; -/* fall into next case. */ - -case RCU_SAVE_COMPLETED : - -/* Update state, record completion counter. */ - forcenow =0 ; -if (rsp->gpnum -1 == rsp->completed) { - forcenow = rsp->signaled ==RCU_SAVE_COMPLETED ; +if (rcu_gp_in_progress (rsp)) rsp->signaled =RCU_FORCE_QS ; - } -if (!forcenow) -break ; -/* fall into next case. */ +break ;case RCU_FORCE_QS :
kernel/rcutree.h +2 -3
@@ -237,12 +237,11 @@ struct rcu_data {#define RCU_GP_IDLE 0/* No grace period in progress. */ #define RCU_GP_INIT 1/* Grace period being initialized. */ #define RCU_SAVE_DYNTICK 2/* Need to scan dyntick state. */ -#define RCU_SAVE_COMPLETED 3/* Need to save rsp->completed. */ -#define RCU_FORCE_QS 4/* Need to force quiescent state. */ +#define RCU_FORCE_QS 3/* Need to force quiescent state. */ #ifdef CONFIG_NO_HZ #define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK#else /* #ifdef CONFIG_NO_HZ */ -#define RCU_SIGNAL_INIT RCU_SAVE_COMPLETED +#define RCU_SIGNAL_INIT RCU_FORCE_QS#endif /* #else #ifdef CONFIG_NO_HZ */ #define RCU_JIFFIES_TILL_FORCE_QS 3/* for rsp->jiffies_force_qs */
PATCH 9/11 rcu: remove redundant grace-period check
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
The rcu_process_dyntick() function checks twice for the end of the current grace period. However, it holds the current rcu_node structure's ->lock field throughout, and doesn't get to the second call to rcu_gp_in_progress() unless there is at least one CPU corresponding to this rcu_node structure that has not yet checked in for the current grace period, which would prevent the current grace period from ending. So the current grace period cannot have ended, and the second check is redundant, so remove it.
Also, given that this function is used even with !CONFIG_NO_HZ, its name is quite misleading. Change from rcu_process_dyntick() to force_qs_rnp().
--- kernel/rcutree.c | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-)
kernel/rcutree.c +4 -5
@@ -1146,8 +1146,7 @@ void rcu_check_callbacks(int cpu, int user)* have not yet encountered a quiescent state, using the function specified. * The caller must have suppressed start of new grace periods. */ -static void rcu_process_dyntick (struct rcu_state *rsp, -int (*f)(struct rcu_data *)) +static void force_qs_rnp (struct rcu_state *rsp,int (*f)(struct rcu_data *)) {unsigned long bit;int cpu;
@@ -1172,7 +1171,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp,if ((rnp->qsmask & bit) !=0 &&f (rsp->rda[cpu])) mask |= bit; } -if (mask !=0 &&rcu_gp_in_progress (rsp)) { +if (mask !=0 ) {/* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp (mask, rsp, rnp, flags);
@@ -1222,7 +1221,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ -rcu_process_dyntick (rsp, dyntick_save_progress_counter); +force_qs_rnp (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ if (rcu_gp_in_progress (rsp)) rsp->signaled =RCU_FORCE_QS ;
@@ -1232,7 +1231,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ -rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs); +force_qs_rnp (rsp, rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Remove redundant grace-period check
Commit-ID: 45f014c52eef022873b19d6a20eb0ec9668f2b09 Gitweb: http://git.kernel.org/tip/45f014c52eef022873b19d6a20eb0ec9668f2b09 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:08 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:04 +0100
rcu: Remove redundant grace-period check
The rcu_process_dyntick() function checks twice for the end of the current grace period. However, it holds the current rcu_node structure's ->lock field throughout, and doesn't get to the second call to rcu_gp_in_progress() unless there is at least one CPU corresponding to this rcu_node structure that has not yet checked in for the current grace period, which would prevent the current grace period from ending. So the current grace period cannot have ended, and the second check is redundant, so remove it.
Also, given that this function is used even with !CONFIG_NO_HZ, its name is quite misleading. Change from rcu_process_dyntick() to force_qs_rnp().
LKML-Reference: <1262646550562-git-send-email->
--- kernel/rcutree.c | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-)
kernel/rcutree.c +4 -5
@@ -1146,8 +1146,7 @@ void rcu_check_callbacks(int cpu, int user)* have not yet encountered a quiescent state, using the function specified. * The caller must have suppressed start of new grace periods. */ -static void rcu_process_dyntick (struct rcu_state *rsp, -int (*f)(struct rcu_data *)) +static void force_qs_rnp (struct rcu_state *rsp,int (*f)(struct rcu_data *)) {unsigned long bit;int cpu;
@@ -1172,7 +1171,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp,if ((rnp->qsmask & bit) !=0 &&f (rsp->rda[cpu])) mask |= bit; } -if (mask !=0 &&rcu_gp_in_progress (rsp)) { +if (mask !=0 ) {/* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp (mask, rsp, rnp, flags);
@@ -1222,7 +1221,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ;/* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ -rcu_process_dyntick (rsp, dyntick_save_progress_counter); +force_qs_rnp (rsp, dyntick_save_progress_counter);spin_lock (&rnp->lock);/* irqs already disabled */ if (rcu_gp_in_progress (rsp)) rsp->signaled =RCU_FORCE_QS ;
@@ -1232,7 +1231,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)/* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock (&rnp->lock);/* irqs remain disabled */ -rcu_process_dyntick (rsp, rcu_implicit_dynticks_qs); +force_qs_rnp (rsp, rcu_implicit_dynticks_qs);/* Leave state in case more forcing is required. */
PATCH 10/11 rcu: make force_quiescent_state() start grace period if needed
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
Grace periods cannot be started while force_quiescent_state() is active. This is OK in that the affected CPUs will try again later, but it does induce needless grace-period delays. This patch causes rcu_start_gp() to record a failed attempt to start a grace period. When force_quiescent_state() prepares to return, it then starts the grace period if there was such a failed attempt.
--- kernel/rcutree.c | 8 ++++++++ kernel/rcutree.h | 5 +++++ 2 files changed, 13 insertions(+), 0 deletions(-)
kernel/rcutree.c +8 -0
@@ -660,6 +660,8 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)struct rcu_node *rnp =rcu_get_root (rsp);if (!cpu_needs_another_gp (rsp, rdp) || rsp->fqs_active) { +if (cpu_needs_another_gp (rsp, rdp)) + rsp->fqs_need_gp =1 ;if (rnp->completed == rsp->completed) {spin_unlock_irqrestore (&rnp->lock, flags);return ;
@@ -1239,6 +1241,12 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ; } rsp->fqs_active =0 ; +if (rsp->fqs_need_gp) { +spin_unlock (&rsp->fqslock);/* irqs remain disabled */ + rsp->fqs_need_gp =0 ; +rcu_start_gp (rsp, flags);/* releases rnp->lock */ +return ; + }spin_unlock (&rnp->lock);/* irqs remain disabled */ unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags);
kernel/rcutree.h +5 -0
@@ -278,6 +278,11 @@ struct rcu_state {/* Force QS state. */ u8 fqs_active;/* force_quiescent_state() */ /* is running. */ +u8 fqs_need_gp;/* A CPU was prevented from */ +/* starting a new grace */ +/* period because */ +/* force_quiescent_state() */ +/* was running. */ long gpnum;/* Current gp number. */ long completed;/* # of last completed gp. */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Make force_quiescent_state() start grace period if needed
Commit-ID: 46a1e34eda805501a8b32f26394faa435149f6d1 Gitweb: http://git.kernel.org/tip/46a1e34eda805501a8b32f26394faa435149f6d1 Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:09 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:05 +0100
rcu: Make force_quiescent_state() start grace period if needed
Grace periods cannot be started while force_quiescent_state() is active. This is OK in that the affected CPUs will try again later, but it does induce needless grace-period delays. This patch causes rcu_start_gp() to record a failed attempt to start a grace period. When force_quiescent_state() prepares to return, it then starts the grace period if there was such a failed attempt.
LKML-Reference: <12626465501854-git-send-email->
--- kernel/rcutree.c | 8 ++++++++ kernel/rcutree.h | 5 +++++ 2 files changed, 13 insertions(+), 0 deletions(-)
kernel/rcutree.c +8 -0
@@ -660,6 +660,8 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)struct rcu_node *rnp =rcu_get_root (rsp);if (!cpu_needs_another_gp (rsp, rdp) || rsp->fqs_active) { +if (cpu_needs_another_gp (rsp, rdp)) + rsp->fqs_need_gp =1 ;if (rnp->completed == rsp->completed) {spin_unlock_irqrestore (&rnp->lock, flags);return ;
@@ -1239,6 +1241,12 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)break ; } rsp->fqs_active =0 ; +if (rsp->fqs_need_gp) { +spin_unlock (&rsp->fqslock);/* irqs remain disabled */ + rsp->fqs_need_gp =0 ; +rcu_start_gp (rsp, flags);/* releases rnp->lock */ +return ; + }spin_unlock (&rnp->lock);/* irqs remain disabled */ unlock_fqs_ret:spin_unlock_irqrestore (&rsp->fqslock, flags);
kernel/rcutree.h +5 -0
@@ -278,6 +278,11 @@ struct rcu_state {/* Force QS state. */ u8 fqs_active;/* force_quiescent_state() */ /* is running. */ +u8 fqs_need_gp;/* A CPU was prevented from */ +/* starting a new grace */ +/* period because */ +/* force_quiescent_state() */ +/* was running. */ long gpnum;/* Current gp number. */ long completed;/* # of last completed gp. */
PATCH 11/11 rcu: add force_quiescent_state() testing to rcutorture
In reply to Paul E. McKenneyFrom: Paul E. McKenney <[email protected]>
Add force_quiescent_state() testing to rcutorture, with a separate thread that repeatedly invokes force_quiescent_state() in bursts. This can greatly increase the probability of encountering certain types of race conditions.
--- include/linux/rcutiny.h | 12 +++++++ include/linux/rcutree.h | 3 ++ kernel/rcutorture.c | 80 +++++++++++++++++++++++++++++++++++++++++++++- kernel/rcutree.c | 18 ++++++++++ kernel/rcutree_plugin.h | 19 +++++++++++ 5 files changed, 130 insertions(+), 2 deletions(-)
include/linux/rcutiny.h +12 -0
@@ -62,6 +62,18 @@ static inline long rcu_batches_completed_bh(void)extern int rcu_expedited_torture_stats (char *page); +static inline void rcu_force_quiescent_state (void ) +{ +} + +static inline void rcu_bh_force_quiescent_state (void ) +{ +} + +static inline void rcu_sched_force_quiescent_state (void ) +{ +} +#define synchronize_rcu synchronize_schedstatic inline void synchronize_rcu_expedited (void )
include/linux/rcutree.h +3 -0
@@ -88,6 +88,9 @@ extern void rcu_check_callbacks(int cpu, int user);extern long rcu_batches_completed (void );extern long rcu_batches_completed_bh (void );extern long rcu_batches_completed_sched (void ); +extern void rcu_force_quiescent_state (void ); +extern void rcu_bh_force_quiescent_state (void ); +extern void rcu_sched_force_quiescent_state (void );#ifdef CONFIG_NO_HZ void rcu_enter_nohz (void );
kernel/rcutorture.c +78 -2
184 lines not on this page · raw message
kernel/rcutree.c +18 -0
@@ -157,6 +157,24 @@ long rcu_batches_completed_bh(void)EXPORT_SYMBOL_GPL (rcu_batches_completed_bh);/* +* Force a quiescent state for RCU BH. +*/ +void rcu_bh_force_quiescent_state (void ) +{ +force_quiescent_state (&rcu_bh_state,0 ); +} +EXPORT_SYMBOL_GPL (rcu_bh_force_quiescent_state); + +/* +* Force a quiescent state for RCU-sched. +*/ +void rcu_sched_force_quiescent_state (void ) +{ +force_quiescent_state (&rcu_sched_state,0 ); +} +EXPORT_SYMBOL_GPL (rcu_sched_force_quiescent_state); + +/* * Does the CPU have callbacks ready to be invoked? */ static int
kernel/rcutree_plugin.h +19 -0
@@ -62,6 +62,15 @@ long rcu_batches_completed(void)EXPORT_SYMBOL_GPL (rcu_batches_completed);/* +* Force a quiescent state for preemptible RCU. +*/ +void rcu_force_quiescent_state (void ) +{ +force_quiescent_state (&rcu_preempt_state,0 ); +} +EXPORT_SYMBOL_GPL (rcu_force_quiescent_state); + +/* * Record a preemptable-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is * not in a quiescent state. There might be any number of tasks blocked
@@ -713,6 +722,16 @@ long rcu_batches_completed(void)EXPORT_SYMBOL_GPL (rcu_batches_completed);/* +* Force a quiescent state for RCU, which, because there is no preemptible +* RCU, becomes the same as rcu-sched. +*/ +void rcu_force_quiescent_state (void ) +{ +rcu_sched_force_quiescent_state (); +} +EXPORT_SYMBOL_GPL (rcu_force_quiescent_state); + +/* * Because preemptable RCU does not exist, we never have to check for * CPUs being in quiescent states. */
Signature · 1 line
1.5.2.5
[tip:core/rcu] rcu: Add force_quiescent_state() testing to rcutorture
Commit-ID: bf66f18e79e34c421bbd8f6511e2c556b779df2f Gitweb: http://git.kernel.org/tip/bf66f18e79e34c421bbd8f6511e2c556b779df2f Author: Paul E. McKenney <[email protected]> AuthorDate: Mon, 4 Jan 2010 15:09:10 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 13 Jan 2010 09:06:05 +0100
rcu: Add force_quiescent_state() testing to rcutorture
Add force_quiescent_state() testing to rcutorture, with a separate thread that repeatedly invokes force_quiescent_state() in bursts. This can greatly increase the probability of encountering certain types of race conditions.
LKML-Reference: <1262646551116-git-send-email->
--- include/linux/rcutiny.h | 12 +++++++ include/linux/rcutree.h | 3 ++ kernel/rcutorture.c | 80 +++++++++++++++++++++++++++++++++++++++++++++- kernel/rcutree.c | 18 ++++++++++ kernel/rcutree_plugin.h | 19 +++++++++++ 5 files changed, 130 insertions(+), 2 deletions(-)
include/linux/rcutiny.h +12 -0
@@ -62,6 +62,18 @@ static inline long rcu_batches_completed_bh(void)extern int rcu_expedited_torture_stats (char *page); +static inline void rcu_force_quiescent_state (void ) +{ +} + +static inline void rcu_bh_force_quiescent_state (void ) +{ +} + +static inline void rcu_sched_force_quiescent_state (void ) +{ +} +#define synchronize_rcu synchronize_schedstatic inline void synchronize_rcu_expedited (void )
include/linux/rcutree.h +3 -0
@@ -99,6 +99,9 @@ extern void rcu_check_callbacks(int cpu, int user);extern long rcu_batches_completed (void );extern long rcu_batches_completed_bh (void );extern long rcu_batches_completed_sched (void ); +extern void rcu_force_quiescent_state (void ); +extern void rcu_bh_force_quiescent_state (void ); +extern void rcu_sched_force_quiescent_state (void );#ifdef CONFIG_NO_HZ void rcu_enter_nohz (void );
kernel/rcutorture.c +78 -2
184 lines not on this page · raw message
kernel/rcutree.c +18 -0
@@ -157,6 +157,24 @@ long rcu_batches_completed_bh(void)EXPORT_SYMBOL_GPL (rcu_batches_completed_bh);/* +* Force a quiescent state for RCU BH. +*/ +void rcu_bh_force_quiescent_state (void ) +{ +force_quiescent_state (&rcu_bh_state,0 ); +} +EXPORT_SYMBOL_GPL (rcu_bh_force_quiescent_state); + +/* +* Force a quiescent state for RCU-sched. +*/ +void rcu_sched_force_quiescent_state (void ) +{ +force_quiescent_state (&rcu_sched_state,0 ); +} +EXPORT_SYMBOL_GPL (rcu_sched_force_quiescent_state); + +/* * Does the CPU have callbacks ready to be invoked? */ static int
kernel/rcutree_plugin.h +19 -0
@@ -62,6 +62,15 @@ long rcu_batches_completed(void)EXPORT_SYMBOL_GPL (rcu_batches_completed);/* +* Force a quiescent state for preemptible RCU. +*/ +void rcu_force_quiescent_state (void ) +{ +force_quiescent_state (&rcu_preempt_state,0 ); +} +EXPORT_SYMBOL_GPL (rcu_force_quiescent_state); + +/* * Record a preemptable-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is * not in a quiescent state. There might be any number of tasks blocked
@@ -713,6 +722,16 @@ long rcu_batches_completed(void)EXPORT_SYMBOL_GPL (rcu_batches_completed);/* +* Force a quiescent state for RCU, which, because there is no preemptible +* RCU, becomes the same as rcu-sched. +*/ +void rcu_force_quiescent_state (void ) +{ +rcu_sched_force_quiescent_state (); +} +EXPORT_SYMBOL_GPL (rcu_force_quiescent_state); + +/* * Because preemptable RCU does not exist, we never have to check for * CPUs being in quiescent states. */