From 9ecb5c10fdfadc945fda93b0b28fb88d1102d399 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Mon, 10 Aug 2020 11:15:48 +0100 Subject: [PATCH] dissect: account for EBUSY when verity device already exists 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 | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 48b98c4f2d..97f0e46e78 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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