btrfs-progs: Allow btrfs_read_dev_super() to read all 3 super for super_recover.

Btrfs-progs superblock checksum check is somewhat too restricted for
super-recover, since current btrfs-progs will only read the 1st
superblock and if you need super-recover the 1st superblock is
possibly already damaged.

The fix is introducing super_recover parameter for
btrfs_read_dev_super() and callers to allow scan backup superblocks if
needed.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
master
Qu Wenruo 2014-07-03 17:36:36 +08:00 committed by David Sterba
parent bc70abad8c
commit 23d7f6d9dc
9 changed files with 29 additions and 24 deletions

View File

@ -82,7 +82,7 @@ static struct btrfs_root *open_ctree_broken(int fd, const char *device)
return NULL;
}
ret = btrfs_scan_fs_devices(fd, device, &fs_devices, 0, 1);
ret = btrfs_scan_fs_devices(fd, device, &fs_devices, 0, 1, 1);
if (ret)
goto out;
@ -94,7 +94,7 @@ static struct btrfs_root *open_ctree_broken(int fd, const char *device)
disk_super = fs_info->super_copy;
ret = btrfs_read_dev_super(fs_devices->latest_bdev,
disk_super, fs_info->super_bytenr);
disk_super, fs_info->super_bytenr, 1);
if (ret) {
printk("No valid btrfs found\n");
goto out_devices;

View File

@ -1281,7 +1281,7 @@ open_ctree_with_broken_chunk(struct recover_control *rc)
disk_super = fs_info->super_copy;
ret = btrfs_read_dev_super(fs_info->fs_devices->latest_bdev,
disk_super, fs_info->super_bytenr);
disk_super, fs_info->super_bytenr, 1);
if (ret) {
fprintf(stderr, "No valid btrfs found\n");
goto out_devices;
@ -1347,7 +1347,7 @@ static int recover_prepare(struct recover_control *rc, char *path)
goto fail_close_fd;
}
ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET);
ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET, 1);
if (ret) {
fprintf(stderr, "read super block error\n");
goto fail_free_sb;
@ -1366,7 +1366,7 @@ static int recover_prepare(struct recover_control *rc, char *path)
goto fail_free_sb;
}
ret = btrfs_scan_fs_devices(fd, path, &fs_devices, 0, 1);
ret = btrfs_scan_fs_devices(fd, path, &fs_devices, 0, 1, 1);
if (ret)
goto fail_free_sb;

View File

@ -513,7 +513,7 @@ static int dev_to_fsid(char *dev, __u8 *fsid)
disk_super = (struct btrfs_super_block *)buf;
ret = btrfs_read_dev_super(fd, disk_super,
BTRFS_SUPER_INFO_OFFSET);
BTRFS_SUPER_INFO_OFFSET, 0);
if (ret)
goto out;

View File

@ -992,7 +992,7 @@ void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info)
int btrfs_scan_fs_devices(int fd, const char *path,
struct btrfs_fs_devices **fs_devices,
u64 sb_bytenr, int run_ioctl)
u64 sb_bytenr, int run_ioctl, int super_recover)
{
u64 total_devs;
int ret;
@ -1000,7 +1000,7 @@ int btrfs_scan_fs_devices(int fd, const char *path,
sb_bytenr = BTRFS_SUPER_INFO_OFFSET;
ret = btrfs_scan_one_device(fd, path, fs_devices,
&total_devs, sb_bytenr);
&total_devs, sb_bytenr, super_recover);
if (ret) {
fprintf(stderr, "No valid Btrfs found on %s\n", path);
return ret;
@ -1088,7 +1088,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
fs_info->on_restoring = 1;
ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr,
!(flags & OPEN_CTREE_RECOVER_SUPER));
!(flags & OPEN_CTREE_RECOVER_SUPER),
(flags & OPEN_CTREE_RECOVER_SUPER));
if (ret)
goto out;
@ -1108,9 +1109,9 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
disk_super = fs_info->super_copy;
if (!(flags & OPEN_CTREE_RECOVER_SUPER))
ret = btrfs_read_dev_super(fs_devices->latest_bdev,
disk_super, sb_bytenr);
disk_super, sb_bytenr, 1);
else
ret = btrfs_read_dev_super(fp, disk_super, sb_bytenr);
ret = btrfs_read_dev_super(fp, disk_super, sb_bytenr, 0);
if (ret) {
printk("No valid btrfs found\n");
goto out_devices;
@ -1194,13 +1195,15 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
return info->fs_root;
}
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr)
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,
int super_recover)
{
u8 fsid[BTRFS_FSID_SIZE];
int fsid_is_initialized = 0;
struct btrfs_super_block buf;
int i;
int ret;
int max_super = super_recover ? BTRFS_SUPER_MIRROR_MAX : 1;
u64 transid = 0;
u64 bytenr;
@ -1224,7 +1227,7 @@ int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr)
* later supers, using BTRFS_SUPER_MIRROR_MAX instead
*/
for (i = 0; i < 1; i++) {
for (i = 0; i < max_super; i++) {
bytenr = btrfs_sb_offset(i);
ret = pread64(fd, &buf, sizeof(buf), bytenr);
if (ret < sizeof(buf))

View File

@ -68,7 +68,7 @@ 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,
struct btrfs_fs_devices **fs_devices, u64 sb_bytenr,
int run_ioctl);
int run_ioctl, int super_recover);
int btrfs_setup_chunk_tree_and_device_map(struct btrfs_fs_info *fs_info);
struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr,
@ -82,7 +82,8 @@ int close_ctree(struct btrfs_root *root);
int write_all_supers(struct btrfs_root *root);
int write_ctree_super(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr);
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,
int super_recover);
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct extent_buffer *bh,
u64 logical);
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,

View File

@ -292,7 +292,7 @@ int btrfs_recover_superblocks(const char *dname,
}
init_recover_superblock(&recover);
ret = btrfs_scan_fs_devices(fd, dname, &recover.fs_devices, 0, 0);
ret = btrfs_scan_fs_devices(fd, dname, &recover.fs_devices, 0, 0, 1);
close(fd);
if (ret) {
ret = 1;

11
utils.c
View File

@ -1163,7 +1163,7 @@ int check_mounted_where(int fd, const char *file, char *where, int size,
/* scan the initial device */
ret = btrfs_scan_one_device(fd, file, &fs_devices_mnt,
&total_devs, BTRFS_SUPER_INFO_OFFSET);
&total_devs, BTRFS_SUPER_INFO_OFFSET, 0);
is_btrfs = (ret >= 0);
/* scan other devices */
@ -1325,7 +1325,7 @@ again:
}
ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices,
&num_devices,
BTRFS_SUPER_INFO_OFFSET);
BTRFS_SUPER_INFO_OFFSET, 0);
if (ret == 0 && run_ioctl > 0) {
btrfs_register_one_device(fullpath);
}
@ -1668,7 +1668,7 @@ scan_again:
}
ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices,
&num_devices,
BTRFS_SUPER_INFO_OFFSET);
BTRFS_SUPER_INFO_OFFSET, 0);
if (ret == 0 && run_ioctl > 0) {
btrfs_register_one_device(fullpath);
}
@ -1880,7 +1880,8 @@ int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
fi_args->num_devices = 1;
disk_super = (struct btrfs_super_block *)buf;
ret = btrfs_read_dev_super(fd, disk_super, BTRFS_SUPER_INFO_OFFSET);
ret = btrfs_read_dev_super(fd, disk_super,
BTRFS_SUPER_INFO_OFFSET, 0);
if (ret < 0) {
ret = -EIO;
goto out;
@ -2229,7 +2230,7 @@ int btrfs_scan_lblkid(int update_kernel)
continue;
}
ret = btrfs_scan_one_device(fd, path, &tmp_devices,
&num_devices, BTRFS_SUPER_INFO_OFFSET);
&num_devices, BTRFS_SUPER_INFO_OFFSET, 0);
if (ret) {
printf("ERROR: could not scan %s\n", path);
close (fd);

View File

@ -233,7 +233,7 @@ fail:
int btrfs_scan_one_device(int fd, const char *path,
struct btrfs_fs_devices **fs_devices_ret,
u64 *total_devs, u64 super_offset)
u64 *total_devs, u64 super_offset, int super_recover)
{
struct btrfs_super_block *disk_super;
char *buf;
@ -246,7 +246,7 @@ int btrfs_scan_one_device(int fd, const char *path,
goto error;
}
disk_super = (struct btrfs_super_block *)buf;
ret = btrfs_read_dev_super(fd, disk_super, super_offset);
ret = btrfs_read_dev_super(fd, disk_super, super_offset, super_recover);
if (ret < 0) {
ret = -EIO;
goto error_brelse;

View File

@ -179,7 +179,7 @@ int btrfs_update_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device);
int btrfs_scan_one_device(int fd, const char *path,
struct btrfs_fs_devices **fs_devices_ret,
u64 *total_devs, u64 super_offset);
u64 *total_devs, u64 super_offset, int super_recover);
int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
struct list_head *btrfs_scanned_uuids(void);
int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,