xfs: when replaying bmap operations, don't let unlinked inodes get reaped
Log recovery will iget an inode to replay BUI items and iput the inode when it's done. Unfortunately, if the inode was unlinked, the iput will see that i_nlink == 0 and decide to truncate & free the inode, which prevents us from replaying subsequent BUIs. We can't skip the BUIs because we have to replay all the redo items to ensure that atomic operations complete. Since unlinked inode recovery will reap the inode anyway, we can safely introduce a new inode flag to indicate that an inode is in this 'unlinked recovery' state and should not be auto-reaped in the drop_inode path. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Родитель
9f3afb57d5
Коммит
17c12bcd30
|
@ -456,6 +456,8 @@ xfs_bui_recover(
|
||||||
if (error)
|
if (error)
|
||||||
goto err_inode;
|
goto err_inode;
|
||||||
|
|
||||||
|
if (VFS_I(ip)->i_nlink == 0)
|
||||||
|
xfs_iflags_set(ip, XFS_IRECOVERY);
|
||||||
xfs_defer_init(&dfops, &firstfsb);
|
xfs_defer_init(&dfops, &firstfsb);
|
||||||
|
|
||||||
/* Process deferred bmap item. */
|
/* Process deferred bmap item. */
|
||||||
|
|
|
@ -1850,6 +1850,7 @@ xfs_inactive(
|
||||||
}
|
}
|
||||||
|
|
||||||
mp = ip->i_mount;
|
mp = ip->i_mount;
|
||||||
|
ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY));
|
||||||
|
|
||||||
/* If this is a read-only mount, don't do this (would generate I/O) */
|
/* If this is a read-only mount, don't do this (would generate I/O) */
|
||||||
if (mp->m_flags & XFS_MOUNT_RDONLY)
|
if (mp->m_flags & XFS_MOUNT_RDONLY)
|
||||||
|
|
|
@ -222,6 +222,12 @@ static inline bool xfs_is_reflink_inode(struct xfs_inode *ip)
|
||||||
#define XFS_IPINNED (1 << __XFS_IPINNED_BIT)
|
#define XFS_IPINNED (1 << __XFS_IPINNED_BIT)
|
||||||
#define XFS_IDONTCACHE (1 << 9) /* don't cache the inode long term */
|
#define XFS_IDONTCACHE (1 << 9) /* don't cache the inode long term */
|
||||||
#define XFS_IEOFBLOCKS (1 << 10)/* has the preallocblocks tag set */
|
#define XFS_IEOFBLOCKS (1 << 10)/* has the preallocblocks tag set */
|
||||||
|
/*
|
||||||
|
* If this unlinked inode is in the middle of recovery, don't let drop_inode
|
||||||
|
* truncate and free the inode. This can happen if we iget the inode during
|
||||||
|
* log recovery to replay a bmap operation on the inode.
|
||||||
|
*/
|
||||||
|
#define XFS_IRECOVERY (1 << 11)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-lifetime flags need to be reset when re-using a reclaimable inode during
|
* Per-lifetime flags need to be reset when re-using a reclaimable inode during
|
||||||
|
|
|
@ -4969,6 +4969,7 @@ xlog_recover_process_one_iunlink(
|
||||||
if (error)
|
if (error)
|
||||||
goto fail_iput;
|
goto fail_iput;
|
||||||
|
|
||||||
|
xfs_iflags_clear(ip, XFS_IRECOVERY);
|
||||||
ASSERT(VFS_I(ip)->i_nlink == 0);
|
ASSERT(VFS_I(ip)->i_nlink == 0);
|
||||||
ASSERT(VFS_I(ip)->i_mode != 0);
|
ASSERT(VFS_I(ip)->i_mode != 0);
|
||||||
|
|
||||||
|
|
|
@ -924,6 +924,15 @@ xfs_mountfs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During the second phase of log recovery, we need iget and
|
||||||
|
* iput to behave like they do for an active filesystem.
|
||||||
|
* xfs_fs_drop_inode needs to be able to prevent the deletion
|
||||||
|
* of inodes before we're done replaying log items on those
|
||||||
|
* inodes.
|
||||||
|
*/
|
||||||
|
mp->m_super->s_flags |= MS_ACTIVE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finish recovering the file system. This part needed to be delayed
|
* Finish recovering the file system. This part needed to be delayed
|
||||||
* until after the root and real-time bitmap inodes were consistently
|
* until after the root and real-time bitmap inodes were consistently
|
||||||
|
|
|
@ -1008,6 +1008,16 @@ xfs_fs_drop_inode(
|
||||||
{
|
{
|
||||||
struct xfs_inode *ip = XFS_I(inode);
|
struct xfs_inode *ip = XFS_I(inode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this unlinked inode is in the middle of recovery, don't
|
||||||
|
* drop the inode just yet; log recovery will take care of
|
||||||
|
* that. See the comment for this inode flag.
|
||||||
|
*/
|
||||||
|
if (ip->i_flags & XFS_IRECOVERY) {
|
||||||
|
ASSERT(ip->i_mount->m_log->l_flags & XLOG_RECOVERY_NEEDED);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
|
return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче