]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: allow bulkstat to return metadata directories
authorDarrick J. Wong <djwong@kernel.org>
Wed, 7 Aug 2024 22:54:15 +0000 (15:54 -0700)
committerChristoph Hellwig <hch@lst.de>
Sun, 22 Sep 2024 06:07:18 +0000 (08:07 +0200)
Allow the V5 bulkstat ioctl to return information about metadata
directory files so that xfs_scrub can find and scrub them, since they
are otherwise ordinary directories.

(Metadata files of course require per-file scrub code and hence do not
need exposure.)

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_fs.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_itable.h

index 162256f9b04c224387ffd5e388b6de2a3e869a85..b652225cd682567071cc1357345df81740c854ea 100644 (file)
@@ -491,9 +491,17 @@ struct xfs_bulk_ireq {
  */
 #define XFS_BULK_IREQ_NREXT64  (1U << 2)
 
+/*
+ * Allow bulkstat to return information about metadata directories.  This
+ * enables xfs_scrub to find them for scanning, as they are otherwise ordinary
+ * directories.
+ */
+#define XFS_BULK_IREQ_METADIR  (1U << 31)
+
 #define XFS_BULK_IREQ_FLAGS_ALL        (XFS_BULK_IREQ_AGNO |    \
                                 XFS_BULK_IREQ_SPECIAL | \
-                                XFS_BULK_IREQ_NREXT64)
+                                XFS_BULK_IREQ_NREXT64 | \
+                                XFS_BULK_IREQ_METADIR)
 
 /* Operate on the root directory inode. */
 #define XFS_BULK_IREQ_SPECIAL_ROOT     (1)
index 7226d27e8afc3f29e090c6b308c07782802e9b39..461780ffb8fc0ac4c3c492e6577b159b1abffd88 100644 (file)
@@ -233,6 +233,10 @@ xfs_bulk_ireq_setup(
        if (hdr->flags & XFS_BULK_IREQ_NREXT64)
                breq->flags |= XFS_IBULK_NREXT64;
 
+       /* Caller wants to see metadata directories in bulkstat output. */
+       if (hdr->flags & XFS_BULK_IREQ_METADIR)
+               breq->flags |= XFS_IBULK_METADIR;
+
        return 0;
 }
 
@@ -323,6 +327,9 @@ xfs_ioc_inumbers(
        if (copy_from_user(&hdr, &arg->hdr, sizeof(hdr)))
                return -EFAULT;
 
+       if (hdr.flags & XFS_BULK_IREQ_METADIR)
+               return -EINVAL;
+
        error = xfs_bulk_ireq_setup(mp, &hdr, &breq, arg->inumbers);
        if (error == -ECANCELED)
                goto out_teardown;
index c0757ab994957ba2d14d43df9c4faebaf31e0aad..198d52e9f81f631809590185874bd6b94ffddf15 100644 (file)
@@ -36,6 +36,14 @@ struct xfs_bstat_chunk {
        struct xfs_bulkstat     *buf;
 };
 
+static inline bool
+want_metadir_file(
+       struct xfs_inode        *ip,
+       struct xfs_ibulk        *breq)
+{
+       return xfs_is_metadir_inode(ip) && (breq->flags & XFS_IBULK_METADIR);
+}
+
 /*
  * Fill out the bulkstat info for a single inode and report it somewhere.
  *
@@ -69,9 +77,6 @@ xfs_bulkstat_one_int(
        vfsuid_t                vfsuid;
        vfsgid_t                vfsgid;
 
-       if (xfs_internal_inum(mp, ino))
-               goto out_advance;
-
        error = xfs_iget(mp, tp, ino,
                         (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
                         XFS_ILOCK_SHARED, &ip);
@@ -97,8 +102,28 @@ xfs_bulkstat_one_int(
        vfsuid = i_uid_into_vfsuid(idmap, inode);
        vfsgid = i_gid_into_vfsgid(idmap, inode);
 
+       /*
+        * If caller wants files from the metadata directories, push out the
+        * bare minimum information for enabling scrub.
+        */
+       if (want_metadir_file(ip, bc->breq)) {
+               memset(buf, 0, sizeof(*buf));
+               buf->bs_ino = ino;
+               buf->bs_gen = inode->i_generation;
+               buf->bs_mode = inode->i_mode & S_IFMT;
+               xfs_bulkstat_health(ip, buf);
+               buf->bs_version = XFS_BULKSTAT_VERSION_V5;
+               xfs_iunlock(ip, XFS_ILOCK_SHARED);
+               xfs_irele(ip);
+
+               error = bc->formatter(bc->breq, buf);
+               if (!error || error == -ECANCELED)
+                       goto out_advance;
+               goto out;
+       }
+
        /* If this is a private inode, don't leak its details to userspace. */
-       if (IS_PRIVATE(inode)) {
+       if (IS_PRIVATE(inode) || xfs_internal_inum(mp, ino)) {
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
                xfs_irele(ip);
                error = -EINVAL;
index 1659f13f17a89d6e93ba4cbe3267397379f8bb72..f10e8f8f2335100d07a1b631a6fa8fc38ceb3851 100644 (file)
@@ -22,6 +22,9 @@ struct xfs_ibulk {
 /* Fill out the bs_extents64 field if set. */
 #define XFS_IBULK_NREXT64      (1U << 1)
 
+/* Signal that we can return metadata directories. */
+#define XFS_IBULK_METADIR      (1U << 2)
+
 /*
  * Advance the user buffer pointer by one record of the given size.  If the
  * buffer is now full, return the appropriate error code.