forked from mirrors/linux
		
	writeback: add lockdep annotation to inode_to_wb()
With the previous three patches, all operations which acquire wb from
inode are either under one of inode->i_lock, mapping->tree_lock or
wb->list_lock or protected by unlocked_inode_to_wb transaction.  This
will be depended upon by foreign inode wb switching.
This patch adds lockdep assertion to inode_to_wb() so that usages
outside the above list locks can be caught easily.  There are three
exceptions.
* locked_inode_to_wb_and_lock_list() is holding wb->list_lock but the
  wb may not be the inode's.  Ensuring that is the function's role
  after all.  Updated to deref inode->i_wb directly.
* inode_wb_stat_unlocked_begin() is usually protected by combination
  of !I_WB_SWITCH and rcu_read_lock().  Updated to deref inode->i_wb
  directly.
* inode_congested() wants to test whether inode->i_wb is set before
  starting the transaction.  Added inode_to_wb_is_valid() which tests
  inode->i_wb directly.
v5: might_lock() removed.  It annotates that the lock is grabbed w/
    irq enabled which isn't the case and triggering lockdep warning
    spuriously.
v4: might_lock() added to unlocked_inode_to_wb_begin().
v3: inode_congested() conversion added.
v2: locked_inode_to_wb_and_lock_list() was missing in the first
    version.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jan Kara <jack@suse.cz>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Greg Thelen <gthelen@google.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
			
			
This commit is contained in:
		
							parent
							
								
									5cb8b8241e
								
							
						
					
					
						commit
						aaa2cacf81
					
				
					 2 changed files with 35 additions and 4 deletions
				
			
		|  | @ -285,7 +285,8 @@ locked_inode_to_wb_and_lock_list(struct inode *inode) | ||||||
| 		spin_lock(&wb->list_lock); | 		spin_lock(&wb->list_lock); | ||||||
| 		wb_put(wb);		/* not gonna deref it anymore */ | 		wb_put(wb);		/* not gonna deref it anymore */ | ||||||
| 
 | 
 | ||||||
| 		if (likely(wb == inode_to_wb(inode))) | 		/* i_wb may have changed inbetween, can't use inode_to_wb() */ | ||||||
|  | 		if (likely(wb == inode->i_wb)) | ||||||
| 			return wb;	/* @inode already has ref */ | 			return wb;	/* @inode already has ref */ | ||||||
| 
 | 
 | ||||||
| 		spin_unlock(&wb->list_lock); | 		spin_unlock(&wb->list_lock); | ||||||
|  | @ -622,7 +623,7 @@ int inode_congested(struct inode *inode, int cong_bits) | ||||||
| 	 * Once set, ->i_wb never becomes NULL while the inode is alive. | 	 * Once set, ->i_wb never becomes NULL while the inode is alive. | ||||||
| 	 * Start transaction iff ->i_wb is visible. | 	 * Start transaction iff ->i_wb is visible. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (inode && inode_to_wb(inode)) { | 	if (inode && inode_to_wb_is_valid(inode)) { | ||||||
| 		struct bdi_writeback *wb; | 		struct bdi_writeback *wb; | ||||||
| 		bool locked, congested; | 		bool locked, congested; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -321,14 +321,34 @@ wb_get_create_current(struct backing_dev_info *bdi, gfp_t gfp) | ||||||
| 	return wb; | 	return wb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * inode_to_wb_is_valid - test whether an inode has a wb associated | ||||||
|  |  * @inode: inode of interest | ||||||
|  |  * | ||||||
|  |  * Returns %true if @inode has a wb associated.  May be called without any | ||||||
|  |  * locking. | ||||||
|  |  */ | ||||||
|  | static inline bool inode_to_wb_is_valid(struct inode *inode) | ||||||
|  | { | ||||||
|  | 	return inode->i_wb; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * inode_to_wb - determine the wb of an inode |  * inode_to_wb - determine the wb of an inode | ||||||
|  * @inode: inode of interest |  * @inode: inode of interest | ||||||
|  * |  * | ||||||
|  * Returns the wb @inode is currently associated with. |  * Returns the wb @inode is currently associated with.  The caller must be | ||||||
|  |  * holding either @inode->i_lock, @inode->i_mapping->tree_lock, or the | ||||||
|  |  * associated wb's list_lock. | ||||||
|  */ |  */ | ||||||
| static inline struct bdi_writeback *inode_to_wb(struct inode *inode) | static inline struct bdi_writeback *inode_to_wb(struct inode *inode) | ||||||
| { | { | ||||||
|  | #ifdef CONFIG_LOCKDEP | ||||||
|  | 	WARN_ON_ONCE(debug_locks && | ||||||
|  | 		     (!lockdep_is_held(&inode->i_lock) && | ||||||
|  | 		      !lockdep_is_held(&inode->i_mapping->tree_lock) && | ||||||
|  | 		      !lockdep_is_held(&inode->i_wb->list_lock))); | ||||||
|  | #endif | ||||||
| 	return inode->i_wb; | 	return inode->i_wb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -360,7 +380,12 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(*lockedp)) | 	if (unlikely(*lockedp)) | ||||||
| 		spin_lock_irq(&inode->i_mapping->tree_lock); | 		spin_lock_irq(&inode->i_mapping->tree_lock); | ||||||
| 	return inode_to_wb(inode); | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock. | ||||||
|  | 	 * inode_to_wb() will bark.  Deref directly. | ||||||
|  | 	 */ | ||||||
|  | 	return inode->i_wb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -459,6 +484,11 @@ wb_get_create_current(struct backing_dev_info *bdi, gfp_t gfp) | ||||||
| 	return &bdi->wb; | 	return &bdi->wb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline bool inode_to_wb_is_valid(struct inode *inode) | ||||||
|  | { | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline struct bdi_writeback *inode_to_wb(struct inode *inode) | static inline struct bdi_writeback *inode_to_wb(struct inode *inode) | ||||||
| { | { | ||||||
| 	return &inode_to_bdi(inode)->wb; | 	return &inode_to_bdi(inode)->wb; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Tejun Heo
						Tejun Heo