From: Lennart Poettering Date: Tue, 15 Jul 2025 15:03:58 +0000 (+0200) Subject: btrfs-util: use BTRFS_IOC_GET_SUBVOL_INFO ioctl() X-Git-Tag: v258-rc1~51^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95e63822c26682efea6ca52550989e27d7e82188;p=thirdparty%2Fsystemd.git btrfs-util: use BTRFS_IOC_GET_SUBVOL_INFO ioctl() Since kernel 4.18 BTRFS_IOC_GET_SUBVOL_INFO exists to query subvolume metadata without privs. This is much better than the manual approach with finding objects in the fs tree (which is priv). Let's use it, and drop the old code (since 4.18 is older than our baseline). --- diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 61fe50e012a..869eb490f8e 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -299,23 +299,6 @@ static int btrfs_iterate(BtrfsForeachIterator *i) { btrfs_iterate(&iterator) > 0; ) int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) { - struct btrfs_ioctl_search_args args = { - /* Tree of tree roots */ - .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, - - /* Look precisely for the subvolume items */ - .key.min_type = BTRFS_ROOT_ITEM_KEY, - .key.max_type = BTRFS_ROOT_ITEM_KEY, - - .key.min_offset = 0, - .key.max_offset = UINT64_MAX, - - /* No restrictions on the other components */ - .key.min_transid = 0, - .key.max_transid = UINT64_MAX, - }; - - bool found = false; int r; assert(fd >= 0); @@ -327,66 +310,29 @@ int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) { if (fd < 0) return fd; - if (subvol_id == 0) { - r = btrfs_subvol_get_id_fd(fd, &subvol_id); - if (r < 0) - return r; - } else { - r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC); - if (r < 0) - return r; - if (r == 0) - return -ENOTTY; - } - - args.key.min_objectid = args.key.max_objectid = subvol_id; - - while (btrfs_ioctl_search_args_compare(&args) <= 0) { - struct btrfs_ioctl_search_header sh; - const void *body; - - args.key.nr_items = 256; - if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) - return -errno; - - if (args.key.nr_items <= 0) - break; - - FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args) { - /* Make sure we start the next search at least from this entry */ - btrfs_ioctl_search_args_set(&args, &sh); - - if (sh.objectid != subvol_id) - continue; - if (sh.type != BTRFS_ROOT_ITEM_KEY) - continue; - - /* Older versions of the struct lacked the otime setting */ - if (sh.len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec)) - continue; + r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC); + if (r < 0) + return r; + if (r == 0) + return -ENOTTY; - const struct btrfs_root_item *ri = body; - ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC + - (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC; + struct btrfs_ioctl_get_subvol_info_args info; + if (ioctl(fd, BTRFS_IOC_GET_SUBVOL_INFO, &info) < 0) + return -errno; - ret->subvol_id = subvol_id; - ret->read_only = le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY; + *ret = (BtrfsSubvolInfo) { + .subvol_id = info.treeid, + .otime = info.otime.sec * USEC_PER_SEC + (info.otime.nsec / NSEC_PER_USEC), + .read_only = FLAGS_SET(info.flags, BTRFS_SUBVOL_RDONLY), + }; - assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid)); - memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid)); - memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid)); + assert_cc(sizeof(info.uuid) == sizeof(sd_id128_t)); + memcpy(&ret->uuid, info.uuid, sizeof(sd_id128_t)); - found = true; - goto finish; - } + assert_cc(sizeof(info.parent_uuid) == sizeof(sd_id128_t)); + memcpy(&ret->parent_uuid, info.parent_uuid, sizeof(sd_id128_t)); - /* Increase search key by one, to read the next item, if we can. */ - if (!btrfs_ioctl_search_args_inc(&args)) - break; - } - -finish: - return found ? 0 : -ENODATA; + return 0; } int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) {