提交 ccc89aba 编写于 作者: D Darrick J. Wong 提交者: Zheng Zengkai

xfs: refactor the inode recycling code

mainline-inclusion
from mainline-v5.13-rc4
commit ff7bebeb
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I4KIAO
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ff7bebeb91f8cc2e26e7dabbf301da5ec0e9328c

-------------------------------------------------

Hoist the code in xfs_iget_cache_hit that restores the VFS inode state
to an xfs_inode that was previously vfs-destroyed.  The next patch will
add a new set of state flags, so we need the helper to avoid
duplication.
Signed-off-by: NDarrick J. Wong <djwong@kernel.org>
Reviewed-by: NDave Chinner <dchinner@redhat.com>
Signed-off-by: NLihong Kou <koulihong@huawei.com>
Reviewed-by: NZhang Yi <yi.zhang@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 5dc41107
...@@ -354,14 +354,14 @@ xfs_reinit_inode( ...@@ -354,14 +354,14 @@ xfs_reinit_inode(
struct xfs_mount *mp, struct xfs_mount *mp,
struct inode *inode) struct inode *inode)
{ {
int error; int error;
uint32_t nlink = inode->i_nlink; uint32_t nlink = inode->i_nlink;
uint32_t generation = inode->i_generation; uint32_t generation = inode->i_generation;
uint64_t version = inode_peek_iversion(inode); uint64_t version = inode_peek_iversion(inode);
umode_t mode = inode->i_mode; umode_t mode = inode->i_mode;
dev_t dev = inode->i_rdev; dev_t dev = inode->i_rdev;
kuid_t uid = inode->i_uid; kuid_t uid = inode->i_uid;
kgid_t gid = inode->i_gid; kgid_t gid = inode->i_gid;
error = inode_init_always(mp->m_super, inode); error = inode_init_always(mp->m_super, inode);
...@@ -375,6 +375,74 @@ xfs_reinit_inode( ...@@ -375,6 +375,74 @@ xfs_reinit_inode(
return error; return error;
} }
/*
* Carefully nudge an inode whose VFS state has been torn down back into a
* usable state. Drops the i_flags_lock and the rcu read lock.
*/
static int
xfs_iget_recycle(
struct xfs_perag *pag,
struct xfs_inode *ip) __releases(&ip->i_flags_lock)
{
struct xfs_mount *mp = ip->i_mount;
struct inode *inode = VFS_I(ip);
int error;
trace_xfs_iget_recycle(ip);
/*
* We need to make it look like the inode is being reclaimed to prevent
* the actual reclaim workers from stomping over us while we recycle
* the inode. We can't clear the radix tree tag yet as it requires
* pag_ici_lock to be held exclusive.
*/
ip->i_flags |= XFS_IRECLAIM;
spin_unlock(&ip->i_flags_lock);
rcu_read_unlock();
ASSERT(!rwsem_is_locked(&inode->i_rwsem));
error = xfs_reinit_inode(mp, inode);
if (error) {
bool wake;
/*
* Re-initializing the inode failed, and we are in deep
* trouble. Try to re-add it to the reclaim list.
*/
rcu_read_lock();
spin_lock(&ip->i_flags_lock);
wake = !!__xfs_iflags_test(ip, XFS_INEW);
ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
if (wake)
wake_up_bit(&ip->i_flags, __XFS_INEW_BIT);
ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
spin_unlock(&ip->i_flags_lock);
rcu_read_unlock();
trace_xfs_iget_recycle_fail(ip);
return error;
}
spin_lock(&pag->pag_ici_lock);
spin_lock(&ip->i_flags_lock);
/*
* Clear the per-lifetime state in the inode as we are now effectively
* a new inode and need to return to the initial state before reuse
* occurs.
*/
ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS;
ip->i_flags |= XFS_INEW;
xfs_perag_clear_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
XFS_ICI_RECLAIM_TAG);
inode->i_state = I_NEW;
spin_unlock(&ip->i_flags_lock);
spin_unlock(&pag->pag_ici_lock);
return 0;
}
/* /*
* If we are allocating a new inode, then check what was returned is * If we are allocating a new inode, then check what was returned is
* actually a free, empty inode. If we are not allocating an inode, * actually a free, empty inode. If we are not allocating an inode,
...@@ -449,7 +517,7 @@ xfs_iget_cache_hit( ...@@ -449,7 +517,7 @@ xfs_iget_cache_hit(
/* /*
* If we are racing with another cache hit that is currently * If we are racing with another cache hit that is currently
* instantiating this inode or currently recycling it out of * instantiating this inode or currently recycling it out of
* reclaimabe state, wait for the initialisation to complete * reclaimable state, wait for the initialisation to complete
* before continuing. * before continuing.
* *
* XXX(hch): eventually we should do something equivalent to * XXX(hch): eventually we should do something equivalent to
...@@ -471,64 +539,16 @@ xfs_iget_cache_hit( ...@@ -471,64 +539,16 @@ xfs_iget_cache_hit(
if (error) if (error)
goto out_error; goto out_error;
/*
* If IRECLAIMABLE is set, we've torn down the VFS inode already.
* Need to carefully get it back into useable state.
*/
if (ip->i_flags & XFS_IRECLAIMABLE) { if (ip->i_flags & XFS_IRECLAIMABLE) {
trace_xfs_iget_reclaim(ip);
if (flags & XFS_IGET_INCORE) { if (flags & XFS_IGET_INCORE) {
error = -EAGAIN; error = -EAGAIN;
goto out_error; goto out_error;
} }
/* /* Drops i_flags_lock and RCU read lock. */
* We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode error = xfs_iget_recycle(pag, ip);
* from stomping over us while we recycle the inode. We can't if (error)
* clear the radix tree reclaimable tag yet as it requires return error;
* pag_ici_lock to be held exclusive.
*/
ip->i_flags |= XFS_IRECLAIM;
spin_unlock(&ip->i_flags_lock);
rcu_read_unlock();
ASSERT(!rwsem_is_locked(&inode->i_rwsem));
error = xfs_reinit_inode(mp, inode);
if (error) {
bool wake;
/*
* Re-initializing the inode failed, and we are in deep
* trouble. Try to re-add it to the reclaim list.
*/
rcu_read_lock();
spin_lock(&ip->i_flags_lock);
wake = !!__xfs_iflags_test(ip, XFS_INEW);
ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
if (wake)
wake_up_bit(&ip->i_flags, __XFS_INEW_BIT);
ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
trace_xfs_iget_reclaim_fail(ip);
goto out_error;
}
spin_lock(&pag->pag_ici_lock);
spin_lock(&ip->i_flags_lock);
/*
* Clear the per-lifetime state in the inode as we are now
* effectively a new inode and need to return to the initial
* state before reuse occurs.
*/
ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS;
ip->i_flags |= XFS_INEW;
xfs_perag_clear_inode_tag(pag,
XFS_INO_TO_AGINO(pag->pag_mount, ino),
XFS_ICI_RECLAIM_TAG);
inode->i_state = I_NEW;
spin_unlock(&ip->i_flags_lock);
spin_unlock(&pag->pag_ici_lock);
} else { } else {
/* If the VFS inode is being torn down, pause and try again. */ /* If the VFS inode is being torn down, pause and try again. */
if (!igrab(inode)) { if (!igrab(inode)) {
...@@ -558,7 +578,6 @@ xfs_iget_cache_hit( ...@@ -558,7 +578,6 @@ xfs_iget_cache_hit(
return error; return error;
} }
static int static int
xfs_iget_cache_miss( xfs_iget_cache_miss(
struct xfs_mount *mp, struct xfs_mount *mp,
......
...@@ -613,8 +613,8 @@ DEFINE_EVENT(xfs_inode_class, name, \ ...@@ -613,8 +613,8 @@ DEFINE_EVENT(xfs_inode_class, name, \
TP_PROTO(struct xfs_inode *ip), \ TP_PROTO(struct xfs_inode *ip), \
TP_ARGS(ip)) TP_ARGS(ip))
DEFINE_INODE_EVENT(xfs_iget_skip); DEFINE_INODE_EVENT(xfs_iget_skip);
DEFINE_INODE_EVENT(xfs_iget_reclaim); DEFINE_INODE_EVENT(xfs_iget_recycle);
DEFINE_INODE_EVENT(xfs_iget_reclaim_fail); DEFINE_INODE_EVENT(xfs_iget_recycle_fail);
DEFINE_INODE_EVENT(xfs_iget_hit); DEFINE_INODE_EVENT(xfs_iget_hit);
DEFINE_INODE_EVENT(xfs_iget_miss); DEFINE_INODE_EVENT(xfs_iget_miss);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册