mirror of
https://github.com/kdave/btrfs-progs
synced 2025-05-05 17:37:55 +00:00
Btrfs-progs: add -b to btrfsck to look at backup roots
In some cases the tree root is so hosed we can't get anything useful out of it. So add the -b option to btrfsck to make us look for the most recent backup tree root to use for repair. Then we can hopefully get ourselves into a working state. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
parent
4fc17596aa
commit
337f86fea1
@ -171,7 +171,7 @@ int main(int ac, char **av)
|
|||||||
if (ac != 1)
|
if (ac != 1)
|
||||||
print_usage();
|
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) {
|
if (!info) {
|
||||||
fprintf(stderr, "unable to open %s\n", av[optind]);
|
fprintf(stderr, "unable to open %s\n", av[optind]);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
10
cmds-check.c
10
cmds-check.c
@ -6022,6 +6022,7 @@ static struct option long_options[] = {
|
|||||||
{ "repair", 0, NULL, 0 },
|
{ "repair", 0, NULL, 0 },
|
||||||
{ "init-csum-tree", 0, NULL, 0 },
|
{ "init-csum-tree", 0, NULL, 0 },
|
||||||
{ "init-extent-tree", 0, NULL, 0 },
|
{ "init-extent-tree", 0, NULL, 0 },
|
||||||
|
{ "backup", 0, NULL, 0 },
|
||||||
{ NULL, 0, NULL, 0}
|
{ NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -6030,6 +6031,7 @@ const char * const cmd_check_usage[] = {
|
|||||||
"Check an unmounted btrfs filesystem.",
|
"Check an unmounted btrfs filesystem.",
|
||||||
"",
|
"",
|
||||||
"-s|--super <superblock> use this superblock copy",
|
"-s|--super <superblock> use this superblock copy",
|
||||||
|
"-b|--backup use the backup root copy",
|
||||||
"--repair try to repair the filesystem",
|
"--repair try to repair the filesystem",
|
||||||
"--init-csum-tree create a new CRC tree",
|
"--init-csum-tree create a new CRC tree",
|
||||||
"--init-extent-tree create a new extent 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;
|
struct btrfs_fs_info *info;
|
||||||
u64 bytenr = 0;
|
u64 bytenr = 0;
|
||||||
char uuidbuf[37];
|
char uuidbuf[37];
|
||||||
|
int backup_root = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int num;
|
int num;
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
@ -6052,12 +6055,15 @@ int cmd_check(int argc, char **argv)
|
|||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
int c;
|
int c;
|
||||||
c = getopt_long(argc, argv, "as:", long_options,
|
c = getopt_long(argc, argv, "as:b", long_options,
|
||||||
&option_index);
|
&option_index);
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
break;
|
break;
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'a': /* ignored */ break;
|
case 'a': /* ignored */ break;
|
||||||
|
case 'b':
|
||||||
|
backup_root = 1;
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
num = atol(optarg);
|
num = atol(optarg);
|
||||||
bytenr = btrfs_sb_offset(num);
|
bytenr = btrfs_sb_offset(num);
|
||||||
@ -6099,7 +6105,7 @@ int cmd_check(int argc, char **argv)
|
|||||||
return -EBUSY;
|
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) {
|
if (!info) {
|
||||||
fprintf(stderr, "Couldn't open file system\n");
|
fprintf(stderr, "Couldn't open file system\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -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++) {
|
for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
||||||
bytenr = btrfs_sb_offset(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)
|
if (fs_info)
|
||||||
break;
|
break;
|
||||||
fprintf(stderr, "Could not open root, trying backup super\n");
|
fprintf(stderr, "Could not open root, trying backup super\n");
|
||||||
|
54
disk-io.c
54
disk-io.c
@ -808,8 +808,27 @@ int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable)
|
|||||||
return 0;
|
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,
|
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_super_block *sb = fs_info->super_copy;
|
||||||
struct btrfs_root *root;
|
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));
|
blocksize = btrfs_level_size(root, btrfs_super_root_level(sb));
|
||||||
generation = btrfs_super_generation(sb);
|
generation = btrfs_super_generation(sb);
|
||||||
|
|
||||||
if (!root_tree_bytenr)
|
if (!root_tree_bytenr && !backup_root) {
|
||||||
root_tree_bytenr = btrfs_super_root(sb);
|
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,
|
root->node = read_tree_block(root, root_tree_bytenr, blocksize,
|
||||||
generation);
|
generation);
|
||||||
if (!extent_buffer_uptodate(root->node)) {
|
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 sb_bytenr,
|
||||||
u64 root_tree_bytenr, int writes,
|
u64 root_tree_bytenr, int writes,
|
||||||
int partial, int restore,
|
int partial, int restore,
|
||||||
int recover_super)
|
int recover_super,
|
||||||
|
int backup_root)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info;
|
struct btrfs_fs_info *fs_info;
|
||||||
struct btrfs_super_block *disk_super;
|
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),
|
(unsigned long)btrfs_header_chunk_tree_uuid(eb),
|
||||||
BTRFS_UUID_SIZE);
|
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)
|
if (ret)
|
||||||
goto out_failed;
|
goto out_failed;
|
||||||
|
|
||||||
@ -1105,14 +1138,15 @@ struct btrfs_fs_info *open_ctree_fs_info_restore(const char *filename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
|
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
|
||||||
writes, partial, restore, 0);
|
writes, partial, restore, 0, 0);
|
||||||
close(fp);
|
close(fp);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
|
struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
|
||||||
u64 sb_bytenr, u64 root_tree_bytenr,
|
u64 sb_bytenr, u64 root_tree_bytenr,
|
||||||
int writes, int partial)
|
int writes, int partial,
|
||||||
|
int backup_root)
|
||||||
{
|
{
|
||||||
int fp;
|
int fp;
|
||||||
struct btrfs_fs_info *info;
|
struct btrfs_fs_info *info;
|
||||||
@ -1127,7 +1161,7 @@ struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
|
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
|
||||||
writes, partial, 0, 0);
|
writes, partial, 0, 0, backup_root);
|
||||||
close(fp);
|
close(fp);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -1148,7 +1182,7 @@ struct btrfs_root *open_ctree_with_broken_super(const char *filename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
info = __open_ctree_fd(fp, filename, sb_bytenr, 0,
|
info = __open_ctree_fd(fp, filename, sb_bytenr, 0,
|
||||||
writes, 0, 0, 1);
|
writes, 0, 0, 1, 0);
|
||||||
close(fp);
|
close(fp);
|
||||||
if (info)
|
if (info)
|
||||||
return info->fs_root;
|
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;
|
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)
|
if (!info)
|
||||||
return NULL;
|
return NULL;
|
||||||
return info->fs_root;
|
return info->fs_root;
|
||||||
@ -1169,7 +1203,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
|
|||||||
int writes)
|
int writes)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *info;
|
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)
|
if (!info)
|
||||||
return NULL;
|
return NULL;
|
||||||
return info->fs_root;
|
return info->fs_root;
|
||||||
|
@ -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);
|
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_check_fs_compatibility(struct btrfs_super_block *sb, int writable);
|
||||||
int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
|
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_release_all_roots(struct btrfs_fs_info *fs_info);
|
||||||
void btrfs_cleanup_all_caches(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,
|
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);
|
int writes, int partial);
|
||||||
struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
|
struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
|
||||||
u64 sb_bytenr, u64 root_tree_bytenr,
|
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,
|
struct btrfs_root *open_ctree_with_broken_super(const char *filename,
|
||||||
u64 sb_bytenr, int writes);
|
u64 sb_bytenr, int writes);
|
||||||
int close_ctree(struct btrfs_root *root);
|
int close_ctree(struct btrfs_root *root);
|
||||||
|
Loading…
Reference in New Issue
Block a user