mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
xfs: scrub metadata directories
Teach online scrub about the metadata directory tree. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
5dab2daa8a
commit
3d2c341111
@ -100,6 +100,14 @@ xchk_dir_check_ftype(
|
||||
|
||||
if (xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype)
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
|
||||
|
||||
/*
|
||||
* Metadata and regular inodes cannot cross trees. This property
|
||||
* cannot change without a full inode free and realloc cycle, so it's
|
||||
* safe to check this without holding locks.
|
||||
*/
|
||||
if (xfs_is_metadir_inode(ip) != xfs_is_metadir_inode(sc->ip))
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -415,6 +415,12 @@ xrep_dir_salvage_entry(
|
||||
if (error)
|
||||
return 0;
|
||||
|
||||
/* Don't mix metadata and regular directory trees. */
|
||||
if (xfs_is_metadir_inode(ip) != xfs_is_metadir_inode(rd->sc->ip)) {
|
||||
xchk_irele(sc, ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xname.type = xfs_mode_to_ftype(VFS_I(ip)->i_mode);
|
||||
xchk_irele(sc, ip);
|
||||
|
||||
|
@ -362,7 +362,8 @@ xchk_dirpath_set_outcome(
|
||||
STATIC int
|
||||
xchk_dirpath_step_up(
|
||||
struct xchk_dirtree *dl,
|
||||
struct xchk_dirpath *path)
|
||||
struct xchk_dirpath *path,
|
||||
bool is_metadir)
|
||||
{
|
||||
struct xfs_scrub *sc = dl->sc;
|
||||
struct xfs_inode *dp;
|
||||
@ -435,6 +436,14 @@ xchk_dirpath_step_up(
|
||||
goto out_scanlock;
|
||||
}
|
||||
|
||||
/* Parent must be in the same directory tree. */
|
||||
if (is_metadir != xfs_is_metadir_inode(dp)) {
|
||||
trace_xchk_dirpath_crosses_tree(dl->sc, dp, path->path_nr,
|
||||
path->nr_steps, &dl->xname, &dl->pptr_rec);
|
||||
error = -EFSCORRUPTED;
|
||||
goto out_scanlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the extended attributes look as though they has been zapped by
|
||||
* the inode record repair code, we cannot scan for parent pointers.
|
||||
@ -508,6 +517,7 @@ xchk_dirpath_walk_upwards(
|
||||
struct xchk_dirpath *path)
|
||||
{
|
||||
struct xfs_scrub *sc = dl->sc;
|
||||
bool is_metadir;
|
||||
int error;
|
||||
|
||||
ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL);
|
||||
@ -538,6 +548,7 @@ xchk_dirpath_walk_upwards(
|
||||
* ILOCK state is no longer tracked in the scrub context. Hence we
|
||||
* must drop @sc->ip's ILOCK during the walk.
|
||||
*/
|
||||
is_metadir = xfs_is_metadir_inode(sc->ip);
|
||||
mutex_unlock(&dl->lock);
|
||||
xchk_iunlock(sc, XFS_ILOCK_EXCL);
|
||||
|
||||
@ -547,7 +558,7 @@ xchk_dirpath_walk_upwards(
|
||||
* If we see any kind of error here (including corruptions), the parent
|
||||
* pointer of @sc->ip is corrupt. Stop the whole scan.
|
||||
*/
|
||||
error = xchk_dirpath_step_up(dl, path);
|
||||
error = xchk_dirpath_step_up(dl, path, is_metadir);
|
||||
if (error) {
|
||||
xchk_ilock(sc, XFS_ILOCK_EXCL);
|
||||
mutex_lock(&dl->lock);
|
||||
@ -560,7 +571,7 @@ xchk_dirpath_walk_upwards(
|
||||
* *somewhere* in the path, but we don't need to stop scanning.
|
||||
*/
|
||||
while (!error && path->outcome == XCHK_DIRPATH_SCANNING)
|
||||
error = xchk_dirpath_step_up(dl, path);
|
||||
error = xchk_dirpath_step_up(dl, path, is_metadir);
|
||||
|
||||
/* Retake the locks we had, mark paths, etc. */
|
||||
xchk_ilock(sc, XFS_ILOCK_EXCL);
|
||||
|
@ -172,6 +172,10 @@ xrep_findparent_walk_directory(
|
||||
*/
|
||||
lock_mode = xfs_ilock_data_map_shared(dp);
|
||||
|
||||
/* Don't mix metadata and regular directory trees. */
|
||||
if (xfs_is_metadir_inode(dp) != xfs_is_metadir_inode(sc->ip))
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* If this directory is known to be sick, we cannot scan it reliably
|
||||
* and must abort.
|
||||
@ -368,6 +372,12 @@ xrep_findparent_confirm(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The metadata root directory always points to itself. */
|
||||
if (sc->ip == sc->mp->m_metadirip) {
|
||||
*parent_ino = sc->mp->m_sb.sb_metadirino;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unlinked dirs can point anywhere; point them up to the root dir. */
|
||||
if (VFS_I(sc->ip)->i_nlink == 0) {
|
||||
*parent_ino = xchk_inode_rootdir_inum(sc->ip);
|
||||
@ -415,6 +425,9 @@ xrep_findparent_self_reference(
|
||||
if (sc->ip->i_ino == sc->mp->m_sb.sb_rootino)
|
||||
return sc->mp->m_sb.sb_rootino;
|
||||
|
||||
if (sc->ip->i_ino == sc->mp->m_sb.sb_metadirino)
|
||||
return sc->mp->m_sb.sb_metadirino;
|
||||
|
||||
if (VFS_I(sc->ip)->i_nlink == 0)
|
||||
return xchk_inode_rootdir_inum(sc->ip);
|
||||
|
||||
|
@ -132,6 +132,14 @@ xchk_parent_validate(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is this the metadata root dir? Then '..' must point to itself. */
|
||||
if (sc->ip == mp->m_metadirip) {
|
||||
if (sc->ip->i_ino != mp->m_sb.sb_metadirino ||
|
||||
sc->ip->i_ino != parent_ino)
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* '..' must not point to ourselves. */
|
||||
if (sc->ip->i_ino == parent_ino) {
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
|
||||
@ -185,6 +193,12 @@ xchk_parent_validate(
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Metadata and regular inodes cannot cross trees. */
|
||||
if (xfs_is_metadir_inode(dp) != xfs_is_metadir_inode(sc->ip)) {
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Look for a directory entry in the parent pointing to the child. */
|
||||
error = xchk_dir_walk(sc, dp, xchk_parent_actor, &spc);
|
||||
if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
|
||||
|
@ -1753,6 +1753,7 @@ DEFINE_XCHK_DIRPATH_EVENT(xchk_dirpath_badgen);
|
||||
DEFINE_XCHK_DIRPATH_EVENT(xchk_dirpath_nondir_parent);
|
||||
DEFINE_XCHK_DIRPATH_EVENT(xchk_dirpath_unlinked_parent);
|
||||
DEFINE_XCHK_DIRPATH_EVENT(xchk_dirpath_found_next_step);
|
||||
DEFINE_XCHK_DIRPATH_EVENT(xchk_dirpath_crosses_tree);
|
||||
|
||||
TRACE_DEFINE_ENUM(XCHK_DIRPATH_SCANNING);
|
||||
TRACE_DEFINE_ENUM(XCHK_DIRPATH_DELETE);
|
||||
|
Loading…
Reference in New Issue
Block a user