X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fbtrfs-util.c;h=164ac9f337c8522c5ec393cd9f82ec7573918140;hp=84c81106fa2a1fdd0cc9438408ac1a637e1ddb2e;hb=b6b1849830f5e4a6065c3b0c993668e500c954d3;hpb=10f9c75519671e7c7ab8993b54fe22da7c2d0c38 diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 84c81106f..164ac9f33 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -33,6 +33,8 @@ #include "macro.h" #include "strv.h" #include "copy.h" +#include "selinux-util.h" +#include "smack-util.h" #include "btrfs-ctree.h" #include "btrfs-util.h" @@ -184,6 +186,24 @@ int btrfs_subvol_make(const char *path) { return 0; } +int btrfs_subvol_make_label(const char *path) { + int r; + + assert(path); + + r = mac_selinux_create_file_prepare(path, S_IFDIR); + if (r < 0) + return r; + + r = btrfs_subvol_make(path); + mac_selinux_create_file_clear(); + + if (r < 0) + return r; + + return mac_smack_fix(path, false, false); +} + int btrfs_subvol_remove(const char *path) { struct btrfs_ioctl_vol_args args = {}; _cleanup_close_ int fd = -1; @@ -321,7 +341,7 @@ int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) { int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { struct btrfs_ioctl_search_args args = { /* Tree of tree roots */ - .key.tree_id = 1, + .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, /* Look precisely for the subvolume items */ .key.min_type = BTRFS_ROOT_ITEM_KEY, @@ -332,14 +352,10 @@ int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { .key.max_offset = (uint64_t) -1, .key.min_transid = 0, .key.max_transid = (uint64_t) -1, - - /* Some large value */ - .key.nr_items = 2, }; - struct btrfs_ioctl_search_header *sh; - struct btrfs_root_item *ri; uint64_t subvol_id; + bool found = false; int r; assert(fd >= 0); @@ -350,30 +366,168 @@ int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { return r; args.key.min_objectid = args.key.max_objectid = subvol_id; - if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) - return -errno; - if (args.key.nr_items != 1) - return -EIO; + for (;;) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + return -errno; + + if (args.key.nr_items <= 0) + break; + + for (i = 0, + sh = (const struct btrfs_ioctl_search_header*) args.buf; + i < args.key.nr_items; + i++, + args.key.min_type = sh->type, + args.key.min_offset = sh->offset, + args.key.min_objectid = sh->objectid, + sh = (const struct btrfs_ioctl_search_header*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header) + sh->len)) { + + const struct btrfs_root_item *ri; + + if (sh->objectid != subvol_id) + continue; + if (sh->type != BTRFS_ROOT_ITEM_KEY) + continue; + if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec)) + continue; + + ri = (const struct btrfs_root_item *)(args.buf + sizeof(struct btrfs_ioctl_search_header)); + + ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC + + (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC; + + ret->subvol_id = subvol_id; + ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_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)); + + found = true; + goto finish; + } + + args.key.min_offset++; + if (!args.key.min_offset) /* overflow */ + break; + } + +finish: + if (!found) + return -ENODATA; + + return 0; +} + +int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { + + struct btrfs_ioctl_search_args args = { + /* Tree of quota items */ + .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID, + + /* Look precisely for the quota items */ + .key.min_type = BTRFS_QGROUP_STATUS_KEY, + .key.max_type = BTRFS_QGROUP_LIMIT_KEY, + + .key.min_objectid = 0, + .key.max_objectid = 0, + + /* No restrictions on the other components */ + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + + uint64_t subvol_id; + bool found_info = false, found_limit = false; + int r; + + assert(fd >= 0); + assert(ret); + + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + + args.key.min_offset = args.key.max_offset = subvol_id; - sh = (struct btrfs_ioctl_search_header*) args.buf; - assert(sh->type == BTRFS_ROOT_ITEM_KEY); - assert(sh->objectid == subvol_id); + for (;;) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; - if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec)) - return -ENOTSUP; + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + return -errno; - ri = (struct btrfs_root_item *)(args.buf + sizeof(struct btrfs_ioctl_search_header)); + if (args.key.nr_items <= 0) + break; - ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC + - (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC; + for (i = 0, + sh = (const struct btrfs_ioctl_search_header*) args.buf; + i < args.key.nr_items; + i++, + args.key.min_type = sh->type, + args.key.min_offset = sh->offset, + args.key.min_objectid = sh->objectid, + sh = (const struct btrfs_ioctl_search_header*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header) + sh->len)) { - ret->subvol_id = subvol_id; - ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY); + const void *body; - 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)); + if (sh->objectid != 0) + continue; + if (sh->offset != subvol_id) + continue; + + body = (uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header); + + if (sh->type == BTRFS_QGROUP_INFO_KEY) { + const struct btrfs_qgroup_info_item *qii = body; + + ret->referred = le64toh(qii->rfer); + ret->exclusive = le64toh(qii->excl); + + found_info = true; + + } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) { + const struct btrfs_qgroup_limit_item *qli = body; + + ret->referred_max = le64toh(qli->max_rfer); + ret->exclusive_max = le64toh(qli->max_excl); + + if (ret->referred_max == 0) + ret->referred_max = (uint64_t) -1; + if (ret->exclusive_max == 0) + ret->exclusive_max = (uint64_t) -1; + + found_limit = true; + } + + if (found_info && found_limit) + goto finish; + } + + args.key.min_offset++; + if (!args.key.min_offset) + break; + } + +finish: + if (!found_limit && !found_info) + return -ENODATA; + + if (!found_info) { + ret->referred = (uint64_t) -1; + ret->exclusive = (uint64_t) -1; + } + + if (!found_limit) { + ret->referred_max = (uint64_t) -1; + ret->exclusive_max = (uint64_t) -1; + } return 0; }