Loading fs/xfs/scrub/dir.c +8 −0 Original line number Diff line number Diff line Loading @@ -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); } /* Loading fs/xfs/scrub/dir_repair.c +6 −0 Original line number Diff line number Diff line Loading @@ -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); Loading fs/xfs/scrub/dirtree.c +14 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading fs/xfs/scrub/findparent.c +13 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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); Loading fs/xfs/scrub/parent.c +14 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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)) Loading Loading
fs/xfs/scrub/dir.c +8 −0 Original line number Diff line number Diff line Loading @@ -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); } /* Loading
fs/xfs/scrub/dir_repair.c +6 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
fs/xfs/scrub/dirtree.c +14 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading
fs/xfs/scrub/findparent.c +13 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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); Loading
fs/xfs/scrub/parent.c +14 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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)) Loading