diff mbox

[07/25] xfs: create an ioctl to scrub AG metadata

Message ID 147216845703.3108.9850206520479318952.stgit@birch.djwong.org
State Superseded, archived
Headers show

Commit Message

Darrick J. Wong Aug. 25, 2016, 11:40 p.m. UTC
Create an ioctl that can be used to scrub internal filesystem
metadata.  The new ioctl takes the metadata type, an (optional)
AG number, and a flags argument.  This will be used by the
upcoming XFS online scrub tool.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_fs.h |   16 ++++++++++++++++
 fs/xfs/xfs_ioctl.c     |   20 ++++++++++++++++++++
 fs/xfs/xfs_scrub.c     |   44 ++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_scrub.h     |    2 +-
 4 files changed, 81 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 58e14b14e..22559ab 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -524,6 +524,21 @@  typedef struct xfs_swapext
 #define XFS_FSOP_GOING_FLAGS_LOGFLUSH		0x1	/* flush log but not data */
 #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH		0x2	/* don't flush log nor data */
 
+/* metadata scrubbing */
+struct xfs_scrub_metadata {
+	__u32 type;		/* What to check? */
+	__u32 flags;		/* Flags; none defined right now. */
+	__u64 control;		/* AG or inode number */
+	__u64 reserved[6];	/* Must be zero. */
+};
+
+/*
+ * Metadata types and flags for scrub operation.
+ */
+#define XFS_SCRUB_TYPE_MAX	0
+
+#define XFS_SCRUB_FLAGS_ALL	0x0	/* no flags yet */
+
 /*
  * ioctl limits
  */
@@ -567,6 +582,7 @@  typedef struct xfs_swapext
 #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
 #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
 #define XFS_IOC_GETFSMAP	_IOWR('X', 59, struct getfsmap)
+#define XFS_IOC_SCRUB_METADATA	_IOR ('X', 60, struct xfs_scrub_metadata)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 936cb45..65f0c03 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -44,6 +44,7 @@ 
 #include "xfs_reflink.h"
 #include "xfs_btree.h"
 #include "xfs_fsmap.h"
+#include "xfs_scrub.h"
 
 #include <linux/capability.h>
 #include <linux/dcache.h>
@@ -1686,6 +1687,22 @@  xfs_ioc_getfsmap(
 	return 0;
 }
 
+STATIC int
+xfs_ioc_scrub_metadata(
+	struct xfs_inode		*ip,
+	void				__user *arg)
+{
+	struct xfs_scrub_metadata	scrub;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&scrub, arg, sizeof(scrub)))
+		return -EFAULT;
+
+	return xfs_scrub_metadata(ip, &scrub);
+}
+
 int
 xfs_ioc_swapext(
 	xfs_swapext_t	*sxp)
@@ -1871,6 +1888,9 @@  xfs_file_ioctl(
 			return -EPERM;
 		return xfs_ioc_getfsmap(ip, arg);
 
+	case XFS_IOC_SCRUB_METADATA:
+		return xfs_ioc_scrub_metadata(ip, arg);
+
 	case XFS_IOC_FD_TO_HANDLE:
 	case XFS_IOC_PATH_TO_HANDLE:
 	case XFS_IOC_PATH_TO_FSHANDLE: {
diff --git a/fs/xfs/xfs_scrub.c b/fs/xfs/xfs_scrub.c
index 13bea55..fd24af7 100644
--- a/fs/xfs/xfs_scrub.c
+++ b/fs/xfs/xfs_scrub.c
@@ -703,3 +703,47 @@  out:
 out_badcursor:
 	return error;
 }
+
+/* Scrubbing dispatch. */
+
+struct xfs_scrub_meta_fns {
+	int	(*scrub_fn)(struct xfs_inode *, struct xfs_scrub_metadata *);
+	bool	(*has_fn)(struct xfs_sb *);
+};
+
+static const struct xfs_scrub_meta_fns meta_scrub_fns[] = {
+};
+
+/* Dispatch metadata scrubbing. */
+int
+xfs_scrub_metadata(
+	struct xfs_inode		*ip,
+	struct xfs_scrub_metadata	*sm)
+{
+	struct xfs_mount		*mp = ip->i_mount;
+	const struct xfs_scrub_meta_fns	*fns;
+	int				i;
+	int				error = 0;
+
+	trace_xfs_scrub(ip, sm->type, sm->control, sm->flags, error);
+
+	error = -EINVAL;
+	for (i = 0; i < ARRAY_SIZE(sm->reserved); i++)
+		if (sm->reserved[i])
+			goto out;
+	if (sm->type > XFS_SCRUB_TYPE_MAX)
+		goto out;
+	if (sm->flags & ~XFS_SCRUB_FLAGS_ALL)
+		goto out;
+
+	fns = &meta_scrub_fns[sm->type];
+	if (fns->has_fn && !fns->has_fn(&mp->m_sb)) {
+		error = -ENOENT;
+		goto out;
+	}
+	error = fns->scrub_fn(ip, sm);
+
+out:
+	trace_xfs_scrub_done(ip, sm->type, sm->control, sm->flags, error);
+	return error;
+}
diff --git a/fs/xfs/xfs_scrub.h b/fs/xfs/xfs_scrub.h
index 474df7e..f4bb021 100644
--- a/fs/xfs/xfs_scrub.h
+++ b/fs/xfs/xfs_scrub.h
@@ -20,6 +20,6 @@ 
 #ifndef __XFS_SCRUB_H__
 #define __XFS_SCRUB_H__
 
-/* Functions to come later. */
+int xfs_scrub_metadata(struct xfs_inode *ip, struct xfs_scrub_metadata *sm);
 
 #endif	/* __XFS_SCRUB_H__ */