]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_scrub: detect and repair directory tree corruptions
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)
Now that we have online fsck for directory tree structure problems, we
need to find a place to call it.  The scanner requires that parent
pointers are enabled, that directory link counts are correct, and that
every directory entry has a corresponding parent pointer.  Therefore, we
can only run it after phase 4 fixes every file, and phase 5 resets the
link counts.

In other words, we call it as part of the phase 5 file scan that we do
to warn about weird looking file names.  This has the added benefit that
opening the directory by handle is less likely to fail if there are
loops in the directory structure.  For now, only plumb in enough to try
to fix directory tree problems right away; the next patch will make
phase 5 retry the dirloop scanner until the problems are fixed or we
stop making forward progress.

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

index b3719627755485c2fde37121e49dd8db8b9f8745..6c8dee66e6e2f7486ff9257c9560b4a02eaae232 100644 (file)
@@ -252,6 +252,47 @@ render_ino_from_handle(
                        bstat->bs_gen, NULL);
 }
 
+/*
+ * Check the directory structure for problems that could cause open_by_handle
+ * not to work.  Returns 0 for no problems; EADDRNOTAVAIL if the there are
+ * problems that would prevent name checking.
+ */
+static int
+check_dir_connection(
+       struct scrub_ctx                *ctx,
+       struct descr                    *dsc,
+       const struct xfs_bulkstat       *bstat)
+{
+       struct scrub_item               sri = { };
+       int                             error;
+
+       /* The dirtree scrubber only works when parent pointers are enabled */
+       if (!(ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_PARENT))
+               return 0;
+
+       scrub_item_init_file(&sri, bstat);
+       scrub_item_schedule(&sri, XFS_SCRUB_TYPE_DIRTREE);
+
+       error = scrub_item_check_file(ctx, &sri, -1);
+       if (error) {
+               str_liberror(ctx, error, _("checking directory loops"));
+               return error;
+       }
+
+       error = repair_file_corruption(ctx, &sri, -1);
+       if (error) {
+               str_liberror(ctx, error, _("repairing directory loops"));
+               return error;
+       }
+
+       /* No directory tree problems?  Clear this inode if it was deferred. */
+       if (repair_item_count_needsrepair(&sri) == 0)
+               return 0;
+
+       str_corrupt(ctx, descr_render(dsc), _("directory loop uncorrected!"));
+       return EADDRNOTAVAIL;
+}
+
 /*
  * Verify the connectivity of the directory tree.
  * We know that the kernel's open-by-handle function will try to reconnect
@@ -275,6 +316,20 @@ check_inode_names(
        descr_set(&dsc, bstat);
        background_sleep();
 
+       /*
+        * Try to fix directory loops before we have problems opening files by
+        * handle.
+        */
+       if (S_ISDIR(bstat->bs_mode)) {
+               error = check_dir_connection(ctx, &dsc, bstat);
+               if (error == EADDRNOTAVAIL) {
+                       error = 0;
+                       goto out;
+               }
+               if (error)
+                       goto err;
+       }
+
        /* Warn about naming problems in xattrs. */
        if (bstat->bs_xflags & FS_XFLAG_HASATTR) {
                error = check_xattr_names(ctx, &dsc, handle, bstat);
@@ -315,6 +370,7 @@ err_fd:
 err:
        if (error)
                *aborted = true;
+out:
        if (!error && *aborted)
                error = ECANCELED;