From 0e6aead68455a1043aed04e0557dc14af2cd6f60 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 1 Nov 2011 14:26:20 -0400 Subject: [PATCH 01/33] 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 --- restore.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/restore.c b/restore.c index 250c9d3c3..38c4ded6d 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); From 9dee07a6365d2facddea9a501737dce92333c582 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 4 Nov 2011 09:10:49 -0400 Subject: [PATCH 02/33] 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 --- restore.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/restore.c b/restore.c index 38c4ded6d..f062a2bbf 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 @@ static int copy_one_extent(struct btrfs_root *root, int fd, 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 @@ static int copy_one_extent(struct btrfs_root *root, int fd, 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); From ff0e1b17030a9b1e027c8b77f67ab44136e172ac Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 7 Nov 2011 16:41:01 -0500 Subject: [PATCH 03/33] 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 --- restore.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/restore.c b/restore.c index f062a2bbf..4dabae2c3 100644 --- a/restore.c +++ b/restore.c @@ -244,9 +244,16 @@ static int copy_one_extent(struct btrfs_root *root, int fd, 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; From 16073605bb947e6acfa3b13b6280a90fed9b717a Mon Sep 17 00:00:00 2001 From: David Marcin Date: Wed, 9 Nov 2011 13:23:28 -0800 Subject: [PATCH 04/33] btrfs-progs: Fix error handling for failed reads in restore tool when mirrors exist --- restore.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/restore.c b/restore.c index 4dabae2c3..389b10788 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 @@ static int copy_one_extent(struct btrfs_root *root, int fd, 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 @@ static int copy_one_extent(struct btrfs_root *root, int fd, goto again; } + mirror_num = 1; + size_left -= length; count += length; bytenr += length; if (size_left) From a1ebf7b951c6796039748601404aa01fd283ddef Mon Sep 17 00:00:00 2001 From: David Marcin Date: Wed, 16 Nov 2011 12:18:08 -0800 Subject: [PATCH 05/33] btrfs-progs: Check metadata mirrors in find-root. Signed-off-by: David Marcin --- find-root.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/find-root.c b/find-root.c index c0f38b884..2899632e6 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; } From 266f413a32d774c68f41f488bb79fac6ad63e930 Mon Sep 17 00:00:00 2001 From: Peter Stuge Date: Fri, 25 Nov 2011 01:03:57 +0100 Subject: [PATCH 06/33] 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 Signed-off-by: Josef Bacik --- restore.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/restore.c b/restore.c index 389b10788..0b92ed574 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 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key, } 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); From 2f0c2a29ab13b17ae1cc21effcf532f2447b7c8c Mon Sep 17 00:00:00 2001 From: Peter Stuge Date: Fri, 25 Nov 2011 01:03:58 +0100 Subject: [PATCH 07/33] 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 Signed-off-by: Josef Bacik --- restore.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/restore.c b/restore.c index 0b92ed574..e65746ae7 100644 --- a/restore.c +++ b/restore.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "kerncompat.h" #include "ctree.h" #include "disk-io.h" @@ -451,7 +453,8 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key, } 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 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key, static void usage() { - fprintf(stderr, "Usage: restore [-svio] [-t disk offset] " - "\n"); + fprintf(stderr, "Usage: restore [-svioc] [-t disk offset] " + "[-m regex] \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; } From e8919ef79253ace49de01ba228290e4e0cafbfb7 Mon Sep 17 00:00:00 2001 From: David Marcin Date: Mon, 21 Nov 2011 20:51:15 -0600 Subject: [PATCH 08/33] btrfs-progs: In find-root, dump bytenr for every slot. Signed-off-by: David Marcin --- find-root.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/find-root.c b/find-root.c index 2899632e6..bd44e1f0d 100644 --- a/find-root.c +++ b/find-root.c @@ -258,8 +258,63 @@ static struct btrfs_root *open_ctree_broken(int fd, const char *device) 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, " From db874f1e8924e86bbdee6600b0e5b3e6d11f9238 Mon Sep 17 00:00:00 2001 From: David Marcin Date: Tue, 22 Nov 2011 10:08:00 -0800 Subject: [PATCH 09/33] btrfs-progs: Add utility to dump all superblocks found on a device. Signed-off-by: David Marcin --- .gitignore | 4 +++ Makefile | 9 +++-- btrfs-dump-super.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 btrfs-dump-super.c diff --git a/.gitignore b/.gitignore index 0e560d518..cc5d69075 100644 --- a/.gitignore +++ b/.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 diff --git a/Makefile b/Makefile index 96e200201..548f88c35 100644 --- a/Makefile +++ b/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 # make C=1 to enable sparse ifdef C @@ -73,6 +74,9 @@ btrfs-zero-log: $(objects) btrfs-zero-log.o 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) @@ -105,7 +109,8 @@ install-man: clean : 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 cd man; make clean install: $(progs) install-man diff --git a/btrfs-dump-super.c b/btrfs-dump-super.c new file mode 100644 index 000000000..033140c56 --- /dev/null +++ b/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 +#include +#include +#include +#include +#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; +} From 6330d8d3b70c0ad35ce8048ccf69b3e96718ed53 Mon Sep 17 00:00:00 2001 From: David Marcin Date: Mon, 21 Nov 2011 20:31:01 -0600 Subject: [PATCH 10/33] btrfs-progs: Add the ability to use the earliest super found when opening the ctree. Signed-off-by: David Marcin --- 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 291dc27d4..c036f4696 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 408b2d58c..a161f1568 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 2048fcfcb..8fdcd9185 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 03bfb8cca..cde20ad7e 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 7104d36e6..08c53e474 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; From a780325614c0d89c9c0ea6779ada5af512b6e319 Mon Sep 17 00:00:00 2001 From: David Marcin Date: Tue, 22 Nov 2011 10:09:35 -0800 Subject: [PATCH 11/33] btrfs-progs: Use oldest super for btrfs-select-super. Add required confirmation to btrfs-select-super. Signed-off-by: David Marcin --- 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 51eb9c969..4d27f1b2a 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 a161f1568..9585057b6 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; From 2fe46117d3cde3737a1600195883e63ab4c59a8d Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 2 Dec 2011 10:07:43 -0500 Subject: [PATCH 12/33] 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 --- Makefile | 2 +- restore.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 548f88c35..64de4e67c 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 e65746ae7..6433378d0 100644 --- a/restore.c +++ b/restore.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #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 @@ static int copy_one_extent(struct btrfs_root *root, int fd, 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); From 1b8b3c3579ee127b174a850213df7ad81edd5710 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 2 Dec 2011 12:52:15 -0500 Subject: [PATCH 13/33] 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 --- restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restore.c b/restore.c index 6433378d0..a4ccb18ab 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 */ From 3ceceda914e19a3f7982c5050e6ffb23522071f2 Mon Sep 17 00:00:00 2001 From: David Marcin Date: Tue, 6 Dec 2011 12:14:54 -0800 Subject: [PATCH 14/33] btrfs-progs: Fix compilation errors with btrfs-select-super.c introduced by refactoring. Signed-off-by: David Marcin --- btrfs-select-super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/btrfs-select-super.c b/btrfs-select-super.c index 4d27f1b2a..079986aff 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; From fb0cfed5d3500e76ce30c6a9803ee1720bf1b4a5 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 7 Dec 2011 14:13:35 -0500 Subject: [PATCH 15/33] 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 --- 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 9585057b6..8a8071c58 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 8fdcd9185..2b1fcd530 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 bd44e1f0d..e0bc06991 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 a4ccb18ab..90d54e44c 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) From 412d4f1fe3a14c7e61efbd0ad4280323de71606a Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 7 Dec 2011 15:54:13 -0500 Subject: [PATCH 16/33] 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 --- root-tree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/root-tree.c b/root-tree.c index 782472ca9..7a6ae0adc 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); From df8b44a2980ace8b2e7483b96a661907e20b8a4c Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 7 Dec 2011 16:11:23 -0500 Subject: [PATCH 17/33] 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 --- disk-io.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/disk-io.c b/disk-io.c index 8a8071c58..b0b9502ad 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; } From 4686f96637316b509cb16c657b73b40a329be6db Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 8 Dec 2011 17:24:54 -0500 Subject: [PATCH 18/33] 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 --- restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/restore.c b/restore.c index 90d54e44c..398c49a88 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; } From 9bb7aa76e43f4942f5fa398bf00778067859f66c Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 9 Dec 2011 14:09:18 -0500 Subject: [PATCH 19/33] 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 --- restore.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/restore.c b/restore.c index 398c49a88..95daef244 100644 --- a/restore.c +++ b/restore.c @@ -773,11 +773,71 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key, static void usage() { - fprintf(stderr, "Usage: restore [-svioc] [-t disk offset] " + fprintf(stderr, "Usage: restore [-sviocl] [-t disk offset] " "[-m regex] \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); From 767972eece8f235b8c83e95c21a570e1fdd902e3 Mon Sep 17 00:00:00 2001 From: Hermann Gausterer Date: Wed, 4 Jan 2012 13:43:41 +0100 Subject: [PATCH 20/33] Btrfs-progs: fix typo --- btrfs_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/btrfs_cmds.c b/btrfs_cmds.c index f2b635512..887bdd4e2 100644 --- a/btrfs_cmds.c +++ b/btrfs_cmds.c @@ -613,7 +613,7 @@ int do_scan(int argc, char **argv) if( argc >= 2 && !strcmp(argv[1],"--all-devices")){ if( argc >2 ){ - fprintf(stderr, "ERROR: too may arguments\n"); + fprintf(stderr, "ERROR: too many arguments\n"); return 22; } From b36b23becb0d79faefd38da11b684a78b95243c9 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 09:56:06 -0500 Subject: [PATCH 21/33] 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 --- find-root.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/find-root.c b/find-root.c index e0bc06991..f9cb7ed8d 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)) { From d4d88fe3c9b393e2b21754237104c68a37123aa6 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 10:03:33 -0500 Subject: [PATCH 22/33] 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 --- find-root.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/find-root.c b/find-root.c index f9cb7ed8d..484f85f6d 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: From f0346659db85b826c14392f9a627d845ab47b7e2 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 10:36:41 -0500 Subject: [PATCH 23/33] 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 --- restore.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/restore.c b/restore.c index 95daef244..0b7590222 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; } From a3958e5a851f8d0efeafe5946b8a32ea0fd45436 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 10:37:43 -0500 Subject: [PATCH 24/33] 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 --- find-root.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/find-root.c b/find-root.c index 484f85f6d..43cb77845 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"); From 5ec6eeaff067c706e5bb9fc3144e9bab4e50da1e Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 10:48:32 -0500 Subject: [PATCH 25/33] 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 --- restore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/restore.c b/restore.c index 0b7590222..abc66cad9 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; } From a657103b449bfae0cc67dc9d7153ee19c20d9115 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 10:50:31 -0500 Subject: [PATCH 26/33] 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 --- find-root.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/find-root.c b/find-root.c index 43cb77845..bc7440a5b 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]++; } From 87edb6fbf4991e47e7563c4589197aa88befe266 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 11:50:55 -0500 Subject: [PATCH 27/33] 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 --- restore.c | 109 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/restore.c b/restore.c index abc66cad9..5aa35ae63 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) From 77ac61128a0722cab89c785f5f2247304133b214 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 4 Jan 2012 11:55:43 -0500 Subject: [PATCH 28/33] 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 --- restore.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/restore.c b/restore.c index 5aa35ae63..a2c29315f 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"); From 2d18933498291f04fcd1a3c1dbbb7774fab9b23f Mon Sep 17 00:00:00 2001 From: Ivan Tarasov Date: Thu, 5 Apr 2012 16:47:16 -0700 Subject: [PATCH 29/33] Fix long int size specifier in the printf format string --- restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restore.c b/restore.c index a2c29315f..1237b7baf 100644 --- a/restore.c +++ b/restore.c @@ -948,7 +948,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, 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", + fprintf(stderr, "Error reading fs root %ld\n", PTR_ERR(root->fs_info->fs_root)); close_ctree(root); return NULL; From 0cd8e404e1c9150281d93de72f2ba6911fafff7c Mon Sep 17 00:00:00 2001 From: Ivan Tarasov Date: Thu, 5 Apr 2012 16:49:06 -0700 Subject: [PATCH 30/33] Fix undefined reference to pthreads build problem --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 64de4e67c..ac1a150b1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -CFLAGS = -g -O0 +CFLAGS = -g -O0 -pthread 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 \ From 2a43e2b987b45b757f562ecaf0d6e203d747c08d Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Sun, 22 Jul 2012 21:17:58 +0930 Subject: [PATCH 31/33] naive attempt to fix super block with found root --- btrfsck.c | 20 +++++++++++++++++--- disk-io.c | 18 +++++++++++------- disk-io.h | 2 +- restore.c | 2 +- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/btrfsck.c b/btrfsck.c index 3a23e6656..ac4257ab3 100644 --- a/btrfsck.c +++ b/btrfsck.c @@ -2800,7 +2800,7 @@ static int check_extents(struct btrfs_root *root) static void print_usage(void) { - fprintf(stderr, "usage: btrfsck dev\n"); + fprintf(stderr, "usage: btrfsck [-s superblock] [-t tree root] [-g generation] dev\n"); fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); exit(1); } @@ -2810,12 +2810,14 @@ int main(int ac, char **av) struct cache_tree root_cache; struct btrfs_root *root; u64 bytenr = 0; + u64 root_tree_bytenr = 0; + u64 root_tree_generation = 0; int ret; int num; while(1) { int c; - c = getopt(ac, av, "s:"); + c = getopt(ac, av, "s:t:g:"); if (c < 0) break; switch(c) { @@ -2825,6 +2827,14 @@ int main(int ac, char **av) printf("using SB copy %d, bytenr %llu\n", num, (unsigned long long)bytenr); break; + case 't': + root_tree_bytenr = atoll(optarg); + printf("Using root tree %llu\n", root_tree_bytenr); + break; + case 'g': + root_tree_generation = atoll(optarg); + printf("Using generation %llu\n", root_tree_generation); + break; default: print_usage(); } @@ -2845,18 +2855,22 @@ int main(int ac, char **av) return -EBUSY; } - root = open_ctree(av[optind], bytenr, 0); + root = open_ctree_recovery(av[optind], bytenr, root_tree_bytenr, root_tree_generation); if (root == NULL) return 1; + printf("Checking extents...\n"); ret = check_extents(root); if (ret) goto out; + + printf("Checking fs roots...\n"); ret = check_fs_roots(root, &root_cache); if (ret) goto out; + printf("Checking root references...\n"); ret = check_root_refs(root, &root_cache); out: free_root_recs(&root_cache); diff --git a/disk-io.c b/disk-io.c index b0b9502ad..d12911aaf 100644 --- a/disk-io.c +++ b/disk-io.c @@ -604,7 +604,7 @@ 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, u64 root_tree_generation, int writes, int use_earliest_bdev) { u32 sectorsize; @@ -763,9 +763,13 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, if (!root_tree_bytenr) root_tree_bytenr = btrfs_super_root(disk_super); + + if (!root_tree_generation) + root_tree_generation = generation; + tree_root->node = read_tree_block(tree_root, root_tree_bytenr, - blocksize, generation); + blocksize, root_tree_generation); if (!tree_root->node) { printk("Couldn't read tree root\n"); goto out_chunk; @@ -796,7 +800,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, find_and_setup_log_root(tree_root, fs_info, disk_super); - fs_info->generation = generation; + fs_info->generation = root_tree_generation; fs_info->last_trans_committed = generation; btrfs_read_block_groups(fs_info->tree_root); @@ -856,14 +860,14 @@ 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); + root = __open_ctree_fd(fp, filename, sb_bytenr, 0, 0, writes, 0); close(fp); return root; } struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, - u64 root_tree_bytenr) + u64 root_tree_bytenr, u64 root_tree_generation) { int fp; struct btrfs_root *root; @@ -873,7 +877,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, 0); + root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, root_tree_generation, 0, 0); close(fp); return root; @@ -882,7 +886,7 @@ 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 use_earliest_bdev) { - return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev); + return __open_ctree_fd(fp, path, sb_bytenr, 0, 0, writes, use_earliest_bdev); } struct btrfs_root *open_ctree_broken(int fd, const char *device) diff --git a/disk-io.h b/disk-io.h index 2b1fcd530..ef1ec21fe 100644 --- a/disk-io.h +++ b/disk-io.h @@ -47,7 +47,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes); struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes, int use_earliest_bdev); struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, - u64 root_tree_bytenr); + u64 root_tree_bytenr, u64 root_tree_generation); 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/restore.c b/restore.c index 1237b7baf..3c704b617 100644 --- a/restore.c +++ b/restore.c @@ -877,7 +877,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); - root = open_ctree_recovery(dev, bytenr, root_location); + root = open_ctree_recovery(dev, bytenr, root_location, 0); if (root) goto out; fprintf(stderr, "Could not open root, trying backup super\n"); From 1605ee08999452f23e5dc18698f96f470c2f34a3 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Sun, 29 Jul 2012 12:13:20 +0930 Subject: [PATCH 32/33] Reduce spam when trying to find the best valid tree --- find-root.c | 38 +++++++++++++++++++++++++++----------- readme.ubuntu | 2 ++ 2 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 readme.ubuntu diff --git a/find-root.c b/find-root.c index bc7440a5b..3ad7af88a 100644 --- a/find-root.c +++ b/find-root.c @@ -38,6 +38,8 @@ static int verbose = 0; static u16 csum_size = 0; static u64 search_objectid = BTRFS_ROOT_TREE_OBJECTID; +u64 best_gen=0; +u64 best_hbyte=0; static void usage() { @@ -138,9 +140,10 @@ 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 " - "Root objectid: %Lu\n", gen, - btrfs_root_bytenr(&ri), found_key.objectid); + if (verbose) + printf("Generation: %Lu Root bytenr: %Lu " + "Root objectid: %Lu\n", gen, + btrfs_root_bytenr(&ri), found_key.objectid); } path->slots[0]++; } @@ -157,7 +160,7 @@ static int search_iobuf(struct btrfs_root *root, void *iobuf, u32 size = btrfs_super_nodesize(&root->fs_info->super_copy); u8 level = root->fs_info->super_copy.root_level; size_t block_off = 0; - + while (block_off < iobuf_size) { void *block = iobuf + block_off; struct btrfs_header *header = block; @@ -176,21 +179,29 @@ static int search_iobuf(struct btrfs_root *root, void *iobuf, if (h_level != level) goto next; if (csum_block(block, size)) { - fprintf(stderr, "Well block %Lu seems good, " - "but the csum doesn't match\n", - h_byte); + if (verbose) + fprintf(stderr, "Well block %Lu seems good, " + "but the csum doesn't match\n", + 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, " - "have=%Lu, want=%Lu\n", h_byte, h_gen, - gen); + if (h_gen > best_gen){ + best_gen=h_gen; + best_hbyte=h_byte; + } + if (verbose) + fprintf(stderr, "Well block %Lu seems great, " + "but generation doesn't match, " + "have=%Lu, want=%Lu\n", h_byte, h_gen, + gen); goto next; } + best_gen=h_gen; + best_hbyte=h_byte; printf("Found tree root at %Lu\n", h_byte); return 0; next: @@ -363,5 +374,10 @@ int main(int argc, char **argv) csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); ret = find_root(root); close_ctree(root); + + if (best_gen) + printf("Best generation I found was gen=%Lu at block %Lu", best_gen, best_hbyte); + else + printf("I couldn't find any valid blocks."); return ret; } diff --git a/readme.ubuntu b/readme.ubuntu new file mode 100644 index 000000000..5bbc8710a --- /dev/null +++ b/readme.ubuntu @@ -0,0 +1,2 @@ +sudo apt-get install uuid-dev zlib1g-dev liblzo2-dev +And edit mkfs.c replacing with From eba137a85986084770ad57c6729297a182857024 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Sun, 29 Jul 2012 13:03:22 +0930 Subject: [PATCH 33/33] Allow fsck to update super block (cross fingers) --- btrfsck.c | 10 +++++++--- disk-io.c | 4 ++-- disk-io.h | 2 +- restore.c | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/btrfsck.c b/btrfsck.c index ac4257ab3..43bff9e33 100644 --- a/btrfsck.c +++ b/btrfsck.c @@ -2814,10 +2814,11 @@ int main(int ac, char **av) u64 root_tree_generation = 0; int ret; int num; - + int writes=0; + while(1) { int c; - c = getopt(ac, av, "s:t:g:"); + c = getopt(ac, av, "s:t:g:c"); if (c < 0) break; switch(c) { @@ -2835,6 +2836,9 @@ int main(int ac, char **av) root_tree_generation = atoll(optarg); printf("Using generation %llu\n", root_tree_generation); break; + case 'c': + writes=1; + break; default: print_usage(); } @@ -2855,7 +2859,7 @@ int main(int ac, char **av) return -EBUSY; } - root = open_ctree_recovery(av[optind], bytenr, root_tree_bytenr, root_tree_generation); + root = open_ctree_recovery(av[optind], bytenr, root_tree_bytenr, root_tree_generation, writes); if (root == NULL) return 1; diff --git a/disk-io.c b/disk-io.c index d12911aaf..e0adf5ab5 100644 --- a/disk-io.c +++ b/disk-io.c @@ -867,7 +867,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes) } struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, - u64 root_tree_bytenr, u64 root_tree_generation) + u64 root_tree_bytenr, u64 root_tree_generation, int writes) { int fp; struct btrfs_root *root; @@ -877,7 +877,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, root_tree_generation, 0, 0); + root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, root_tree_generation, writes, 0); close(fp); return root; diff --git a/disk-io.h b/disk-io.h index ef1ec21fe..9edb9eccc 100644 --- a/disk-io.h +++ b/disk-io.h @@ -47,7 +47,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes); struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes, int use_earliest_bdev); struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, - u64 root_tree_bytenr, u64 root_tree_generation); + u64 root_tree_bytenr, u64 root_tree_generation, int writes); 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/restore.c b/restore.c index 3c704b617..4e175f04b 100644 --- a/restore.c +++ b/restore.c @@ -877,7 +877,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); - root = open_ctree_recovery(dev, bytenr, root_location, 0); + root = open_ctree_recovery(dev, bytenr, root_location, 0, 0); if (root) goto out; fprintf(stderr, "Could not open root, trying backup super\n");