mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									3afe7fa535
								
							
						
					
					
						commit
						b4e6039e8a
					
				
					 3 changed files with 21 additions and 2 deletions
				
			
		| 
						 | 
					@ -94,6 +94,18 @@ static long rcu_segcblist_get_seglen(struct rcu_segcblist *rsclp, int seg)
 | 
				
			||||||
	return READ_ONCE(rsclp->seglen[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. */
 | 
					/* 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)
 | 
					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 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_init(struct rcu_cblist *rclp);
 | 
				
			||||||
void rcu_cblist_enqueue(struct rcu_cblist *rclp, struct rcu_head *rhp);
 | 
					void rcu_cblist_enqueue(struct rcu_cblist *rclp, struct rcu_head *rhp);
 | 
				
			||||||
void rcu_cblist_flush_enqueue(struct rcu_cblist *drclp,
 | 
					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)
 | 
					static void rcu_do_batch(struct rcu_data *rdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int div;
 | 
						int div;
 | 
				
			||||||
 | 
						bool __maybe_unused empty;
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
	const bool offloaded = rcu_segcblist_is_offloaded(&rdp->cblist);
 | 
						const bool offloaded = rcu_segcblist_is_offloaded(&rdp->cblist);
 | 
				
			||||||
	struct rcu_head *rhp;
 | 
						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
 | 
						 * The following usually indicates a double call_rcu().  To track
 | 
				
			||||||
	 * this down, try building with CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.
 | 
						 * 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) &&
 | 
						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);
 | 
						rcu_nocb_unlock_irqrestore(rdp, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue