diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 5e6d782fdb..e7dc26794c 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -1433,6 +1433,11 @@ int home_setup_luks( return r; } + /* Before we make the loop device, make sure offset is zero & we are using the full partition + * If our offset is not zero, loop_device_make will create a loop device on top of the block device */ + if (S_ISBLK(st.st_mode)) + assert(offset == 0 && size == UINT64_MAX); + r = loop_device_make( setup->image_fd, O_RDWR, @@ -2191,6 +2196,7 @@ int home_create_luks( _cleanup_close_ int mount_fd = -EBADF; const char *fstype, *ip; struct statfs sfs; + struct stat st; int r; _cleanup_strv_free_ char **extra_mkfs_options = NULL; @@ -2263,7 +2269,6 @@ int home_create_luks( if (path_startswith(ip, "/dev/")) { _cleanup_free_ char *sysfs = NULL; uint64_t block_device_size; - struct stat st; /* Let's place the home directory on a real device, i.e. a USB stick or such */ @@ -2376,21 +2381,48 @@ int home_create_luks( log_info("Writing of partition table completed."); - r = loop_device_make( - setup->image_fd, - O_RDWR, - partition_offset, - partition_size, - image_sector_size, - 0, - LOCK_EX, - &setup->loop); - if (r == -ENOENT) /* this means /dev/loop-control doesn't exist, i.e. we are in a container - * or similar and loopback bock devices are not available, return a - * recognizable error in this case. */ - return log_error_errno(SYNTHETIC_ERRNO(ENOLINK), "Loopback block device support is not available on this system."); - if (r < 0) - return log_error_errno(r, "Failed to set up loopback device for %s: %m", setup->temporary_image_path); + if (fstat(setup->image_fd, &st) < 0) + return log_error_errno(errno, "Failed to fstat home image: %m"); + + /* Ensure we don't create a loop device over block device as it leads to huge overhead for discard operations + * if the device does not support discard_zeroes_data */ + if (S_ISBLK(st.st_mode)) { + _cleanup_free_ char *partition_path = NULL; + assert(!sd_id128_is_null(partition_uuid)); + if (asprintf(&partition_path, "/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(partition_uuid)) < 0) + return log_oom(); + + /* Release the lock, so that udev can find the partition */ + setup->image_fd = safe_close(setup->image_fd); + (void) wait_for_devlink(partition_path); + setup->image_fd = open_image_file(h, ip, &st); + if (setup->image_fd < 0) + return setup->image_fd; + + r = loop_device_open_from_path( + partition_path, + O_RDWR, + LOCK_EX, + &setup->loop); + if (r < 0) + return log_error_errno(r, "Failed to open newly written partition device: %s", partition_path); + } else { + r = loop_device_make( + setup->image_fd, + O_RDWR, + partition_offset, + partition_size, + image_sector_size, + 0, + LOCK_EX, + &setup->loop); + if (r == -ENOENT) /* this means /dev/loop-control doesn't exist, i.e. we are in a container + * or similar and loopback bock devices are not available, return a + * recognizable error in this case. */ + return log_error_errno(SYNTHETIC_ERRNO(ENOLINK), "Loopback block device support is not available on this system."); + if (r < 0) + return log_error_errno(r, "Failed to set up loopback device for %s: %m", setup->temporary_image_path); + } log_info("Setting up loopback device %s completed.", setup->loop->node ?: ip);