On Mon, Oct 26, 2020 at 01:32:12AM +0100, Frederic Weisbecker wrote: > On Wed, Oct 21, 2020 at 03:08:09PM -0400, Joel Fernandes (Google) wrote: > > @@ -307,6 +317,7 @@ void rcu_segcblist_extract_done_cbs(struct > > rcu_segcblist *rsclp, > > > > if (!rcu_segcblist_ready_cbs(rsclp)) > > return; /* Nothing to do. */ > > + rclp->len = rcu_segcblist_get_seglen(rsclp, RCU_DONE_TAIL); > > I realize, doesn't it break the unsegmented count in srcu_invoke_callbacks() ? > > It still does rcu_segcblist_insert_count(), so it adds zero to rsclp->len > which thus doesn't get cleared and probably keeps growing.
You are right. This needs changing :-( Its my fault, I did not test SRCU torture tests which are indeed failing. I fixed it with the diff attached to the end of the email and will test it more. > > *rclp->tail = rsclp->head; > > WRITE_ONCE(rsclp->head, *rsclp->tails[RCU_DONE_TAIL]); > > WRITE_ONCE(*rsclp->tails[RCU_DONE_TAIL], NULL); > > @@ -314,6 +325,7 @@ void rcu_segcblist_extract_done_cbs(struct > > rcu_segcblist *rsclp, > > for (i = RCU_CBLIST_NSEGS - 1; i >= RCU_DONE_TAIL; i--) > > if (rsclp->tails[i] == rsclp->tails[RCU_DONE_TAIL]) > > WRITE_ONCE(rsclp->tails[i], &rsclp->head); > > + rcu_segcblist_set_seglen(rsclp, RCU_DONE_TAIL, 0); > > } > > > > /* > > @@ -330,11 +342,16 @@ void rcu_segcblist_extract_pend_cbs(struct > > rcu_segcblist *rsclp, > > > > if (!rcu_segcblist_pend_cbs(rsclp)) > > return; /* Nothing to do. */ > > + rclp->len = rcu_segcblist_get_seglen(rsclp, RCU_WAIT_TAIL) + > > + rcu_segcblist_get_seglen(rsclp, RCU_NEXT_READY_TAIL) + > > + rcu_segcblist_get_seglen(rsclp, RCU_NEXT_TAIL); > > *rclp->tail = *rsclp->tails[RCU_DONE_TAIL]; > > rclp->tail = rsclp->tails[RCU_NEXT_TAIL]; > > WRITE_ONCE(*rsclp->tails[RCU_DONE_TAIL], NULL); > > - for (i = RCU_DONE_TAIL + 1; i < RCU_CBLIST_NSEGS; i++) > > + for (i = RCU_DONE_TAIL + 1; i < RCU_CBLIST_NSEGS; i++) { > > WRITE_ONCE(rsclp->tails[i], rsclp->tails[RCU_DONE_TAIL]); > > + rcu_segcblist_set_seglen(rsclp, i, 0); > > You seem to have forgotten the suggestion? > > rclp->len += rcu_segcblist_get_seglen(rsclp, i) I decided to keep it this way as I did not see how it could be better. You mentioned you are Ok with either option so I left it as is. Thanks! - Joel ---8<----------------------- diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index 0f23d20d485a..79b7081143a7 100644 --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c @@ -1160,6 +1160,7 @@ static void srcu_advance_state(struct srcu_struct *ssp) */ static void srcu_invoke_callbacks(struct work_struct *work) { + long len; bool more; struct rcu_cblist ready_cbs; struct rcu_head *rhp; @@ -1182,6 +1183,7 @@ static void srcu_invoke_callbacks(struct work_struct *work) /* We are on the job! Extract and invoke ready callbacks. */ sdp->srcu_cblist_invoking = true; rcu_segcblist_extract_done_cbs(&sdp->srcu_cblist, &ready_cbs); + len = ready_cbs.len; spin_unlock_irq_rcu_node(sdp); rhp = rcu_cblist_dequeue(&ready_cbs); for (; rhp != NULL; rhp = rcu_cblist_dequeue(&ready_cbs)) { @@ -1190,13 +1192,14 @@ static void srcu_invoke_callbacks(struct work_struct *work) rhp->func(rhp); local_bh_enable(); } + WARN_ON_ONCE(ready_cbs.len); /* * Update counts, accelerate new callbacks, and if needed, * schedule another round of callback invocation. */ spin_lock_irq_rcu_node(sdp); - rcu_segcblist_insert_count(&sdp->srcu_cblist, &ready_cbs); + rcu_segcblist_add_len(&sdp->srcu_cblist, -len); (void)rcu_segcblist_accelerate(&sdp->srcu_cblist, rcu_seq_snap(&ssp->srcu_gp_seq)); sdp->srcu_cblist_invoking = false;