xfs: allow parent directory scans to be interrupted with fatal signals
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 26 Nov 2019 02:43:10 +0000 (18:43 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 27 Nov 2019 16:23:14 +0000 (08:23 -0800)
Allow a fatal signal to interrupt us when we're scanning a directory to
verify a parent pointer.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/xfs/scrub/parent.c

index 17100a8..5705adc 100644 (file)
@@ -32,8 +32,10 @@ xchk_setup_parent(
 
 struct xchk_parent_ctx {
        struct dir_context      dc;
+       struct xfs_scrub        *sc;
        xfs_ino_t               ino;
        xfs_nlink_t             nlink;
+       bool                    cancelled;
 };
 
 /* Look for a single entry in a directory pointing to an inode. */
@@ -47,11 +49,21 @@ xchk_parent_actor(
        unsigned                type)
 {
        struct xchk_parent_ctx  *spc;
+       int                     error = 0;
 
        spc = container_of(dc, struct xchk_parent_ctx, dc);
        if (spc->ino == ino)
                spc->nlink++;
-       return 0;
+
+       /*
+        * If we're facing a fatal signal, bail out.  Store the cancellation
+        * status separately because the VFS readdir code squashes error codes
+        * into short directory reads.
+        */
+       if (xchk_should_terminate(spc->sc, &error))
+               spc->cancelled = true;
+
+       return error;
 }
 
 /* Count the number of dentries in the parent dir that point to this inode. */
@@ -62,10 +74,9 @@ xchk_parent_count_parent_dentries(
        xfs_nlink_t             *nlink)
 {
        struct xchk_parent_ctx  spc = {
-               .dc.actor = xchk_parent_actor,
-               .dc.pos = 0,
-               .ino = sc->ip->i_ino,
-               .nlink = 0,
+               .dc.actor       = xchk_parent_actor,
+               .ino            = sc->ip->i_ino,
+               .sc             = sc,
        };
        size_t                  bufsize;
        loff_t                  oldpos;
@@ -97,6 +108,10 @@ xchk_parent_count_parent_dentries(
                error = xfs_readdir(sc->tp, parent, &spc.dc, bufsize);
                if (error)
                        goto out;
+               if (spc.cancelled) {
+                       error = -EAGAIN;
+                       goto out;
+               }
                if (oldpos == spc.dc.pos)
                        break;
                oldpos = spc.dc.pos;