]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - scrub/inodes.c
libfrog: convert workqueue.c functions to negative error codes
[thirdparty/xfsprogs-dev.git] / scrub / inodes.c
index 700e52009e5bd8648a649dcfc88827bca8bd7d92..099489d83778dd05a189e582672c69e6bbf4fb8d 100644 (file)
 #include "xfs_arch.h"
 #include "xfs_format.h"
 #include "handle.h"
-#include "path.h"
-#include "workqueue.h"
+#include "libfrog/paths.h"
+#include "libfrog/workqueue.h"
 #include "xfs_scrub.h"
 #include "common.h"
 #include "inodes.h"
+#include "libfrog/fsgeom.h"
+#include "libfrog/bulkstat.h"
 
 /*
  * Iterate a range of inodes.
  */
 
 /*
- * Did we get exactly the inodes we expected?  If not, load them one at a
- * time (or fake it) into the bulkstat data.
+ * Run bulkstat on an entire inode allocation group, then check that we got
+ * exactly the inodes we expected.  If not, load them one at a time (or fake
+ * it) into the bulkstat data.
  */
 static void
-xfs_iterate_inodes_range_check(
+bulkstat_for_inumbers(
        struct scrub_ctx        *ctx,
-       struct xfs_inogrp       *inogrp,
-       struct xfs_bstat        *bstat)
+       const char              *descr,
+       const struct xfs_inumbers *inumbers,
+       struct xfs_bulkstat_req *breq)
 {
-       struct xfs_fsop_bulkreq onereq = {NULL};
-       struct xfs_bstat        *bs;
-       __u64                   oneino;
-       __s32                   onelen = 0;
+       struct xfs_bulkstat     *bstat = breq->bulkstat;
+       struct xfs_bulkstat     *bs;
        int                     i;
        int                     error;
 
-       onereq.lastip  = &oneino;
-       onereq.icount  = 1;
-       onereq.ocount  = &onelen;
+       /* First we try regular bulkstat, for speed. */
+       breq->hdr.ino = inumbers->xi_startino;
+       breq->hdr.icount = inumbers->xi_alloccount;
+       error = -xfrog_bulkstat(&ctx->mnt, breq);
+       if (error) {
+               char    errbuf[DESCR_BUFSZ];
+
+               str_info(ctx, descr, "%s",
+                        strerror_r(error, errbuf, DESCR_BUFSZ));
+       }
 
+       /*
+        * Check each of the stats we got back to make sure we got the inodes
+        * we asked for.
+        */
        for (i = 0, bs = bstat; i < XFS_INODES_PER_CHUNK; i++) {
-               if (!(inogrp->xi_allocmask & (1ULL << i)))
+               if (!(inumbers->xi_allocmask & (1ULL << i)))
                        continue;
-               if (bs->bs_ino == inogrp->xi_startino + i) {
+               if (bs->bs_ino == inumbers->xi_startino + i) {
                        bs++;
                        continue;
                }
 
                /* Load the one inode. */
-               oneino = inogrp->xi_startino + i;
-               onereq.ubuffer = bs;
-               error = ioctl(ctx->mnt.fd, XFS_IOC_FSBULKSTAT_SINGLE,
-                               &onereq);
-               if (error || bs->bs_ino != inogrp->xi_startino + i) {
-                       memset(bs, 0, sizeof(struct xfs_bstat));
-                       bs->bs_ino = inogrp->xi_startino + i;
+               error = -xfrog_bulkstat_single(&ctx->mnt,
+                               inumbers->xi_startino + i, 0, bs);
+               if (error || bs->bs_ino != inumbers->xi_startino + i) {
+                       memset(bs, 0, sizeof(struct xfs_bulkstat));
+                       bs->bs_ino = inumbers->xi_startino + i;
                        bs->bs_blksize = ctx->mnt_sv.f_frsize;
                }
                bs++;
        }
 }
 
+/* BULKSTAT wrapper routines. */
+struct scan_inodes {
+       scrub_inode_iter_fn     fn;
+       void                    *arg;
+       bool                    aborted;
+};
+
 /*
  * Call into the filesystem for inode/bulkstat information and call our
  * iterator function.  We'll try to fill the bulkstat information in batches,
  * but we also can detect iget failures.
  */
-static bool
-xfs_iterate_inodes_range(
-       struct scrub_ctx        *ctx,
-       const char              *descr,
-       void                    *fshandle,
-       uint64_t                first_ino,
-       uint64_t                last_ino,
-       xfs_inode_iter_fn       fn,
+static void
+scan_ag_inodes(
+       struct workqueue        *wq,
+       xfs_agnumber_t          agno,
        void                    *arg)
 {
-       struct xfs_fsop_bulkreq igrpreq = {NULL};
-       struct xfs_fsop_bulkreq bulkreq = {NULL};
        struct xfs_handle       handle;
-       struct xfs_inogrp       inogrp;
-       struct xfs_bstat        bstat[XFS_INODES_PER_CHUNK];
-       char                    idescr[DESCR_BUFSZ];
-       char                    buf[DESCR_BUFSZ];
-       struct xfs_bstat        *bs;
-       __u64                   igrp_ino;
-       __u64                   ino;
-       __s32                   bulklen = 0;
-       __s32                   igrplen = 0;
-       bool                    moveon = true;
+       char                    descr[DESCR_BUFSZ];
+       struct xfs_inumbers_req *ireq;
+       struct xfs_bulkstat_req *breq;
+       struct scan_inodes      *si = arg;
+       struct scrub_ctx        *ctx = (struct scrub_ctx *)wq->wq_ctx;
+       struct xfs_bulkstat     *bs;
+       struct xfs_inumbers     *inumbers;
        int                     i;
        int                     error;
        int                     stale_count = 0;
 
+       snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
+                               major(ctx->fsinfo.fs_datadev),
+                               minor(ctx->fsinfo.fs_datadev),
+                               agno);
 
-       memset(bstat, 0, XFS_INODES_PER_CHUNK * sizeof(struct xfs_bstat));
-       bulkreq.lastip  = &ino;
-       bulkreq.icount  = XFS_INODES_PER_CHUNK;
-       bulkreq.ubuffer = &bstat;
-       bulkreq.ocount  = &bulklen;
-
-       igrpreq.lastip  = &igrp_ino;
-       igrpreq.icount  = 1;
-       igrpreq.ubuffer = &inogrp;
-       igrpreq.ocount  = &igrplen;
-
-       memcpy(&handle.ha_fsid, fshandle, sizeof(handle.ha_fsid));
+       memcpy(&handle.ha_fsid, ctx->fshandle, sizeof(handle.ha_fsid));
        handle.ha_fid.fid_len = sizeof(xfs_fid_t) -
                        sizeof(handle.ha_fid.fid_len);
        handle.ha_fid.fid_pad = 0;
 
+       error = -xfrog_bulkstat_alloc_req(XFS_INODES_PER_CHUNK, 0, &breq);
+       if (error) {
+               str_liberror(ctx, error, descr);
+               si->aborted = true;
+               return;
+       }
+
+       error = -xfrog_inumbers_alloc_req(1, 0, &ireq);
+       if (error) {
+               str_liberror(ctx, error, descr);
+               free(breq);
+               si->aborted = true;
+               return;
+       }
+       inumbers = &ireq->inumbers[0];
+       xfrog_inumbers_set_ag(ireq, agno);
+
        /* Find the inode chunk & alloc mask */
-       igrp_ino = first_ino;
-       error = ioctl(ctx->mnt.fd, XFS_IOC_FSINUMBERS, &igrpreq);
-       while (!error && igrplen) {
-               /* Load the inodes. */
-               ino = inogrp.xi_startino - 1;
-               bulkreq.icount = inogrp.xi_alloccount;
+       error = -xfrog_inumbers(&ctx->mnt, ireq);
+       while (!error && !si->aborted && ireq->hdr.ocount > 0) {
                /*
                 * We can have totally empty inode chunks on filesystems where
                 * there are more than 64 inodes per block.  Skip these.
                 */
-               if (inogrp.xi_alloccount == 0)
+               if (inumbers->xi_alloccount == 0)
                        goto igrp_retry;
-               error = ioctl(ctx->mnt.fd, XFS_IOC_FSBULKSTAT, &bulkreq);
-               if (error)
-                       str_info(ctx, descr, "%s", strerror_r(errno,
-                                               buf, DESCR_BUFSZ));
 
-               xfs_iterate_inodes_range_check(ctx, &inogrp, bstat);
+               bulkstat_for_inumbers(ctx, descr, inumbers, breq);
 
                /* Iterate all the inodes. */
-               for (i = 0, bs = bstat; i < inogrp.xi_alloccount; i++, bs++) {
-                       if (bs->bs_ino > last_ino)
-                               goto out;
-
+               for (i = 0, bs = breq->bulkstat;
+                    !si->aborted && i < inumbers->xi_alloccount;
+                    i++, bs++) {
                        handle.ha_fid.fid_ino = bs->bs_ino;
                        handle.ha_fid.fid_gen = bs->bs_gen;
-                       error = fn(ctx, &handle, bs, arg);
+                       error = si->fn(ctx, &handle, bs, si->arg);
                        switch (error) {
                        case 0:
                                break;
-                       case ESTALE:
+                       case ESTALE: {
+                               char    idescr[DESCR_BUFSZ];
+
                                stale_count++;
                                if (stale_count < 30) {
-                                       igrp_ino = inogrp.xi_startino;
+                                       ireq->hdr.ino = inumbers->xi_startino;
                                        goto igrp_retry;
                                }
-                               snprintf(idescr, DESCR_BUFSZ, "inode %"PRIu64,
-                                               (uint64_t)bs->bs_ino);
+                               scrub_render_ino_descr(ctx, idescr, DESCR_BUFSZ,
+                                               bs->bs_ino, bs->bs_gen, NULL);
                                str_info(ctx, idescr,
 _("Changed too many times during scan; giving up."));
                                break;
-                       case XFS_ITERATE_INODES_ABORT:
+                       }
+                       case ECANCELED:
                                error = 0;
                                /* fall thru */
                        default:
-                               moveon = false;
-                               errno = error;
                                goto err;
                        }
                        if (xfs_scrub_excessive_errors(ctx)) {
-                               moveon = false;
+                               si->aborted = true;
                                goto out;
                        }
                }
 
                stale_count = 0;
 igrp_retry:
-               error = ioctl(ctx->mnt.fd, XFS_IOC_FSINUMBERS, &igrpreq);
+               error = -xfrog_inumbers(&ctx->mnt, ireq);
        }
 
 err:
        if (error) {
-               str_errno(ctx, descr);
-               moveon = false;
+               str_liberror(ctx, error, descr);
+               si->aborted = true;
        }
 out:
-       return moveon;
+       free(ireq);
+       free(breq);
 }
 
-/* BULKSTAT wrapper routines. */
-struct xfs_scan_inodes {
-       xfs_inode_iter_fn       fn;
-       void                    *arg;
-       bool                    moveon;
-};
-
-/* Scan all the inodes in an AG. */
-static void
-xfs_scan_ag_inodes(
-       struct workqueue        *wq,
-       xfs_agnumber_t          agno,
-       void                    *arg)
-{
-       struct xfs_scan_inodes  *si = arg;
-       struct scrub_ctx        *ctx = (struct scrub_ctx *)wq->wq_ctx;
-       char                    descr[DESCR_BUFSZ];
-       uint64_t                ag_ino;
-       uint64_t                next_ag_ino;
-       bool                    moveon;
-
-       snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
-                               major(ctx->fsinfo.fs_datadev),
-                               minor(ctx->fsinfo.fs_datadev),
-                               agno);
-
-       ag_ino = cvt_agino_to_ino(&ctx->mnt, agno, 0);
-       next_ag_ino = cvt_agino_to_ino(&ctx->mnt, agno + 1, 0);
-
-       moveon = xfs_iterate_inodes_range(ctx, descr, ctx->fshandle, ag_ino,
-                       next_ag_ino - 1, si->fn, si->arg);
-       if (!moveon)
-               si->moveon = false;
-}
-
-/* Scan all the inodes in a filesystem. */
-bool
-xfs_scan_all_inodes(
+/*
+ * Scan all the inodes in a filesystem.  On error, this function will log
+ * an error message and return -1.
+ */
+int
+scrub_scan_all_inodes(
        struct scrub_ctx        *ctx,
-       xfs_inode_iter_fn       fn,
+       scrub_inode_iter_fn     fn,
        void                    *arg)
 {
-       struct xfs_scan_inodes  si;
+       struct scan_inodes      si = {
+               .fn             = fn,
+               .arg            = arg,
+       };
        xfs_agnumber_t          agno;
        struct workqueue        wq;
        int                     ret;
 
-       si.moveon = true;
-       si.fn = fn;
-       si.arg = arg;
-
-       ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
+       ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
                        scrub_nproc_workqueue(ctx));
        if (ret) {
-               str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
-               return false;
+               str_liberror(ctx, ret, _("creating bulkstat workqueue"));
+               return -1;
        }
 
        for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
-               ret = workqueue_add(&wq, xfs_scan_ag_inodes, agno, &si);
+               ret = -workqueue_add(&wq, scan_ag_inodes, agno, &si);
                if (ret) {
-                       si.moveon = false;
-                       str_info(ctx, ctx->mntpoint,
-_("Could not queue AG %u bulkstat work."), agno);
+                       si.aborted = true;
+                       str_liberror(ctx, ret, _("queueing bulkstat work"));
                        break;
                }
        }
 
+       ret = -workqueue_terminate(&wq);
+       if (ret) {
+               si.aborted = true;
+               str_liberror(ctx, ret, _("finishing bulkstat work"));
+       }
        workqueue_destroy(&wq);
 
-       return si.moveon;
+       return si.aborted ? -1 : 0;
 }
 
-/*
- * Open a file by handle, or return a negative error code.
- */
+/* Open a file by handle, returning either the fd or -1 on error. */
 int
-xfs_open_handle(
+scrub_open_handle(
        struct xfs_handle       *handle)
 {
        return open_by_fshandle(handle, sizeof(*handle),