Accepting request 184455 from filesystems

- Simplify checks in mkinitrd scripts.
  They are always true because they come from the same package
  Use relative paths to binaries
- Move udev rules to /usr.
- Adjust rules to call binary from /usr
- Simplify fsck.btrfs, its just a dummy until fixed

- update to upstream master (f00dd8386a57d241d0f7c)

OBS-URL: https://build.opensuse.org/request/show/184455
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/btrfsprogs?expand=0&rev=30
This commit is contained in:
Stephan Kulow 2013-07-29 15:35:55 +00:00 committed by Git OBS Bridge
commit ef5b405e60
105 changed files with 207 additions and 13205 deletions

View File

@ -0,0 +1,33 @@
From 5ca1ded494d7d58b71877bf1f774ac313fabe35f Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Thu, 2 May 2013 11:20:22 -0500
Subject: [PATCH 10/48] Btrfs-progs: make btrfsck a hardlink at install time
btrfsck gets hardlinked to btrfs during the build, but the
install phase simply copies them both to the destination without
preserving the link.
Just force-link btrfsck in the destination again during install
so that the installed btrfsck is a link as well.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
Makefile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Makefile b/Makefile
index da7438e..0f0b1ac 100644
--- a/Makefile
+++ b/Makefile
@@ -193,6 +193,8 @@ clean :
install: $(libs) $(progs) install-man
$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
$(INSTALL) $(progs) $(DESTDIR)$(bindir)
+ # btrfsck is a link to btrfs in the src tree, make it so for installed file as well
+ $(LN) -f $(DESTDIR)$(bindir)/btrfs $(DESTDIR)$(bindir)/btrfsck
$(INSTALL) -m755 -d $(DESTDIR)$(libdir)
$(INSTALL) $(libs) $(DESTDIR)$(libdir)
cp -a $(lib_links) $(DESTDIR)$(libdir)
--
1.8.2

View File

@ -0,0 +1,27 @@
From 86f2f0e7742ccbfaf62e2d6415bf170a85c71c0e Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Sun, 12 May 2013 16:33:44 +0100
Subject: [PATCH 12/48] libbtrfs: Set SONAME to "libbtrfs.so.0" (instead of
"libbtrfs.so").
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 0f0b1ac..7a49174 100644
--- a/Makefile
+++ b/Makefile
@@ -100,7 +100,7 @@ version.h:
$(libs_shared): $(libbtrfs_objects) $(lib_links) send.h
@echo " [LD] $@"
$(Q)$(CC) $(CFLAGS) $(libbtrfs_objects) $(LDFLAGS) $(lib_LIBS) \
- -shared -Wl,-soname,libbtrfs.so -o libbtrfs.so.0.1
+ -shared -Wl,-soname,libbtrfs.so.0 -o libbtrfs.so.0.1
$(libs_static): $(libbtrfs_objects)
@echo " [AR] $@"
--
1.8.2

View File

@ -1,37 +0,0 @@
From a6aa706ee793b406761baeaa7cde78d1250f2d2b Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Wed, 12 Oct 2011 13:36:13 +0200
Subject: [PATCH 01/35] btrfs-progs: ignore -a option in mkfs
Let mkfs accept '-a' option and not complain. When a partition has non-zero
value in the fs_passno filed in /etc/fstab, the fsck is run but fails and boot
stops. As fsck does not break things currently, it's safe to ignore the option
and let the boot proceed.
Reference: https://bugzilla.novell.com/show_bug.cgi?id=655906
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfsck.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 3a23e66..509ab72 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2815,10 +2815,11 @@ int main(int ac, char **av)
while(1) {
int c;
- c = getopt(ac, av, "s:");
+ c = getopt(ac, av, "as:");
if (c < 0)
break;
switch(c) {
+ case 'a': /* ignored */ break;
case 's':
num = atol(optarg);
bytenr = btrfs_sb_offset(num);
--
1.7.6.233.gd79bc

View File

@ -1,108 +0,0 @@
From 8456dc84b0c7548ca4f83c4e58e8e9dd443b7686 Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Mon, 3 Jan 2011 19:51:46 +0100
Subject: [PATCH 03/35] Add the --force option.
Add the --force option to not check if a device is already mounted.
---
mkfs.c | 46 ++++++++++++++++++++++++++++------------------
1 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/mkfs.c b/mkfs.c
index e3ced19..be236d0 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -303,6 +303,7 @@ static void print_usage(void)
fprintf(stderr, "\t -A --alloc-start the offset to start the FS\n");
fprintf(stderr, "\t -b --byte-count total number of bytes in the FS\n");
fprintf(stderr, "\t -d --data data profile, raid0, raid1, raid10 or single\n");
+ fprintf(stderr, "\t -f --force don't check if a device is already mounted\n");
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");
@@ -368,6 +369,7 @@ static struct option long_options[] = {
{ "data", 1, NULL, 'd' },
{ "version", 0, NULL, 'V' },
{ "rootdir", 1, NULL, 'r' },
+ { "force", 0, NULL, 'f' },
{ 0, 0, 0, 0}
};
@@ -1191,10 +1193,11 @@ int main(int ac, char **av)
u64 size_of_data = 0;
u64 source_dir_size = 0;
char *pretty_buf;
+ int force=0;
while(1) {
int c;
- c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VM", long_options,
+ c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VMf", long_options,
&option_index);
if (c < 0)
break;
@@ -1240,6 +1243,8 @@ int main(int ac, char **av)
case 'r':
source_dir = optarg;
source_dir_set = 1;
+ case 'f':
+ force=1;
break;
default:
print_usage();
@@ -1263,14 +1268,17 @@ int main(int ac, char **av)
if (source_dir == 0) {
file = av[optind++];
- ret = check_mounted(file);
- if (ret < 0) {
- fprintf(stderr, "error checking %s mount status\n", file);
- exit(1);
- }
- if (ret == 1) {
- fprintf(stderr, "%s is mounted\n", file);
- exit(1);
+ if(!force){
+ ret = check_mounted(file);
+ if (ret < 0) {
+ fprintf(stderr,
+ "error checking %s mount status\n", file);
+ exit(1);
+ }
+ if (ret == 1) {
+ fprintf(stderr, "%s is mounted\n", file);
+ exit(1);
+ }
}
ac--;
fd = open(file, O_RDWR);
@@ -1353,15 +1361,17 @@ int main(int ac, char **av)
int old_mixed = mixed;
file = av[optind++];
- ret = check_mounted(file);
- if (ret < 0) {
- fprintf(stderr, "error checking %s mount status\n",
- file);
- exit(1);
- }
- if (ret == 1) {
- fprintf(stderr, "%s is mounted\n", file);
- exit(1);
+ if(!force){
+ ret = check_mounted(file);
+ if (ret < 0) {
+ fprintf(stderr, "error checking %s"
+ " mount status\n",file);
+ exit(1);
+ }
+ if (ret == 1) {
+ fprintf(stderr, "%s is mounted\n", file);
+ exit(1);
+ }
}
fd = open(file, O_RDWR);
if (fd < 0) {
--
1.7.6.233.gd79bc

View File

@ -1,35 +0,0 @@
From fdd55a58d661cede927b741e57abc4f564bb7bd6 Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Mon, 3 Jan 2011 19:53:05 +0100
Subject: [PATCH 04/35] mkfs.btrfs man page: document the --force option.
Add the --force option to not check if a device is already mounted.
---
man/mkfs.btrfs.8.in | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/man/mkfs.btrfs.8.in b/man/mkfs.btrfs.8.in
index 432db1b..2610e9d 100644
--- a/man/mkfs.btrfs.8.in
+++ b/man/mkfs.btrfs.8.in
@@ -6,6 +6,7 @@ mkfs.btrfs \- create an btrfs filesystem
[ \fB\-A\fP\fI alloc-start\fP ]
[ \fB\-b\fP\fI byte-count\fP ]
[ \fB \-d\fP\fI data-profile\fP ]
+[ \fB \-f\fP ]
[ \fB \-l\fP\fI leafsize\fP ]
[ \fB \-L\fP\fI label\fP ]
[ \fB \-m\fP\fI metadata profile\fP ]
@@ -35,6 +36,9 @@ mkfs.btrfs uses all the available storage for the filesystem.
Specify how the data must be spanned across the devices specified. Valid
values are raid0, raid1, raid10 or single.
.TP
+\fB\-f\fR, \fB\-\-force \fR
+Don't check if the device is already mounted.
+.TP
\fB\-l\fR, \fB\-\-leafsize \fIsize\fR
Specify the leaf size, the least data item in which btrfs stores data. The
default value is the page size.
--
1.7.6.233.gd79bc

View File

@ -1,42 +0,0 @@
From da911929cf232b81a4e2dcffbb26dc3cc6f222af Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Fri, 21 Oct 2011 19:00:28 +0200
Subject: [PATCH 05/35] Ignore the error ENXIO and ENOMEDIUM during a devs
scan
Ignore the error ENXIO (device don't exists) and ENOMEDIUM (
No medium found -> like a cd tray empty) in the function
btrfs_scan_one_dir.
This avoids spurios errors due to an empty CD or a block device node
without a device (which is frequent in a static /dev).
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
utils.c | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/utils.c b/utils.c
index 178d1b9..1c27e14 100644
--- a/utils.c
+++ b/utils.c
@@ -1003,8 +1003,14 @@ again:
}
fd = open(fullpath, O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "failed to read %s: %s\n", fullpath,
- strerror(errno));
+ /* ignore the following errors:
+ ENXIO (device don't exists)
+ ENOMEDIUM (No medium found ->
+ like a cd tray empty)
+ */
+ if(errno != ENXIO && errno != ENOMEDIUM)
+ fprintf(stderr, "failed to read %s: %s\n",
+ fullpath, strerror(errno));
continue;
}
ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices,
--
1.7.6.233.gd79bc

View File

@ -1,275 +0,0 @@
From 8ed24be618165f2f76851e007347408ab9013d30 Mon Sep 17 00:00:00 2001
From: Hugo Mills <hugo@carfax.org.uk>
Date: Thu, 27 Oct 2011 22:14:26 +0100
Subject: [PATCH 06/35] Regression tests
Add a shell-script based test harness for performing regression tests
on btrfs tools. This is not intended as a test system for kernel
issues, but instead to put the userspace tools through their paces.
Currently implemented tests are compilation of all tools, and checking
argument counting on "btrfs sub snap". Other tests will follow.
Signed-off-by: Hugo Mills <hugo@carfax.org.uk>
---
Makefile | 8 +++
test/001u.sh | 23 ++++++++++
test/002s.sh | 42 +++++++++++++++++
test/functions.sh | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++
test/run-tests | 13 +++++
5 files changed, 214 insertions(+), 0 deletions(-)
create mode 100755 test/001u.sh
create mode 100755 test/002s.sh
create mode 100644 test/functions.sh
create mode 100755 test/run-tests
diff --git a/Makefile b/Makefile
index 7a5e2c1..5f25d66 100644
--- a/Makefile
+++ b/Makefile
@@ -113,4 +113,12 @@ install: $(progs) install-man
$(INSTALL) $(progs) $(DESTDIR)$(bindir)
if [ -e btrfs-convert ]; then $(INSTALL) btrfs-convert $(DESTDIR)$(bindir); fi
+test: test-userspace test-root
+
+test-userspace:
+ ./test/run-tests
+
+test-root:
+ sudo ./test/run-tests
+
-include .*.d
diff --git a/test/001u.sh b/test/001u.sh
new file mode 100755
index 0000000..d2cadff
--- /dev/null
+++ b/test/001u.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. test/functions.sh
+
+unset BTRFS_TESTS_VOLUMES
+
+announce compilation
+
+export CC=gcc-4.6
+catchclean
+make clean >/dev/null 2>&1
+
+catch make || fail Plain make failed
+#catch make dir-test || fail Failed to make dir-test
+catch make btrfs-zero-log || fail Failed to make btrfs-zero-log
+catch make btrfs-select-super || fail Failed to make btrfs-select-super
+catch make btrfstune || fail Failed to make btrfstune
+catch make btrfs-image || fail Failed to make btrfsimage
+catch make quick-test || fail Failed to make quick-test
+catch make convert || fail Failed to make btrfs-convert
+catch make ioctl-test || fail Failed to make ioctl-test
+
+summarise
diff --git a/test/002s.sh b/test/002s.sh
new file mode 100755
index 0000000..2c715b7
--- /dev/null
+++ b/test/002s.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+. test/functions.sh
+
+MNT=./test-mountpoint
+
+function setup() {
+ setup_mkfs btrfs-tests $MNT
+
+ ./btrfs subvolume create $MNT/source >/dev/null || return 1
+ dd if=/dev/urandom of=$MNT/source/file1 \
+ bs=1M count=1 >/dev/null 2>&1 || return 1
+}
+
+function teardown() {
+ teardown_rmfs $MNT
+}
+
+announce snapshot
+catchclean
+
+function test_ro() {
+ ./btrfs subvolume snapshot -r $MNT/source $MNT/destination
+ echo foo >$MNT/destination/foo.txt
+}
+
+# Success modes
+catch ./btrfs subvolume snapshot $MNT/source $MNT/destination \
+ || fail Failed to create rw snapshot
+catch ./btrfs subvolume snapshot -r $MNT/source $MNT/destination \
+ || fail Failed to create ro snapshot
+catch test_ro && fail Failed to use read-only flag
+
+# Failure modes
+catch ./btrfs subvolume snapshot \
+ && fail Accepted incorrect parameters \(0 params\)
+catch ./btrfs subvolume snapshot $MNT/source \
+ && fail Accepted incorrect parameters \(1 param\)
+catch ./btrfs subvolume snapshot -r $MNT/source \
+ && fail Accepted incorrect parameters \(1 param, ro\)
+
+summarise
diff --git a/test/functions.sh b/test/functions.sh
new file mode 100644
index 0000000..ca89c67
--- /dev/null
+++ b/test/functions.sh
@@ -0,0 +1,128 @@
+BTRFS_TESTS_VOLUMES="test1.img test2.img test3.img test4.img"
+TESTS_RUN=0
+TESTS_SUCCEEDED=0
+
+if [ -f .tests.conf ]; then
+ . .tests.conf
+fi
+
+function announce()
+{
+ echo --- $(basename $0) --- Testing "$@"
+}
+
+function summarise()
+{
+ echo === ${TESTS_RUN} tests run
+ echo === ${TESTS_SUCCEEDED} successes
+ echo === $((${TESTS_RUN}-${TESTS_SUCCEEDED})) failures
+}
+
+function catchclean()
+{
+ export SUITE=$(basename "$0" .sh)
+ rm -f ${SUITE}.out ${SUITE}.err
+ touch ${SUITE}.out ${SUITE}.err
+}
+
+# Internal function: set up/check the test volumes as requested
+function local_setup()
+{
+ # Set up for this test
+ VOLUMES=
+ for vol in $BTRFS_TESTS_VOLUMES; do
+ if [ ! -e $vol ]; then
+ dd if=/dev/zero of=$vol count=0 seek=4G bs=1 >/dev/null 2>&1 || return 1
+ fi
+ if [ -f $vol ]; then
+ vol=$(losetup -f --show $vol) || return 1
+ VOLUMES="$VOLUMES $vol"
+ elif [ -b $vol ]; then
+ VOLUMES="$VOLUMES $vol"
+ else
+ echo Don\'t know what to do with $vol
+ fi
+ done
+}
+
+# Internal function: destroy test volumes if we created them
+function local_teardown()
+{
+ for vol in $VOLUMES; do
+ if [ -b $vol ]; then
+ if losetup $vol >/dev/null 2>&1; then
+ file=$(losetup $vol | sed -e 's/^.* (\(.*\)).*$/\1/')
+ losetup -d $vol
+ rm $file
+ fi
+ fi
+ done
+ return 0
+}
+
+trap local_teardown EXIT
+
+function catch()
+{
+ TESTS_RUN=$((${TESTS_RUN}+1))
+
+ local_setup
+ if ! setup; then
+ teardown
+ local_teardown
+ return 1
+ fi
+
+ # Preemptively increase the success count: if we call fail, we'll
+ # decrease it again
+ TESTS_SUCCEEDED=$((${TESTS_SUCCEEDED}+1))
+
+ "$@" >>${SUITE}.out 2>>${SUITE}.err
+ rv=$?
+
+ # Undo any setup we did earlier
+ teardown
+ local_teardown
+
+ return ${rv}
+}
+
+function fail()
+{
+ echo "$@"
+ TESTS_SUCCEEDED=$((${TESTS_SUCCEEDED}-1))
+ summarise
+ exit 1
+}
+
+function setup()
+{
+ echo -n
+}
+
+function teardown()
+{
+ echo -n
+}
+
+function setup_mkfs()
+{
+ LABEL=$1
+ MNT=$2
+
+ mkdir -p $MNT
+ ./mkfs.btrfs -L $LABEL $VOLUMES >/dev/null || return 1
+ mount LABEL=$LABEL $MNT || return 1
+}
+
+function teardown_rmfs()
+{
+ MNT=$1
+
+ sleeptime=1
+ while ! umount $MNT 2>/dev/null; do
+ sleep ${sleeptime}
+ sleeptime=$((${sleeptime}+2))
+ done
+ rmdir $MNT
+}
diff --git a/test/run-tests b/test/run-tests
new file mode 100755
index 0000000..981fc22
--- /dev/null
+++ b/test/run-tests
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+testdir=$(dirname $0)
+
+if [ $UID -eq 0 ]; then
+ type=s
+else
+ type=u
+fi
+
+for test in ${testdir}/[0-9][0-9][0-9]${type}.sh; do
+ ${test}
+done
--
1.7.6.233.gd79bc

View File

@ -1,84 +0,0 @@
From 33be6f1695e8bd450be2e22fbf88b826488186a1 Mon Sep 17 00:00:00 2001
From: Hugo Mills <hugo@carfax.org.uk>
Date: Sun, 30 Oct 2011 20:17:07 +0000
Subject: [PATCH 07/35] Fix sub snap parameter handling
btrfs sub snap uses a local copy of optind, which causes the number of
parameters to be miscounted, preventing it from working properly. This
patch, originally from Arne Jansen <sensille@gmx.net>, fixes it.
Signed-off-by: Hugo Mills <hugo@carfax.org.uk>
---
btrfs_cmds.c | 23 ++++++++++++-----------
1 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index b59e9cb..9252ffa 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -304,7 +304,8 @@ int do_subvol_list(int argc, char **argv)
int ret;
int print_parent = 0;
char *subvol;
- int optind = 1;
+
+ optind = 1;
while(1) {
int c = getopt(argc, argv, "p");
@@ -312,7 +313,6 @@ int do_subvol_list(int argc, char **argv)
switch(c) {
case 'p':
print_parent = 1;
- optind++;
break;
}
}
@@ -347,11 +347,13 @@ int do_subvol_list(int argc, char **argv)
int do_clone(int argc, char **argv)
{
- char *subvol, *dst;
- int res, fd, fddst, len, e, optind = 0, readonly = 0;
- char *newname;
- char *dstdir;
- struct btrfs_ioctl_vol_args_v2 args;
+ char *subvol, *dst;
+ int res, fd, fddst, len, e, readonly = 0;
+ char *newname;
+ char *dstdir;
+ struct btrfs_ioctl_vol_args_v2 args;
+
+ optind = 1;
memset(&args, 0, sizeof(args));
@@ -362,7 +364,6 @@ int do_clone(int argc, char **argv)
break;
switch (c) {
case 'r':
- optind++;
readonly = 1;
break;
default:
@@ -372,14 +373,14 @@ int do_clone(int argc, char **argv)
return 1;
}
}
- if (argc - optind != 3) {
+ if (argc - optind != 2) {
fprintf(stderr, "Invalid arguments for subvolume snapshot\n");
free(argv);
return 1;
}
- subvol = argv[optind+1];
- dst = argv[optind+2];
+ subvol = argv[optind];
+ dst = argv[optind+1];
res = test_issubvolume(subvol);
if(res<0){
--
1.7.6.233.gd79bc

View File

@ -1,474 +0,0 @@
From 18254b66cf6ff7c9eff605ac7de9b4947d39a96f Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Sat, 16 Jul 2011 11:35:39 +0200
Subject: [PATCH 08/35] Add info for the commands.
Add info for every btrfs sub-commands in the sources.
---
btrfs_cmds.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
scrub.c | 79 +++++++++++++++++++
2 files changed, 316 insertions(+), 0 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 9252ffa..1bfc669 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -28,6 +28,7 @@
#include <limits.h>
#include <uuid/uuid.h>
#include <ctype.h>
+#include <getopt.h>
#undef ULONG_MAX
@@ -155,6 +156,42 @@ static int parse_compress_type(char *s)
};
}
+
+/**** man: btrfs filesystem defragment
+ *
+ * \Bbtrfs\b \Bfilesystem defragment\b -c[zlib|lzo] [-l \Ilen\i] [-s \Istart\i] [-t \Isize\i] -[vf] <\Ifile\i>|<\Idir\i> [<\Ifile\i>|<\Idir\i>...]
+ *
+ * Defragment a file or a directory.
+ *
+ * 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.
+ *
+ * The start position and the number of bytes to deframention can be specified
+ * by \Istart\i and \Ilen\i. Any extent bigger than \Ithresh\i will be
+ * considered already defragged. Use 0 to take the kernel default, and use 1
+ * to say eveery single extent must be rewritten. You can also turn on
+ * compression in defragment operations.
+ *
+ * \B-v\b be verbose
+ *
+ * \B-c\b compress file contents while defragmenting
+ *
+ * \B-f\b flush filesystem after defragmenting
+ *
+ * \B-s start\b defragment only from byte \Istart\i onward
+ *
+ * \B-l len\b defragment only up to \Ilen\i bytes
+ *
+ * \B-t size\b defragment only files at least \Isize\i 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
+ *
+ * \Bcp --reflink\b.
+ ****/
+
int do_defrag(int ac, char **av)
{
int fd;
@@ -267,6 +304,16 @@ int do_defrag(int ac, char **av)
return errors + 20;
}
+
+/**** man: btrfs subvolume find-new
+ *
+ * \Bbtrfs\b \Bsubvolume find-new\b\I <subvolume> <last_gen>\i
+ *
+ * List the recently modified files in a filesystem.
+ *
+ * List the recently modified files in a subvolume, after \I<last_gen>\i ID.
+ ****/
+
int do_find_newer(int argc, char **argv)
{
int fd;
@@ -298,6 +345,25 @@ int do_find_newer(int argc, char **argv)
return 0;
}
+
+/**** man: btrfs subvolume list
+ *
+ * \Bbtrfs\b \Bsubvolume list\b\I [-p] <path>\i
+ *
+ * List the snapshot/subvolume of a filesystem.
+ *
+ * List the subvolumes present in the filesystem \I<path>\i. For every
+ * subvolume the following information is shown by default.
+ * ID <ID> top level <ID> path <path>
+ * where path is the relative path of the subvolume to the \Itop level\i
+ * subvolume.
+ * The subvolume's ID may be used by the \Bsubvolume set-default\b command, or
+ * at mount time via the \Isubvol=\i option.
+ * If \I-p\i is given, then \Iparent <ID>\i is added to the output between ID
+ * and top level. The parent's ID may be used at mount time via the
+ * \Isubvolrootid=\i option.
+ ****/
+
int do_subvol_list(int argc, char **argv)
{
int fd;
@@ -345,6 +411,20 @@ int do_subvol_list(int argc, char **argv)
return 0;
}
+
+/**** man: btrfs subvolume snapshot
+ *
+ * \Bbtrfs\b \Bsubvolume snapshot\b\I [-r] <source> [<dest>/]<name>\i
+ *
+ * Create a writable/readonly snapshot of the subvolume <source> with
+ * the name <name> in the <dest> directory.
+ *
+ * Create a writable/readonly snapshot of the subvolume \I<source>\i with the
+ * name \I<name>\i in the \I<dest>\i directory. If \I<source>\i is not a
+ * subvolume, \Bbtrfs\b returns an error. If \I-r\i is given, the snapshot
+ * will be readonly.
+ ****/
+
int do_clone(int argc, char **argv)
{
char *subvol, *dst;
@@ -463,6 +543,17 @@ int do_clone(int argc, char **argv)
}
+
+/**** man: btrfs subvolume delete
+ *
+ * \Bbtrfs\b \Bsubvolume delete\b\I <subvolume>\i
+ *
+ * Delete the subvolume <subvolume>.
+ *
+ * Delete the subvolume \I<subvolume>\i. If \I<subvolume>\i is not a
+ * subvolume, \Bbtrfs\b returns an error.
+ ****/
+
int do_delete_subvolume(int argc, char **argv)
{
int res, fd, len, e;
@@ -525,6 +616,18 @@ int do_delete_subvolume(int argc, char **argv)
}
+
+/**** man: btrfs subvolume create
+ *
+ * \Bbtrfs\b \Bsubvolume create\b\I [<dest>/]<name>\i
+ *
+ * Create a subvolume in <dest> (or the current directory if
+ * not passed).
+ *
+ * Create a subvolume in \I<dest>\i (or in the current directory if
+ * \I<dest>\i is omitted).
+ ****/
+
int do_create_subvol(int argc, char **argv)
{
int res, fddst, len, e;
@@ -581,6 +684,16 @@ int do_create_subvol(int argc, char **argv)
}
+
+/**** man: btrfs filesystem sync
+ *
+ * \Bbtrfs\b \Bfilesystem sync\b\I <path> \i
+ *
+ * Force a sync on the filesystem <path>.
+ *
+ * Force a sync for the filesystem identified by \I<path>\i.
+ ****/
+
int do_fssync(int argc, char **argv)
{
int fd, res, e;
@@ -605,6 +718,21 @@ int do_fssync(int argc, char **argv)
return 0;
}
+
+/**** man: btrfs device scan
+ *
+ * \Bbtrfs\b \Bdevice scan\b \I[--all-devices|<device> [<device>...]\i
+ *
+ * Scan all device for or the passed device for a btrfs
+ * filesystem.
+ *
+ * If one or more devices are passed, these are scanned for a btrfs filesystem.
+ * If no devices are passed, \Bbtrfs\b scans all the block devices listed
+ * in the /proc/partitions file.
+ * Finally, if \B--all-devices\b is passed, all the devices under /dev are
+ * scanned.
+ ****/
+
int do_scan(int argc, char **argv)
{
int i, fd, e;
@@ -672,6 +800,32 @@ int do_scan(int argc, char **argv)
}
+
+/**** man: btrfs filesystem resize
+ *
+ * \Bbtrfs\b \Bfilesystem resize\b\I [+/\-]<size>[gkm]|max <path>\i
+ *
+ * Resize the file system. If 'max' is passed, the filesystem
+ * will occupe all available space on the device.
+ *
+ * Resize a filesystem identified by \I<path>\i.
+ * The \I<size>\i parameter specifies the new size of the filesystem.
+ * If the prefix \I+\i or \I\-\i is present the size is increased or decreased
+ * by the quantity \I<size>\i.
+ * If no units are specified, the unit of the \I<size>\i parameter defaults to
+ * bytes. Optionally, the size parameter may be suffixed by one of the following
+ * the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
+ * respectively.
+ *
+ * If 'max' is passed, the filesystem will occupy all available space on the
+ * volume(s).
+ *
+ * The \Bresize\b command \Bdoes not\b manipulate the size of underlying
+ * partition. If you wish to enlarge/reduce a filesystem, you must make sure
+ * you can expand the partition before enlarging the filesystem and shrink the
+ * partition after reducing the size of the filesystem.
+ ****/
+
int do_resize(int argc, char **argv)
{
@@ -762,6 +916,20 @@ static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
printf("\n");
}
+
+/**** man: btrfs filesystem show
+ *
+ * \Bbtrfs\b \Bfilesystem show\b [--all-devices|<uuid>|<label>]\b
+ *
+ * Show the info of a btrfs filesystem. If no argument
+ * is passed, info of all the btrfs filesystem are shown.
+ *
+ * Show the btrfs filesystem with some additional info. If no \IUUID\i or
+ * \Ilabel\i is passed, \Bbtrfs\b show info of all the btrfs filesystem.
+ * If \B--all-devices\b is passed, all the devices under /dev are scanned;
+ * otherwise the devices list is extracted from the /proc/partitions file.
+ ****/
+
int do_show_filesystem(int argc, char **argv)
{
struct list_head *all_uuids;
@@ -807,6 +975,16 @@ int do_show_filesystem(int argc, char **argv)
return 0;
}
+
+/**** man: btrfs device add
+ *
+ * \Bbtrfs\b \Bdevice add\b\I <dev> [<dev>..] <path>\i
+ *
+ * Add a device to a filesystem.
+ *
+ * Add device(s) to the filesystem identified by \I<path>\i.
+ ****/
+
int do_add_volume(int nargs, char **args)
{
@@ -889,6 +1067,15 @@ int do_add_volume(int nargs, char **args)
}
+/**** man: btrfs filesystem balance
+ *
+ * \Bbtrfs\b \Bfilesystem balance\b \I<path>\i
+ *
+ * Balance chunks across the devices.
+ *
+ * Balance chunks across the devices.
+ ****/
+
int do_balance(int argc, char **argv)
{
@@ -914,6 +1101,18 @@ int do_balance(int argc, char **argv)
}
return 0;
}
+
+
+
+/**** man: btrfs device delete
+ *
+ * \Bbtrfs\b \Bdevice delete\b\I <dev> [<dev>..] <path>\i
+ *
+ * Remove a device from a filesystem.
+ *
+ * Remove device(s) from a filesystem identified by \I<path>\i.
+ ****/
+
int do_remove_volume(int nargs, char **args)
{
@@ -947,6 +1146,19 @@ int do_remove_volume(int nargs, char **args)
return 0;
}
+
+/**** man: btrfs subvolume set-default
+ *
+ * \Bbtrfs\b \Bsubvolume set-default\b\I <id> <path>\i
+ *
+ * Set the subvolume of the filesystem <path> which will be mounted
+ * as default.
+ *
+ * Set the subvolume of the filesystem \I<path>\i which is mounted as
+ * \Idefault\i. The subvolume is identified by \I<id>\i, which
+ * is returned by the \Bsubvolume list\b command.
+ ****/
+
int do_set_default_subvol(int nargs, char **argv)
{
int ret=0, fd, e;
@@ -976,6 +1188,31 @@ int do_set_default_subvol(int nargs, char **argv)
return 0;
}
+
+/**** man: btrfs filesystem label
+ *
+ * \Bbtrfs\b \Bfilesystem label\b\I <dev> [newlabel]\i
+ *
+ * With one argument, get the label of filesystem on <device>.
+ * If <newlabel> is passed, set the filesystem label to <newlabel>.
+ * The filesystem must be unmounted.
+ *
+ * Show or update the label of a filesystem. \I<dev>\i is used to identify the
+ * filesystem.
+ * If a \Inewlabel\i optional argument is passed, the label is changed. The
+ * following costraints exist for a label:
+ * \t
+ * - the maximum allowable lenght shall be less or equal than 256 chars
+ * \t
+ * - the label shall not contain the '/' or '\\' characters.
+ *
+ * NOTE: Currently there are the following limitations:
+ * \t
+ * - the filesystem has to be unmounted
+ * \t
+ * - the filesystem should not have more than one device.
+ ****/
+
int do_change_label(int nargs, char **argv)
{
/* check the number of argument */
diff --git a/scrub.c b/scrub.c
index 9dca5f6..66761c5 100644
--- a/scrub.c
+++ b/scrub.c
@@ -1473,16 +1473,76 @@ out:
return 0;
}
+
+/**** man: btrfs scrub start
+ *
+ * \Bbtrfs\b \Bscrub start\b [-Bdqru] {\I<path>\i|\I<device>\i}
+ *
+ * Start a new scrub.
+ *
+ * Start a scrub on all devices of the filesystem identified by \I<path>\i or on
+ * a single \I<device>\i. Without options, scrub is started as a background
+ * process. Progress can be obtained with the \Bscrub status\b command.
+ * Scrubbing involves reading all data from all disks and verifying checksums.
+ * Errors are corrected along the way if possible.
+ * \w
+ *
+ * \IOptions\i
+ * \t -B 5
+ * Do not background and print scrub statistics when finished.
+ * \t -d 5
+ * Print separate statistics for each device of the filesystem (-B only).
+ * \t -q 5
+ * Quiet. Omit error messages and statistics.
+ * \t -r 5
+ * Read only mode. Do not attempt to correct anything.
+ * \t -u 5
+ * Scrub unused space as well. (NOT IMPLEMENTED)
+ * \q
+ ****/
+
int do_scrub_start(int argc, char **argv)
{
return scrub_start(argc, argv, 0);
}
+
+/**** man: btrfs scrub resume
+ *
+ * \Bbtrfs\b \Bscrub resume\b [-Bdqru] {\I<path>\i|\I<device>\i}
+ *
+ * Resume previously canceled or interrupted scrub.
+ *
+ * Resume a canceled or interrupted scrub cycle on the filesystem identified by
+ * \I<path>\i or on a given \I<device>\i. Does not start a new scrub if the
+ * last scrub finished successfully.
+ * \w
+ *
+ * \IOptions\i
+ * \p
+ * see \Bscrub start\b.
+ * \q
+ ****/
+
int do_scrub_resume(int argc, char **argv)
{
return scrub_start(argc, argv, 1);
}
+
+/**** man: btrfs scrub cancel
+ *
+ * \Bbtrfs\b \Bscrub cancel\b {\I<path>\i|\I<device>\i}
+ *
+ * Cancel a running scrub.
+ *
+ * If a scrub is running on the filesystem identified by \I<path>\i, cancel it.
+ * Progress is saved in the scrub progress file and scrubbing can be resumed later
+ * using the \Bscrub resume\b command.
+ * If a \I<device>\i is given, the corresponding filesystem is found and
+ * \Bscrub cancel\b behaves as if it was called on that filesystem.
+ ****/
+
int do_scrub_cancel(int argc, char **argv)
{
char *path = argv[1];
@@ -1528,6 +1588,25 @@ again:
return 0;
}
+
+/**** man: btrfs scrub status
+ *
+ * \Bbtrfs\b \Bscrub status\b [-d] {\I<path>\i|\I<device>\i}
+ *
+ * Show status of running or finished scrub.
+ *
+ * Show status of a running scrub for the filesystem identified by \I<path>\i or
+ * for the specified \I<device>\i.
+ * If no scrub is running, show statistics of the last finished or canceled scrub
+ * for that filesystem or device.
+ * \w
+ *
+ * \IOptions\i
+ * \t -d 5
+ * Print separate statistics for each device of the filesystem.
+ * \q
+ ****/
+
int do_scrub_status(int argc, char **argv)
{
--
1.7.6.233.gd79bc

View File

@ -1,202 +0,0 @@
From aa8bba1e2c99eb895c7e43f5092e4bf56d68d9c5 Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Sat, 16 Jul 2011 11:11:08 +0200
Subject: [PATCH 09/35] Add the header/footer/introduction of the man page.
Add the header/footer/introduction of the man page. There is also an
introduction to the syntax recognized by the tool helpextract to format
the information.
---
btrfs.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 176 insertions(+), 0 deletions(-)
diff --git a/btrfs.c b/btrfs.c
index 1def354..d2f6d4d 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -26,6 +26,182 @@
#define BASIC_HELP 0
#define ADVANCED_HELP 1
+/**
+ ** The comments below are used to make the man page
+ **
+ ** There are:
+ ** - Header,
+ ** - The synopsis title section (the content are extracted from other
+ ** comments)
+ ** - The synopsis format, which is a template: the '%s' is replaced by
+ ** the command line "syntax"
+ ** - The btrfs introduction section
+ ** - The btfrs command title section (the content are extracted from other
+ ** comments)
+ ** - The command format, which is a template: the first '%s' is replaced by
+ ** the command line "syntax"; the ssecond '%s' is replaced by the
+ ** detailed descritpion
+ ** - The "notes" section
+ ** - The footer (currentli empty)
+ **
+ ** The comments are the following sytax [replace '{slash}' with '/']
+ **
+ ** If the comment starts with '{slash}**** text: ', then all the text below
+ ** are used until ' ***'. The text after 'text: ' are the key used to
+ ** index teh content.
+ **
+ ** If the comment starts with '{slash}**** man: ', then below the comment are
+ ** divided in three section:
+ ** 1) (one line) command line syntax
+ ** 2) (multiple line) short description (showed in the command "btrfs help")
+ ** 3) (multiple line) detailled description (showed in the man page and
+ ** command "btrfs <subcommand> --help")
+ ** The text after 'man: ' are the key used to index the content. This must
+ ** be equal to the subcommand which the info is referred.
+ **
+ ** Below the escape sequence which may be used in the text
+ **
+ ** escape troff
+ ** sequence command
+ **
+ ** \B \fB bold
+ ** \b \fP end bold
+ ** \I \fI italic
+ ** \i \fP end italic
+ ** \c .\" comment
+ ** \P .PP start paragraph
+ ** \p .TP indented paragraph
+ ** \h .SH header
+ ** \d .BR bold regular
+ ** \e .B bold
+ ** \t .IP indented paragraph
+ ** \w .RS move the left margin
+ ** \q .RE move the left margin back
+ ** \- \- minus (it *must* escaped )
+ **
+ **
+ **/
+
+
+/**** text: man btrfs header
+ * .TH BTRFS 8 "" "btrfs" "btrfs"
+ * .\"
+ * .\" Man page for the "btrfs" tool
+ * .\"
+ * .SH NAME
+ * btrfs \- control a btrfs filesystem
+ ****/
+
+/**** text: man btrfs synopsis
+ * .SH SYNOPSIS
+ ****/
+
+/**** text: man btrfs synopsis format
+ * \fB%s\fP
+ * .PP
+ ****/
+
+/**** text: btrfs introduction
+ * \h DESCRIPTION
+ * \Bbtrfs\b is used to control the filesystem and the files and directories
+ * stored. It is the tool to create or destroy a snapshot or a subvolume for
+ * the filesystem, to defrag a file or a directory, flush the data to the disk,
+ * to resize the filesystem, to scan the device.
+ *
+ * It is possible to abbreviate the commands unless the commands are ambiguous.
+ * For example: it is possible to run
+ * \Ibtrfs sub snaps\i instead of \Ibtrfs subvolume snapshot\i. But \Ibtrfs
+ * file s\i is not allowed, because \Ifile s\i may be interpreted both as
+ * \Ifilesystem show\i and as \Ifilesystem sync\i.
+ *
+ * If a command is terminated by \I--help\i, the detailed help is showed.
+ * If the passed command matches more commands, detailed help of all the
+ * matched commands is showed. For example \Ibtrfs dev --help\i shows the
+ * help of all \Idevice*\i commands.
+ ****/
+
+/**** text: man btrfs command format
+ *
+ * .TP
+ * %s%s
+ ****/
+
+/**** text: man btrfs commands
+ * .SH COMMANDS
+ * .TP
+ */
+
+/**** text: btrfs notes
+ * \h BALANCE FILTERS
+ *
+ * With balance filters, it is possible to perform a balance operation on
+ * only a subset of the available chunks. Filters are specified with the
+ * \B--filter\b option of \Bbtrfs filesystem balance\b or \Bbtrfs
+ * balance start\b. Multiple filters may be given, either with multiple
+ * \B--filter\b options, or in a colon-separated list. When multiple
+ * filters are given, only the chunks meeting all of the selection
+ * critera are balanced. Help on the avaialble filters can be obtained
+ * with \B--filter=help\b.
+ *
+ *
+ * \Btype\b=[\B~\b]\I<flagname>\i[\B,\b...]
+ *
+ * Select only the chunks with the given type flag(s). Requiring a flag
+ * to be off can be specified with a \B~\b preceding the flag
+ * name. Flag names are:
+ *
+ * \Bmeta\b, \Bdata\b, \Bsys\b for metadata, file data and system
+ * chunk types.
+ *
+ * \Braid0\b, \Braid1\b, \Braid10\b, \Bdup\b for chunks of the
+ * given replication levels.
+ *
+ *
+ * \Bdevid\b=\I<n>\i
+ *
+ * Select chunks which have data on device ID \I<n>\i. This can be
+ * used, for example, to reduplicate data in a mirrored configuration
+ * where one drive has been lost due to hardware failure.
+ *
+ *
+ * \Bvrange\b=\I<start>\i,\I<end>\i
+ *
+ * Select chunks which have btrfs-internal virtual addresses within the
+ * range \I<start>\i (inclusive) to \I<end>\i (exclusive). Given the
+ * address of the last chunk moved, this filter can be used to restart a
+ * cancelled or interrupted balance operation, by supplying a range of
+ * \I0,<chunkaddr+1>\i.
+ *
+ * \Bdrange\b=\I<start>\i,\I<end>\i
+ *
+ * Select chunks which contain data in the address range \I<start>\i
+ * (inclusive) to \I<end>\i (exclusive) on \Iany\i block device in
+ * the filesystem. Can be mixed with the \Bdevid\b filter to select
+ * chunks in a given address range on a specific device.
+ *
+ * \h EXIT STATUS
+ * \Bbtrfs\b returns a zero exist status if it succeeds. Non zero is returned in
+ * case of failure.
+ *
+ * \h AVAILABILITY
+ * \Bbtrfs\b is part of btrfs-progs. Btrfs filesystem is currently under
+ * heavy development, and not suitable for any uses other than benchmarking and
+ * review.
+ *
+ * Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for
+ * further details.
+ *
+ * \h SEE ALSO
+ * \Bmkfs.btrfs (8)\b
+ ****/
+
+/**** text: man btrfs footer
+ ****/
+
+
+
+
+
typedef int (*CommandFunction)(int argc, char **argv);
struct Command {
--
1.7.6.233.gd79bc

View File

@ -1,458 +0,0 @@
From e1825e850af190793dadf5ca78f36f394bae9e86 Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Sat, 16 Jul 2011 10:55:30 +0200
Subject: [PATCH 10/35] helpextract: tool to extract the info for the help
from the source.
It is created the file helpextract.c, which is the source for the tool
"helpextract". This program extract the info showed in the man page and
the help command from the sources comments.
---
helpextract.c | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 435 insertions(+), 0 deletions(-)
create mode 100644 helpextract.c
diff --git a/helpextract.c b/helpextract.c
new file mode 100644
index 0000000..9489ea0
--- /dev/null
+++ b/helpextract.c
@@ -0,0 +1,435 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PREFIX_MAN "/**** man: "
+#define PREFIX_TEXT "/**** text: "
+#define PREFIX_END " ****"
+#define PREFIX_SKIP " * "
+
+#define LINEBUF 1024
+
+char **msgs=0;
+int nmsg=0;
+
+static char *xstrdup(char *str){
+ char *new = strdup(str);
+ if(!new){
+ fprintf(stderr,"*** Memory allocation fail ! (xstrdup)\n");
+ exit(101);
+ }
+ return new;
+}
+
+static void *xrealloc(void *ptr, int newsize){
+ void *new = realloc(ptr, newsize);
+ if(!new){
+ fprintf(stderr,"*** Memory allocation fail ! (xrealloc)\n");
+ exit(101);
+ }
+ return new;
+
+
+}
+
+static char *xstrip(char *s){
+
+ char *last=NULL;
+ char *first;
+
+ while(*s && isspace(*s) ) s++;
+
+ first=s;
+
+ while(*s){
+ if(isspace(*s)) last=s;
+ s++;
+ }
+
+ if(last) *last=0;
+ return first;
+
+
+}
+
+static void addtuple(char *key, char *cmdline, char *short_help,
+ char *long_help){
+
+ msgs = (char**)xrealloc(msgs, sizeof(char *)*(nmsg+1)*4);
+
+ key = xstrip(key);
+
+ if( !long_help || !strcmp(long_help,"\n"))
+ long_help = short_help;
+ else if(!short_help || !strcmp(short_help, "\n"))
+ short_help = long_help;
+
+ msgs[nmsg*4] = key;
+ msgs[nmsg*4+1] = cmdline;
+ msgs[nmsg*4+2] = short_help;
+ msgs[nmsg*4+3] = long_help;
+ nmsg++;
+}
+
+
+static int search_in_file(char *nf){
+ char buf[LINEBUF+1];
+ FILE *fp;
+ int status;
+ char *key=NULL;
+ char *cmdline=NULL;
+ char *short_help=NULL;
+ char *long_help=NULL;
+
+ fp = fopen(nf,"r");
+ if(!fp){
+ int e=errno;
+ fprintf(stderr, "*** Cannot open '%s'; error = %d - '%s'\n",
+ nf, e, strerror(e));
+ return -1;
+ }
+
+ status = 0;
+ while(fgets(buf,LINEBUF,fp)){
+ // printf("status = %d, buf=%s",status, buf);
+
+ if(status == 0){
+ if(!strncmp(buf,PREFIX_MAN, strlen(PREFIX_MAN)) ){
+ key = xstrdup(buf+strlen(PREFIX_MAN));
+ status++;
+ }else if(!strncmp(buf,PREFIX_TEXT,
+ strlen(PREFIX_TEXT))){
+ key = xstrdup(buf+strlen(PREFIX_TEXT));
+ status=5;
+ }
+ continue;
+
+ }
+
+ if( !strncmp(buf,PREFIX_END, strlen(PREFIX_END)) ||
+ strncmp(buf, PREFIX_SKIP,2)){
+
+ addtuple(key, cmdline, short_help, long_help);
+ key = cmdline = short_help = long_help = 0;
+ status = 0;
+
+ continue;
+ }
+ if( status == 2){
+ if(strlen(buf)>strlen(PREFIX_SKIP))
+ cmdline = xstrdup(buf+strlen(PREFIX_SKIP));
+ status++;
+ continue;
+ }
+ if( status == 4){
+ int len;
+ int len2;
+ char *p;
+
+ if(strlen(buf)<=strlen(PREFIX_SKIP)){
+ status++;
+ continue;
+ }
+ p=buf+3;
+ while(isspace(*p) && *p ) p++;
+ if(!*p){
+ status++;
+ continue;
+ }
+
+ len2 = strlen(buf)-strlen(PREFIX_SKIP);
+
+ if(short_help)
+ len = strlen(short_help);
+ else
+ len = 0;
+ short_help = (char*)xrealloc(short_help, len+len2+1);
+ strcpy(short_help+len,buf+strlen(PREFIX_SKIP));
+ continue;
+ }
+ if( status == 5){
+ int len;
+ int len2 = strlen(buf)-strlen(PREFIX_SKIP);
+
+ if(long_help)
+ len = strlen(long_help);
+ else
+ len = 0;
+ long_help = (char*)xrealloc(long_help, len+len2+1);
+ strcpy(long_help+len,buf+strlen(PREFIX_SKIP));
+ continue;
+ }
+ if( status == 1 || status == 3 ){
+ status++;
+ continue;
+ }
+
+ fprintf(stderr,"*** Internal error: status = %d\n",status);
+ exit(100);
+
+ }
+
+ if( status != 0 ){
+ fprintf(stderr,"*** Parse error: file = '%s', "
+ "status = %d at the end of file\n",
+ nf, status);
+ exit(100);
+
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+/* remove all the escape sequence excepet \\ */
+static char * my_escape(char *src, char *filters[] ){
+
+ static char buffer[LINEBUF*5];
+
+ int i=0;
+ while(*src){
+ int j;
+ int next_char = *(src+1);
+ if(*src != '\\'){
+ buffer[i++]=*src++;
+ continue;
+ }
+ if(!next_char){
+ buffer[i++]=*src++;
+ continue;
+ }
+ if( !filters ){
+ src +=2;
+ continue;
+ }
+
+ j=0;
+ while(filters[j]){
+ if(filters[j][0] == next_char ){
+ strcpy(buffer+i, filters[j]+2);
+ i+=strlen(filters[j]+2);
+ break;
+ }
+ j++;
+ }
+ if(!filters[j]){
+ char *p=src;
+ int l=40;
+ fprintf(stderr,
+ "Unknow escape sequence '\%c' in [\"",
+ next_char);
+ while(*p && l--) fputc(*p++, stderr);
+ fprintf(stderr, "\"...]\n");
+ }
+ src += 2;
+
+ }
+
+ buffer[i]=0;
+ return buffer;
+
+}
+
+static char * escape_c_array(char *src ){
+ static char *filters[]={
+
+ /* remove the all know esc-sequence */
+
+ "B ", /* bold */
+ "b ", /* end bold */
+ "I ", /* italic */
+ "i ", /* end italic */
+ "c ", /* comment */
+ "P ", /* start paragraph */
+ "p ", /* indented paragraph */
+ "h ", /* header */
+ "d ", /* bold regular */
+ "e ", /* bold */
+ "t ", /* indented paragraph */
+ "w ", /* move the left margin */
+ "q ", /* move the left margin back */
+
+ "\\ \\\\",
+ "- -",
+
+ 0
+ };
+
+ return my_escape(src, filters);
+}
+
+static char *escape_man_page(char *src){
+ /* from Gnu troff manual */
+ static char *filters[]={
+ "B \\fB", /* bold */
+ "b \\fP", /* end bold */
+ "I \\fI", /* italic */
+ "i \\fP", /* end italic */
+ "c .\\\"", /* comment */
+ "P .PP", /* start paragraph */
+ "p .TP", /* indented paragraph */
+ "h .SH", /* header */
+ "d .BR", /* bold regular */
+ "e .B", /* bold */
+ "t .IP", /* indented paragraph */
+ "w .RS", /* move the left margin */
+ "q .RE", /* move the left margin back */
+
+ "- \\-", /* escape the minus sign */
+ "\\ \\",
+
+ 0
+ };
+
+ return my_escape(src, filters);
+}
+
+
+static void dump_c_array(){
+
+ int i;
+
+ printf("{");
+ for(i=0; i < nmsg*4 ; i++){
+ char *c = msgs[i];
+ int begin;
+
+ if(!(i%4) && strncmp(c,"btrfs ",5)){
+ i+=3;
+ continue;
+ }
+
+ if(i>0){
+ putchar(',');
+ if(!(i%4)) putchar('\n');
+ }
+
+ if(!c){
+ printf("\n NULL");
+ continue;
+ }
+
+ c = escape_c_array(c);
+
+ begin = 1;
+ while( *c ){
+ if(begin)
+ printf("\n \"");
+ begin = 0;
+ if( *c == '\n' ){
+ printf("\\n\"");
+ begin = 1;
+ }else if( *c == '"' ){
+ printf("\\\"");
+ }else{
+ putchar(*c);
+ }
+
+ c++;
+ }
+ if(!begin) putchar('"');
+ }
+ printf(",\n\n ");
+ for(i=0; i < 4; i++){
+ if(i>0) putchar(',');
+ printf("NULL");
+ }
+ printf("\n}\n");
+
+}
+
+static int my_sort_cmp(const void *p1, const void *p2){
+ return strcmp(*(char**)p1, *(char **)p2);
+}
+
+static void my_sort(){
+ qsort(msgs, nmsg, sizeof(char*)*4, my_sort_cmp);
+}
+
+static int find_section(char *key){
+ int i;
+ for(i = 0 ; i < nmsg ; i++ )
+ if(!strcmp( msgs[i*4],key) ) return i;
+
+ return -1;
+}
+
+static void dump_man_page(){
+
+ int i, fmt;
+
+ i = find_section("man btrfs header");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ i = find_section("man btrfs synopsis");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ fmt = find_section("man btrfs synopsis format");
+ for(i = 0; i < nmsg && fmt>=0; i++ ){
+ if( strncmp("btrfs ",msgs[i*4], 6) ||
+ !strcmp("btrfs introduction", msgs[i*4] ) ||
+ !strcmp("btrfs notes", msgs[i*4] ) )
+ continue;
+
+ printf(msgs[fmt*4+3], escape_man_page(msgs[i*4+1]));
+ }
+
+ i = find_section("btrfs introduction");
+ if( i>= 0 ) printf(escape_man_page(msgs[i*4+3]));
+
+ i = find_section("man btrfs commands");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ fmt = find_section("man btrfs command format");
+ for(i = 0; i < nmsg && fmt>=0; i++ ){
+
+ char big2[LINEBUF*5];
+ if( strncmp("btrfs ",msgs[i*4], 6) ||
+ !strcmp("btrfs introduction", msgs[i*4] ) ||
+ !strcmp("btrfs notes", msgs[i*4] ) )
+ continue;
+
+ strcpy(big2, escape_man_page(msgs[i*4+3]));
+ printf(msgs[fmt*4+3], escape_man_page(msgs[i*4+1]), big2);
+
+ }
+
+ i = find_section("man btrfs notes");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ i = find_section("btrfs notes");
+ if( i>= 0 ) printf(escape_man_page(msgs[i*4+3]));
+
+ i = find_section("man btrfs footer");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+}
+
+static void usage(char *np){
+ printf("usage: %s --man-page|--c-array <file> [<file> [...]]\n", np);
+}
+
+int main(int argc, char **argv ){
+
+ int i;
+ if( argc < 3 || ( strcmp(argv[1],"--man-page") &&
+ strcmp(argv[1],"--c-array") )){
+ usage(argv[0]);
+ return 0;
+ }
+
+ for(i=2; i < argc ; i++)
+ search_in_file(argv[i]);
+
+ my_sort();
+
+ if(!strcmp(argv[1], "--man-page"))
+ dump_man_page();
+ else if (!strcmp(argv[1], "--c-array"))
+ dump_c_array();
+
+ return 0;
+
+}
--
1.7.6.233.gd79bc

View File

@ -1,710 +0,0 @@
From e93b09f73b0914d8e0b8c2c78b6a1a8ebefa151c Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Sat, 16 Jul 2011 11:03:14 +0200
Subject: [PATCH 11/35] Update the makefile for generating the man page.
The makefile is update in order to generate the man/btrfs.8.in by the
helpextract tool on the basis of the sources comments. The old man page
is renamed as btrfs.8.in.old.
---
Makefile | 11 ++-
man/btrfs.8.in | 322 ----------------------------------------------------
man/btrfs.8.in.old | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 332 insertions(+), 323 deletions(-)
delete mode 100644 man/btrfs.8.in
create mode 100644 man/btrfs.8.in.old
diff --git a/Makefile b/Makefile
index 5f25d66..b673100 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,8 @@ RESTORE_LIBS=-lz
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block
+btrfs_man_page_source = btrfs.c btrfs_cmds.c scrub.c
+
# make C=1 to enable sparse
ifdef C
check = sparse $(CHECKFLAGS)
@@ -97,13 +99,20 @@ convert: $(objects) convert.o
ioctl-test: $(objects) ioctl-test.o
$(CC) $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
-manpages:
+helpextract: helpextract.o
+ $(CC) $(CFLAGS) -o $@ helpextract.o
+
+man/btrfs.8.in: helpextract $(btrfs_man_page_source)
+ ./helpextract --man-page $(btrfs_man_page_source) >$@
+
+manpages: man/btrfs.8.in
cd man; make
install-man:
cd man; make install
clean :
+ rm -f man/btrfs.8.in
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
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
deleted file mode 100644
index be478e0..0000000
--- a/man/btrfs.8.in
+++ /dev/null
@@ -1,322 +0,0 @@
-.TH BTRFS 8 "" "btrfs" "btrfs"
-.\"
-.\" Man page written by Goffredo Baroncelli <kreijack@inwind.it> (Feb 2010)
-.\"
-.SH NAME
-btrfs \- control a btrfs filesystem
-.SH SYNOPSIS
-\fBbtrfs\fP \fBsubvolume snapshot\fP\fI [-r] <source> [<dest>/]<name>\fP
-.PP
-\fBbtrfs\fP \fBsubvolume delete\fP\fI <subvolume>\fP
-.PP
-\fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP
-.PP
-\fBbtrfs\fP \fBsubvolume list\fP\fI [-p] <path>\fP
-.PP
-\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
-.PP
-\fBbtrfs\fP \fBsubvolume get-default\fP\fI <path>\fP
-.PP
-\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
-.PP
-\fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
-.PP
-\fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
-.PP
-\fBbtrfs\fP \fBfilesystem defrag\fP\fI [options] <file>|<dir> [<file>|<dir>...]\fP
-.PP
-\fBbtrfs\fP \fBsubvolume find-new\fP\fI <subvolume> <last_gen>\fP
-.PP
-\fBbtrfs\fP \fBfilesystem balance\fP\fI <path> \fP
-.PP
-\fBbtrfs\fP \fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fP
-.PP
-\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
-.PP
-\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
-.PP
-\fBbtrfs\fP \fBdevice add\fP\fI <device> [<device>...] <path> \fP
-.PP
-\fBbtrfs\fP \fBdevice delete\fP\fI <device> [<device>...] <path> \fP
-.PP
-\fBbtrfs\fP \fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
-.PP
-\fBbtrfs\fP \fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
-.PP
-\fBbtrfs\fP \fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
-.PP
-\fBbtrfs\fP \fBscrub status\fP [-d] {\fI<path>\fP|\fI<device>\fP}
-.PP
-\fBbtrfs\fP \fBinspect-internal inode-resolve\fP [-v] \fI<inode>\fP \fI<path>\fP
-.PP
-\fBbtrfs\fP \fBinspect-internal logical-resolve\fP
-[-Pv] \fI<logical>\fP \fI<path>\fP
-.PP
-\fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP
-.PP
-\fBbtrfs\fP \fB<command> \-\-help \fP\fI\fP
-.PP
-.SH DESCRIPTION
-.B btrfs
-is used to control the filesystem and the files and directories stored. It is
-the tool to create or destroy a snapshot or a subvolume for the
-filesystem, to defrag a file or a directory, flush the data to the disk,
-to resize the filesystem, to scan the device.
-
-It is possible to abbreviate the commands unless the commands are ambiguous.
-For example: it is possible to run
-.I btrfs sub snaps
-instead of
-.I btrfs subvolume snapshot.
-But
-.I btrfs file s
-is not allowed, because
-.I file s
-may be interpreted both as
-.I filesystem show
-and as
-.I filesystem sync.
-In this case
-.I btrfs
-returnsfilesystem sync
-If a command is terminated by
-.I --help
-, 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*
-commands.
-
-.SH COMMANDS
-.TP
-
-\fBsubvolume snapshot\fR\fI [-r] <source> [<dest>/]<name>\fR
-Create a writable/readonly snapshot of the subvolume \fI<source>\fR with the
-name \fI<name>\fR in the \fI<dest>\fR directory. If \fI<source>\fR is not a
-subvolume, \fBbtrfs\fR returns an error. If \fI-r\fR is given, the snapshot
-will be readonly.
-.TP
-
-\fBsubvolume delete\fR\fI <subvolume>\fR
-Delete the subvolume \fI<subvolume>\fR. If \fI<subvolume>\fR is not a
-subvolume, \fBbtrfs\fR returns an error.
-.TP
-
-\fBsubvolume create\fR\fI [<dest>/]<name>\fR
-Create a subvolume in \fI<dest>\fR (or in the current directory if
-\fI<dest>\fR is omitted).
-.TP
-
-\fBsubvolume list\fR\fI [-p] <path>\fR
-List the subvolumes present in the filesystem \fI<path>\fR. For every
-subvolume the following information is shown by default.
-ID <ID> top level <ID> path <path>
-where path is the relative path of the subvolume to the \fItop level\fR
-subvolume.
-The subvolume's ID may be used by the \fBsubvolume set-default\fR command, or
-at mount time via the \fIsubvol=\fR option.
-If \fI-p\fR is given, then \fIparent <ID>\fR is added to the output between ID
-and top level. The parent's ID may be used at mount time via the
-\fIsubvolrootid=\fR option.
-.TP
-
-\fBsubvolume set-default\fR\fI <id> <path>\fR
-Set the subvolume of the filesystem \fI<path>\fR which is mounted as
-\fIdefault\fR. The subvolume is identified by \fI<id>\fR, which
-is returned by the \fBsubvolume list\fR command.
-.TP
-
-\fBsubvolume get-default\fR\fI <path>\fR
-Get the default subvolume of the filesystem \fI<path>\fR. The output format
-is similar to \fBsubvolume list\fR command.
-.TP
-
-\fBfilesystem defragment\fP -c[zlib|lzo] [-l \fIlen\fR] [-s \fIstart\fR] [-t \fIsize\fR] -[vf] <\fIfile\fR>|<\fIdir\fR> [<\fIfile\fR>|<\fIdir\fR>...]
-
-Defragment file data and/or directory metadata. To defragment all files in a
-directory you have to specify each one on its own or use your shell wildcards.
-
-The start position and the number of bytes to deframention can be specified by \fIstart\fR and \fIlen\fR. Any extent bigger than \fIthresh\fR will be considered already defragged. Use 0 to take the kernel default, and use 1 to say eveery single extent must be rewritten. You can also turn on compression in defragment operations.
-
-\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.
-\fBsubvolume find-new\fR\fI <subvolume> <last_gen>\fR
-List the recently modified files in a subvolume, after \fI<last_gen>\fR ID.
-.TP
-
-\fBfilesystem sync\fR\fI <path> \fR
-Force a sync for the filesystem identified by \fI<path>\fR.
-.TP
-
-.\"
-.\" Some wording are extracted by the resize2fs man page
-.\"
-
-\fBfilesystem resize\fR\fI [+/\-]<size>[gkm]|max <path>\fR
-Resize a filesystem identified by \fI<path>\fR.
-The \fI<size>\fR parameter specifies the new size of the filesystem.
-If the prefix \fI+\fR or \fI\-\fR is present the size is increased or decreased
-by the quantity \fI<size>\fR.
-If no units are specified, the unit of the \fI<size>\fR parameter defaults to
-bytes. Optionally, the size parameter may be suffixed by one of the following
-the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
-respectively.
-
-If 'max' is passed, the filesystem will occupy all available space on the
-volume(s).
-
-The \fBresize\fR command \fBdoes not\fR manipulate the size of underlying
-partition. If you wish to enlarge/reduce a filesystem, you must make sure you
-can expand the partition before enlarging the filesystem and shrink the
-partition after reducing the size of the filesystem.
-.TP
-
-\fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
-Show or update the label of a filesystem. \fI<dev>\fR is used to identify the
-filesystem.
-If a \fInewlabel\fR optional argument is passed, the label is changed. The
-following costraints exist for a label:
-.IP
-- the maximum allowable lenght shall be less or equal than 256 chars
-.IP
-- the label shall not contain the '/' or '\\' characters.
-
-NOTE: Currently there are the following limitations:
-.IP
-- the filesystem has to be unmounted
-.IP
-- the filesystem should not have more than one device.
-.TP
-
-\fBfilesystem show\fR [--all-devices|<uuid>|<label>]\fR
-Show the btrfs filesystem with some additional info. If no \fIUUID\fP or
-\fIlabel\fP is passed, \fBbtrfs\fR show info of all the btrfs filesystem.
-If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
-otherwise the devices list is extracted from the /proc/partitions file.
-.TP
-
-\fBdevice balance\fR \fI<path>\fR
-Balance the chunks of the filesystem identified by \fI<path>\fR
-across the devices.
-.TP
-
-\fBdevice add\fR\fI <dev> [<dev>..] <path>\fR
-Add device(s) to the filesystem identified by \fI<path>\fR.
-.TP
-
-\fBdevice delete\fR\fI <dev> [<dev>..] <path>\fR
-Remove device(s) from a filesystem identified by \fI<path>\fR.
-.TP
-
-\fBdevice scan\fR \fI[--all-devices|<device> [<device>...]\fR
-If one or more devices are passed, these are scanned for a btrfs filesystem.
-If no devices are passed, \fBbtrfs\fR scans all the block devices listed
-in the /proc/partitions file.
-Finally, if \fB--all-devices\fP is passed, all the devices under /dev are
-scanned.
-.TP
-
-\fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
-Start a scrub on all devices of the filesystem identified by \fI<path>\fR or on
-a single \fI<device>\fR. Without options, scrub is started as a background
-process. Progress can be obtained with the \fBscrub status\fR command. Scrubbing
-involves reading all data from all disks and verifying checksums. Errors are
-corrected along the way if possible.
-.RS
-
-\fIOptions\fR
-.IP -B 5
-Do not background and print scrub statistics when finished.
-.IP -d 5
-Print separate statistics for each device of the filesystem (-B only).
-.IP -q 5
-Quiet. Omit error messages and statistics.
-.IP -r 5
-Read only mode. Do not attempt to correct anything.
-.IP -u 5
-Scrub unused space as well. (NOT IMPLEMENTED)
-.RE
-.TP
-
-\fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
-If a scrub is running on the filesystem identified by \fI<path>\fR, cancel it.
-Progress is saved in the scrub progress file and scrubbing can be resumed later
-using the \fBscrub resume\fR command.
-If a \fI<device>\fR is given, the corresponding filesystem is found and
-\fBscrub cancel\fP behaves as if it was called on that filesystem.
-.TP
-
-\fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
-Resume a canceled or interrupted scrub cycle on the filesystem identified by
-\fI<path>\fR or on a given \fI<device>\fR. Does not start a new scrub if the
-last scrub finished successfully.
-.RS
-
-\fIOptions\fR
-.TP
-see \fBscrub start\fP.
-.RE
-.TP
-
-\fBscrub status\fP [-d] {\fI<path>\fP|\fI<device>\fP}
-Show status of a running scrub for the filesystem identified by \fI<path>\fR or
-for the specified \fI<device>\fR.
-If no scrub is running, show statistics of the last finished or canceled scrub
-for that filesystem or device.
-.RS
-
-\fIOptions\fR
-.IP -d 5
-Print separate statistics for each device of the filesystem.
-.RE
-.TP
-
-\fBinspect-internal inode-resolve\fP [-v] \fI<inode>\fP \fI<path>\fP
-Resolves an <inode> in subvolume <path> to all filesystem paths.
-.RS
-
-\fIOptions\fR
-.IP -v 5
-verbose mode. print count of returned paths and ioctl() return value
-.RE
-.TP
-
-\fBinspect-internal logical-resolve\fP [-Pv] \fI<logical>\fP \fI<path>\fP
-Resolves a <logical> address in the filesystem mounted at <path> to all inodes.
-By default, each inode is then resolved to a file system path (similar to the
-\fBinode-resolve\fP subcommand).
-.RS
-
-\fIOptions\fR
-.IP -P 5
-skip the path resolving and print the inodes instead
-.IP -v 5
-verbose mode. print count of returned paths and all ioctl() return values
-.RE
-
-.SH EXIT STATUS
-\fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned in
-case of failure.
-
-.SH AVAILABILITY
-.B btrfs
-is part of btrfs-progs. Btrfs filesystem is currently under heavy development,
-and not suitable for any uses other than benchmarking and review.
-Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for
-further details.
-.SH SEE ALSO
-.BR mkfs.btrfs (8)
diff --git a/man/btrfs.8.in.old b/man/btrfs.8.in.old
new file mode 100644
index 0000000..be478e0
--- /dev/null
+++ b/man/btrfs.8.in.old
@@ -0,0 +1,322 @@
+.TH BTRFS 8 "" "btrfs" "btrfs"
+.\"
+.\" Man page written by Goffredo Baroncelli <kreijack@inwind.it> (Feb 2010)
+.\"
+.SH NAME
+btrfs \- control a btrfs filesystem
+.SH SYNOPSIS
+\fBbtrfs\fP \fBsubvolume snapshot\fP\fI [-r] <source> [<dest>/]<name>\fP
+.PP
+\fBbtrfs\fP \fBsubvolume delete\fP\fI <subvolume>\fP
+.PP
+\fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP
+.PP
+\fBbtrfs\fP \fBsubvolume list\fP\fI [-p] <path>\fP
+.PP
+\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
+.PP
+\fBbtrfs\fP \fBsubvolume get-default\fP\fI <path>\fP
+.PP
+\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
+.PP
+\fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
+.PP
+\fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
+.PP
+\fBbtrfs\fP \fBfilesystem defrag\fP\fI [options] <file>|<dir> [<file>|<dir>...]\fP
+.PP
+\fBbtrfs\fP \fBsubvolume find-new\fP\fI <subvolume> <last_gen>\fP
+.PP
+\fBbtrfs\fP \fBfilesystem balance\fP\fI <path> \fP
+.PP
+\fBbtrfs\fP \fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fP
+.PP
+\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
+.PP
+\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
+.PP
+\fBbtrfs\fP \fBdevice add\fP\fI <device> [<device>...] <path> \fP
+.PP
+\fBbtrfs\fP \fBdevice delete\fP\fI <device> [<device>...] <path> \fP
+.PP
+\fBbtrfs\fP \fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+.PP
+\fBbtrfs\fP \fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
+.PP
+\fBbtrfs\fP \fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+.PP
+\fBbtrfs\fP \fBscrub status\fP [-d] {\fI<path>\fP|\fI<device>\fP}
+.PP
+\fBbtrfs\fP \fBinspect-internal inode-resolve\fP [-v] \fI<inode>\fP \fI<path>\fP
+.PP
+\fBbtrfs\fP \fBinspect-internal logical-resolve\fP
+[-Pv] \fI<logical>\fP \fI<path>\fP
+.PP
+\fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP
+.PP
+\fBbtrfs\fP \fB<command> \-\-help \fP\fI\fP
+.PP
+.SH DESCRIPTION
+.B btrfs
+is used to control the filesystem and the files and directories stored. It is
+the tool to create or destroy a snapshot or a subvolume for the
+filesystem, to defrag a file or a directory, flush the data to the disk,
+to resize the filesystem, to scan the device.
+
+It is possible to abbreviate the commands unless the commands are ambiguous.
+For example: it is possible to run
+.I btrfs sub snaps
+instead of
+.I btrfs subvolume snapshot.
+But
+.I btrfs file s
+is not allowed, because
+.I file s
+may be interpreted both as
+.I filesystem show
+and as
+.I filesystem sync.
+In this case
+.I btrfs
+returnsfilesystem sync
+If a command is terminated by
+.I --help
+, 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*
+commands.
+
+.SH COMMANDS
+.TP
+
+\fBsubvolume snapshot\fR\fI [-r] <source> [<dest>/]<name>\fR
+Create a writable/readonly snapshot of the subvolume \fI<source>\fR with the
+name \fI<name>\fR in the \fI<dest>\fR directory. If \fI<source>\fR is not a
+subvolume, \fBbtrfs\fR returns an error. If \fI-r\fR is given, the snapshot
+will be readonly.
+.TP
+
+\fBsubvolume delete\fR\fI <subvolume>\fR
+Delete the subvolume \fI<subvolume>\fR. If \fI<subvolume>\fR is not a
+subvolume, \fBbtrfs\fR returns an error.
+.TP
+
+\fBsubvolume create\fR\fI [<dest>/]<name>\fR
+Create a subvolume in \fI<dest>\fR (or in the current directory if
+\fI<dest>\fR is omitted).
+.TP
+
+\fBsubvolume list\fR\fI [-p] <path>\fR
+List the subvolumes present in the filesystem \fI<path>\fR. For every
+subvolume the following information is shown by default.
+ID <ID> top level <ID> path <path>
+where path is the relative path of the subvolume to the \fItop level\fR
+subvolume.
+The subvolume's ID may be used by the \fBsubvolume set-default\fR command, or
+at mount time via the \fIsubvol=\fR option.
+If \fI-p\fR is given, then \fIparent <ID>\fR is added to the output between ID
+and top level. The parent's ID may be used at mount time via the
+\fIsubvolrootid=\fR option.
+.TP
+
+\fBsubvolume set-default\fR\fI <id> <path>\fR
+Set the subvolume of the filesystem \fI<path>\fR which is mounted as
+\fIdefault\fR. The subvolume is identified by \fI<id>\fR, which
+is returned by the \fBsubvolume list\fR command.
+.TP
+
+\fBsubvolume get-default\fR\fI <path>\fR
+Get the default subvolume of the filesystem \fI<path>\fR. The output format
+is similar to \fBsubvolume list\fR command.
+.TP
+
+\fBfilesystem defragment\fP -c[zlib|lzo] [-l \fIlen\fR] [-s \fIstart\fR] [-t \fIsize\fR] -[vf] <\fIfile\fR>|<\fIdir\fR> [<\fIfile\fR>|<\fIdir\fR>...]
+
+Defragment file data and/or directory metadata. To defragment all files in a
+directory you have to specify each one on its own or use your shell wildcards.
+
+The start position and the number of bytes to deframention can be specified by \fIstart\fR and \fIlen\fR. Any extent bigger than \fIthresh\fR will be considered already defragged. Use 0 to take the kernel default, and use 1 to say eveery single extent must be rewritten. You can also turn on compression in defragment operations.
+
+\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.
+\fBsubvolume find-new\fR\fI <subvolume> <last_gen>\fR
+List the recently modified files in a subvolume, after \fI<last_gen>\fR ID.
+.TP
+
+\fBfilesystem sync\fR\fI <path> \fR
+Force a sync for the filesystem identified by \fI<path>\fR.
+.TP
+
+.\"
+.\" Some wording are extracted by the resize2fs man page
+.\"
+
+\fBfilesystem resize\fR\fI [+/\-]<size>[gkm]|max <path>\fR
+Resize a filesystem identified by \fI<path>\fR.
+The \fI<size>\fR parameter specifies the new size of the filesystem.
+If the prefix \fI+\fR or \fI\-\fR is present the size is increased or decreased
+by the quantity \fI<size>\fR.
+If no units are specified, the unit of the \fI<size>\fR parameter defaults to
+bytes. Optionally, the size parameter may be suffixed by one of the following
+the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
+respectively.
+
+If 'max' is passed, the filesystem will occupy all available space on the
+volume(s).
+
+The \fBresize\fR command \fBdoes not\fR manipulate the size of underlying
+partition. If you wish to enlarge/reduce a filesystem, you must make sure you
+can expand the partition before enlarging the filesystem and shrink the
+partition after reducing the size of the filesystem.
+.TP
+
+\fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
+Show or update the label of a filesystem. \fI<dev>\fR is used to identify the
+filesystem.
+If a \fInewlabel\fR optional argument is passed, the label is changed. The
+following costraints exist for a label:
+.IP
+- the maximum allowable lenght shall be less or equal than 256 chars
+.IP
+- the label shall not contain the '/' or '\\' characters.
+
+NOTE: Currently there are the following limitations:
+.IP
+- the filesystem has to be unmounted
+.IP
+- the filesystem should not have more than one device.
+.TP
+
+\fBfilesystem show\fR [--all-devices|<uuid>|<label>]\fR
+Show the btrfs filesystem with some additional info. If no \fIUUID\fP or
+\fIlabel\fP is passed, \fBbtrfs\fR show info of all the btrfs filesystem.
+If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
+otherwise the devices list is extracted from the /proc/partitions file.
+.TP
+
+\fBdevice balance\fR \fI<path>\fR
+Balance the chunks of the filesystem identified by \fI<path>\fR
+across the devices.
+.TP
+
+\fBdevice add\fR\fI <dev> [<dev>..] <path>\fR
+Add device(s) to the filesystem identified by \fI<path>\fR.
+.TP
+
+\fBdevice delete\fR\fI <dev> [<dev>..] <path>\fR
+Remove device(s) from a filesystem identified by \fI<path>\fR.
+.TP
+
+\fBdevice scan\fR \fI[--all-devices|<device> [<device>...]\fR
+If one or more devices are passed, these are scanned for a btrfs filesystem.
+If no devices are passed, \fBbtrfs\fR scans all the block devices listed
+in the /proc/partitions file.
+Finally, if \fB--all-devices\fP is passed, all the devices under /dev are
+scanned.
+.TP
+
+\fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+Start a scrub on all devices of the filesystem identified by \fI<path>\fR or on
+a single \fI<device>\fR. Without options, scrub is started as a background
+process. Progress can be obtained with the \fBscrub status\fR command. Scrubbing
+involves reading all data from all disks and verifying checksums. Errors are
+corrected along the way if possible.
+.RS
+
+\fIOptions\fR
+.IP -B 5
+Do not background and print scrub statistics when finished.
+.IP -d 5
+Print separate statistics for each device of the filesystem (-B only).
+.IP -q 5
+Quiet. Omit error messages and statistics.
+.IP -r 5
+Read only mode. Do not attempt to correct anything.
+.IP -u 5
+Scrub unused space as well. (NOT IMPLEMENTED)
+.RE
+.TP
+
+\fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
+If a scrub is running on the filesystem identified by \fI<path>\fR, cancel it.
+Progress is saved in the scrub progress file and scrubbing can be resumed later
+using the \fBscrub resume\fR command.
+If a \fI<device>\fR is given, the corresponding filesystem is found and
+\fBscrub cancel\fP behaves as if it was called on that filesystem.
+.TP
+
+\fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+Resume a canceled or interrupted scrub cycle on the filesystem identified by
+\fI<path>\fR or on a given \fI<device>\fR. Does not start a new scrub if the
+last scrub finished successfully.
+.RS
+
+\fIOptions\fR
+.TP
+see \fBscrub start\fP.
+.RE
+.TP
+
+\fBscrub status\fP [-d] {\fI<path>\fP|\fI<device>\fP}
+Show status of a running scrub for the filesystem identified by \fI<path>\fR or
+for the specified \fI<device>\fR.
+If no scrub is running, show statistics of the last finished or canceled scrub
+for that filesystem or device.
+.RS
+
+\fIOptions\fR
+.IP -d 5
+Print separate statistics for each device of the filesystem.
+.RE
+.TP
+
+\fBinspect-internal inode-resolve\fP [-v] \fI<inode>\fP \fI<path>\fP
+Resolves an <inode> in subvolume <path> to all filesystem paths.
+.RS
+
+\fIOptions\fR
+.IP -v 5
+verbose mode. print count of returned paths and ioctl() return value
+.RE
+.TP
+
+\fBinspect-internal logical-resolve\fP [-Pv] \fI<logical>\fP \fI<path>\fP
+Resolves a <logical> address in the filesystem mounted at <path> to all inodes.
+By default, each inode is then resolved to a file system path (similar to the
+\fBinode-resolve\fP subcommand).
+.RS
+
+\fIOptions\fR
+.IP -P 5
+skip the path resolving and print the inodes instead
+.IP -v 5
+verbose mode. print count of returned paths and all ioctl() return values
+.RE
+
+.SH EXIT STATUS
+\fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned in
+case of failure.
+
+.SH AVAILABILITY
+.B btrfs
+is part of btrfs-progs. Btrfs filesystem is currently under heavy development,
+and not suitable for any uses other than benchmarking and review.
+Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for
+further details.
+.SH SEE ALSO
+.BR mkfs.btrfs (8)
--
1.7.6.233.gd79bc

View File

@ -1,78 +0,0 @@
From 72aba9c58e83186db249f31198c03ebd0c34d7af Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Sat, 16 Jul 2011 12:11:06 +0200
Subject: [PATCH 12/35] Show the help messages from the info in the comment.
The makefile is update in order to use the tool "helpextract" to extract
the info from the sources comments and to generate the file "helpmsg.c"
which contains an array of string with all the information.
Then the function "print_help" prints these information.
---
btrfs.c | 34 +++++++++++++++++++++++++++++-----
1 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/btrfs.c b/btrfs.c
index d2f6d4d..66b0d80 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -358,6 +358,8 @@ static struct Command commands[] = {
{ 0, 0, 0, 0 }
};
+extern char * help_messages[];
+
static char *get_prgname(char *programname)
{
char *np;
@@ -373,21 +375,43 @@ static char *get_prgname(char *programname)
static void print_help(char *programname, struct Command *cmd, int helptype)
{
char *pc;
+ int i;
+ char *adv_help;
+ char *std_help;
+
+ /* printf("\t%s %s ", programname, cmd->verb ); */
+
+ adv_help = cmd->adv_help;
+ std_help = cmd->help;
+
+ for(i = 0; help_messages[i]; i+= 4 ){
+ if(!strncmp(help_messages[i],"btrfs ",6) &&
+ !strcmp(help_messages[i]+6,cmd->verb) ){
+ if(help_messages[i+2])
+ std_help = help_messages[i+2];
+ if(help_messages[i+3])
+ adv_help = help_messages[i+3];
+ printf("\t%s\t\t",help_messages[i+1]);
+ break;
+ }
+ }
- printf("\t%s %s ", programname, cmd->verb );
+ if( !help_messages[i])
+ printf("\t%s %s ", programname, cmd->verb );
- if (helptype == ADVANCED_HELP && cmd->adv_help)
- for(pc = cmd->adv_help; *pc; pc++){
+ if (helptype == ADVANCED_HELP && adv_help){
+ for(pc = adv_help; *pc; pc++){
putchar(*pc);
if(*pc == '\n')
printf("\t\t");
}
- else
- for(pc = cmd->help; *pc; pc++){
+ }else{
+ for(pc = std_help; *pc; pc++){
putchar(*pc);
if(*pc == '\n')
printf("\t\t");
}
+ }
putchar('\n');
}
--
1.7.6.233.gd79bc

View File

@ -1,53 +0,0 @@
From e2d4509137cb8713b02a030e6116b041ae82588d Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Sat, 16 Jul 2011 12:11:52 +0200
Subject: [PATCH 13/35] Update the makefile for generating the help messages.
Update the makefile for generating the help messages.
---
Makefile | 17 ++++++++++++++++-
1 files changed, 16 insertions(+), 1 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/Makefile
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/Makefile
+++ btrfs-progs-v0.19-118-gfdb6c04/Makefile
@@ -38,8 +38,9 @@ all: version $(progs) manpages
version:
bash version.sh
-btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o
+btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o helpmsg.o
$(CC) $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o \
+ helpmsg.o \
$(objects) $(LDFLAGS) $(LIBS) -lpthread
calc-size: $(objects) calc-size.o
@@ -108,6 +109,19 @@ man/btrfs.8.in: helpextract $(btrfs_man_
manpages: man/btrfs.8.in
cd man; make
+helpmsg.c: helpextract $(btrfs_man_page_source)
+ echo >$@ "/*"
+ echo >>$@ " * this file contains the help messages. It is "
+ echo >>$@ " * automatically generated. do not edit ! "
+ echo >>$@ " */"
+ echo >>$@
+ echo >>$@ "#define NULL 0"
+ echo >>$@
+
+ echo -n "char * help_messages[] = " >>$@
+ ./helpextract --c-array $(btrfs_man_page_source) >>$@
+ echo >>$@ ";"
+
install-man:
cd man; make install
@@ -115,6 +129,7 @@ clean :
rm -f man/btrfs.8.in
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
+ rm -f helpmsg.c
cd man; make clean
install: $(progs) install-man

View File

@ -1,907 +0,0 @@
From b35dbf547122fa2502c8c7e5646d48148ffdee44 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Mon, 16 Jan 2012 12:38:03 +0100
Subject: [PATCH 15/43] Btrfs-progs: add restriper commands
Import restriper commands under btrfs fi balance:
btrfs fi balance start
btrfs fi balance cancel
btrfs fi balance pause
btrfs fi balance resume
btrfs fi balance status
NOTE: Backwards compatibility is broken for now, to get the old "balance
everything" behaviour one has to call 'btrfs fi balance start' with no
options instead of 'btrfs fi balance'. This is because btrfs utility
sub-command parser is not flexible enough.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
btrfs.c | 27 +++-
btrfs_cmds.c | 589 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
btrfs_cmds.h | 8 +-
ctree.h | 23 ++-
ioctl.h | 53 ++++++
print-tree.c | 6 +
volumes.h | 30 +++
7 files changed, 687 insertions(+), 49 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs.c
@@ -295,9 +295,30 @@ static struct Command commands[] = {
"Show space usage information for a mount point.",
NULL
},
- { do_balance, 1,
- "filesystem balance", "<path>\n"
- "Balance the chunks across the device.",
+ { do_balance, -1,
+ "filesystem balance start", "[-d [filters]] [-m [filters]] "
+ "[-s [filters]] [-vf] <path>\n"
+ "Balance chunks across the devices.",
+ NULL
+ },
+ { do_balance_pause, 1,
+ "filesystem balance pause", "<path>\n"
+ "Pause running balance.",
+ NULL
+ },
+ { do_balance_cancel, 1,
+ "filesystem balance cancel", "<path>\n"
+ "Cancel running or paused balance.",
+ NULL
+ },
+ { do_balance_resume, 1,
+ "filesystem balance resume", "<path>\n"
+ "Resume interrupted balance.",
+ NULL
+ },
+ { do_balance_progress, -1,
+ "filesystem balance status", "[-v] <path>\n"
+ "Show status of running or paused balance.",
NULL
},
{ do_change_label, -1,
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs_cmds.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <dirent.h>
@@ -1067,43 +1068,6 @@ int do_add_volume(int nargs, char **args
}
-/**** man: btrfs filesystem balance
- *
- * \Bbtrfs\b \Bfilesystem balance\b \I<path>\i
- *
- * Balance chunks across the devices.
- *
- * Balance chunks across the devices.
- ****/
-
-int do_balance(int argc, char **argv)
-{
-
- int fdmnt, ret=0, e;
- struct btrfs_ioctl_vol_args args;
- char *path = argv[1];
-
- fdmnt = open_file_or_dir(path);
- if (fdmnt < 0) {
- fprintf(stderr, "ERROR: can't access to '%s'\n", path);
- return 12;
- }
-
- memset(&args, 0, sizeof(args));
- ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args);
- e = errno;
- close(fdmnt);
- if(ret<0){
- fprintf(stderr, "ERROR: error during balancing '%s' - %s\n",
- path, strerror(e));
-
- return 19;
- }
- return 0;
-}
-
-
-
/**** man: btrfs device delete
*
* \Bbtrfs\b \Bdevice delete\b\I <dev> [<dev>..] <path>\i
@@ -1188,6 +1152,575 @@ int do_set_default_subvol(int nargs, cha
return 0;
}
+static int parse_one_profile(const char *profile, u64 *flags)
+{
+ if (!strcmp(profile, "raid0")) {
+ *flags |= BTRFS_BLOCK_GROUP_RAID0;
+ } else if (!strcmp(profile, "raid1")) {
+ *flags |= BTRFS_BLOCK_GROUP_RAID1;
+ } else if (!strcmp(profile, "raid10")) {
+ *flags |= BTRFS_BLOCK_GROUP_RAID10;
+ } else if (!strcmp(profile, "dup")) {
+ *flags |= BTRFS_BLOCK_GROUP_DUP;
+ } else if (!strcmp(profile, "single")) {
+ *flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+ } else {
+ fprintf(stderr, "Unknown profile '%s'\n", profile);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int parse_profiles(char *profiles, u64 *flags)
+{
+ char *this_char;
+ char *save_ptr;
+
+ for (this_char = strtok_r(profiles, "|", &save_ptr);
+ this_char != NULL;
+ this_char = strtok_r(NULL, "|", &save_ptr)) {
+ if (parse_one_profile(this_char, flags))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int parse_u64(const char *str, u64 *result)
+{
+ char *endptr;
+ u64 val;
+
+ val = strtoull(str, &endptr, 10);
+ if (*endptr)
+ return 1;
+
+ *result = val;
+ return 0;
+}
+
+static int parse_range(const char *range, u64 *start, u64 *end)
+{
+ char *dots;
+
+ dots = strstr(range, "..");
+ if (dots) {
+ const char *rest = dots + 2;
+ int skipped = 0;
+
+ *dots = 0;
+
+ if (!*rest) {
+ *end = (u64)-1;
+ skipped++;
+ } else {
+ if (parse_u64(rest, end))
+ return 1;
+ }
+ if (dots == range) {
+ *start = 0;
+ skipped++;
+ } else {
+ if (parse_u64(range, start))
+ return 1;
+ }
+
+ if (*start >= *end) {
+ fprintf(stderr, "Range %llu..%llu doesn't make "
+ "sense\n", (unsigned long long)*start,
+ (unsigned long long)*end);
+ return 1;
+ }
+
+ if (skipped <= 1)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int parse_filters(char *filters, struct btrfs_balance_args *args)
+{
+ char *this_char;
+ char *value;
+ char *save_ptr;
+
+ if (!filters)
+ return 0;
+
+ for (this_char = strtok_r(filters, ",", &save_ptr);
+ this_char != NULL;
+ this_char = strtok_r(NULL, ",", &save_ptr)) {
+ if ((value = strchr(this_char, '=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char, "profiles")) {
+ if (!value || !*value) {
+ fprintf(stderr, "the profiles filter requires "
+ "an argument\n");
+ return 1;
+ }
+ if (parse_profiles(value, &args->profiles)) {
+ fprintf(stderr, "Invalid profiles argument\n");
+ return 1;
+ }
+ args->flags |= BTRFS_BALANCE_ARGS_PROFILES;
+ } else if (!strcmp(this_char, "usage")) {
+ if (!value || !*value) {
+ fprintf(stderr, "the usage filter requires "
+ "an argument\n");
+ return 1;
+ }
+ if (parse_u64(value, &args->usage) ||
+ args->usage < 1 || args->usage > 100) {
+ fprintf(stderr, "Invalid usage argument: %s\n",
+ value);
+ return 1;
+ }
+ args->flags |= BTRFS_BALANCE_ARGS_USAGE;
+ } else if (!strcmp(this_char, "devid")) {
+ if (!value || !*value) {
+ fprintf(stderr, "the devid filter requires "
+ "an argument\n");
+ return 1;
+ }
+ if (parse_u64(value, &args->devid) ||
+ args->devid == 0) {
+ fprintf(stderr, "Invalid devid argument: %s\n",
+ value);
+ return 1;
+ }
+ args->flags |= BTRFS_BALANCE_ARGS_DEVID;
+ } else if (!strcmp(this_char, "drange")) {
+ if (!value || !*value) {
+ fprintf(stderr, "the drange filter requires "
+ "an argument\n");
+ return 1;
+ }
+ if (parse_range(value, &args->pstart, &args->pend)) {
+ fprintf(stderr, "Invalid drange argument\n");
+ return 1;
+ }
+ args->flags |= BTRFS_BALANCE_ARGS_DRANGE;
+ } else if (!strcmp(this_char, "vrange")) {
+ if (!value || !*value) {
+ fprintf(stderr, "the vrange filter requires "
+ "an argument\n");
+ return 1;
+ }
+ if (parse_range(value, &args->vstart, &args->vend)) {
+ fprintf(stderr, "Invalid vrange argument\n");
+ return 1;
+ }
+ args->flags |= BTRFS_BALANCE_ARGS_VRANGE;
+ } else if (!strcmp(this_char, "convert")) {
+ if (!value || !*value) {
+ fprintf(stderr, "the convert option requires "
+ "an argument\n");
+ return 1;
+ }
+ if (parse_one_profile(value, &args->target)) {
+ fprintf(stderr, "Invalid convert argument\n");
+ return 1;
+ }
+ args->flags |= BTRFS_BALANCE_ARGS_CONVERT;
+ } else if (!strcmp(this_char, "soft")) {
+ args->flags |= BTRFS_BALANCE_ARGS_SOFT;
+ } else {
+ fprintf(stderr, "Unrecognized balance option '%s'\n",
+ this_char);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void dump_ioctl_balance_args(struct btrfs_ioctl_balance_args *args);
+
+static struct option balance_longopts[] = {
+ { "data", optional_argument, NULL, 'd'},
+ { "metadata", optional_argument, NULL, 'm' },
+ { "system", optional_argument, NULL, 's' },
+ { "force", no_argument, NULL, 'f' },
+ { "verbose", no_argument, NULL, 'v' },
+ { 0, 0, 0, 0}
+};
+
+/*
+ * [-d [filters]] [-m [filters]] [-s [filters]] [-vf]
+ */
+int do_balance(int argc, char **argv)
+{
+ int fd;
+ char *path;
+ struct btrfs_ioctl_balance_args args;
+ struct btrfs_balance_args *ptrs[] = { &args.data, &args.sys,
+ &args.meta, NULL };
+ int force = 0;
+ int verbose = 0;
+ int nofilters = 1;
+ int i;
+ int longindex;
+ int ret;
+ int e;
+
+ memset(&args, 0, sizeof(args));
+
+ while (1) {
+ int opt = getopt_long(argc, argv, "d::s::m::fv",
+ balance_longopts, &longindex);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'd':
+ nofilters = 0;
+ args.flags |= BTRFS_BALANCE_DATA;
+
+ if (parse_filters(optarg, &args.data))
+ return 1;
+ break;
+ case 's':
+ nofilters = 0;
+ args.flags |= BTRFS_BALANCE_SYSTEM;
+
+ if (parse_filters(optarg, &args.sys))
+ return 1;
+ break;
+ case 'm':
+ nofilters = 0;
+ args.flags |= BTRFS_BALANCE_METADATA;
+
+ if (parse_filters(optarg, &args.meta))
+ return 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ fprintf(stderr, "Invalid arguments for balance\n");
+ return 1;
+ }
+ }
+
+ if (argc - optind != 1) {
+ fprintf(stderr, "Invalid arguments for balance\n");
+ return 1;
+ }
+
+ /*
+ * allow -s only under --force, otherwise do with system chunks
+ * the same thing we were ordered to do with meta chunks
+ */
+ if (args.flags & BTRFS_BALANCE_SYSTEM) {
+ if (!force) {
+ fprintf(stderr,
+"Refusing to explicitly operate on system chunks.\n"
+"Pass --force if you really want to do that.\n");
+ return 1;
+ }
+ } else if (args.flags & BTRFS_BALANCE_METADATA) {
+ args.flags |= BTRFS_BALANCE_SYSTEM;
+ memcpy(&args.sys, &args.meta,
+ sizeof(struct btrfs_balance_args));
+ }
+
+ if (nofilters) {
+ /* relocate everything - no filters */
+ args.flags |= BTRFS_BALANCE_TYPE_MASK;
+ }
+
+ /* drange makes sense only when devid is set */
+ for (i = 0; ptrs[i]; i++) {
+ if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
+ !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_DEVID)) {
+ fprintf(stderr, "drange filter can be used only if "
+ "devid filter is used\n");
+ return 1;
+ }
+ }
+
+ /* soft makes sense only when convert for corresponding type is set */
+ for (i = 0; ptrs[i]; i++) {
+ if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_SOFT) &&
+ !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_CONVERT)) {
+ fprintf(stderr, "'soft' option can be used only if "
+ "changing profiles\n");
+ return 1;
+ }
+ }
+
+ path = argv[optind];
+ fd = open_file_or_dir(path);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
+ return 12;
+ }
+
+ if (force)
+ args.flags |= BTRFS_BALANCE_FORCE;
+ if (verbose)
+ dump_ioctl_balance_args(&args);
+
+ ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, &args);
+ e = errno;
+ close(fd);
+
+ if (ret < 0) {
+ if (e == ECANCELED) {
+ if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
+ fprintf(stderr, "balance paused by user\n");
+ if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
+ fprintf(stderr, "balance canceled by user\n");
+ } else {
+ fprintf(stderr, "ERROR: error during balancing '%s' "
+ "- %s\n", path, strerror(e));
+ if (e != EINPROGRESS)
+ fprintf(stderr, "There may be more info in "
+ "syslog - try dmesg | tail\n");
+ return 19;
+ }
+ } else {
+ printf("Done, had to relocate %llu out of %llu chunks\n",
+ (unsigned long long)args.stat.completed,
+ (unsigned long long)args.stat.considered);
+ }
+
+ return 0;
+}
+
+int do_balance_pause(int argc, char **argv)
+{
+ int fd;
+ char *path = argv[1];
+ int ret;
+ int e;
+
+ fd = open_file_or_dir(path);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
+ return 12;
+ }
+
+ ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_PAUSE);
+ e = errno;
+ close(fd);
+
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: balance pause on '%s' failed - %s\n",
+ path, (e == ENOTCONN) ? "Not running" : strerror(e));
+ return 19;
+ }
+
+ return 0;
+}
+
+int do_balance_cancel(int argc, char **argv)
+{
+ int fd;
+ char *path = argv[1];
+ int ret;
+ int e;
+
+ fd = open_file_or_dir(path);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
+ return 12;
+ }
+
+ ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_CANCEL);
+ e = errno;
+ close(fd);
+
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: balance cancel on '%s' failed - %s\n",
+ path, (e == ENOTCONN) ? "Not in progress" : strerror(e));
+ return 19;
+ }
+
+ return 0;
+}
+
+int do_balance_resume(int argc, char **argv)
+{
+ int fd;
+ char *path = argv[1];
+ struct btrfs_ioctl_balance_args args;
+ int ret;
+ int e;
+
+ fd = open_file_or_dir(path);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
+ return 12;
+ }
+
+ memset(&args, 0, sizeof(args));
+ args.flags |= BTRFS_BALANCE_RESUME;
+
+ ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, &args);
+ e = errno;
+ close(fd);
+
+ if (ret < 0) {
+ if (e == ECANCELED) {
+ if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
+ fprintf(stderr, "balance paused by user\n");
+ if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
+ fprintf(stderr, "balance canceled by user\n");
+ } else if (e == ENOTCONN || e == EINPROGRESS) {
+ fprintf(stderr, "ERROR: balance resume on '%s' "
+ "failed - %s\n", path,
+ (e == ENOTCONN) ? "Not in progress" :
+ "Already running");
+ return 19;
+ } else {
+ fprintf(stderr,
+"ERROR: error during balancing '%s' - %s\n"
+"There may be more info in syslog - try dmesg | tail\n", path, strerror(e));
+ return 19;
+ }
+ } else {
+ printf("Done, had to relocate %llu out of %llu chunks\n",
+ (unsigned long long)args.stat.completed,
+ (unsigned long long)args.stat.considered);
+ }
+
+ return 0;
+}
+
+static struct option balance_progress_longopts[] = {
+ { "verbose", no_argument, NULL, 'v' },
+ { 0, 0, 0, 0}
+};
+
+int do_balance_progress(int argc, char **argv)
+{
+ int fd;
+ char *path;
+ struct btrfs_ioctl_balance_args args;
+ int verbose = 0;
+ int longindex;
+ int ret;
+ int e;
+
+ while (1) {
+ int opt = getopt_long(argc, argv, "v",
+ balance_progress_longopts, &longindex);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ fprintf(stderr, "Invalid arguments for balance "
+ "status\n");
+ return 1;
+ }
+ }
+
+ if (argc - optind != 1) {
+ fprintf(stderr, "Invalid arguments for balance status\n");
+ return 1;
+ }
+
+ path = argv[optind];
+ fd = open_file_or_dir(path);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
+ return 12;
+ }
+
+ ret = ioctl(fd, BTRFS_IOC_BALANCE_PROGRESS, &args);
+ e = errno;
+ close(fd);
+
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: balance status on '%s' failed - %s\n",
+ path, (e == ENOTCONN) ? "Not in progress" : strerror(e));
+ return 19;
+ }
+
+ if (args.state & BTRFS_BALANCE_STATE_RUNNING) {
+ printf("Balance on '%s' is running", path);
+ if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
+ printf(", cancel requested\n");
+ else if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
+ printf(", pause requested\n");
+ else
+ printf("\n");
+ } else {
+ printf("Balance on '%s' is paused\n", path);
+ }
+
+ printf("%llu out of about %llu chunks balanced (%llu considered), "
+ "%3.f%% left\n", (unsigned long long)args.stat.completed,
+ (unsigned long long)args.stat.expected,
+ (unsigned long long)args.stat.considered,
+ 100 * (1 - (float)args.stat.completed/args.stat.expected));
+
+ if (verbose)
+ dump_ioctl_balance_args(&args);
+
+ return 0;
+}
+
+static void dump_balance_args(struct btrfs_balance_args *args)
+{
+ if (args->flags & BTRFS_BALANCE_ARGS_CONVERT) {
+ printf("converting, target=%llu, soft is %s",
+ (unsigned long long)args->target,
+ (args->flags & BTRFS_BALANCE_ARGS_SOFT) ? "on" : "off");
+ } else {
+ printf("balancing");
+ }
+
+ if (args->flags & BTRFS_BALANCE_ARGS_PROFILES)
+ printf(", profiles=%llu", (unsigned long long)args->profiles);
+ if (args->flags & BTRFS_BALANCE_ARGS_USAGE)
+ printf(", usage=%llu", (unsigned long long)args->usage);
+ if (args->flags & BTRFS_BALANCE_ARGS_DEVID)
+ printf(", devid=%llu", (unsigned long long)args->devid);
+ if (args->flags & BTRFS_BALANCE_ARGS_DRANGE)
+ printf(", drange=%llu..%llu",
+ (unsigned long long)args->pstart,
+ (unsigned long long)args->pend);
+ if (args->flags & BTRFS_BALANCE_ARGS_VRANGE)
+ printf(", vrange=%llu..%llu",
+ (unsigned long long)args->vstart,
+ (unsigned long long)args->vend);
+
+ printf("\n");
+}
+
+static void dump_ioctl_balance_args(struct btrfs_ioctl_balance_args *args)
+{
+ printf("Dumping filters: flags 0x%llx, state 0x%llx, force is %s\n",
+ (unsigned long long)args->flags, (unsigned long long)args->state,
+ (args->flags & BTRFS_BALANCE_FORCE) ? "on" : "off");
+ if (args->flags & BTRFS_BALANCE_DATA) {
+ printf(" DATA (flags 0x%llx): ",
+ (unsigned long long)args->data.flags);
+ dump_balance_args(&args->data);
+ }
+ if (args->flags & BTRFS_BALANCE_METADATA) {
+ printf(" METADATA (flags 0x%llx): ",
+ (unsigned long long)args->meta.flags);
+ dump_balance_args(&args->meta);
+ }
+ if (args->flags & BTRFS_BALANCE_SYSTEM) {
+ printf(" SYSTEM (flags 0x%llx): ",
+ (unsigned long long)args->sys.flags);
+ dump_balance_args(&args->sys);
+ }
+}
+
/**** man: btrfs filesystem label
*
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs_cmds.h
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.h
@@ -22,12 +22,16 @@ int do_fssync(int nargs, char **argv);
int do_defrag(int argc, char **argv);
int do_show_filesystem(int nargs, char **argv);
int do_add_volume(int nargs, char **args);
-int do_balance(int nargs, char **argv);
+int do_remove_volume(int nargs, char **args);
+int do_balance(int argc, char **argv);
+int do_balance_pause(int argc, char **argv);
+int do_balance_cancel(int argc, char **argv);
+int do_balance_resume(int argc, char **argv);
+int do_balance_progress(int argc, char **argv);
int do_scrub_start(int nargs, char **argv);
int do_scrub_status(int argc, char **argv);
int do_scrub_resume(int argc, char **argv);
int do_scrub_cancel(int nargs, char **argv);
-int do_remove_volume(int nargs, char **args);
int do_scan(int nargs, char **argv);
int do_resize(int nargs, char **argv);
int do_subvol_list(int nargs, char **argv);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -61,6 +61,9 @@ struct btrfs_trans_handle;
#define BTRFS_CSUM_TREE_OBJECTID 7ULL
+/* for storing balance parameters in the root tree */
+#define BTRFS_BALANCE_OBJECTID -4ULL
+
/* oprhan objectid for tracking unlinked/truncated files */
#define BTRFS_ORPHAN_OBJECTID -5ULL
@@ -697,13 +700,17 @@ struct btrfs_csum_item {
} __attribute__ ((__packed__));
/* tag for the radix tree of block groups in ram */
-#define BTRFS_BLOCK_GROUP_DATA (1 << 0)
-#define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1)
-#define BTRFS_BLOCK_GROUP_METADATA (1 << 2)
-#define BTRFS_BLOCK_GROUP_RAID0 (1 << 3)
-#define BTRFS_BLOCK_GROUP_RAID1 (1 << 4)
-#define BTRFS_BLOCK_GROUP_DUP (1 << 5)
-#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6)
+#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0)
+#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1)
+#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2)
+#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3)
+#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4)
+#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5)
+#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6)
+#define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE
+
+/* used in struct btrfs_balance_args fields */
+#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48)
struct btrfs_block_group_item {
__le64 used;
@@ -911,6 +918,8 @@ struct btrfs_root {
#define BTRFS_DEV_ITEM_KEY 216
#define BTRFS_CHUNK_ITEM_KEY 228
+#define BTRFS_BALANCE_ITEM_KEY 248
+
/*
* string items are for debugging. They just store a short string of
* data in the FS
Index: btrfs-progs-v0.19-118-gfdb6c04/ioctl.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ioctl.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ioctl.h
@@ -91,6 +91,54 @@ struct btrfs_ioctl_fs_info_args {
__u64 reserved[124]; /* pad to 1k */
};
+/* balance control ioctl modes */
+#define BTRFS_BALANCE_CTL_PAUSE 1
+#define BTRFS_BALANCE_CTL_CANCEL 2
+#define BTRFS_BALANCE_CTL_RESUME 3
+
+/*
+ * this is packed, because it should be exactly the same as its disk
+ * byte order counterpart (struct btrfs_disk_balance_args)
+ */
+struct btrfs_balance_args {
+ __u64 profiles;
+ __u64 usage;
+ __u64 devid;
+ __u64 pstart;
+ __u64 pend;
+ __u64 vstart;
+ __u64 vend;
+
+ __u64 target;
+
+ __u64 flags;
+
+ __u64 unused[8];
+} __attribute__ ((__packed__));
+
+struct btrfs_balance_progress {
+ __u64 expected;
+ __u64 considered;
+ __u64 completed;
+};
+
+#define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0)
+#define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1)
+#define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2)
+
+struct btrfs_ioctl_balance_args {
+ __u64 flags; /* in/out */
+ __u64 state; /* out */
+
+ struct btrfs_balance_args data; /* in/out */
+ struct btrfs_balance_args meta; /* in/out */
+ struct btrfs_balance_args sys; /* in/out */
+
+ struct btrfs_balance_progress stat; /* out */
+
+ __u64 unused[72]; /* pad to 1k */
+};
+
struct btrfs_ioctl_search_key {
/* which root are we searching. 0 is the tree of tree roots */
__u64 tree_id;
@@ -284,6 +332,11 @@ struct btrfs_ioctl_compr_size_args {
struct btrfs_ioctl_dev_info_args)
#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
struct btrfs_ioctl_fs_info_args)
+#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \
+ struct btrfs_ioctl_balance_args)
+#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int)
+#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \
+ struct btrfs_ioctl_balance_args)
#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
Index: btrfs-progs-v0.19-118-gfdb6c04/print-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/print-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/print-tree.c
@@ -351,6 +351,9 @@ static void print_key_type(u8 type)
case BTRFS_DEV_EXTENT_KEY:
printf("DEV_EXTENT");
break;
+ case BTRFS_BALANCE_ITEM_KEY:
+ printf("BALANCE_ITEM");
+ break;
case BTRFS_STRING_ITEM_KEY:
printf("STRING_ITEM");
break;
@@ -391,6 +394,9 @@ static void print_objectid(unsigned long
case BTRFS_CSUM_TREE_OBJECTID:
printf("CSUM_TREE");
break;
+ case BTRFS_BALANCE_OBJECTID:
+ printf("BALANCE");
+ break;
case BTRFS_ORPHAN_OBJECTID:
printf("ORPHAN");
break;
Index: btrfs-progs-v0.19-118-gfdb6c04/volumes.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/volumes.h
+++ btrfs-progs-v0.19-118-gfdb6c04/volumes.h
@@ -91,6 +91,37 @@ struct btrfs_multi_bio {
#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
+/*
+ * Restriper's general type filter
+ */
+#define BTRFS_BALANCE_DATA (1ULL << 0)
+#define BTRFS_BALANCE_SYSTEM (1ULL << 1)
+#define BTRFS_BALANCE_METADATA (1ULL << 2)
+
+#define BTRFS_BALANCE_TYPE_MASK (BTRFS_BALANCE_DATA | \
+ BTRFS_BALANCE_SYSTEM | \
+ BTRFS_BALANCE_METADATA)
+
+#define BTRFS_BALANCE_FORCE (1ULL << 3)
+#define BTRFS_BALANCE_RESUME (1ULL << 4)
+
+/*
+ * Balance filters
+ */
+#define BTRFS_BALANCE_ARGS_PROFILES (1ULL << 0)
+#define BTRFS_BALANCE_ARGS_USAGE (1ULL << 1)
+#define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2)
+#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3)
+#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4)
+
+/*
+ * Profile changing flags. When SOFT is set we won't relocate chunk if
+ * it already has the target profile (even though it may be
+ * half-filled).
+ */
+#define BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8)
+#define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9)
+
int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
u64 chunk_tree, u64 chunk_objectid,

View File

@ -1,181 +0,0 @@
From 72218a2090e1cbafe9baa97aaa465a28438c3dbb Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 19 Dec 2011 17:51:11 +0100
Subject: [PATCH 16/43] btrfs-progs: Add ioctl to read compressed size of a
file
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs.c | 9 ++++++-
btrfs_cmds.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
btrfs_cmds.h | 1 +
ioctl.h | 13 ++++++++++
man/btrfs.8.in.old | 10 +++++++
5 files changed, 100 insertions(+), 1 deletions(-)
diff --git a/btrfs.c b/btrfs.c
index e78f194..f5b8fd4 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -325,7 +325,14 @@ static struct Command commands[] = {
"filesystem label", "<device> [<newlabel>]\n"
"With one argument, get the label of filesystem on <device>.\n"
"If <newlabel> is passed, set the filesystem label to <newlabel>.\n"
- "The filesystem must be unmounted.\n"
+ "The filesystem must be unmounted."
+ },
+ { do_compr_size, -1,
+ "filesystem csize", "[-s start] [-e end] <file>\n"
+ "Read ordinary and compressed size of extents in the range [start,end)\n"
+ "-s start range start inclusive, accepts K/M/G modifiers\n"
+ "-e end range end exclusive, accepts K/M/G modifiers\n",
+ NULL
},
{ do_scrub_start, -1,
"scrub start", "[-Bdqr] <path>|<device>\n"
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 12346e5..c8196d1 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -2058,3 +2058,71 @@ out:
free(inodes);
return ret;
}
+
+int do_compr_size(int argc, char **argv)
+{
+ int ret;
+ int fd;
+ struct btrfs_ioctl_compr_size_args args;
+
+ args.start = 0;
+ args.end = (u64)-1;
+ optind = 1;
+ while (1) {
+ int c = getopt(argc, argv, "s:e:r");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 's':
+ args.start = parse_size(optarg);
+ break;
+ case 'e':
+ args.end = parse_size(optarg);
+ break;
+ default:
+ fprintf(stderr, "ERROR: Invalid arguments for csize\n");
+ return 1;
+ }
+ }
+
+ if (args.start > args.end) {
+ fprintf(stderr, "ERROR: Invalid range for csize\n");
+ return 1;
+ }
+
+ if (argc - optind == 0) {
+ fprintf(stderr, "ERROR: Invalid arguments for csize\n");
+ return 1;
+ }
+ argc -= optind;
+
+ fd = open_file_or_dir(argv[optind]);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
+ return 1;
+ }
+
+ ret = ioctl(fd, BTRFS_IOC_COMPR_SIZE, &args);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: ioctl returned %d, errno %d %s\n",
+ ret, errno, strerror(errno));
+ return errno;
+ }
+
+ printf("File name: %s\n", argv[optind]);
+ if (args.end == (u64)-1)
+ printf("File range: %llu-EOF\n",
+ (unsigned long long)args.start);
+ else
+ printf("File range: %llu-%llu\n",
+ (unsigned long long)args.start,
+ (unsigned long long)args.end);
+
+ printf("Compressed size: %llu\n",
+ (unsigned long long)(args.compressed_size << 9));
+ printf("Uncompressed size: %llu\n",
+ (unsigned long long)(args.size << 9));
+ printf("Ratio: %3.2f%%\n",
+ 100.0 * args.compressed_size / args.size);
+ return 0;
+}
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 53d51d6..07dad7a 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -46,3 +46,4 @@ int open_file_or_dir(const char *fname);
int do_ino_to_path(int nargs, char **argv);
int do_logical_to_ino(int nargs, char **argv);
char *path_for_root(int fd, u64 root);
+int do_compr_size(int argc, char **argv);
diff --git a/ioctl.h b/ioctl.h
index 78aebce..a820098 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -272,6 +272,17 @@ struct btrfs_ioctl_logical_ino_args {
__u64 inodes;
};
+struct btrfs_ioctl_compr_size_args {
+ /* Range start, inclusive */
+ __u64 start; /* in */
+ /* Range end, exclusive */
+ __u64 end; /* in */
+ __u64 size; /* out */
+ __u64 compressed_size; /* out */
+ __u64 reserved[2];
+};
+
+
/* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
@@ -330,5 +341,7 @@ struct btrfs_ioctl_logical_ino_args {
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+ struct btrfs_ioctl_compr_size_args)
#endif
diff --git a/man/btrfs.8.in.old b/man/btrfs.8.in.old
index be478e0..b7dacea 100644
--- a/man/btrfs.8.in.old
+++ b/man/btrfs.8.in.old
@@ -31,6 +31,8 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fP
.PP
+\fBbtrfs\fP \fBfilesystem csize \fP\fI [-s start] [-e end] <file> \fP
+.PP
\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
.PP
\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
@@ -209,6 +211,14 @@ If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
otherwise the devices list is extracted from the /proc/partitions file.
.TP
+\fBfilesystem csize \fR \fI [-s start] [-e end] <file> \fR
+Read ordinary and compressed size of extents in the range [start,end) of \fI<file>\fR
+.IP
+\fB-s start\fP range start inclusive, accepts K/M/G modifiers
+.IP
+\fB-e end\fP range end exclusive, accepts K/M/G modifiers
+.TP
+
\fBdevice balance\fR \fI<path>\fR
Balance the chunks of the filesystem identified by \fI<path>\fR
across the devices.
--
1.7.6.233.gd79bc

View File

@ -1,85 +0,0 @@
From 6ca37050db7e94257559da2b8e8009c2347ed798 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 27 Oct 2011 16:23:14 -0400
Subject: [PATCH 16/35] btrfs-progs: fixup is_mounted checks
/proc/mounts contains device names that don't exist,
we end up erroring out because we're not able to stat
the device (that doesn't exist).
Fix this by allowing the mkfs when the target device doesn't exist.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
utils.c | 34 +++++++++++++++++++---------------
1 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/utils.c b/utils.c
index 1c27e14..6c96548 100644
--- a/utils.c
+++ b/utils.c
@@ -674,11 +674,11 @@ int is_same_blk_file(const char* a, const char* b)
char real_a[PATH_MAX];
char real_b[PATH_MAX];
- if(!realpath(a, real_a) ||
- !realpath(b, real_b))
- {
- return -errno;
- }
+ if(!realpath(a, real_a))
+ strcpy(real_a, a);
+
+ if (!realpath(b, real_b))
+ strcpy(real_b, b);
/* Identical path? */
if(strcmp(real_a, real_b) == 0)
@@ -719,8 +719,8 @@ int is_same_loop_file(const char* a, const char* b)
{
char res_a[PATH_MAX];
char res_b[PATH_MAX];
- const char* final_a;
- const char* final_b;
+ const char* final_a = NULL;
+ const char* final_b = NULL;
int ret;
/* Resolve a if it is a loop device */
@@ -729,10 +729,12 @@ int is_same_loop_file(const char* a, const char* b)
return 0;
return ret;
} else if (ret) {
- if ((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0)
- return ret;
-
- final_a = res_a;
+ if ((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0) {
+ if (errno != EPERM)
+ return ret;
+ }
+ else
+ final_a = res_a;
} else {
final_a = a;
}
@@ -743,10 +745,12 @@ int is_same_loop_file(const char* a, const char* b)
return 0;
return ret;
} else if (ret) {
- if((ret = resolve_loop_device(b, res_b, sizeof(res_b))) < 0)
- return ret;
-
- final_b = res_b;
+ if ((ret = resolve_loop_device(b, res_b, sizeof(res_b))) < 0) {
+ if (errno != EPERM)
+ return ret;
+ }
+ else
+ final_b = res_b;
} else {
final_b = b;
}
--
1.7.6.233.gd79bc

View File

@ -1,95 +0,0 @@
From 0e6aead68455a1043aed04e0557dc14af2cd6f60 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Tue, 1 Nov 2011 14:26:20 -0400
Subject: [PATCH 17/35] Btrfs-progs: add an option for specifying the root to
restore
If the normal fs tree is hosed and the user has multiple subvolumes it's handy
to be able to specify just one of the subvolumes to restore. It's also handy if
a user only wants to restore say /home instead of his entire disk. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 32 ++++++++++++++++++++++++++++----
1 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/restore.c b/restore.c
index 250c9d3..38c4ded 100644
--- a/restore.c
+++ b/restore.c
@@ -760,13 +760,14 @@ int main(int argc, char **argv)
char dir_name[128];
u64 tree_location = 0;
u64 fs_location = 0;
+ u64 root_objectid = 0;
int len;
int ret;
int opt;
int super_mirror = 0;
int find_dir = 0;
- while ((opt = getopt(argc, argv, "sviot:u:df:")) != -1) {
+ while ((opt = getopt(argc, argv, "sviot:u:df:r:")) != -1) {
switch (opt) {
case 's':
get_snaps = 1;
@@ -809,6 +810,14 @@ int main(int argc, char **argv)
case 'd':
find_dir = 1;
break;
+ case 'r':
+ errno = 0;
+ root_objectid = (u64)strtoll(optarg, NULL, 10);
+ if (errno != 0) {
+ fprintf(stderr, "Root objectid not valid\n");
+ exit(1);
+ }
+ break;
default:
usage();
exit(1);
@@ -842,8 +851,6 @@ int main(int argc, char **argv)
}
}
- printf("Root objectid is %Lu\n", root->objectid);
-
memset(path_name, 0, 4096);
strncpy(dir_name, argv[optind + 1], 128);
@@ -856,6 +863,23 @@ int main(int argc, char **argv)
dir_name[len - 1] = '\0';
}
+ if (root_objectid != 0) {
+ struct btrfs_root *orig_root = root;
+
+ key.objectid = root_objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+ root = btrfs_read_fs_root(orig_root->fs_info, &key);
+ if (IS_ERR(root)) {
+ fprintf(stderr, "Error reading root\n");
+ root = orig_root;
+ ret = 1;
+ goto out;
+ }
+ key.type = 0;
+ key.offset = 0;
+ }
+
if (find_dir) {
ret = find_first_dir(root, &key.objectid);
if (ret)
@@ -864,7 +888,7 @@ int main(int argc, char **argv)
key.objectid = BTRFS_FIRST_FREE_OBJECTID;
}
- ret = search_dir(root->fs_info->fs_root, &key, dir_name);
+ ret = search_dir(root, &key, dir_name);
out:
close_ctree(root);
--
1.7.6.233.gd79bc

View File

@ -1,134 +0,0 @@
From 9dee07a6365d2facddea9a501737dce92333c582 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Fri, 4 Nov 2011 09:10:49 -0400
Subject: [PATCH 18/35] Btrfs-progs: try other mirrors if decomression fails
This will make the restore program fall back on other mirrors if it fails to
decompress an extent for whatever reason. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 47 +++++++++++++++++++++++++----------------------
1 files changed, 25 insertions(+), 22 deletions(-)
diff --git a/restore.c b/restore.c
index 38c4ded..f062a2b 100644
--- a/restore.c
+++ b/restore.c
@@ -61,7 +61,7 @@ static int decompress(char *inbuf, char *outbuf, u64 compress_len,
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != Z_STREAM_END) {
(void)inflateEnd(&strm);
- fprintf(stderr, "ret is %d\n", ret);
+ fprintf(stderr, "failed to inflate: %d\n", ret);
return -1;
}
@@ -197,6 +197,8 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
int compress;
int ret;
int dev_fd;
+ int mirror_num = 0;
+ int num_copies;
compress = btrfs_file_extent_compression(leaf, fi);
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
@@ -225,12 +227,10 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
again:
length = size_left;
ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
- bytenr, &length, &multi, 0);
+ bytenr, &length, &multi, mirror_num);
if (ret) {
- free(inbuf);
- free(outbuf);
fprintf(stderr, "Error mapping block %d\n", ret);
- return ret;
+ goto out;
}
device = multi->stripes[0].dev;
dev_fd = device->fd;
@@ -244,10 +244,9 @@ again:
done = pread(dev_fd, inbuf+count, length, dev_bytenr);
if (done < length) {
- free(inbuf);
- free(outbuf);
+ ret = -1;
fprintf(stderr, "Short read %d\n", errno);
- return -1;
+ goto out;
}
count += length;
@@ -255,41 +254,46 @@ again:
if (size_left)
goto again;
-
if (compress == BTRFS_COMPRESS_NONE) {
while (total < ram_size) {
done = pwrite(fd, inbuf+total, ram_size-total,
pos+total);
if (done < 0) {
- free(inbuf);
+ ret = -1;
fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno));
- return -1;
+ goto out;
}
total += done;
}
- free(inbuf);
- return 0;
+ ret = 0;
+ goto out;
}
ret = decompress(inbuf, outbuf, disk_size, ram_size);
- free(inbuf);
if (ret) {
- free(outbuf);
- return ret;
+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
+ bytenr, length);
+ mirror_num++;
+ if (mirror_num >= num_copies) {
+ ret = -1;
+ goto out;
+ }
+ fprintf(stderr, "Trying another mirror\n");
+ goto again;
}
while (total < ram_size) {
done = pwrite(fd, outbuf+total, ram_size-total, pos+total);
if (done < 0) {
- free(outbuf);
- fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno));
- return -1;
+ ret = -1;
+ goto out;
}
total += done;
}
+out:
+ free(inbuf);
free(outbuf);
-
- return 0;
+ return ret;
}
static int ask_to_continue(const char *file)
@@ -385,7 +389,6 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
/* No more leaves to search */
btrfs_free_path(path);
goto set_size;
- return 0;
}
leaf = path->nodes[0];
} while (!leaf);
--
1.7.6.233.gd79bc

View File

@ -1,40 +0,0 @@
From ff0e1b17030a9b1e027c8b77f67ab44136e172ac Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Mon, 7 Nov 2011 16:41:01 -0500
Subject: [PATCH 19/35] Btrfs-progs: try other mirrors on read failure
If we hit a bad disk and the read doesn't work, try other mirrors in case we
have other disks with good copies. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/restore.c b/restore.c
index f062a2b..4dabae2 100644
--- a/restore.c
+++ b/restore.c
@@ -244,9 +244,16 @@ again:
done = pread(dev_fd, inbuf+count, length, dev_bytenr);
if (done < length) {
- ret = -1;
- fprintf(stderr, "Short read %d\n", errno);
- goto out;
+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
+ bytenr, length);
+ mirror_num++;
+ if (mirror_num >= num_copies) {
+ ret = -1;
+ fprintf(stderr, "Exhausted mirrors trying to read\n");
+ goto out;
+ }
+ fprintf(stderr, "Trying another mirror\n");
+ goto again;
}
count += length;
--
1.7.6.233.gd79bc

View File

@ -1,54 +0,0 @@
From 16073605bb947e6acfa3b13b6280a90fed9b717a Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Wed, 9 Nov 2011 13:23:28 -0800
Subject: [PATCH 20/35] btrfs-progs: Fix error handling for failed reads in
restore tool when mirrors exist
---
restore.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/restore.c b/restore.c
index 4dabae2..389b107 100644
--- a/restore.c
+++ b/restore.c
@@ -197,7 +197,7 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
int compress;
int ret;
int dev_fd;
- int mirror_num = 0;
+ int mirror_num = 1;
int num_copies;
compress = btrfs_file_extent_compression(leaf, fi);
@@ -240,14 +240,15 @@ again:
if (size_left < length)
length = size_left;
- size_left -= length;
done = pread(dev_fd, inbuf+count, length, dev_bytenr);
- if (done < length) {
+ /* Need both checks, or we miss negative values due to u64 conversion */
+ if (done < 0 || done < length) {
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
bytenr, length);
mirror_num++;
- if (mirror_num >= num_copies) {
+ /* mirror_num is 1-indexed, so num_copies is a valid mirror. */
+ if (mirror_num > num_copies) {
ret = -1;
fprintf(stderr, "Exhausted mirrors trying to read\n");
goto out;
@@ -256,6 +257,8 @@ again:
goto again;
}
+ mirror_num = 1;
+ size_left -= length;
count += length;
bytenr += length;
if (size_left)
--
1.7.6.233.gd79bc

View File

@ -1,55 +0,0 @@
From a1ebf7b951c6796039748601404aa01fd283ddef Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Wed, 16 Nov 2011 12:18:08 -0800
Subject: [PATCH 21/35] btrfs-progs: Check metadata mirrors in find-root.
Signed-off-by: David Marcin <djmarcin@google.com>
---
find-root.c | 13 ++++++++++++-
1 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/find-root.c b/find-root.c
index c0f38b8..2899632 100644
--- a/find-root.c
+++ b/find-root.c
@@ -361,6 +361,8 @@ static int find_root(struct btrfs_root *root)
while (1) {
u64 map_length = 4096;
u64 type;
+ int mirror_num;
+ int num_copies;
if (offset >
btrfs_super_total_bytes(&root->fs_info->super_copy)) {
@@ -377,8 +379,10 @@ static int find_root(struct btrfs_root *root)
}
offset = metadata_offset;
}
+ mirror_num = 1;
+ again:
err = __btrfs_map_block(&root->fs_info->mapping_tree, READ,
- offset, &map_length, &type, &multi, 0);
+ offset, &map_length, &type, &multi, mirror_num);
if (err) {
offset += map_length;
continue;
@@ -396,9 +400,16 @@ static int find_root(struct btrfs_root *root)
err = read_physical(root, fd, offset, bytenr, map_length);
if (!err) {
+ /* Found the root. */
ret = 0;
break;
} else if (err < 0) {
+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
+ offset, map_length);
+ mirror_num++;
+ if (mirror_num <= num_copies)
+ goto again;
+ /* Unrecoverable error in read. */
ret = err;
break;
}
--
1.7.6.233.gd79bc

View File

@ -1,84 +0,0 @@
From 266f413a32d774c68f41f488bb79fac6ad63e930 Mon Sep 17 00:00:00 2001
From: Peter Stuge <peter@stuge.se>
Date: Fri, 25 Nov 2011 01:03:57 +0100
Subject: [PATCH 22/35] restore: Split output directory and btrfs-local path
search_dir() parameters
search_dir() recurses down the btrfs tree, and used to take the output
path for every item (i.e. in the running system, output root directory
concatenated with btrfs-local pathname) passed as the only path
parameter. Moving the output root directory to a separate parameter
and passing the btrfs-local pathname for each file and directory
separately allows easy filtering based on the btrfs-local pathname.
Signed-off-by: Peter Stuge <peter@stuge.se>
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/restore.c b/restore.c
index 389b107..0b92ed5 100644
--- a/restore.c
+++ b/restore.c
@@ -35,6 +35,7 @@
#include "volumes.h"
#include "utils.h"
+static char fs_name[4096];
static char path_name[4096];
static int get_snaps = 0;
static int verbose = 0;
@@ -450,7 +451,7 @@ set_size:
}
static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
- const char *dir)
+ const char *output_rootdir, const char *dir)
{
struct btrfs_path *path;
struct extent_buffer *leaf;
@@ -554,8 +555,11 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
type = btrfs_dir_type(leaf, dir_item);
btrfs_dir_item_key_to_cpu(leaf, dir_item, &location);
- snprintf(path_name, 4096, "%s/%s", dir, filename);
+ /* full path from root of btrfs being restored */
+ snprintf(fs_name, 4096, "%s/%s", dir, filename);
+ /* full path from system root */
+ snprintf(path_name, 4096, "%s%s", output_rootdir, fs_name);
/*
* At this point we're only going to restore directories and
@@ -603,7 +607,7 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
}
} else if (type == BTRFS_FT_DIR) {
struct btrfs_root *search_root = root;
- char *dir = strdup(path_name);
+ char *dir = strdup(fs_name);
if (!dir) {
fprintf(stderr, "Ran out of memory\n");
@@ -664,7 +668,8 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
return -1;
}
loops = 0;
- ret = search_dir(search_root, &location, dir);
+ ret = search_dir(search_root, &location,
+ output_rootdir, dir);
free(dir);
if (ret) {
if (ignore_errors)
@@ -901,7 +906,7 @@ int main(int argc, char **argv)
key.objectid = BTRFS_FIRST_FREE_OBJECTID;
}
- ret = search_dir(root, &key, dir_name);
+ ret = search_dir(root, &key, dir_name, "");
out:
close_ctree(root);
--
1.7.6.233.gd79bc

View File

@ -1,130 +0,0 @@
From 2f0c2a29ab13b17ae1cc21effcf532f2447b7c8c Mon Sep 17 00:00:00 2001
From: Peter Stuge <peter@stuge.se>
Date: Fri, 25 Nov 2011 01:03:58 +0100
Subject: [PATCH 23/35] restore: Add regex matching of paths and files to be
restored
The option -m is used to specify the regex string. -c is used to
specify case insensitive matching. -i was already taken.
In order to restore only a single folder somewhere in the btrfs
tree, it is unfortunately neccessary to construct a slightly
nontrivial regex, e.g.:
restore -m '^/(|home(|/username(|/Desktop(|/.*))))$' /dev/sdb2 /output
This is needed in order to match each directory along the way to the
Desktop directory, as well as all contents below the Desktop directory.
Signed-off-by: Peter Stuge <peter@stuge.se>
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 40 ++++++++++++++++++++++++++++++++++------
1 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/restore.c b/restore.c
index 0b92ed5..e65746a 100644
--- a/restore.c
+++ b/restore.c
@@ -25,6 +25,8 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <zlib.h>
+#include <sys/types.h>
+#include <regex.h>
#include "kerncompat.h"
#include "ctree.h"
#include "disk-io.h"
@@ -451,7 +453,8 @@ set_size:
}
static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
- const char *output_rootdir, const char *dir)
+ const char *output_rootdir, const char *dir,
+ const regex_t *mreg)
{
struct btrfs_path *path;
struct extent_buffer *leaf;
@@ -558,6 +561,9 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
/* full path from root of btrfs being restored */
snprintf(fs_name, 4096, "%s/%s", dir, filename);
+ if (REG_NOMATCH == regexec(mreg, fs_name, 0, NULL, 0))
+ goto next;
+
/* full path from system root */
snprintf(path_name, 4096, "%s%s", output_rootdir, fs_name);
@@ -669,7 +675,7 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
}
loops = 0;
ret = search_dir(search_root, &location,
- output_rootdir, dir);
+ output_rootdir, dir, mreg);
free(dir);
if (ret) {
if (ignore_errors)
@@ -690,8 +696,8 @@ next:
static void usage()
{
- fprintf(stderr, "Usage: restore [-svio] [-t disk offset] <device> "
- "<directory>\n");
+ fprintf(stderr, "Usage: restore [-svioc] [-t disk offset] "
+ "[-m regex] <device> <directory>\n");
}
static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror)
@@ -784,8 +790,12 @@ int main(int argc, char **argv)
int opt;
int super_mirror = 0;
int find_dir = 0;
+ const char *match_regstr = NULL;
+ int match_cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
+ regex_t match_reg, *mreg = NULL;
+ char reg_err[256];
- while ((opt = getopt(argc, argv, "sviot:u:df:r:")) != -1) {
+ while ((opt = getopt(argc, argv, "sviot:u:df:r:cm:")) != -1) {
switch (opt) {
case 's':
get_snaps = 1;
@@ -836,6 +846,12 @@ int main(int argc, char **argv)
exit(1);
}
break;
+ case 'c':
+ match_cflags |= REG_ICASE;
+ break;
+ case 'm':
+ match_regstr = optarg;
+ break;
default:
usage();
exit(1);
@@ -906,9 +922,21 @@ int main(int argc, char **argv)
key.objectid = BTRFS_FIRST_FREE_OBJECTID;
}
- ret = search_dir(root, &key, dir_name, "");
+ if (match_regstr) {
+ ret = regcomp(&match_reg, match_regstr, match_cflags);
+ if (ret) {
+ regerror(ret, &match_reg, reg_err, sizeof(reg_err));
+ fprintf(stderr, "Regex compile failed: %s\n", reg_err);
+ goto out;
+ }
+ mreg = &match_reg;
+ }
+
+ ret = search_dir(root, &key, dir_name, "", mreg);
out:
+ if (mreg)
+ regfree(mreg);
close_ctree(root);
return ret;
}
--
1.7.6.233.gd79bc

View File

@ -1,92 +0,0 @@
From e8919ef79253ace49de01ba228290e4e0cafbfb7 Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Mon, 21 Nov 2011 20:51:15 -0600
Subject: [PATCH 24/35] btrfs-progs: In find-root, dump bytenr for every slot.
Signed-off-by: David Marcin <djmarcin@google.com>
---
find-root.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 59 insertions(+), 1 deletions(-)
diff --git a/find-root.c b/find-root.c
index 2899632..bd44e1f 100644
--- a/find-root.c
+++ b/find-root.c
@@ -258,8 +258,63 @@ out:
return NULL;
}
+static int dump_root_bytenr(struct btrfs_root *root, u64 bytenr, u64 gen)
+{
+ struct btrfs_root *tmp = malloc(sizeof(struct btrfs_root));
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ struct btrfs_root_item ri;
+ struct extent_buffer *leaf;
+ struct btrfs_disk_key disk_key;
+ struct btrfs_key found_key;
+ int slot;
+ int ret;
+
+ if (!tmp)
+ return -ENOMEM;
+
+ __setup_root(4096, 4096, 4096, 4096, tmp,
+ root->fs_info, BTRFS_ROOT_TREE_OBJECTID);
+
+ tmp->node = read_tree_block(root, bytenr, 4096, gen);
+
+ key.objectid = 0;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = -1;
+
+ path = btrfs_alloc_path();
+
+ /* Walk the slots of this root looking for BTRFS_ROOT_ITEM_KEYs. */
+ ret = btrfs_search_slot(NULL, tmp, &key, path, 0, 0);
+ BUG_ON(ret < 0);
+ while (1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(tmp, path);
+ if (ret != 0)
+ break;
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ }
+ btrfs_item_key(leaf, &disk_key, path->slots[0]);
+ btrfs_disk_key_to_cpu(&found_key, &disk_key);
+ if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
+ unsigned long offset;
+
+ offset = btrfs_item_ptr_offset(leaf, slot);
+ read_extent_buffer(leaf, &ri, offset, sizeof(ri));
+ printf("Generation: %Lu Root bytenr: %Lu\n", gen, btrfs_root_bytenr(&ri));
+ }
+ path->slots[0]++;
+ }
+ btrfs_free_path(path);
+ free_extent_buffer(leaf);
+ return 0;
+}
+
static int search_iobuf(struct btrfs_root *root, void *iobuf,
- size_t iobuf_size, off_t offset)
+ size_t iobuf_size, off_t offset)
{
u64 gen = btrfs_super_generation(&root->fs_info->super_copy);
u64 objectid = search_objectid;
@@ -290,6 +345,9 @@ static int search_iobuf(struct btrfs_root *root, void *iobuf,
h_byte);
goto next;
}
+ /* Found some kind of root and it's fairly valid. */
+ if (dump_root_bytenr(root, h_byte, h_gen))
+ break;
if (h_gen != gen) {
fprintf(stderr, "Well block %Lu seems great, "
"but generation doesn't match, "
--
1.7.6.233.gd79bc

View File

@ -1,161 +0,0 @@
From db874f1e8924e86bbdee6600b0e5b3e6d11f9238 Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Tue, 22 Nov 2011 10:08:00 -0800
Subject: [PATCH 25/35] btrfs-progs: Add utility to dump all superblocks found
on a device.
Signed-off-by: David Marcin <djmarcin@google.com>
---
.gitignore | 4 ++
Makefile | 9 ++++-
btrfs-dump-super.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 98 insertions(+), 2 deletions(-)
create mode 100644 btrfs-dump-super.c
Index: btrfs-progs-v0.19-117-g6da41f2/.gitignore
===================================================================
--- btrfs-progs-v0.19-117-g6da41f2.orig/.gitignore
+++ btrfs-progs-v0.19-117-g6da41f2/.gitignore
@@ -3,12 +3,16 @@
version.h
man/*.gz
btrfs
+btrfs-corrupt-block
btrfs-debug-tree
+btrfs-dump-super
btrfs-map-logical
+btrfs-select-super
btrfs-show
btrfs-vol
btrfsck
btrfsctl
+calc-size
find-root
mkfs.btrfs
repair
Index: btrfs-progs-v0.19-117-g6da41f2/Makefile
===================================================================
--- btrfs-progs-v0.19-117-g6da41f2.orig/Makefile
+++ btrfs-progs-v0.19-117-g6da41f2/Makefile
@@ -17,7 +17,8 @@ LIBS=-luuid
RESTORE_LIBS=-lz
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
- btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block
+ btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block \
+ btrfs-dump-super
btrfs_man_page_source = btrfs.c btrfs_cmds.c scrub.c
@@ -76,6 +77,9 @@ btrfs-zero-log: $(objects) btrfs-zero-lo
btrfs-select-super: $(objects) btrfs-select-super.o
$(CC) $(CFLAGS) -o btrfs-select-super $(objects) btrfs-select-super.o $(LDFLAGS) $(LIBS)
+btrfs-dump-super: $(objects) btrfs-dump-super.o
+ $(CC) $(CFLAGS) -o btrfs-dump-super $(objects) btrfs-dump-super.o $(LDFLAGS) $(LIBS)
+
btrfstune: $(objects) btrfstune.o
$(CC) $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
@@ -128,7 +132,8 @@ install-man:
clean :
rm -f man/btrfs.8.in
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
+ btrfs-dump-super btrfs-zero-log btrfstune dir-test ioctl-test quick-test \
+ version.h
rm -f helpmsg.c
cd man; make clean
Index: btrfs-progs-v0.19-117-g6da41f2/btrfs-dump-super.c
===================================================================
--- /dev/null
+++ btrfs-progs-v0.19-117-g6da41f2/btrfs-dump-super.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 Google. 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "kerncompat.h"
+#include "ctree.h"
+#include "disk-io.h"
+#include "version.h"
+
+static void print_usage(void)
+{
+ fprintf(stderr, "usage: btrfs-dump-super dev\n");
+ fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
+ exit(1);
+}
+
+static int read_block(const char* filename, u64 bytenr, struct btrfs_super_block* sb) {
+ int fd = open(filename, O_RDONLY, 0600);
+ int block_size = sizeof(struct btrfs_super_block);
+ int bytes_read = 0;
+
+ if (fd < 0) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ return -1;
+ }
+
+ bytes_read = pread(fd, sb, block_size, bytenr);
+ if (bytes_read < block_size) {
+ fprintf(stderr, "Only read %d bytes of %d.\n", bytes_read, block_size);
+ }
+
+ close(fd);
+ return bytes_read;
+}
+
+int main(int ac, char **av)
+{
+ int i;
+
+ if (ac != 2)
+ print_usage();
+
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ u64 bytenr = btrfs_sb_offset(i);
+ int fd;
+ struct btrfs_super_block sb;
+ int block_size = sizeof(struct btrfs_super_block);
+ char filename[1024];
+ int bytes_read = read_block(av[optind], bytenr, &sb);
+ if (bytes_read < block_size)
+ continue;
+
+ sprintf(filename, "/tmp/block.%s.%llu",
+ strrchr(av[optind], '/') + 1, bytenr);
+ fd = open(filename, O_CREAT|O_WRONLY, 0644);
+ if (block_size != pwrite(fd, &sb, block_size, 0)) {
+ fprintf(stderr, "Failed to dump superblock %d", i);
+ continue;
+ }
+ fprintf(stderr, "Dumped superblock %s:%d, gen %llu to %s.\n",
+ av[optind], i, sb.generation, filename);
+ close(fd);
+ }
+
+ return 0;
+}

View File

@ -1,179 +0,0 @@
From 6330d8d3b70c0ad35ce8048ccf69b3e96718ed53 Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Mon, 21 Nov 2011 20:31:01 -0600
Subject: [PATCH 26/35] btrfs-progs: Add the ability to use the earliest super
found when opening the ctree.
Signed-off-by: David Marcin <djmarcin@google.com>
---
convert.c | 6 +++---
disk-io.c | 21 ++++++++++++++-------
disk-io.h | 2 +-
volumes.c | 9 ++++++++-
volumes.h | 6 +++++-
5 files changed, 31 insertions(+), 13 deletions(-)
diff --git a/convert.c b/convert.c
index 291dc27..c036f46 100644
--- a/convert.c
+++ b/convert.c
@@ -2386,7 +2386,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "unable to update system chunk\n");
goto fail;
}
- root = open_ctree_fd(fd, devname, super_bytenr, O_RDWR);
+ root = open_ctree_fd(fd, devname, super_bytenr, O_RDWR, 0);
if (!root) {
fprintf(stderr, "unable to open ctree\n");
goto fail;
@@ -2447,7 +2447,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
goto fail;
}
- root = open_ctree_fd(fd, devname, 0, O_RDWR);
+ root = open_ctree_fd(fd, devname, 0, O_RDWR, 0);
if (!root) {
fprintf(stderr, "unable to open ctree\n");
goto fail;
@@ -2546,7 +2546,7 @@ int do_rollback(const char *devname, int force)
fprintf(stderr, "unable to open %s\n", devname);
goto fail;
}
- root = open_ctree_fd(fd, devname, 0, O_RDWR);
+ root = open_ctree_fd(fd, devname, 0, O_RDWR, 0);
if (!root) {
fprintf(stderr, "unable to open ctree\n");
goto fail;
diff --git a/disk-io.c b/disk-io.c
index 408b2d5..a161f15 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -580,7 +580,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
return fs_info->dev_root;
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
return fs_info->csum_root;
-
+
BUG_ON(location->objectid == BTRFS_TREE_RELOC_OBJECTID ||
location->offset != (u64)-1);
@@ -602,7 +602,8 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
}
struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
- u64 root_tree_bytenr, int writes)
+ u64 root_tree_bytenr, int writes,
+ int use_earliest_bdev)
{
u32 sectorsize;
u32 nodesize;
@@ -677,8 +678,14 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
fs_info->super_bytenr = sb_bytenr;
disk_super = &fs_info->super_copy;
- ret = btrfs_read_dev_super(fs_devices->latest_bdev,
- disk_super, sb_bytenr);
+ if (use_earliest_bdev) {
+ ret = btrfs_read_dev_super(fs_devices->earliest_bdev,
+ disk_super, sb_bytenr);
+ } else {
+ ret = btrfs_read_dev_super(fs_devices->latest_bdev,
+ disk_super, sb_bytenr);
+ }
+
if (ret) {
printk("No valid btrfs found\n");
goto out_devices;
@@ -847,7 +854,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
fprintf (stderr, "Could not open %s\n", filename);
return NULL;
}
- root = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes);
+ root = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, 0);
close(fp);
return root;
@@ -871,9 +878,9 @@ struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
}
struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
- int writes)
+ int writes, int use_earliest_bdev)
{
- return __open_ctree_fd(fp, path, sb_bytenr, 0, writes);
+ return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev);
}
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr)
diff --git a/disk-io.h b/disk-io.h
index 2048fcf..8fdcd91 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -45,7 +45,7 @@ int clean_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf);
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 writes, int use_earliest_bdev);
struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
u64 root_tree_bytenr);
int close_ctree(struct btrfs_root *root);
diff --git a/volumes.c b/volumes.c
index 03bfb8c..cde20ad 100644
--- a/volumes.c
+++ b/volumes.c
@@ -99,6 +99,8 @@ static int device_list_add(const char *path,
memcpy(fs_devices->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
fs_devices->latest_devid = devid;
fs_devices->latest_trans = found_transid;
+ fs_devices->earliest_devid = devid;
+ fs_devices->earliest_trans = found_transid;
fs_devices->lowest_devid = (u64)-1;
device = NULL;
} else {
@@ -133,8 +135,11 @@ static int device_list_add(const char *path,
if (found_transid > fs_devices->latest_trans) {
fs_devices->latest_devid = devid;
fs_devices->latest_trans = found_transid;
+ } else if (found_transid < fs_devices->earliest_trans) {
+ fs_devices->earliest_devid = devid;
+ fs_devices->earliest_trans = found_transid;
}
- if (fs_devices->lowest_devid > devid) {
+ if (devid < fs_devices->lowest_devid) {
fs_devices->lowest_devid = devid;
}
*fs_devices_ret = fs_devices;
@@ -183,6 +188,8 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int flags)
if (device->devid == fs_devices->latest_devid)
fs_devices->latest_bdev = fd;
+ if (device->devid == fs_devices->earliest_devid)
+ fs_devices->earliest_bdev = fd;
if (device->devid == fs_devices->lowest_devid)
fs_devices->lowest_bdev = fd;
device->fd = fd;
diff --git a/volumes.h b/volumes.h
index 7104d36..08c53e4 100644
--- a/volumes.h
+++ b/volumes.h
@@ -64,11 +64,15 @@ struct btrfs_device {
struct btrfs_fs_devices {
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
- /* the device with this id has the most recent coyp of the super */
+ /* the device with this id has the most recent copy of the super */
u64 latest_devid;
u64 latest_trans;
+ /* the device with this id has the least recent copy of the super */
+ u64 earliest_devid;
+ u64 earliest_trans;
u64 lowest_devid;
int latest_bdev;
+ int earliest_bdev;
int lowest_bdev;
struct list_head devices;
struct list_head list;
--
1.7.6.233.gd79bc

View File

@ -1,111 +0,0 @@
From a780325614c0d89c9c0ea6779ada5af512b6e319 Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Tue, 22 Nov 2011 10:09:35 -0800
Subject: [PATCH 27/35] btrfs-progs: Use oldest super for btrfs-select-super.
Add required confirmation to btrfs-select-super.
Signed-off-by: David Marcin <djmarcin@google.com>
---
btrfs-select-super.c | 38 ++++++++++++++++++++++++++++++--------
disk-io.c | 2 +-
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/btrfs-select-super.c b/btrfs-select-super.c
index 51eb9c9..4d27f1b 100644
--- a/btrfs-select-super.c
+++ b/btrfs-select-super.c
@@ -34,7 +34,9 @@
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-select-super -s number dev\n");
+ fprintf(stderr, "usage: btrfs-select-super [-c] [-e] -s number dev\n");
+ fprintf(stderr, " -c Commit changes to disk [IRREVERSIBLE]\n");
+ fprintf(stderr, " -e Use the earliest super found, may help recover transid verify problems\n");
fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
exit(1);
}
@@ -45,10 +47,13 @@ int main(int ac, char **av)
int ret;
int num;
u64 bytenr = 0;
+ int commit = 0;
+ int use_lowest_bdev = 0;
+ int fp;
while(1) {
int c;
- c = getopt(ac, av, "s:");
+ c = getopt(ac, av, "s:ce");
if (c < 0)
break;
switch(c) {
@@ -58,6 +63,12 @@ int main(int ac, char **av)
printf("using SB copy %d, bytenr %llu\n", num,
(unsigned long long)bytenr);
break;
+ case 'c':
+ commit = 1;
+ break;
+ case 'e':
+ use_earliest_bdev = 1;
+ break;
default:
print_usage();
}
@@ -74,22 +85,33 @@ int main(int ac, char **av)
radix_tree_init();
- if((ret = check_mounted(av[optind])) < 0) {
+ if ((ret = check_mounted(av[optind])) < 0) {
fprintf(stderr, "Could not check mount status: %s\n", strerror(-ret));
return ret;
- } else if(ret) {
+ } else if (ret) {
fprintf(stderr, "%s is currently mounted. Aborting.\n", av[optind]);
return -EBUSY;
}
- root = open_ctree(av[optind], bytenr, 1);
+ fp = open(av[optind], O_CREAT|O_RDRW, 0600);
+ if (fp < 0) {
+ fprintf(stderr, "Could not open %s\n", av[optind]);
+ return 1;
+ }
+ root = open_ctree_fd(fp, av[optind], bytenr, 1, use_earliest_bdev);
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);
+ fprintf(stderr, "Found superblock with generation %llu.\n", root->fs_info->super_copy.generation);
+
+ if (commit) {
+ fprintf(stderr, "Committing...\n");
+
+ /* 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
diff --git a/disk-io.c b/disk-io.c
index a161f15..9585057 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -871,7 +871,7 @@ struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
fprintf (stderr, "Could not open %s\n", filename);
return NULL;
}
- root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0);
+ root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0, 0);
close(fp);
return root;
--
1.7.6.233.gd79bc

View File

@ -1,191 +0,0 @@
From 2fe46117d3cde3737a1600195883e63ab4c59a8d Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Fri, 2 Dec 2011 10:07:43 -0500
Subject: [PATCH 28/35] btrfs-progs: add lzo compression support to restore
This patch simply adds support to decompress lzo compressed extents in restore.
Signed-off-by: Josef Bacik <josef@redhat.com>
---
Makefile | 2 +-
restore.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile
index 548f88c..64de4e6 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ INSTALL = install
prefix ?= /usr/local
bindir = $(prefix)/bin
LIBS=-luuid
-RESTORE_LIBS=-lz
+RESTORE_LIBS=-lz -llzo2
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block \
diff --git a/restore.c b/restore.c
index e65746a..6433378 100644
--- a/restore.c
+++ b/restore.c
@@ -27,6 +27,8 @@
#include <zlib.h>
#include <sys/types.h>
#include <regex.h>
+#include <lzo/lzoconf.h>
+#include <lzo/lzo1x.h>
#include "kerncompat.h"
#include "ctree.h"
#include "disk-io.h"
@@ -44,8 +46,12 @@ static int verbose = 0;
static int ignore_errors = 0;
static int overwrite = 0;
-static int decompress(char *inbuf, char *outbuf, u64 compress_len,
- u64 decompress_len)
+#define LZO_LEN 4
+#define PAGE_CACHE_SIZE 4096
+#define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3)
+
+static int decompress_zlib(char *inbuf, char *outbuf, u64 compress_len,
+ u64 decompress_len)
{
z_stream strm;
int ret;
@@ -71,6 +77,73 @@ static int decompress(char *inbuf, char *outbuf, u64 compress_len,
(void)inflateEnd(&strm);
return 0;
}
+static inline size_t read_compress_length(unsigned char *buf)
+{
+ __le32 dlen;
+ memcpy(&dlen, buf, LZO_LEN);
+ return le32_to_cpu(dlen);
+}
+
+static int decompress_lzo(unsigned char *inbuf, char *outbuf, u64 compress_len,
+ u64 *decompress_len)
+{
+ size_t new_len;
+ size_t in_len;
+ size_t out_len = 0;
+ size_t tot_len;
+ size_t tot_in;
+ int ret;
+
+ ret = lzo_init();
+ if (ret != LZO_E_OK) {
+ fprintf(stderr, "lzo init returned %d\n", ret);
+ return -1;
+ }
+
+ tot_len = read_compress_length(inbuf);
+ inbuf += LZO_LEN;
+ tot_in = LZO_LEN;
+
+ while (tot_in < tot_len) {
+ in_len = read_compress_length(inbuf);
+ inbuf += LZO_LEN;
+ tot_in += LZO_LEN;
+
+ new_len = lzo1x_worst_compress(PAGE_CACHE_SIZE);
+ ret = lzo1x_decompress_safe((const unsigned char *)inbuf, in_len,
+ (unsigned char *)outbuf, &new_len, NULL);
+ if (ret != LZO_E_OK) {
+ fprintf(stderr, "failed to inflate: %d\n", ret);
+ return -1;
+ }
+ out_len += new_len;
+ outbuf += new_len;
+ inbuf += in_len;
+ tot_in += in_len;
+ }
+
+ *decompress_len = out_len;
+
+ return 0;
+}
+
+static int decompress(char *inbuf, char *outbuf, u64 compress_len,
+ u64 *decompress_len, int compress)
+{
+ switch (compress) {
+ case BTRFS_COMPRESS_ZLIB:
+ return decompress_zlib(inbuf, outbuf, compress_len,
+ *decompress_len);
+ case BTRFS_COMPRESS_LZO:
+ return decompress_lzo((unsigned char *)inbuf, outbuf, compress_len,
+ decompress_len);
+ default:
+ break;
+ }
+
+ fprintf(stderr, "invalid compression type: %d\n", compress);
+ return -1;
+}
int next_leaf(struct btrfs_root *root, struct btrfs_path *path)
{
@@ -133,11 +206,11 @@ static int copy_one_inline(int fd, struct btrfs_path *path, u64 pos)
struct btrfs_file_extent_item *fi;
char buf[4096];
char *outbuf;
+ u64 ram_size;
ssize_t done;
unsigned long ptr;
int ret;
int len;
- int ram_size;
int compress;
fi = btrfs_item_ptr(leaf, path->slots[0],
@@ -165,7 +238,7 @@ static int copy_one_inline(int fd, struct btrfs_path *path, u64 pos)
return -1;
}
- ret = decompress(buf, outbuf, len, ram_size);
+ ret = decompress(buf, outbuf, len, &ram_size, compress);
if (ret) {
free(outbuf);
return ret;
@@ -174,7 +247,7 @@ static int copy_one_inline(int fd, struct btrfs_path *path, u64 pos)
done = pwrite(fd, outbuf, ram_size, pos);
free(outbuf);
if (done < len) {
- fprintf(stderr, "Short compressed inline write, wanted %d, "
+ fprintf(stderr, "Short compressed inline write, wanted %Lu, "
"did %zd: %d\n", ram_size, done, errno);
return -1;
}
@@ -196,6 +269,7 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
u64 length;
u64 size_left;
u64 dev_bytenr;
+ u64 offset;
u64 count = 0;
int compress;
int ret;
@@ -207,8 +281,11 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
disk_size = btrfs_file_extent_disk_num_bytes(leaf, fi);
ram_size = btrfs_file_extent_ram_bytes(leaf, fi);
+ offset = btrfs_file_extent_offset(leaf, fi);
size_left = disk_size;
+ if (offset)
+ printf("offset is %Lu\n", offset);
/* we found a hole */
if (disk_size == 0)
return 0;
@@ -282,7 +359,7 @@ again:
goto out;
}
- ret = decompress(inbuf, outbuf, disk_size, ram_size);
+ ret = decompress(inbuf, outbuf, disk_size, &ram_size, compress);
if (ret) {
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
bytenr, length);
--
1.7.6.233.gd79bc

View File

@ -1,31 +0,0 @@
From 1b8b3c3579ee127b174a850213df7ad81edd5710 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Fri, 2 Dec 2011 12:52:15 -0500
Subject: [PATCH 29/35] btrfs-progs: fix regexec to only work if we actually
have a regexec
We were unconditionally executing our regular expression, even though we may not
have one, so check to make sure mreg is not null before calling regexec.
Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/restore.c b/restore.c
index 6433378..a4ccb18 100644
--- a/restore.c
+++ b/restore.c
@@ -638,7 +638,7 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
/* full path from root of btrfs being restored */
snprintf(fs_name, 4096, "%s/%s", dir, filename);
- if (REG_NOMATCH == regexec(mreg, fs_name, 0, NULL, 0))
+ if (mreg && REG_NOMATCH == regexec(mreg, fs_name, 0, NULL, 0))
goto next;
/* full path from system root */
--
1.7.6.233.gd79bc

View File

@ -1,36 +0,0 @@
From 3ceceda914e19a3f7982c5050e6ffb23522071f2 Mon Sep 17 00:00:00 2001
From: David Marcin <djmarcin@google.com>
Date: Tue, 6 Dec 2011 12:14:54 -0800
Subject: [PATCH 30/35] btrfs-progs: Fix compilation errors with
btrfs-select-super.c introduced by refactoring.
Signed-off-by: David Marcin <djmarcin@google.com>
---
btrfs-select-super.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/btrfs-select-super.c b/btrfs-select-super.c
index 4d27f1b..079986a 100644
--- a/btrfs-select-super.c
+++ b/btrfs-select-super.c
@@ -48,7 +48,7 @@ int main(int ac, char **av)
int num;
u64 bytenr = 0;
int commit = 0;
- int use_lowest_bdev = 0;
+ int use_earliest_bdev = 0;
int fp;
while(1) {
@@ -93,7 +93,7 @@ int main(int ac, char **av)
return -EBUSY;
}
- fp = open(av[optind], O_CREAT|O_RDRW, 0600);
+ fp = open(av[optind], O_CREAT|O_RDWR, 0600);
if (fp < 0) {
fprintf(stderr, "Could not open %s\n", av[optind]);
return 1;
--
1.7.6.233.gd79bc

View File

@ -1,443 +0,0 @@
From fb0cfed5d3500e76ce30c6a9803ee1720bf1b4a5 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 7 Dec 2011 14:13:35 -0500
Subject: [PATCH 31/35] Btrfs-progs: fix restore to fall back to the broken
open_ctree
We don't need most of the roots when doing restore, like the extent tree. So if
the recovery open_ctree fails because it's trying to open one of these useless
roots just fall back to open_ctree_broken. This will just open the chunk root
which is the bare minimum of what we need to operate. Then from there we can
setup the tree_root and the fs_root, and if either of those are gone we can't
restore anyway. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
disk-io.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++
disk-io.h | 1 +
find-root.c | 166 -----------------------------------------------------------
restore.c | 48 +++++++++++++++++-
4 files changed, 198 insertions(+), 167 deletions(-)
diff --git a/disk-io.c b/disk-io.c
index 9585057..8a8071c 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -883,6 +883,156 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev);
}
+struct btrfs_root *open_ctree_broken(int fd, const char *device)
+{
+ u32 sectorsize;
+ u32 nodesize;
+ u32 leafsize;
+ u32 blocksize;
+ u32 stripesize;
+ u64 generation;
+ struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
+ int ret;
+ struct btrfs_super_block *disk_super;
+ struct btrfs_fs_devices *fs_devices = NULL;
+ u64 total_devs;
+ u64 features;
+
+ ret = btrfs_scan_one_device(fd, device, &fs_devices,
+ &total_devs, BTRFS_SUPER_INFO_OFFSET);
+
+ if (ret) {
+ fprintf(stderr, "No valid Btrfs found on %s\n", device);
+ goto out;
+ }
+
+ if (total_devs != 1) {
+ ret = btrfs_scan_for_fsid(fs_devices, total_devs, 1);
+ if (ret)
+ goto out;
+ }
+
+ memset(fs_info, 0, sizeof(*fs_info));
+ fs_info->tree_root = tree_root;
+ fs_info->extent_root = extent_root;
+ fs_info->chunk_root = chunk_root;
+ fs_info->dev_root = dev_root;
+ fs_info->csum_root = csum_root;
+
+ fs_info->readonly = 1;
+
+ extent_io_tree_init(&fs_info->extent_cache);
+ extent_io_tree_init(&fs_info->free_space_cache);
+ extent_io_tree_init(&fs_info->block_group_cache);
+ extent_io_tree_init(&fs_info->pinned_extents);
+ extent_io_tree_init(&fs_info->pending_del);
+ extent_io_tree_init(&fs_info->extent_ins);
+ cache_tree_init(&fs_info->fs_root_cache);
+
+ cache_tree_init(&fs_info->mapping_tree.cache_tree);
+
+ mutex_init(&fs_info->fs_mutex);
+ fs_info->fs_devices = fs_devices;
+ INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
+ INIT_LIST_HEAD(&fs_info->space_info);
+
+ __setup_root(4096, 4096, 4096, 4096, tree_root,
+ fs_info, BTRFS_ROOT_TREE_OBJECTID);
+
+ ret = btrfs_open_devices(fs_devices, O_RDONLY);
+ if (ret)
+ goto out_cleanup;
+
+ fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET;
+ disk_super = &fs_info->super_copy;
+ ret = btrfs_read_dev_super(fs_devices->latest_bdev,
+ disk_super, BTRFS_SUPER_INFO_OFFSET);
+ if (ret) {
+ printk("No valid btrfs found\n");
+ goto out_devices;
+ }
+
+ memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
+
+
+ features = btrfs_super_incompat_flags(disk_super) &
+ ~BTRFS_FEATURE_INCOMPAT_SUPP;
+ if (features) {
+ printk("couldn't open because of unsupported "
+ "option features (%Lx).\n", features);
+ goto out_devices;
+ }
+
+ features = btrfs_super_incompat_flags(disk_super);
+ if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) {
+ features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
+ btrfs_set_super_incompat_flags(disk_super, features);
+ }
+
+ nodesize = btrfs_super_nodesize(disk_super);
+ leafsize = btrfs_super_leafsize(disk_super);
+ sectorsize = btrfs_super_sectorsize(disk_super);
+ stripesize = btrfs_super_stripesize(disk_super);
+ tree_root->nodesize = nodesize;
+ tree_root->leafsize = leafsize;
+ tree_root->sectorsize = sectorsize;
+ tree_root->stripesize = stripesize;
+
+ ret = btrfs_read_sys_array(tree_root);
+ if (ret)
+ goto out_devices;
+ blocksize = btrfs_level_size(tree_root,
+ btrfs_super_chunk_root_level(disk_super));
+ generation = btrfs_super_chunk_root_generation(disk_super);
+
+ __setup_root(nodesize, leafsize, sectorsize, stripesize,
+ chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
+
+ chunk_root->node = read_tree_block(chunk_root,
+ btrfs_super_chunk_root(disk_super),
+ blocksize, generation);
+ if (!chunk_root->node) {
+ printk("Couldn't read chunk root\n");
+ goto out_devices;
+ }
+
+ read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid,
+ (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
+ BTRFS_UUID_SIZE);
+
+ if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) {
+ ret = btrfs_read_chunk_tree(chunk_root);
+ if (ret)
+ goto out_chunk;
+ }
+
+ return fs_info->chunk_root;
+out_chunk:
+ free_extent_buffer(fs_info->chunk_root->node);
+out_devices:
+ close_all_devices(fs_info);
+out_cleanup:
+ extent_io_tree_cleanup(&fs_info->extent_cache);
+ extent_io_tree_cleanup(&fs_info->free_space_cache);
+ extent_io_tree_cleanup(&fs_info->block_group_cache);
+ extent_io_tree_cleanup(&fs_info->pinned_extents);
+ extent_io_tree_cleanup(&fs_info->pending_del);
+ extent_io_tree_cleanup(&fs_info->extent_ins);
+out:
+ free(tree_root);
+ free(extent_root);
+ free(chunk_root);
+ free(dev_root);
+ free(csum_root);
+ free(fs_info);
+ return NULL;
+}
+
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr)
{
u8 fsid[BTRFS_FSID_SIZE];
diff --git a/disk-io.h b/disk-io.h
index 8fdcd91..2b1fcd5 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -48,6 +48,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int writes, int use_earliest_bdev);
struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
u64 root_tree_bytenr);
+struct btrfs_root *open_ctree_broken(int fd, const char *device);
int close_ctree(struct btrfs_root *root);
int write_all_supers(struct btrfs_root *root);
int write_ctree_super(struct btrfs_trans_handle *trans,
diff --git a/find-root.c b/find-root.c
index bd44e1f..e0bc069 100644
--- a/find-root.c
+++ b/find-root.c
@@ -92,172 +92,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
return 0;
}
-static int close_all_devices(struct btrfs_fs_info *fs_info)
-{
- struct list_head *list;
- struct list_head *next;
- struct btrfs_device *device;
-
- return 0;
-
- list = &fs_info->fs_devices->devices;
- list_for_each(next, list) {
- device = list_entry(next, struct btrfs_device, dev_list);
- close(device->fd);
- }
- return 0;
-}
-
-static struct btrfs_root *open_ctree_broken(int fd, const char *device)
-{
- u32 sectorsize;
- u32 nodesize;
- u32 leafsize;
- u32 blocksize;
- u32 stripesize;
- u64 generation;
- struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root));
- struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
- struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root));
- struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root));
- struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root));
- struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
- int ret;
- struct btrfs_super_block *disk_super;
- struct btrfs_fs_devices *fs_devices = NULL;
- u64 total_devs;
- u64 features;
-
- ret = btrfs_scan_one_device(fd, device, &fs_devices,
- &total_devs, BTRFS_SUPER_INFO_OFFSET);
-
- if (ret) {
- fprintf(stderr, "No valid Btrfs found on %s\n", device);
- goto out;
- }
-
- if (total_devs != 1) {
- ret = btrfs_scan_for_fsid(fs_devices, total_devs, 1);
- if (ret)
- goto out;
- }
-
- memset(fs_info, 0, sizeof(*fs_info));
- fs_info->tree_root = tree_root;
- fs_info->extent_root = extent_root;
- fs_info->chunk_root = chunk_root;
- fs_info->dev_root = dev_root;
- fs_info->csum_root = csum_root;
-
- fs_info->readonly = 1;
-
- extent_io_tree_init(&fs_info->extent_cache);
- extent_io_tree_init(&fs_info->free_space_cache);
- extent_io_tree_init(&fs_info->block_group_cache);
- extent_io_tree_init(&fs_info->pinned_extents);
- extent_io_tree_init(&fs_info->pending_del);
- extent_io_tree_init(&fs_info->extent_ins);
- cache_tree_init(&fs_info->fs_root_cache);
-
- cache_tree_init(&fs_info->mapping_tree.cache_tree);
-
- mutex_init(&fs_info->fs_mutex);
- fs_info->fs_devices = fs_devices;
- INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
- INIT_LIST_HEAD(&fs_info->space_info);
-
- __setup_root(4096, 4096, 4096, 4096, tree_root,
- fs_info, BTRFS_ROOT_TREE_OBJECTID);
-
- ret = btrfs_open_devices(fs_devices, O_RDONLY);
- if (ret)
- goto out_cleanup;
-
- fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET;
- disk_super = &fs_info->super_copy;
- ret = btrfs_read_dev_super(fs_devices->latest_bdev,
- disk_super, BTRFS_SUPER_INFO_OFFSET);
- if (ret) {
- printk("No valid btrfs found\n");
- goto out_devices;
- }
-
- memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
-
-
- features = btrfs_super_incompat_flags(disk_super) &
- ~BTRFS_FEATURE_INCOMPAT_SUPP;
- if (features) {
- printk("couldn't open because of unsupported "
- "option features (%Lx).\n", features);
- goto out_devices;
- }
-
- features = btrfs_super_incompat_flags(disk_super);
- if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) {
- features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
- btrfs_set_super_incompat_flags(disk_super, features);
- }
-
- nodesize = btrfs_super_nodesize(disk_super);
- leafsize = btrfs_super_leafsize(disk_super);
- sectorsize = btrfs_super_sectorsize(disk_super);
- stripesize = btrfs_super_stripesize(disk_super);
- tree_root->nodesize = nodesize;
- tree_root->leafsize = leafsize;
- tree_root->sectorsize = sectorsize;
- tree_root->stripesize = stripesize;
-
- ret = btrfs_read_sys_array(tree_root);
- if (ret)
- goto out_devices;
- blocksize = btrfs_level_size(tree_root,
- btrfs_super_chunk_root_level(disk_super));
- generation = btrfs_super_chunk_root_generation(disk_super);
-
- __setup_root(nodesize, leafsize, sectorsize, stripesize,
- chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
-
- chunk_root->node = read_tree_block(chunk_root,
- btrfs_super_chunk_root(disk_super),
- blocksize, generation);
- if (!chunk_root->node) {
- printk("Couldn't read chunk root\n");
- goto out_devices;
- }
-
- read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid,
- (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
- BTRFS_UUID_SIZE);
-
- if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) {
- ret = btrfs_read_chunk_tree(chunk_root);
- if (ret)
- goto out_chunk;
- }
-
- return fs_info->chunk_root;
-out_chunk:
- free_extent_buffer(fs_info->chunk_root->node);
-out_devices:
- close_all_devices(fs_info);
-out_cleanup:
- extent_io_tree_cleanup(&fs_info->extent_cache);
- extent_io_tree_cleanup(&fs_info->free_space_cache);
- extent_io_tree_cleanup(&fs_info->block_group_cache);
- extent_io_tree_cleanup(&fs_info->pinned_extents);
- extent_io_tree_cleanup(&fs_info->pending_del);
- extent_io_tree_cleanup(&fs_info->extent_ins);
-out:
- free(tree_root);
- free(extent_root);
- free(chunk_root);
- free(dev_root);
- free(csum_root);
- free(fs_info);
- return NULL;
-}
-
static int dump_root_bytenr(struct btrfs_root *root, u64 bytenr, u64 gen)
{
struct btrfs_root *tmp = malloc(sizeof(struct btrfs_root));
diff --git a/restore.c b/restore.c
index a4ccb18..90d54e4 100644
--- a/restore.c
+++ b/restore.c
@@ -779,9 +779,13 @@ static void usage()
static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror)
{
+ struct btrfs_key key;
struct btrfs_root *root;
u64 bytenr;
+ u64 generation;
+ u32 blocksize;
int i;
+ int dev_fd;
for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) {
bytenr = btrfs_sb_offset(i);
@@ -791,7 +795,49 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
fprintf(stderr, "Could not open root, trying backup super\n");
}
- return NULL;
+ fprintf(stderr, "Ok couldn't open the root the normal way, trying "
+ "the broken way\n");
+
+ dev_fd = open(dev, O_RDONLY);
+ if (dev_fd < 0) {
+ fprintf(stderr, "Failed to open device %s\n", dev);
+ return NULL;
+ }
+
+ root = open_ctree_broken(dev_fd, dev);
+ close(dev_fd);
+ if (!root) {
+ fprintf(stderr, "Broken ctree open failed\n");
+ return NULL;
+ }
+ if (!root_location)
+ bytenr = btrfs_super_root(&root->fs_info->super_copy);
+
+ blocksize = btrfs_level_size(root,
+ btrfs_super_root_level(&root->fs_info->super_copy));
+ generation = btrfs_super_generation(&root->fs_info->super_copy);
+
+ root->fs_info->tree_root->node = read_tree_block(root, bytenr,
+ blocksize,
+ generation);
+ if (!root->fs_info->tree_root->node) {
+ fprintf(stderr, "Couldn't read tree node\n");
+ close_ctree(root);
+ return NULL;
+ }
+
+ key.objectid = BTRFS_FS_TREE_OBJECTID;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+ root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
+ if (!root->fs_info->fs_root) {
+ fprintf(stderr, "Couldn't read fs_root\n");
+ close_ctree(root);
+ return NULL;
+ }
+
+ return root->fs_info->fs_root;
}
static int find_first_dir(struct btrfs_root *root, u64 *objectid)
--
1.7.6.233.gd79bc

View File

@ -1,32 +0,0 @@
From 412d4f1fe3a14c7e61efbd0ad4280323de71606a Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 7 Dec 2011 15:54:13 -0500
Subject: [PATCH 32/35] Btrfs-progs: don't bug out if we can't find the last
root
Return an error instead of BUG()'ing out.
Signed-off-by: Josef Bacik <josef@redhat.com>
---
root-tree.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/root-tree.c b/root-tree.c
index 782472c..7a6ae0a 100644
--- a/root-tree.c
+++ b/root-tree.c
@@ -43,6 +43,11 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
BUG_ON(ret == 0);
l = path->nodes[0];
+ if (path->slots[0] == 0) {
+ ret = -ENOENT;
+ goto out;
+ }
+
BUG_ON(path->slots[0] == 0);
slot = path->slots[0] - 1;
btrfs_item_key_to_cpu(l, &found_key, slot);
--
1.7.6.233.gd79bc

View File

@ -1,37 +0,0 @@
From df8b44a2980ace8b2e7483b96a661907e20b8a4c Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 7 Dec 2011 16:11:23 -0500
Subject: [PATCH 33/35] Btrfs-progs: make find_and_setup_root return an error
Don't BUG(), return an error so the recovery program can work its mojo.
Signed-off-by: Josef Bacik <josef@redhat.com>
---
disk-io.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/disk-io.c b/disk-io.c
index 8a8071c..b0b9502 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -438,13 +438,15 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
root, fs_info, objectid);
ret = btrfs_find_last_root(tree_root, objectid,
&root->root_item, &root->root_key);
- BUG_ON(ret);
+ if (ret)
+ return ret;
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
generation = btrfs_root_generation(&root->root_item);
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
- BUG_ON(!root->node);
+ if (!root->node)
+ return -ENOENT;
return 0;
}
--
1.7.6.233.gd79bc

View File

@ -1,31 +0,0 @@
From 4686f96637316b509cb16c657b73b40a329be6db Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Thu, 8 Dec 2011 17:24:54 -0500
Subject: [PATCH 34/35] Btrfs-progs: check return value properly
We were checking for a null root coming back from btrfs_read_fs_root but thats
not right since it returns a ERR_PTR. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/restore.c b/restore.c
index 90d54e4..398c49a 100644
--- a/restore.c
+++ b/restore.c
@@ -831,8 +831,8 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
key.offset = (u64)-1;
root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
- if (!root->fs_info->fs_root) {
- fprintf(stderr, "Couldn't read fs_root\n");
+ if (IS_ERR(root->fs_info->fs_root)) {
+ fprintf(stderr, "Couldn't read fs_root: %d\n", PTR_ERR(root));
close_ctree(root);
return NULL;
}
--
1.7.6.233.gd79bc

View File

@ -1,180 +0,0 @@
From 9bb7aa76e43f4942f5fa398bf00778067859f66c Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Fri, 9 Dec 2011 14:09:18 -0500
Subject: [PATCH 35/35] Btrfs-progs: give restore a list roots option
Since restore has the ability to open really really screwed up file systems, add
a list roots option to it so we can still get the contents of the tree root on a
horribly broken fs. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/restore.c b/restore.c
index 398c49a..95daef2 100644
--- a/restore.c
+++ b/restore.c
@@ -773,11 +773,71 @@ next:
static void usage()
{
- fprintf(stderr, "Usage: restore [-svioc] [-t disk offset] "
+ fprintf(stderr, "Usage: restore [-sviocl] [-t disk offset] "
"[-m regex] <device> <directory>\n");
}
-static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror)
+static int do_list_roots(struct btrfs_root *root)
+{
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct btrfs_disk_key disk_key;
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_root_item ri;
+ unsigned long offset;
+ int slot;
+ int ret;
+
+ root = root->fs_info->tree_root;
+ path = btrfs_alloc_path();
+ if (!path) {
+ fprintf(stderr, "Failed to alloc path\n");
+ return -1;
+ }
+
+ key.offset = 0;
+ key.objectid = 0;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to do search %d\n", ret);
+ btrfs_free_path(path);
+ return -1;
+ }
+
+ while (1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret)
+ break;
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ }
+ btrfs_item_key(leaf, &disk_key, slot);
+ btrfs_disk_key_to_cpu(&found_key, &disk_key);
+ if (btrfs_key_type(&found_key) != BTRFS_ROOT_ITEM_KEY) {
+ path->slots[0]++;
+ continue;
+ }
+
+ offset = btrfs_item_ptr_offset(leaf, slot);
+ read_extent_buffer(leaf, &ri, offset, sizeof(ri));
+ printf(" tree ");
+ btrfs_print_key(&disk_key);
+ printf(" %Lu level %d\n", btrfs_root_bytenr(&ri),
+ btrfs_root_level(&ri));
+ path->slots[0]++;
+ }
+ btrfs_free_path(path);
+
+ return 0;
+}
+
+static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror, int list_roots)
{
struct btrfs_key key;
struct btrfs_root *root;
@@ -791,7 +851,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
bytenr = btrfs_sb_offset(i);
root = open_ctree_recovery(dev, bytenr, root_location);
if (root)
- return root;
+ goto out;
fprintf(stderr, "Could not open root, trying backup super\n");
}
@@ -826,16 +886,27 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
return NULL;
}
+ if (list_roots)
+ goto out;
+
key.objectid = BTRFS_FS_TREE_OBJECTID;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %d\n", PTR_ERR(root));
+ fprintf(stderr, "Couldn't read fs_root: %ld\n", PTR_ERR(root));
close_ctree(root);
return NULL;
}
+out:
+ if (list_roots) {
+ int ret = do_list_roots(root);
+ if (ret) {
+ root = NULL;
+ close_ctree(root);
+ }
+ }
return root->fs_info->fs_root;
}
@@ -917,8 +988,9 @@ int main(int argc, char **argv)
int match_cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
regex_t match_reg, *mreg = NULL;
char reg_err[256];
+ int list_roots = 0;
- while ((opt = getopt(argc, argv, "sviot:u:df:r:cm:")) != -1) {
+ while ((opt = getopt(argc, argv, "sviot:u:df:r:cm:l")) != -1) {
switch (opt) {
case 's':
get_snaps = 1;
@@ -975,13 +1047,19 @@ int main(int argc, char **argv)
case 'm':
match_regstr = optarg;
break;
+ case 'l':
+ list_roots = 1;
+ break;
default:
usage();
exit(1);
}
}
- if (optind + 1 >= argc) {
+ if (!list_roots && optind + 1 >= argc) {
+ usage();
+ exit(1);
+ } else if (list_roots && optind >= argc) {
usage();
exit(1);
}
@@ -995,10 +1073,13 @@ int main(int argc, char **argv)
return -EBUSY;
}
- root = open_fs(argv[optind], tree_location, super_mirror);
+ root = open_fs(argv[optind], tree_location, super_mirror, list_roots);
if (root == NULL)
return 1;
+ if (list_roots)
+ goto out;
+
if (fs_location != 0) {
free_extent_buffer(root->node);
root->node = read_tree_block(root, fs_location, 4096, 0);
--
1.7.6.233.gd79bc

View File

@ -1,32 +0,0 @@
From 243a10fc066200621fbdee91eb28a53f5cc91d81 Mon Sep 17 00:00:00 2001
From: Tsutomu Itoh <t-itoh@jp.fujitsu.com>
Date: Tue, 1 Nov 2011 12:20:42 +0900
Subject: [PATCH 135/138] Btrfs-progs: fix compiler warning of extent-tree.c
In recovery-beta, following compiler warning was displayed.
gcc -Wp,-MMD,./.extent-tree.o.d,-MT,extent-tree.o -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -g -O0 -c extent-tree.c
extent-tree.c: In function 'lookup_inline_extent_backref':
extent-tree.c:1071: warning: format '%u' expects type 'unsigned int', but argument 3 has type 'long unsigned int'
Signed-off-by: Tsutomu Itoh <t-itoh@jp.fujitsu.com>
---
extent-tree.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/extent-tree.c b/extent-tree.c
index 5bed3c2..5144d57 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1068,7 +1068,7 @@ static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
#endif
if (item_size < sizeof(*ei)) {
printf("Size is %u, needs to be %u, slot %d\n", item_size,
- sizeof(*ei), path->slots[0]);
+ (u32)sizeof(*ei), path->slots[0]);
btrfs_print_leaf(root, leaf);
return -EINVAL;
}
--
1.7.6.233.gd79bc

View File

@ -1,130 +0,0 @@
From 6b74bd1ecd84d86cad6aaa1fd643de6f3f3c40b8 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Tue, 1 Nov 2011 23:27:39 +0200
Subject: [PATCH 136/138] Btrfs-progs: change the way mkfs picks raid profiles
Currently mkfs in response to
mkfs.btrfs -d raid10 dev1 dev2
instead of telling "you can't do that" creates a SINGLE on two devices,
and only rebalance can transform it to raid0. Generally, it never warns
users about decisions it makes and it's not at all obvious which profile
it picks when.
Fix this by checking the number of effective devices and reporting back
if the specified profile is impossible to create. Do not create FS in
case invalid profile was given.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
mkfs.c | 46 +++++++++++++++++++++++++++++++++++-----------
1 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/mkfs.c b/mkfs.c
index be236d0..d39c5a7 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -228,12 +228,26 @@ 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, int mixed)
+ int data_profile_opt, u64 metadata_profile,
+ int metadata_profile_opt, int mixed)
{
u64 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy);
u64 allowed;
int ret;
+ /*
+ * Set default profiles according to number of added devices.
+ * For mixed groups defaults are single/single.
+ */
+ if (!metadata_profile_opt && !mixed) {
+ metadata_profile = (num_devices > 1) ?
+ BTRFS_BLOCK_GROUP_RAID1 : BTRFS_BLOCK_GROUP_DUP;
+ }
+ if (!data_profile_opt && !mixed) {
+ data_profile = (num_devices > 1) ?
+ BTRFS_BLOCK_GROUP_RAID0 : 0; /* raid0 or single */
+ }
+
if (num_devices == 1)
allowed = BTRFS_BLOCK_GROUP_DUP;
else if (num_devices >= 4) {
@@ -242,6 +256,19 @@ static int create_raid_groups(struct btrfs_trans_handle *trans,
} else
allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1;
+ if (metadata_profile & ~allowed) {
+ fprintf(stderr, "unable to create FS with metadata "
+ "profile %llu (%llu devices)\n", metadata_profile,
+ num_devices);
+ exit(1);
+ }
+ if (data_profile & ~allowed) {
+ fprintf(stderr, "unable to create FS with data "
+ "profile %llu (%llu devices)\n", data_profile,
+ num_devices);
+ exit(1);
+ }
+
if (allowed & metadata_profile) {
u64 meta_flags = BTRFS_BLOCK_GROUP_METADATA;
@@ -326,15 +353,16 @@ static u64 parse_profile(char *s)
if (strcmp(s, "raid0") == 0) {
return BTRFS_BLOCK_GROUP_RAID0;
} else if (strcmp(s, "raid1") == 0) {
- return BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP;
+ return BTRFS_BLOCK_GROUP_RAID1;
} else if (strcmp(s, "raid10") == 0) {
- return BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP;
+ return BTRFS_BLOCK_GROUP_RAID10;
} else if (strcmp(s, "single") == 0) {
return 0;
} else {
fprintf(stderr, "Unknown option %s\n", s);
print_usage();
}
+ /* not reached */
return 0;
}
@@ -1172,8 +1200,8 @@ int main(int ac, char **av)
u64 dev_block_count = 0;
u64 blocks[7];
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 sectorsize = 4096;
u32 nodesize = leafsize;
@@ -1311,11 +1339,6 @@ int main(int ac, char **av)
}
}
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");
@@ -1400,7 +1423,8 @@ int main(int ac, char **av)
raid_groups:
if (!source_dir_set) {
ret = create_raid_groups(trans, root, data_profile,
- metadata_profile, mixed);
+ data_profile_opt, metadata_profile,
+ metadata_profile_opt, mixed);
BUG_ON(ret);
}
--
1.7.6.233.gd79bc

View File

@ -1,45 +0,0 @@
From 670b953e28c25f835b713a22b03b9b0f86d8e025 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Tue, 1 Nov 2011 23:47:22 +0200
Subject: [PATCH 137/138] Btrfs-progs: fail gracefully on error from
open_ctree()
Error checking block got moved mistakenly exposing us to a potential
segmentation fault.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
mkfs.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/mkfs.c b/mkfs.c
index d39c5a7..d4d13af 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -1359,7 +1359,12 @@ int main(int ac, char **av)
fprintf(stderr, "error during mkfs %d\n", ret);
exit(1);
}
+
root = open_ctree(file, 0, O_RDWR);
+ if (!root) {
+ fprintf(stderr, "ctree init failed\n");
+ return -1;
+ }
root->fs_info->alloc_start = alloc_start;
ret = make_root_dir(root, mixed);
@@ -1374,10 +1379,6 @@ int main(int ac, char **av)
goto raid_groups;
btrfs_register_one_device(file);
- if (!root) {
- fprintf(stderr, "ctree init failed\n");
- return -1;
- }
zero_end = 1;
while(ac-- > 0) {
--
1.7.6.233.gd79bc

View File

@ -1,32 +0,0 @@
From d439a663a5ba789f7542163317264a6b4dbbe3f2 Mon Sep 17 00:00:00 2001
From: Arne Jansen <sensille@gmx.net>
Date: Tue, 29 Nov 2011 08:40:28 +0100
Subject: [PATCH 138/138] Btrfs-progs: bugfix for scrubbing single devices
Scrub can be invoked to scrub only a single device of a (mounted) filesystem.
The code determines whether the given path is a mountpoint of a filesystem
by issueing a btrfs-specific ioctl to it. Only in case of EINVAL it assumed
it may be a device, all other errnos just caused it fail, but some devices
(correctly) return ENOTTY. This patch adds this to the error check.
Signed-off-by: Arne Jansen <sensille@gmx.net>
---
scrub.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/scrub.c b/scrub.c
index 66761c5..5b0bf16 100644
--- a/scrub.c
+++ b/scrub.c
@@ -987,7 +987,7 @@ static int scrub_fs_info(int fd, char *path,
memset(fi_args, 0, sizeof(*fi_args));
ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
- if (ret && errno == EINVAL) {
+ if (ret && (errno == EINVAL || errno == ENOTTY)) {
/* path is no mounted btrfs. try if it's a device */
ret = check_mounted_where(fd, path, mp, sizeof(mp),
&fs_devices_mnt);
--
1.7.6.233.gd79bc

View File

@ -1,34 +0,0 @@
From b36b23becb0d79faefd38da11b684a78b95243c9 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 09:56:06 -0500
Subject: [PATCH 36/43] Btrfs-progs: make find root spit out the size of the
disk
In order to figure out what exactly is broken on a fs we need to spit out the
current offset we are on and the size of the fs to know if the super is wrong
and we just need to ignore it, or if the offset we got is bad and we should just
keep searching. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/find-root.c b/find-root.c
index e0bc069..f9cb7ed 100644
--- a/find-root.c
+++ b/find-root.c
@@ -258,7 +258,9 @@ static int find_root(struct btrfs_root *root)
if (offset >
btrfs_super_total_bytes(&root->fs_info->super_copy)) {
- printf("Went past the fs size, exiting");
+ printf("Went past the fs size, exiting, offset=%Lu, "
+ "total_bytes=%Lu\n", offset,
+ btrfs_super_total_bytes(&root->fs_info->super_copy));
break;
}
if (offset >= (metadata_offset + metadata_size)) {
--
1.7.6.233.gd79bc

View File

@ -1,50 +0,0 @@
From d4d88fe3c9b393e2b21754237104c68a37123aa6 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:03:33 -0500
Subject: [PATCH 37/43] Btrfs-progs: add some verbose output to find-root
Trying to track down why we can't find roots, add some verbose output so we know
what chunks we're scanning and when we move to new chunks. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/find-root.c b/find-root.c
index f9cb7ed..484f85f 100644
--- a/find-root.c
+++ b/find-root.c
@@ -250,6 +250,10 @@ static int find_root(struct btrfs_root *root)
return ret;
offset = metadata_offset;
+ if (verbose)
+ printf("Checking metadata chunk %Lu, size %Lu\n",
+ metadata_offset, metadata_size);
+
while (1) {
u64 map_length = 4096;
u64 type;
@@ -264,6 +268,8 @@ static int find_root(struct btrfs_root *root)
break;
}
if (offset >= (metadata_offset + metadata_size)) {
+ if (verbose)
+ printf("Moving to the next metadata chunk\n");
err = btrfs_next_metadata(&root->fs_info->mapping_tree,
&metadata_offset,
&metadata_size);
@@ -272,6 +278,9 @@ static int find_root(struct btrfs_root *root)
break;
}
offset = metadata_offset;
+ if (verbose)
+ printf("Checking metadata chunk %Lu, size %Lu"
+ "\n", metadata_offset, metadata_size);
}
mirror_num = 1;
again:
--
1.7.6.233.gd79bc

View File

@ -1,46 +0,0 @@
From f0346659db85b826c14392f9a627d845ab47b7e2 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:36:41 -0500
Subject: [PATCH 38/43] Btrfs-progs: fix restore to actually use the root
location if specified
We were using the wrong variable for the root location if we specified -f when
doing restore. Fix this. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/restore.c b/restore.c
index 95daef2..0b75902 100644
--- a/restore.c
+++ b/restore.c
@@ -871,13 +871,13 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
return NULL;
}
if (!root_location)
- bytenr = btrfs_super_root(&root->fs_info->super_copy);
+ root_location = btrfs_super_root(&root->fs_info->super_copy);
blocksize = btrfs_level_size(root,
btrfs_super_root_level(&root->fs_info->super_copy));
generation = btrfs_super_generation(&root->fs_info->super_copy);
- root->fs_info->tree_root->node = read_tree_block(root, bytenr,
+ root->fs_info->tree_root->node = read_tree_block(root, root_location,
blocksize,
generation);
if (!root->fs_info->tree_root->node) {
@@ -895,7 +895,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %ld\n", PTR_ERR(root));
+ fprintf(stderr, "Couldn't read fs_root: %d\n", PTR_ERR(root));
close_ctree(root);
return NULL;
}
--
1.7.6.233.gd79bc

View File

@ -1,35 +0,0 @@
From a3958e5a851f8d0efeafe5946b8a32ea0fd45436 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:37:43 -0500
Subject: [PATCH 39/43] Btrfs-progs: remove the physical disk size check from
find-root
Our logical offsets may be beyond what we think the size of the disk is, so our
check is bogus, remove it. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)
diff --git a/find-root.c b/find-root.c
index 484f85f..43cb778 100644
--- a/find-root.c
+++ b/find-root.c
@@ -260,13 +260,6 @@ static int find_root(struct btrfs_root *root)
int mirror_num;
int num_copies;
- if (offset >
- btrfs_super_total_bytes(&root->fs_info->super_copy)) {
- printf("Went past the fs size, exiting, offset=%Lu, "
- "total_bytes=%Lu\n", offset,
- btrfs_super_total_bytes(&root->fs_info->super_copy));
- break;
- }
if (offset >= (metadata_offset + metadata_size)) {
if (verbose)
printf("Moving to the next metadata chunk\n");
--
1.7.6.233.gd79bc

View File

@ -1,34 +0,0 @@
From 5ec6eeaff067c706e5bb9fc3144e9bab4e50da1e Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:48:32 -0500
Subject: [PATCH 40/43] Btrfs-progs: fix error output and dont read from cache
If we have to build our fs_info by hand don't read from the cache when looking
for the fs_root just in case we set something up last time. Also actually print
the right error, not the root which is ok. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/restore.c b/restore.c
index 0b75902..abc66ca 100644
--- a/restore.c
+++ b/restore.c
@@ -893,9 +893,10 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
- root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
+ root->fs_info->fs_root = btrfs_read_fs_root_no_cache(root->fs_info, &key);
if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %d\n", PTR_ERR(root));
+ fprintf(stderr, "Couldn't read fs_root: %d\n",
+ PTR_ERR(root->fs_info->fs_root));
close_ctree(root);
return NULL;
}
--
1.7.6.233.gd79bc

View File

@ -1,32 +0,0 @@
From a657103b449bfae0cc67dc9d7153ee19c20d9115 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:50:31 -0500
Subject: [PATCH 41/43] Btrfs-progs: print the objectid of the root we find
when doing find-root
We need to know if we find a valid fs tree when doing find root, so print the
objectid of the roots we find when we find a tree root. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/find-root.c b/find-root.c
index 43cb778..bc7440a 100644
--- a/find-root.c
+++ b/find-root.c
@@ -138,7 +138,9 @@ static int dump_root_bytenr(struct btrfs_root *root, u64 bytenr, u64 gen)
offset = btrfs_item_ptr_offset(leaf, slot);
read_extent_buffer(leaf, &ri, offset, sizeof(ri));
- printf("Generation: %Lu Root bytenr: %Lu\n", gen, btrfs_root_bytenr(&ri));
+ printf("Generation: %Lu Root bytenr: %Lu "
+ "Root objectid: %Lu\n", gen,
+ btrfs_root_bytenr(&ri), found_key.objectid);
}
path->slots[0]++;
}
--
1.7.6.233.gd79bc

View File

@ -1,170 +0,0 @@
From 87edb6fbf4991e47e7563c4589197aa88befe266 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 11:50:55 -0500
Subject: [PATCH 42/43] Btrfs-progs: make specifying root objectid work if the
fs is broken
We need to be able to handle the case where we want to restore from a specific
root if the fs is really really really toast, this patch does that. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 109 +++++++++++++++++++++++++++++++++++++++----------------------
1 files changed, 70 insertions(+), 39 deletions(-)
diff --git a/restore.c b/restore.c
index abc66ca..5aa35ae 100644
--- a/restore.c
+++ b/restore.c
@@ -837,7 +837,35 @@ static int do_list_roots(struct btrfs_root *root)
return 0;
}
-static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror, int list_roots)
+static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
+ u32 stripesize, struct btrfs_root *root,
+ struct btrfs_fs_info *fs_info, u64 objectid)
+{
+ root->node = NULL;
+ root->commit_root = NULL;
+ root->sectorsize = sectorsize;
+ root->nodesize = nodesize;
+ root->leafsize = leafsize;
+ root->stripesize = stripesize;
+ root->ref_cows = 0;
+ root->track_dirty = 0;
+
+ root->fs_info = fs_info;
+ root->objectid = objectid;
+ root->last_trans = 0;
+ root->highest_inode = 0;
+ root->last_inode_alloc = 0;
+
+ INIT_LIST_HEAD(&root->dirty_list);
+ memset(&root->root_key, 0, sizeof(root->root_key));
+ memset(&root->root_item, 0, sizeof(root->root_item));
+ root->root_key.objectid = objectid;
+ return 0;
+}
+
+static struct btrfs_root *open_fs(const char *dev, u64 root_location,
+ u64 fs_location, u64 root_objectid,
+ int super_mirror, int list_roots)
{
struct btrfs_key key;
struct btrfs_root *root;
@@ -889,23 +917,51 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
if (list_roots)
goto out;
- key.objectid = BTRFS_FS_TREE_OBJECTID;
- key.type = BTRFS_ROOT_ITEM_KEY;
- key.offset = (u64)-1;
+ if (!root_objectid)
+ root_objectid = BTRFS_FS_TREE_OBJECTID;
- root->fs_info->fs_root = btrfs_read_fs_root_no_cache(root->fs_info, &key);
- if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %d\n",
- PTR_ERR(root->fs_info->fs_root));
- close_ctree(root);
- return NULL;
- }
out:
+ if (fs_location) {
+ struct btrfs_root *fs_root = root->fs_info->fs_root;
+ if (fs_root) {
+ free_extent_buffer(fs_root->node);
+ } else {
+ fs_root = malloc(sizeof(struct btrfs_root));
+ if (!fs_root) {
+ fprintf(stderr, "Out of memory\n");
+ close_ctree(root);
+ return NULL;
+ }
+ __setup_root(4096, 4096, 4096, 4096, fs_root,
+ root->fs_info, root_objectid);
+ root->fs_info->fs_root = fs_root;
+ }
+ fs_root->node = read_tree_block(root, fs_location, 4096, 0);
+ if (!fs_root->node) {
+ fprintf(stderr, "Failed to read fs location\n");
+ close_ctree(root);
+ return NULL;
+ }
+ } else if (root_objectid) {
+ key.objectid = root_objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+ root->fs_info->fs_root =
+ btrfs_read_fs_root_no_cache(root->fs_info, &key);
+ if (IS_ERR(root->fs_info->fs_root)) {
+ fprintf(stderr, "Error reading fs root %d\n",
+ PTR_ERR(root->fs_info->fs_root));
+ close_ctree(root);
+ return NULL;
+ }
+ }
+
if (list_roots) {
int ret = do_list_roots(root);
if (ret) {
- root = NULL;
close_ctree(root);
+ return NULL;
}
}
@@ -1074,22 +1130,14 @@ int main(int argc, char **argv)
return -EBUSY;
}
- root = open_fs(argv[optind], tree_location, super_mirror, list_roots);
+ root = open_fs(argv[optind], tree_location, fs_location, root_objectid,
+ super_mirror, list_roots);
if (root == NULL)
return 1;
if (list_roots)
goto out;
- if (fs_location != 0) {
- free_extent_buffer(root->node);
- root->node = read_tree_block(root, fs_location, 4096, 0);
- if (!root->node) {
- fprintf(stderr, "Failed to read fs location\n");
- goto out;
- }
- }
-
memset(path_name, 0, 4096);
strncpy(dir_name, argv[optind + 1], 128);
@@ -1102,23 +1150,6 @@ int main(int argc, char **argv)
dir_name[len - 1] = '\0';
}
- if (root_objectid != 0) {
- struct btrfs_root *orig_root = root;
-
- key.objectid = root_objectid;
- key.type = BTRFS_ROOT_ITEM_KEY;
- key.offset = (u64)-1;
- root = btrfs_read_fs_root(orig_root->fs_info, &key);
- if (IS_ERR(root)) {
- fprintf(stderr, "Error reading root\n");
- root = orig_root;
- ret = 1;
- goto out;
- }
- key.type = 0;
- key.offset = 0;
- }
-
if (find_dir) {
ret = find_first_dir(root, &key.objectid);
if (ret)
--
1.7.6.233.gd79bc

View File

@ -1,31 +0,0 @@
From 77ac61128a0722cab89c785f5f2247304133b214 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 11:55:43 -0500
Subject: [PATCH 43/43] Btrfs-progs: don't free the existing node
It may be used elsewhere and in the case of a broken fs it won't be there at all
and it makes an assertion trip. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/restore.c b/restore.c
index 5aa35ae..a2c2931 100644
--- a/restore.c
+++ b/restore.c
@@ -923,9 +923,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
out:
if (fs_location) {
struct btrfs_root *fs_root = root->fs_info->fs_root;
- if (fs_root) {
- free_extent_buffer(fs_root->node);
- } else {
+ if (!fs_root) {
fs_root = malloc(sizeof(struct btrfs_root));
if (!fs_root) {
fprintf(stderr, "Out of memory\n");
--
1.7.6.233.gd79bc

View File

@ -1,105 +0,0 @@
From 7e2b203768ae87b3614149e99e00afe4fa9394ab Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Thu, 26 Jan 2012 17:03:05 +0100
Subject: [PATCH] mkfs: Handle creation of filesystem larger than the first
device
make_btrfs() function takes a size of filesystem as an argument. It uses this
value to set the size of the first device as well which is wrong for
filesystems larger than this device. It results in 'attemp to access beyond end
of device' messages from the kernel. So add size of the first device as an
argument to make_btrfs().
CC: David Sterba <dsterba@suse.cz>
Signed-off-by: Jan Kara <jack@suse.cz>
---
convert.c | 2 +-
mkfs.c | 6 ++++--
utils.c | 4 ++--
utils.h | 2 +-
4 files changed, 8 insertions(+), 6 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/convert.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/convert.c
+++ btrfs-progs-v0.19-118-gfdb6c04/convert.c
@@ -2374,7 +2374,7 @@ int do_convert(const char *devname, int
goto fail;
}
ret = make_btrfs(fd, devname, ext2_fs->super->s_volume_name,
- blocks, total_bytes, blocksize, blocksize,
+ blocks, total_bytes, total_bytes, blocksize, blocksize,
blocksize, blocksize);
if (ret) {
fprintf(stderr, "unable to create initial ctree\n");
Index: btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/mkfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
@@ -1290,6 +1290,10 @@ int main(int ac, char **av)
ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, &mixed);
if (block_count == 0)
block_count = dev_block_count;
+ else if (block_count > dev_block_count) {
+ fprintf(stderr, "%s is smaller than requested size\n", file);
+ exit(1);
+ }
} else {
ac = 0;
file = av[optind++];
@@ -1302,8 +1306,10 @@ int main(int ac, char **av)
first_file = file;
source_dir_size = size_sourcedir(source_dir, sectorsize,
&num_of_meta_chunks, &size_of_data);
- if(block_count < source_dir_size)
+ if (block_count < source_dir_size)
block_count = source_dir_size;
+ dev_block_count = block_count;
+
ret = zero_output_file(fd, block_count, sectorsize);
if (ret) {
fprintf(stderr, "unable to zero the output file\n");
@@ -1329,7 +1335,7 @@ int main(int ac, char **av)
leafsize * i;
}
- ret = make_btrfs(fd, file, label, blocks, block_count,
+ ret = make_btrfs(fd, file, label, blocks, block_count, dev_block_count,
nodesize, leafsize,
sectorsize, stripesize);
if (ret) {
Index: btrfs-progs-v0.19-118-gfdb6c04/utils.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/utils.c
+++ btrfs-progs-v0.19-118-gfdb6c04/utils.c
@@ -74,7 +74,7 @@ static u64 reference_root_table[] = {
};
int make_btrfs(int fd, const char *device, const char *label,
- u64 blocks[7], u64 num_bytes, u32 nodesize,
+ u64 blocks[7], u64 num_bytes, u64 dev_num_bytes, u32 nodesize,
u32 leafsize, u32 sectorsize, u32 stripesize)
{
struct btrfs_super_block super;
@@ -276,7 +276,7 @@ int make_btrfs(int fd, const char *devic
dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item);
btrfs_set_device_id(buf, dev_item, 1);
btrfs_set_device_generation(buf, dev_item, 0);
- btrfs_set_device_total_bytes(buf, dev_item, num_bytes);
+ btrfs_set_device_total_bytes(buf, dev_item, dev_num_bytes);
btrfs_set_device_bytes_used(buf, dev_item,
BTRFS_MKFS_SYSTEM_GROUP_SIZE);
btrfs_set_device_io_align(buf, dev_item, sectorsize);
Index: btrfs-progs-v0.19-118-gfdb6c04/utils.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/utils.h
+++ btrfs-progs-v0.19-118-gfdb6c04/utils.h
@@ -22,7 +22,7 @@
#define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024)
int make_btrfs(int fd, const char *device, const char *label,
- u64 blocks[6], u64 num_bytes, u32 nodesize,
+ u64 blocks[6], u64 num_bytes, u64 dev_num_bytes, u32 nodesize,
u32 leafsize, u32 sectorsize, u32 stripesize);
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 objectid);

View File

@ -1,47 +0,0 @@
From c250b72ed982832cb8833dd962afed6ec7c5b27e Mon Sep 17 00:00:00 2001
From: Phillip Susi <psusi@cfl.rr.com>
Date: Mon, 9 Jan 2012 10:18:55 -0500
Subject: [PATCH 150/151] btrfs-progs: removed extraneous whitespace from mkfs
man page
There were extra spaces around some of the arguments in the man
page for mkfs.
Signed-off-by: Phillip Susi <psusi@cfl.rr.com>
---
man/mkfs.btrfs.8.in | 22 +++++++++++-----------
1 files changed, 11 insertions(+), 11 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/man/mkfs.btrfs.8.in
+++ btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
@@ -5,17 +5,17 @@ mkfs.btrfs \- create an btrfs filesystem
.B mkfs.btrfs
[ \fB\-A\fP\fI alloc-start\fP ]
[ \fB\-b\fP\fI byte-count\fP ]
-[ \fB \-d\fP\fI data-profile\fP ]
-[ \fB \-f\fP ]
-[ \fB \-l\fP\fI leafsize\fP ]
-[ \fB \-L\fP\fI label\fP ]
-[ \fB \-m\fP\fI metadata profile\fP ]
-[ \fB \-M\fP\fI mixed data+metadata\fP ]
-[ \fB \-n\fP\fI nodesize\fP ]
-[ \fB \-s\fP\fI sectorsize\fP ]
-[ \fB \-T\fP ]
-[ \fB \-h\fP ]
-[ \fB \-V\fP ] \fI device\fP [ \fI device ...\fP ]
+[ \fB\-d\fP\fI data-profile\fP ]
+[ \fB\-f\fP ]
+[ \fB\-l\fP\fI leafsize\fP ]
+[ \fB\-L\fP\fI label\fP ]
+[ \fB\-m\fP\fI metadata profile\fP ]
+[ \fB\-M\fP\fI mixed data+metadata\fP ]
+[ \fB\-n\fP\fI nodesize\fP ]
+[ \fB\-s\fP\fI sectorsize\fP ]
+[ \fB\-T\fP ]
+[ \fB\-h\fP ]
+[ \fB\-V\fP ] \fI device\fP [ \fI device ...\fP ]
.SH DESCRIPTION
.B mkfs.btrfs
is used to create an btrfs filesystem (usually in a disk partition, or an array

View File

@ -1,32 +0,0 @@
From 3a858a5e19255c402f7c97f492d0b2ac69cf286a Mon Sep 17 00:00:00 2001
From: Phillip Susi <psusi@cfl.rr.com>
Date: Mon, 9 Jan 2012 10:18:56 -0500
Subject: [PATCH 151/151] btrfs-progs: document --rootdir mkfs switch
Signed-off-by: Phillip Susi <psusi@cfl.rr.com>
---
man/mkfs.btrfs.8.in | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/man/mkfs.btrfs.8.in
+++ btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
@@ -13,6 +13,7 @@ mkfs.btrfs \- create an btrfs filesystem
[ \fB\-M\fP\fI mixed data+metadata\fP ]
[ \fB\-n\fP\fI nodesize\fP ]
[ \fB\-s\fP\fI sectorsize\fP ]
+[ \fB\-r\fP\fI rootdir\fP ]
[ \fB\-T\fP ]
[ \fB\-h\fP ]
[ \fB\-V\fP ] \fI device\fP [ \fI device ...\fP ]
@@ -63,6 +64,9 @@ Specify the nodesize. By default the val
\fB\-s\fR, \fB\-\-sectorsize \fIsize\fR
Specify the sectorsize, the minimum block allocation.
.TP
+\fB\-r\fR, \fB\-\-rootdir \fIrootdir\fR
+Specify a directory to copy into the newly created fs.
+.TP
\fB\-T\fR, \fB\-\-nodiscard \fR
Do not perform whole device TRIM operation by default.
.TP

View File

@ -1,409 +0,0 @@
From bffb42193524b984ec8407773a0997707bb20cbf Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Sun, 5 Feb 2012 16:11:48 -0500
Subject: [PATCH 01/18] Add open_ctree_fs_info for partial FS opens
fsck needs to be able to open a damaged FS, which means open_ctree needs
to be able to return a damaged FS.
This adds a new open_ctree_fs_info which can be used to open any and all
roots that are valid. btrfs-debug-tree is changed to use it.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 7 +++-
debug-tree.c | 59 +++++++++++++++++++++++++-------------
disk-io.c | 90 ++++++++++++++++++++++++++++++++++++---------------------
disk-io.h | 3 ++
extent_io.c | 3 ++
5 files changed, 107 insertions(+), 55 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 509ab72..40eb407 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2809,6 +2809,7 @@ int main(int ac, char **av)
{
struct cache_tree root_cache;
struct btrfs_root *root;
+ struct btrfs_fs_info *info;
u64 bytenr = 0;
int ret;
int num;
@@ -2846,11 +2847,13 @@ int main(int ac, char **av)
return -EBUSY;
}
- root = open_ctree(av[optind], bytenr, 0);
+ info = open_ctree_fs_info(av[optind], bytenr, 0, 0);
- if (root == NULL)
+ if (info == NULL)
return 1;
+ root = info->fs_root;
+
ret = check_extents(root);
if (ret)
goto out;
diff --git a/debug-tree.c b/debug-tree.c
index 2aeabfd..c497892 100644
--- a/debug-tree.c
+++ b/debug-tree.c
@@ -104,6 +104,7 @@ static void print_old_roots(struct btrfs_super_block *super)
int main(int ac, char **av)
{
struct btrfs_root *root;
+ struct btrfs_fs_info *info;
struct btrfs_path path;
struct btrfs_key key;
struct btrfs_root_item ri;
@@ -152,12 +153,18 @@ int main(int ac, char **av)
if (ac != 1)
print_usage();
- root = open_ctree(av[optind], 0, 0);
- if (!root) {
+ info = open_ctree_fs_info(av[optind], 0, 0, 1);
+ if (!info) {
fprintf(stderr, "unable to open %s\n", av[optind]);
exit(1);
}
+ root = info->fs_root;
+
if (block_only) {
+ if (!root) {
+ fprintf(stderr, "unable to open %s\n", av[optind]);
+ exit(1);
+ }
leaf = read_tree_block(root,
block_only,
root->leafsize, 0);
@@ -184,25 +191,32 @@ int main(int ac, char **av)
if (!extent_only) {
if (roots_only) {
printf("root tree: %llu level %d\n",
- (unsigned long long)root->fs_info->tree_root->node->start,
- btrfs_header_level(root->fs_info->tree_root->node));
+ (unsigned long long)info->tree_root->node->start,
+ btrfs_header_level(info->tree_root->node));
printf("chunk tree: %llu level %d\n",
- (unsigned long long)root->fs_info->chunk_root->node->start,
- btrfs_header_level(root->fs_info->chunk_root->node));
+ (unsigned long long)info->chunk_root->node->start,
+ btrfs_header_level(info->chunk_root->node));
} else {
- printf("root tree\n");
- btrfs_print_tree(root->fs_info->tree_root,
- root->fs_info->tree_root->node, 1);
+ if (info->tree_root->node) {
+ printf("root tree\n");
+ btrfs_print_tree(info->tree_root,
+ info->tree_root->node, 1);
+ }
- printf("chunk tree\n");
- btrfs_print_tree(root->fs_info->chunk_root,
- root->fs_info->chunk_root->node, 1);
+ if (info->chunk_root->node) {
+ printf("chunk tree\n");
+ btrfs_print_tree(info->chunk_root,
+ info->chunk_root->node, 1);
+ }
}
}
- tree_root_scan = root->fs_info->tree_root;
+ tree_root_scan = info->tree_root;
btrfs_init_path(&path);
again:
+ if (!extent_buffer_uptodate(tree_root_scan->node))
+ goto no_node;
+
key.offset = 0;
key.objectid = 0;
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
@@ -232,6 +246,9 @@ again:
btrfs_level_size(tree_root_scan,
btrfs_root_level(&ri)),
0);
+ if (!extent_buffer_uptodate(buf))
+ goto next;
+
switch(found_key.objectid) {
case BTRFS_ROOT_TREE_OBJECTID:
if (!skip)
@@ -320,13 +337,15 @@ again:
}
}
}
+next:
path.slots[0]++;
}
+no_node:
btrfs_release_path(root, &path);
- if (tree_root_scan == root->fs_info->tree_root &&
- root->fs_info->log_root_tree) {
- tree_root_scan = root->fs_info->log_root_tree;
+ if (tree_root_scan == info->tree_root &&
+ info->log_root_tree) {
+ tree_root_scan = info->log_root_tree;
goto again;
}
@@ -334,14 +353,14 @@ again:
return 0;
if (root_backups)
- print_old_roots(&root->fs_info->super_copy);
+ print_old_roots(&info->super_copy);
printf("total bytes %llu\n",
- (unsigned long long)btrfs_super_total_bytes(&root->fs_info->super_copy));
+ (unsigned long long)btrfs_super_total_bytes(&info->super_copy));
printf("bytes used %llu\n",
- (unsigned long long)btrfs_super_bytes_used(&root->fs_info->super_copy));
+ (unsigned long long)btrfs_super_bytes_used(&info->super_copy));
uuidbuf[36] = '\0';
- uuid_unparse(root->fs_info->super_copy.fsid, uuidbuf);
+ uuid_unparse(info->super_copy.fsid, uuidbuf);
printf("uuid %s\n", uuidbuf);
printf("%s\n", BTRFS_BUILD_VERSION);
return 0;
diff --git a/disk-io.c b/disk-io.c
index b0b9502..e9fdba8 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -445,8 +445,9 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
generation = btrfs_root_generation(&root->root_item);
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
- if (!root->node)
- return -ENOENT;
+ if (!extent_buffer_uptodate(root->node))
+ return -EIO;
+
return 0;
}
@@ -473,7 +474,9 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root,
btrfs_super_generation(disk_super) + 1);
fs_info->log_root_tree = log_root;
- BUG_ON(!log_root->node);
+
+ if (!extent_buffer_uptodate(log_root->node))
+ return -EIO;
return 0;
}
@@ -603,9 +606,9 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
return root;
}
-struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
+static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
u64 root_tree_bytenr, int writes,
- int use_earliest_bdev)
+ int use_earliest_bdev, int partial)
{
u32 sectorsize;
u32 nodesize;
@@ -742,7 +745,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
chunk_root->node = read_tree_block(chunk_root,
btrfs_super_chunk_root(disk_super),
blocksize, generation);
- if (!chunk_root->node) {
+ if (!extent_buffer_uptodate(chunk_root->node)) {
printk("Couldn't read chunk root\n");
goto out_devices;
}
@@ -754,7 +757,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) {
ret = btrfs_read_chunk_tree(chunk_root);
if (ret)
- goto out_chunk;
+ goto out_failed;
}
blocksize = btrfs_level_size(tree_root,
@@ -766,15 +769,15 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
tree_root->node = read_tree_block(tree_root,
root_tree_bytenr,
blocksize, generation);
- if (!tree_root->node) {
+ if (!extent_buffer_uptodate(tree_root->node)) {
printk("Couldn't read tree root\n");
- goto out_chunk;
+ goto out_failed;
}
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_EXTENT_TREE_OBJECTID, extent_root);
if (ret) {
printk("Couldn't setup extent tree\n");
- goto out_tree;
+ goto out_failed;
}
extent_root->track_dirty = 1;
@@ -782,7 +785,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
BTRFS_DEV_TREE_OBJECTID, dev_root);
if (ret) {
printk("Couldn't setup device tree\n");
- goto out_extent;
+ goto out_failed;
}
dev_root->track_dirty = 1;
@@ -790,7 +793,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
BTRFS_CSUM_TREE_OBJECTID, csum_root);
if (ret) {
printk("Couldn't setup csum tree\n");
- goto out_dev;
+ goto out_failed;
}
csum_root->track_dirty = 1;
@@ -806,23 +809,28 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
fs_info->fs_root = btrfs_read_fs_root(fs_info, &key);
if (!fs_info->fs_root)
- goto out_csum;
+ goto out_failed;
fs_info->data_alloc_profile = (u64)-1;
fs_info->metadata_alloc_profile = (u64)-1;
fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
- return fs_info->fs_root;
-out_csum:
- free_extent_buffer(fs_info->csum_root->node);
-out_dev:
- free_extent_buffer(fs_info->dev_root->node);
-out_extent:
- free_extent_buffer(fs_info->extent_root->node);
-out_tree:
- free_extent_buffer(fs_info->tree_root->node);
-out_chunk:
- free_extent_buffer(fs_info->chunk_root->node);
+ return fs_info;
+
+out_failed:
+ if (partial)
+ return fs_info;
+
+ if (fs_info->csum_root)
+ free_extent_buffer(fs_info->csum_root->node);
+ if (fs_info->dev_root)
+ free_extent_buffer(fs_info->dev_root->node);
+ if (fs_info->extent_root)
+ free_extent_buffer(fs_info->extent_root->node);
+ if (fs_info->tree_root)
+ free_extent_buffer(fs_info->tree_root->node);
+ if (fs_info->chunk_root)
+ free_extent_buffer(fs_info->chunk_root->node);
out_devices:
close_all_devices(fs_info);
out_cleanup:
@@ -842,10 +850,12 @@ out:
return NULL;
}
-struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
+struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
+ u64 sb_bytenr, int writes,
+ int partial)
{
int fp;
- struct btrfs_root *root;
+ struct btrfs_fs_info *info;
int flags = O_CREAT | O_RDWR;
if (!writes)
@@ -856,33 +866,47 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
fprintf (stderr, "Could not open %s\n", filename);
return NULL;
}
- root = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, 0);
+ info = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, 0, partial);
close(fp);
+ return info;
+}
- return root;
+struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
+{
+ struct btrfs_fs_info *info;
+
+ info = open_ctree_fs_info(filename, sb_bytenr, writes, 0);
+ if (!info)
+ return NULL;
+ return info->fs_root;
}
struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
u64 root_tree_bytenr)
{
int fp;
- struct btrfs_root *root;
+ struct btrfs_fs_info *info;
fp = open(filename, O_RDONLY);
if (fp < 0) {
fprintf (stderr, "Could not open %s\n", filename);
return NULL;
}
- root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0, 0);
+ info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0, 0, 0);
close(fp);
-
- return root;
+ if (!info)
+ return NULL;
+ return info->fs_root;
}
struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int writes, int use_earliest_bdev)
{
- return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev);
+ struct btrfs_fs_info *info;
+ info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev, 0);
+ if (!info)
+ return NULL;
+ return info->fs_root;
}
struct btrfs_root *open_ctree_broken(int fd, const char *device)
diff --git a/disk-io.h b/disk-io.h
index 2b1fcd5..664cabd 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -48,6 +48,9 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int writes, int use_earliest_bdev);
struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
u64 root_tree_bytenr);
+struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
+ u64 sb_bytenr, int writes,
+ int partial);
struct btrfs_root *open_ctree_broken(int fd, const char *device);
int close_ctree(struct btrfs_root *root);
int write_all_supers(struct btrfs_root *root);
diff --git a/extent_io.c b/extent_io.c
index 973e918..9990338 100644
--- a/extent_io.c
+++ b/extent_io.c
@@ -706,6 +706,9 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
int extent_buffer_uptodate(struct extent_buffer *eb)
{
+ if (!eb)
+ return 0;
+
if (eb->flags & EXTENT_UPTODATE)
return 1;
return 0;
--
1.7.6.233.gd79bc

View File

@ -1,34 +0,0 @@
From bed79b9cd39caf88f5bf8fe9340afa539924a8cc Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 05:05:59 -0500
Subject: [PATCH 02/18] btrfsck: print some progress Signed-off-by: Chris
Mason <chris.mason@oracle.com>
---
btrfsck.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 40eb407..a3c6286 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2854,13 +2854,16 @@ int main(int ac, char **av)
root = info->fs_root;
+ fprintf(stderr, "checking extents\n");
ret = check_extents(root);
if (ret)
goto out;
+ fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
if (ret)
goto out;
+ fprintf(stderr, "checking root refs\n");
ret = check_root_refs(root, &root_cache);
out:
free_root_recs(&root_cache);
--
1.7.6.233.gd79bc

View File

@ -1,54 +0,0 @@
From 769671c6aeef3359498100f0ef31975706d99fca Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 05:06:18 -0500
Subject: [PATCH 03/18] Allow extent_buffers to use more ram
This changes free_some_buffers (called each time we allocate an extent
buffer) to allow a higher hard limit on the number of extent buffers
in use.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
extent_io.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/extent_io.c b/extent_io.c
index 9990338..ebb35b2 100644
--- a/extent_io.c
+++ b/extent_io.c
@@ -28,7 +28,8 @@
#include "extent_io.h"
#include "list.h"
-u64 cache_max = 1024 * 1024 * 32;
+u64 cache_soft_max = 1024 * 1024 * 256;
+u64 cache_hard_max = 1 * 1024 * 1024 * 1024;
void extent_io_tree_init(struct extent_io_tree *tree)
{
@@ -540,18 +541,19 @@ static int free_some_buffers(struct extent_io_tree *tree)
struct extent_buffer *eb;
struct list_head *node, *next;
- if (tree->cache_size < cache_max)
+ if (tree->cache_size < cache_soft_max)
return 0;
+
list_for_each_safe(node, next, &tree->lru) {
eb = list_entry(node, struct extent_buffer, lru);
if (eb->refs == 1) {
free_extent_buffer(eb);
- if (tree->cache_size < cache_max)
+ if (tree->cache_size < cache_hard_max)
break;
} else {
list_move_tail(&eb->lru, &tree->lru);
}
- if (nrscan++ > 64)
+ if (nrscan++ > 64 && tree->cache_size < cache_hard_max)
break;
}
return 0;
--
1.7.6.233.gd79bc

View File

@ -1,32 +0,0 @@
From ab19832dce62c53452454897fe1d2eaf2e1dbd59 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 08:53:43 -0500
Subject: [PATCH 04/18] btrfsck: don't BUG on corrupted extent records
---
btrfsck.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index a3c6286..90e9c80 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2441,11 +2441,14 @@ static int process_extent_item(struct cache_tree *extent_cache,
0);
break;
default:
- BUG();
+ fprintf(stderr, "corrupt extent record: key %Lu %u %Lu\n",
+ key.objectid, key.type, key.offset);
+ goto out;
}
ptr += btrfs_extent_inline_ref_size(type);
}
WARN_ON(ptr > end);
+out:
return 0;
}
--
1.7.6.233.gd79bc

View File

@ -1,194 +0,0 @@
From a0e60b027576e8e3e3d77b77eaff1360a374af60 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 08:54:05 -0500
Subject: [PATCH 05/18] btrfs-corrupt-block: add -e option to corrupt the
extent record
This will zero out the extent allocation tree records for the extent.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfs-corrupt-block.c | 115 ++++++++++++++++++++++++++++++++-----------------
1 files changed, 76 insertions(+), 39 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index ace61c1..59e7cb4 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -32,11 +32,6 @@
#include "list.h"
#include "version.h"
-/* we write the mirror info to stdout unless they are dumping the data
- * to stdout
- * */
-static FILE *info_file;
-
struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize, int copy)
{
@@ -62,7 +57,7 @@ struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
device->total_ios++;
eb->dev_bytenr = multi->stripes[0].physical;
- fprintf(info_file, "mirror %d logical %Lu physical %Lu "
+ 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);
@@ -106,24 +101,88 @@ static struct option long_options[] = {
{ 0, 0, 0, 0}
};
+static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ u32 item_size;
+ unsigned long ptr;
+ struct btrfs_path *path;
+ int ret;
+ int slot;
+
+ trans = btrfs_start_transaction(root, 1);
+ 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, 0, 1);
+ if (ret < 0)
+ break;
+
+ if (ret > 0) {
+ if (path->slots[0] == 0)
+ break;
+ path->slots[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;
+
+ 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);
+ btrfs_commit_transaction(trans, root);
+ ret = close_ctree(root);
+ BUG_ON(ret);
+ return 0;
+}
+
int main(int ac, char **av)
{
struct cache_tree root_cache;
struct btrfs_root *root;
struct extent_buffer *eb;
char *dev;
- char *output_file = NULL;
u64 logical = 0;
int ret = 0;
int option_index = 0;
int copy = 0;
u64 bytes = 4096;
- int out_fd = 0;
- int err;
+ int extent_rec;
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:", long_options,
+ c = getopt_long(ac, av, "l:c:e", long_options,
&option_index);
if (c < 0)
break;
@@ -152,6 +211,9 @@ int main(int ac, char **av)
print_usage();
}
break;
+ case 'e':
+ extent_rec = 1;
+ break;
default:
print_usage();
}
@@ -174,23 +236,9 @@ int main(int ac, char **av)
fprintf(stderr, "Open ctree failed\n");
exit(1);
}
-
- info_file = stdout;
- if (output_file) {
- if (strcmp(output_file, "-") == 0) {
- out_fd = 1;
- info_file = stderr;
- } else {
- out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
- if (out_fd < 0)
- goto close;
- err = ftruncate(out_fd, 0);
- if (err) {
- close(out_fd);
- goto close;
- }
- info_file = stdout;
- }
+ if (extent_rec) {
+ ret = corrupt_extent (root, logical, 0);
+ goto out;
}
if (bytes == 0)
@@ -201,21 +249,10 @@ int main(int ac, char **av)
while (bytes > 0) {
eb = debug_corrupt_block(root, logical, root->sectorsize, copy);
- if (eb && output_file) {
- err = write(out_fd, eb->data, eb->len);
- if (err < 0 || err != eb->len) {
- fprintf(stderr, "output file write failed\n");
- goto out_close_fd;
- }
- }
free_extent_buffer(eb);
logical += root->sectorsize;
bytes -= root->sectorsize;
}
-
-out_close_fd:
- if (output_file && out_fd != 1)
- close(out_fd);
-close:
+out:
return ret;
}
--
1.7.6.233.gd79bc

View File

@ -1,892 +0,0 @@
From a3921c085c75c6d1983442dc0db35131db874d84 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 7 Feb 2012 05:13:24 -0500
Subject: [PATCH 06/18] btrfsck: add code to rebuild extent records
This also includes a new --repair btrfsck option. For now it can
only fix errors in the extent allocation tree.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
ctree.h | 1 +
extent-tree.c | 24 ++--
print-tree.c | 2 +-
4 files changed, 437 insertions(+), 49 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
#include "disk-io.h"
@@ -74,9 +75,13 @@ struct extent_record {
struct cache_extent cache;
struct btrfs_disk_key parent_key;
u64 start;
+ u64 max_size;
u64 nr;
u64 refs;
u64 extent_item_refs;
+ u64 generation;
+ u64 info_objectid;
+ u8 info_level;
unsigned int content_checked:1;
unsigned int owner_ref_checked:1;
unsigned int is_root:1;
@@ -1082,7 +1087,9 @@ static int walk_down_tree(struct btrfs_r
ret = btrfs_lookup_extent_info(NULL, root,
path->nodes[*level]->start,
path->nodes[*level]->len, &refs, NULL);
- BUG_ON(ret);
+ if (ret < 0)
+ goto out;
+
if (refs > 1) {
ret = enter_shared_node(root, path->nodes[*level]->start,
refs, wc, *level);
@@ -1109,7 +1116,8 @@ static int walk_down_tree(struct btrfs_r
blocksize = btrfs_level_size(root, *level - 1);
ret = btrfs_lookup_extent_info(NULL, root, bytenr, blocksize,
&refs, NULL);
- BUG_ON(ret);
+ if (ret < 0)
+ refs = 0;
if (refs > 1) {
ret = enter_shared_node(root, bytenr, refs,
@@ -1834,12 +1842,12 @@ static int all_backpointers_checked(stru
if (!print_errs)
goto out;
tback = (struct tree_backref *)back;
- fprintf(stderr, "Backref %llu %s %llu not referenced\n",
+ fprintf(stderr, "Backref %llu %s %llu not referenced back %p\n",
(unsigned long long)rec->start,
back->full_backref ? "parent" : "root",
back->full_backref ?
(unsigned long long)tback->parent :
- (unsigned long long)tback->root);
+ (unsigned long long)tback->root, back);
}
if (back->is_data) {
dback = (struct data_backref *)back;
@@ -1849,7 +1857,7 @@ static int all_backpointers_checked(stru
goto out;
fprintf(stderr, "Incorrect local backref count"
" on %llu %s %llu owner %llu"
- " offset %llu found %u wanted %u\n",
+ " offset %llu found %u wanted %u back %p\n",
(unsigned long long)rec->start,
back->full_backref ?
"parent" : "root",
@@ -1858,7 +1866,7 @@ static int all_backpointers_checked(stru
(unsigned long long)dback->root,
(unsigned long long)dback->owner,
(unsigned long long)dback->offset,
- dback->found_ref, dback->num_refs);
+ dback->found_ref, dback->num_refs, back);
}
}
if (!back->is_data) {
@@ -1965,12 +1973,28 @@ static int check_block(struct btrfs_root
{
struct extent_record *rec;
struct cache_extent *cache;
+ struct btrfs_key key;
int ret = 1;
+ int level;
cache = find_cache_extent(extent_cache, buf->start, buf->len);
if (!cache)
return 1;
rec = container_of(cache, struct extent_record, cache);
+ rec->generation = btrfs_header_generation(buf);
+
+ level = btrfs_header_level(buf);
+ if (btrfs_header_nritems(buf) > 0) {
+
+ if (level == 0)
+ btrfs_item_key_to_cpu(buf, &key, 0);
+ else
+ btrfs_node_key_to_cpu(buf, &key, 0);
+
+ rec->info_objectid = key.objectid;
+ }
+ rec->info_level = level;
+
if (btrfs_is_leaf(buf)) {
ret = check_leaf(root, &rec->parent_key, buf);
} else {
@@ -2035,6 +2059,7 @@ static struct tree_backref *alloc_tree_b
ref->node.full_backref = 0;
}
list_add_tail(&ref->node.list, &rec->backrefs);
+
return ref;
}
@@ -2052,7 +2077,7 @@ static struct data_backref *find_data_ba
if (!node->is_data)
continue;
back = (struct data_backref *)node;
- if (parent > 0) {
+ if (parent > 0) {
if (!node->full_backref)
continue;
if (parent == back->parent)
@@ -2070,11 +2095,13 @@ static struct data_backref *find_data_ba
static struct data_backref *alloc_data_backref(struct extent_record *rec,
u64 parent, u64 root,
- u64 owner, u64 offset)
+ u64 owner, u64 offset,
+ u64 max_size)
{
struct data_backref *ref = malloc(sizeof(*ref));
memset(&ref->node, 0, sizeof(ref->node));
ref->node.is_data = 1;
+
if (parent > 0) {
ref->parent = parent;
ref->owner = 0;
@@ -2089,13 +2116,16 @@ static struct data_backref *alloc_data_b
ref->found_ref = 0;
ref->num_refs = 0;
list_add_tail(&ref->node.list, &rec->backrefs);
+ if (max_size > rec->max_size)
+ rec->max_size = max_size;
return ref;
}
static int add_extent_rec(struct cache_tree *extent_cache,
struct btrfs_key *parent_key,
u64 start, u64 nr, u64 extent_item_refs,
- int is_root, int inc_ref, int set_checked)
+ int is_root, int inc_ref, int set_checked,
+ u64 max_size)
{
struct extent_record *rec;
struct cache_extent *cache;
@@ -2136,11 +2166,15 @@ static int add_extent_rec(struct cache_t
if (parent_key)
btrfs_cpu_key_to_disk(&rec->parent_key, parent_key);
+ if (rec->max_size < max_size)
+ rec->max_size = max_size;
+
maybe_free_extent_rec(extent_cache, rec);
return ret;
}
rec = malloc(sizeof(*rec));
rec->start = start;
+ rec->max_size = max_size;
rec->nr = nr;
rec->content_checked = 0;
rec->owner_ref_checked = 0;
@@ -2187,7 +2221,7 @@ static int add_tree_backref(struct cache
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache) {
- add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0);
+ add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0, 0);
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache)
abort();
@@ -2226,7 +2260,7 @@ static int add_tree_backref(struct cache
static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
u64 parent, u64 root, u64 owner, u64 offset,
- u32 num_refs, int found_ref)
+ u32 num_refs, int found_ref, u64 max_size)
{
struct extent_record *rec;
struct data_backref *back;
@@ -2234,7 +2268,8 @@ static int add_data_backref(struct cache
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache) {
- add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0);
+ add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0,
+ max_size);
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache)
abort();
@@ -2244,9 +2279,13 @@ static int add_data_backref(struct cache
if (rec->start != bytenr) {
abort();
}
+ if (rec->max_size < max_size)
+ rec->max_size = max_size;
+
back = find_data_backref(rec, parent, root, owner, offset);
if (!back)
- back = alloc_data_backref(rec, parent, root, owner, offset);
+ back = alloc_data_backref(rec, parent, root, owner, offset,
+ max_size);
if (found_ref) {
BUG_ON(num_refs != 1);
@@ -2359,11 +2398,10 @@ static int process_extent_ref_v0(struct
btrfs_item_key_to_cpu(leaf, &key, slot);
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
- add_tree_backref(extent_cache, key.objectid, key.offset,
- 0, 0);
+ add_tree_backref(extent_cache, key.objectid, key.offset, 0, 0);
} else {
add_data_backref(extent_cache, key.objectid, key.offset, 0,
- 0, 0, btrfs_ref_count_v0(leaf, ref0), 0);
+ 0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
}
return 0;
}
@@ -2396,14 +2434,14 @@ static int process_extent_item(struct ca
BUG();
#endif
return add_extent_rec(extent_cache, NULL, key.objectid,
- key.offset, refs, 0, 0, 0);
+ key.offset, refs, 0, 0, 0, key.offset);
}
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
refs = btrfs_extent_refs(eb, ei);
add_extent_rec(extent_cache, NULL, key.objectid, key.offset,
- refs, 0, 0, 0);
+ refs, 0, 0, 0, key.offset);
ptr = (unsigned long)(ei + 1);
if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
@@ -2431,14 +2469,14 @@ static int process_extent_item(struct ca
dref),
btrfs_extent_data_ref_offset(eb, dref),
btrfs_extent_data_ref_count(eb, dref),
- 0);
+ 0, key.offset);
break;
case BTRFS_SHARED_DATA_REF_KEY:
sref = (struct btrfs_shared_data_ref *)(iref + 1);
add_data_backref(extent_cache, key.objectid, offset,
0, 0, 0,
btrfs_shared_data_ref_count(eb, sref),
- 0);
+ 0, key.offset);
break;
default:
fprintf(stderr, "corrupt extent record: key %Lu %u %Lu\n",
@@ -2515,6 +2553,8 @@ static int run_next_block(struct btrfs_r
nritems = btrfs_header_nritems(buf);
ret = btrfs_lookup_extent_info(NULL, root, bytenr, size, NULL, &flags);
+ if (ret < 0)
+ flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
parent = bytenr;
@@ -2573,7 +2613,7 @@ static int run_next_block(struct btrfs_r
ref),
btrfs_extent_data_ref_offset(buf, ref),
btrfs_extent_data_ref_count(buf, ref),
- 0);
+ 0, root->sectorsize);
continue;
}
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
@@ -2583,7 +2623,7 @@ static int run_next_block(struct btrfs_r
add_data_backref(extent_cache,
key.objectid, key.offset, 0, 0, 0,
btrfs_shared_data_ref_count(buf, ref),
- 0);
+ 0, root->sectorsize);
continue;
}
if (key.type != BTRFS_EXTENT_DATA_KEY)
@@ -2606,26 +2646,33 @@ static int run_next_block(struct btrfs_r
ret = add_extent_rec(extent_cache, NULL,
btrfs_file_extent_disk_bytenr(buf, fi),
btrfs_file_extent_disk_num_bytes(buf, fi),
- 0, 0, 1, 1);
+ 0, 0, 1, 1,
+ btrfs_file_extent_disk_num_bytes(buf, fi));
add_data_backref(extent_cache,
btrfs_file_extent_disk_bytenr(buf, fi),
parent, owner, key.objectid, key.offset -
- btrfs_file_extent_offset(buf, fi), 1, 1);
+ btrfs_file_extent_offset(buf, fi), 1, 1,
+ btrfs_file_extent_disk_num_bytes(buf, fi));
BUG_ON(ret);
}
} else {
int level;
+ struct btrfs_key first_key;
+
+ first_key.objectid = 0;
+
+ if (nritems > 0)
+ btrfs_item_key_to_cpu(buf, &first_key, 0);
level = btrfs_header_level(buf);
for (i = 0; i < nritems; i++) {
u64 ptr = btrfs_node_blockptr(buf, i);
u32 size = btrfs_level_size(root, level - 1);
btrfs_node_key_to_cpu(buf, &key, i);
ret = add_extent_rec(extent_cache, &key,
- ptr, size, 0, 0, 1, 0);
+ ptr, size, 0, 0, 1, 0, size);
BUG_ON(ret);
- add_tree_backref(extent_cache, ptr, parent,
- owner, 1);
+ add_tree_backref(extent_cache, ptr, parent, owner, 1);
if (level > 1) {
add_pending(nodes, seen, ptr, size);
@@ -2663,25 +2710,313 @@ static int add_root_to_pending(struct ex
else
add_pending(pending, seen, buf->start, buf->len);
add_extent_rec(extent_cache, NULL, buf->start, buf->len,
- 0, 1, 1, 0);
+ 0, 1, 1, 0, buf->len);
if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
- add_tree_backref(extent_cache, buf->start, buf->start, 0, 1);
+ add_tree_backref(extent_cache, buf->start, buf->start,
+ 0, 1);
else
add_tree_backref(extent_cache, buf->start, 0,
root_key->objectid, 1);
return 0;
}
+static int delete_extent_records(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ u64 bytenr)
+{
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct extent_buffer *leaf;
+ int ret;
+ int slot;
+
+
+ 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, 0, 1);
+ if (ret < 0)
+ break;
+
+ if (ret > 0) {
+ 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, &found_key, slot);
+ if (found_key.objectid != bytenr)
+ break;
+
+ if (found_key.type != BTRFS_EXTENT_ITEM_KEY &&
+ found_key.type != BTRFS_TREE_BLOCK_REF_KEY &&
+ found_key.type != BTRFS_EXTENT_DATA_REF_KEY &&
+ found_key.type != BTRFS_EXTENT_REF_V0_KEY &&
+ found_key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
+ found_key.type != BTRFS_SHARED_DATA_REF_KEY) {
+ btrfs_release_path(NULL, path);
+ if (found_key.type == 0) {
+ if (found_key.offset == 0)
+ break;
+ key.offset = found_key.offset - 1;
+ key.type = found_key.type;
+ }
+ key.type = found_key.type - 1;
+ key.offset = (u64)-1;
+ continue;
+ }
+
+ fprintf(stderr, "repair deleting extent record: key %Lu %u %Lu\n",
+ found_key.objectid, found_key.type, found_key.offset);
+
+ ret = btrfs_del_item(trans, root->fs_info->extent_root, path);
+ if (ret)
+ break;
+ btrfs_release_path(NULL, path);
+
+ if (found_key.type == BTRFS_EXTENT_ITEM_KEY) {
+ ret = btrfs_update_block_group(trans, root, bytenr,
+ found_key.offset, 0, 1);
+ if (ret)
+ break;
+ }
+ }
+
+ btrfs_release_path(NULL, path);
+ return ret;
+}
+
+/*
+ * for a single backref, this will allocate a new extent
+ * and add the backref to it.
+ */
+static int record_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct btrfs_path *path,
+ struct extent_record *rec,
+ struct extent_backref *back,
+ int allocated, u64 flags)
+{
+ int ret;
+ struct btrfs_root *extent_root = info->extent_root;
+ struct extent_buffer *leaf;
+ struct btrfs_key ins_key;
+ struct btrfs_extent_item *ei;
+ struct tree_backref *tback;
+ struct data_backref *dback;
+ struct btrfs_tree_block_info *bi;
+
+ if (!back->is_data)
+ rec->max_size = max_t(u64, rec->max_size,
+ info->extent_root->leafsize);
+
+ if (!allocated) {
+ u32 item_size = sizeof(*ei);
+
+ if (!back->is_data)
+ item_size += sizeof(*bi);
+
+ ins_key.objectid = rec->start;
+ ins_key.offset = rec->max_size;
+ ins_key.type = BTRFS_EXTENT_ITEM_KEY;
+
+ ret = btrfs_insert_empty_item(trans, extent_root, path,
+ &ins_key, item_size);
+ if (ret)
+ goto fail;
+
+ leaf = path->nodes[0];
+ ei = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_extent_item);
+
+ btrfs_set_extent_refs(leaf, ei, 0);
+ btrfs_set_extent_generation(leaf, ei, rec->generation);
+
+ if (back->is_data) {
+ btrfs_set_extent_flags(leaf, ei,
+ BTRFS_EXTENT_FLAG_DATA);
+ } else {
+ struct btrfs_disk_key copy_key;;
+
+ tback = (struct tree_backref *)back;
+ bi = (struct btrfs_tree_block_info *)(ei + 1);
+ memset_extent_buffer(leaf, 0, (unsigned long)bi,
+ sizeof(*bi));
+ memset(&copy_key, 0, sizeof(copy_key));
+
+ copy_key.objectid = le64_to_cpu(rec->info_objectid);
+ btrfs_set_tree_block_level(leaf, bi, rec->info_level);
+ btrfs_set_tree_block_key(leaf, bi, &copy_key);
+
+ btrfs_set_extent_flags(leaf, ei,
+ BTRFS_EXTENT_FLAG_TREE_BLOCK | flags);
+ }
+
+ btrfs_mark_buffer_dirty(leaf);
+ ret = btrfs_update_block_group(trans, extent_root, rec->start,
+ rec->max_size, 1, 0);
+ if (ret)
+ goto fail;
+ btrfs_release_path(NULL, path);
+ }
+
+ if (back->is_data) {
+ u64 parent;
+ int i;
+
+ dback = (struct data_backref *)back;
+ if (back->full_backref)
+ parent = dback->parent;
+ else
+ parent = 0;
+
+ for (i = 0; i < dback->found_ref; i++) {
+ /* if parent != 0, we're doing a full backref
+ * passing BTRFS_FIRST_FREE_OBJECTID as the owner
+ * just makes the backref allocator create a data
+ * backref
+ */
+ ret = btrfs_inc_extent_ref(trans, info->extent_root,
+ rec->start, rec->max_size,
+ parent,
+ dback->root,
+ parent ?
+ BTRFS_FIRST_FREE_OBJECTID :
+ dback->owner,
+ dback->offset);
+ if (ret)
+ break;
+ }
+ fprintf(stderr, "adding new data backref"
+ " on %llu %s %llu owner %llu"
+ " offset %llu found %d\n",
+ (unsigned long long)rec->start,
+ back->full_backref ?
+ "parent" : "root",
+ back->full_backref ?
+ (unsigned long long)parent :
+ (unsigned long long)dback->root,
+ (unsigned long long)dback->owner,
+ (unsigned long long)dback->offset,
+ dback->found_ref);
+ } else {
+ u64 parent;
+
+ tback = (struct tree_backref *)back;
+ if (back->full_backref)
+ parent = tback->parent;
+ else
+ parent = 0;
+
+ ret = btrfs_inc_extent_ref(trans, info->extent_root,
+ rec->start, rec->max_size,
+ parent, tback->root, 0, 0);
+ fprintf(stderr, "adding new tree backref on "
+ "start %llu len %llu parent %llu root %llu\n",
+ rec->start, rec->max_size, tback->parent, tback->root);
+ }
+ if (ret)
+ goto fail;
+fail:
+ btrfs_release_path(NULL, path);
+ return ret;
+}
+
+/*
+ * when an incorrect extent item is found, this will delete
+ * all of the existing entries for it and recreate them
+ * based on what the tree scan found.
+ */
+static int fixup_extent_refs(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct extent_record *rec)
+{
+ int ret;
+ struct btrfs_path *path;
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *back;
+ int allocated = 0;
+ u64 flags = 0;
+
+ /* remember our flags for recreating the extent */
+ ret = btrfs_lookup_extent_info(NULL, info->extent_root, rec->start,
+ rec->max_size, NULL, &flags);
+ if (ret < 0)
+ flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
+
+ path = btrfs_alloc_path();
+
+ /* step one, delete all the existing records */
+ ret = delete_extent_records(trans, info->extent_root, path,
+ rec->start);
+
+ if (ret < 0)
+ goto out;
+
+ /* step two, recreate all the refs we did find */
+ while(cur != &rec->backrefs) {
+ back = list_entry(cur, struct extent_backref, list);
+ cur = cur->next;
+
+ /*
+ * if we didn't find any references, don't create a
+ * new extent record
+ */
+ if (!back->found_ref)
+ continue;
+
+ ret = record_extent(trans, info, path, rec, back, allocated, flags);
+ allocated = 1;
+
+ if (ret)
+ goto out;
+ }
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
static int check_extent_refs(struct btrfs_root *root,
- struct cache_tree *extent_cache)
+ struct cache_tree *extent_cache, int repair)
{
struct extent_record *rec;
struct cache_extent *cache;
+ struct btrfs_trans_handle *trans = NULL;
int err = 0;
+ int ret = 0;
+ int fixed = 0;
+ if (repair)
+ trans = btrfs_start_transaction(root, 1);
+
+ if (repair) {
+ /*
+ * if we're doing a repair, we have to make sure
+ * we don't allocate from the problem extents.
+ * In the worst case, this will be all the
+ * extents in the FS
+ */
+ cache = find_first_cache_extent(extent_cache, 0);
+ while(cache) {
+ rec = container_of(cache, struct extent_record, cache);
+ btrfs_pin_extent(root->fs_info,
+ rec->start, rec->nr);
+ cache = next_cache_extent(cache);
+ }
+ }
while(1) {
+ fixed = 0;
cache = find_first_cache_extent(extent_cache, 0);
if (!cache)
break;
@@ -2693,19 +3028,39 @@ static int check_extent_refs(struct btrf
fprintf(stderr, "extent item %llu, found %llu\n",
(unsigned long long)rec->extent_item_refs,
(unsigned long long)rec->refs);
+ if (!fixed && repair) {
+ ret = fixup_extent_refs(trans, root->fs_info, rec);
+ if (ret)
+ goto repair_abort;
+ fixed = 1;
+ }
err = 1;
+
}
if (all_backpointers_checked(rec, 1)) {
fprintf(stderr, "backpointer mismatch on [%llu %llu]\n",
(unsigned long long)rec->start,
(unsigned long long)rec->nr);
+ if (!fixed && repair) {
+ ret = fixup_extent_refs(trans, root->fs_info, rec);
+ if (ret)
+ goto repair_abort;
+ fixed = 1;
+ }
+
err = 1;
}
if (!rec->owner_ref_checked) {
fprintf(stderr, "owner ref check failed [%llu %llu]\n",
(unsigned long long)rec->start,
(unsigned long long)rec->nr);
+ if (!fixed && repair) {
+ ret = fixup_extent_refs(trans, root->fs_info, rec);
+ if (ret)
+ goto repair_abort;
+ fixed = 1;
+ }
err = 1;
}
@@ -2713,10 +3068,18 @@ static int check_extent_refs(struct btrf
free_all_extent_backrefs(rec);
free(rec);
}
+repair_abort:
+ if (repair) {
+ if (ret) {
+ fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
+ exit(1);
+ }
+ btrfs_commit_transaction(trans, root);
+ }
return err;
}
-static int check_extents(struct btrfs_root *root)
+static int check_extents(struct btrfs_root *root, int repair)
{
struct cache_tree extent_cache;
struct cache_tree seen;
@@ -2797,7 +3160,7 @@ static int check_extents(struct btrfs_ro
if (ret != 0)
break;
}
- ret = check_extent_refs(root, &extent_cache);
+ ret = check_extent_refs(root, &extent_cache, repair);
free(bits);
return ret;
}
@@ -2809,6 +3172,12 @@ static void print_usage(void)
exit(1);
}
+static struct option long_options[] = {
+ { "super", 1, NULL, 's' },
+ { "repair", 0, NULL, 0 },
+ { 0, 0, 0, 0}
+};
+
int main(int ac, char **av)
{
struct cache_tree root_cache;
@@ -2817,10 +3186,13 @@ int main(int ac, char **av)
u64 bytenr = 0;
int ret;
int num;
+ int repair = 0;
+ int option_index = 0;
while(1) {
int c;
- c = getopt(ac, av, "as:");
+ c = getopt_long(ac, av, "a", long_options,
+ &option_index);
if (c < 0)
break;
switch(c) {
@@ -2831,9 +3203,14 @@ int main(int ac, char **av)
printf("using SB copy %d, bytenr %llu\n", num,
(unsigned long long)bytenr);
break;
- default:
+ case '?':
print_usage();
}
+ if (option_index == 1) {
+ printf("enabling repair mode\n");
+ repair = 1;
+ }
+
}
ac = ac - optind;
@@ -2851,15 +3228,23 @@ int main(int ac, char **av)
return -EBUSY;
}
- info = open_ctree_fs_info(av[optind], bytenr, 0, 0);
+ info = open_ctree_fs_info(av[optind], bytenr, repair, 1);
if (info == NULL)
return 1;
+ if (!extent_buffer_uptodate(info->tree_root->node) ||
+ !extent_buffer_uptodate(info->dev_root->node) ||
+ !extent_buffer_uptodate(info->extent_root->node) ||
+ !extent_buffer_uptodate(info->chunk_root->node)) {
+ fprintf(stderr, "Critical roots corrupted, unable to fsck the FS\n");
+ return -EIO;
+ }
+
root = info->fs_root;
fprintf(stderr, "checking extents\n");
- ret = check_extents(root);
+ ret = check_extents(root, repair);
if (ret)
goto out;
fprintf(stderr, "checking fs roots\n");
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -1785,6 +1785,7 @@ static inline u32 btrfs_level_size(struc
btrfs_item_offset_nr(leaf, slot)))
/* extent-tree.c */
+void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -1041,8 +1041,6 @@ static int lookup_inline_extent_backref(
}
if (ret) {
printf("Failed to find [%llu, %u, %llu]\n", key.objectid, key.type, key.offset);
- btrfs_print_leaf(root, path->nodes[0]);
- btrfs_free_path(path);
return -ENOENT;
}
@@ -1067,8 +1065,9 @@ static int lookup_inline_extent_backref(
}
#endif
if (item_size < sizeof(*ei)) {
- printf("Size is %u, needs to be %u, slot %d\n", item_size,
- (u32)sizeof(*ei), path->slots[0]);
+ printf("Size is %u, needs to be %u, slot %d\n",
+ (unsigned)item_size,
+ (unsigned)sizeof(*ei), path->slots[0]);
btrfs_print_leaf(root, leaf);
return -EINVAL;
}
@@ -1460,10 +1459,8 @@ int btrfs_lookup_extent_info(struct btrf
if (ret < 0)
goto out;
if (ret != 0) {
- btrfs_print_leaf(root, path->nodes[0]);
- printk("failed to find block number %Lu\n",
- (unsigned long long)bytenr);
- BUG();
+ ret = -EIO;
+ goto out;
}
l = path->nodes[0];
@@ -1484,9 +1481,8 @@ int btrfs_lookup_extent_info(struct btrf
extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
#else
BUG();
-#endif
- }
- BUG_ON(num_refs == 0);
+#endif
+ }
item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
if (refs)
*refs = num_refs;
@@ -2033,6 +2029,12 @@ pinit:
return 0;
}
+void btrfs_pin_extent(struct btrfs_fs_info *fs_info,
+ u64 bytenr, u64 num_bytes)
+{
+ update_pinned_extents(fs_info->extent_root, bytenr, num_bytes, 1);
+}
+
/*
* remove an extent from the root, returns 0 on success
*/
Index: btrfs-progs-v0.19-118-gfdb6c04/print-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/print-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/print-tree.c
@@ -239,7 +239,7 @@ static void print_extent_item(struct ext
btrfs_shared_data_ref_count(eb, sref));
break;
default:
- BUG();
+ return;
}
ptr += btrfs_extent_inline_ref_size(type);
}

View File

@ -1,277 +0,0 @@
From 395fb7119f0aa110a2b8988e68159ff1fcf1f7f0 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 7 Feb 2012 08:36:38 -0500
Subject: [PATCH 07/18] btrfs-corrupt-block: add -E option to randomly corrupt
the extent_root
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfs-corrupt-block.c | 132 +++++++++++++++++++++++++++++++++++++++----------
extent-tree.c | 9 ++-
2 files changed, 111 insertions(+), 30 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 59e7cb4..9ad3e05 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -93,17 +93,9 @@ static void print_usage(void)
exit(1);
}
-static struct option long_options[] = {
- /* { "byte-count", 1, NULL, 'b' }, */
- { "logical", 1, NULL, 'l' },
- { "copy", 1, NULL, 'c' },
- { "bytes", 1, NULL, 'b' },
- { 0, 0, 0, 0}
-};
-
-static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
+static int corrupt_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 bytenr, int copy)
{
- struct btrfs_trans_handle *trans;
struct btrfs_key key;
struct extent_buffer *leaf;
u32 item_size;
@@ -111,8 +103,8 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
struct btrfs_path *path;
int ret;
int slot;
+ int should_del = rand() % 3;
- trans = btrfs_start_transaction(root, 1);
path = btrfs_alloc_path();
key.objectid = bytenr;
@@ -121,7 +113,7 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
while(1) {
ret = btrfs_search_slot(trans, root->fs_info->extent_root,
- &key, path, 0, 1);
+ &key, path, -1, 1);
if (ret < 0)
break;
@@ -129,6 +121,7 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
if (path->slots[0] == 0)
break;
path->slots[0]--;
+ ret = 0;
}
leaf = path->nodes[0];
slot = path->slots[0];
@@ -144,13 +137,26 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
key.type != BTRFS_SHARED_DATA_REF_KEY)
goto next;
- fprintf(stderr, "corrupting extent record: key %Lu %u %Lu\n",
- key.objectid, key.type, key.offset);
+ if (should_del) {
+ fprintf(stderr, "deleting 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);
+ 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);
@@ -161,12 +167,65 @@ next:
}
btrfs_free_path(path);
- btrfs_commit_transaction(trans, root);
- ret = close_ctree(root);
- BUG_ON(ret);
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' },
+ { 0, 0, 0, 0}
+};
+
+
int main(int ac, char **av)
{
struct cache_tree root_cache;
@@ -178,11 +237,14 @@ int main(int ac, char **av)
int option_index = 0;
int copy = 0;
u64 bytes = 4096;
- int extent_rec;
+ int extent_rec = 0;
+ int extent_tree = 0;
+
+ srand(128);
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:e", long_options,
+ c = getopt_long(ac, av, "l:c:eE", long_options,
&option_index);
if (c < 0)
break;
@@ -214,6 +276,9 @@ int main(int ac, char **av)
case 'e':
extent_rec = 1;
break;
+ case 'E':
+ extent_tree = 1;
+ break;
default:
print_usage();
}
@@ -221,7 +286,7 @@ int main(int ac, char **av)
ac = ac - optind;
if (ac == 0)
print_usage();
- if (logical == 0)
+ if (logical == 0 && !extent_tree)
print_usage();
if (copy < 0)
print_usage();
@@ -237,8 +302,19 @@ int main(int ac, char **av)
exit(1);
}
if (extent_rec) {
- ret = corrupt_extent (root, logical, 0);
- goto out;
+ 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)
@@ -253,6 +329,8 @@ int main(int ac, char **av)
logical += root->sectorsize;
bytes -= root->sectorsize;
}
-out:
+ return ret;
+out_close:
+ close_ctree(root);
return ret;
}
diff --git a/extent-tree.c b/extent-tree.c
index 1f13992..01dfa3f 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1083,7 +1083,9 @@ static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
ptr += sizeof(struct btrfs_tree_block_info);
BUG_ON(ptr > end);
} else {
- BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA));
+ if (!(flags & BTRFS_EXTENT_FLAG_DATA)) {
+ return -EIO;
+ }
}
err = -ENOENT;
@@ -2120,8 +2122,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
extent_slot = path->slots[0];
}
} else {
- btrfs_print_leaf(extent_root, path->nodes[0]);
- WARN_ON(1);
printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
"parent %llu root %llu owner %llu offset %llu\n",
(unsigned long long)bytenr,
@@ -2129,6 +2129,8 @@ static int __free_extent(struct btrfs_trans_handle *trans,
(unsigned long long)root_objectid,
(unsigned long long)owner_objectid,
(unsigned long long)owner_offset);
+ ret = -EIO;
+ goto fail;
}
leaf = path->nodes[0];
@@ -2238,6 +2240,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
mark_free);
BUG_ON(ret);
}
+fail:
btrfs_free_path(path);
finish_current_insert(trans, extent_root);
return ret;
--
1.7.6.233.gd79bc

View File

@ -1,393 +0,0 @@
From 4fc0390c2bbce8a5b39fb592da80bfe1870152a4 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 21:29:13 -0500
Subject: [PATCH 08/18] btrfsck: fix block group accounting during repair
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 36 +++++++++-----
convert.c | 62 +-----------------------
ctree.h | 3 +
extent-tree.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 174 insertions(+), 75 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -2725,7 +2725,7 @@ static int add_root_to_pending(struct ex
static int delete_extent_records(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- u64 bytenr)
+ u64 bytenr, u64 new_len)
{
struct btrfs_key key;
struct btrfs_key found_key;
@@ -2787,7 +2787,7 @@ static int delete_extent_records(struct
if (found_key.type == BTRFS_EXTENT_ITEM_KEY) {
ret = btrfs_update_block_group(trans, root, bytenr,
- found_key.offset, 0, 1);
+ found_key.offset, 0, 0);
if (ret)
break;
}
@@ -2959,7 +2959,7 @@ static int fixup_extent_refs(struct btrf
/* step one, delete all the existing records */
ret = delete_extent_records(trans, info->extent_root, path,
- rec->start);
+ rec->start, rec->max_size);
if (ret < 0)
goto out;
@@ -2987,19 +2987,16 @@ out:
return ret;
}
-static int check_extent_refs(struct btrfs_root *root,
- struct cache_tree *extent_cache, int repair)
+static int check_extent_refs(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct cache_tree *extent_cache, int repair)
{
struct extent_record *rec;
struct cache_extent *cache;
- struct btrfs_trans_handle *trans = NULL;
int err = 0;
int ret = 0;
int fixed = 0;
- if (repair)
- trans = btrfs_start_transaction(root, 1);
-
if (repair) {
/*
* if we're doing a repair, we have to make sure
@@ -3074,12 +3071,12 @@ repair_abort:
fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
exit(1);
}
- btrfs_commit_transaction(trans, root);
}
return err;
}
-static int check_extents(struct btrfs_root *root, int repair)
+static int check_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, int repair)
{
struct cache_tree extent_cache;
struct cache_tree seen;
@@ -3160,7 +3157,7 @@ static int check_extents(struct btrfs_ro
if (ret != 0)
break;
}
- ret = check_extent_refs(root, &extent_cache, repair);
+ ret = check_extent_refs(trans, root, &extent_cache, repair);
free(bits);
return ret;
}
@@ -3183,6 +3180,7 @@ int main(int ac, char **av)
struct cache_tree root_cache;
struct btrfs_root *root;
struct btrfs_fs_info *info;
+ struct btrfs_trans_handle *trans = NULL;
u64 bytenr = 0;
int ret;
int num;
@@ -3244,9 +3242,16 @@ int main(int ac, char **av)
root = info->fs_root;
fprintf(stderr, "checking extents\n");
- ret = check_extents(root, repair);
+ if (repair)
+ trans = btrfs_start_transaction(root, 1);
+
+ ret = check_extents(trans, root, repair);
if (ret)
goto out;
+
+ if (repair)
+ btrfs_fix_block_accounting(trans, root);
+
fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
if (ret)
@@ -3256,6 +3261,11 @@ int main(int ac, char **av)
ret = check_root_refs(root, &root_cache);
out:
free_root_recs(&root_cache);
+ if (repair) {
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret)
+ exit(1);
+ }
close_ctree(root);
if (found_old_backref) {
Index: btrfs-progs-v0.19-118-gfdb6c04/convert.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/convert.c
+++ btrfs-progs-v0.19-118-gfdb6c04/convert.c
@@ -1504,66 +1504,6 @@ fail:
return new_root;
}
-/*
- * Fixup block accounting. The initial block accounting created by
- * make_block_groups isn't accuracy in this case.
- */
-static int fixup_block_accounting(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- int ret;
- int slot;
- u64 start = 0;
- u64 bytes_used = 0;
- struct btrfs_path path;
- struct btrfs_key key;
- struct extent_buffer *leaf;
- struct btrfs_block_group_cache *cache;
- struct btrfs_fs_info *fs_info = root->fs_info;
-
- while(1) {
- cache = btrfs_lookup_block_group(fs_info, start);
- if (!cache)
- break;
- start = cache->key.objectid + cache->key.offset;
- btrfs_set_block_group_used(&cache->item, 0);
- cache->space_info->bytes_used = 0;
- }
-
- btrfs_init_path(&path);
- key.offset = 0;
- key.objectid = 0;
- btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
- ret = btrfs_search_slot(trans, root->fs_info->extent_root,
- &key, &path, 0, 0);
- if (ret < 0)
- return ret;
- while(1) {
- leaf = path.nodes[0];
- slot = path.slots[0];
- if (slot >= btrfs_header_nritems(leaf)) {
- ret = btrfs_next_leaf(root, &path);
- if (ret < 0)
- return ret;
- if (ret > 0)
- break;
- leaf = path.nodes[0];
- slot = path.slots[0];
- }
- btrfs_item_key_to_cpu(leaf, &key, slot);
- if (key.type == BTRFS_EXTENT_ITEM_KEY) {
- bytes_used += key.offset;
- ret = btrfs_update_block_group(trans, root,
- key.objectid, key.offset, 1, 0);
- BUG_ON(ret);
- }
- path.slots[0]++;
- }
- btrfs_set_super_bytes_used(&root->fs_info->super_copy, bytes_used);
- btrfs_release_path(root, &path);
- return 0;
-}
-
static int create_chunk_mapping(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
@@ -1735,7 +1675,7 @@ static int init_btrfs(struct btrfs_root
ret = btrfs_make_block_groups(trans, root);
if (ret)
goto err;
- ret = fixup_block_accounting(trans, root);
+ ret = btrfs_fixup_block_accounting(trans, root);
if (ret)
goto err;
ret = create_chunk_mapping(trans, root);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -1785,6 +1785,9 @@ static inline u32 btrfs_level_size(struc
btrfs_item_offset_nr(leaf, slot)))
/* extent-tree.c */
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
+int btrfs_check_block_accounting(struct btrfs_root *root);
void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -1734,7 +1734,12 @@ static int update_space_info(struct btrf
if (found) {
found->total_bytes += total_bytes;
found->bytes_used += bytes_used;
- WARN_ON(found->total_bytes < found->bytes_used);
+ if (found->total_bytes < found->bytes_used) {
+ fprintf(stderr, "warning, bad space info total_bytes "
+ "%llu used %llu\n",
+ (unsigned long long)found->total_bytes,
+ (unsigned long long)found->bytes_used);
+ }
*space_info = found;
return 0;
}
@@ -1853,6 +1858,7 @@ static int update_block_group(struct btr
old_val = btrfs_block_group_used(&cache->item);
num_bytes = min(total, cache->key.offset - byte_in_group);
+
if (alloc) {
old_val += num_bytes;
cache->space_info->bytes_used += num_bytes;
@@ -3274,3 +3280,143 @@ int btrfs_update_block_group(struct btrf
return update_block_group(trans, root, bytenr, num_bytes,
alloc, mark_free);
}
+
+static int btrfs_count_extents_in_block_group(struct btrfs_root *root,
+ struct btrfs_path *path, u64 start,
+ u64 len,
+ u64 *total)
+{
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ u64 bytes_used = 0;
+ int ret;
+ int slot;
+
+ key.offset = 0;
+ key.objectid = start;
+ btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
+ ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
+ &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+ while(1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ break;
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ }
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.objectid > start + len)
+ break;
+ if (key.type == BTRFS_EXTENT_ITEM_KEY)
+ bytes_used += key.offset;
+ path->slots[0]++;
+ }
+ *total = bytes_used;
+ btrfs_release_path(root, path);
+ return 0;
+}
+
+int btrfs_check_block_accounting(struct btrfs_root *root)
+{
+ int ret;
+ u64 start = 0;
+ u64 bytes_used = 0;
+ struct btrfs_path path;
+ struct btrfs_block_group_cache *cache;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ btrfs_init_path(&path);
+
+ while(1) {
+ cache = btrfs_lookup_block_group(fs_info, start);
+ if (!cache)
+ break;
+
+ ret = btrfs_count_extents_in_block_group(root, &path,
+ cache->key.objectid,
+ cache->key.offset,
+ &bytes_used);
+
+ if (ret == 0) {
+ u64 on_disk = btrfs_block_group_used(&cache->item);
+ if (on_disk != bytes_used) {
+ fprintf(stderr, "bad block group accounting found %llu "
+ "expected %llu block group %llu\n",
+ (unsigned long long)bytes_used,
+ (unsigned long long)on_disk,
+ (unsigned long long)cache->key.objectid);
+ }
+ }
+ start = cache->key.objectid + cache->key.offset;
+
+ cache->space_info->bytes_used = 0;
+ }
+ return 0;
+}
+
+/*
+ * Fixup block accounting. The initial block accounting created by
+ * make_block_groups isn't accuracy in this case.
+ */
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ int ret;
+ int slot;
+ u64 start = 0;
+ u64 bytes_used = 0;
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ struct btrfs_block_group_cache *cache;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ while(1) {
+ cache = btrfs_lookup_block_group(fs_info, start);
+ if (!cache)
+ break;
+ start = cache->key.objectid + cache->key.offset;
+ btrfs_set_block_group_used(&cache->item, 0);
+ cache->space_info->bytes_used = 0;
+ }
+
+ btrfs_init_path(&path);
+ key.offset = 0;
+ key.objectid = 0;
+ btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
+ ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+ &key, &path, 0, 0);
+ if (ret < 0)
+ return ret;
+ while(1) {
+ leaf = path.nodes[0];
+ slot = path.slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, &path);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ break;
+ leaf = path.nodes[0];
+ slot = path.slots[0];
+ }
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.type == BTRFS_EXTENT_ITEM_KEY) {
+ bytes_used += key.offset;
+ ret = btrfs_update_block_group(trans, root,
+ key.objectid, key.offset, 1, 0);
+ BUG_ON(ret);
+ }
+ path.slots[0]++;
+ }
+ btrfs_set_super_bytes_used(&root->fs_info->super_copy, bytes_used);
+ btrfs_release_path(root, &path);
+ return 0;
+}

View File

@ -1,26 +0,0 @@
From 6608cffe25fb1d1c3c33caffc98f2f9ba59ed2e6 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 21:38:20 -0500
Subject: [PATCH 09/18] Turn off some commands in Makefile
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Makefile b/Makefile
index 055d2d6..930500e 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ LIBS=-luuid
RESTORE_LIBS=-lz -llzo2
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
- btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block \
+ btrfs btrfs-map-logical btrfs-image btrfs-zero-log \
btrfs-dump-super
btrfs_man_page_source = btrfs.c btrfs_cmds.c scrub.c
--
1.7.6.233.gd79bc

View File

@ -1,78 +0,0 @@
From 46f7f481f4270304f358c4c6a0020ca0ca7b9e97 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 22:26:26 -0500
Subject: [PATCH 10/18] Fix btrfs-convert, btrfs-restore and btrfs-find-root
build
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fixit
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 14 +++++++-------
convert.c | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
index 930500e..556bcce 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,8 @@ LIBS=-luuid
RESTORE_LIBS=-lz -llzo2
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
- btrfs btrfs-map-logical btrfs-image btrfs-zero-log \
+ btrfs btrfs-map-logical btrfs-image btrfs-zero-log btrfs-convert \
+ btrfs-find-root btrfs-restore btrfstune \
btrfs-dump-super
btrfs_man_page_source = btrfs.c btrfs_cmds.c scrub.c
@@ -47,11 +48,11 @@ btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o helpmsg.o
calc-size: $(objects) calc-size.o
gcc $(CFLAGS) -o calc-size calc-size.o $(objects) $(LDFLAGS) $(LIBS)
-find-root: $(objects) find-root.o
- gcc $(CFLAGS) -o find-root find-root.o $(objects) $(LDFLAGS) $(LIBS)
+btrfs-find-root: $(objects) find-root.o
+ gcc $(CFLAGS) -o btrfs-find-root find-root.o $(objects) $(LDFLAGS) $(LIBS)
-restore: $(objects) restore.o
- gcc $(CFLAGS) -o restore restore.o $(objects) $(LDFLAGS) $(LIBS) $(RESTORE_LIBS)
+btrfs-restore: $(objects) restore.o
+ gcc $(CFLAGS) -o btrfs-restore restore.o $(objects) $(LDFLAGS) $(LIBS) $(RESTORE_LIBS)
btrfsctl: $(objects) btrfsctl.o
$(CC) $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS)
@@ -98,7 +99,7 @@ dir-test: $(objects) dir-test.o
quick-test: $(objects) quick-test.o
$(CC) $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS)
-convert: $(objects) convert.o
+btrfs-convert: $(objects) convert.o
$(CC) $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lcom_err $(LDFLAGS) $(LIBS)
ioctl-test: $(objects) ioctl-test.o
@@ -140,7 +141,6 @@ 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
test: test-userspace test-root
diff --git a/convert.c b/convert.c
index a2f7925..5afcc45 100644
--- a/convert.c
+++ b/convert.c
@@ -1675,7 +1675,7 @@ static int init_btrfs(struct btrfs_root *root)
ret = btrfs_make_block_groups(trans, root);
if (ret)
goto err;
- ret = btrfs_fixup_block_accounting(trans, root);
+ ret = btrfs_fix_block_accounting(trans, root);
if (ret)
goto err;
ret = create_chunk_mapping(trans, root);
--
1.7.6.233.gd79bc

View File

@ -1,43 +0,0 @@
From 494ba283ed46df812d56652d6ccc1b548bb5fe17 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 9 Feb 2012 09:29:19 -0500
Subject: [PATCH 11/18] btrfsck: make sure to dirty all block groups as we fix
accounting
The code that corrects the count of bytes used in each block group
was only marking block groups dirty when they contained extents. This
fixes things to dirty all the block groups, so any empty block groups
are written with their correct (zero) count.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
extent-tree.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/extent-tree.c b/extent-tree.c
index 544ab2f..5c4057e 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -3378,6 +3378,8 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *fs_info = root->fs_info;
+ root = root->fs_info->extent_root;
+
while(1) {
cache = btrfs_lookup_block_group(fs_info, start);
if (!cache)
@@ -3385,6 +3387,10 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
start = cache->key.objectid + cache->key.offset;
btrfs_set_block_group_used(&cache->item, 0);
cache->space_info->bytes_used = 0;
+ set_extent_bits(&root->fs_info->block_group_cache,
+ cache->key.objectid,
+ cache->key.objectid + cache->key.offset -1,
+ BLOCK_GROUP_DIRTY, GFP_NOFS);
}
btrfs_init_path(&path);
--
1.7.6.233.gd79bc

View File

@ -1,179 +0,0 @@
From 80a0a84e46d07d2b2b07991ee2813b017301786c Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 9 Feb 2012 10:38:05 -0500
Subject: [PATCH 12/18] btrfsck: add --init-csum-tree to replace the csum root
with an empty one
This will effectively delete all of your crcs, but at least you'll
be able to mount the FS with nodatasum.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 27 ++++++++++++++++++++++-----
ctree.c | 40 ++++++++++++++++++++++++++++++++++++++++
ctree.h | 2 ++
disk-io.c | 3 ++-
4 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 1320238..a451397 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -3171,6 +3171,7 @@ static void print_usage(void)
static struct option long_options[] = {
{ "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 },
+ { "init-csum-tree", 0, NULL, 0 },
{ 0, 0, 0, 0}
};
@@ -3185,6 +3186,8 @@ int main(int ac, char **av)
int num;
int repair = 0;
int option_index = 0;
+ int init_csum_tree = 0;
+ int rw = 0;
while(1) {
int c;
@@ -3206,6 +3209,11 @@ int main(int ac, char **av)
if (option_index == 1) {
printf("enabling repair mode\n");
repair = 1;
+ rw = 1;
+ } else if (option_index == 2) {
+ printf("Creating a new CRC tree\n");
+ init_csum_tree = 1;
+ rw = 1;
}
}
@@ -3225,7 +3233,7 @@ int main(int ac, char **av)
return -EBUSY;
}
- info = open_ctree_fs_info(av[optind], bytenr, repair, 1);
+ info = open_ctree_fs_info(av[optind], bytenr, rw, 1);
if (info == NULL)
return 1;
@@ -3241,9 +3249,19 @@ int main(int ac, char **av)
root = info->fs_root;
fprintf(stderr, "checking extents\n");
- if (repair)
+ if (rw)
trans = btrfs_start_transaction(root, 1);
+ if (init_csum_tree) {
+ fprintf(stderr, "Reinit crc root\n");
+ ret = btrfs_fsck_reinit_root(trans, info->csum_root);
+ if (ret) {
+ fprintf(stderr, "crc root initialization failed\n");
+ return -EIO;
+ }
+ goto out;
+ }
+
ret = check_extents(trans, root, repair);
if (ret)
goto out;
@@ -3260,15 +3278,14 @@ int main(int ac, char **av)
ret = check_root_refs(root, &root_cache);
out:
free_root_recs(&root_cache);
- if (repair) {
+ if (rw) {
ret = btrfs_commit_transaction(trans, root);
if (ret)
exit(1);
}
close_ctree(root);
- if (found_old_backref) {
- /*
+ if (found_old_backref) { /*
* there was a disk format change when mixed
* backref was in testing tree. The old format
* existed about one week.
diff --git a/ctree.c b/ctree.c
index 005550f..282c868 100644
--- a/ctree.c
+++ b/ctree.c
@@ -138,6 +138,46 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
return 0;
}
+int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ struct extent_buffer *c;
+ struct extent_buffer *old = root->node;
+ int level;
+ struct btrfs_disk_key disk_key = {0,0,0};
+
+ level = 0;
+
+ c = btrfs_alloc_free_block(trans, root,
+ btrfs_level_size(root, 0),
+ root->root_key.objectid,
+ &disk_key, level, 0, 0);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
+ btrfs_set_header_level(c, level);
+ btrfs_set_header_bytenr(c, c->start);
+ btrfs_set_header_generation(c, trans->transid);
+ btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
+ btrfs_set_header_owner(c, root->root_key.objectid);
+
+ write_extent_buffer(c, root->fs_info->fsid,
+ (unsigned long)btrfs_header_fsid(c),
+ BTRFS_FSID_SIZE);
+
+ write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
+ (unsigned long)btrfs_header_chunk_tree_uuid(c),
+ BTRFS_UUID_SIZE);
+
+ btrfs_mark_buffer_dirty(c);
+
+ free_extent_buffer(old);
+ root->node = c;
+ add_root_to_dirty_list(root);
+ return 0;
+}
+
/*
* check if the tree block can be shared by multiple trees
*/
diff --git a/ctree.h b/ctree.h
index 6f12869..c53f65a 100644
--- a/ctree.h
+++ b/ctree.h
@@ -1851,6 +1851,8 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 num,
int alloc, int mark_free);
/* ctree.c */
+int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot, u64 objectid);
struct extent_buffer *read_node_slot(struct btrfs_root *root,
diff --git a/disk-io.c b/disk-io.c
index e9fdba8..d9df313 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -793,7 +793,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, u64 sb_by
BTRFS_CSUM_TREE_OBJECTID, csum_root);
if (ret) {
printk("Couldn't setup csum tree\n");
- goto out_failed;
+ if (!partial)
+ goto out_failed;
}
csum_root->track_dirty = 1;
--
1.7.6.233.gd79bc

View File

@ -1,93 +0,0 @@
From 1cc34194f336d77e96bc11baec9bea765fdc9849 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 9 Feb 2012 11:53:33 -0500
Subject: [PATCH 13/18] btrfsck: make sure we fix the block group accounting
during repair
The block group accounting is fixed after we check the extent back
references. This makes sure the accounting is fixed unless we
were not able to repair the backrefs.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 12 ++++++++----
extent-tree.c | 24 ++++++++++++++++++++++++
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index a451397..3aa19ae 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -3070,7 +3070,12 @@ repair_abort:
if (ret) {
fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
exit(1);
+ } else {
+ btrfs_fix_block_accounting(trans, root);
}
+ if (err)
+ fprintf(stderr, "repaired damaged extent references\n");
+ return ret;
}
return err;
}
@@ -3263,11 +3268,10 @@ int main(int ac, char **av)
}
ret = check_extents(trans, root, repair);
- if (ret)
+ if (ret) {
+ fprintf(stderr, "check extents failed with %d!!!!!!!!!\n", ret);
goto out;
-
- if (repair)
- btrfs_fix_block_accounting(trans, root);
+ }
fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
diff --git a/extent-tree.c b/extent-tree.c
index 5c4057e..dd593fe 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1953,6 +1953,21 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
return 0;
}
+static int extent_root_pending_ops(struct btrfs_fs_info *info)
+{
+ u64 start;
+ u64 end;
+ int ret;
+
+ ret = find_first_extent_bit(&info->extent_ins, 0, &start,
+ &end, EXTENT_LOCKED);
+ if (!ret) {
+ ret = find_first_extent_bit(&info->pending_del, 0, &start, &end,
+ EXTENT_LOCKED);
+ }
+ return ret == 0;
+
+}
static int finish_current_insert(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root)
{
@@ -3380,6 +3395,15 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
root = root->fs_info->extent_root;
+ while(extent_root_pending_ops(fs_info)) {
+ ret = finish_current_insert(trans, root);
+ if (ret)
+ return ret;
+ ret = del_pending_extents(trans, root);
+ if (ret)
+ return ret;
+ }
+
while(1) {
cache = btrfs_lookup_block_group(fs_info, start);
if (!cache)
--
1.7.6.233.gd79bc

View File

@ -1,209 +0,0 @@
From a84a34ca88e7157fda4306ab87a6372e0825628d Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Fri, 10 Feb 2012 13:28:50 -0500
Subject: [PATCH 14/18] btrfsck: remove extents from the fsck reference
tracker as they are freed
During btrfsck --repair, we make an index of extents that have incorrect
reference counts. Once we've collect the whole index, we go through
and modify the extent allocation tree to reflect the correct results.
Changing the extent allocation tree may free blocks, and so it may
end up removing a block that had a missing reference structure. The
fsck code may then circle back around and add the reference back.
The result is an extent that isn't actually used, but is recorded in the
extent allocation tree.
This commit adds a hook called as extents are freed. The hook searches
the index of incorrect references and updates it to reflect the freeing
of the extent.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
ctree.h | 6 ++++
extent-tree.c | 6 ++++
3 files changed, 99 insertions(+), 7 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -2137,7 +2137,7 @@ static int add_extent_rec(struct cache_t
if (inc_ref)
rec->refs++;
if (rec->nr == 1)
- rec->nr = nr;
+ rec->nr = max(nr, max_size);
if (start != rec->start) {
fprintf(stderr, "warning, start mismatch %llu %llu\n",
@@ -2175,7 +2175,7 @@ static int add_extent_rec(struct cache_t
rec = malloc(sizeof(*rec));
rec->start = start;
rec->max_size = max_size;
- rec->nr = nr;
+ rec->nr = max(nr, max_size);
rec->content_checked = 0;
rec->owner_ref_checked = 0;
INIT_LIST_HEAD(&rec->backrefs);
@@ -2722,6 +2722,77 @@ static int add_root_to_pending(struct ex
return 0;
}
+/* as we fix the tree, we might be deleting blocks that
+ * we're tracking for repair. This hook makes sure we
+ * remove any backrefs for blocks as we are fixing them.
+ */
+static int free_extent_hook(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 root_objectid, u64 owner, u64 offset,
+ int refs_to_drop)
+{
+ struct extent_record *rec;
+ struct cache_extent *cache;
+ int is_data;
+ struct cache_tree *extent_cache = root->fs_info->fsck_extent_cache;
+
+ is_data = owner >= BTRFS_FIRST_FREE_OBJECTID;
+ cache = find_cache_extent(extent_cache, bytenr, num_bytes);
+ if (!cache)
+ return 0;
+
+ rec = container_of(cache, struct extent_record, cache);
+ if (is_data) {
+ struct data_backref *back;
+ back = find_data_backref(rec, parent, root_objectid, owner,
+ offset);
+ if (!back)
+ goto out;
+ if (back->node.found_ref) {
+ back->found_ref -= refs_to_drop;
+ if (rec->refs)
+ rec->refs -= refs_to_drop;
+ }
+ if (back->node.found_extent_tree) {
+ back->num_refs -= refs_to_drop;
+ if (rec->extent_item_refs)
+ rec->extent_item_refs -= refs_to_drop;
+ }
+ if (back->found_ref == 0)
+ back->node.found_ref = 0;
+ if (back->num_refs == 0)
+ back->node.found_extent_tree = 0;
+
+ if (!back->node.found_extent_tree && back->node.found_ref) {
+ list_del(&back->node.list);
+ free(back);
+ }
+ } else {
+ struct tree_backref *back;
+ back = find_tree_backref(rec, parent, root_objectid);
+ if (!back)
+ goto out;
+ if (back->node.found_ref) {
+ if (rec->refs)
+ rec->refs--;
+ back->node.found_ref = 0;
+ }
+ if (back->node.found_extent_tree) {
+ if (rec->extent_item_refs)
+ rec->extent_item_refs--;
+ back->node.found_extent_tree = 0;
+ }
+ if (!back->node.found_extent_tree && back->node.found_ref) {
+ list_del(&back->node.list);
+ free(back);
+ }
+ }
+ maybe_free_extent_rec(extent_cache, rec);
+out:
+ return 0;
+}
+
static int delete_extent_records(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
@@ -3008,7 +3079,7 @@ static int check_extent_refs(struct btrf
while(cache) {
rec = container_of(cache, struct extent_record, cache);
btrfs_pin_extent(root->fs_info,
- rec->start, rec->nr);
+ rec->start, rec->max_size);
cache = next_cache_extent(cache);
}
}
@@ -3105,6 +3176,11 @@ static int check_extents(struct btrfs_tr
cache_tree_init(&nodes);
cache_tree_init(&reada);
+ if (repair) {
+ root->fs_info->fsck_extent_cache = &extent_cache;
+ root->fs_info->free_extent_hook = free_extent_hook;
+ }
+
bits_nr = 1024;
bits = malloc(bits_nr * sizeof(struct block_info));
if (!bits) {
@@ -3163,6 +3239,12 @@ static int check_extents(struct btrfs_tr
break;
}
ret = check_extent_refs(trans, root, &extent_cache, repair);
+
+ if (repair) {
+ root->fs_info->fsck_extent_cache = NULL;
+ root->fs_info->free_extent_hook = NULL;
+ }
+
free(bits);
return ret;
}
@@ -3269,10 +3351,8 @@ int main(int ac, char **av)
}
ret = check_extents(trans, root, repair);
- if (ret) {
- fprintf(stderr, "check extents failed with %d!!!!!!!!!\n", ret);
- goto out;
- }
+ if (ret)
+ fprintf(stderr, "Errors found in extent allocation tree\n");
fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -797,6 +797,12 @@ struct btrfs_fs_info {
struct list_head space_info;
int system_allocs;
int readonly;
+ int (*free_extent_hook)(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 root_objectid, u64 owner, u64 offset,
+ int refs_to_drop);
+ struct cache_tree * fsck_extent_cache;
};
/*
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -2083,6 +2083,12 @@ static int __free_extent(struct btrfs_tr
u32 item_size;
u64 refs;
+ if (root->fs_info->free_extent_hook) {
+ root->fs_info->free_extent_hook(trans, root, bytenr, num_bytes,
+ parent, root_objectid, owner_objectid,
+ owner_offset, refs_to_drop);
+
+ }
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;

View File

@ -1,974 +0,0 @@
From 6ee262863cbe668c340bc9b61ebce4ee77f06d8c Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 14:37:21 -0500
Subject: [PATCH 15/18] Btrfsck: add the ability to prune corrupt extent
allocation tree blocks
When we discover bad blocks in the extent allocation tree, repair can
now discard them and recreate the references from the rest of the trees.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 2 +-
btrfs-corrupt-block.c | 71 +++++++++++++-
btrfsck.c | 269 +++++++++++++++++++++++++++++++++----------------
ctree.c | 222 +++++++++++++++++-----------------------
ctree.h | 11 ++-
repair.c | 50 +++++++++
repair.h | 32 ++++++
7 files changed, 439 insertions(+), 218 deletions(-)
create mode 100644 repair.c
create mode 100644 repair.h
Index: btrfs-progs-v0.19-118-gfdb6c04/Makefile
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/Makefile
+++ btrfs-progs-v0.19-118-gfdb6c04/Makefile
@@ -4,7 +4,7 @@ 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 btrfs-list.o btrfslabel.o
+ volumes.o utils.o btrfs-list.o btrfslabel.o repair.o
CHECKFLAGS= -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
-Wuninitialized -Wshadow -Wundef
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs-corrupt-block.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs-corrupt-block.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs-corrupt-block.c
@@ -93,6 +93,56 @@ static void print_usage(void)
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)
{
@@ -192,6 +242,11 @@ static void btrfs_corrupt_extent_tree(st
if (!eb)
return;
+ if ((rand() % 10) == 0) {
+ corrupt_keys(trans, root, eb);
+ return;
+ }
+
nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) {
btrfs_corrupt_extent_leaf(trans, root, eb);
@@ -222,6 +277,7 @@ static struct option long_options[] = {
{ "bytes", 1, NULL, 'b' },
{ "extent-record", 0, NULL, 'e' },
{ "extent-tree", 0, NULL, 'E' },
+ { "keys", 0, NULL, 'k' },
{ 0, 0, 0, 0}
};
@@ -239,12 +295,13 @@ int main(int ac, char **av)
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:eE", long_options,
+ c = getopt_long(ac, av, "l:c:eEk", long_options,
&option_index);
if (c < 0)
break;
@@ -279,6 +336,9 @@ int main(int ac, char **av)
case 'E':
extent_tree = 1;
break;
+ case 'k':
+ corrupt_block_keys = 1;
+ break;
default:
print_usage();
}
@@ -324,8 +384,13 @@ int main(int ac, char **av)
bytes *= root->sectorsize;
while (bytes > 0) {
- eb = debug_corrupt_block(root, logical, root->sectorsize, copy);
- free_extent_buffer(eb);
+ 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;
}
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -26,6 +26,7 @@
#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
+#include "repair.h"
#include "disk-io.h"
#include "print-tree.h"
#include "transaction.h"
@@ -1718,86 +1719,6 @@ static int check_fs_roots(struct btrfs_r
return err;
}
-static int check_node(struct btrfs_root *root,
- struct btrfs_disk_key *parent_key,
- struct extent_buffer *buf)
-{
- int i;
- struct btrfs_key cpukey;
- struct btrfs_disk_key key;
- u32 nritems = btrfs_header_nritems(buf);
-
- if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root))
- return 1;
- if (parent_key->type) {
- btrfs_node_key(buf, &key, 0);
- if (memcmp(parent_key, &key, sizeof(key)))
- return 1;
- }
- for (i = 0; nritems > 1 && i < nritems - 2; i++) {
- btrfs_node_key(buf, &key, i);
- btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
- if (btrfs_comp_keys(&key, &cpukey) >= 0)
- return 1;
- }
- return 0;
-}
-
-static int check_leaf(struct btrfs_root *root,
- struct btrfs_disk_key *parent_key,
- struct extent_buffer *buf)
-{
- int i;
- struct btrfs_key cpukey;
- struct btrfs_disk_key key;
- u32 nritems = btrfs_header_nritems(buf);
-
- if (btrfs_header_level(buf) != 0) {
- fprintf(stderr, "leaf is not a leaf %llu\n",
- (unsigned long long)btrfs_header_bytenr(buf));
- return 1;
- }
- if (btrfs_leaf_free_space(root, buf) < 0) {
- fprintf(stderr, "leaf free space incorrect %llu %d\n",
- (unsigned long long)btrfs_header_bytenr(buf),
- btrfs_leaf_free_space(root, buf));
- return 1;
- }
-
- if (nritems == 0)
- return 0;
-
- btrfs_item_key(buf, &key, 0);
- if (parent_key->type && memcmp(parent_key, &key, sizeof(key))) {
- fprintf(stderr, "leaf parent key incorrect %llu\n",
- (unsigned long long)btrfs_header_bytenr(buf));
- return 1;
- }
- for (i = 0; nritems > 1 && i < nritems - 2; i++) {
- btrfs_item_key(buf, &key, i);
- btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
- if (btrfs_comp_keys(&key, &cpukey) >= 0) {
- fprintf(stderr, "bad key ordering %d %d\n", i, i+1);
- return 1;
- }
- if (btrfs_item_offset_nr(buf, i) !=
- btrfs_item_end_nr(buf, i + 1)) {
- fprintf(stderr, "incorrect offsets %u %u\n",
- btrfs_item_offset_nr(buf, i),
- btrfs_item_end_nr(buf, i + 1));
- return 1;
- }
- if (i == 0 && btrfs_item_end_nr(buf, i) !=
- BTRFS_LEAF_DATA_SIZE(root)) {
- fprintf(stderr, "bad item end %u wanted %u\n",
- btrfs_item_end_nr(buf, i),
- (unsigned)BTRFS_LEAF_DATA_SIZE(root));
- return 1;
- }
- }
- return 0;
-}
-
static int all_backpointers_checked(struct extent_record *rec, int print_errs)
{
struct list_head *cur = rec->backrefs.next;
@@ -1954,7 +1875,7 @@ static int check_owner_ref(struct btrfs_
btrfs_item_key_to_cpu(buf, &key, 0);
else
btrfs_node_key_to_cpu(buf, &key, 0);
-
+
btrfs_init_path(&path);
path.lowest_level = level + 1;
btrfs_search_slot(NULL, ref_root, &key, &path, 0, 0);
@@ -1967,6 +1888,48 @@ static int check_owner_ref(struct btrfs_
return found ? 0 : 1;
}
+static int is_extent_tree_record(struct extent_record *rec)
+{
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
+ struct tree_backref *back;
+ int is_extent = 0;
+
+ while(cur != &rec->backrefs) {
+ node = list_entry(cur, struct extent_backref, list);
+ cur = cur->next;
+ if (node->is_data)
+ return 0;
+ back = (struct tree_backref *)node;
+ if (node->full_backref)
+ return 0;
+ if (back->root == BTRFS_EXTENT_TREE_OBJECTID)
+ is_extent = 1;
+ }
+ return is_extent;
+}
+
+
+static int record_bad_block_io(struct btrfs_fs_info *info,
+ struct cache_tree *extent_cache,
+ u64 start, u64 len)
+{
+ struct extent_record *rec;
+ struct cache_extent *cache;
+ struct btrfs_key key;
+
+ cache = find_cache_extent(extent_cache, start, len);
+ if (!cache)
+ return 0;
+
+ rec = container_of(cache, struct extent_record, cache);
+ if (!is_extent_tree_record(rec))
+ return 0;
+
+ btrfs_disk_key_to_cpu(&key, &rec->parent_key);
+ return btrfs_add_corrupt_extent_record(info, &key, start, len, 0);
+}
+
static int check_block(struct btrfs_root *root,
struct cache_tree *extent_cache,
struct extent_buffer *buf, u64 flags)
@@ -1995,11 +1958,11 @@ static int check_block(struct btrfs_root
}
rec->info_level = level;
- if (btrfs_is_leaf(buf)) {
- ret = check_leaf(root, &rec->parent_key, buf);
- } else {
- ret = check_node(root, &rec->parent_key, buf);
- }
+ if (btrfs_is_leaf(buf))
+ ret = btrfs_check_leaf(root, &rec->parent_key, buf);
+ else
+ ret = btrfs_check_node(root, &rec->parent_key, buf);
+
if (ret) {
fprintf(stderr, "bad block %llu\n",
(unsigned long long)buf->start);
@@ -2550,6 +2513,13 @@ static int run_next_block(struct btrfs_r
/* fixme, get the real parent transid */
buf = read_tree_block(root, bytenr, size, 0);
+ if (!extent_buffer_uptodate(buf)) {
+ record_bad_block_io(root->fs_info,
+ extent_cache, bytenr, size);
+ free_extent_buffer(buf);
+ goto out;
+ }
+
nritems = btrfs_header_nritems(buf);
ret = btrfs_lookup_extent_info(NULL, root, bytenr, size, NULL, &flags);
@@ -2565,6 +2535,8 @@ static int run_next_block(struct btrfs_r
}
ret = check_block(root, extent_cache, buf, flags);
+ if (ret)
+ goto out;
if (btrfs_is_leaf(buf)) {
btree_space_waste += btrfs_leaf_free_space(root, buf);
@@ -2691,6 +2663,7 @@ static int run_next_block(struct btrfs_r
btrfs_header_backref_rev(buf) == BTRFS_MIXED_BACKREF_REV &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))
found_old_backref = 1;
+out:
free_extent_buffer(buf);
return 0;
}
@@ -3016,6 +2989,7 @@ static int fixup_extent_refs(struct btrf
int ret;
struct btrfs_path *path;
struct list_head *cur = rec->backrefs.next;
+ struct cache_extent *cache;
struct extent_backref *back;
int allocated = 0;
u64 flags = 0;
@@ -3035,6 +3009,13 @@ static int fixup_extent_refs(struct btrf
if (ret < 0)
goto out;
+ /* was this block corrupt? If so, don't add references to it */
+ cache = find_cache_extent(info->corrupt_blocks, rec->start, rec->max_size);
+ if (cache) {
+ ret = 0;
+ goto out;
+ }
+
/* step two, recreate all the refs we did find */
while(cur != &rec->backrefs) {
back = list_entry(cur, struct extent_backref, list);
@@ -3058,6 +3039,107 @@ out:
return ret;
}
+/* right now we only prune from the extent allocation tree */
+static int prune_one_block(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct btrfs_corrupt_block *corrupt)
+{
+ int ret;
+ struct btrfs_path path;
+ struct extent_buffer *eb;
+ u64 found;
+ int slot;
+ int nritems;
+ int level = corrupt->level + 1;
+
+ btrfs_init_path(&path);
+again:
+ /* we want to stop at the parent to our busted block */
+ path.lowest_level = level;
+
+ ret = btrfs_search_slot(trans, info->extent_root,
+ &corrupt->key, &path, -1, 1);
+
+ if (ret < 0)
+ goto out;
+
+ eb = path.nodes[level];
+ if (!eb) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /*
+ * hopefully the search gave us the block we want to prune,
+ * lets try that first
+ */
+ slot = path.slots[level];
+ found = btrfs_node_blockptr(eb, slot);
+ if (found == corrupt->cache.start)
+ goto del_ptr;
+
+ nritems = btrfs_header_nritems(eb);
+
+ /* the search failed, lets scan this node and hope we find it */
+ for (slot = 0; slot < nritems; slot++) {
+ found = btrfs_node_blockptr(eb, slot);
+ if (found == corrupt->cache.start)
+ goto del_ptr;
+ }
+ /*
+ * we couldn't find the bad block. TODO, search all the nodes for pointers
+ * to this block
+ */
+ if (eb == info->extent_root->node) {
+ ret = -ENOENT;
+ goto out;
+ } else {
+ level++;
+ btrfs_release_path(NULL, &path);
+ goto again;
+ }
+
+del_ptr:
+ printk("deleting pointer to block %Lu\n", corrupt->cache.start);
+ ret = btrfs_del_ptr(trans, info->extent_root, &path, level, slot);
+
+out:
+ btrfs_release_path(NULL, &path);
+ return ret;
+}
+
+static int prune_corrupt_blocks(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info)
+{
+ struct cache_extent *cache;
+ struct btrfs_corrupt_block *corrupt;
+
+ cache = find_first_cache_extent(info->corrupt_blocks, 0);
+ while (1) {
+ if (!cache)
+ break;
+ corrupt = container_of(cache, struct btrfs_corrupt_block, cache);
+ prune_one_block(trans, info, corrupt);
+ cache = next_cache_extent(cache);
+ }
+ return 0;
+}
+
+static void free_corrupt_blocks(struct btrfs_fs_info *info)
+{
+ struct cache_extent *cache;
+ struct btrfs_corrupt_block *corrupt;
+
+ while (1) {
+ cache = find_first_cache_extent(info->corrupt_blocks, 0);
+ if (!cache)
+ break;
+ corrupt = container_of(cache, struct btrfs_corrupt_block, cache);
+ remove_cache_extent(info->corrupt_blocks, cache);
+ free(corrupt);
+ }
+}
+
static int check_extent_refs(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct cache_tree *extent_cache, int repair)
@@ -3082,6 +3164,16 @@ static int check_extent_refs(struct btrf
rec->start, rec->max_size);
cache = next_cache_extent(cache);
}
+
+ /* pin down all the corrupted blocks too */
+ cache = find_first_cache_extent(root->fs_info->corrupt_blocks, 0);
+ while(cache) {
+ rec = container_of(cache, struct extent_record, cache);
+ btrfs_pin_extent(root->fs_info,
+ rec->start, rec->max_size);
+ cache = next_cache_extent(cache);
+ }
+ prune_corrupt_blocks(trans, root->fs_info);
}
while(1) {
fixed = 0;
@@ -3159,6 +3251,7 @@ static int check_extents(struct btrfs_tr
struct cache_tree pending;
struct cache_tree reada;
struct cache_tree nodes;
+ struct cache_tree corrupt_blocks;
struct btrfs_path path;
struct btrfs_key key;
struct btrfs_key found_key;
@@ -3175,10 +3268,12 @@ static int check_extents(struct btrfs_tr
cache_tree_init(&pending);
cache_tree_init(&nodes);
cache_tree_init(&reada);
+ cache_tree_init(&corrupt_blocks);
if (repair) {
root->fs_info->fsck_extent_cache = &extent_cache;
root->fs_info->free_extent_hook = free_extent_hook;
+ root->fs_info->corrupt_blocks = &corrupt_blocks;
}
bits_nr = 1024;
@@ -3241,8 +3336,10 @@ static int check_extents(struct btrfs_tr
ret = check_extent_refs(trans, root, &extent_cache, repair);
if (repair) {
+ free_corrupt_blocks(root->fs_info);
root->fs_info->fsck_extent_cache = NULL;
root->fs_info->free_extent_hook = NULL;
+ root->fs_info->corrupt_blocks = NULL;
}
free(bits);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.c
@@ -19,6 +19,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "print-tree.h"
+#include "repair.h"
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
@@ -32,8 +33,6 @@ static int balance_node_right(struct btr
struct btrfs_root *root,
struct extent_buffer *dst_buf,
struct extent_buffer *src_buf);
-static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
- struct btrfs_path *path, int level, int slot);
inline void btrfs_init_path(struct btrfs_path *p)
{
@@ -589,156 +588,125 @@ static inline unsigned int leaf_data_end
return btrfs_item_offset_nr(leaf, nr - 1);
}
-static int check_node(struct btrfs_root *root, struct btrfs_path *path,
- int level)
+int btrfs_check_node(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf)
{
- struct extent_buffer *parent = NULL;
- struct extent_buffer *node = path->nodes[level];
- struct btrfs_disk_key parent_key;
- struct btrfs_disk_key node_key;
- int parent_slot;
- int slot;
+ int i;
struct btrfs_key cpukey;
- u32 nritems = btrfs_header_nritems(node);
+ struct btrfs_disk_key key;
+ u32 nritems = btrfs_header_nritems(buf);
- if (path->nodes[level + 1])
- parent = path->nodes[level + 1];
+ if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root))
+ goto fail;
- slot = path->slots[level];
- BUG_ON(nritems == 0);
- if (parent) {
- parent_slot = path->slots[level + 1];
- btrfs_node_key(parent, &parent_key, parent_slot);
- btrfs_node_key(node, &node_key, 0);
- BUG_ON(memcmp(&parent_key, &node_key,
- sizeof(struct btrfs_disk_key)));
- BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
- btrfs_header_bytenr(node));
- }
- BUG_ON(nritems > BTRFS_NODEPTRS_PER_BLOCK(root));
- if (slot != 0) {
- btrfs_node_key_to_cpu(node, &cpukey, slot - 1);
- btrfs_node_key(node, &node_key, slot);
- BUG_ON(btrfs_comp_keys(&node_key, &cpukey) <= 0);
- }
- if (slot < nritems - 1) {
- btrfs_node_key_to_cpu(node, &cpukey, slot + 1);
- btrfs_node_key(node, &node_key, slot);
- BUG_ON(btrfs_comp_keys(&node_key, &cpukey) >= 0);
+ if (parent_key && parent_key->type) {
+ btrfs_node_key(buf, &key, 0);
+ if (memcmp(parent_key, &key, sizeof(key)))
+ goto fail;
+ }
+ for (i = 0; nritems > 1 && i < nritems - 2; i++) {
+ btrfs_node_key(buf, &key, i);
+ btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
+ if (btrfs_comp_keys(&key, &cpukey) >= 0)
+ goto fail;
}
return 0;
+fail:
+ if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
+ if (parent_key)
+ btrfs_disk_key_to_cpu(&cpukey, parent_key);
+ else
+ btrfs_node_key_to_cpu(buf, &cpukey, 0);
+ btrfs_add_corrupt_extent_record(root->fs_info, &cpukey,
+ buf->start, buf->len,
+ btrfs_header_level(buf));
+ }
+ return -EIO;
}
-static int check_leaf(struct btrfs_root *root, struct btrfs_path *path,
- int level)
+int btrfs_check_leaf(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf)
{
- struct extent_buffer *leaf = path->nodes[level];
- struct extent_buffer *parent = NULL;
- int parent_slot;
+ int i;
struct btrfs_key cpukey;
- struct btrfs_disk_key parent_key;
- struct btrfs_disk_key leaf_key;
- int slot = path->slots[0];
-
- u32 nritems = btrfs_header_nritems(leaf);
+ struct btrfs_disk_key key;
+ u32 nritems = btrfs_header_nritems(buf);
- if (path->nodes[level + 1])
- parent = path->nodes[level + 1];
+ if (btrfs_header_level(buf) != 0) {
+ fprintf(stderr, "leaf is not a leaf %llu\n",
+ (unsigned long long)btrfs_header_bytenr(buf));
+ goto fail;
+ }
+ if (btrfs_leaf_free_space(root, buf) < 0) {
+ fprintf(stderr, "leaf free space incorrect %llu %d\n",
+ (unsigned long long)btrfs_header_bytenr(buf),
+ btrfs_leaf_free_space(root, buf));
+ goto fail;
+ }
if (nritems == 0)
return 0;
- if (parent) {
- parent_slot = path->slots[level + 1];
- btrfs_node_key(parent, &parent_key, parent_slot);
- btrfs_item_key(leaf, &leaf_key, 0);
-
- BUG_ON(memcmp(&parent_key, &leaf_key,
- sizeof(struct btrfs_disk_key)));
- BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
- btrfs_header_bytenr(leaf));
+ btrfs_item_key(buf, &key, 0);
+ if (parent_key && parent_key->type &&
+ memcmp(parent_key, &key, sizeof(key))) {
+ fprintf(stderr, "leaf parent key incorrect %llu\n",
+ (unsigned long long)btrfs_header_bytenr(buf));
+ goto fail;
}
-#if 0
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
- btrfs_item_key_to_cpu(leaf, &cpukey, i + 1);
- btrfs_item_key(leaf, &leaf_key, i);
- if (comp_keys(&leaf_key, &cpukey) >= 0) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad key\n", i);
- BUG_ON(1);
- }
- if (btrfs_item_offset_nr(leaf, i) !=
- btrfs_item_end_nr(leaf, i + 1)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad\n", i);
- BUG_ON(1);
- }
- if (i == 0) {
- if (btrfs_item_offset_nr(leaf, i) +
- btrfs_item_size_nr(leaf, i) !=
- BTRFS_LEAF_DATA_SIZE(root)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d first offset bad\n", i);
- BUG_ON(1);
- }
+ btrfs_item_key(buf, &key, i);
+ btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
+ if (btrfs_comp_keys(&key, &cpukey) >= 0) {
+ fprintf(stderr, "bad key ordering %d %d\n", i, i+1);
+ goto fail;
+ }
+ if (btrfs_item_offset_nr(buf, i) !=
+ btrfs_item_end_nr(buf, i + 1)) {
+ fprintf(stderr, "incorrect offsets %u %u\n",
+ btrfs_item_offset_nr(buf, i),
+ btrfs_item_end_nr(buf, i + 1));
+ goto fail;
+ }
+ if (i == 0 && btrfs_item_end_nr(buf, i) !=
+ BTRFS_LEAF_DATA_SIZE(root)) {
+ fprintf(stderr, "bad item end %u wanted %u\n",
+ btrfs_item_end_nr(buf, i),
+ (unsigned)BTRFS_LEAF_DATA_SIZE(root));
+ goto fail;
}
}
- if (nritems > 0) {
- if (btrfs_item_size_nr(leaf, nritems - 1) > 4096) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d bad size \n", nritems - 1);
- BUG_ON(1);
- }
- }
-#endif
- if (slot != 0 && slot < nritems - 1) {
- btrfs_item_key(leaf, &leaf_key, slot);
- btrfs_item_key_to_cpu(leaf, &cpukey, slot - 1);
- if (btrfs_comp_keys(&leaf_key, &cpukey) <= 0) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad key\n", slot);
- BUG_ON(1);
- }
- if (btrfs_item_offset_nr(leaf, slot - 1) !=
- btrfs_item_end_nr(leaf, slot)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad\n", slot);
- BUG_ON(1);
- }
- }
- if (slot < nritems - 1) {
- btrfs_item_key(leaf, &leaf_key, slot);
- btrfs_item_key_to_cpu(leaf, &cpukey, slot + 1);
- BUG_ON(btrfs_comp_keys(&leaf_key, &cpukey) >= 0);
- if (btrfs_item_offset_nr(leaf, slot) !=
- btrfs_item_end_nr(leaf, slot + 1)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad\n", slot);
- BUG_ON(1);
- }
- }
- BUG_ON(btrfs_item_offset_nr(leaf, 0) +
- btrfs_item_size_nr(leaf, 0) != BTRFS_LEAF_DATA_SIZE(root));
return 0;
+fail:
+ if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
+ if (parent_key)
+ btrfs_disk_key_to_cpu(&cpukey, parent_key);
+ else
+ btrfs_item_key_to_cpu(buf, &cpukey, 0);
+
+ btrfs_add_corrupt_extent_record(root->fs_info, &cpukey,
+ buf->start, buf->len, 0);
+ }
+ return -EIO;
}
static int noinline check_block(struct btrfs_root *root,
struct btrfs_path *path, int level)
{
- return 0;
-#if 0
- struct extent_buffer *buf = path->nodes[level];
+ struct btrfs_disk_key key;
+ struct btrfs_disk_key *key_ptr = NULL;
+ struct extent_buffer *parent;
- if (memcmp_extent_buffer(buf, root->fs_info->fsid,
- (unsigned long)btrfs_header_fsid(buf),
- BTRFS_FSID_SIZE)) {
- printk("warning bad block %Lu\n", buf->start);
- return 1;
+ if (path->nodes[level + 1]) {
+ parent = path->nodes[level + 1];
+ btrfs_node_key(parent, &key, path->slots[level + 1]);
+ key_ptr = &key;
}
-#endif
if (level == 0)
- return check_leaf(root, path, level);
- return check_node(root, path, level);
+ return btrfs_check_leaf(root, key_ptr, path->nodes[0]);
+ return btrfs_check_node(root, key_ptr, path->nodes[level]);
}
/*
@@ -924,8 +892,8 @@ static int balance_level(struct btrfs_tr
wait_on_tree_block_writeback(root, right);
free_extent_buffer(right);
right = NULL;
- wret = del_ptr(trans, root, path, level + 1, pslot +
- 1);
+ wret = btrfs_del_ptr(trans, root, path,
+ level + 1, pslot + 1);
if (wret)
ret = wret;
wret = btrfs_free_extent(trans, root, bytenr,
@@ -972,7 +940,7 @@ static int balance_level(struct btrfs_tr
wait_on_tree_block_writeback(root, mid);
free_extent_buffer(mid);
mid = NULL;
- wret = del_ptr(trans, root, path, level + 1, pslot);
+ wret = btrfs_del_ptr(trans, root, path, level + 1, pslot);
if (wret)
ret = wret;
wret = btrfs_free_extent(trans, root, bytenr, blocksize,
@@ -2699,7 +2667,7 @@ int btrfs_insert_item(struct btrfs_trans
* continuing all the way the root if required. The root is converted into
* a leaf if all the nodes are emptied.
*/
-static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int level, int slot)
{
struct extent_buffer *parent = path->nodes[level];
@@ -2751,7 +2719,7 @@ static noinline int btrfs_del_leaf(struc
int ret;
WARN_ON(btrfs_header_generation(leaf) != trans->transid);
- ret = del_ptr(trans, root, path, 1, path->slots[1]);
+ ret = btrfs_del_ptr(trans, root, path, 1, path->slots[1]);
if (ret)
return ret;
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -802,7 +802,8 @@ struct btrfs_fs_info {
u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 owner, u64 offset,
int refs_to_drop);
- struct cache_tree * fsck_extent_cache;
+ struct cache_tree *fsck_extent_cache;
+ struct cache_tree *corrupt_blocks;
};
/*
@@ -1857,6 +1858,14 @@ int btrfs_update_block_group(struct btrf
struct btrfs_root *root, u64 bytenr, u64 num,
int alloc, int mark_free);
/* ctree.c */
+int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_path *path, int level, int slot);
+int btrfs_check_node(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf);
+int btrfs_check_leaf(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf);
int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
diff --git a/repair.c b/repair.c
new file mode 100644
index 0000000..e640465
--- /dev/null
+++ b/repair.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "ctree.h"
+#include "extent-cache.h"
+#include "utils.h"
+#include "repair.h"
+
+int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info,
+ struct btrfs_key *first_key,
+ u64 start, u64 len, int level)
+
+{
+ int ret = 0;
+ struct btrfs_corrupt_block *corrupt;
+
+ if (!info->corrupt_blocks)
+ return 0;
+
+ corrupt = malloc(sizeof(*corrupt));
+ if (!corrupt)
+ return -ENOMEM;
+
+ memcpy(&corrupt->key, first_key, sizeof(*first_key));
+ corrupt->cache.start = start;
+ corrupt->cache.size = len;
+ corrupt->level = level;
+
+ ret = insert_existing_cache_extent(info->corrupt_blocks, &corrupt->cache);
+ if (ret)
+ free(corrupt);
+ BUG_ON(ret && ret != -EEXIST);
+ return ret;
+}
+
diff --git a/repair.h b/repair.h
new file mode 100644
index 0000000..3d0dcb9
--- /dev/null
+++ b/repair.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef __BTRFS_REPAIR__
+#define __BTRFS_REPAIR__
+
+struct btrfs_corrupt_block {
+ struct cache_extent cache;
+ struct btrfs_key key;
+ int level;
+};
+
+int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info,
+ struct btrfs_key *first_key,
+ u64 start, u64 len, int level);
+
+#endif
--
1.7.6.233.gd79bc

View File

@ -1,36 +0,0 @@
From 8ded348cf85fd8572d4ee7fc9d0cad150f4fc2be Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 15:33:20 -0500
Subject: [PATCH 16/18] Btrfs: use /proc/partitions scanning for
btrfs_scan_for_fsid
btrfs_scan_for_fsid is used by open_ctree and by mkfs when it is
checking for mounted devices. It currently scans all of /dev,
which is rarely the right answer.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
utils.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/utils.c b/utils.c
index cfb8fde..2d82342 100644
--- a/utils.c
+++ b/utils.c
@@ -1052,7 +1052,12 @@ fail:
int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
int run_ioctls)
{
- return btrfs_scan_one_dir("/dev", run_ioctls);
+ int ret;
+
+ ret = btrfs_scan_block_devices(run_ioctls);
+ if (ret)
+ ret = btrfs_scan_one_dir("/dev", run_ioctls);
+ return ret;
}
int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
--
1.7.6.233.gd79bc

View File

@ -1,93 +0,0 @@
From bde44c1e4808c8b3d7291d2ad22536d4b5d7e2f5 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 15:56:10 -0500
Subject: [PATCH 17/18] Scan /dev/md and device mapper devices last
When we're using multipath or raid0, it is possible
that btrfs dev scan will find one of the component devices
instead of the proper virtual device the kernel creates.
We want to make sure the kernel scans the virtual devices last,
since it always remembers the last device it finds with a given fsid.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
utils.c | 25 ++++++++++++++++++++++++-
volumes.c | 9 ++++++++-
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/utils.c b/utils.c
index 2d82342..0beaf80 100644
--- a/utils.c
+++ b/utils.c
@@ -1156,7 +1156,10 @@ int btrfs_scan_block_devices(int run_ioctl)
int i;
char buf[1024];
char fullpath[110];
+ int scans = 0;
+ int special;
+scan_again:
proc_partitions = fopen("/proc/partitions","r");
if (!proc_partitions) {
fprintf(stderr, "Unable to open '/proc/partitions' for scanning\n");
@@ -1172,8 +1175,23 @@ int btrfs_scan_block_devices(int run_ioctl)
strcpy(fullpath,"/dev/");
while(fgets(buf, 1023, proc_partitions)) {
-
i = sscanf(buf," %*d %*d %*d %99s", fullpath+5);
+
+ /*
+ * multipath and MD devices may register as a btrfs filesystem
+ * both through the original block device and through
+ * the special (/dev/mapper or /dev/mdX) entry.
+ * This scans the special entries last
+ */
+ special = strncmp(fullpath, "/dev/dm-", strlen("/dev/dm-")) == 0;
+ if (!special)
+ special = strncmp(fullpath, "/dev/md", strlen("/dev/md")) == 0;
+
+ if (scans == 0 && special)
+ continue;
+ if (scans > 0 && !special)
+ continue;
+
ret = lstat(fullpath, &st);
if (ret < 0) {
fprintf(stderr, "failed to stat %s\n", fullpath);
@@ -1198,6 +1216,11 @@ int btrfs_scan_block_devices(int run_ioctl)
}
fclose(proc_partitions);
+
+ if (scans == 0) {
+ scans++;
+ goto scan_again;
+ }
return 0;
}
diff --git a/volumes.c b/volumes.c
index 74c88de..e7f4c3e 100644
--- a/volumes.c
+++ b/volumes.c
@@ -130,7 +130,14 @@ static int device_list_add(const char *path,
btrfs_stack_device_bytes_used(&disk_super->dev_item);
list_add(&device->dev_list, &fs_devices->devices);
device->fs_devices = fs_devices;
- }
+ } else if (!device->name || strcmp(device->name, path)) {
+ char *name = strdup(path);
+ if (!name)
+ return -ENOMEM;
+ kfree(device->name);
+ device->name = name;
+ }
+
if (found_transid > fs_devices->latest_trans) {
fs_devices->latest_devid = devid;
--
1.7.6.233.gd79bc

View File

@ -1,285 +0,0 @@
From 6d1e1b7a4cfd1e0ab93efa42c14759848a26a6d4 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 21:20:54 -0500
Subject: [PATCH 18/18] btrfsck: add early code to handle corrupted block
groups
This is mostly disabled, but it is step one in handling
corrupted block groups in the extent allocation tree.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfs-corrupt-block.c | 5 ----
btrfsck.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-
ctree.c | 8 +++++-
extent-tree.c | 19 ++++++----------
volumes.c | 12 ----------
volumes.h | 13 +++++++++++
6 files changed, 81 insertions(+), 32 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 980a006..7051e99 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -242,11 +242,6 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
if (!eb)
return;
- if ((rand() % 10) == 0) {
- corrupt_keys(trans, root, eb);
- return;
- }
-
nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) {
btrfs_corrupt_extent_leaf(trans, root, eb);
diff --git a/btrfsck.c b/btrfsck.c
index 7dc84b5..c1a28bc 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -26,6 +26,7 @@
#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
+#include "volumes.h"
#include "repair.h"
#include "disk-io.h"
#include "print-tree.h"
@@ -3140,6 +3141,55 @@ static void free_corrupt_blocks(struct btrfs_fs_info *info)
}
}
+static int check_block_group(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct map_lookup *map,
+ int *reinit)
+{
+ struct btrfs_key key;
+ struct btrfs_path path;
+ int ret;
+
+ key.objectid = map->ce.start;
+ key.offset = map->ce.size;
+ key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+
+ btrfs_init_path(&path);
+ ret = btrfs_search_slot(NULL, info->extent_root,
+ &key, &path, 0, 0);
+ btrfs_release_path(NULL, &path);
+ if (ret <= 0)
+ goto out;
+
+ ret = btrfs_make_block_group(trans, info->extent_root, 0, map->type,
+ BTRFS_FIRST_CHUNK_TREE_OBJECTID,
+ key.objectid, key.offset);
+ *reinit = 1;
+out:
+ return ret;
+}
+
+static int check_block_groups(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info, int *reinit)
+{
+ struct cache_extent *ce;
+ struct map_lookup *map;
+ struct btrfs_mapping_tree *map_tree = &info->mapping_tree;
+
+ /* this isn't quite working */
+ return 0;
+
+ ce = find_first_cache_extent(&map_tree->cache_tree, 0);
+ while (1) {
+ if (!ce)
+ break;
+ map = container_of(ce, struct map_lookup, ce);
+ check_block_group(trans, info, map, reinit);
+ ce = next_cache_extent(ce);
+ }
+ return 0;
+}
+
static int check_extent_refs(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct cache_tree *extent_cache, int repair)
@@ -3149,6 +3199,7 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
int err = 0;
int ret = 0;
int fixed = 0;
+ int reinit = 0;
if (repair) {
/*
@@ -3174,6 +3225,9 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
cache = next_cache_extent(cache);
}
prune_corrupt_blocks(trans, root->fs_info);
+ check_block_groups(trans, root->fs_info, &reinit);
+ if (reinit)
+ btrfs_read_block_groups(root->fs_info->extent_root);
}
while(1) {
fixed = 0;
@@ -3356,6 +3410,7 @@ static struct option long_options[] = {
{ "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 },
{ "init-csum-tree", 0, NULL, 0 },
+ { "init-extent-tree", 0, NULL, 0 },
{ 0, 0, 0, 0}
};
@@ -3445,7 +3500,6 @@ int main(int ac, char **av)
}
goto out;
}
-
ret = check_extents(trans, root, repair);
if (ret)
fprintf(stderr, "Errors found in extent allocation tree\n");
diff --git a/ctree.c b/ctree.c
index a49bce4..2d86b1e 100644
--- a/ctree.c
+++ b/ctree.c
@@ -151,8 +151,10 @@ int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
btrfs_level_size(root, 0),
root->root_key.objectid,
&disk_key, level, 0, 0);
- if (IS_ERR(c))
- return PTR_ERR(c);
+ if (IS_ERR(c)) {
+ c = old;
+ extent_buffer_get(c);
+ }
memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_level(c, level);
@@ -1262,6 +1264,8 @@ again:
key->objectid);
b = read_node_slot(root, b, slot);
+ if (!extent_buffer_uptodate(b))
+ return -EIO;
} else {
p->slots[level] = slot;
if (ins_len > 0 &&
diff --git a/extent-tree.c b/extent-tree.c
index ee87f1f..20cdffa 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1703,7 +1703,6 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
cache = (struct btrfs_block_group_cache *)(unsigned long)ptr;
ret = write_one_cache_group(trans, root, path, cache);
- BUG_ON(ret);
}
btrfs_free_path(path);
return 0;
@@ -1894,6 +1893,10 @@ static int update_pinned_extents(struct btrfs_root *root,
}
while (num > 0) {
cache = btrfs_lookup_block_group(fs_info, bytenr);
+ if (!cache) {
+ len = min((u64)root->sectorsize, num);
+ goto next;
+ }
WARN_ON(!cache);
len = min(num, cache->key.offset -
(bytenr - cache->key.objectid));
@@ -1906,6 +1909,7 @@ static int update_pinned_extents(struct btrfs_root *root,
cache->space_info->bytes_pinned -= len;
fs_info->total_pinned -= len;
}
+next:
bytenr += len;
num -= len;
}
@@ -2263,9 +2267,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
BUG_ON(ret);
}
- ret = update_block_group(trans, root, bytenr, num_bytes, 0,
- mark_free);
- BUG_ON(ret);
+ update_block_group(trans, root, bytenr, num_bytes, 0, mark_free);
}
fail:
btrfs_free_path(path);
@@ -2596,13 +2598,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
ret = update_block_group(trans, root, ins->objectid, ins->offset,
1, 0);
- if (ret) {
- printk(KERN_ERR "btrfs update block group failed for %llu "
- "%llu\n", (unsigned long long)ins->objectid,
- (unsigned long long)ins->offset);
- BUG();
- }
- return ret;
+ return 0;
}
static int alloc_tree_block(struct btrfs_trans_handle *trans,
@@ -3185,7 +3181,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
finish_current_insert(trans, extent_root);
ret = del_pending_extents(trans, extent_root);
- BUG_ON(ret);
set_avail_alloc_bits(extent_root->fs_info, type);
return 0;
}
diff --git a/volumes.c b/volumes.c
index e7f4c3e..088f639 100644
--- a/volumes.c
+++ b/volumes.c
@@ -35,18 +35,6 @@ struct stripe {
u64 physical;
};
-struct map_lookup {
- struct cache_extent ce;
- u64 type;
- int io_align;
- int io_width;
- int stripe_len;
- int sector_size;
- int num_stripes;
- int sub_stripes;
- struct btrfs_bio_stripe stripes[];
-};
-
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
diff --git a/volumes.h b/volumes.h
index c34af74..4755176 100644
--- a/volumes.h
+++ b/volumes.h
@@ -18,6 +18,7 @@
#ifndef __BTRFS_VOLUMES_
#define __BTRFS_VOLUMES_
+
struct btrfs_device {
struct list_head dev_list;
struct btrfs_root *dev_root;
@@ -92,6 +93,18 @@ struct btrfs_multi_bio {
struct btrfs_bio_stripe stripes[];
};
+struct map_lookup {
+ struct cache_extent ce;
+ u64 type;
+ int io_align;
+ int io_width;
+ int stripe_len;
+ int sector_size;
+ int num_stripes;
+ int sub_stripes;
+ struct btrfs_bio_stripe stripes[];
+};
+
#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
--
1.7.6.233.gd79bc

View File

@ -1,38 +0,0 @@
From 863db40c3f7cc3a3f7c035ea5747e84c9e2b8747 Mon Sep 17 00:00:00 2001
From: Miao Xie <miaox@cn.fujitsu.com>
Date: Thu, 23 Feb 2012 15:51:09 +0800
Subject: [PATCH 1/3] Btrfs-progs, btrfs-map-logical: Fix typo in usage
The right option is 'o' not 'c'. And this tool is used for the block devices
on which there is a btrfs file system, so change "mount_point" to "device".
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
btrfs-map-logical.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
index d79a73a..fa4fb3f 100644
--- a/btrfs-map-logical.c
+++ b/btrfs-map-logical.c
@@ -84,7 +84,7 @@ struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr,
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n");
+ fprintf(stderr, "usage: btrfs-map-logical [options] device\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");
@@ -96,7 +96,7 @@ static struct option long_options[] = {
/* { "byte-count", 1, NULL, 'b' }, */
{ "logical", 1, NULL, 'l' },
{ "copy", 1, NULL, 'c' },
- { "output", 1, NULL, 'c' },
+ { "output", 1, NULL, 'o' },
{ "bytes", 1, NULL, 'b' },
{ 0, 0, 0, 0}
};
--
1.7.6.233.gd79bc

View File

@ -1,48 +0,0 @@
From 2b0d4908db8a2b6120be1617b50187b32b79e56e Mon Sep 17 00:00:00 2001
From: Miao Xie <miaox@cn.fujitsu.com>
Date: Thu, 23 Feb 2012 15:52:05 +0800
Subject: [PATCH 2/3] Btrfs-progs, btrfs-corrupt-block: fix the wrong usage
The old usage is a copy of btrfs-map-logical, it's wrong, fix it.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
btrfs-corrupt-block.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 7051e99..124fb38 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -85,11 +85,14 @@ struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
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");
+ fprintf(stderr, "usage: btrfs-corrupt-block [options] device\n");
+ fprintf(stderr, "\t-l Logical extent to be corrupted\n");
+ fprintf(stderr, "\t-c Copy of the extent to be corrupted"
+ " (usually 1 or 2, default: 0)\n");
+ fprintf(stderr, "\t-b Number of bytes to be corrupted\n");
+ fprintf(stderr, "\t-e Extent to be corrupted\n");
+ fprintf(stderr, "\t-E The whole extent free to be corrupted\n");
+ fprintf(stderr, "\t-k Corrupt keys\n");
exit(1);
}
@@ -296,7 +299,7 @@ int main(int ac, char **av)
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:eEk", long_options,
+ c = getopt_long(ac, av, "l:c:b:eEk", long_options,
&option_index);
if (c < 0)
break;
--
1.7.6.233.gd79bc

View File

@ -1,116 +0,0 @@
From c1d427d2a7b8557265a641a6d199f1b9436d27af Mon Sep 17 00:00:00 2001
From: Miao Xie <miaox@cn.fujitsu.com>
Date: Thu, 23 Feb 2012 15:52:58 +0800
Subject: [PATCH 3/3] Btrfs-progs: fix btrfsck's snapshot wrong "unresolved
refs"
If the fs/file tree is not the parent of the snapshot, it is reasonable
that we can not find the relative reference and back reference. But btrfsck
doesn't consider this case, and reports "unresolved refs" message, it's wrong,
fix it.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
btrfsck.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index c1a28bc..2f1a515 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -747,7 +747,65 @@ static int leave_shared_node(struct btrfs_root *root,
return 0;
}
-static int process_dir_item(struct extent_buffer *eb,
+static int is_child_root(struct btrfs_root *root, u64 parent_root_id,
+ u64 child_root_id)
+{
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ int has_parent = 0;
+ int ret;
+
+ btrfs_init_path(&path);
+
+ key.objectid = parent_root_id;
+ key.type = BTRFS_ROOT_REF_KEY;
+ key.offset = child_root_id;
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, &path,
+ 0, 0);
+ BUG_ON(ret < 0);
+ btrfs_release_path(root, &path);
+ if (!ret)
+ return 1;
+
+ key.objectid = child_root_id;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = 0;
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, &path,
+ 0, 0);
+ BUG_ON(ret <= 0);
+
+ while (1) {
+ leaf = path.nodes[0];
+ if (path.slots[0] >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root->fs_info->tree_root, &path);
+ BUG_ON(ret < 0);
+
+ if (ret > 0)
+ break;
+ }
+
+ btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
+ if (key.objectid != child_root_id ||
+ key.type != BTRFS_ROOT_BACKREF_KEY)
+ break;
+
+ has_parent = 1;
+
+ if (key.offset == parent_root_id) {
+ btrfs_release_path(root, &path);
+ return 1;
+ }
+
+ path.slots[0]++;
+ }
+
+ btrfs_release_path(root, &path);
+ return has_parent? 0 : -1;
+}
+
+static int process_dir_item(struct btrfs_root *root,
+ struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
{
@@ -795,9 +853,13 @@ static int process_dir_item(struct extent_buffer *eb,
key->objectid, key->offset, namebuf,
len, filetype, key->type, error);
} else if (location.type == BTRFS_ROOT_ITEM_KEY) {
- add_inode_backref(root_cache, location.objectid,
- key->objectid, key->offset, namebuf,
- len, filetype, key->type, error);
+ u64 parent = root->objectid;
+
+ if (is_child_root(root, parent, location.objectid))
+ add_inode_backref(root_cache, location.objectid,
+ key->objectid, key->offset,
+ namebuf, len, filetype,
+ key->type, error);
} else {
fprintf(stderr, "warning line %d\n", __LINE__);
}
@@ -1028,7 +1090,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
switch (key.type) {
case BTRFS_DIR_ITEM_KEY:
case BTRFS_DIR_INDEX_KEY:
- ret = process_dir_item(eb, i, &key, active_node);
+ ret = process_dir_item(root, eb, i, &key, active_node);
break;
case BTRFS_INODE_REF_KEY:
ret = process_inode_ref(eb, i, &key, active_node);
--
1.7.6.233.gd79bc

View File

@ -1,28 +0,0 @@
From 08121cd091aa7b555dcb09077296deec8b1c4d72 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Tue, 13 Mar 2012 18:10:09 +0100
Subject: [PATCH 1/8] btrfs-progs: adjust size of filesystem if blockdevice is
larger
Signed-off-by: David Sterba <dsterba@suse.cz>
---
utils.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/utils.c b/utils.c
index 0beaf80..f885307 100644
--- a/utils.c
+++ b/utils.c
@@ -273,6 +273,9 @@ int make_btrfs(int fd, const char *device, const char *label,
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems), itemoff);
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems), item_size);
+ if (num_bytes < dev_num_bytes)
+ dev_num_bytes = num_bytes;
+
dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item);
btrfs_set_device_id(buf, dev_item, 1);
btrfs_set_device_generation(buf, dev_item, 0);
--
1.7.6.233.gd79bc

View File

@ -1,31 +0,0 @@
From 04ed6645aa91d023c06c1db361a2a22f4615eea0 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Mon, 12 Mar 2012 19:17:39 +0200
Subject: [PATCH 2/8] Btrfs-progs: nuke redundant zeroing in
__list_subvol_search()
There's no need to zero out things twice.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
btrfs-list.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/btrfs-list.c b/btrfs-list.c
index 5f4a9be..44a73de 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -569,10 +569,6 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
root_lookup_init(root_lookup);
memset(&args, 0, sizeof(args));
- root_lookup_init(root_lookup);
-
- memset(&args, 0, sizeof(args));
-
/* search in the tree of tree roots */
sk->tree_id = 1;
--
1.7.6.233.gd79bc

View File

@ -1,89 +0,0 @@
From 039e2ae2add77881b332667ef5c8e218cd208198 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Mon, 12 Mar 2012 19:17:39 +0200
Subject: [PATCH 3/8] Btrfs-progs: refactor resolve_root() function a bit
Don't pass a pointer to root_id to resolve_root(). It's always the same as
ri->root_id, passing a pointer hints that root_id can somehow change which is
not true.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
btrfs-list.c | 21 ++++++++++-----------
1 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/btrfs-list.c b/btrfs-list.c
index 44a73de..cc1dc66 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -200,7 +200,7 @@ static int add_root(struct root_lookup *root_lookup,
* in by lookup_ino_path
*/
static int resolve_root(struct root_lookup *rl, struct root_info *ri,
- u64 *root_id, u64 *parent_id, u64 *top_id, char **path)
+ u64 *parent_id, u64 *top_id, char **path)
{
char *full_path = NULL;
int len = 0;
@@ -254,7 +254,6 @@ static int resolve_root(struct root_lookup *rl, struct root_info *ri,
}
}
- *root_id = ri->root_id;
*path = full_path;
return 0;
@@ -692,23 +691,23 @@ int list_subvols(int fd, int print_parent)
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, &root_id, &parent_id,
- &level, &path);
+ resolve_root(&root_lookup, entry, &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)entry->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)entry->root_id,
(unsigned long long)level, path);
}
+
free(path);
n = rb_prev(n);
}
@@ -914,17 +913,17 @@ char *path_for_root(int fd, u64 root)
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)
+ resolve_root(&root_lookup, entry, &parent_id, &level, &path);
+ if (entry->root_id == root)
ret_path = path;
else
free(path);
+
n = rb_prev(n);
}
--
1.7.6.233.gd79bc

View File

@ -1,142 +0,0 @@
From ab67e5db559701b71a20e39948c5a531b7469362 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Mon, 12 Mar 2012 19:17:39 +0200
Subject: [PATCH 4/8] Btrfs-progs: bring 'subvol get-default' back in
Commit bab2c565 accidentally broke 'subvol get-default' command by
removing almost all of the underlying code. Bring it back with some
fixes and improvements.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
btrfs-list.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
ctree.h | 2 +
2 files changed, 82 insertions(+), 1 deletions(-)
diff --git a/btrfs-list.c b/btrfs-list.c
index cc1dc66..00c428b 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -552,6 +552,60 @@ build:
return full;
}
+static int get_default_subvolid(int fd, u64 *default_id)
+{
+ struct btrfs_ioctl_search_args args;
+ struct btrfs_ioctl_search_key *sk = &args.key;
+ struct btrfs_ioctl_search_header *sh;
+ u64 found = 0;
+ int ret;
+
+ memset(&args, 0, sizeof(args));
+
+ /*
+ * search for a dir item with a name 'default' in the tree of
+ * tree roots, it should point us to a default root
+ */
+ sk->tree_id = 1;
+
+ /* don't worry about ancient format and request only one item */
+ sk->nr_items = 1;
+
+ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->max_type = BTRFS_DIR_ITEM_KEY;
+ sk->min_type = BTRFS_DIR_ITEM_KEY;
+ sk->max_offset = (u64)-1;
+ sk->max_transid = (u64)-1;
+
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0)
+ return ret;
+
+ /* the ioctl returns the number of items it found in nr_items */
+ if (sk->nr_items == 0)
+ goto out;
+
+ sh = (struct btrfs_ioctl_search_header *)args.buf;
+
+ if (sh->type == BTRFS_DIR_ITEM_KEY) {
+ struct btrfs_dir_item *di;
+ int name_len;
+ char *name;
+
+ di = (struct btrfs_dir_item *)(sh + 1);
+ name_len = btrfs_stack_dir_name_len(di);
+ name = (char *)(di + 1);
+
+ if (!strncmp("default", name, name_len))
+ found = btrfs_disk_key_objectid(&di->location);
+ }
+
+out:
+ *default_id = found;
+ return 0;
+}
+
static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
{
int ret;
@@ -663,12 +717,32 @@ static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
return 0;
}
-int list_subvols(int fd, int print_parent)
+int list_subvols(int fd, int print_parent, int get_default)
{
struct root_lookup root_lookup;
struct rb_node *n;
+ u64 default_id;
int ret;
+ if (get_default) {
+ ret = get_default_subvolid(fd, &default_id);
+ if (ret) {
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(errno));
+ return ret;
+ }
+ if (default_id == 0) {
+ fprintf(stderr, "ERROR: 'default' dir item not found\n");
+ return ret;
+ }
+
+ /* no need to resolve roots if FS_TREE is default */
+ if (default_id == BTRFS_FS_TREE_OBJECTID) {
+ printf("ID 5 (FS_TREE)\n");
+ return ret;
+ }
+ }
+
ret = __list_subvol_search(fd, &root_lookup);
if (ret) {
fprintf(stderr, "ERROR: can't perform the search - %s\n",
@@ -696,6 +770,11 @@ int list_subvols(int fd, int print_parent)
char *path;
entry = rb_entry(n, struct root_info, rb_node);
+ if (get_default && entry->root_id != default_id) {
+ n = rb_prev(n);
+ continue;
+ }
+
resolve_root(&root_lookup, entry, &parent_id, &level, &path);
if (print_parent) {
printf("ID %llu parent %llu top level %llu path %s\n",
diff --git a/ctree.h b/ctree.h
index 5309059..141ec59 100644
--- a/ctree.h
+++ b/ctree.h
@@ -1416,6 +1416,8 @@ BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16);
+
static inline void btrfs_dir_item_key(struct extent_buffer *eb,
struct btrfs_dir_item *item,
struct btrfs_disk_key *key)
--
1.7.6.233.gd79bc

View File

@ -1,185 +0,0 @@
From 55b993c8889135f51ce66b26caf54e3e17b03e34 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Tue, 13 Mar 2012 18:36:56 +0200
Subject: [PATCH 5/8] Btrfs-progs: make print-tree.c aware of free space cache
This adds proper formatting for free space and inode cache items in
btrfs-debug-tree output.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
ctree.h | 29 +++++++++++++++++++++++++++++
print-tree.c | 52 +++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 72 insertions(+), 9 deletions(-)
diff --git a/ctree.h b/ctree.h
index 141ec59..147c3cb 100644
--- a/ctree.h
+++ b/ctree.h
@@ -256,6 +256,13 @@ struct btrfs_chunk {
/* additional stripes go here */
} __attribute__ ((__packed__));
+struct btrfs_free_space_header {
+ struct btrfs_disk_key location;
+ __le64 generation;
+ __le64 num_entries;
+ __le64 num_bitmaps;
+} __attribute__ ((__packed__));
+
static inline unsigned long btrfs_chunk_item_size(int num_stripes)
{
BUG_ON(num_stripes == 0);
@@ -1432,6 +1439,28 @@ static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
write_eb_member(eb, item, struct btrfs_dir_item, location, key);
}
+/* struct btrfs_free_space_header */
+BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header,
+ num_entries, 64);
+BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header,
+ num_bitmaps, 64);
+BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,
+ generation, 64);
+
+static inline void btrfs_free_space_key(struct extent_buffer *eb,
+ struct btrfs_free_space_header *h,
+ struct btrfs_disk_key *key)
+{
+ read_eb_member(eb, h, struct btrfs_free_space_header, location, key);
+}
+
+static inline void btrfs_set_free_space_key(struct extent_buffer *eb,
+ struct btrfs_free_space_header *h,
+ struct btrfs_disk_key *key)
+{
+ write_eb_member(eb, h, struct btrfs_free_space_header, location, key);
+}
+
/* struct btrfs_disk_key */
BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key,
objectid, 64);
diff --git a/print-tree.c b/print-tree.c
index fc134c0..face47a 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -94,6 +94,7 @@ static void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk)
(unsigned long long)btrfs_stripe_offset_nr(eb, chunk, i));
}
}
+
static void print_dev_item(struct extent_buffer *eb,
struct btrfs_dev_item *dev_item)
{
@@ -276,8 +277,29 @@ static void print_root_ref(struct extent_buffer *leaf, int slot, char *tag)
namelen, namebuf);
}
-static void print_key_type(u8 type)
+static void print_free_space_header(struct extent_buffer *leaf, int slot)
{
+ struct btrfs_free_space_header *header;
+ struct btrfs_disk_key location;
+
+ header = btrfs_item_ptr(leaf, slot, struct btrfs_free_space_header);
+ btrfs_free_space_key(leaf, header, &location);
+ printf("\t\tlocation ");
+ btrfs_print_key(&location);
+ printf("\n");
+ printf("\t\tcache generation %llu entries %llu bitmaps %llu\n",
+ (unsigned long long)btrfs_free_space_generation(leaf, header),
+ (unsigned long long)btrfs_free_space_entries(leaf, header),
+ (unsigned long long)btrfs_free_space_bitmaps(leaf, header));
+}
+
+static void print_key_type(u64 objectid, u8 type)
+{
+ if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID) {
+ printf("UNTYPED");
+ return;
+ }
+
switch (type) {
case BTRFS_INODE_ITEM_KEY:
printf("INODE_ITEM");
@@ -362,10 +384,10 @@ static void print_key_type(u8 type)
};
}
-static void print_objectid(unsigned long long objectid, u8 type)
+static void print_objectid(u64 objectid, u8 type)
{
if (type == BTRFS_DEV_EXTENT_KEY) {
- printf("%llu", objectid); /* device id */
+ printf("%llu", (unsigned long long)objectid); /* device id */
return;
}
@@ -415,6 +437,12 @@ static void print_objectid(unsigned long long objectid, u8 type)
case BTRFS_EXTENT_CSUM_OBJECTID:
printf("EXTENT_CSUM");
break;
+ case BTRFS_FREE_SPACE_OBJECTID:
+ printf("FREE_SPACE");
+ break;
+ case BTRFS_FREE_INO_OBJECTID:
+ printf("FREE_INO");
+ break;
case BTRFS_MULTIPLE_OBJECTIDS:
printf("MULTIPLE");
break;
@@ -425,19 +453,19 @@ static void print_objectid(unsigned long long objectid, u8 type)
}
/* fall-thru */
default:
- printf("%llu", objectid);
+ printf("%llu", (unsigned long long)objectid);
}
}
void btrfs_print_key(struct btrfs_disk_key *disk_key)
{
- u8 type;
+ u64 objectid = btrfs_disk_key_objectid(disk_key);
+ u8 type = btrfs_disk_key_type(disk_key);
+
printf("key (");
- type = btrfs_disk_key_type(disk_key);
- print_objectid((unsigned long long)btrfs_disk_key_objectid(disk_key),
- type);
+ print_objectid(objectid, type);
printf(" ");
- print_key_type(type);
+ print_key_type(objectid, type);
printf(" %llu)", (unsigned long long)btrfs_disk_key_offset(disk_key));
}
@@ -460,6 +488,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
struct btrfs_block_group_item bg_item;
struct btrfs_dir_log_item *dlog;
u32 nr = btrfs_header_nritems(l);
+ u64 objectid;
u32 type;
printf("leaf %llu items %d free space %d generation %llu owner %llu\n",
@@ -472,12 +501,17 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
for (i = 0 ; i < nr ; i++) {
item = btrfs_item_nr(l, i);
btrfs_item_key(l, &disk_key, i);
+ objectid = btrfs_disk_key_objectid(&disk_key);
type = btrfs_disk_key_type(&disk_key);
printf("\titem %d ", i);
btrfs_print_key(&disk_key);
printf(" itemoff %d itemsize %d\n",
btrfs_item_offset(l, item),
btrfs_item_size(l, item));
+
+ if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID)
+ print_free_space_header(l, i);
+
switch (type) {
case BTRFS_INODE_ITEM_KEY:
ii = btrfs_item_ptr(l, i, struct btrfs_inode_item);
--
1.7.6.233.gd79bc

View File

@ -1,72 +0,0 @@
From c64c11e0a2918e6319be9337a756979e1f398730 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Tue, 13 Mar 2012 22:15:07 +0200
Subject: [PATCH 6/8] Btrfs-progs: allow dup for data chunks in mixed mode
Before commit a46e7ff2 was merged it was possible to create dup for
data+metadata chunks (mixed mode) by giving -m raid1 -d raid1 -M to
mkfs. a46e7ff2 purposefully disabled behind the scenes profile
upgrading/downgrading, so give users a chance to pick dup explicitly and
bail if dup for data is requested in normal mode.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
mkfs.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/mkfs.c b/mkfs.c
index acdb646..cf571c4 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -258,17 +258,23 @@ static int create_raid_groups(struct btrfs_trans_handle *trans,
if (metadata_profile & ~allowed) {
fprintf(stderr, "unable to create FS with metadata "
- "profile %llu (%llu devices)\n", metadata_profile,
+ "profile %llu (have %llu devices)\n", metadata_profile,
num_devices);
exit(1);
}
if (data_profile & ~allowed) {
fprintf(stderr, "unable to create FS with data "
- "profile %llu (%llu devices)\n", data_profile,
+ "profile %llu (have %llu devices)\n", data_profile,
num_devices);
exit(1);
}
+ /* allow dup'ed data chunks only in mixed mode */
+ if (!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP)) {
+ fprintf(stderr, "dup for data is allowed only in mixed mode\n");
+ exit(1);
+ }
+
if (allowed & metadata_profile) {
u64 meta_flags = BTRFS_BLOCK_GROUP_METADATA;
@@ -329,7 +335,7 @@ static void print_usage(void)
fprintf(stderr, "options:\n");
fprintf(stderr, "\t -A --alloc-start the offset to start the FS\n");
fprintf(stderr, "\t -b --byte-count total number of bytes in the FS\n");
- fprintf(stderr, "\t -d --data data profile, raid0, raid1, raid10 or single\n");
+ fprintf(stderr, "\t -d --data data profile, raid0, raid1, raid10, dup or single\n");
fprintf(stderr, "\t -f --force don't check if a device is already mounted\n");
fprintf(stderr, "\t -l --leafsize size of btree leaves\n");
fprintf(stderr, "\t -L --label set a label\n");
@@ -357,10 +363,12 @@ static u64 parse_profile(char *s)
return BTRFS_BLOCK_GROUP_RAID1;
} else if (strcmp(s, "raid10") == 0) {
return BTRFS_BLOCK_GROUP_RAID10;
+ } else if (strcmp(s, "dup") == 0) {
+ return BTRFS_BLOCK_GROUP_DUP;
} else if (strcmp(s, "single") == 0) {
return 0;
} else {
- fprintf(stderr, "Unknown option %s\n", s);
+ fprintf(stderr, "Unknown profile %s\n", s);
print_usage();
}
/* not reached */
--
1.7.6.233.gd79bc

View File

@ -1,79 +0,0 @@
From b6f17f9e5c87b93cd887088121551839d2f24b35 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 26 Mar 2012 14:50:02 +0200
Subject: [PATCH 7/8] btrfs-progs: mkfs: rename -T to -K
Fixup to "mkfs: allow not to trim a device", to match mkfs.xfs option
name.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
man/mkfs.btrfs.8.in | 4 ++--
mkfs.c | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/man/mkfs.btrfs.8.in b/man/mkfs.btrfs.8.in
index 307d1fb..71f061d 100644
--- a/man/mkfs.btrfs.8.in
+++ b/man/mkfs.btrfs.8.in
@@ -14,7 +14,7 @@ mkfs.btrfs \- create an btrfs filesystem
[ \fB\-n\fP\fI nodesize\fP ]
[ \fB\-s\fP\fI sectorsize\fP ]
[ \fB\-r\fP\fI rootdir\fP ]
-[ \fB\-T\fP ]
+[ \fB\-K\fP ]
[ \fB\-h\fP ]
[ \fB\-V\fP ] \fI device\fP [ \fI device ...\fP ]
.SH DESCRIPTION
@@ -67,7 +67,7 @@ Specify the sectorsize, the minimum block allocation.
\fB\-r\fR, \fB\-\-rootdir \fIrootdir\fR
Specify a directory to copy into the newly created fs.
.TP
-\fB\-T\fR, \fB\-\-nodiscard \fR
+\fB\-K\fR, \fB\-\-nodiscard \fR
Do not perform whole device TRIM operation by default.
.TP
\fB\-V\fR, \fB\-\-version\fR
diff --git a/mkfs.c b/mkfs.c
index cf571c4..d17f71c 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -344,7 +344,7 @@ static void print_usage(void)
fprintf(stderr, "\t -n --nodesize size of btree nodes\n");
fprintf(stderr, "\t -s --sectorsize min block allocation\n");
fprintf(stderr, "\t -r --rootdir the source directory\n");
- fprintf(stderr, "\t -T --nodiscard do not perform whole device TRIM\n");
+ fprintf(stderr, "\t -K --nodiscard do not perform whole device TRIM\n");
fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
exit(1);
}
@@ -407,7 +407,7 @@ static struct option long_options[] = {
{ "version", 0, NULL, 'V' },
{ "rootdir", 1, NULL, 'r' },
{ "force", 0, NULL, 'f' },
- { "nodiscard", 0, NULL, 'T' },
+ { "nodiscard", 0, NULL, 'K' },
{ 0, 0, 0, 0}
};
@@ -1236,7 +1236,7 @@ int main(int ac, char **av)
while(1) {
int c;
- c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VMfT", long_options,
+ c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VMfK", long_options,
&option_index);
if (c < 0)
break;
@@ -1285,7 +1285,7 @@ int main(int ac, char **av)
case 'f':
force=1;
break;
- case 'T':
+ case 'K':
nodiscard=1;
break;
default:
--
1.7.6.233.gd79bc

View File

@ -1,152 +0,0 @@
From 251cef9c8992b79d9d80515387cb0c26ab3b154d Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Tue, 31 Jan 2012 15:32:28 +0100
Subject: [PATCH] btrfs-progs: mkfs: allow not to trim a device
Signed-off-by: David Sterba <dsterba@suse.cz>
---
man/mkfs.btrfs.8.in | 4 ++++
mkfs.c | 15 +++++++++++----
utils.c | 18 +++++++++++++-----
utils.h | 2 ++
4 files changed, 30 insertions(+), 9 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/man/mkfs.btrfs.8.in
+++ btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
@@ -13,6 +13,7 @@ mkfs.btrfs \- create an btrfs filesystem
[ \fB \-M\fP\fI mixed data+metadata\fP ]
[ \fB \-n\fP\fI nodesize\fP ]
[ \fB \-s\fP\fI sectorsize\fP ]
+[ \fB \-T\fP ]
[ \fB \-h\fP ]
[ \fB \-V\fP ] \fI device\fP [ \fI device ...\fP ]
.SH DESCRIPTION
@@ -62,6 +63,9 @@ Specify the nodesize. By default the val
\fB\-s\fR, \fB\-\-sectorsize \fIsize\fR
Specify the sectorsize, the minimum block allocation.
.TP
+\fB\-T\fR, \fB\-\-nodiscard \fR
+Do not perform whole device TRIM operation by default.
+.TP
\fB\-V\fR, \fB\-\-version\fR
Print the \fBmkfs.btrfs\fP version and exit.
.SH AVAILABILITY
Index: btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/mkfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
@@ -311,6 +311,7 @@ static void print_usage(void)
fprintf(stderr, "\t -n --nodesize size of btree nodes\n");
fprintf(stderr, "\t -s --sectorsize min block allocation\n");
fprintf(stderr, "\t -r --rootdir the source directory\n");
+ fprintf(stderr, "\t -T --nodiscard do not perform whole device TRIM\n");
fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
exit(1);
}
@@ -370,6 +371,7 @@ static struct option long_options[] = {
{ "version", 0, NULL, 'V' },
{ "rootdir", 1, NULL, 'r' },
{ "force", 0, NULL, 'f' },
+ { "nodiscard", 0, NULL, 'T' },
{ 0, 0, 0, 0}
};
@@ -1186,6 +1188,7 @@ int main(int ac, char **av)
int mixed = 0;
int data_profile_opt = 0;
int metadata_profile_opt = 0;
+ int nodiscard = 0;
char *source_dir = NULL;
int source_dir_set = 0;
@@ -1197,7 +1200,7 @@ int main(int ac, char **av)
while(1) {
int c;
- c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VMf", long_options,
+ c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VMfT", long_options,
&option_index);
if (c < 0)
break;
@@ -1246,6 +1249,9 @@ int main(int ac, char **av)
case 'f':
force=1;
break;
+ case 'T':
+ nodiscard=1;
+ break;
default:
print_usage();
}
@@ -1287,7 +1293,8 @@ int main(int ac, char **av)
exit(1);
}
first_file = file;
- ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, &mixed);
+ ret = __btrfs_prepare_device(fd, file, zero_end,
+ &dev_block_count, &mixed, nodiscard);
if (block_count == 0)
block_count = dev_block_count;
else if (block_count > dev_block_count) {
@@ -1392,8 +1399,8 @@ int main(int ac, char **av)
close(fd);
continue;
}
- ret = btrfs_prepare_device(fd, file, zero_end,
- &dev_block_count, &mixed);
+ ret = __btrfs_prepare_device(fd, file, zero_end,
+ &dev_block_count, &mixed, nodiscard);
mixed = old_mixed;
BUG_ON(ret);
Index: btrfs-progs-v0.19-118-gfdb6c04/utils.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/utils.c
+++ btrfs-progs-v0.19-118-gfdb6c04/utils.c
@@ -539,6 +539,12 @@ int btrfs_add_to_fsid(struct btrfs_trans
int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret,
int *mixed)
{
+ /* discard by default when called from 'device add' */
+ return __btrfs_prepare_device(fd, file, zero_end, block_count_ret, mixed, 0);
+}
+int __btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret,
+ int *mixed, int nodiscard)
+{
u64 block_count;
u64 bytenr;
struct stat st;
@@ -562,11 +568,13 @@ int btrfs_prepare_device(int fd, char *f
*mixed = 1;
}
- /*
- * We intentionally ignore errors from the discard ioctl. It is
- * not necessary for the mkfs functionality but just an optimization.
- */
- discard_blocks(fd, 0, block_count);
+ if (!nodiscard) {
+ /*
+ * We intentionally ignore errors from the discard ioctl. It is
+ * not necessary for the mkfs functionality but just an optimization.
+ */
+ discard_blocks(fd, 0, block_count);
+ }
ret = zero_dev_start(fd);
if (ret) {
Index: btrfs-progs-v0.19-118-gfdb6c04/utils.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/utils.h
+++ btrfs-progs-v0.19-118-gfdb6c04/utils.h
@@ -28,6 +28,8 @@ int btrfs_make_root_dir(struct btrfs_tra
struct btrfs_root *root, u64 objectid);
int btrfs_prepare_device(int fd, char *file, int zero_end,
u64 *block_count_ret, int *mixed);
+int __btrfs_prepare_device(int fd, char *file, int zero_end,
+ u64 *block_count_ret, int *mixed, int nodiscard);
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,

View File

@ -1,107 +0,0 @@
From 9e2b399e046af8a0ec96662b7b849fb7327384cc Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Tue, 31 Jan 2012 14:40:22 +0100
Subject: [PATCH] btrfs-progs: convert: set label or copy from origin
Signed-off-by: David Sterba <dsterba@suse.cz>
---
convert.c | 46 ++++++++++++++++++++++++++++++++++++++--------
1 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/convert.c b/convert.c
index 13f3ece..3e74108 100644
--- a/convert.c
+++ b/convert.c
@@ -2332,7 +2332,8 @@ err:
return ret;
}
-int do_convert(const char *devname, int datacsum, int packing, int noxattr)
+int do_convert(const char *devname, int datacsum, int packing, int noxattr,
+ int copylabel, const char *fslabel)
{
int i, fd, ret;
u32 blocksize;
@@ -2424,6 +2425,17 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "error during create_ext2_image %d\n", ret);
goto fail;
}
+ memset(root->fs_info->super_copy.label, 0, BTRFS_LABEL_SIZE);
+ if (copylabel == 1) {
+ strncpy(root->fs_info->super_copy.label,
+ ext2_fs->super->s_volume_name, 16);
+ fprintf(stderr, "copy label '%s'\n",
+ root->fs_info->super_copy.label);
+ } else if (copylabel == -1) {
+ strncpy(root->fs_info->super_copy.label, fslabel, BTRFS_LABEL_SIZE);
+ fprintf(stderr, "set label to '%s'\n", fslabel);
+ }
+
printf("cleaning up system chunk.\n");
ret = cleanup_sys_chunk(root, ext2_root);
if (ret) {
@@ -2812,11 +2824,13 @@ fail:
static void print_usage(void)
{
- printf("usage: btrfs-convert [-d] [-i] [-n] [-r] device\n");
- printf("\t-d disable data checksum\n");
- printf("\t-i ignore xattrs and ACLs\n");
- printf("\t-n disable packing of small files\n");
- printf("\t-r roll back to ext2fs\n");
+ printf("usage: btrfs-convert [-d] [-i] [-n] [-r] [-l label] [-L] device\n");
+ printf("\t-d disable data checksum\n");
+ printf("\t-i ignore xattrs and ACLs\n");
+ printf("\t-n disable packing of small files\n");
+ printf("\t-r roll back to ext2fs\n");
+ printf("\t-l LABEL set filesystem label\n");
+ printf("\t-L use label from converted fs\n");
}
int main(int argc, char *argv[])
@@ -2826,9 +2840,12 @@ int main(int argc, char *argv[])
int noxattr = 0;
int datacsum = 1;
int rollback = 0;
+ int copylabel = 0;
char *file;
+ char *fslabel = NULL;
+
while(1) {
- int c = getopt(argc, argv, "dinr");
+ int c = getopt(argc, argv, "dinrl:L");
if (c < 0)
break;
switch(c) {
@@ -2844,6 +2861,19 @@ int main(int argc, char *argv[])
case 'r':
rollback = 1;
break;
+ case 'l':
+ copylabel = -1;
+ fslabel = strdup(optarg);
+ if (strlen(fslabel) > BTRFS_LABEL_SIZE) {
+ fprintf(stderr,
+ "warning: label too long, trimmed to %d bytes\n",
+ BTRFS_LABEL_SIZE);
+ fslabel[BTRFS_LABEL_SIZE]=0;
+ }
+ break;
+ case 'L':
+ copylabel = 1;
+ break;
default:
print_usage();
return 1;
@@ -2864,7 +2894,7 @@ int main(int argc, char *argv[])
if (rollback) {
ret = do_rollback(file, 0);
} else {
- ret = do_convert(file, datacsum, packing, noxattr);
+ ret = do_convert(file, datacsum, packing, noxattr, copylabel, fslabel);
}
if (ret)
return 1;
--
1.7.9

View File

@ -1,42 +0,0 @@
From 273488299effe9a9182fffc1a7cd9639b68a0da4 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Fri, 17 Feb 2012 11:44:03 +0100
Subject: [PATCH] btrfs-progs: mkfs: disallow uneven data/metadata blocksize
for mixed
With support for bigger metadata blocks, we must avoid different
block size for mixed block groups, this causes corruption
(xfstests/083).
Signed-off-by: David Sterba <dsterba@suse.cz>
---
mkfs.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/mkfs.c b/mkfs.c
index e3ced19..e02efcc 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -1313,6 +1313,19 @@ int main(int ac, char **av)
"profiles must be the same\n");
exit(1);
}
+
+ if (leafsize != nodesize) {
+ fprintf(stderr, "With mixed block groups node and leaf "
+ "block sizes must be the same\n");
+ exit(1);
+ }
+
+ if (sectorsize != nodesize) {
+ fprintf(stderr, "With mixed block groups data and metadata "
+ "block sizes must be the same\n");
+ exit(1);
+ }
+
}
blocks[0] = BTRFS_SUPER_INFO_OFFSET;
--
1.7.6.233.gd79bc

View File

@ -1,36 +0,0 @@
From 68b5d415ff9515863c2080aebfe8d069b00a47fc Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Mon, 26 Mar 2012 17:41:33 +0200
Subject: [PATCH 01/10] btrfs-progs: get-default man page
Added the man page info for the "btrfs subvolume get-default" command
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
btrfs_cmds.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 558d40e..26a0700 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1761,6 +1761,16 @@ int do_change_label(int nargs, char **argv)
}
+/**** man: btrfs subvolume get-default
+ *
+ * \Bbtrfs\b \Bsubvolume get-default\b\I <path>\i
+ *
+ * Query which subvolume of the filesystem <path> will be mounted
+ * as default.
+ *
+ * Get the \Idefault\i subvolume of the filesystem \I<path>\i.
+ ****/
+
int do_get_default_subvol(int nargs, char **argv)
{
int fd;
--
1.7.6.233.gd79bc

View File

@ -1,51 +0,0 @@
From e38f0663be83e68f682919ca4e2d60cf6683b643 Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli <kreijack@inwind.it>
Date: Mon, 26 Mar 2012 17:43:26 +0200
Subject: [PATCH 02/10] btrfs-progs: Correct xstrip() function
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
helpextract.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/helpextract.c b/helpextract.c
index 9489ea0..a729074 100644
--- a/helpextract.c
+++ b/helpextract.c
@@ -38,20 +38,21 @@ static char *xstrip(char *s){
char *last=NULL;
char *first;
+ char prev;
while(*s && isspace(*s) ) s++;
first=s;
-
+ prev=*s;
while(*s){
- if(isspace(*s)) last=s;
+ if(!isspace(prev) && isspace(*s)) last=s;
+ prev=*s;
s++;
}
if(last) *last=0;
return first;
-
}
static void addtuple(char *key, char *cmdline, char *short_help,
@@ -184,7 +185,7 @@ static int search_in_file(char *nf){
return 0;
}
-/* remove all the escape sequence excepet \\ */
+/* remove all the escape sequence except \\ */
static char * my_escape(char *src, char *filters[] ){
static char buffer[LINEBUF*5];
--
1.7.6.233.gd79bc

View File

@ -1,53 +0,0 @@
From a8d78caea3bd1983181806f5110288f23c776005 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 26 Mar 2012 18:00:58 +0200
Subject: [PATCH 03/10] btrfs-progs: document devid parameter for resize
Based on patch from Goffredo Baroncelli.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 26a0700..0a741f0 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -804,10 +804,9 @@ int do_scan(int argc, char **argv)
/**** man: btrfs filesystem resize
*
- * \Bbtrfs\b \Bfilesystem resize\b\I [+/\-]<size>[gkm]|max <path>\i
+ * \Bbtrfs\b \Bfilesystem resize\b\I [<devid>:][+/\-]<size>[gkm]|max <path>\i
*
- * Resize the file system. If 'max' is passed, the filesystem
- * will occupe all available space on the device.
+ * Resize the file system.
*
* Resize a filesystem identified by \I<path>\i.
* The \I<size>\i parameter specifies the new size of the filesystem.
@@ -818,13 +817,17 @@ int do_scan(int argc, char **argv)
* the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
* respectively.
*
- * If 'max' is passed, the filesystem will occupy all available space on the
+ * If 'max' is specified, the filesystem will occupy all available space on the
* volume(s).
*
- * The \Bresize\b command \Bdoes not\b manipulate the size of underlying
- * partition. If you wish to enlarge/reduce a filesystem, you must make sure
+ * The \Bresize\b command \Bdoes not\b manipulate the size of the underlying
+ * partition. If you wish to enlarge/reduce a filesystem, you have to make sure
* you can expand the partition before enlarging the filesystem and shrink the
* partition after reducing the size of the filesystem.
+ *
+ * When the filesystem consists of multiple devices, it is possible to specify
+ * which one should be resized via the <devid> parameter. To know the <devid>
+ * of a device use the command \fBbtrfs filesystem show\fR.
****/
int do_resize(int argc, char **argv)
--
1.7.6.233.gd79bc

View File

@ -1,41 +0,0 @@
From ffa4e18f557d39e5d4b2357a40e073607e0c98a0 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 26 Mar 2012 18:14:20 +0200
Subject: [PATCH 04/10] btrfs-progs: document csize in manpage
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 0a741f0..17c3f8e 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -2090,6 +2090,23 @@ out:
return ret;
}
+/**** man: btrfs filesystem csize
+ *
+ * \Bbtrfs\b \Bfilesystem csize [-s \Istart\i\B] [-e \Iend\i\B] <file>
+ *
+ * Read regular and compressed size of extents in the range \I[start,end)\i.
+ *
+ * Read regular and compressed size of extents in the range \I[start,end)\i.
+ *
+ * \B-s\b\I start\i
+ * range start inclusive, accepts K/M/G modifiers
+ * \B-e\b\I end\i
+ * range end exclusive, accepts K/M/G modifiers
+ *
+ * No range specified will read the whole file, no end of range reads up to
+ * the end of file.
+ ****/
+
int do_compr_size(int argc, char **argv)
{
int ret;
--
1.7.6.233.gd79bc

View File

@ -1,126 +0,0 @@
From ba5f32986c342795eb910e8d77b5a5756af049ce Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 26 Mar 2012 19:25:41 +0200
Subject: [PATCH 05/10] btrfs-progs: document balance in manpage
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 17c3f8e..a7231d0 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1350,9 +1350,38 @@ static struct option balance_longopts[] = {
{ 0, 0, 0, 0}
};
-/*
- * [-d [filters]] [-m [filters]] [-s [filters]] [-vf]
- */
+/**** man: btrfs filesystem balance start
+ *
+ * \Bbtrfs\b \Bfilesystem balance start\b \B[-d [filters]] [-m [filters]] [-s [filters]] [-vf]\b \I<path>\i
+ *
+ * Balance chunks accross the devices on filesystem under \Ipath\i. Control
+ * operation by subcommands.
+ *
+ * \B-d\b apply filters on data block groups
+ *
+ * \B-m\b apply filters on metadata block groups
+ *
+ * \B-s\b apply filters on system block groups
+ *
+ * \B-f\b force operation on system block groups
+ *
+ * \B-v\b verbose, dupms filters at the end of operation
+ *
+ * \Ifilters\i may be a comma separated list of the following items, see section \BBALANCE FILTERS\b for more.
+ *
+ * \Bprofile\b=raid0|raid1|raid10|single|dup specify profiles, multiple allowed, note to escape the '|' from shell
+ *
+ * \Busage\b=<nnn> process only block groups with usage above \Innn\i percent
+ *
+ * \Bdevid\b=<devid> process only block groups on device \Idevid\i
+ *
+ * \Bconvert\b=raid0|raid1|radi10|single|dup convert raid profile to the specified one (only one profile allowed)
+ *
+ * \Bvrange\b=[start]..[end] virtual block address space subset filter
+ *
+ * \Bdrange\b=[start]..[end] devid subset filter, it's tied to devid filter: we say balance out range [start..end) on a particular devid.
+ ****/
+
int do_balance(int argc, char **argv)
{
int fd;
@@ -1496,6 +1525,16 @@ int do_balance(int argc, char **argv)
return 0;
}
+/**** man: btrfs filesystem balance pause
+ *
+ * \Bbtrfs\b \Bfilesystem balance pause\b \I<path>\i
+ *
+ * Pause balance operation at the first possible occasion.
+ *
+ * Pause balance operation at the first possible occasion. This may block for a
+ * few minutes if the balance is in the middle of processing.
+ ****/
+
int do_balance_pause(int argc, char **argv)
{
int fd;
@@ -1522,6 +1561,16 @@ int do_balance_pause(int argc, char **argv)
return 0;
}
+/**** man: btrfs filesystem balance cancel
+ *
+ * \Bbtrfs\b \Bfilesystem balance cancel\b \I<path>\i
+ *
+ * Cancel balance operation at the first possible occasion.
+ *
+ * Cancel balance operation at the first possible occasion. This may block for
+ * a few minutes if the balance is in the middle of processing.
+ ****/
+
int do_balance_cancel(int argc, char **argv)
{
int fd;
@@ -1548,6 +1597,15 @@ int do_balance_cancel(int argc, char **argv)
return 0;
}
+/**** man: btrfs filesystem balance resume
+ *
+ * \Bbtrfs\b \Bfilesystem balance resume\b \I<path>\i
+ *
+ * Resume balance operation.
+ *
+ * Resume balance operation and continue from the last position.
+ ****/
+
int do_balance_resume(int argc, char **argv)
{
int fd;
@@ -1601,6 +1659,16 @@ static struct option balance_progress_longopts[] = {
{ 0, 0, 0, 0}
};
+/**** man: btrfs filesystem balance status
+ *
+ * \Bbtrfs\b \Bfilesystem balance status\b [-v] \I<path>\i
+ *
+ * Show status of running or paused balance operation.
+ *
+ * Show status of running or paused balance operation.
+ *
+ * \B-v\b verbose
+ ****/
int do_balance_progress(int argc, char **argv)
{
int fd;
--
1.7.6.233.gd79bc

View File

@ -1,26 +0,0 @@
From 05b288e9a3ced5f077156726622904081f41388f Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 26 Mar 2012 23:35:14 +0200
Subject: [PATCH 06/10] btrfs-progs: manpage:fix markup in device scan
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index a7231d0..c2fd09e 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -827,7 +827,7 @@ int do_scan(int argc, char **argv)
*
* When the filesystem consists of multiple devices, it is possible to specify
* which one should be resized via the <devid> parameter. To know the <devid>
- * of a device use the command \fBbtrfs filesystem show\fR.
+ * of a device use the command \Bbtrfs filesystem show\b.
****/
int do_resize(int argc, char **argv)
--
1.7.6.233.gd79bc

View File

@ -1,55 +0,0 @@
From 13a29ecb84a41af67c1d96c2c5f2848738a2f570 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Tue, 27 Mar 2012 00:02:35 +0200
Subject: [PATCH 07/10] btrfs-progs: document fi df
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index c2fd09e..f7310ee 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1871,6 +1871,37 @@ int do_get_default_subvol(int nargs, char **argv)
return 0;
}
+/**** man: btrfs filesystem df
+ *
+ * \Bbtrfs\b \Bfilesystem df\b\I <path>\i
+ *
+ * Print allocated and used data for all block group types.
+ *
+ * Print allocated and used data for all block group types.
+ *
+ * Example of filesystem created with default mkfs options:
+ *
+ * Data, RAID0: total=4.00GiB, used=0.00
+ * Data: total=8.00MiB, used=0.00
+ * System, RAID1: total=8.00MiB, used=4.00KiB
+ * System: total=4.00MiB, used=0.00
+ * Metadata, RAID1: total=1.00GiB, used=24.00KiB
+ * Metadata: total=8.00MiB, used=0.00
+ *
+ * Example of filesystem created with \Isingle\i profiles for data and metadata:
+ *
+ * Data: total=38.99GiB, used=58.89MiB
+ * System: total=4.00MiB, used=12.00KiB
+ * Metadata: total=1.01GiB, used=2.86MiB
+ *
+ * \Itotal\i allocated space
+ * \t
+ * \Iused\i actually used data
+ *
+ * This information gives better idea of allocated space than the 'df' utility,
+ * though it does not actually answer the question of how much free space there is.
+ ****/
+
int do_df_filesystem(int nargs, char **argv)
{
struct btrfs_ioctl_space_args *sargs;
--
1.7.6.233.gd79bc

View File

@ -1,54 +0,0 @@
From 9219cfd9e5cb86a2123b3159056ad53b6efd578e Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Tue, 27 Mar 2012 00:15:39 +0200
Subject: [PATCH 08/10] btrfs-progs: document inspect-internal commands
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 23 +++++++++++++++++++++++
1 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index f7310ee..cb6df70 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -2047,6 +2047,17 @@ out:
return ret;
}
+/**** man: btrfs inspect-internal inode-resolve
+ *
+ * \Bbtrfs\b \Binspect-internal inode-resolve\b \B[-v]\b\I <inode> <path>\i
+ *
+ * Resolve given inode number to path name.
+ *
+ * Resolve given inode number to path name. This operation does not need to
+ * traverse the whole filesystem, but effectively uses internal
+ * structures.
+ ****/
+
int do_ino_to_path(int nargs, char **argv)
{
int fd;
@@ -2081,6 +2092,18 @@ int do_ino_to_path(int nargs, char **argv)
argv[optind+1]);
}
+/**** man: btrfs inspect-internal logical-resolve
+ *
+ * \Bbtrfs\b \Binspect-internal logical-resolve\b \B[-v] [-P]\b\I <logical> <path>\i
+ *
+ * Resolve given logical block number to path name or inode number.
+ *
+ * Resolve given logical block number to path name or inode number. Can be used
+ * in connection with scrub reports.
+ *
+ * \I-P\i print paths instead of inode numbers
+ ****/
+
int do_logical_to_ino(int nargs, char **argv)
{
int ret;
--
1.7.6.233.gd79bc

View File

@ -1,28 +0,0 @@
From e2a577cb8f553a1cc74f949b0a798aa5f07d6302 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Tue, 27 Mar 2012 00:51:11 +0200
Subject: [PATCH 10/10] btrfs-progs: tweak order of devices in fi show
Devids are printed in descending order, change it to ascending.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs_cmds.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index cb6df70..82fb61f 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -901,7 +901,7 @@ static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
free(super_bytes_used);
- list_for_each(cur, &fs_devices->devices) {
+ list_for_each_prev(cur, &fs_devices->devices) {
char *total_bytes;
char *bytes_used;
device = list_entry(cur, struct btrfs_device, dev_list);
--
1.7.6.233.gd79bc

20
80-btrfs.rules Normal file
View File

@ -0,0 +1,20 @@
SUBSYSTEM!="block", GOTO="btrfs_end"
ACTION!="add|change", GOTO="btrfs_end"
ENV{ID_FS_TYPE}=="LVM2_member|LVM1_member", GOTO="btrfs_end"
ENV{ID_FS_TYPE}=="linux_raid_member", GOTO="btrfs_end"
ENV{ID_FS_TYPE}=="btrfs", GOTO="btrfs_do_scan"
ENV{DM_UUID}=="LVM-?*", GOTO="btrfs_do_scan"
ENV{DM_UUID}=="LUKS-CRYPT1-?*", GOTO="btrfs_do_scan"
ENV{DM_UUID}=="LUKS-PLAIN-?*", GOTO="btrfs_do_scan"
ENV{DM_UUID}=="LUKS-VERITY-?*", GOTO="btrfs_do_scan"
ENV{DM_UUID}=="LUKS-LOOPAES-?*", GOTO="btrfs_do_scan"
ENV{MD_UUID}=="?*", GOTO="btrfs_do_scan"
GOTO="btrfs_end"
LABEL="btrfs_do_scan"
RUN+="/sbin/modprobe btrfs"
RUN+="/usr/sbin/btrfs device scan $env{DEVNAME}"
LABEL="btrfs_end"

View File

@ -1,28 +0,0 @@
commit a2fe2e1b978f724f53d025461e65adb4e030d043
Author: Dirk Mueller <dmueller@suse.de>
Date: Thu Dec 16 20:40:34 2010 +0100
[PATCH] Plug Memory leak in find_and_setup_log_root()
The error path forgets to free a previously allocated
memory structure.
Index: btrfs-progs-v0.19-116-g13eced9/disk-io.c
===================================================================
--- btrfs-progs-v0.19-116-g13eced9.orig/disk-io.c
+++ btrfs-progs-v0.19-116-g13eced9/disk-io.c
@@ -454,11 +454,13 @@ static int find_and_setup_log_root(struc
{
u32 blocksize;
u64 blocknr = btrfs_super_log_root(disk_super);
- struct btrfs_root *log_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_root *log_root;
if (blocknr == 0)
return 0;
+ log_root = malloc(sizeof(struct btrfs_root));
+
blocksize = btrfs_level_size(tree_root,
btrfs_super_log_root_level(disk_super));

View File

@ -1,11 +1,22 @@
#!/bin/bash -e #!/bin/bash -e
#%stage: filesystem #%stage: filesystem
#%if: -x /usr/sbin/btrfs #%depends: dm dmraid lvm2 udev md luks
#%programs: /sbin/btrfs /sbin/btrfs-zero-log /sbin/btrfs-convert /sbin/btrfs-select-super /sbin/btrfs-image /sbin/btrfstune /sbin/btrfs-restore /sbin/btrfs-find-root /sbin/btrfsck /sbin/mkfs.btrfs /sbin/btrfs-dump-super /sbin/btrfs-debug-tree #%programs: btrfs
#%programs: btrfs-convert
#%programs: btrfs-debug-tree
#%programs: btrfs-dump-super
#%programs: btrfs-find-root
#%programs: btrfs-image
#%programs: btrfs-select-super
#%programs: btrfs-zero-log
#%programs: btrfsck
#%programs: btrfstune
# for fsck(8): listed twice so that a copy really ends up in /sbin
#%programs: /sbin/fsck.btrfs
#%programs: fsck.btrfs
#%programs: mkfs.btrfs
#%modules: btrfs #%modules: btrfs
modprobe btrfs modprobe btrfs
if [ -x /usr/sbin/btrfs ]; then btrfs dev scan >& /dev/null
/usr/sbin/btrfs dev scan >& /dev/null
fi

View File

@ -1,43 +1,19 @@
From 2c19dc5e7bd5fe9a2838ec852128f64a5be54c4c Mon Sep 17 00:00:00 2001 From 3c7ae0fc5139c195100eb931bc6e1148ac1f11f5 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz> From: David Sterba <dsterba@suse.cz>
Date: Mon, 26 Mar 2012 15:39:08 +0200 Date: Mon, 26 Mar 2012 15:39:08 +0200
Subject: [PATCH 09/10] btrfs-progs: add man page for btrfs-convert Subject: [PATCH 37/46] btrfs-progs: add man page for btrfs-convert
Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: David Sterba <dsterba@suse.cz>
--- ---
man/Makefile | 5 +++- man/Makefile | 2 +-
man/btrfs-convert.8.in | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ man/btrfs-convert.8.in | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletions(-) 2 files changed, 61 insertions(+), 1 deletion(-)
create mode 100644 man/btrfs-convert.8.in create mode 100644 man/btrfs-convert.8.in
diff --git a/man/Makefile b/man/Makefile Index: btrfs-progs-v0.20-rc1-335-gf00dd83/man/btrfs-convert.8.in
index 4a90b75..f28eec7 100644 ===================================================================
--- a/man/Makefile
+++ b/man/Makefile
@@ -7,7 +7,7 @@ mandir = $(prefix)/man
man8dir = $(mandir)/man8
MANPAGES = mkfs.btrfs.8.gz btrfsctl.8.gz btrfsck.8.gz btrfs-image.8.gz \
- btrfs-show.8.gz btrfs.8.gz
+ btrfs-show.8.gz btrfs.8.gz btrfs-convert.8.gz
all: $(MANPAGES)
@@ -29,6 +29,9 @@ btrfs-image.8.gz: btrfs-image.8.in
btrfs-show.8.gz: btrfs-show.8.in
$(GZIP) -n -c btrfs-show.8.in > btrfs-show.8.gz
+btrfs-convert.8.gz: btrfs-convert.8.in
+ $(GZIP) -n -c btrfs-convert.8.in > btrfs-convert.8.gz
+
clean :
rm -f $(MANPAGES)
diff --git a/man/btrfs-convert.8.in b/man/btrfs-convert.8.in
new file mode 100644
index 0000000..4057419
--- /dev/null --- /dev/null
+++ b/man/btrfs-convert.8.in +++ btrfs-progs-v0.20-rc1-335-gf00dd83/man/btrfs-convert.8.in
@@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
+.TH BTRFS-CONVERT 8 +.TH BTRFS-CONVERT 8
+.SH NAME +.SH NAME
@ -99,6 +75,16 @@ index 0000000..4057419
+is part of btrfs-progs. +is part of btrfs-progs.
+.SH SEE ALSO +.SH SEE ALSO
+.BR mkfs.btrfs (8) +.BR mkfs.btrfs (8)
-- Index: btrfs-progs-v0.20-rc1-335-gf00dd83/man/Makefile
1.7.6.233.gd79bc ===================================================================
--- btrfs-progs-v0.20-rc1-335-gf00dd83.orig/man/Makefile
+++ btrfs-progs-v0.20-rc1-335-gf00dd83/man/Makefile
@@ -11,7 +11,7 @@ man8dir = $(mandir)/man8
# list only those we use
.SUFFIXES: .in .gz
-MANPAGES = mkfs.btrfs.8.gz btrfsck.8.gz btrfs-image.8.gz btrfs.8.gz
+MANPAGES = mkfs.btrfs.8.gz btrfsck.8.gz btrfs-image.8.gz btrfs.8.gz btrfs-convert.8.gz
INFILES = ${MANPAGES:.in=.gz}
all: $(MANPAGES)

View File

@ -1,248 +0,0 @@
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs-image.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs-image.c
@@ -491,6 +491,11 @@ static int create_metadump(const char *i
int ret;
root = open_ctree(input, 0, 0);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
+
BUG_ON(root->nodesize != root->leafsize);
ret = metadump_init(&metadump, root, out, num_threads,
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs-select-super.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs-select-super.c
@@ -100,8 +100,10 @@ int main(int ac, char **av)
}
root = open_ctree_fd(fp, av[optind], bytenr, 1, use_earliest_bdev);
- if (root == NULL)
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
return 1;
+ }
fprintf(stderr, "Found superblock with generation %llu.\n", root->fs_info->super_copy.generation);
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfslabel.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfslabel.c
@@ -46,7 +46,7 @@
#define GET_LABEL 3
#define SET_LABEL 4
-static void change_label_unmounted(char *dev, char *nLabel)
+static int change_label_unmounted(char *dev, char *nLabel)
{
struct btrfs_root *root;
struct btrfs_trans_handle *trans;
@@ -55,6 +55,10 @@ static void change_label_unmounted(char
* and as read-write.
*/
root = open_ctree(dev, 0, 1);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ return -1;
+ }
trans = btrfs_start_transaction(root, 1);
strncpy(root->fs_info->super_copy.label, nLabel, BTRFS_LABEL_SIZE);
@@ -62,9 +66,10 @@ static void change_label_unmounted(char
/* Now we close it since we are done. */
close_ctree(root);
+ return 0;
}
-static void get_label_unmounted(char *dev)
+static int get_label_unmounted(char *dev)
{
struct btrfs_root *root;
@@ -72,11 +77,16 @@ static void get_label_unmounted(char *de
* and as read-only.
*/
root = open_ctree(dev, 0, 0);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ return -1;
+ }
fprintf(stdout, "%s\n", root->fs_info->super_copy.label);
/* Now we close it since we are done. */
close_ctree(root);
+ return 0;
}
int get_label(char *btrfs_dev)
@@ -95,8 +105,7 @@ int get_label(char *btrfs_dev)
fprintf(stderr, "FATAL: the filesystem has to be unmounted\n");
return -2;
}
- get_label_unmounted(btrfs_dev);
- return 0;
+ return get_label_unmounted(btrfs_dev);
}
@@ -116,6 +125,5 @@ int set_label(char *btrfs_dev, char *nLa
fprintf(stderr, "FATAL: the filesystem has to be unmounted\n");
return -2;
}
- change_label_unmounted(btrfs_dev, nLabel);
- return 0;
+ return change_label_unmounted(btrfs_dev, nLabel);
}
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfstune.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfstune.c
@@ -108,6 +108,11 @@ int main(int argc, char *argv[])
root = open_ctree(device, 0, 1);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ return 1;
+ }
+
if (seeding_flag) {
ret = update_seeding_flag(root, seeding_value);
if (!ret)
--- btrfs-progs-v0.19-118-gfdb6c04.orig/dir-test.c
+++ btrfs-progs-v0.19-118-gfdb6c04/dir-test.c
@@ -436,6 +436,12 @@ int main(int ac, char **av)
radix_tree_init();
root = open_ctree(av[ac-1], &super, 0);
+
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ return 1;
+ }
+
trans = btrfs_start_transaction(root, 1);
dir_oid = btrfs_super_root_dir(&super);
@@ -479,6 +485,11 @@ int main(int ac, char **av)
btrfs_header_nritems(&root->node->node.header));
close_ctree(root, &super);
root = open_ctree("dbfile", &super, 0);
+
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ return 1;
+ }
}
while(count--) {
ret = ops[op](trans, root, &radix);
--- btrfs-progs-v0.19-118-gfdb6c04.orig/find-root.c
+++ btrfs-progs-v0.19-118-gfdb6c04/find-root.c
@@ -351,8 +351,11 @@ int main(int argc, char **argv)
root = open_ctree_broken(dev_fd, argv[optind]);
close(dev_fd);
- if (!root)
+
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
exit(1);
+ }
csum_size = btrfs_super_csum_size(&root->fs_info->super_copy);
ret = find_root(root);
--- btrfs-progs-v0.19-118-gfdb6c04.orig/mkfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
@@ -1362,8 +1362,9 @@ int main(int ac, char **av)
root = open_ctree(file, 0, O_RDWR);
if (!root) {
- fprintf(stderr, "ctree init failed\n");
- return -1;
+ fprintf(stderr, "Open ctree failed\n");
+ close (fd);
+ exit(1);
}
root->fs_info->alloc_start = alloc_start;
--- btrfs-progs-v0.19-118-gfdb6c04.orig/quick-test.c
+++ btrfs-progs-v0.19-118-gfdb6c04/quick-test.c
@@ -52,6 +52,10 @@ int main(int ac, char **av) {
radix_tree_init();
root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, O_RDWR);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
trans = btrfs_start_transaction(root, 1);
srand(55);
btrfs_set_key_type(&ins, BTRFS_STRING_ITEM_KEY);
@@ -75,6 +79,10 @@ int main(int ac, char **av) {
close_ctree(root);
exit(1);
root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, O_RDWR);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
printf("starting search\n");
srand(55);
for (i = 0; i < run_size; i++) {
@@ -94,6 +102,10 @@ int main(int ac, char **av) {
close_ctree(root);
root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, O_RDWR);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
printf("node %p level %d total ptrs %d free spc %lu\n", root->node,
btrfs_header_level(root->node),
btrfs_header_nritems(root->node),
@@ -122,6 +134,10 @@ int main(int ac, char **av) {
close_ctree(root);
root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, O_RDWR);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
trans = btrfs_start_transaction(root, 1);
srand(128);
for (i = 0; i < run_size; i++) {
@@ -138,6 +154,10 @@ int main(int ac, char **av) {
close_ctree(root);
root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, O_RDWR);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
srand(128);
printf("starting search2\n");
for (i = 0; i < run_size; i++) {
--- btrfs-progs-v0.19-118-gfdb6c04.orig/random-test.c
+++ btrfs-progs-v0.19-118-gfdb6c04/random-test.c
@@ -356,6 +356,10 @@ int main(int ac, char **av)
struct btrfs_trans_handle *trans;
radix_tree_init();
root = open_ctree("dbfile", &super);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
fill_radix(root, &radix);
signal(SIGTERM, sigstopper);
@@ -398,6 +402,10 @@ int main(int ac, char **av)
btrfs_header_nritems(&root->node->node.header));
close_ctree(root, &super);
root = open_ctree("dbfile", &super);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ goto out;
+ }
}
while(count--) {
ret = ops[op](trans, root, &radix);

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c7d0bb613659bd63e4894bfb481a85cbadb695f7b9418c97921274ac8344021
size 162236

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:08e8eafbcc4cdd65eabdfc24e1165e1cb835a63a37f0e0f88af1e48c37d54826
size 234916

View File

@ -1,47 +0,0 @@
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs.c
@@ -231,17 +231,17 @@ static struct Command commands[] = {
"the name <name> in the <dest> directory.",
NULL
},
- { do_delete_subvolume, 1,
- "subvolume delete", "<subvolume>\n"
- "Delete the subvolume <subvolume>.",
- NULL
- },
{ do_create_subvol, 1,
"subvolume create", "[<dest>/]<name>\n"
"Create a subvolume in <dest> (or the current directory if\n"
"not passed).",
NULL
},
+ { do_delete_subvolume, 1,
+ "subvolume delete", "<subvolume>\n"
+ "Delete the subvolume <subvolume>.",
+ NULL
+ },
{ do_subvol_list, -1, "subvolume list", "[-p] <path>\n"
"List the snapshot/subvolume of a filesystem.",
"[-p] <path>\n"
@@ -254,6 +254,9 @@ static struct Command commands[] = {
"as default.",
NULL
},
+ { do_get_default_subvol, 1, "subvolume get-default", "<path>\n"
+ "Get the default subvolume of a filesystem."
+ },
{ do_find_newer, 2, "subvolume find-new", "<path> <last_gen>\n"
"List the recently modified files in a filesystem.",
NULL
@@ -270,9 +273,6 @@ static struct Command commands[] = {
"-l len defragment only up to len bytes\n"
"-t size minimal size of file to be considered for defragmenting\n"
},
- { do_get_default_subvol, 1, "subvolume get-default", "<path>\n"
- "Get the default subvolume of a filesystem."
- },
{ do_fssync, 1,
"filesystem sync", "<path>\n"
"Force a sync on the filesystem <path>.",

Some files were not shown because too many files have changed in this diff Show More