diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/btrfs-ctree.h | 23 | ||||
-rw-r--r-- | src/shared/btrfs-util.c | 180 | ||||
-rw-r--r-- | src/shared/btrfs-util.h | 8 | ||||
-rw-r--r-- | src/shared/machine-image.c | 15 | ||||
-rw-r--r-- | src/shared/machine-image.h | 5 | ||||
-rw-r--r-- | src/shared/missing.h | 20 |
6 files changed, 228 insertions, 23 deletions
diff --git a/src/shared/btrfs-ctree.h b/src/shared/btrfs-ctree.h index 45b94cdbf6..7bdf3fe139 100644 --- a/src/shared/btrfs-ctree.h +++ b/src/shared/btrfs-ctree.h @@ -66,3 +66,26 @@ struct btrfs_root_item { } _packed_; #define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) + +struct btrfs_qgroup_info_item { + le64_t generation; + le64_t rfer; + le64_t rfer_cmpr; + le64_t excl; + le64_t excl_cmpr; +} _packed_; + +#define BTRFS_QGROUP_LIMIT_MAX_RFER (1ULL << 0) +#define BTRFS_QGROUP_LIMIT_MAX_EXCL (1ULL << 1) +#define BTRFS_QGROUP_LIMIT_RSV_RFER (1ULL << 2) +#define BTRFS_QGROUP_LIMIT_RSV_EXCL (1ULL << 3) +#define BTRFS_QGROUP_LIMIT_RFER_CMPR (1ULL << 4) +#define BTRFS_QGROUP_LIMIT_EXCL_CMPR (1ULL << 5) + +struct btrfs_qgroup_limit_item { + le64_t flags; + le64_t max_rfer; + le64_t max_excl; + le64_t rsv_rfer; + le64_t rsv_excl; +} _packed_; diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 9b47330a6f..164ac9f337 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -341,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, @@ -352,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); @@ -370,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; - sh = (struct btrfs_ioctl_search_header*) args.buf; - assert(sh->type == BTRFS_ROOT_ITEM_KEY); - assert(sh->objectid == subvol_id); + 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)) { - if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec)) - return -ENOTSUP; + 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 = (struct btrfs_root_item *)(args.buf + sizeof(struct btrfs_ioctl_search_header)); + 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->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); + 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)); + 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; + + 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 void *body; + + 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; } diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h index dff8c015a6..1532c120df 100644 --- a/src/shared/btrfs-util.h +++ b/src/shared/btrfs-util.h @@ -34,6 +34,13 @@ typedef struct BtrfsSubvolInfo { bool read_only; } BtrfsSubvolInfo; +typedef struct BtrfsQuotaInfo { + uint64_t referred; + uint64_t exclusive; + uint64_t referred_max; + uint64_t exclusive_max; +} BtrfsQuotaInfo; + int btrfs_is_snapshot(int fd); int btrfs_subvol_make(const char *path); @@ -45,6 +52,7 @@ int btrfs_subvol_set_read_only(const char *path, bool b); int btrfs_subvol_get_read_only_fd(int fd); int btrfs_subvol_get_id_fd(int fd, uint64_t *ret); int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info); +int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota); int btrfs_reflink(int infd, int outfd); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 7c041fab76..36b64e1fab 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -71,6 +71,8 @@ static int image_new( i->read_only = read_only; i->crtime = crtime; i->mtime = mtime; + i->size = i->size_exclusive = (uint64_t) -1; + i->limit = i->limit_exclusive = (uint64_t) -1; i->name = strdup(pretty); if (!i->name) @@ -138,6 +140,7 @@ static int image_make( if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) { BtrfsSubvolInfo info; + BtrfsQuotaInfo quota; /* It's a btrfs subvolume */ @@ -156,6 +159,15 @@ static int image_make( if (r < 0) return r; + r = btrfs_subvol_get_quota_fd(fd, "a); + if (r >= 0) { + (*ret)->size = quota.referred; + (*ret)->size_exclusive = quota.exclusive; + + (*ret)->limit = quota.referred_max; + (*ret)->limit_exclusive = quota.exclusive_max; + } + return 1; } } @@ -199,6 +211,9 @@ static int image_make( if (r < 0) return r; + (*ret)->size = (*ret)->size_exclusive = st.st_blocks * 512; + (*ret)->limit = (*ret)->limit_exclusive = st.st_size; + return 1; } diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index 9e0f6aedba..10e5d0a533 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -40,6 +40,11 @@ typedef struct Image { usec_t crtime; usec_t mtime; + + uint64_t size; + uint64_t size_exclusive; + uint64_t limit; + uint64_t limit_exclusive; } Image; Image *image_unref(Image *i); diff --git a/src/shared/missing.h b/src/shared/missing.h index 08cf83647d..94d9d8d35d 100644 --- a/src/shared/missing.h +++ b/src/shared/missing.h @@ -254,10 +254,30 @@ struct btrfs_ioctl_fs_info_args { #define BTRFS_FIRST_FREE_OBJECTID 256 #endif +#ifndef BTRFS_ROOT_TREE_OBJECTID +#define BTRFS_ROOT_TREE_OBJECTID 1 +#endif + +#ifndef BTRFS_QUOTA_TREE_OBJECTID +#define BTRFS_QUOTA_TREE_OBJECTID 8ULL +#endif + #ifndef BTRFS_ROOT_ITEM_KEY #define BTRFS_ROOT_ITEM_KEY 132 #endif +#ifndef BTRFS_QGROUP_STATUS_KEY +#define BTRFS_QGROUP_STATUS_KEY 240 +#endif + +#ifndef BTRFS_QGROUP_INFO_KEY +#define BTRFS_QGROUP_INFO_KEY 242 +#endif + +#ifndef BTRFS_QGROUP_LIMIT_KEY +#define BTRFS_QGROUP_LIMIT_KEY 244 +#endif + #ifndef BTRFS_SUPER_MAGIC #define BTRFS_SUPER_MAGIC 0x9123683E #endif |