From 6d2cf042471cc728b5399b2beae54603739bc66a Mon Sep 17 00:00:00 2001 From: ghigo Date: Sun, 24 Jan 2010 18:00:05 +0100 Subject: [PATCH] new util: 'btrfs' This commit introduces a new command called 'btrfs' for managing a btrfs filesystem. 'btrfs' handles: - snapshot/subvolume creation - adding/removal of volume (ie: disk) - defragment of a tree - scan of a device searching a btrfs filesystem - re-balancing of the chunk on the disks - listing subvolumes and snapshots This has also been updated to include the new defrag range ioctl. Signed-off-by: Chris Mason --- Makefile | 13 +- btrfs-defrag.c | 112 -------- btrfs-list.c | 55 +--- btrfs.c | 335 ++++++++++++++++++++++++ btrfs_cmds.c | 788 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ btrfs_cmds.h | 30 +++ man/Makefile | 5 +- 7 files changed, 1167 insertions(+), 171 deletions(-) create mode 100644 btrfs.c create mode 100644 btrfs_cmds.c create mode 100644 btrfs_cmds.h diff --git a/Makefile b/Makefile index 1000268..9735fc6 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS = -g -Werror -Os objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \ - volumes.o utils.o + volumes.o utils.o btrfs-list.o # CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ @@ -17,7 +17,8 @@ bindir = $(prefix)/bin LIBS=-luuid progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \ - btrfs-map-logical btrfs-list btrfs-defrag + btrfs \ + btrfs-map-logical # make C=1 to enable sparse ifdef C @@ -36,11 +37,9 @@ all: version $(progs) manpages version: bash version.sh -btrfs-list: $(objects) btrfs-list.o - gcc $(CFLAGS) -o btrfs-list btrfs-list.o $(objects) $(LDFLAGS) $(LIBS) - -btrfs-defrag: $(objects) btrfs-defrag.o - gcc $(CFLAGS) -o btrfs-defrag btrfs-defrag.o $(objects) $(LDFLAGS) $(LIBS) +btrfs: $(objects) btrfs.o btrfs_cmds.o + gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o \ + $(objects) $(LDFLAGS) $(LIBS) btrfsctl: $(objects) btrfsctl.o gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) diff --git a/btrfs-defrag.c b/btrfs-defrag.c index 9aab3ba..8f1525a 100644 --- a/btrfs-defrag.c +++ b/btrfs-defrag.c @@ -37,115 +37,3 @@ #include "utils.h" #include "version.h" -static u64 parse_size(char *s) -{ - int len = strlen(s); - char c; - u64 mult = 1; - - if (!isdigit(s[len - 1])) { - c = tolower(s[len - 1]); - switch (c) { - case 'g': - mult *= 1024; - case 'm': - mult *= 1024; - case 'k': - mult *= 1024; - case 'b': - break; - default: - fprintf(stderr, "Unknown size descriptor %c\n", c); - exit(1); - } - s[len - 1] = '\0'; - } - return atoll(s) * mult; -} - -static void print_usage(void) -{ - printf("usage: btrfs-defrag [-c] [-f] [-s start] [-l len] " - "[-t threshold] file ...\n"); - exit(1); -} - -int main(int ac, char **av) -{ - int fd; - int compress = 0; - int flush = 0; - u64 start = 0; - u64 len = (u64)-1; - u32 thresh = 0; - int i; - int errors = 0; - int ret = 0; - int verbose = 0; - struct btrfs_ioctl_defrag_range_args range; - - while(1) { - int c = getopt(ac, av, "vcfs:l:t:"); - if (c < 0) - break; - switch(c) { - case 'c': - compress = 1; - break; - case 'f': - flush = 1; - break; - case 'v': - verbose = 1; - break; - case 's': - start = parse_size(optarg); - break; - case 'l': - len = parse_size(optarg); - break; - case 't': - thresh = parse_size(optarg); - break; - default: - print_usage(); - return 1; - } - } - if (ac - optind == 0) - print_usage(); - - memset(&range, 0, sizeof(range)); - range.start = start; - range.len = len; - range.extent_thresh = thresh; - if (compress) - range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS; - if (flush) - range.flags |= BTRFS_DEFRAG_RANGE_START_IO; - - for (i = optind; i < ac; i++) { - fd = open(av[i], O_RDWR); - if (fd < 0) { - fprintf(stderr, "failed to open %s\n", av[i]); - perror("open:"); - errors++; - continue; - } - ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range); - if (ret) { - fprintf(stderr, "ioctl failed on %s ret %d\n", - av[i], ret); - errors++; - } - close(fd); - } - if (verbose) - printf("%s\n", BTRFS_BUILD_VERSION); - if (errors) { - fprintf(stderr, "total %d failures\n", errors); - exit(1); - } - return 0; -} - diff --git a/btrfs-list.c b/btrfs-list.c index c922f09..6305d3c 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -154,39 +154,6 @@ static struct root_info *tree_search(struct rb_root *root, u64 root_id) } /* - * helper to open either a file or directory so that - * we can run ioctls on it. - */ -static int open_file_or_dir(const char *fname) -{ - int ret; - struct stat st; - DIR *dirstream; - int fd; - - ret = stat(fname, &st); - if (ret < 0) { - perror("stat:"); - exit(1); - } - if (S_ISDIR(st.st_mode)) { - dirstream = opendir(fname); - if (!dirstream) { - perror("opendir"); - exit(1); - } - fd = dirfd(dirstream); - } else { - fd = open(fname, O_RDWR); - } - if (fd < 0) { - perror("open"); - exit(1); - } - return fd; -} - -/* * this allocates a new root in the lookup tree. * * root_id should be the object id of the root @@ -205,11 +172,12 @@ static int add_root(struct root_lookup *root_lookup, { struct root_info *ri; struct rb_node *ret; - ri = malloc(sizeof(*ri) + name_len); + ri = malloc(sizeof(*ri) + name_len + 1); if (!ri) { printf("memory allocation failed\n"); exit(1); } + memset(ri, 0, sizeof(*ri) + name_len + 1); ri->path = NULL; ri->dir_id = dir_id; ri->root_id = root_id; @@ -301,9 +269,9 @@ static int lookup_ino_path(int fd, struct root_info *ri) if (ri->path) return 0; + memset(&args, 0, sizeof(args)); args.treeid = ri->ref_tree; args.objectid = ri->dir_id; - args.name[0] = '\0'; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); if (ret) { @@ -335,7 +303,7 @@ static int lookup_ino_path(int fd, struct root_info *ri) return 0; } -static int list_subvols(int fd) +int list_subvols(int fd) { struct root_lookup root_lookup; struct rb_node *n; @@ -447,20 +415,5 @@ static int list_subvols(int fd) n = rb_prev(n); } - printf("%s\n", BTRFS_BUILD_VERSION); return ret; } - -int main(int ac, char **av) -{ - int fd; - - if (ac != 2) { - fprintf(stderr, "usage: btrfs-list mount_point\n"); - exit(1); - } - fd = open_file_or_dir(av[1]); - - return list_subvols(fd); -} - diff --git a/btrfs.c b/btrfs.c new file mode 100644 index 0000000..20f7413 --- /dev/null +++ b/btrfs.c @@ -0,0 +1,335 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + + +#include +#include +#include + +#include "btrfs_cmds.h" +#include "version.h" + +typedef int (*CommandFunction)(int argc, char **argv); + +struct Command { + CommandFunction func; /* function which implements the command */ + int nargs; /* if == 999, any number of arguments + if >= 0, number of arguments, + if < 0, _minimum_ number of arguments */ + char *verb; /* verb */ + char *help; /* help lines; form the 2nd onward they are + indented */ + + /* the following fields are run-time filled by the program */ + char **cmds; /* array of subcommands */ + int ncmds; /* number of subcommand */ +}; + +static struct Command commands[] = { + + /* + avoid short commands different for the case only + */ + { do_clone, 2, + "subvolume snapshot", " [/]\n" + "Create a writable snapshot of the subvolume with\n" + "the name in the directory." + }, + { do_delete_subvolume, 1, + "subvolume delete", "\n" + "Delete the subvolume ." + }, + { do_create_subvol, 1, + "subvolume create", "[/]\n" + "Create a subvolume in (or the current directory if\n" + "not passed)." + }, + { do_subvol_list, 1, "subvolume list", "\n" + "List the snapshot/subvolume of a filesystem." + }, + + { do_defrag, -1, + "filesystem defragment", "[-vcf] [-s start] [-l len] [-t size] | [|...]\n" + "Defragment a file or a directory." + }, + { do_fssync, 1, + "filesystem sync", "\n" + "Force a sync on the filesystem ." + }, + { do_resize, 2, + "filesystem resize", "[+/-][gkm]|max \n" + "Resize the file system. If 'max' is passed, the filesystem\n" + "will occupe all available space on the device." + }, + { do_show_filesystem, 999, + "filesystem show", "[|