diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_fs.h | 6 | ||||
-rw-r--r-- | fs/xfs/scrub/scrub.c | 7 | ||||
-rw-r--r-- | fs/xfs/scrub/trace.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 3 |
4 files changed, 16 insertions, 3 deletions
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 5e7956dc03d0..b36b10e76696 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -793,9 +793,13 @@ struct xfs_scrub_metadata { /* i: Don't mark inodes DONTCACHE at the end. */ #define XFS_SCRUB_IFLAG_RETAIN_INODES (1 << 9) +/* i: Rebuild the data structure. */ +#define XFS_SCRUB_IFLAG_FORCE_REBUILD (1 << 10) + #define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR | \ XFS_SCRUB_IFLAG_FREEZE_OK | \ - XFS_SCRUB_IFLAG_RETAIN_INODES) + XFS_SCRUB_IFLAG_RETAIN_INODES | \ + XFS_SCRUB_IFLAG_FORCE_REBUILD) #define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \ XFS_SCRUB_OFLAG_PREEN | \ XFS_SCRUB_OFLAG_XFAIL | \ diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c index 104e27f0bc1c..882d60735648 100644 --- a/fs/xfs/scrub/scrub.c +++ b/fs/xfs/scrub/scrub.c @@ -464,6 +464,11 @@ xchk_validate_inputs( goto out; } + /* No rebuild without repair. */ + if ((sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) && + !(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) + return -EINVAL; + /* * We only want to repair read-write v5+ filesystems. Defer the check * for ops->repair until after our scrub confirms that we need to @@ -625,6 +630,8 @@ retry_op: /* Let debug users force us into the repair routines. */ if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR)) needs_fix = true; + if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) + needs_fix = true; /* * If userspace asked for a repair but it wasn't necessary, diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h index 80fcc76d9b69..1083ae5c5093 100644 --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -111,7 +111,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_BARRIER); { XFS_SCRUB_OFLAG_WARNING, "warning" }, \ { XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED, "norepair" }, \ { XFS_SCRUB_IFLAG_FREEZE_OK, "freeze" }, \ - { XFS_SCRUB_IFLAG_RETAIN_INODES, "icache" } + { XFS_SCRUB_IFLAG_RETAIN_INODES, "icache" }, \ + { XFS_SCRUB_IFLAG_FORCE_REBUILD, "rebuild" } DECLARE_EVENT_CLASS(xchk_class, TP_PROTO(struct xfs_inode *ip, struct xfs_scrub_metadata *sm, diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 6c37d201912f..97b1f9303c8f 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1810,7 +1810,8 @@ xfs_ioc_scrub_metadata( if (copy_from_user(&scrub, arg, sizeof(scrub))) return -EFAULT; - if ((scrub.sm_flags & XFS_SCRUB_IFLAG_FREEZE_OK) && + if ((scrub.sm_flags & (XFS_SCRUB_IFLAG_FREEZE_OK | + XFS_SCRUB_IFLAG_FORCE_REBUILD)) && !capable(CAP_SYS_ADMIN)) return -EPERM; |