summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_fs.h6
-rw-r--r--fs/xfs/scrub/common.h3
-rw-r--r--fs/xfs/scrub/scrub.c5
-rw-r--r--fs/xfs/scrub/trace.h3
-rw-r--r--fs/xfs/xfs_ioctl.c3
5 files changed, 16 insertions, 4 deletions
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index c0a42019f8f5..f30767902660 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -794,9 +794,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/common.h b/fs/xfs/scrub/common.h
index 819bb7e2007a..81361d67cefd 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -202,7 +202,8 @@ static inline bool xfs_scrub_needs_repair(struct xfs_scrub_metadata *sm)
{
return sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
XFS_SCRUB_OFLAG_XCORRUPT |
- XFS_SCRUB_OFLAG_PREEN);
+ XFS_SCRUB_OFLAG_PREEN |
+ XFS_SCRUB_IFLAG_FORCE_REBUILD);
}
int xchk_iwalk_find_next(struct xfs_mount *mp, struct xfs_trans *tp,
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index 181d66773b45..875cf7ac08d0 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
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index 5c43578a174e..a2e6094e8c5a 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 8913c27ddd11..525eba22c2a2 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;