return CMP(args->key.min_offset, args->key.max_offset);
}
-#define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
- for ((i) = 0, \
- (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
- (i) < (args).key.nr_items; \
- (i)++, \
- (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
-
-#define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
- ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
+typedef struct BtrfsForeachIterator {
+ const void *p;
+ size_t i;
+} BtrfsForeachIterator;
+
+/* Iterates through a series of struct btrfs_file_extent_item elements. They are unfortunately not aligned,
+ * hence we copy out the header from them */
+#define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args) \
+ for (BtrfsForeachIterator iterator = { \
+ .p = ({ \
+ memcpy(&(sh), (args).buf, sizeof(struct btrfs_ioctl_search_header)); \
+ (body) = (const void*) ((const uint8_t*) (args).buf + sizeof(struct btrfs_ioctl_search_header)); \
+ (args).buf; \
+ }), \
+ }; \
+ iterator.i < (args).key.nr_items; \
+ iterator.i++, \
+ memcpy(&(sh), iterator.p = (const uint8_t*) iterator.p + sizeof(struct btrfs_ioctl_search_header) + (sh).len, sizeof(struct btrfs_ioctl_search_header)), \
+ (body) = (const void*) ((const uint8_t*) iterator.p + sizeof(struct btrfs_ioctl_search_header)))
int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) {
struct btrfs_ioctl_search_args args = {
args.key.min_objectid = args.key.max_objectid = subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
-
- const struct btrfs_root_item *ri;
-
+ 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);
+ btrfs_ioctl_search_args_set(&args, &sh);
- if (sh->objectid != subvol_id)
+ if (sh.objectid != subvol_id)
continue;
- if (sh->type != BTRFS_ROOT_ITEM_KEY)
+ 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))
+ if (sh.len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
continue;
- ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
-
+ 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;
args.key.min_offset = args.key.max_offset = qgroupid;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ 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);
+ btrfs_ioctl_search_args_set(&args, &sh);
- if (sh->objectid != 0)
+ if (sh.objectid != 0)
continue;
- if (sh->offset != qgroupid)
+ if (sh.offset != qgroupid)
continue;
- if (sh->type == BTRFS_QGROUP_INFO_KEY) {
- const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+ if (sh.type == BTRFS_QGROUP_INFO_KEY) {
+ const struct btrfs_qgroup_info_item *qii = body;
ret->referenced = 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 = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+ } else if (sh.type == BTRFS_QGROUP_LIMIT_KEY) {
+ const struct btrfs_qgroup_limit_item *qli = body;
if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER)
ret->referenced_max = le64toh(qli->max_rfer);
args.key.min_offset = args.key.max_offset = subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args) {
_cleanup_free_ char *p = NULL;
- const struct btrfs_root_ref *ref;
- btrfs_ioctl_search_args_set(&args, sh);
+ btrfs_ioctl_search_args_set(&args, &sh);
- if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ if (sh.type != BTRFS_ROOT_BACKREF_KEY)
continue;
- if (sh->offset != subvol_id)
+ if (sh.offset != subvol_id)
continue;
- ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
-
+ const struct btrfs_root_ref *ref = body;
p = memdup_suffix0((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
if (!p)
return -ENOMEM;
if (isempty(ino_args.name))
/* Subvolume is in the top-level
* directory of the subvolume. */
- r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
+ r = subvol_remove_children(subvol_fd, p, sh.objectid, flags);
else {
_cleanup_close_ int child_fd = -EBADF;
if (child_fd < 0)
return -errno;
- r = subvol_remove_children(child_fd, p, sh->objectid, flags);
+ r = subvol_remove_children(child_fd, p, sh.objectid, flags);
}
if (r < 0)
return r;
return -ENOTTY;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
- const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args) {
struct btrfs_ioctl_qgroup_limit_args qargs;
unsigned c;
/* Make sure we start the next search at least from this entry */
- btrfs_ioctl_search_args_set(&args, sh);
+ btrfs_ioctl_search_args_set(&args, &sh);
- if (sh->objectid != 0)
+ if (sh.objectid != 0)
continue;
- if (sh->type != BTRFS_QGROUP_LIMIT_KEY)
+ if (sh.type != BTRFS_QGROUP_LIMIT_KEY)
continue;
- if (sh->offset != old_qgroupid)
+ if (sh.offset != old_qgroupid)
continue;
/* We found the entry, now copy things over. */
+ const struct btrfs_qgroup_limit_item *qli = body;
qargs = (struct btrfs_ioctl_qgroup_limit_args) {
.qgroupid = new_qgroupid,
args.key.min_offset = args.key.max_offset = old_subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
args.key.nr_items = 256;
if (ioctl(old_fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args) {
_cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
- const struct btrfs_root_ref *ref;
_cleanup_close_ int old_child_fd = -EBADF, new_child_fd = -EBADF;
- btrfs_ioctl_search_args_set(&args, sh);
+ btrfs_ioctl_search_args_set(&args, &sh);
- if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ if (sh.type != BTRFS_ROOT_BACKREF_KEY)
continue;
- /* Avoid finding the source subvolume a second
- * time */
- if (sh->offset != old_subvol_id)
+ /* Avoid finding the source subvolume a second time */
+ if (sh.offset != old_subvol_id)
continue;
- /* Avoid running into loops if the new
- * subvolume is below the old one. */
- if (sh->objectid == new_subvol_id)
+ /* Avoid running into loops if the new subvolume is below the old one. */
+ if (sh.objectid == new_subvol_id)
continue;
- ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+ const struct btrfs_root_ref *ref = body;
p = memdup_suffix0((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
if (!p)
return -ENOMEM;
return -errno;
if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
- /* If the snapshot is read-only we
- * need to mark it writable
- * temporarily, to put the subsnapshot
- * into place. */
+ /* If the snapshot is read-only we need to mark it writable temporarily, to
+ * put the subsnapshot into place. */
if (subvolume_fd < 0) {
subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
return r;
}
- /* When btrfs clones the subvolumes, child
- * subvolumes appear as empty directories. Remove
- * them, so that we can create a new snapshot
- * in their place */
+ /* When btrfs clones the subvolumes, child subvolumes appear as empty
+ * directories. Remove them, so that we can create a new snapshot in their place */
if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) {
int k = -errno;
return k;
}
- r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid,
+ r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh.objectid,
flags & ~(BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_LOCK_BSD));
/* Restore the readonly flag */
args.key.min_objectid = args.key.max_objectid = qgroupid;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ _unused_ const void *body;
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ 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);
+ btrfs_ioctl_search_args_set(&args, &sh);
- if (sh->type != BTRFS_QGROUP_RELATION_KEY)
+ if (sh.type != BTRFS_QGROUP_RELATION_KEY)
continue;
- if (sh->offset < sh->objectid)
+ if (sh.offset < sh.objectid)
continue;
- if (sh->objectid != qgroupid)
+ if (sh.objectid != qgroupid)
continue;
if (!GREEDY_REALLOC(items, n_items+1))
return -ENOMEM;
- items[n_items++] = sh->offset;
+ items[n_items++] = sh.offset;
}
/* Increase search key by one, to read the next item, if we can. */
args.key.min_objectid = args.key.max_objectid = subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ _unused_ const void *body = NULL;
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
if (args.key.nr_items <= 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args) {
- if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ if (sh.type != BTRFS_ROOT_BACKREF_KEY)
continue;
- if (sh->objectid != subvol_id)
+ if (sh.objectid != subvol_id)
continue;
- *ret = sh->offset;
+ *ret = sh.offset;
return 0;
}
}
assert(ret);
while (btrfs_ioctl_search_args_compare(&search_args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
search_args.key.nr_items = 256;
if (search_args.key.nr_items == 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, search_args) {
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, search_args) {
_cleanup_(btrfs_chunk_freep) BtrfsChunk *chunk = NULL;
- const struct btrfs_chunk *item;
- btrfs_ioctl_search_args_set(&search_args, sh);
+ btrfs_ioctl_search_args_set(&search_args, &sh);
- if (sh->objectid != BTRFS_FIRST_CHUNK_TREE_OBJECTID)
+ if (sh.objectid != BTRFS_FIRST_CHUNK_TREE_OBJECTID)
continue;
- if (sh->type != BTRFS_CHUNK_ITEM_KEY)
+ if (sh.type != BTRFS_CHUNK_ITEM_KEY)
continue;
chunk = new(BtrfsChunk, 1);
if (!chunk)
return -ENOMEM;
- item = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
-
+ const struct btrfs_chunk *item = body;
*chunk = (BtrfsChunk) {
- .offset = sh->offset,
+ .offset = sh.offset,
.length = le64toh(item->length),
.type = le64toh(item->type),
.n_stripes = le16toh(item->num_stripes),
search_args.key.min_objectid = search_args.key.max_objectid = st.st_ino;
while (btrfs_ioctl_search_args_compare(&search_args) <= 0) {
- const struct btrfs_ioctl_search_header *sh;
- unsigned i;
+ struct btrfs_ioctl_search_header sh;
+ const void *body;
search_args.key.nr_items = 256;
if (search_args.key.nr_items == 0)
break;
- FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, search_args) {
- const struct btrfs_file_extent_item *item;
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, search_args) {
uint64_t logical_offset;
BtrfsChunk *chunk;
- btrfs_ioctl_search_args_set(&search_args, sh);
+ btrfs_ioctl_search_args_set(&search_args, &sh);
- if (sh->type != BTRFS_EXTENT_DATA_KEY)
+ if (sh.type != BTRFS_EXTENT_DATA_KEY)
continue;
- if (sh->objectid != st.st_ino)
+ if (sh.objectid != st.st_ino)
continue;
- item = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
-
+ const struct btrfs_file_extent_item *item = body;
if (!IN_SET(item->type, BTRFS_FILE_EXTENT_REG, BTRFS_FILE_EXTENT_PREALLOC))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot get physical address for btrfs extent: invalid type %" PRIu8,