From 67f0ac8c79bb08451a70ee314daf06ee081ef24d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2020 18:50:41 +0200 Subject: [PATCH 1/2] btrfs: if BTRFS_IOC_DEV_INFO returns /dev/root generate a friendly error message On systems that boot without initrd on a btrfs root file systems the BTRFS_IOC_DEV_INFO ioctl returns /dev/root as backing device. That sucks, since that is not a real device visible to userspace. Since this has been that way since forever, and it doesn't look like the kernel will get fixed soon for this, let's at least generate a useful error message in this case. This is not a bug fix, just a tweak to make this more recognizable. Once the kernel gets fixed to report the correct device nodes in this case, in a way userspace can make sense of them things will magically work for systemd, too. (Note that this doesn't add a log message about this to really all cases we call get_device() in, but just the main ones that are called in early boot context, after all all there's no benefit in seeing this message too many times.) https://github.com/systemd/systemd/issues/16953 https://bugs.freedesktop.org/show_bug.cgi?id=84689 https://bugzilla.kernel.org/show_bug.cgi?id=89721 --- src/basic/btrfs-util.c | 9 +++++++++ src/basic/btrfs-util.h | 6 ++++++ src/gpt-auto-generator/gpt-auto-generator.c | 4 ++++ src/partition/growfs.c | 3 +++ src/partition/repart.c | 6 ++++++ 5 files changed, 28 insertions(+) diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 71e1bc92eb7..7de77707373 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -315,6 +315,15 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) { return -errno; } + /* For the root fs — when no initrd is involved — btrfs returns /dev/root on any kernels from + * the past few years. That sucks, as we have no API to determine the actual root then. let's + * return an recognizable error for this case, so that the caller can maybe print a nice + * message about this. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=89721 */ + if (path_equal((char*) di.path, "/dev/root")) + return -EUCLEAN; + if (stat((char*) di.path, &st) < 0) return -errno; diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index c1bbb42ca1b..d9cb95af006 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -121,3 +121,9 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret); int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota); int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota); + +static inline int btrfs_log_dev_root(int level, int ret, const char *p) { + return log_full_errno(level, ret, + "File system behind %s is reported by btrfs to be backed by pseudo-device /dev/root, which is not a valid userspace accessible device node. " + "Cannot determine correct backing block device.", p); +} diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 02d8837ca9b..d1c90266a8f 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -729,10 +729,14 @@ static int add_mounts(void) { int r; r = get_block_device_harder("/", &devno); + if (r == -EUCLEAN) + return btrfs_log_dev_root(LOG_ERR, r, "root file system"); if (r < 0) return log_error_errno(r, "Failed to determine block device of root file system: %m"); if (r == 0) { r = get_block_device_harder("/usr", &devno); + if (r == -EUCLEAN) + return btrfs_log_dev_root(LOG_ERR, r, "/usr"); if (r < 0) return log_error_errno(r, "Failed to determine block device of /usr file system: %m"); if (r == 0) { diff --git a/src/partition/growfs.c b/src/partition/growfs.c index c097963e0cd..8c1a84d981e 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -11,6 +11,7 @@ #include #include "blockdev-util.h" +#include "btrfs-util.h" #include "cryptsetup-util.h" #include "device-nodes.h" #include "dissect-image.h" @@ -212,6 +213,8 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "\"%s\" is not a mount point: %m", arg_target); r = get_block_device(arg_target, &devno); + if (r == -EUCLEAN) + return btrfs_log_dev_root(LOG_ERR, r, arg_target); if (r < 0) return log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target); diff --git a/src/partition/repart.c b/src/partition/repart.c index bcbf2273e86..f5015b73a13 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3369,6 +3369,8 @@ static int context_open_copy_block_paths(Context *context) { /* Special support for btrfs */ r = btrfs_get_block_device_fd(source_fd, &devt); + if (r == -EUCLEAN) + return btrfs_log_dev_root(LOG_ERR, r, p->copy_blocks_path); if (r < 0) return log_error_errno(r, "Unable to determine backing block device of '%s': %m", p->copy_blocks_path); @@ -3833,6 +3835,8 @@ static int find_root(char **ret, int *ret_fd) { } r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret, ret_fd); + if (r == -EUCLEAN) + return btrfs_log_dev_root(LOG_ERR, r, arg_node); if (r < 0) return log_error_errno(r, "Failed to open file or determine backing device of %s: %m", arg_node); @@ -3860,6 +3864,8 @@ static int find_root(char **ret, int *ret_fd) { r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret, ret_fd); if (r < 0) { + if (r == -EUCLEAN) + return btrfs_log_dev_root(LOG_ERR, r, p); if (r != -ENODEV) return log_error_errno(r, "Failed to determine backing device of %s: %m", p); } else From d161680e7afb7ae01593ffc5deb6c02bbc08ed19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2020 19:01:41 +0200 Subject: [PATCH 2/2] tree-wide: if get_block_device() returns zero devno, check for it in all cases And add a comment for the existing cases where things aren't clear already. --- src/basic/quota-util.c | 2 +- src/gpt-auto-generator/gpt-auto-generator.c | 2 +- src/partition/growfs.c | 4 ++++ src/shared/sleep-config.c | 2 ++ src/volatile-root/volatile-root.c | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/basic/quota-util.c b/src/basic/quota-util.c index e048f5571fc..96ea9ee3643 100644 --- a/src/basic/quota-util.c +++ b/src/basic/quota-util.c @@ -34,7 +34,7 @@ int quotactl_path(int cmd, const char *path, int id, void *addr) { r = get_block_device(path, &devno); if (r < 0) return r; - if (devno == 0) + if (devno == 0) /* Doesn't have a block device */ return -ENODEV; return quotactl_devno(cmd, devno, id, addr); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index d1c90266a8f..16086c8b86c 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -733,7 +733,7 @@ static int add_mounts(void) { return btrfs_log_dev_root(LOG_ERR, r, "root file system"); if (r < 0) return log_error_errno(r, "Failed to determine block device of root file system: %m"); - if (r == 0) { + if (r == 0) { /* Not backed by block device */ r = get_block_device_harder("/usr", &devno); if (r == -EUCLEAN) return btrfs_log_dev_root(LOG_ERR, r, "/usr"); diff --git a/src/partition/growfs.c b/src/partition/growfs.c index 8c1a84d981e..3f34ad3f7c9 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -97,6 +97,8 @@ static int maybe_resize_underlying_device(const char *mountpath, dev_t main_devn if (r < 0) return log_error_errno(r, "Failed to determine underlying block device of \"%s\": %m", mountpath); + if (devno == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" not backed by block device.", arg_target); log_debug("Underlying device %d:%d, main dev %d:%d, %s", major(devno), minor(devno), @@ -217,6 +219,8 @@ static int run(int argc, char *argv[]) { return btrfs_log_dev_root(LOG_ERR, r, arg_target); if (r < 0) return log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target); + if (devno == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" not backed by block device.", arg_target); r = maybe_resize_underlying_device(arg_target, devno); if (r < 0) diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 0dccc8f9700..96c125b993e 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -403,6 +403,8 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location) { r = swap_device_to_device_id(swap, &swap_device); if (r < 0) return log_debug_errno(r, "%s: failed to query device number: %m", swap->device); + if (swap_device == 0) + return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "%s: not backed by block device.", swap->device); hibernate_location = hibernate_location_free(hibernate_location); hibernate_location = new(HibernateLocation, 1); diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c index e55864d6cc1..6a084642454 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c @@ -175,7 +175,7 @@ static int run(int argc, char *argv[]) { r = get_block_device_harder(path, &devt); if (r < 0) return log_error_errno(r, "Failed to determine device major/minor of %s: %m", path); - else if (r > 0) { + else if (r > 0) { /* backed by block device */ _cleanup_free_ char *dn = NULL; r = device_path_make_major_minor(S_IFBLK, devt, &dn);