]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect: account for EBUSY when verity device already exists
authorLuca Boccassi <luca.boccassi@microsoft.com>
Mon, 10 Aug 2020 10:15:48 +0000 (11:15 +0100)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Fri, 14 Aug 2020 14:26:04 +0000 (15:26 +0100)
In some cases, libdevmapper/libcrypsetup might return EBUSY instead of
EEXIST when opening a shared device. Treat it in the same way.

src/shared/dissect-image.c

index 48b98c4f2de879f4573c2dda106c67e6f0767327..97f0e46e7887a3f864258f9fdfdbaafcd1b8f61d 100644 (file)
@@ -1430,26 +1430,33 @@ static int verity_partition(
                  * Improvements in libcrypsetup can ensure this never happens: https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */
                 if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
                         return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
-                if (!IN_SET(r, 0, -EEXIST, -ENODEV))
+                if (!IN_SET(r,
+                            0, /* Success */
+                            -EEXIST, /* Volume is already open and ready to be used */
+                            -EBUSY, /* Volume is being opened but not ready, crypt_init_by_name can fetch details */
+                            -ENODEV /* Volume is being opened but not ready, crypt_init_by_name would fail, try to open again */))
                         return r;
-                if (r == -EEXIST) {
+                if (IN_SET(r, -EEXIST, -EBUSY)) {
                         struct crypt_device *existing_cd = NULL;
 
                         if (!restore_deferred_remove){
                                 /* To avoid races, disable automatic removal on umount while setting up the new device. Restore it on failure. */
                                 r = dm_deferred_remove_cancel(name);
-                                if (r < 0)
+                                /* If activation returns EBUSY there might be no deferred removal to cancel, that's fine */
+                                if (r < 0 && r != -ENXIO)
                                         return log_debug_errno(r, "Disabling automated deferred removal for verity device %s failed: %m", node);
-                                restore_deferred_remove = strdup(name);
-                                if (!restore_deferred_remove)
-                                        return -ENOMEM;
+                                if (r == 0) {
+                                        restore_deferred_remove = strdup(name);
+                                        if (!restore_deferred_remove)
+                                                return -ENOMEM;
+                                }
                         }
 
                         r = verity_can_reuse(root_hash, root_hash_size, !!root_hash_sig || !!hash_sig_from_file, name, &existing_cd);
                         /* Same as above, -EINVAL can randomly happen when it actually means -EEXIST */
                         if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
                                 return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
-                        if (!IN_SET(r, 0, -ENODEV, -ENOENT))
+                        if (!IN_SET(r, 0, -ENODEV, -ENOENT, -EBUSY))
                                 return log_debug_errno(r, "Checking whether existing verity device %s can be reused failed: %m", node);
                         if (r == 0) {
                                 /* devmapper might say that the device exists, but the devlink might not yet have been