Btrfs-progs: add "btrfs subvolume get-default" subcommand
authorZhong, Xin <xin.zhong@intel.com>
Tue, 12 Jul 2011 02:48:37 +0000 (10:48 +0800)
committerChris Mason <chris.mason@oracle.com>
Tue, 25 Oct 2011 13:18:59 +0000 (09:18 -0400)
Add subcommand to get the default subvolume of btrfs filesystem

V2->V3:
* add man page
* based on http://git.darksatanic.net/repo/btrfs-progs-unstable.git
  integration-20110705

Reviewed-by: Andreas Philipp <philipp.andreas@gmail.com>
Reviewed-by: Goffredo Baroncelli <kreijack@libero.it>
Reported-by: Yang, Yi <yi.y.yang@intel.com>
Signed-off-by: Zhong, Xin <xin.zhong@intel.com>
btrfs-list.c
btrfs.c
btrfs_cmds.c
btrfs_cmds.h
man/btrfs.8.in

index ab73e65..817a450 100644 (file)
@@ -560,7 +560,7 @@ build:
        return full;
 }
 
-int list_subvols(int fd, int print_parent)
+int list_subvols(int fd, int print_parent, int get_default)
 {
        struct root_lookup root_lookup;
        struct rb_node *n;
@@ -569,10 +569,12 @@ int list_subvols(int fd, int print_parent)
        struct btrfs_ioctl_search_key *sk = &args.key;
        struct btrfs_ioctl_search_header *sh;
        struct btrfs_root_ref *ref;
+       struct btrfs_dir_item *di;
        unsigned long off = 0;
        int name_len;
        char *name;
        u64 dir_id;
+       u64 subvol_id = 0;
        int i;
        int e;
 
@@ -669,6 +671,52 @@ int list_subvols(int fd, int print_parent)
                n = rb_next(n);
        }
 
+       memset(&args, 0, sizeof(args));
+
+       /* search in the tree of tree roots */
+       sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+
+       /* search dir item */
+       sk->max_type = BTRFS_DIR_ITEM_KEY;
+       sk->min_type = BTRFS_DIR_ITEM_KEY;
+
+       sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+       sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+       sk->max_offset = (u64)-1;
+       sk->max_transid = (u64)-1;
+
+       /* just a big number, doesn't matter much */
+       sk->nr_items = 4096;
+
+       /* try to get the objectid of default subvolume */
+       if (get_default) {
+               ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+               if (ret < 0) {
+                       fprintf(stderr, "ERROR: can't perform the search\n");
+                       return ret;
+               }
+
+               off = 0;
+               /* go through each item to find dir item named "default" */
+               for (i = 0; i < sk->nr_items; i++) {
+                       sh = (struct btrfs_ioctl_search_header *)(args.buf +
+                                                                 off);
+                       off += sizeof(*sh);
+                       if (sh->type == BTRFS_DIR_ITEM_KEY) {
+                               di = (struct btrfs_dir_item *)(args.buf + off);
+                               name_len = le16_to_cpu(di->name_len);
+                               name = (char *)di + sizeof(struct btrfs_dir_item);
+                               if (!strncmp("default", name, name_len)) {
+                                       subvol_id = btrfs_disk_key_objectid(
+                                               &di->location);
+                                       break;
+                               }
+                       }
+
+                       off += sh->len;
+               }
+       }
+
        /* now that we have all the subvol-relative paths filled in,
         * we have to string the subvols together so that we can get
         * a path all the way back to the FS root
@@ -677,7 +725,13 @@ int list_subvols(int fd, int print_parent)
        while (n) {
                struct root_info *entry;
                entry = rb_entry(n, struct root_info, rb_node);
-               resolve_root(&root_lookup, entry, print_parent);
+               if (!get_default)
+                       resolve_root(&root_lookup, entry, print_parent);
+               /* we only want the default subvolume */
+               else if (subvol_id == entry->root_id)
+                       resolve_root(&root_lookup, entry, print_parent);
+               else if (subvol_id == 0)
+                       break;
                n = rb_prev(n);
        }
 
diff --git a/btrfs.c b/btrfs.c
index a3f9a01..a48f07b 100644 (file)
--- a/btrfs.c
+++ b/btrfs.c
@@ -94,6 +94,9 @@ static struct Command commands[] = {
                "-l len     defragment only up to len bytes\n"
                "-t size    minimal size of file to be considered for defragmenting\n"
        },
+       { do_get_default_subvol, 1, "subvolume get-default", "<path>\n"
+               "Get the default subvolume of a filesystem."
+       },
        { do_fssync, 1,
          "filesystem sync", "<path>\n"
                "Force a sync on the filesystem <path>.",
index 699dfc2..7d2fd8c 100644 (file)
@@ -339,7 +339,7 @@ int do_subvol_list(int argc, char **argv)
                fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
                return 12;
        }
-       ret = list_subvols(fd, print_parent);
+       ret = list_subvols(fd, print_parent, 0);
        if (ret)
                return 19;
        return 0;
@@ -953,6 +953,35 @@ int do_change_label(int nargs, char **argv)
 }
 
 
+int do_get_default_subvol(int nargs, char **argv)
+{
+       int fd;
+       int ret;
+       char *subvol;
+
+       subvol = argv[1];
+
+       ret = test_issubvolume(subvol);
+       if (ret < 0) {
+               fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
+               return 12;
+       }
+       if (!ret) {
+               fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
+               return 13;
+       }
+
+       fd = open_file_or_dir(subvol);
+       if (fd < 0) {
+               fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
+               return 12;
+       }
+       ret = list_subvols(fd, 0, 1);
+       if (ret)
+               return 19;
+       return 0;
+}
+
 int do_df_filesystem(int nargs, char **argv)
 {
        struct btrfs_ioctl_space_args *sargs;
index 3e171da..8958596 100644 (file)
@@ -32,7 +32,8 @@ int do_scan(int nargs, char **argv);
 int do_resize(int nargs, char **argv);
 int do_subvol_list(int nargs, char **argv);
 int do_set_default_subvol(int nargs, char **argv);
-int list_subvols(int fd, int print_parent);
+int do_get_default_subvol(int nargs, char **argv);
+int list_subvols(int fd, int print_parent, int get_default);
 int do_df_filesystem(int nargs, char **argv);
 int find_updated_files(int fd, u64 root_id, u64 oldest_gen);
 int do_find_newer(int argc, char **argv);
index faa7bf8..e830abd 100644 (file)
@@ -15,6 +15,8 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
 .PP
+\fBbtrfs\fP \fBsubvolume get-default\fP\fI <path>\fP
+.PP
 \fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
 .PP
 \fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
@@ -120,6 +122,11 @@ Set the subvolume of the filesystem \fI<path>\fR which is mounted as
 is returned by the \fBsubvolume list\fR command.
 .TP
 
+\fBsubvolume get-default\fR\fI <path>\fR
+Get the default subvolume of the filesystem \fI<path>\fR. The output format
+is similar to \fBsubvolume list\fR command.
+.TP
+
 \fBfilesystem defragment\fP -c[zlib|lzo] [-l \fIlen\fR] [-s \fIstart\fR] [-t \fIsize\fR] -[vf] <\fIfile\fR>|<\fIdir\fR> [<\fIfile\fR>|<\fIdir\fR>...]
 
 Defragment file data and/or directory metadata. To defragment all files in a