]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
libfrog: support vectored scrub
authorDarrick J. Wong <djwong@kernel.org>
Tue, 9 Jan 2024 17:39:31 +0000 (09:39 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 10 Apr 2024 00:21:32 +0000 (17:21 -0700)
Enhance libfrog to support performing vectored metadata scrub.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libfrog/fsgeom.h
libfrog/scrub.c
libfrog/scrub.h

index f327dc7d70d03a3d66e3ebdf4ba6c79887bd5155..df2ca2a408e78a99e1d50112648eb074b4d277e0 100644 (file)
@@ -50,6 +50,12 @@ struct xfs_fd {
 /* Only use v5 bulkstat/inumbers ioctls. */
 #define XFROG_FLAG_BULKSTAT_FORCE_V5   (1 << 1)
 
+/* Only use the older one-at-a-time scrub ioctl. */
+#define XFROG_FLAG_SCRUB_FORCE_SINGLE  (1 << 2)
+
+/* Only use the vectored scrub ioctl. */
+#define XFROG_FLAG_SCRUB_FORCE_VECTOR  (1 << 3)
+
 /* Static initializers */
 #define XFS_FD_INIT(_fd)       { .fd = (_fd), }
 #define XFS_FD_INIT_EMPTY      XFS_FD_INIT(-1)
index a2146e228f5b6dbdf7e9aa4d4a2d22dc79078f16..8264aab00ef25d7ec80e662c1dcb6a3baec3809d 100644 (file)
@@ -171,3 +171,127 @@ xfrog_scrub_metadata(
 
        return 0;
 }
+
+/* Decide if there have been any scrub failures up to this point. */
+static inline int
+xfrog_scrubv_previous_failures(
+       struct xfs_scrub_vec_head       *vhead,
+       struct xfs_scrub_vec            *barrier_vec)
+{
+       struct xfs_scrub_vec            *v;
+       __u32                           failmask;
+
+       failmask = barrier_vec->sv_flags & XFS_SCRUB_FLAGS_OUT;
+       for (v = vhead->svh_vecs; v < barrier_vec; v++) {
+               if (v->sv_type == XFS_SCRUB_TYPE_BARRIER)
+                       continue;
+
+               /*
+                * Runtime errors count as a previous failure, except the ones
+                * used to ask userspace to retry.
+                */
+               if (v->sv_ret && v->sv_ret != -EBUSY && v->sv_ret != -ENOENT &&
+                   v->sv_ret != -EUSERS)
+                       return -ECANCELED;
+
+               /*
+                * If any of the out-flags on the scrub vector match the mask
+                * that was set on the barrier vector, that's a previous fail.
+                */
+               if (v->sv_flags & failmask)
+                       return -ECANCELED;
+       }
+
+       return 0;
+}
+
+static int
+xfrog_scrubv_fallback(
+       struct xfs_fd                   *xfd,
+       struct xfs_scrub_vec_head       *vhead)
+{
+       struct xfs_scrub_vec            *v;
+       unsigned int                    i;
+
+       if (vhead->svh_flags & ~XFS_SCRUB_VEC_FLAGS_ALL)
+               return -EINVAL;
+       for (i = 0, v = vhead->svh_vecs; i < vhead->svh_nr; i++, v++) {
+               if (v->sv_reserved)
+                       return -EINVAL;
+               if (v->sv_type == XFS_SCRUB_TYPE_BARRIER &&
+                   (v->sv_flags & ~XFS_SCRUB_FLAGS_OUT))
+                       return -EINVAL;
+       }
+
+       /* Run all the scrubbers. */
+       for (i = 0, v = vhead->svh_vecs; i < vhead->svh_nr; i++, v++) {
+               struct xfs_scrub_metadata       sm = {
+                       .sm_type        = v->sv_type,
+                       .sm_flags       = v->sv_flags,
+                       .sm_ino         = vhead->svh_ino,
+                       .sm_gen         = vhead->svh_gen,
+                       .sm_agno        = vhead->svh_agno,
+               };
+               struct timespec tv;
+
+               if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) {
+                       v->sv_ret = xfrog_scrubv_previous_failures(vhead, v);
+                       if (v->sv_ret)
+                               break;
+                       continue;
+               }
+
+               v->sv_ret = xfrog_scrub_metadata(xfd, &sm);
+               v->sv_flags = sm.sm_flags;
+
+               if (vhead->svh_rest_us) {
+                       tv.tv_sec = 0;
+                       tv.tv_nsec = vhead->svh_rest_us * 1000;
+                       nanosleep(&tv, NULL);
+               }
+       }
+
+       return 0;
+}
+
+/* Invoke the vectored scrub ioctl. */
+static int
+xfrog_scrubv_call(
+       struct xfs_fd                   *xfd,
+       struct xfs_scrub_vec_head       *vhead)
+{
+       int                             ret;
+
+       ret = ioctl(xfd->fd, XFS_IOC_SCRUBV_METADATA, vhead);
+       if (ret)
+               return -errno;
+
+       return 0;
+}
+
+/* Invoke the vectored scrub ioctl.  Returns zero or negative error code. */
+int
+xfrog_scrubv_metadata(
+       struct xfs_fd                   *xfd,
+       struct xfs_scrub_vec_head       *vhead)
+{
+       int                             error = 0;
+
+       if (xfd->flags & XFROG_FLAG_SCRUB_FORCE_SINGLE)
+               goto try_single;
+
+       error = xfrog_scrubv_call(xfd, vhead);
+       if (error == 0 || (xfd->flags & XFROG_FLAG_SCRUB_FORCE_VECTOR))
+               return error;
+
+       /* If the vectored scrub ioctl wasn't found, force single mode. */
+       switch (error) {
+       case -EOPNOTSUPP:
+       case -ENOTTY:
+               xfd->flags |= XFROG_FLAG_SCRUB_FORCE_SINGLE;
+               break;
+       }
+
+try_single:
+       return xfrog_scrubv_fallback(xfd, vhead);
+}
index 27230c62f71aed3ee7ab3c10fa7e45c492d95b3f..43456230479974aaf5073557dcb1822e969a0bce 100644 (file)
@@ -28,4 +28,8 @@ extern const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR];
 
 int xfrog_scrub_metadata(struct xfs_fd *xfd, struct xfs_scrub_metadata *meta);
 
+struct xfs_scrub_vec_head;
+
+int xfrog_scrubv_metadata(struct xfs_fd *xfd, struct xfs_scrub_vec_head *vhead);
+
 #endif /* __LIBFROG_SCRUB_H__ */