diff --git a/0001-Btrfs-progs-add-a-btrfs-select-super-command-to-over.patch b/0001-Btrfs-progs-add-a-btrfs-select-super-command-to-over.patch new file mode 100644 index 0000000..95e1d16 --- /dev/null +++ b/0001-Btrfs-progs-add-a-btrfs-select-super-command-to-over.patch @@ -0,0 +1,157 @@ +From 70c6c10134b502fa69955746554031939b85fb0c Mon Sep 17 00:00:00 2001 +From: Chris Mason +Date: Thu, 9 Dec 2010 16:36:29 -0500 +Subject: [PATCH 01/15] Btrfs-progs: add a btrfs-select-super command to + overwrite the super + +Btrfs stores multiple copies of the superblock, and for common power-failure +crashes where barriers were not in use, one of the super copies is often +valid while the first copy is not. + +This adds a btrfs-select-super -s N /dev/xxx command, which can +overwrite all the super blocks with a copy that you have already +determined is valid with btrfsck -s + +Signed-off-by: Chris Mason +--- + Makefile | 3 ++ + btrfs-select-super.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ + disk-io.c | 2 +- + disk-io.h | 1 + + 4 files changed, 104 insertions(+), 1 deletions(-) + create mode 100644 btrfs-select-super.c + +diff --git a/Makefile b/Makefile +index 6e6f6c6..d65f6a2 100644 +--- a/Makefile ++++ b/Makefile +@@ -62,6 +62,9 @@ btrfs-debug-tree: $(objects) debug-tree.o + btrfs-zero-log: $(objects) btrfs-zero-log.o + gcc $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS) + ++btrfs-select-super: $(objects) btrfs-select-super.o ++ gcc $(CFLAGS) -o btrfs-select-super $(objects) btrfs-select-super.o $(LDFLAGS) $(LIBS) ++ + btrfstune: $(objects) btrfstune.o + gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS) + +diff --git a/btrfs-select-super.c b/btrfs-select-super.c +new file mode 100644 +index 0000000..f12f36c +--- /dev/null ++++ b/btrfs-select-super.c +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (C) 2007 Oracle. All rights reserved. ++ * ++ * 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. ++ */ ++ ++#define _XOPEN_SOURCE 500 ++#define _GNU_SOURCE 1 ++#include ++#include ++#include ++#include ++#include ++#include "kerncompat.h" ++#include "ctree.h" ++#include "disk-io.h" ++#include "print-tree.h" ++#include "transaction.h" ++#include "list.h" ++#include "version.h" ++#include "utils.h" ++ ++static void print_usage(void) ++{ ++ fprintf(stderr, "usage: btrfs-select-super -s number dev\n"); ++ fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); ++ exit(1); ++} ++ ++int main(int ac, char **av) ++{ ++ struct btrfs_root *root; ++ int ret; ++ int num; ++ u64 bytenr = 0; ++ ++ while(1) { ++ int c; ++ c = getopt(ac, av, "s:"); ++ if (c < 0) ++ break; ++ switch(c) { ++ case 's': ++ num = atol(optarg); ++ bytenr = btrfs_sb_offset(num); ++ printf("using SB copy %d, bytenr %llu\n", num, ++ (unsigned long long)bytenr); ++ break; ++ default: ++ print_usage(); ++ } ++ } ++ ac = ac - optind; ++ ++ if (ac != 1) ++ print_usage(); ++ ++ if (bytenr == 0) { ++ fprintf(stderr, "Please select the super copy with -s\n"); ++ print_usage(); ++ } ++ ++ radix_tree_init(); ++ ++ if((ret = check_mounted(av[optind])) < 0) { ++ fprintf(stderr, "Could not check mount status: %s\n", strerror(ret)); ++ return ret; ++ } else if(ret) { ++ fprintf(stderr, "%s is currently mounted. Aborting.\n", av[optind]); ++ return -EBUSY; ++ } ++ ++ root = open_ctree(av[optind], bytenr, 1); ++ ++ if (root == NULL) ++ return 1; ++ ++ /* make the super writing code think we've read the first super */ ++ root->fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET; ++ ret = write_all_supers(root); ++ ++ /* we don't close the ctree or anything, because we don't want a real ++ * transaction commit. We just want the super copy we pulled off the ++ * disk to overwrite all the other copies ++ */ ++ return ret; ++} +diff --git a/disk-io.h b/disk-io.h +index 49e5692..7ebec24 100644 +--- a/disk-io.h ++++ b/disk-io.h +@@ -47,6 +47,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes); + struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, + int writes); + int close_ctree(struct btrfs_root *root); ++int write_all_supers(struct btrfs_root *root); + int write_ctree_super(struct btrfs_trans_handle *trans, + struct btrfs_root *root); + int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr); +-- +1.7.5.2.353.g5df3e + diff --git a/0002-Btrfs-progs-use-safe-string-manipulation-functions.patch b/0002-Btrfs-progs-use-safe-string-manipulation-functions.patch new file mode 100644 index 0000000..205a009 --- /dev/null +++ b/0002-Btrfs-progs-use-safe-string-manipulation-functions.patch @@ -0,0 +1,151 @@ +From 2636bf1da17720fc99b14cf4db33f1d1a4c9e0ee Mon Sep 17 00:00:00 2001 +From: Eduardo Silva +Date: Mon, 7 Feb 2011 08:55:04 -0300 +Subject: [PATCH 02/15] Btrfs-progs use safe string manipulation functions + +Signed-off-by: Eduardo Silva +Signed-off-by: Chris Mason +--- + btrfs_cmds.c | 14 +++++++------- + btrfsctl.c | 2 +- + convert.c | 2 +- + utils.c | 9 +++++---- + 4 files changed, 14 insertions(+), 13 deletions(-) + +diff --git a/btrfs_cmds.c b/btrfs_cmds.c +index 8031c58..fffb423 100644 +--- a/btrfs_cmds.c ++++ b/btrfs_cmds.c +@@ -375,7 +375,7 @@ int do_clone(int argc, char **argv) + printf("Create a snapshot of '%s' in '%s/%s'\n", + subvol, dstdir, newname); + args.fd = fd; +- strcpy(args.name, newname); ++ strncpy(args.name, newname, BTRFS_PATH_NAME_MAX); + res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args); + + close(fd); +@@ -436,7 +436,7 @@ int do_delete_subvolume(int argc, char **argv) + } + + printf("Delete subvolume '%s/%s'\n", dname, vname); +- strcpy(args.name, vname); ++ strncpy(args.name, vname, BTRFS_PATH_NAME_MAX); + res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args); + + close(fd); +@@ -490,7 +490,7 @@ int do_create_subvol(int argc, char **argv) + } + + printf("Create subvolume '%s/%s'\n", dstdir, newname); +- strcpy(args.name, newname); ++ strncpy(args.name, newname, BTRFS_PATH_NAME_MAX); + res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args); + + close(fddst); +@@ -553,7 +553,7 @@ int do_scan(int argc, char **argv) + + printf("Scanning for Btrfs filesystems in '%s'\n", argv[i]); + +- strcpy(args.name, argv[i]); ++ strncpy(args.name, argv[i], BTRFS_PATH_NAME_MAX); + /* + * FIXME: which are the error code returned by this ioctl ? + * it seems that is impossible to understand if there no is +@@ -593,7 +593,7 @@ int do_resize(int argc, char **argv) + } + + printf("Resize '%s' of '%s'\n", path, amount); +- strcpy(args.name, amount); ++ strncpy(args.name, amount, BTRFS_PATH_NAME_MAX); + res = ioctl(fd, BTRFS_IOC_RESIZE, &args); + close(fd); + if( res < 0 ){ +@@ -736,7 +736,7 @@ int do_add_volume(int nargs, char **args) + } + close(devfd); + +- strcpy(ioctl_args.name, args[i]); ++ strncpy(ioctl_args.name, args[i], BTRFS_PATH_NAME_MAX); + res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); + if(res<0){ + fprintf(stderr, "ERROR: error adding the device '%s'\n", args[i]); +@@ -792,7 +792,7 @@ int do_remove_volume(int nargs, char **args) + struct btrfs_ioctl_vol_args arg; + int res; + +- strcpy(arg.name, args[i]); ++ strncpy(arg.name, args[i], BTRFS_PATH_NAME_MAX); + res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); + if(res<0){ + fprintf(stderr, "ERROR: error removing the device '%s'\n", args[i]); +diff --git a/btrfsctl.c b/btrfsctl.c +index 92bdf39..adfa519 100644 +--- a/btrfsctl.c ++++ b/btrfsctl.c +@@ -237,7 +237,7 @@ int main(int ac, char **av) + } + + if (name) +- strcpy(args.name, name); ++ strncpy(args.name, name, BTRFS_PATH_NAME_MAX + 1); + else + args.name[0] = '\0'; + +diff --git a/convert.c b/convert.c +index d037c98..fbcf4a3 100644 +--- a/convert.c ++++ b/convert.c +@@ -857,7 +857,7 @@ static int copy_single_xattr(struct btrfs_trans_handle *trans, + data = databuf; + datalen = bufsize; + } +- strcpy(namebuf, xattr_prefix_table[name_index]); ++ strncpy(namebuf, xattr_prefix_table[name_index], XATTR_NAME_MAX); + strncat(namebuf, EXT2_EXT_ATTR_NAME(entry), entry->e_name_len); + if (name_len + datalen > BTRFS_LEAF_DATA_SIZE(root) - + sizeof(struct btrfs_item) - sizeof(struct btrfs_dir_item)) { +diff --git a/utils.c b/utils.c +index fd894f3..96ef94d 100644 +--- a/utils.c ++++ b/utils.c +@@ -108,7 +108,7 @@ int make_btrfs(int fd, const char *device, const char *label, + btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32); + btrfs_set_super_chunk_root_generation(&super, 1); + if (label) +- strcpy(super.label, label); ++ strncpy(super.label, label, BTRFS_LABEL_SIZE - 1); + + buf = malloc(sizeof(*buf) + max(sectorsize, leafsize)); + +@@ -828,7 +828,7 @@ void btrfs_register_one_device(char *fname) + "skipping device registration\n"); + return; + } +- strcpy(args.name, fname); ++ strncpy(args.name, fname, BTRFS_PATH_NAME_MAX); + ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); + close(fd); + } +@@ -971,6 +971,7 @@ static char *size_strs[] = { "", "KB", "MB", "GB", "TB", + char *pretty_sizes(u64 size) + { + int num_divs = 0; ++ int pretty_len = 16; + u64 last_size = size; + u64 fract_size = size; + float fraction; +@@ -988,8 +989,8 @@ char *pretty_sizes(u64 size) + return NULL; + + fraction = (float)fract_size / 1024; +- pretty = malloc(16); +- sprintf(pretty, "%.2f%s", fraction, size_strs[num_divs-1]); ++ pretty = malloc(pretty_len); ++ snprintf(pretty, pretty_len, "%.2f%s", fraction, size_strs[num_divs-1]); + return pretty; + } + +-- +1.7.5.2.353.g5df3e + diff --git a/0003-Btrfs-progs-utils-Informative-errors.patch b/0003-Btrfs-progs-utils-Informative-errors.patch new file mode 100644 index 0000000..f4e7c73 --- /dev/null +++ b/0003-Btrfs-progs-utils-Informative-errors.patch @@ -0,0 +1,36 @@ +From ac1a80f52434d05230f9933d8f68e28cc09e10b0 Mon Sep 17 00:00:00 2001 +From: Goldwyn Rodrigues +Date: Mon, 7 Feb 2011 07:34:36 +0000 +Subject: [PATCH 03/15] Btrfs-progs utils Informative errors + +Signed-off-by: Chris Mason +--- + utils.c | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/utils.c b/utils.c +index 96ef94d..d8c3dcc 100644 +--- a/utils.c ++++ b/utils.c +@@ -867,7 +867,7 @@ again: + } + dirp = opendir(dirname); + if (!dirp) { +- fprintf(stderr, "Unable to open /sys/block for scanning\n"); ++ fprintf(stderr, "Unable to open %s for scanning\n", dirname); + return -ENOENT; + } + while(1) { +@@ -902,7 +902,8 @@ again: + } + fd = open(fullpath, O_RDONLY); + if (fd < 0) { +- fprintf(stderr, "failed to read %s\n", fullpath); ++ fprintf(stderr, "failed to read %s: %s\n", fullpath, ++ strerror(errno)); + continue; + } + ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices, +-- +1.7.5.2.353.g5df3e + diff --git a/0004-update-man-page-to-new-defragment-command-interface.patch b/0004-update-man-page-to-new-defragment-command-interface.patch new file mode 100644 index 0000000..3bb77d0 --- /dev/null +++ b/0004-update-man-page-to-new-defragment-command-interface.patch @@ -0,0 +1,98 @@ +From 0a63a11c3d3bbb7e061daad28435b5eef91a947d Mon Sep 17 00:00:00 2001 +From: Hubert Kario +Date: Sun, 23 Jan 2011 15:31:07 +0000 +Subject: [PATCH 04/15] update man page to new defragment command interface + +Update + + btrfs filesystem defragment + +command explanation. Add explanation of advanced parameters and notes +about general usage. + +Add few notes about the + + btrfs --help + +usage, fix related grammar. + +Signed-off-by: Hubert Kario +Signed-off-by: Chris Mason +--- + man/btrfs.8.in | 33 ++++++++++++++++++++++++++------- + 1 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/man/btrfs.8.in b/man/btrfs.8.in +index 26ef982..cba2de1 100644 +--- a/man/btrfs.8.in ++++ b/man/btrfs.8.in +@@ -15,7 +15,7 @@ btrfs \- control a btrfs filesystem + .PP + \fBbtrfs\fP \fBsubvolume set-default\fP\fI \fP + .PP +-\fBbtrfs\fP \fBfilesystem defrag\fP\fI | [|...]\fP ++\fBbtrfs\fP \fBfilesystem defragment\fP\fI [-vcf] [-s start] [-l len] [-t size] | [|...]\fP + .PP + \fBbtrfs\fP \fBfilesystem sync\fP\fI \fP + .PP +@@ -34,6 +34,8 @@ btrfs \- control a btrfs filesystem + .PP + \fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP + .PP ++\fBbtrfs\fP \fB \-\-help \fP\fI\fP ++.PP + .SH DESCRIPTION + .B btrfs + is used to control the filesystem and the files and directories stored. It is +@@ -60,12 +62,12 @@ returns an error. + + If a command is terminated by + .I --help +-, the relevant help is showed. If the passed command matches more commands, +-the help of all the matched commands are showed. For example ++, the detailed help is showed. If the passed command matches more commands, ++detailed help of all the matched commands is showed. For example + .I btrfs dev --help + shows the help of all + .I device* +-command. ++commands. + + .SH COMMANDS + .TP +@@ -98,12 +100,29 @@ mount time via the \fIsubvol=\fR option. + + \fBsubvolume set-default\fR\fI \fR + Set the subvolume of the filesystem \fI\fR which is mounted as +-\fIdefault\fR. The subvolume is identified by \fB\fR, which ++\fIdefault\fR. The subvolume is identified by \fI\fR, which + is returned by the \fBsubvolume list\fR command. + .TP + +-\fBfilesystem defragment\fP\fI | [|...]\fR +-Defragment files and/or directories. ++\fBfilesystem defragment\fP\fI [-vcf] [-s start] [-l len] [-t size] | [|...]\fR ++Defragment file data and/or directory metadata. To defragment all files in a ++directory you have to specify each one on its own or use your shell wildcards. ++ ++\fB-v\fP be verbose ++ ++\fB-c\fP compress file contents while defragmenting ++ ++\fB-f\fP flush filesystem after defragmenting ++ ++\fB-s start\fP defragment only from byte \fIstart\fR onward ++ ++\fB-l len\fP defragment only up to \fIlen\fR bytes ++ ++\fB-t size\fP defragment only files at least \fIsize\fR bytes big ++ ++NOTE: defragmenting with kernels up to 2.6.37 will unlink COW-ed copies of data, don't ++use it if you use snapshots, have de-duplicated your data or made copies with ++\fBcp --reflink\fP. + .TP + + \fBdevice scan\fR \fI[ [..]]\fR +-- +1.7.5.2.353.g5df3e + diff --git a/0005-Improve-error-handling-in-the-btrfs-command.patch b/0005-Improve-error-handling-in-the-btrfs-command.patch new file mode 100644 index 0000000..3a71256 --- /dev/null +++ b/0005-Improve-error-handling-in-the-btrfs-command.patch @@ -0,0 +1,509 @@ +From b3007332100e01ca84c161b6c75f0a414ab4611b Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Mon, 20 Dec 2010 20:06:19 +0000 +Subject: [PATCH 05/15] Improve error handling in the btrfs command + +Hi Chris, + +below is enclosed a trivial patch, which has the aim to improve the error +reporting of the "btrfs" command. + +You can pull from + + http://cassiopea.homelinux.net/git/btrfs-progs-unstable.git + +branch + + strerror + +I changed every printf("some-error") to something like: + + e = errno; + fprintf(stderr, "ERROR: .... - %s", strerror(e)); + +so: + +1) all the error are reported to standard error +2) At the end of the message is printed the error as returned by the system. + +The change is quite simple, I replaced every printf("some-error") to the line +above. I don't touched anything other. +I also integrated a missing "printf" on the basis of the Ben patch. + +This patch leads the btrfs command to be more "user friendly" :-) + +Regards +G.Baroncelli + + btrfs-list.c | 40 ++++++++++++++++++++++-------- + btrfs_cmds.c | 77 ++++++++++++++++++++++++++++++++++++++++----------------- + utils.c | 6 ++++ + 3 files changed, 89 insertions(+), 34 deletions(-) + +Signed-off-by: Chris Mason +--- + btrfs-list.c | 40 ++++++++++++++++++++++-------- + btrfs_cmds.c | 77 ++++++++++++++++++++++++++++++++++++++++----------------- + utils.c | 6 ++++ + 3 files changed, 89 insertions(+), 34 deletions(-) + +diff --git a/btrfs-list.c b/btrfs-list.c +index 93766a8..abcc2f4 100644 +--- a/btrfs-list.c ++++ b/btrfs-list.c +@@ -265,7 +265,7 @@ static int resolve_root(struct root_lookup *rl, struct root_info *ri) + static int lookup_ino_path(int fd, struct root_info *ri) + { + struct btrfs_ioctl_ino_lookup_args args; +- int ret; ++ int ret, e; + + if (ri->path) + return 0; +@@ -275,9 +275,11 @@ static int lookup_ino_path(int fd, struct root_info *ri) + args.objectid = ri->dir_id; + + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); ++ e = errno; + if (ret) { +- fprintf(stderr, "ERROR: Failed to lookup path for root %llu\n", +- (unsigned long long)ri->ref_tree); ++ fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n", ++ (unsigned long long)ri->ref_tree, ++ strerror(e)); + return ret; + } + +@@ -320,15 +322,18 @@ static u64 find_root_gen(int fd) + unsigned long off = 0; + u64 max_found = 0; + int i; ++ int e; + + memset(&ino_args, 0, sizeof(ino_args)); + ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID; + + /* this ioctl fills in ino_args->treeid */ + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args); ++ e = errno; + if (ret) { +- fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n", +- (unsigned long long)BTRFS_FIRST_FREE_OBJECTID); ++ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", ++ (unsigned long long)BTRFS_FIRST_FREE_OBJECTID, ++ strerror(e)); + return 0; + } + +@@ -351,8 +356,10 @@ static u64 find_root_gen(int fd) + + while (1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ e = errno; + if (ret < 0) { +- fprintf(stderr, "ERROR: can't perform the search\n"); ++ fprintf(stderr, "ERROR: can't perform the search - %s\n", ++ strerror(e)); + return 0; + } + /* the ioctl returns the number of item it found in nr_items */ +@@ -407,14 +414,16 @@ static char *__ino_resolve(int fd, u64 dirid) + struct btrfs_ioctl_ino_lookup_args args; + int ret; + char *full; ++ int e; + + memset(&args, 0, sizeof(args)); + args.objectid = dirid; + + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); ++ e = errno; + if (ret) { +- fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n", +- (unsigned long long)dirid); ++ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", ++ (unsigned long long)dirid, strerror(e) ); + return ERR_PTR(ret); + } + +@@ -472,6 +481,7 @@ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name) + struct btrfs_ioctl_search_header *sh; + unsigned long off = 0; + int namelen; ++ int e; + + memset(&args, 0, sizeof(args)); + +@@ -490,8 +500,10 @@ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name) + sk->nr_items = 1; + + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ e = errno; + if (ret < 0) { +- fprintf(stderr, "ERROR: can't perform the search\n"); ++ fprintf(stderr, "ERROR: can't perform the search - %s\n", ++ strerror(e)); + return NULL; + } + /* the ioctl returns the number of item it found in nr_items */ +@@ -550,6 +562,7 @@ int list_subvols(int fd) + char *name; + u64 dir_id; + int i; ++ int e; + + root_lookup_init(&root_lookup); + +@@ -578,8 +591,10 @@ int list_subvols(int fd) + + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ e = errno; + if (ret < 0) { +- fprintf(stderr, "ERROR: can't perform the search\n"); ++ fprintf(stderr, "ERROR: can't perform the search - %s\n", ++ strerror(e)); + return ret; + } + /* the ioctl returns the number of item it found in nr_items */ +@@ -747,6 +762,7 @@ int find_updated_files(int fd, u64 root_id, u64 oldest_gen) + u64 found_gen; + u64 max_found = 0; + int i; ++ int e; + u64 cache_dirid = 0; + u64 cache_ino = 0; + char *cache_dir_name = NULL; +@@ -773,8 +789,10 @@ int find_updated_files(int fd, u64 root_id, u64 oldest_gen) + max_found = find_root_gen(fd); + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ e = errno; + if (ret < 0) { +- fprintf(stderr, "ERROR: can't perform the search\n"); ++ fprintf(stderr, "ERROR: can't perform the search- %s\n", ++ strerror(e)); + return ret; + } + /* the ioctl returns the number of item it found in nr_items */ +diff --git a/btrfs_cmds.c b/btrfs_cmds.c +index fffb423..775bfe1 100644 +--- a/btrfs_cmds.c ++++ b/btrfs_cmds.c +@@ -156,6 +156,7 @@ int do_defrag(int ac, char **av) + int verbose = 0; + int fancy_ioctl = 0; + struct btrfs_ioctl_defrag_range_args range; ++ int e=0; + + optind = 1; + while(1) { +@@ -219,19 +220,21 @@ int do_defrag(int ac, char **av) + } + if (!fancy_ioctl) { + ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL); ++ e=errno; + } else { + ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range); + if (ret && errno == ENOTTY) { +- fprintf(stderr, "defrag range ioctl not " ++ fprintf(stderr, "ERROR: defrag range ioctl not " + "supported in this kernel, please try " + "without any options.\n"); + errors++; ++ close(fd); + break; + } + } + if (ret) { +- fprintf(stderr, "ioctl failed on %s ret %d errno %d\n", +- av[i], ret, errno); ++ fprintf(stderr, "ERROR: defrag failed on %s - %s\n", ++ av[i], strerror(e)); + errors++; + } + close(fd); +@@ -310,7 +313,7 @@ int do_subvol_list(int argc, char **argv) + int do_clone(int argc, char **argv) + { + char *subvol, *dst; +- int res, fd, fddst, len; ++ int res, fd, fddst, len, e; + char *newname; + char *dstdir; + +@@ -377,12 +380,14 @@ int do_clone(int argc, char **argv) + args.fd = fd; + strncpy(args.name, newname, BTRFS_PATH_NAME_MAX); + res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args); ++ e = errno; + + close(fd); + close(fddst); + + if(res < 0 ){ +- fprintf( stderr, "ERROR: cannot snapshot '%s'\n",subvol); ++ fprintf( stderr, "ERROR: cannot snapshot '%s' - %s\n", ++ subvol, strerror(e)); + return 11; + } + +@@ -392,7 +397,7 @@ int do_clone(int argc, char **argv) + + int do_delete_subvolume(int argc, char **argv) + { +- int res, fd, len; ++ int res, fd, len, e; + struct btrfs_ioctl_vol_args args; + char *dname, *vname, *cpath; + char *path = argv[1]; +@@ -438,11 +443,13 @@ int do_delete_subvolume(int argc, char **argv) + printf("Delete subvolume '%s/%s'\n", dname, vname); + strncpy(args.name, vname, BTRFS_PATH_NAME_MAX); + res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args); ++ e = errno; + + close(fd); + + if(res < 0 ){ +- fprintf( stderr, "ERROR: cannot delete '%s/%s'\n",dname, vname); ++ fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n", ++ dname, vname, strerror(e)); + return 11; + } + +@@ -452,7 +459,7 @@ int do_delete_subvolume(int argc, char **argv) + + int do_create_subvol(int argc, char **argv) + { +- int res, fddst, len; ++ int res, fddst, len, e; + char *newname; + char *dstdir; + struct btrfs_ioctl_vol_args args; +@@ -492,11 +499,13 @@ int do_create_subvol(int argc, char **argv) + printf("Create subvolume '%s/%s'\n", dstdir, newname); + strncpy(args.name, newname, BTRFS_PATH_NAME_MAX); + res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args); ++ e = errno; + + close(fddst); + + if(res < 0 ){ +- fprintf( stderr, "ERROR: cannot create subvolume\n"); ++ fprintf( stderr, "ERROR: cannot create subvolume - %s\n", ++ strerror(e)); + return 11; + } + +@@ -506,7 +515,7 @@ int do_create_subvol(int argc, char **argv) + + int do_fssync(int argc, char **argv) + { +- int fd, res; ++ int fd, res, e; + char *path = argv[1]; + + fd = open_file_or_dir(path); +@@ -517,9 +526,11 @@ int do_fssync(int argc, char **argv) + + printf("FSSync '%s'\n", path); + res = ioctl(fd, BTRFS_IOC_SYNC); ++ e = errno; + close(fd); + if( res < 0 ){ +- fprintf(stderr, "ERROR: unable to fs-syncing '%s'\n", path); ++ fprintf(stderr, "ERROR: unable to fs-syncing '%s' - %s\n", ++ path, strerror(e)); + return 16; + } + +@@ -528,7 +539,7 @@ int do_fssync(int argc, char **argv) + + int do_scan(int argc, char **argv) + { +- int i, fd; ++ int i, fd, e; + if(argc<=1){ + int ret; + +@@ -560,10 +571,12 @@ int do_scan(int argc, char **argv) + * a btrfs filesystem from an I/O error !!! + */ + ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); ++ e = errno; + + if( ret < 0 ){ + close(fd); +- fprintf(stderr, "ERROR: unable to scan the device '%s'\n", argv[i]); ++ fprintf(stderr, "ERROR: unable to scan the device '%s' - %s\n", ++ argv[i], strerror(e)); + return 11; + } + } +@@ -577,7 +590,7 @@ int do_resize(int argc, char **argv) + { + + struct btrfs_ioctl_vol_args args; +- int fd, res, len; ++ int fd, res, len, e; + char *amount=argv[1], *path=argv[2]; + + fd = open_file_or_dir(path); +@@ -595,9 +608,11 @@ int do_resize(int argc, char **argv) + printf("Resize '%s' of '%s'\n", path, amount); + strncpy(args.name, amount, BTRFS_PATH_NAME_MAX); + res = ioctl(fd, BTRFS_IOC_RESIZE, &args); ++ e = errno; + close(fd); + if( res < 0 ){ +- fprintf(stderr, "ERROR: unable to resize '%s'\n", path); ++ fprintf(stderr, "ERROR: unable to resize '%s' - %s\n", ++ path, strerror(e)); + return 30; + } + return 0; +@@ -691,7 +706,7 @@ int do_add_volume(int nargs, char **args) + { + + char *mntpnt = args[nargs-1]; +- int i, fdmnt, ret=0; ++ int i, fdmnt, ret=0, e; + + + fdmnt = open_file_or_dir(mntpnt); +@@ -738,8 +753,10 @@ int do_add_volume(int nargs, char **args) + + strncpy(ioctl_args.name, args[i], BTRFS_PATH_NAME_MAX); + res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); ++ e = errno; + if(res<0){ +- fprintf(stderr, "ERROR: error adding the device '%s'\n", args[i]); ++ fprintf(stderr, "ERROR: error adding the device '%s' - %s\n", ++ args[i], strerror(e)); + ret++; + } + +@@ -756,7 +773,7 @@ int do_add_volume(int nargs, char **args) + int do_balance(int argc, char **argv) + { + +- int fdmnt, ret=0; ++ int fdmnt, ret=0, e; + struct btrfs_ioctl_vol_args args; + char *path = argv[1]; + +@@ -768,9 +785,11 @@ int do_balance(int argc, char **argv) + + memset(&args, 0, sizeof(args)); + ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args); ++ e = errno; + close(fdmnt); + if(ret<0){ +- fprintf(stderr, "ERROR: balancing '%s'\n", path); ++ fprintf(stderr, "ERROR: error during balancing '%s' - %s\n", ++ path, strerror(e)); + + return 19; + } +@@ -780,7 +799,7 @@ int do_remove_volume(int nargs, char **args) + { + + char *mntpnt = args[nargs-1]; +- int i, fdmnt, ret=0; ++ int i, fdmnt, ret=0, e; + + fdmnt = open_file_or_dir(mntpnt); + if (fdmnt < 0) { +@@ -794,8 +813,10 @@ int do_remove_volume(int nargs, char **args) + + strncpy(arg.name, args[i], BTRFS_PATH_NAME_MAX); + res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); ++ e = errno; + if(res<0){ +- fprintf(stderr, "ERROR: error removing the device '%s'\n", args[i]); ++ fprintf(stderr, "ERROR: error removing the device '%s' - %s\n", ++ args[i], strerror(e)); + ret++; + } + } +@@ -809,7 +830,7 @@ int do_remove_volume(int nargs, char **args) + + int do_set_default_subvol(int nargs, char **argv) + { +- int ret=0, fd; ++ int ret=0, fd, e; + u64 objectid; + char *path = argv[2]; + char *subvolid = argv[1]; +@@ -826,9 +847,11 @@ int do_set_default_subvol(int nargs, char **argv) + return 30; + } + ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid); ++ e = errno; + close(fd); + if( ret < 0 ){ +- fprintf(stderr, "ERROR: unable to set a new default subvolume\n"); ++ fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n", ++ strerror(e)); + return 30; + } + return 0; +@@ -840,6 +863,7 @@ int do_df_filesystem(int nargs, char **argv) + u64 count = 0, i; + int ret; + int fd; ++ int e; + char *path = argv[1]; + + fd = open_file_or_dir(path); +@@ -856,7 +880,10 @@ int do_df_filesystem(int nargs, char **argv) + sargs->total_spaces = 0; + + ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs); ++ e = errno; + if (ret) { ++ fprintf(stderr, "ERROR: couldn't get space info on '%s' - %s\n", ++ path, strerror(e)); + free(sargs); + return ret; + } +@@ -874,7 +901,11 @@ int do_df_filesystem(int nargs, char **argv) + sargs->total_spaces = 0; + + ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs); ++ e = errno; + if (ret) { ++ fprintf(stderr, "ERROR: couldn't get space info on '%s' - %s\n", ++ path, strerror(e)); ++ close(fd); + free(sargs); + return ret; + } +diff --git a/utils.c b/utils.c +index d8c3dcc..2a15d86 100644 +--- a/utils.c ++++ b/utils.c +@@ -821,6 +821,7 @@ void btrfs_register_one_device(char *fname) + struct btrfs_ioctl_vol_args args; + int fd; + int ret; ++ int e; + + fd = open("/dev/btrfs-control", O_RDONLY); + if (fd < 0) { +@@ -830,6 +831,11 @@ void btrfs_register_one_device(char *fname) + } + strncpy(args.name, fname, BTRFS_PATH_NAME_MAX); + ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); ++ e = errno; ++ if(ret<0){ ++ fprintf(stderr, "ERROR: unable to scan the device '%s' - %s\n", ++ fname, strerror(e)); ++ } + close(fd); + } + +-- +1.7.5.2.353.g5df3e + diff --git a/0006-Btrfs-progs-update-super-fields-for-space-cache.patch b/0006-Btrfs-progs-update-super-fields-for-space-cache.patch new file mode 100644 index 0000000..3ec13c3 --- /dev/null +++ b/0006-Btrfs-progs-update-super-fields-for-space-cache.patch @@ -0,0 +1,56 @@ +From c2cefc42ebf8e32e36b1866048a02a579f2cef9a Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Thu, 9 Dec 2010 18:27:03 +0000 +Subject: [PATCH 06/15] Btrfs-progs: update super fields for space cache + +This patch updates the super field to add the cache_generation member. It also +makes us set it to -1 on mkfs so any new filesystem will get the space cache +stuff turned on. Thanks, + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +--- + ctree.h | 6 +++++- + utils.c | 1 + + 2 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/ctree.h b/ctree.h +index b79e238..962c510 100644 +--- a/ctree.h ++++ b/ctree.h +@@ -340,8 +340,10 @@ struct btrfs_super_block { + + char label[BTRFS_LABEL_SIZE]; + ++ __le64 cache_generation; ++ + /* future expansion */ +- __le64 reserved[32]; ++ __le64 reserved[31]; + u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; + } __attribute__ ((__packed__)); + +@@ -1564,6 +1566,8 @@ BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block, + incompat_flags, 64); + BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, + csum_type, 16); ++BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, ++ cache_generation, 64); + + static inline int btrfs_super_csum_size(struct btrfs_super_block *s) + { +diff --git a/utils.c b/utils.c +index 2a15d86..35e17b8 100644 +--- a/utils.c ++++ b/utils.c +@@ -107,6 +107,7 @@ int make_btrfs(int fd, const char *device, const char *label, + btrfs_set_super_stripesize(&super, stripesize); + btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32); + btrfs_set_super_chunk_root_generation(&super, 1); ++ btrfs_set_super_cache_generation(&super, -1); + if (label) + strncpy(super.label, label, BTRFS_LABEL_SIZE - 1); + +-- +1.7.5.2.353.g5df3e + diff --git a/0007-Btrfs-progs-add-support-for-mixed-data-metadata-bloc.patch b/0007-Btrfs-progs-add-support-for-mixed-data-metadata-bloc.patch new file mode 100644 index 0000000..be7d25b --- /dev/null +++ b/0007-Btrfs-progs-add-support-for-mixed-data-metadata-bloc.patch @@ -0,0 +1,403 @@ +From e7ef1f26a25d06d5606934dced7b52f3e33f1d33 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Thu, 9 Dec 2010 18:31:08 +0000 +Subject: [PATCH 07/15] Btrfs-progs: add support for mixed data+metadata block + groups + +So alot of crazy people (I'm looking at you Meego) want to use btrfs on phones +and such with small devices. Unfortunately the way we split out metadata/data +chunks it makes space usage inefficient for volumes that are smaller than +1gigabyte. So add a -M option for mixing metadata+data, and default to this +mixed mode if the filesystem is less than or equal to 1 gigabyte. I've tested +this with xfstests on a 100mb filesystem and everything is a-ok. + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +--- + btrfs-vol.c | 4 +- + btrfs_cmds.c | 13 +++++- + ctree.h | 10 +++-- + mkfs.c | 122 +++++++++++++++++++++++++++++++++++++++++----------------- + utils.c | 10 ++-- + utils.h | 2 +- + 6 files changed, 112 insertions(+), 49 deletions(-) + +diff --git a/btrfs-vol.c b/btrfs-vol.c +index 4ed799d..f573023 100644 +--- a/btrfs-vol.c ++++ b/btrfs-vol.c +@@ -143,7 +143,9 @@ int main(int ac, char **av) + exit(1); + } + if (cmd == BTRFS_IOC_ADD_DEV) { +- ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count); ++ int mixed = 0; ++ ++ ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count, &mixed); + if (ret) { + fprintf(stderr, "Unable to init %s\n", device); + exit(1); +diff --git a/btrfs_cmds.c b/btrfs_cmds.c +index 775bfe1..c21a007 100644 +--- a/btrfs_cmds.c ++++ b/btrfs_cmds.c +@@ -720,6 +720,7 @@ int do_add_volume(int nargs, char **args) + int devfd, res; + u64 dev_block_count = 0; + struct stat st; ++ int mixed = 0; + + devfd = open(args[i], O_RDWR); + if (!devfd) { +@@ -742,7 +743,7 @@ int do_add_volume(int nargs, char **args) + continue; + } + +- res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count); ++ res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count, &mixed); + if (res) { + fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]); + close(devfd); +@@ -920,8 +921,14 @@ int do_df_filesystem(int nargs, char **argv) + memset(description, 0, 80); + + if (flags & BTRFS_BLOCK_GROUP_DATA) { +- snprintf(description, 5, "%s", "Data"); +- written += 4; ++ if (flags & BTRFS_BLOCK_GROUP_METADATA) { ++ snprintf(description, 15, "%s", ++ "Data+Metadata"); ++ written += 14; ++ } else { ++ snprintf(description, 5, "%s", "Data"); ++ written += 4; ++ } + } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { + snprintf(description, 7, "%s", "System"); + written += 6; +diff --git a/ctree.h b/ctree.h +index 962c510..ed83d02 100644 +--- a/ctree.h ++++ b/ctree.h +@@ -352,13 +352,15 @@ struct btrfs_super_block { + * ones specified below then we will fail to mount + */ + #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) +-#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (2ULL << 0) ++#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) ++#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) + + #define BTRFS_FEATURE_COMPAT_SUPP 0ULL + #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL +-#define BTRFS_FEATURE_INCOMPAT_SUPP \ +- (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ +- BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL) ++#define BTRFS_FEATURE_INCOMPAT_SUPP \ ++ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ ++ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ ++ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) + + /* + * A leaf is full of items. offset and size tell us where to find +diff --git a/mkfs.c b/mkfs.c +index 2e99b95..04de93a 100644 +--- a/mkfs.c ++++ b/mkfs.c +@@ -69,7 +69,7 @@ static u64 parse_size(char *s) + return atol(s) * mult; + } + +-static int make_root_dir(struct btrfs_root *root) ++static int make_root_dir(struct btrfs_root *root, int mixed) + { + struct btrfs_trans_handle *trans; + struct btrfs_key location; +@@ -88,30 +88,47 @@ static int make_root_dir(struct btrfs_root *root) + 0, BTRFS_MKFS_SYSTEM_GROUP_SIZE); + BUG_ON(ret); + +- ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, +- &chunk_start, &chunk_size, +- BTRFS_BLOCK_GROUP_METADATA); +- BUG_ON(ret); +- ret = btrfs_make_block_group(trans, root, 0, +- BTRFS_BLOCK_GROUP_METADATA, +- BTRFS_FIRST_CHUNK_TREE_OBJECTID, +- chunk_start, chunk_size); +- BUG_ON(ret); ++ if (mixed) { ++ ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, ++ &chunk_start, &chunk_size, ++ BTRFS_BLOCK_GROUP_METADATA | ++ BTRFS_BLOCK_GROUP_DATA); ++ BUG_ON(ret); ++ ret = btrfs_make_block_group(trans, root, 0, ++ BTRFS_BLOCK_GROUP_METADATA | ++ BTRFS_BLOCK_GROUP_DATA, ++ BTRFS_FIRST_CHUNK_TREE_OBJECTID, ++ chunk_start, chunk_size); ++ BUG_ON(ret); ++ printf("Created a data/metadata chunk of size %llu\n", chunk_size); ++ } else { ++ ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, ++ &chunk_start, &chunk_size, ++ BTRFS_BLOCK_GROUP_METADATA); ++ BUG_ON(ret); ++ ret = btrfs_make_block_group(trans, root, 0, ++ BTRFS_BLOCK_GROUP_METADATA, ++ BTRFS_FIRST_CHUNK_TREE_OBJECTID, ++ chunk_start, chunk_size); ++ BUG_ON(ret); ++ } + + root->fs_info->system_allocs = 0; + btrfs_commit_transaction(trans, root); + trans = btrfs_start_transaction(root, 1); + BUG_ON(!trans); + +- ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, +- &chunk_start, &chunk_size, +- BTRFS_BLOCK_GROUP_DATA); +- BUG_ON(ret); +- ret = btrfs_make_block_group(trans, root, 0, +- BTRFS_BLOCK_GROUP_DATA, +- BTRFS_FIRST_CHUNK_TREE_OBJECTID, +- chunk_start, chunk_size); +- BUG_ON(ret); ++ if (!mixed) { ++ ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, ++ &chunk_start, &chunk_size, ++ BTRFS_BLOCK_GROUP_DATA); ++ BUG_ON(ret); ++ ret = btrfs_make_block_group(trans, root, 0, ++ BTRFS_BLOCK_GROUP_DATA, ++ BTRFS_FIRST_CHUNK_TREE_OBJECTID, ++ chunk_start, chunk_size); ++ BUG_ON(ret); ++ } + + ret = btrfs_make_root_dir(trans, root->fs_info->tree_root, + BTRFS_ROOT_TREE_DIR_OBJECTID); +@@ -200,7 +217,7 @@ static int create_one_raid_group(struct btrfs_trans_handle *trans, + + static int create_raid_groups(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 data_profile, +- u64 metadata_profile) ++ u64 metadata_profile, int mixed) + { + u64 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy); + u64 allowed; +@@ -215,20 +232,24 @@ static int create_raid_groups(struct btrfs_trans_handle *trans, + allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1; + + if (allowed & metadata_profile) { ++ u64 meta_flags = BTRFS_BLOCK_GROUP_METADATA; ++ + ret = create_one_raid_group(trans, root, + BTRFS_BLOCK_GROUP_SYSTEM | + (allowed & metadata_profile)); + BUG_ON(ret); + +- ret = create_one_raid_group(trans, root, +- BTRFS_BLOCK_GROUP_METADATA | ++ if (mixed) ++ meta_flags |= BTRFS_BLOCK_GROUP_DATA; ++ ++ ret = create_one_raid_group(trans, root, meta_flags | + (allowed & metadata_profile)); + BUG_ON(ret); + + ret = recow_roots(trans, root); + BUG_ON(ret); + } +- if (num_devices > 1 && (allowed & data_profile)) { ++ if (!mixed && num_devices > 1 && (allowed & data_profile)) { + ret = create_one_raid_group(trans, root, + BTRFS_BLOCK_GROUP_DATA | + (allowed & data_profile)); +@@ -274,6 +295,7 @@ static void print_usage(void) + fprintf(stderr, "\t -l --leafsize size of btree leaves\n"); + fprintf(stderr, "\t -L --label set a label\n"); + fprintf(stderr, "\t -m --metadata metadata profile, values like data profile\n"); ++ fprintf(stderr, "\t -M --mixed mix metadata and data together\n"); + fprintf(stderr, "\t -n --nodesize size of btree nodes\n"); + fprintf(stderr, "\t -s --sectorsize min block allocation\n"); + fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); +@@ -328,6 +350,7 @@ static struct option long_options[] = { + { "leafsize", 1, NULL, 'l' }, + { "label", 1, NULL, 'L'}, + { "metadata", 1, NULL, 'm' }, ++ { "mixed", 0, NULL, 'M' }, + { "nodesize", 1, NULL, 'n' }, + { "sectorsize", 1, NULL, 's' }, + { "data", 1, NULL, 'd' }, +@@ -358,10 +381,13 @@ int main(int ac, char **av) + int first_fd; + int ret; + int i; ++ int mixed = 0; ++ int data_profile_opt = 0; ++ int metadata_profile_opt = 0; + + while(1) { + int c; +- c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:V", long_options, ++ c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:VM", long_options, + &option_index); + if (c < 0) + break; +@@ -371,6 +397,7 @@ int main(int ac, char **av) + break; + case 'd': + data_profile = parse_profile(optarg); ++ data_profile_opt = 1; + break; + case 'l': + leafsize = parse_size(optarg); +@@ -380,6 +407,10 @@ int main(int ac, char **av) + break; + case 'm': + metadata_profile = parse_profile(optarg); ++ metadata_profile_opt = 1; ++ break; ++ case 'M': ++ mixed = 1; + break; + case 'n': + nodesize = parse_size(optarg); +@@ -389,12 +420,10 @@ int main(int ac, char **av) + break; + case 'b': + block_count = parse_size(optarg); +- if (block_count < 256*1024*1024) { +- fprintf(stderr, "File system size " +- "%llu bytes is too small, " +- "256M is required at least\n", +- (unsigned long long)block_count); +- exit(1); ++ if (block_count <= 1024*1024*1024) { ++ printf("SMALL VOLUME: forcing mixed " ++ "metadata/data groups\n"); ++ mixed = 1; + } + zero_end = 0; + break; +@@ -439,9 +468,22 @@ int main(int ac, char **av) + } + first_fd = fd; + first_file = file; +- ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count); ++ ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, ++ &mixed); + if (block_count == 0) + block_count = dev_block_count; ++ if (mixed) { ++ if (!metadata_profile_opt) ++ metadata_profile = 0; ++ if (!data_profile_opt) ++ data_profile = 0; ++ ++ if (metadata_profile != data_profile) { ++ fprintf(stderr, "With mixed block groups data and metadata " ++ "profiles must be the same\n"); ++ exit(1); ++ } ++ } + + blocks[0] = BTRFS_SUPER_INFO_OFFSET; + for (i = 1; i < 7; i++) { +@@ -459,7 +501,7 @@ int main(int ac, char **av) + root = open_ctree(file, 0, O_RDWR); + root->fs_info->alloc_start = alloc_start; + +- ret = make_root_dir(root); ++ ret = make_root_dir(root, mixed); + if (ret) { + fprintf(stderr, "failed to setup the root directory\n"); + exit(1); +@@ -478,6 +520,8 @@ int main(int ac, char **av) + + zero_end = 1; + while(ac-- > 0) { ++ int old_mixed = mixed; ++ + file = av[optind++]; + ret = check_mounted(file); + if (ret < 0) { +@@ -503,8 +547,8 @@ int main(int ac, char **av) + continue; + } + ret = btrfs_prepare_device(fd, file, zero_end, +- &dev_block_count); +- ++ &dev_block_count, &mixed); ++ mixed = old_mixed; + BUG_ON(ret); + + ret = btrfs_add_to_fsid(trans, root, fd, file, dev_block_count, +@@ -515,12 +559,20 @@ int main(int ac, char **av) + + raid_groups: + ret = create_raid_groups(trans, root, data_profile, +- metadata_profile); ++ metadata_profile, mixed); + BUG_ON(ret); + + ret = create_data_reloc_tree(trans, root); + BUG_ON(ret); + ++ if (mixed) { ++ struct btrfs_super_block *super = &root->fs_info->super_copy; ++ u64 flags = btrfs_super_incompat_flags(super); ++ ++ flags |= BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS; ++ btrfs_set_super_incompat_flags(super, flags); ++ } ++ + printf("fs created label %s on %s\n\tnodesize %u leafsize %u " + "sectorsize %u size %s\n", + label, first_file, nodesize, leafsize, sectorsize, +diff --git a/utils.c b/utils.c +index 35e17b8..ad980ae 100644 +--- a/utils.c ++++ b/utils.c +@@ -512,7 +512,8 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, + return 0; + } + +-int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) ++int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, ++ int *mixed) + { + u64 block_count; + u64 bytenr; +@@ -532,10 +533,9 @@ int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) + } + zero_end = 1; + +- if (block_count < 256 * 1024 * 1024) { +- fprintf(stderr, "device %s is too small " +- "(must be at least 256 MB)\n", file); +- exit(1); ++ if (block_count < 1024 * 1024 * 1024 && !(*mixed)) { ++ printf("SMALL VOLUME: forcing mixed metadata/data groups\n"); ++ *mixed = 1; + } + ret = zero_dev_start(fd); + if (ret) { +diff --git a/utils.h b/utils.h +index 9dce5b0..a28d7f4 100644 +--- a/utils.h ++++ b/utils.h +@@ -27,7 +27,7 @@ int make_btrfs(int fd, const char *device, const char *label, + int btrfs_make_root_dir(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 objectid); + int btrfs_prepare_device(int fd, char *file, int zero_end, +- u64 *block_count_ret); ++ u64 *block_count_ret, int *mixed); + int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, + struct btrfs_root *root, int fd, char *path, + u64 block_count, u32 io_width, u32 io_align, +-- +1.7.5.2.353.g5df3e + diff --git a/0008-Update-for-lzo-support.patch b/0008-Update-for-lzo-support.patch new file mode 100644 index 0000000..6ffc8fa --- /dev/null +++ b/0008-Update-for-lzo-support.patch @@ -0,0 +1,202 @@ +From 97e64f8cb21685b7359169f3047c0d082b0ff7e8 Mon Sep 17 00:00:00 2001 +From: Li Zefan +Date: Thu, 18 Nov 2010 03:49:56 +0000 +Subject: [PATCH 08/15] Update for lzo support + +[Btrfs-Progs][V2] Update for lzo support + +- Add incompat flag, otherwise btrfs-progs will report error + when operating on btrfs filesystems mounted with lzo option. + +- Update man page. + +- Allow to turn on lzo compression for defrag operation: + + # btrfs filesystem defragment -c[zlib, lzo] + + Note: "-c zlib" will fail, because that's how getopt() works + for optional arguments. + +Signed-off-by: Li Zefan +Signed-off-by: Chris Mason +--- + btrfs.c | 2 +- + btrfs_cmds.c | 24 ++++++++++++++++++++---- + ctree.h | 10 +++++++--- + ioctl.h | 9 ++++++++- + man/btrfs.8.in | 10 ++++++---- + 5 files changed, 42 insertions(+), 13 deletions(-) + +diff --git a/btrfs.c b/btrfs.c +index 46314cf..1b4f403 100644 +--- a/btrfs.c ++++ b/btrfs.c +@@ -65,7 +65,7 @@ static struct Command commands[] = { + "List the recently modified files in a filesystem." + }, + { do_defrag, -1, +- "filesystem defragment", "[-vcf] [-s start] [-l len] [-t size] | [|...]\n" ++ "filesystem defragment", "[-vf] [-c[zlib,lzo]] [-s start] [-l len] [-t size] | [|...]\n" + "Defragment a file or a directory." + }, + { do_set_default_subvol, 2, +diff --git a/btrfs_cmds.c b/btrfs_cmds.c +index c21a007..26d4fcc 100644 +--- a/btrfs_cmds.c ++++ b/btrfs_cmds.c +@@ -142,10 +142,21 @@ static u64 parse_size(char *s) + return atoll(s) * mult; + } + ++static int parse_compress_type(char *s) ++{ ++ if (strcmp(optarg, "zlib") == 0) ++ return BTRFS_COMPRESS_ZLIB; ++ else if (strcmp(optarg, "lzo") == 0) ++ return BTRFS_COMPRESS_LZO; ++ else { ++ fprintf(stderr, "Unknown compress type %s\n", s); ++ exit(1); ++ }; ++} ++ + int do_defrag(int ac, char **av) + { + int fd; +- int compress = 0; + int flush = 0; + u64 start = 0; + u64 len = (u64)-1; +@@ -157,15 +168,18 @@ int do_defrag(int ac, char **av) + int fancy_ioctl = 0; + struct btrfs_ioctl_defrag_range_args range; + int e=0; ++ int compress_type = BTRFS_COMPRESS_NONE; + + optind = 1; + while(1) { +- int c = getopt(ac, av, "vcfs:l:t:"); ++ int c = getopt(ac, av, "vc::fs:l:t:"); + if (c < 0) + break; + switch(c) { + case 'c': +- compress = 1; ++ compress_type = BTRFS_COMPRESS_ZLIB; ++ if (optarg) ++ compress_type = parse_compress_type(optarg); + fancy_ioctl = 1; + break; + case 'f': +@@ -203,8 +217,10 @@ int do_defrag(int ac, char **av) + range.start = start; + range.len = len; + range.extent_thresh = thresh; +- if (compress) ++ if (compress_type) { + range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS; ++ range.compress_type = compress_type; ++ } + if (flush) + range.flags |= BTRFS_DEFRAG_RANGE_START_IO; + +diff --git a/ctree.h b/ctree.h +index ed83d02..61eb639 100644 +--- a/ctree.h ++++ b/ctree.h +@@ -354,12 +354,14 @@ struct btrfs_super_block { + #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) + #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) + #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) ++#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) + + #define BTRFS_FEATURE_COMPAT_SUPP 0ULL + #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL + #define BTRFS_FEATURE_INCOMPAT_SUPP \ + (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ + BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ ++ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ + BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) + + /* +@@ -505,9 +507,11 @@ struct btrfs_timespec { + } __attribute__ ((__packed__)); + + typedef enum { +- BTRFS_COMPRESS_NONE = 0, +- BTRFS_COMPRESS_ZLIB = 1, +- BTRFS_COMPRESS_LAST = 2, ++ BTRFS_COMPRESS_NONE = 0, ++ BTRFS_COMPRESS_ZLIB = 1, ++ BTRFS_COMPRESS_LZO = 2, ++ BTRFS_COMPRESS_TYPES = 2, ++ BTRFS_COMPRESS_LAST = 3, + } btrfs_compression_type; + + /* we don't understand any encryption methods right now */ +diff --git a/ioctl.h b/ioctl.h +index 776d7a9..bb7b9e0 100644 +--- a/ioctl.h ++++ b/ioctl.h +@@ -116,8 +116,15 @@ struct btrfs_ioctl_defrag_range_args { + */ + __u32 extent_thresh; + ++ /* ++ * which compression method to use if turning on compression ++ * for this defrag operation. If unspecified, zlib will ++ * be used ++ */ ++ __u32 compress_type; ++ + /* spare for later */ +- __u32 unused[5]; ++ __u32 unused[4]; + }; + + struct btrfs_ioctl_space_info { +diff --git a/man/btrfs.8.in b/man/btrfs.8.in +index cba2de1..1ffed13 100644 +--- a/man/btrfs.8.in ++++ b/man/btrfs.8.in +@@ -15,12 +15,12 @@ btrfs \- control a btrfs filesystem + .PP + \fBbtrfs\fP \fBsubvolume set-default\fP\fI \fP + .PP +-\fBbtrfs\fP \fBfilesystem defragment\fP\fI [-vcf] [-s start] [-l len] [-t size] | [|...]\fP +-.PP + \fBbtrfs\fP \fBfilesystem sync\fP\fI \fP + .PP + \fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-][gkm]|max \fP + .PP ++\fBbtrfs\fP \fBfilesystem defrag\fP\fI [options] | [|...]\fP ++.PP + \fBbtrfs\fP \fBdevice scan\fP\fI [ [..]]\fP + .PP + \fBbtrfs\fP \fBdevice show\fP\fI |