Commit df866c53 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

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: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 688828d8
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -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)
+7 −0
Original line number Diff line number Diff line
@@ -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;
+29 −4
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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.