Commit aaa2cacf authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

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: default avatarTejun 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: default avatarJens Axboe <axboe@fb.com>
parent 5cb8b824
...@@ -285,7 +285,8 @@ locked_inode_to_wb_and_lock_list(struct inode *inode) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment