rcu/segcblist: Add debug checks for segment lengths
This commit adds debug checks near the end of rcu_do_batch() that emit warnings if an empty rcu_segcblist structure has non-zero segment counts, or, conversely, if a non-empty structure has all-zero segment counts. Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org> [ paulmck: Fix queue/segment-length checks. ] Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
Родитель
3afe7fa535
Коммит
b4e6039e8a
|
@ -94,6 +94,18 @@ static long rcu_segcblist_get_seglen(struct rcu_segcblist *rsclp, int seg)
|
|||
return READ_ONCE(rsclp->seglen[seg]);
|
||||
}
|
||||
|
||||
/* Return number of callbacks in segmented callback list by summing seglen. */
|
||||
long rcu_segcblist_n_segment_cbs(struct rcu_segcblist *rsclp)
|
||||
{
|
||||
long len = 0;
|
||||
int i;
|
||||
|
||||
for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++)
|
||||
len += rcu_segcblist_get_seglen(rsclp, i);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Set the length of a segment of the rcu_segcblist structure. */
|
||||
static void rcu_segcblist_set_seglen(struct rcu_segcblist *rsclp, int seg, long v)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,9 @@ static inline long rcu_cblist_n_cbs(struct rcu_cblist *rclp)
|
|||
return READ_ONCE(rclp->len);
|
||||
}
|
||||
|
||||
/* Return number of callbacks in segmented callback list by summing seglen. */
|
||||
long rcu_segcblist_n_segment_cbs(struct rcu_segcblist *rsclp);
|
||||
|
||||
void rcu_cblist_init(struct rcu_cblist *rclp);
|
||||
void rcu_cblist_enqueue(struct rcu_cblist *rclp, struct rcu_head *rhp);
|
||||
void rcu_cblist_flush_enqueue(struct rcu_cblist *drclp,
|
||||
|
|
|
@ -2434,6 +2434,7 @@ int rcutree_dead_cpu(unsigned int cpu)
|
|||
static void rcu_do_batch(struct rcu_data *rdp)
|
||||
{
|
||||
int div;
|
||||
bool __maybe_unused empty;
|
||||
unsigned long flags;
|
||||
const bool offloaded = rcu_segcblist_is_offloaded(&rdp->cblist);
|
||||
struct rcu_head *rhp;
|
||||
|
@ -2548,9 +2549,12 @@ static void rcu_do_batch(struct rcu_data *rdp)
|
|||
* The following usually indicates a double call_rcu(). To track
|
||||
* this down, try building with CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.
|
||||
*/
|
||||
WARN_ON_ONCE(count == 0 && !rcu_segcblist_empty(&rdp->cblist));
|
||||
empty = rcu_segcblist_empty(&rdp->cblist);
|
||||
WARN_ON_ONCE(count == 0 && !empty);
|
||||
WARN_ON_ONCE(!IS_ENABLED(CONFIG_RCU_NOCB_CPU) &&
|
||||
count != 0 && rcu_segcblist_empty(&rdp->cblist));
|
||||
count != 0 && empty);
|
||||
WARN_ON_ONCE(count == 0 && rcu_segcblist_n_segment_cbs(&rdp->cblist) != 0);
|
||||
WARN_ON_ONCE(!empty && rcu_segcblist_n_segment_cbs(&rdp->cblist) == 0);
|
||||
|
||||
rcu_nocb_unlock_irqrestore(rdp, flags);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче