summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--btrfs-debug-tree.c2
-rw-r--r--cmds-check.c10
-rw-r--r--cmds-restore.c2
-rw-r--r--disk-io.c54
-rw-r--r--disk-io.h5
5 files changed, 57 insertions, 16 deletions
diff --git a/btrfs-debug-tree.c b/btrfs-debug-tree.c
index 078dac5d..4a9d89de 100644
--- a/btrfs-debug-tree.c
+++ b/btrfs-debug-tree.c
@@ -171,7 +171,7 @@ int main(int ac, char **av)
if (ac != 1)
print_usage();
- info = open_ctree_fs_info(av[optind], 0, 0, 0, 1);
+ info = open_ctree_fs_info(av[optind], 0, 0, 0, 1, 0);
if (!info) {
fprintf(stderr, "unable to open %s\n", av[optind]);
exit(1);
diff --git a/cmds-check.c b/cmds-check.c
index 668af158..3453cac2 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -6022,6 +6022,7 @@ static struct option long_options[] = {
{ "repair", 0, NULL, 0 },
{ "init-csum-tree", 0, NULL, 0 },
{ "init-extent-tree", 0, NULL, 0 },
+ { "backup", 0, NULL, 0 },
{ NULL, 0, NULL, 0}
};
@@ -6030,6 +6031,7 @@ const char * const cmd_check_usage[] = {
"Check an unmounted btrfs filesystem.",
"",
"-s|--super <superblock> use this superblock copy",
+ "-b|--backup use the backup root copy",
"--repair try to repair the filesystem",
"--init-csum-tree create a new CRC tree",
"--init-extent-tree create a new extent tree",
@@ -6043,6 +6045,7 @@ int cmd_check(int argc, char **argv)
struct btrfs_fs_info *info;
u64 bytenr = 0;
char uuidbuf[37];
+ int backup_root = 0;
int ret;
int num;
int option_index = 0;
@@ -6052,12 +6055,15 @@ int cmd_check(int argc, char **argv)
while(1) {
int c;
- c = getopt_long(argc, argv, "as:", long_options,
+ c = getopt_long(argc, argv, "as:b", long_options,
&option_index);
if (c < 0)
break;
switch(c) {
case 'a': /* ignored */ break;
+ case 'b':
+ backup_root = 1;
+ break;
case 's':
num = atol(optarg);
bytenr = btrfs_sb_offset(num);
@@ -6099,7 +6105,7 @@ int cmd_check(int argc, char **argv)
return -EBUSY;
}
- info = open_ctree_fs_info(argv[optind], bytenr, 0, rw, 1);
+ info = open_ctree_fs_info(argv[optind], bytenr, 0, rw, 1, backup_root);
if (!info) {
fprintf(stderr, "Couldn't open file system\n");
return -EIO;
diff --git a/cmds-restore.c b/cmds-restore.c
index ae0527b6..e315d2e6 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -974,7 +974,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);
- fs_info = open_ctree_fs_info(dev, bytenr, root_location, 0, 1);
+ fs_info = open_ctree_fs_info(dev, bytenr, root_location, 0, 1, 0);
if (fs_info)
break;
fprintf(stderr, "Could not open root, trying backup super\n");
diff --git a/disk-io.c b/disk-io.c
index ca76c425..733714df 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -808,8 +808,27 @@ int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable)
return 0;
}
+static int find_best_backup_root(struct btrfs_super_block *super)
+{
+ struct btrfs_root_backup *backup;
+ u64 orig_gen = btrfs_super_generation(super);
+ u64 gen = 0;
+ int best_index = 0;
+ int i;
+
+ for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
+ backup = super->super_roots + i;
+ if (btrfs_backup_tree_root_gen(backup) != orig_gen &&
+ btrfs_backup_tree_root_gen(backup) > gen) {
+ best_index = i;
+ gen = btrfs_backup_tree_root_gen(backup);
+ }
+ }
+ return best_index;
+}
+
int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
- u64 root_tree_bytenr, int partial)
+ u64 root_tree_bytenr, int partial, int backup_root)
{
struct btrfs_super_block *sb = fs_info->super_copy;
struct btrfs_root *root;
@@ -833,8 +852,20 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
blocksize = btrfs_level_size(root, btrfs_super_root_level(sb));
generation = btrfs_super_generation(sb);
- if (!root_tree_bytenr)
+ if (!root_tree_bytenr && !backup_root) {
root_tree_bytenr = btrfs_super_root(sb);
+ } else if (backup_root) {
+ struct btrfs_root_backup *backup;
+ int index = find_best_backup_root(sb);
+ if (index >= BTRFS_NUM_BACKUP_ROOTS) {
+ fprintf(stderr, "Invalid backup root number\n");
+ return -EIO;
+ }
+ backup = fs_info->super_copy->super_roots + index;
+ root_tree_bytenr = btrfs_backup_tree_root(backup);
+ generation = btrfs_backup_tree_root_gen(backup);
+ }
+
root->node = read_tree_block(root, root_tree_bytenr, blocksize,
generation);
if (!extent_buffer_uptodate(root->node)) {
@@ -1005,7 +1036,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
u64 sb_bytenr,
u64 root_tree_bytenr, int writes,
int partial, int restore,
- int recover_super)
+ int recover_super,
+ int backup_root)
{
struct btrfs_fs_info *fs_info;
struct btrfs_super_block *disk_super;
@@ -1068,7 +1100,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
(unsigned long)btrfs_header_chunk_tree_uuid(eb),
BTRFS_UUID_SIZE);
- ret = btrfs_setup_all_roots(fs_info, root_tree_bytenr, partial);
+ ret = btrfs_setup_all_roots(fs_info, root_tree_bytenr, partial,
+ backup_root);
if (ret)
goto out_failed;
@@ -1105,14 +1138,15 @@ struct btrfs_fs_info *open_ctree_fs_info_restore(const char *filename,
return NULL;
}
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
- writes, partial, restore, 0);
+ writes, partial, restore, 0, 0);
close(fp);
return info;
}
struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
u64 sb_bytenr, u64 root_tree_bytenr,
- int writes, int partial)
+ int writes, int partial,
+ int backup_root)
{
int fp;
struct btrfs_fs_info *info;
@@ -1127,7 +1161,7 @@ struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
return NULL;
}
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
- writes, partial, 0, 0);
+ writes, partial, 0, 0, backup_root);
close(fp);
return info;
}
@@ -1148,7 +1182,7 @@ struct btrfs_root *open_ctree_with_broken_super(const char *filename,
return NULL;
}
info = __open_ctree_fd(fp, filename, sb_bytenr, 0,
- writes, 0, 0, 1);
+ writes, 0, 0, 1, 0);
close(fp);
if (info)
return info->fs_root;
@@ -1159,7 +1193,7 @@ 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, 0, writes, 0);
+ info = open_ctree_fs_info(filename, sb_bytenr, 0, writes, 0, 0);
if (!info)
return NULL;
return info->fs_root;
@@ -1169,7 +1203,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int writes)
{
struct btrfs_fs_info *info;
- info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, 0, 0, 0);
+ info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, 0, 0, 0, 0);
if (!info)
return NULL;
return info->fs_root;
diff --git a/disk-io.h b/disk-io.h
index 6f2d4f41..b0292db2 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -53,7 +53,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info);
struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr);
int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable);
int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
- u64 root_tree_bytenr, int partial);
+ u64 root_tree_bytenr, int partial, int backup_root);
void btrfs_release_all_roots(struct btrfs_fs_info *fs_info);
void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info);
int btrfs_scan_fs_devices(int fd, const char *path,
@@ -69,7 +69,8 @@ struct btrfs_fs_info *open_ctree_fs_info_restore(const char *filename,
int writes, int partial);
struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
u64 sb_bytenr, u64 root_tree_bytenr,
- int writes, int partial);
+ int writes, int partial,
+ int backup_root);
struct btrfs_root *open_ctree_with_broken_super(const char *filename,
u64 sb_bytenr, int writes);
int close_ctree(struct btrfs_root *root);