Skip to content

Commit dc5a052

Browse files
author
Darrick J. Wong
committed
xfs: mark metadir repair tempfiles with IRECOVERY
Once in a long while, xfs/566 and xfs/801 report directory corruption in one of the metadata subdirectories while it's forcibly rebuilding all filesystem metadata. I observed the following sequence of events: 1. Initiate a repair of the parent pointers for the /quota/user file. This is the secret file containing user quota data. 2. The pptr repair thread creates a temporary file and begins staging parent pointers in the ondisk metadata in preparation for an exchange-range to commit the new pptr data. 3. At the same time, initiate a repair of the /quota directory itself. 4. The dir repair thread finds the temporary file from (2), scans it for parent pointers, and stages a dirent in its own temporary dir in preparation to commit the fixed directory. 5. The parent pointer repair completes and frees the temporary file. 6. The dir repair commits the new directory and scans it again. It finds the dirent that points to the old temporary file in (2) and marks the directory corrupt. Oops! Repair code must never scan the temporary files that other repair functions create to stage new metadata. They're not supposed to do that, but the predicate function xrep_is_tempfile is incorrect because it assumes that any XFS_DIFLAG2_METADATA file cannot ever be a temporary file, but xrep_tempfile_adjust_directory_tree creates exactly that. Fix this by setting the IRECOVERY flag on temporary metadata directory inodes and using that to correct the predicate. Repair code is supposed to erase all the data in temporary files before releasing them, so it's ok if a thread scans the temporary file after we drop IRECOVERY. Cc: <stable@vger.kernel.org> # v6.13-rc1 Fixes: bb6cdd5 ("xfs: hide metadata inodes from everyone because they are special") Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 6f46697 commit dc5a052

2 files changed

Lines changed: 9 additions & 3 deletions

File tree

fs/xfs/scrub/tempfile.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ xrep_tempfile_adjust_directory_tree(
223223
if (error)
224224
goto out_ilock;
225225

226+
xfs_iflags_set(sc->tempip, XFS_IRECOVERY);
226227
xfs_qm_dqdetach(sc->tempip);
227228
out_ilock:
228229
xrep_tempfile_iunlock(sc);
@@ -246,6 +247,8 @@ xrep_tempfile_remove_metadir(
246247

247248
ASSERT(sc->tp == NULL);
248249

250+
xfs_iflags_clear(sc->tempip, XFS_IRECOVERY);
251+
249252
xfs_ilock(sc->tempip, XFS_IOLOCK_EXCL);
250253
sc->temp_ilock_flags |= XFS_IOLOCK_EXCL;
251254

@@ -945,10 +948,13 @@ xrep_is_tempfile(
945948

946949
/*
947950
* Files in the metadata directory tree also have S_PRIVATE set and
948-
* IOP_XATTR unset, so we must distinguish them separately.
951+
* IOP_XATTR unset, so we must distinguish them separately. We (ab)use
952+
* the IRECOVERY flag to mark temporary metadir inodes knowing that the
953+
* end of log recovery clears IRECOVERY, so the only ones that can
954+
* exist during online repair are the ones we create.
949955
*/
950956
if (xfs_has_metadir(mp) && (ip->i_diflags2 & XFS_DIFLAG2_METADATA))
951-
return false;
957+
return __xfs_iflags_test(ip, XFS_IRECOVERY);
952958

953959
if (IS_PRIVATE(inode) && !(inode->i_opflags & IOP_XATTR))
954960
return true;

fs/xfs/xfs_inode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ xfs_iflags_clear(xfs_inode_t *ip, unsigned long flags)
231231
}
232232

233233
static inline int
234-
__xfs_iflags_test(xfs_inode_t *ip, unsigned long flags)
234+
__xfs_iflags_test(const struct xfs_inode *ip, unsigned long flags)
235235
{
236236
return (ip->i_flags & flags);
237237
}

0 commit comments

Comments
 (0)