xfs: allow bulkstat to return metadata directories

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>
This commit is contained in:
Darrick J. Wong 2024-11-03 20:18:54 -08:00
parent 688828d8f8
commit df866c538f
4 changed files with 48 additions and 5 deletions

View File

@ -490,9 +490,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 << 3)
#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)

View 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;

View 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_is_sb_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_is_sb_inum(mp, ino)) {
xfs_iunlock(ip, XFS_ILOCK_SHARED);
xfs_irele(ip);
error = -EINVAL;

View 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.