diff options
-rw-r--r-- | cmds-inspect.c | 46 | ||||
-rw-r--r-- | man/btrfs.8.in | 6 | ||||
-rw-r--r-- | send-utils.c | 99 | ||||
-rw-r--r-- | send-utils.h | 2 |
4 files changed, 152 insertions, 1 deletions
diff --git a/cmds-inspect.c b/cmds-inspect.c index 77617596..30b41fc1 100644 --- a/cmds-inspect.c +++ b/cmds-inspect.c @@ -24,6 +24,8 @@ #include "kerncompat.h" #include "ioctl.h" #include "utils.h" +#include "ctree.h" +#include "send-utils.h" #include "commands.h" #include "btrfs-list.h" @@ -253,12 +255,56 @@ out: return ret; } +static const char * const cmd_subvolid_resolve_usage[] = { + "btrfs inspect-internal subvolid-resolve <subvolid> <path>", + "Get file system paths for the given subvolume ID.", + NULL +}; + +static int cmd_subvolid_resolve(int argc, char **argv) +{ + int ret; + int fd = -1; + u64 subvol_id; + char path[BTRFS_PATH_NAME_MAX + 1]; + + if (check_argc_exact(argc, 3)) + usage(cmd_subvolid_resolve_usage); + + fd = open_file_or_dir(argv[2]); + if (fd < 0) { + fprintf(stderr, "ERROR: can't access '%s'\n", argv[2]); + ret = -ENOENT; + goto out; + } + + subvol_id = atoll(argv[1]); + ret = btrfs_subvolid_resolve(fd, path, sizeof(path), subvol_id); + + if (ret) { + fprintf(stderr, + "%s: btrfs_subvolid_resolve(subvol_id %llu) failed with ret=%d\n", + argv[0], (unsigned long long)subvol_id, ret); + goto out; + } + + path[BTRFS_PATH_NAME_MAX] = '\0'; + printf("%s\n", path); + +out: + if (fd >= 0) + close(fd); + return ret ? 1 : 0; +} + const struct cmd_group inspect_cmd_group = { inspect_cmd_group_usage, NULL, { { "inode-resolve", cmd_inode_resolve, cmd_inode_resolve_usage, NULL, 0 }, { "logical-resolve", cmd_logical_resolve, cmd_logical_resolve_usage, NULL, 0 }, + { "subvolid-resolve", cmd_subvolid_resolve, + cmd_subvolid_resolve_usage, NULL, 0 }, { 0, 0, 0, 0, 0 } } }; diff --git a/man/btrfs.8.in b/man/btrfs.8.in index 8ec5d5a4..af7df4de 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -60,6 +60,8 @@ btrfs \- control a btrfs filesystem \fBbtrfs\fP \fBinspect-internal logical-resolve\fP [-Pv] [-s size] \fI<logical>\fP \fI<path>\fP .PP +\fBbtrfs\fP \fBinspect-internal subvolid-resolve\fP \fI<subvolid>\fP \fI<path>\fP +.PP \fBbtrfs\fP \fBqgroup assign\fP \fI<src>\fP \fI<dst>\fP \fI<path>\fP .PP \fBbtrfs\fP \fBqgroup remove\fP \fI<src>\fP \fI<dst>\fP \fI<path>\fP @@ -461,6 +463,10 @@ not enough to read all the resolved results. The max value one can set is 64k. .RE .TP +\fBinspect-internal subvolid-resolve\fP \fI<subvolid>\fP \fI<path>\fP +Get file system paths for the given subvolume ID. +.TP + \fBbtrfs qgroup assign\fP \fI<src>\fP \fI<dst>\fP \fI<path>\fP Enable subvolume qgroup support for a filesystem. .TP diff --git a/send-utils.c b/send-utils.c index bc0feb83..bacd47ea 100644 --- a/send-utils.c +++ b/send-utils.c @@ -23,6 +23,105 @@ #include "ioctl.h" #include "btrfs-list.h" +static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len, + u64 subvol_id); + +int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id) +{ + if (path_len < 1) + return -EOVERFLOW; + path[0] = '\0'; + path_len--; + path[path_len] = '\0'; + return btrfs_subvolid_resolve_sub(fd, path, &path_len, subvol_id); +} + +static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len, + u64 subvol_id) +{ + int ret; + struct btrfs_ioctl_search_args search_arg; + struct btrfs_ioctl_ino_lookup_args ino_lookup_arg; + struct btrfs_ioctl_search_header *search_header; + struct btrfs_root_ref *backref_item; + + if (subvol_id == BTRFS_FS_TREE_OBJECTID) { + if (*path_len < 1) + return -EOVERFLOW; + *path = '\0'; + (*path_len)--; + return 0; + } + + memset(&search_arg, 0, sizeof(search_arg)); + search_arg.key.tree_id = BTRFS_ROOT_TREE_OBJECTID; + search_arg.key.min_objectid = subvol_id; + search_arg.key.max_objectid = subvol_id; + search_arg.key.min_type = BTRFS_ROOT_BACKREF_KEY; + search_arg.key.max_type = BTRFS_ROOT_BACKREF_KEY; + search_arg.key.max_offset = (u64)-1; + search_arg.key.max_transid = (u64)-1; + search_arg.key.nr_items = 1; + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &search_arg); + if (ret) { + fprintf(stderr, + "ioctl(BTRFS_IOC_TREE_SEARCH, subvol_id %llu) ret=%d, error: %s\n", + (unsigned long long)subvol_id, ret, strerror(errno)); + return ret; + } + + if (search_arg.key.nr_items < 1) { + fprintf(stderr, + "failed to lookup subvol_id %llu!\n", + (unsigned long long)subvol_id); + return -ENOENT; + } + search_header = (struct btrfs_ioctl_search_header *)search_arg.buf; + backref_item = (struct btrfs_root_ref *)(search_header + 1); + if (search_header->offset != BTRFS_FS_TREE_OBJECTID) { + int sub_ret; + + sub_ret = btrfs_subvolid_resolve_sub(fd, path, path_len, + search_header->offset); + if (sub_ret) + return sub_ret; + if (*path_len < 1) + return -EOVERFLOW; + strcat(path, "/"); + (*path_len)--; + } + + if (btrfs_stack_root_ref_dirid(backref_item) != + BTRFS_FIRST_FREE_OBJECTID) { + int len; + + memset(&ino_lookup_arg, 0, sizeof(ino_lookup_arg)); + ino_lookup_arg.treeid = search_header->offset; + ino_lookup_arg.objectid = + btrfs_stack_root_ref_dirid(backref_item); + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_lookup_arg); + if (ret) { + fprintf(stderr, + "ioctl(BTRFS_IOC_INO_LOOKUP) ret=%d, error: %s\n", + ret, strerror(errno)); + return ret; + } + + len = strlen(ino_lookup_arg.name); + if (*path_len < len) + return -EOVERFLOW; + strcat(path, ino_lookup_arg.name); + (*path_len) -= len; + } + + if (*path_len < btrfs_stack_root_ref_name_len(backref_item)) + return -EOVERFLOW; + strncat(path, (char *)(backref_item + 1), + btrfs_stack_root_ref_name_len(backref_item)); + (*path_len) -= btrfs_stack_root_ref_name_len(backref_item); + return 0; +} + static struct rb_node *tree_insert(struct rb_root *root, struct subvol_info *si, enum subvol_search_type type) diff --git a/send-utils.h b/send-utils.h index 78abf944..06af75f3 100644 --- a/send-utils.h +++ b/send-utils.h @@ -70,7 +70,7 @@ struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s, void subvol_uuid_search_add(struct subvol_uuid_search *s, struct subvol_info *si); - +int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id); char *path_cat(const char *p1, const char *p2); char *path_cat3(const char *p1, const char *p2, const char *p3); |