summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_fs.h6
-rw-r--r--fs/xfs/scrub/scrub.c7
-rw-r--r--fs/xfs/scrub/trace.h3
-rw-r--r--fs/xfs/xfs_ioctl.c3
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;