Btrfs-progs: added ioctls and commands to resolve inodes and logical addrs
authorJan Schmidt <list.btrfs@jan-o-sch.net>
Wed, 2 Nov 2011 15:42:30 +0000 (11:42 -0400)
committerChris Mason <chris.mason@oracle.com>
Wed, 2 Nov 2011 19:46:10 +0000 (15:46 -0400)
two new commands that make use of the new path resolving functions
implemented for scrub, doing the resolving in-kernel. the result for both
commands is a list of files belonging to that inode / logical address.

Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
btrfs-list.c
btrfs.c
btrfs_cmds.c
btrfs_cmds.h
ioctl.h

index 5751f1d..5f4a9be 100644 (file)
@@ -899,3 +899,38 @@ int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
        printf("transid marker was %llu\n", (unsigned long long)max_found);
        return ret;
 }
+
+char *path_for_root(int fd, u64 root)
+{
+       struct root_lookup root_lookup;
+       struct rb_node *n;
+       char *ret_path = NULL;
+       int ret;
+
+       ret = __list_subvol_search(fd, &root_lookup);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       ret = __list_subvol_fill_paths(fd, &root_lookup);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       n = rb_last(&root_lookup.root);
+       while (n) {
+               struct root_info *entry;
+               u64 root_id;
+               u64 parent_id;
+               u64 level;
+               char *path;
+               entry = rb_entry(n, struct root_info, rb_node);
+               resolve_root(&root_lookup, entry, &root_id, &parent_id, &level,
+                               &path);
+               if (root_id == root)
+                       ret_path = path;
+               else
+                       free(path);
+               n = rb_prev(n);
+       }
+
+       return ret_path;
+}
diff --git a/btrfs.c b/btrfs.c
index c16dc60..1def354 100644 (file)
--- a/btrfs.c
+++ b/btrfs.c
@@ -169,6 +169,16 @@ static struct Command commands[] = {
                "Remove a device from a filesystem.",
          NULL
        },
+       { do_ino_to_path, -2,
+         "inspect-internal inode-resolve", "[-v] <inode> <path>\n"
+               "get file system paths for the given inode.",
+         NULL
+       },
+       { do_logical_to_ino, -2,
+         "inspect-internal logical-resolve", "[-v] [-P] <logical> <path>\n"
+               "get file system paths for the given logical address.",
+         NULL
+       },
        { 0, 0, 0, 0 }
 };
 
index f2b6355..b59e9cb 100644 (file)
@@ -1121,3 +1121,187 @@ int do_df_filesystem(int nargs, char **argv)
 
        return 0;
 }
+
+static int __ino_to_path_fd(u64 inum, int fd, int verbose, const char *prepend)
+{
+       int ret;
+       int i;
+       struct btrfs_ioctl_ino_path_args ipa;
+       struct btrfs_data_container *fspath;
+
+       fspath = malloc(4096);
+       if (!fspath)
+               return 1;
+
+       ipa.inum = inum;
+       ipa.size = 4096;
+       ipa.fspath = (u64)fspath;
+
+       ret = ioctl(fd, BTRFS_IOC_INO_PATHS, &ipa);
+       if (ret) {
+               printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
+               goto out;
+       }
+
+       if (verbose)
+               printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
+                       "cnt=%d, missed=%d\n", ret,
+                       (unsigned long)fspath->bytes_left,
+                       (unsigned long)fspath->bytes_missing,
+                       fspath->elem_cnt, fspath->elem_missed);
+
+       for (i = 0; i < fspath->elem_cnt; ++i) {
+               char **str = (char **)fspath->val;
+               str[i] += (unsigned long)fspath->val;
+               if (prepend)
+                       printf("%s/%s\n", prepend, str[i]);
+               else
+                       printf("%s\n", str[i]);
+       }
+
+out:
+       free(fspath);
+       return ret;
+}
+
+int do_ino_to_path(int nargs, char **argv)
+{
+       int fd;
+       int verbose = 0;
+
+       optind = 1;
+       while (1) {
+               int c = getopt(nargs, argv, "v");
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'v':
+                       verbose = 1;
+                       break;
+               default:
+                       fprintf(stderr, "invalid arguments for ipath\n");
+                       return 1;
+               }
+       }
+       if (nargs - optind != 2) {
+               fprintf(stderr, "invalid arguments for ipath\n");
+               return 1;
+       }
+
+       fd = open_file_or_dir(argv[optind+1]);
+       if (fd < 0) {
+               fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
+               return 12;
+       }
+
+       return __ino_to_path_fd(atoll(argv[optind]), fd, verbose,
+                               argv[optind+1]);
+}
+
+int do_logical_to_ino(int nargs, char **argv)
+{
+       int ret;
+       int fd;
+       int i;
+       int verbose = 0;
+       int getpath = 1;
+       int bytes_left;
+       struct btrfs_ioctl_logical_ino_args loi;
+       struct btrfs_data_container *inodes;
+       char full_path[4096];
+       char *path_ptr;
+
+       optind = 1;
+       while (1) {
+               int c = getopt(nargs, argv, "Pv");
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'P':
+                       getpath = 0;
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               default:
+                       fprintf(stderr, "invalid arguments for ipath\n");
+                       return 1;
+               }
+       }
+       if (nargs - optind != 2) {
+               fprintf(stderr, "invalid arguments for ipath\n");
+               return 1;
+       }
+
+       inodes = malloc(4096);
+       if (!inodes)
+               return 1;
+
+       loi.logical = atoll(argv[optind]);
+       loi.size = 4096;
+       loi.inodes = (u64)inodes;
+
+       fd = open_file_or_dir(argv[optind+1]);
+       if (fd < 0) {
+               fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
+               ret = 12;
+               goto out;
+       }
+
+       ret = ioctl(fd, BTRFS_IOC_LOGICAL_INO, &loi);
+       if (ret) {
+               printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
+               goto out;
+       }
+
+       if (verbose)
+               printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
+                       "cnt=%d, missed=%d\n", ret,
+                       (unsigned long)inodes->bytes_left,
+                       (unsigned long)inodes->bytes_missing,
+                       inodes->elem_cnt, inodes->elem_missed);
+
+       bytes_left = sizeof(full_path);
+       ret = snprintf(full_path, bytes_left, "%s/", argv[optind+1]);
+       path_ptr = full_path + ret;
+       bytes_left -= ret + 1;
+       BUG_ON(bytes_left < 0);
+
+       for (i = 0; i < inodes->elem_cnt; i += 3) {
+               u64 inum = inodes->val[i];
+               u64 offset = inodes->val[i+1];
+               u64 root = inodes->val[i+2];
+               int path_fd;
+               char *name;
+
+               if (getpath) {
+                       name = path_for_root(fd, root);
+                       if (IS_ERR(name))
+                               return PTR_ERR(name);
+                       if (!name) {
+                               path_ptr[-1] = '\0';
+                               path_fd = fd;
+                       } else {
+                               path_ptr[-1] = '/';
+                               ret = snprintf(path_ptr, bytes_left, "%s",
+                                               name);
+                               BUG_ON(ret >= bytes_left);
+                               free(name);
+                               path_fd = open_file_or_dir(full_path);
+                               if (path_fd < 0) {
+                                       fprintf(stderr, "ERROR: can't access "
+                                               "'%s'\n", full_path);
+                                       goto out;
+                               }
+                       }
+                       __ino_to_path_fd(inum, path_fd, verbose, full_path);
+               } else {
+                       printf("inode %llu offset %llu root %llu\n", inum,
+                               offset, root);
+               }
+       }
+
+out:
+       free(inodes);
+       return ret;
+}
index 8958596..81182b1 100644 (file)
@@ -39,3 +39,6 @@ int find_updated_files(int fd, u64 root_id, u64 oldest_gen);
 int do_find_newer(int argc, char **argv);
 int do_change_label(int argc, char **argv);
 int open_file_or_dir(const char *fname);
+int do_ino_to_path(int nargs, char **argv);
+int do_logical_to_ino(int nargs, char **argv);
+char *path_for_root(int fd, u64 root);
diff --git a/ioctl.h b/ioctl.h
index a391695..1ae7537 100644 (file)
--- a/ioctl.h
+++ b/ioctl.h
@@ -200,6 +200,30 @@ struct btrfs_ioctl_space_args {
        struct btrfs_ioctl_space_info spaces[0];
 };
 
+struct btrfs_data_container {
+       __u32   bytes_left;     /* out -- bytes not needed to deliver output */
+       __u32   bytes_missing;  /* out -- additional bytes needed for result */
+       __u32   elem_cnt;       /* out */
+       __u32   elem_missed;    /* out */
+       __u64   val[0];         /* out */
+};
+
+struct btrfs_ioctl_ino_path_args {
+       __u64                           inum;           /* in */
+       __u64                           size;           /* in */
+       __u64                           reserved[4];
+       /* struct btrfs_data_container  *fspath;           out */
+       __u64                           fspath;         /* out */
+};
+
+struct btrfs_ioctl_logical_ino_args {
+       __u64                           logical;        /* in */
+       __u64                           size;           /* in */
+       __u64                           reserved[4];
+       /* struct btrfs_data_container  *inodes;        out   */
+       __u64                           inodes;
+};
+
 /* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
                                   struct btrfs_ioctl_vol_args)
@@ -248,5 +272,10 @@ struct btrfs_ioctl_space_args {
 #define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
                                        struct btrfs_ioctl_dev_info_args)
 #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
-                                       struct btrfs_ioctl_fs_info_args)
+                                 struct btrfs_ioctl_fs_info_args)
+#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
+                                       struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
+                                       struct btrfs_ioctl_ino_path_args)
+
 #endif