summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2013-04-23 12:18:55 +0200
committerDavid Sterba <dsterba@suse.cz>2013-04-23 19:16:25 +0200
commit6d26357f8e7d73d802e8025407fe17542a18164b (patch)
treeabef033343ba9e957b2264dad8d3046310c07c9b
parent6b76570652e2f5a1f776848f330ca01e418a186c (diff)
Btrfs-progs: add function to map subvol ID to path
Several tools like btrfs-send and btrfs-receive need to map a subvolume ID to a filesystem path. The so far existing methods in btrfs-list.c cause a horrible effort when performing this operation (and the effort is dependent on the number of existing subvolumes with quadratic effort). This commit adds a function that is able to map a subvolume ID to a filesystem path with an effort that is independent of the number of existing subvolumes. In addition to this function, a command line frontend is added as well: btrfs inspect-internal subvolid-resolve <subvolid> <path> Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de>
-rw-r--r--cmds-inspect.c46
-rw-r--r--man/btrfs.8.in6
-rw-r--r--send-utils.c99
-rw-r--r--send-utils.h2
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);