Skip to content

Commit 17c12bc

Browse files
committed
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>
1 parent 9f3afb5 commit 17c12bc

File tree

6 files changed

+29
-0
lines changed

6 files changed

+29
-0
lines changed

fs/xfs/xfs_bmap_item.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ xfs_bui_recover(
456456
if (error)
457457
goto err_inode;
458458

459+
if (VFS_I(ip)->i_nlink == 0)
460+
xfs_iflags_set(ip, XFS_IRECOVERY);
459461
xfs_defer_init(&dfops, &firstfsb);
460462

461463
/* Process deferred bmap item. */

fs/xfs/xfs_inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,7 @@ xfs_inactive(
18501850
}
18511851

18521852
mp = ip->i_mount;
1853+
ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY));
18531854

18541855
/* If this is a read-only mount, don't do this (would generate I/O) */
18551856
if (mp->m_flags & XFS_MOUNT_RDONLY)

fs/xfs/xfs_inode.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ static inline bool xfs_is_reflink_inode(struct xfs_inode *ip)
222222
#define XFS_IPINNED (1 << __XFS_IPINNED_BIT)
223223
#define XFS_IDONTCACHE (1 << 9) /* don't cache the inode long term */
224224
#define XFS_IEOFBLOCKS (1 << 10)/* has the preallocblocks tag set */
225+
/*
226+
* If this unlinked inode is in the middle of recovery, don't let drop_inode
227+
* truncate and free the inode. This can happen if we iget the inode during
228+
* log recovery to replay a bmap operation on the inode.
229+
*/
230+
#define XFS_IRECOVERY (1 << 11)
225231

226232
/*
227233
* Per-lifetime flags need to be reset when re-using a reclaimable inode during

fs/xfs/xfs_log_recover.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4969,6 +4969,7 @@ xlog_recover_process_one_iunlink(
49694969
if (error)
49704970
goto fail_iput;
49714971

4972+
xfs_iflags_clear(ip, XFS_IRECOVERY);
49724973
ASSERT(VFS_I(ip)->i_nlink == 0);
49734974
ASSERT(VFS_I(ip)->i_mode != 0);
49744975

fs/xfs/xfs_mount.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,15 @@ xfs_mountfs(
924924
}
925925
}
926926

927+
/*
928+
* During the second phase of log recovery, we need iget and
929+
* iput to behave like they do for an active filesystem.
930+
* xfs_fs_drop_inode needs to be able to prevent the deletion
931+
* of inodes before we're done replaying log items on those
932+
* inodes.
933+
*/
934+
mp->m_super->s_flags |= MS_ACTIVE;
935+
927936
/*
928937
* Finish recovering the file system. This part needed to be delayed
929938
* until after the root and real-time bitmap inodes were consistently

fs/xfs/xfs_super.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,16 @@ xfs_fs_drop_inode(
10081008
{
10091009
struct xfs_inode *ip = XFS_I(inode);
10101010

1011+
/*
1012+
* If this unlinked inode is in the middle of recovery, don't
1013+
* drop the inode just yet; log recovery will take care of
1014+
* that. See the comment for this inode flag.
1015+
*/
1016+
if (ip->i_flags & XFS_IRECOVERY) {
1017+
ASSERT(ip->i_mount->m_log->l_flags & XLOG_RECOVERY_NEEDED);
1018+
return 0;
1019+
}
1020+
10111021
return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
10121022
}
10131023

0 commit comments

Comments
 (0)