]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_scrub: handle concurrent directory updates during name scan
authorDarrick J. Wong <djwong@kernel.org>
Fri, 12 Feb 2021 22:23:06 +0000 (17:23 -0500)
committerEric Sandeen <sandeen@sandeen.net>
Fri, 12 Feb 2021 22:23:06 +0000 (17:23 -0500)
The name scanner in xfs_scrub cannot lock a namespace (dirent or xattr)
and the kernel does not provide a stable cursor interface, which means
that we can see the same byte sequence multiple times during a scan.
This isn't a confusing name error since the kernel enforces uniqueness
on the byte sequence, so all we need to do here is update the old entry.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
scrub/unicrash.c

index de3217c2932df29cad2ff799e663d4ec7f94c0f1..cb0880c1040a73ae3e4c5bf69b4823c9dfc77898 100644 (file)
@@ -68,7 +68,7 @@ struct name_entry {
 
        xfs_ino_t               ino;
 
-       /* Raw UTF8 name */
+       /* Raw dirent name */
        size_t                  namelen;
        char                    name[0];
 };
@@ -627,6 +627,20 @@ unicrash_add(
        uc->buckets[bucket] = new_entry;
 
        while (entry != NULL) {
+               /*
+                * If we see the same byte sequence then someone's modifying
+                * the namespace while we're scanning it.  Update the existing
+                * entry's inode mapping and erase the new entry from existence.
+                */
+               if (new_entry->namelen == entry->namelen &&
+                   !memcmp(new_entry->name, entry->name, entry->namelen)) {
+                       entry->ino = new_entry->ino;
+                       uc->buckets[bucket] = new_entry->next;
+                       name_entry_free(new_entry);
+                       *badflags = 0;
+                       return;
+               }
+
                /* Same normalization? */
                if (new_entry->normstrlen == entry->normstrlen &&
                    !u_strcmp(new_entry->normstr, entry->normstr) &&