We are going to use igrab everywhere we want to acquire a live inode. Update it to do a refcount_inc_not_zero on the i_count, and if successful grab an reference to i_obj_count. Add a comment explaining why we do this and the safety. Signed-off-by: Josef Bacik --- fs/inode.c | 26 +++++++++++++------------- include/linux/fs.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 0be1c137bf1e..66402786cf8f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1632,20 +1632,20 @@ EXPORT_SYMBOL(iunique); struct inode *igrab(struct inode *inode) { + lockdep_assert_not_held(&inode->i_lock); + + inode = inode_tryget(inode); + if (!inode) + return NULL; + + /* + * If this inode is on the LRU, take it off so that we can re-run the + * LRU logic on the next iput(). + */ spin_lock(&inode->i_lock); - if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) { - __iget(inode); - inode_lru_list_del(inode); - spin_unlock(&inode->i_lock); - } else { - spin_unlock(&inode->i_lock); - /* - * Handle the case where s_op->clear_inode is not been - * called yet, and somebody is calling igrab - * while the inode is getting freed. - */ - inode = NULL; - } + inode_lru_list_del(inode); + spin_unlock(&inode->i_lock); + return inode; } EXPORT_SYMBOL(igrab); diff --git a/include/linux/fs.h b/include/linux/fs.h index fc23e37ca250..b13d057ad0d7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3393,6 +3393,36 @@ static inline unsigned int iobj_count_read(const struct inode *inode) return refcount_read(&inode->i_obj_count); } +static inline struct inode *inode_tryget(struct inode *inode) +{ + /* + * We are using inode_tryget() because we're interested in getting a + * live reference to the inode, which is ->i_count. Normally we would + * grab i_obj_count first, as it is the higher priority reference. + * However we're only interested in making sure we have a live inode, + * and we know that if we get a reference for i_count then we can safely + * acquire i_obj_count because we always drop i_obj_count after dropping + * an i_count reference. + * + * This is meant to be used either in a place where we have an existing + * i_obj_count reference on the inode, or under rcu_read_lock() so we + * know we're safe in accessing this inode still. + */ + VFS_WARN_ON_ONCE(!iobj_count_read(inode) && !rcu_read_lock_held()); + + if (refcount_inc_not_zero(&inode->i_count)) { + iobj_get(inode); + return inode; + } + + /* + * If we failed to increment the reference count, then the + * inode is being freed or has been freed. We return NULL + * in this case. + */ + return NULL; +} + /* * inode->i_lock must be held */ -- 2.49.0