diff --git a/btrfs-progs-build-fixes.patch b/btrfs-progs-build-fixes.patch index a78b451..136ac62 100644 --- a/btrfs-progs-build-fixes.patch +++ b/btrfs-progs-build-fixes.patch @@ -1,7 +1,6 @@ -diff --git a/btrfsck.c b/btrfsck.c -index 63e44d1..1e040c4 100644 ---- a/btrfsck.c -+++ b/btrfsck.c +diff -up btrfs-progs-0.19/btrfsck.c.orig btrfs-progs-0.19/btrfsck.c +--- btrfs-progs-0.19/btrfsck.c.orig 2012-04-11 10:44:44.000000000 -0400 ++++ btrfs-progs-0.19/btrfsck.c 2012-04-11 10:45:35.769767880 -0400 @@ -22,7 +22,9 @@ #include #include @@ -9,23 +8,22 @@ index 63e44d1..1e040c4 100644 +#include #include +#include + #include #include "kerncompat.h" #include "ctree.h" - #include "disk-io.h" -diff --git a/mkfs.c b/mkfs.c -index 2e99b95..638f4c2 100644 ---- a/mkfs.c -+++ b/mkfs.c -@@ -348,7 +348,7 @@ int main(int ac, char **av) +diff -up btrfs-progs-0.19/mkfs.c.orig btrfs-progs-0.19/mkfs.c +--- btrfs-progs-0.19/mkfs.c.orig 2012-04-11 10:44:44.652047854 -0400 ++++ btrfs-progs-0.19/mkfs.c 2012-04-11 10:46:03.727553072 -0400 +@@ -1198,7 +1198,7 @@ int main(int ac, char **av) u64 alloc_start = 0; - u64 metadata_profile = BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP; - u64 data_profile = BTRFS_BLOCK_GROUP_RAID0; + u64 metadata_profile = 0; + u64 data_profile = 0; - u32 leafsize = getpagesize(); + u32 leafsize = sysconf(_SC_PAGESIZE); u32 sectorsize = 4096; u32 nodesize = leafsize; u32 stripesize = 4096; -@@ -405,7 +405,7 @@ int main(int ac, char **av) +@@ -1270,7 +1270,7 @@ int main(int ac, char **av) print_usage(); } } diff --git a/btrfs-progs-fix-labels.patch b/btrfs-progs-fix-labels.patch index 92a52e4..c9b0c32 100644 --- a/btrfs-progs-fix-labels.patch +++ b/btrfs-progs-fix-labels.patch @@ -1,17 +1,16 @@ -diff --git a/mkfs.c b/mkfs.c -index d664254..138bcc9 100644 ---- a/mkfs.c -+++ b/mkfs.c -@@ -294,7 +294,6 @@ static u64 parse_profile(char *s) +diff -up btrfs-progs-0.19/mkfs.c.orig btrfs-progs-0.19/mkfs.c +--- btrfs-progs-0.19/mkfs.c.orig 2012-04-11 10:38:26.825973948 -0400 ++++ btrfs-progs-0.19/mkfs.c 2012-04-11 10:39:46.031360540 -0400 +@@ -372,7 +372,6 @@ static u64 parse_profile(char *s) static char *parse_label(char *input) { - int i; int len = strlen(input); - if (len > BTRFS_LABEL_SIZE) { -@@ -302,12 +301,6 @@ static char *parse_label(char *input) - BTRFS_LABEL_SIZE); + if (len >= BTRFS_LABEL_SIZE) { +@@ -380,12 +379,6 @@ static char *parse_label(char *input) + BTRFS_LABEL_SIZE - 1); exit(1); } - for (i = 0; i < len; i++) { diff --git a/btrfs-progs-upstream.patch b/btrfs-progs-upstream.patch index e81558f..83e06a0 100644 --- a/btrfs-progs-upstream.patch +++ b/btrfs-progs-upstream.patch @@ -1,66 +1,645 @@ +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..0e560d5 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,15 @@ ++*.o ++.*.o.d ++version.h ++man/*.gz ++btrfs ++btrfs-debug-tree ++btrfs-map-logical ++btrfs-show ++btrfs-vol ++btrfsck ++btrfsctl ++find-root ++mkfs.btrfs ++repair ++restore +diff --git a/INSTALL b/INSTALL +index 16b45a5..6afbd90 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -22,27 +22,38 @@ in the e2fsprogs sources, and is usually available as libuuid or + e2fsprogs-devel from various distros. + + Building the utilities is just make ; make install. The programs go +-into /usr/local/bin. The commands available are: ++into /usr/local/bin. The mains commands available are: + + mkfs.btrfs: create a filesystem + +-btrfsctl: control program to create snapshots and subvolumes: +- ++btrfs: control program to create snapshots and subvolumes: ++ # mount a btrfs filesystem + mount /dev/sda2 /mnt +- btrfsctl -s new_subvol_name /mnt +- btrfsctl -s snapshot_of_default /mnt/default +- btrfsctl -s snapshot_of_new_subvol /mnt/new_subvol_name +- btrfsctl -s snapshot_of_a_snapshot /mnt/snapshot_of_new_subvol ++ ++ # create a subvolume ++ btrfs subvolume create /mnt/new_subvol_name ++ ++ # snapshot of a subvolume ++ btrfs subvolume snapshot /mnt/default /mnt/snapshot_of_default ++ btrfs subvolume snapshot /mnt/snapshot_of_default \ ++ /mnt/snapshot_of_a_snapshot ++ ++ # list of the subvolumes + ls /mnt + default snapshot_of_a_snapshot snapshot_of_new_subvol + new_subvol_name snapshot_of_default + +- Snapshots and subvolumes cannot be deleted right now, but you can +- rm -rf all the files and directories inside them. ++ # removal of a subvolume or a snapshot ++ btrfs subvolume delete /mn/snapshot_of_a_snapshot ++ ++ # look a the btrfs man page for further information ++ man btrfs + + btrfsck: do a limited check of the FS extent trees. + +-debug-tree: print all of the FS metadata in text form. Example: ++btrfs-debug-tree: print all of the FS metadata in text form. Example: ++ ++ btrfs-debug-tree /dev/sda2 >& big_output_file ++ + +- debug-tree /dev/sda2 >& big_output_file + diff --git a/Makefile b/Makefile -index 8097b5a..6e6f6c6 100644 +index 8097b5a..79818e6 100644 --- a/Makefile +++ b/Makefile -@@ -4,7 +4,7 @@ CFLAGS = -g -Werror -Os +@@ -1,28 +1,32 @@ +-CC=gcc ++CC = gcc + AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 +-CFLAGS = -g -Werror -Os ++CFLAGS = -g -O0 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 ++ volumes.o utils.o btrfs-list.o btrfslabel.o repair.o ++cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ ++ cmds-inspect.o cmds-balance.o - # - CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ -@@ -16,7 +16,9 @@ prefix ?= /usr/local +-# +-CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ +- -Wuninitialized -Wshadow -Wundef ++CHECKFLAGS= -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ ++ -Wuninitialized -Wshadow -Wundef + DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ + +-INSTALL= install ++INSTALL = install + prefix ?= /usr/local bindir = $(prefix)/bin LIBS=-luuid ++RESTORE_LIBS=-lz -progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck +progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \ -+ btrfs \ -+ btrfs-map-logical ++ btrfs btrfs-map-logical btrfs-image btrfs-zero-log btrfs-convert \ ++ btrfs-find-root btrfs-restore btrfstune # make C=1 to enable sparse ifdef C -@@ -35,6 +37,10 @@ all: version $(progs) manpages +- check=sparse $(CHECKFLAGS) ++ check = sparse $(CHECKFLAGS) + else +- check=ls ++ check = ls + endif + + .c.o: +@@ -35,38 +39,66 @@ all: version $(progs) manpages version: bash version.sh -+btrfs: $(objects) btrfs.o btrfs_cmds.o -+ gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o \ -+ $(objects) $(LDFLAGS) $(LIBS) ++btrfs: $(objects) btrfs.o help.o common.o $(cmds_objects) ++ $(CC) $(CFLAGS) -o btrfs btrfs.o help.o common.o $(cmds_objects) \ ++ $(objects) $(LDFLAGS) $(LIBS) -lpthread ++ ++calc-size: $(objects) calc-size.o ++ gcc $(CFLAGS) -o calc-size calc-size.o $(objects) $(LDFLAGS) $(LIBS) ++ ++btrfs-find-root: $(objects) find-root.o ++ gcc $(CFLAGS) -o btrfs-find-root find-root.o $(objects) $(LDFLAGS) $(LIBS) ++ ++btrfs-restore: $(objects) restore.o ++ gcc $(CFLAGS) -o btrfs-restore restore.o $(objects) $(LDFLAGS) $(LIBS) $(RESTORE_LIBS) + btrfsctl: $(objects) btrfsctl.o - gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) +- gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) + + btrfs-vol: $(objects) btrfs-vol.o +- gcc $(CFLAGS) -o btrfs-vol btrfs-vol.o $(objects) $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfs-vol btrfs-vol.o $(objects) $(LDFLAGS) $(LIBS) + + btrfs-show: $(objects) btrfs-show.o +- gcc $(CFLAGS) -o btrfs-show btrfs-show.o $(objects) $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfs-show btrfs-show.o $(objects) $(LDFLAGS) $(LIBS) + + btrfsck: $(objects) btrfsck.o +- gcc $(CFLAGS) -o btrfsck btrfsck.o $(objects) $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfsck btrfsck.o $(objects) $(LDFLAGS) $(LIBS) + + mkfs.btrfs: $(objects) mkfs.o +- gcc $(CFLAGS) -o mkfs.btrfs $(objects) mkfs.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o mkfs.btrfs $(objects) mkfs.o $(LDFLAGS) $(LIBS) -@@ -53,9 +59,15 @@ mkfs.btrfs: $(objects) mkfs.o btrfs-debug-tree: $(objects) debug-tree.o - gcc $(CFLAGS) -o btrfs-debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS) - +- gcc $(CFLAGS) -o btrfs-debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfs-debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS) ++ +btrfs-zero-log: $(objects) btrfs-zero-log.o -+ gcc $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS) + ++btrfs-select-super: $(objects) btrfs-select-super.o ++ $(CC) $(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) - +- gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS) ++ +btrfs-map-logical: $(objects) btrfs-map-logical.o -+ gcc $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS) + ++btrfs-corrupt-block: $(objects) btrfs-corrupt-block.o ++ $(CC) $(CFLAGS) -o btrfs-corrupt-block $(objects) btrfs-corrupt-block.o $(LDFLAGS) $(LIBS) + btrfs-image: $(objects) btrfs-image.o - gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS) +- gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS) -@@ -66,7 +78,10 @@ quick-test: $(objects) quick-test.o - gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS) + dir-test: $(objects) dir-test.o +- gcc $(CFLAGS) -o dir-test $(objects) dir-test.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o dir-test $(objects) dir-test.o $(LDFLAGS) $(LIBS) - convert: $(objects) convert.o -- gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs $(LDFLAGS) $(LIBS) -+ gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lcom_err $(LDFLAGS) $(LIBS) + quick-test: $(objects) quick-test.o +- gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS) + ++btrfs-convert: $(objects) convert.o ++ $(CC) $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lcom_err $(LDFLAGS) $(LIBS) + +-convert: $(objects) convert.o +- gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs $(LDFLAGS) $(LIBS) +ioctl-test: $(objects) ioctl-test.o -+ gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS) ++ $(CC) $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS) manpages: cd man; make +@@ -75,12 +107,12 @@ install-man: + cd man; make install + + clean : +- rm -f $(progs) cscope.out *.o .*.d btrfs-convert ++ rm -f $(progs) cscope.out *.o .*.d btrfs-convert btrfs-image btrfs-select-super \ ++ btrfs-zero-log btrfstune dir-test ioctl-test quick-test version.h + cd man; make clean + + install: $(progs) install-man + $(INSTALL) -m755 -d $(DESTDIR)$(bindir) + $(INSTALL) $(progs) $(DESTDIR)$(bindir) +- if [ -e btrfs-convert ]; then $(INSTALL) btrfs-convert $(DESTDIR)$(bindir); fi + + -include .*.d +diff --git a/bcp b/bcp +index 5729e91..e7ca641 100755 +--- a/bcp ++++ b/bcp +@@ -136,8 +136,7 @@ for srci in xrange(0, src_args): + srcname = os.path.join(dirpath, x) + statinfo = os.lstat(srcname) + +- if srcname.startswith(src): +- part = srcname[len(src) + 1:] ++ part = os.path.relpath(srcname, src) + + if stat.S_ISLNK(statinfo.st_mode): + copylink(srcname, dst, part, statinfo, None) +@@ -152,8 +151,7 @@ for srci in xrange(0, src_args): + + for f in filenames: + srcname = os.path.join(dirpath, f) +- if srcname.startswith(src): +- part = srcname[len(src) + 1:] ++ part = os.path.relpath(srcname, src) + + statinfo = os.lstat(srcname) + copyfile(srcname, dst, part, statinfo, None) +diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c +new file mode 100644 +index 0000000..7051e99 +--- /dev/null ++++ b/btrfs-corrupt-block.c +@@ -0,0 +1,396 @@ ++/* ++ * Copyright (C) 2009 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 "volumes.h" ++#include "disk-io.h" ++#include "print-tree.h" ++#include "transaction.h" ++#include "list.h" ++#include "version.h" ++ ++struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr, ++ u32 blocksize, int copy) ++{ ++ int ret; ++ struct extent_buffer *eb; ++ u64 length; ++ struct btrfs_multi_bio *multi = NULL; ++ struct btrfs_device *device; ++ int num_copies; ++ int mirror_num = 1; ++ ++ eb = btrfs_find_create_tree_block(root, bytenr, blocksize); ++ if (!eb) ++ return NULL; ++ ++ length = blocksize; ++ while (1) { ++ ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, ++ eb->start, &length, &multi, mirror_num); ++ BUG_ON(ret); ++ device = multi->stripes[0].dev; ++ eb->fd = device->fd; ++ device->total_ios++; ++ eb->dev_bytenr = multi->stripes[0].physical; ++ ++ fprintf(stdout, "mirror %d logical %Lu physical %Lu " ++ "device %s\n", mirror_num, (unsigned long long)bytenr, ++ (unsigned long long)eb->dev_bytenr, device->name); ++ kfree(multi); ++ ++ if (!copy || mirror_num == copy) { ++ ret = read_extent_from_disk(eb); ++ printf("corrupting %llu copy %d\n", eb->start, ++ mirror_num); ++ memset(eb->data, 0, eb->len); ++ write_extent_to_disk(eb); ++ fsync(eb->fd); ++ } ++ ++ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, ++ eb->start, eb->len); ++ if (num_copies == 1) ++ break; ++ ++ mirror_num++; ++ if (mirror_num > num_copies) ++ break; ++ } ++ return eb; ++} ++ ++static void print_usage(void) ++{ ++ fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n"); ++ fprintf(stderr, "\t-l Logical extent to map\n"); ++ fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n"); ++ fprintf(stderr, "\t-o Output file to hold the extent\n"); ++ fprintf(stderr, "\t-b Number of bytes to read\n"); ++ exit(1); ++} ++ ++static void corrupt_keys(struct btrfs_trans_handle *trans, ++ struct btrfs_root *root, ++ struct extent_buffer *eb) ++{ ++ int slot; ++ int bad_slot; ++ int nr; ++ struct btrfs_disk_key bad_key;; ++ ++ nr = btrfs_header_nritems(eb); ++ if (nr == 0) ++ return; ++ ++ slot = rand() % nr; ++ bad_slot = rand() % nr; ++ ++ if (bad_slot == slot) ++ return; ++ ++ fprintf(stderr, "corrupting keys in block %llu slot %d swapping with %d\n", ++ (unsigned long long)eb->start, slot, bad_slot); ++ ++ if (btrfs_header_level(eb) == 0) { ++ btrfs_item_key(eb, &bad_key, bad_slot); ++ btrfs_set_item_key(eb, &bad_key, slot); ++ } else { ++ btrfs_node_key(eb, &bad_key, bad_slot); ++ btrfs_set_node_key(eb, &bad_key, slot); ++ } ++ btrfs_mark_buffer_dirty(eb); ++ if (!trans) { ++ csum_tree_block(root, eb, 0); ++ write_extent_to_disk(eb); ++ } ++} ++ ++ ++static int corrupt_keys_in_block(struct btrfs_root *root, u64 bytenr) ++{ ++ struct extent_buffer *eb; ++ ++ eb = read_tree_block(root, bytenr, root->leafsize, 0); ++ if (!eb) ++ return -EIO;; ++ ++ corrupt_keys(NULL, root, eb); ++ free_extent_buffer(eb); ++ return 0; ++} ++ ++static int corrupt_extent(struct btrfs_trans_handle *trans, ++ struct btrfs_root *root, u64 bytenr, int copy) ++{ ++ struct btrfs_key key; ++ struct extent_buffer *leaf; ++ u32 item_size; ++ unsigned long ptr; ++ struct btrfs_path *path; ++ int ret; ++ int slot; ++ int should_del = rand() % 3; ++ ++ path = btrfs_alloc_path(); ++ ++ key.objectid = bytenr; ++ key.type = (u8)-1; ++ key.offset = (u64)-1; ++ ++ while(1) { ++ ret = btrfs_search_slot(trans, root->fs_info->extent_root, ++ &key, path, -1, 1); ++ if (ret < 0) ++ break; ++ ++ if (ret > 0) { ++ if (path->slots[0] == 0) ++ break; ++ path->slots[0]--; ++ ret = 0; ++ } ++ leaf = path->nodes[0]; ++ slot = path->slots[0]; ++ btrfs_item_key_to_cpu(leaf, &key, slot); ++ if (key.objectid != bytenr) ++ break; ++ ++ if (key.type != BTRFS_EXTENT_ITEM_KEY && ++ key.type != BTRFS_TREE_BLOCK_REF_KEY && ++ key.type != BTRFS_EXTENT_DATA_REF_KEY && ++ key.type != BTRFS_EXTENT_REF_V0_KEY && ++ key.type != BTRFS_SHARED_BLOCK_REF_KEY && ++ key.type != BTRFS_SHARED_DATA_REF_KEY) ++ goto next; ++ ++ if (should_del) { ++ fprintf(stderr, "deleting extent record: key %Lu %u %Lu\n", ++ key.objectid, key.type, key.offset); ++ ++ if (key.type == BTRFS_EXTENT_ITEM_KEY) { ++ /* make sure this extent doesn't get ++ * reused for other purposes */ ++ btrfs_pin_extent(root->fs_info, ++ key.objectid, key.offset); ++ } ++ ++ btrfs_del_item(trans, root, path); ++ } else { ++ fprintf(stderr, "corrupting extent record: key %Lu %u %Lu\n", ++ key.objectid, key.type, key.offset); ++ ptr = btrfs_item_ptr_offset(leaf, slot); ++ item_size = btrfs_item_size_nr(leaf, slot); ++ memset_extent_buffer(leaf, 0, ptr, item_size); ++ btrfs_mark_buffer_dirty(leaf); ++ } ++next: ++ btrfs_release_path(NULL, path); ++ ++ if (key.offset > 0) ++ key.offset--; ++ if (key.offset == 0) ++ break; ++ } ++ ++ btrfs_free_path(path); ++ return 0; ++} ++ ++static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans, ++ struct btrfs_root *root, struct extent_buffer *eb) ++{ ++ u32 nr = btrfs_header_nritems(eb); ++ u32 victim = rand() % nr; ++ u64 objectid; ++ struct btrfs_key key; ++ ++ btrfs_item_key_to_cpu(eb, &key, victim); ++ objectid = key.objectid; ++ corrupt_extent(trans, root, objectid, 1); ++} ++ ++static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans, ++ struct btrfs_root *root, struct extent_buffer *eb) ++{ ++ int i; ++ u32 nr; ++ ++ if (!eb) ++ return; ++ ++ nr = btrfs_header_nritems(eb); ++ if (btrfs_is_leaf(eb)) { ++ btrfs_corrupt_extent_leaf(trans, root, eb); ++ return; ++ } ++ ++ if (btrfs_header_level(eb) == 1 && eb != root->node) { ++ if (rand() % 5) ++ return; ++ } ++ ++ for (i = 0; i < nr; i++) { ++ struct extent_buffer *next; ++ ++ next = read_tree_block(root, btrfs_node_blockptr(eb, i), ++ root->leafsize, btrfs_node_ptr_generation(eb, i)); ++ if (!next) ++ continue; ++ btrfs_corrupt_extent_tree(trans, root, next); ++ free_extent_buffer(next); ++ } ++} ++ ++static struct option long_options[] = { ++ /* { "byte-count", 1, NULL, 'b' }, */ ++ { "logical", 1, NULL, 'l' }, ++ { "copy", 1, NULL, 'c' }, ++ { "bytes", 1, NULL, 'b' }, ++ { "extent-record", 0, NULL, 'e' }, ++ { "extent-tree", 0, NULL, 'E' }, ++ { "keys", 0, NULL, 'k' }, ++ { 0, 0, 0, 0} ++}; ++ ++ ++int main(int ac, char **av) ++{ ++ struct cache_tree root_cache; ++ struct btrfs_root *root; ++ struct extent_buffer *eb; ++ char *dev; ++ u64 logical = 0; ++ int ret = 0; ++ int option_index = 0; ++ int copy = 0; ++ u64 bytes = 4096; ++ int extent_rec = 0; ++ int extent_tree = 0; ++ int corrupt_block_keys = 0; ++ ++ srand(128); ++ ++ while(1) { ++ int c; ++ c = getopt_long(ac, av, "l:c:eEk", long_options, ++ &option_index); ++ if (c < 0) ++ break; ++ switch(c) { ++ case 'l': ++ logical = atoll(optarg); ++ if (logical == 0) { ++ fprintf(stderr, ++ "invalid extent number\n"); ++ print_usage(); ++ } ++ break; ++ case 'c': ++ copy = atoi(optarg); ++ if (copy == 0) { ++ fprintf(stderr, ++ "invalid copy number\n"); ++ print_usage(); ++ } ++ break; ++ case 'b': ++ bytes = atoll(optarg); ++ if (bytes == 0) { ++ fprintf(stderr, ++ "invalid byte count\n"); ++ print_usage(); ++ } ++ break; ++ case 'e': ++ extent_rec = 1; ++ break; ++ case 'E': ++ extent_tree = 1; ++ break; ++ case 'k': ++ corrupt_block_keys = 1; ++ break; ++ default: ++ print_usage(); ++ } ++ } ++ ac = ac - optind; ++ if (ac == 0) ++ print_usage(); ++ if (logical == 0 && !extent_tree) ++ print_usage(); ++ if (copy < 0) ++ print_usage(); ++ ++ dev = av[optind]; ++ ++ radix_tree_init(); ++ cache_tree_init(&root_cache); ++ ++ root = open_ctree(dev, 0, 1); ++ if (!root) { ++ fprintf(stderr, "Open ctree failed\n"); ++ exit(1); ++ } ++ if (extent_rec) { ++ struct btrfs_trans_handle *trans; ++ trans = btrfs_start_transaction(root, 1); ++ ret = corrupt_extent (trans, root, logical, 0); ++ btrfs_commit_transaction(trans, root); ++ goto out_close; ++ } ++ if (extent_tree) { ++ struct btrfs_trans_handle *trans; ++ trans = btrfs_start_transaction(root, 1); ++ btrfs_corrupt_extent_tree(trans, root->fs_info->extent_root, ++ root->fs_info->extent_root->node); ++ btrfs_commit_transaction(trans, root); ++ goto out_close; ++ } ++ ++ if (bytes == 0) ++ bytes = root->sectorsize; ++ ++ bytes = (bytes + root->sectorsize - 1) / root->sectorsize; ++ bytes *= root->sectorsize; ++ ++ while (bytes > 0) { ++ if (corrupt_block_keys) { ++ corrupt_keys_in_block(root, logical); ++ } else { ++ eb = debug_corrupt_block(root, logical, ++ root->sectorsize, copy); ++ free_extent_buffer(eb); ++ } ++ logical += root->sectorsize; ++ bytes -= root->sectorsize; ++ } ++ return ret; ++out_close: ++ close_ctree(root); ++ return ret; ++} diff --git a/btrfs-defrag.c b/btrfs-defrag.c new file mode 100644 index 0000000..8f1525a @@ -108,10 +687,10 @@ index 0000000..8f1525a + diff --git a/btrfs-list.c b/btrfs-list.c new file mode 100644 -index 0000000..93766a8 +index 0000000..5f4a9be --- /dev/null +++ b/btrfs-list.c -@@ -0,0 +1,835 @@ +@@ -0,0 +1,936 @@ +/* + * Copyright (C) 2010 Oracle. All rights reserved. + * @@ -148,7 +727,6 @@ index 0000000..93766a8 +#include "ctree.h" +#include "transaction.h" +#include "utils.h" -+#include "version.h" + +/* we store all the roots we find in an rbtree so that we can + * search for them later. @@ -314,9 +892,9 @@ index 0000000..93766a8 + * This can't be called until all the root_info->path fields are filled + * in by lookup_ino_path + */ -+static int resolve_root(struct root_lookup *rl, struct root_info *ri) ++static int resolve_root(struct root_lookup *rl, struct root_info *ri, ++ u64 *root_id, u64 *parent_id, u64 *top_id, char **path) +{ -+ u64 top_id; + char *full_path = NULL; + int len = 0; + struct root_info *found; @@ -325,6 +903,7 @@ index 0000000..93766a8 + * we go backwards from the root_info object and add pathnames + * from parent directories as we go. + */ ++ *parent_id = 0; + found = ri; + while (1) { + char *tmp; @@ -347,9 +926,13 @@ index 0000000..93766a8 + } + + next = found->ref_tree; ++ /* record the first parent */ ++ if (*parent_id == 0) ++ *parent_id = next; ++ + /* if the ref_tree refers to ourselves, we're at the top */ + if (next == found->root_id) { -+ top_id = next; ++ *top_id = next; + break; + } + @@ -359,13 +942,14 @@ index 0000000..93766a8 + */ + found = tree_search(&rl->root, next); + if (!found) { -+ top_id = next; ++ *top_id = next; + break; + } + } -+ printf("ID %llu top level %llu path %s\n", ri->root_id, top_id, -+ full_path); -+ free(full_path); ++ ++ *root_id = ri->root_id; ++ *path = full_path; ++ + return 0; +} + @@ -379,7 +963,7 @@ index 0000000..93766a8 +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; @@ -389,9 +973,11 @@ index 0000000..93766a8 + 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; + } + @@ -434,15 +1020,18 @@ index 0000000..93766a8 + 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; + } + @@ -465,8 +1054,10 @@ index 0000000..93766a8 + + 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 */ @@ -521,14 +1112,16 @@ index 0000000..93766a8 + 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); + } + @@ -586,6 +1179,7 @@ index 0000000..93766a8 + struct btrfs_ioctl_search_header *sh; + unsigned long off = 0; + int namelen; ++ int e; + + memset(&args, 0, sizeof(args)); + @@ -604,8 +1198,10 @@ index 0000000..93766a8 + 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 */ @@ -650,10 +1246,8 @@ index 0000000..93766a8 + return full; +} + -+int list_subvols(int fd) ++static int __list_subvol_search(int fd, struct root_lookup *root_lookup) +{ -+ struct root_lookup root_lookup; -+ struct rb_node *n; + int ret; + struct btrfs_ioctl_search_args args; + struct btrfs_ioctl_search_key *sk = &args.key; @@ -665,7 +1259,10 @@ index 0000000..93766a8 + u64 dir_id; + int i; + -+ root_lookup_init(&root_lookup); ++ root_lookup_init(root_lookup); ++ memset(&args, 0, sizeof(args)); ++ ++ root_lookup_init(root_lookup); + + memset(&args, 0, sizeof(args)); + @@ -692,10 +1289,8 @@ index 0000000..93766a8 + + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); -+ if (ret < 0) { -+ fprintf(stderr, "ERROR: can't perform the search\n"); ++ if (ret < 0) + return ret; -+ } + /* the ioctl returns the number of item it found in nr_items */ + if (sk->nr_items == 0) + break; @@ -716,7 +1311,7 @@ index 0000000..93766a8 + name = (char *)(ref + 1); + dir_id = btrfs_stack_root_ref_dirid(ref); + -+ add_root(&root_lookup, sh->objectid, sh->offset, ++ add_root(root_lookup, sh->objectid, sh->offset, + dir_id, name, name_len); + } + @@ -734,18 +1329,25 @@ index 0000000..93766a8 + /* this iteration is done, step forward one root for the next + * ioctl + */ -+ if (sk->min_objectid < (u64)-1) { ++ if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) { ++ sk->min_type = BTRFS_ROOT_BACKREF_KEY; ++ sk->min_offset = 0; ++ } else if (sk->min_objectid < (u64)-1) { + sk->min_objectid++; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_offset = 0; + } else + break; + } -+ /* -+ * now we have an rbtree full of root_info objects, but we need to fill -+ * in their path names within the subvol that is referencing each one. -+ */ -+ n = rb_first(&root_lookup.root); ++ ++ return 0; ++} ++ ++static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup) ++{ ++ struct rb_node *n; ++ ++ n = rb_first(&root_lookup->root); + while (n) { + struct root_info *entry; + int ret; @@ -756,6 +1358,30 @@ index 0000000..93766a8 + n = rb_next(n); + } + ++ return 0; ++} ++ ++int list_subvols(int fd, int print_parent) ++{ ++ struct root_lookup root_lookup; ++ struct rb_node *n; ++ int ret; ++ ++ ret = __list_subvol_search(fd, &root_lookup); ++ if (ret) { ++ fprintf(stderr, "ERROR: can't perform the search - %s\n", ++ strerror(errno)); ++ return ret; ++ } ++ ++ /* ++ * now we have an rbtree full of root_info objects, but we need to fill ++ * in their path names within the subvol that is referencing each one. ++ */ ++ ret = __list_subvol_fill_paths(fd, &root_lookup); ++ if (ret < 0) ++ return ret; ++ + /* 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 @@ -763,8 +1389,24 @@ index 0000000..93766a8 + n = rb_last(&root_lookup.root); + while (n) { + struct root_info *entry; ++ u64 root_id; ++ u64 level; ++ u64 parent_id; ++ char *path; + entry = rb_entry(n, struct root_info, rb_node); -+ resolve_root(&root_lookup, entry); ++ resolve_root(&root_lookup, entry, &root_id, &parent_id, ++ &level, &path); ++ if (print_parent) { ++ printf("ID %llu parent %llu top level %llu path %s\n", ++ (unsigned long long)root_id, ++ (unsigned long long)parent_id, ++ (unsigned long long)level, path); ++ } else { ++ printf("ID %llu top level %llu path %s\n", ++ (unsigned long long)root_id, ++ (unsigned long long)level, path); ++ } ++ free(path); + n = rb_prev(n); + } + @@ -861,6 +1503,7 @@ index 0000000..93766a8 + u64 found_gen; + u64 max_found = 0; + int i; ++ int e; + u64 cache_dirid = 0; + u64 cache_ino = 0; + char *cache_dir_name = NULL; @@ -887,8 +1530,10 @@ index 0000000..93766a8 + 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 */ @@ -947,12 +1592,47 @@ index 0000000..93766a8 + 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-map-logical.c b/btrfs-map-logical.c new file mode 100644 -index 0000000..a109c6a +index 0000000..d79a73a --- /dev/null +++ b/btrfs-map-logical.c -@@ -0,0 +1,221 @@ +@@ -0,0 +1,220 @@ +/* + * Copyright (C) 2009 Oracle. All rights reserved. + * @@ -996,7 +1676,6 @@ index 0000000..a109c6a + u32 blocksize, int copy) +{ + int ret; -+ int dev_nr; + struct extent_buffer *eb; + u64 length; + struct btrfs_multi_bio *multi = NULL; @@ -1008,7 +1687,6 @@ index 0000000..a109c6a + if (!eb) + return NULL; + -+ dev_nr = 0; + length = blocksize; + while (1) { + ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, @@ -1020,8 +1698,8 @@ index 0000000..a109c6a + eb->dev_bytenr = multi->stripes[0].physical; + + fprintf(info_file, "mirror %d logical %Lu physical %Lu " -+ "device %s\n", mirror_num, bytenr, eb->dev_bytenr, -+ device->name); ++ "device %s\n", mirror_num, (unsigned long long)bytenr, ++ (unsigned long long)eb->dev_bytenr, device->name); + kfree(multi); + + if (!copy || mirror_num == copy) @@ -1045,7 +1723,7 @@ index 0000000..a109c6a + fprintf(stderr, "\t-l Logical extent to map\n"); + fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n"); + fprintf(stderr, "\t-o Output file to hold the extent\n"); -+ fprintf(stderr, "\t-s Number of bytes to read\n"); ++ fprintf(stderr, "\t-b Number of bytes to read\n"); + exit(1); +} + @@ -1130,6 +1808,7 @@ index 0000000..a109c6a + exit(1); + } + ++ info_file = stdout; + if (output_file) { + if (strcmp(output_file, "-") == 0) { + out_fd = 1; @@ -1174,11 +1853,144 @@ index 0000000..a109c6a + close_ctree(root); + return ret; +} +diff --git a/btrfs-select-super.c b/btrfs-select-super.c +new file mode 100644 +index 0000000..51eb9c9 +--- /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/btrfs-show.c b/btrfs-show.c +index c49626c..8210fd2 100644 +--- a/btrfs-show.c ++++ b/btrfs-show.c +@@ -117,6 +117,11 @@ int main(int ac, char **av) + int ret; + int option_index = 0; + ++ printf( "**\n" ++ "** WARNING: this program is considered deprecated\n" ++ "** Please consider to switch to the btrfs utility\n" ++ "**\n"); ++ + while(1) { + int c; + c = getopt_long(ac, av, "", long_options, diff --git a/btrfs-vol.c b/btrfs-vol.c -index 8069778..4ed799d 100644 +index 8069778..0efdbc1 100644 --- a/btrfs-vol.c +++ b/btrfs-vol.c -@@ -108,10 +108,24 @@ int main(int ac, char **av) +@@ -78,6 +78,11 @@ int main(int ac, char **av) + struct btrfs_ioctl_vol_args args; + u64 dev_block_count = 0; + ++ printf( "**\n" ++ "** WARNING: this program is considered deprecated\n" ++ "** Please consider to switch to the btrfs utility\n" ++ "**\n"); ++ + while(1) { + int c; + c = getopt_long(ac, av, "a:br:", long_options, +@@ -108,10 +113,24 @@ int main(int ac, char **av) if (device && strcmp(device, "missing") == 0 && cmd == BTRFS_IOC_RM_DEV) { fprintf(stderr, "removing missing devices from %s\n", mnt); @@ -1205,12 +2017,23 @@ index 8069778..4ed799d 100644 } ret = fstat(devfd, &st); if (ret) { +@@ -129,7 +148,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-zero-log.c b/btrfs-zero-log.c new file mode 100644 -index 0000000..f10438b +index 0000000..1ea867b --- /dev/null +++ b/btrfs-zero-log.c -@@ -0,0 +1,69 @@ +@@ -0,0 +1,72 @@ +/* + * Copyright (C) 2007 Oracle. All rights reserved. + * @@ -1255,6 +2078,7 @@ index 0000000..f10438b +int main(int ac, char **av) +{ + struct btrfs_root *root; ++ struct btrfs_trans_handle *trans; + int ret; + + if (ac != 2) @@ -1263,7 +2087,7 @@ index 0000000..f10438b + radix_tree_init(); + + if((ret = check_mounted(av[1])) < 0) { -+ fprintf(stderr, "Could not check mount status: %s\n", strerror(ret)); ++ 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[1]); @@ -1275,17 +2099,19 @@ index 0000000..f10438b + if (root == NULL) + return 1; + ++ trans = btrfs_start_transaction(root, 1); + btrfs_set_super_log_root(&root->fs_info->super_copy, 0); + btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0); ++ btrfs_commit_transaction(trans, root); + close_ctree(root); + return ret; +} diff --git a/btrfs.c b/btrfs.c new file mode 100644 -index 0000000..46314cf +index 0000000..88238d6 --- /dev/null +++ b/btrfs.c -@@ -0,0 +1,387 @@ +@@ -0,0 +1,276 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public @@ -1307,1357 +2133,279 @@ index 0000000..46314cf +#include +#include + -+#include "kerncompat.h" -+#include "btrfs_cmds.h" ++#include "commands.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 const char * const btrfs_cmd_group_usage[] = { ++ "btrfs [--help] [--version] [...] []", ++ NULL +}; + -+static struct Command commands[] = { ++static const char btrfs_cmd_group_info[] = ++ "Use --help as an argument for information on a specific group or command."; + -+ /* -+ 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_find_newer, 2, "subvolume find-new", " \n" -+ "List the recently modified files in a filesystem." -+ }, -+ { do_defrag, -1, -+ "filesystem defragment", "[-vcf] [-s start] [-l len] [-t size] | [|...]\n" -+ "Defragment a file or a directory." -+ }, -+ { do_set_default_subvol, 2, -+ "subvolume set-default", " \n" -+ "Set the subvolume of the filesystem which will be mounted\n" -+ "as default." -+ }, -+ { 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", "[|