]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
btrfs-util: use BTRFS_IOC_GET_SUBVOL_INFO ioctl()
authorLennart Poettering <lennart@poettering.net>
Tue, 15 Jul 2025 15:03:58 +0000 (17:03 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 15 Jul 2025 15:24:18 +0000 (17:24 +0200)
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).

src/shared/btrfs-util.c

index 61fe50e012aa999c2d5c901957d3cd9916f9de4c..869eb490f8ec84686fa4fc3121fc44f99b0e2025 100644 (file)
@@ -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) {