summaryrefslogtreecommitdiff
path: root/disk-io.c
diff options
context:
space:
mode:
authorWang Shilong <wangsl.fnst@cn.fujitsu.com>2013-09-21 16:34:18 +0800
committerChris Mason <chris.mason@fusionio.com>2013-10-16 08:23:08 -0400
commit7985fe64e0e290d6107bc4218920238928300010 (patch)
tree405340b03e06f4596237f5b2cb99e4e39d046a0c /disk-io.c
parent39813fb7ac3e622b25f27dcd78e98242e121011e (diff)
Btrfs-progs: add super-recover to recover bad supers
Until now if one of device's first superblock is corrupt,btrfs will fail to mount. Luckily, btrfs have at least two superblocks for every disk. In theory, if silent corrupting happens when we are writting superblocks into disk, we must hold at least one good superblock. One side effect is that user must gurantee that the disk must be a btrfs disk. Otherwise, this tool may destroy other fs.(This is also reason why btrfs only use first superblock in every disk to mount) This little program will try to correct bad superblocks from good superblocks with max generation. There will be five kinds of return values: 0: all supers are valid, no need to recover 1: usage or syntax error 2: recover all bad superblocks successfully 3: fail to recover bad superblocks 4: abort to recover bad superblocks Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'disk-io.c')
-rw-r--r--disk-io.c42
1 files changed, 35 insertions, 7 deletions
diff --git a/disk-io.c b/disk-io.c
index 62815692..83a20645 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -982,7 +982,8 @@ int btrfs_setup_chunk_tree_and_device_map(struct btrfs_fs_info *fs_info)
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 partial, int restore,
+ int recover_super)
{
struct btrfs_fs_info *fs_info;
struct btrfs_super_block *disk_super;
@@ -1005,7 +1006,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
if (restore)
fs_info->on_restoring = 1;
- ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr, 1);
+ ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr,
+ !recover_super);
if (ret)
goto out;
@@ -1019,8 +1021,11 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
disk_super = fs_info->super_copy;
- ret = btrfs_read_dev_super(fs_devices->latest_bdev,
- disk_super, sb_bytenr);
+ if (!recover_super)
+ ret = btrfs_read_dev_super(fs_devices->latest_bdev,
+ disk_super, sb_bytenr);
+ else
+ ret = btrfs_read_dev_super(fp, disk_super, sb_bytenr);
if (ret) {
printk("No valid btrfs found\n");
goto out_devices;
@@ -1078,7 +1083,7 @@ 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);
+ writes, partial, restore, 0);
close(fp);
return info;
}
@@ -1100,11 +1105,34 @@ 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);
+ writes, partial, 0, 0);
close(fp);
return info;
}
+struct btrfs_root *open_ctree_with_broken_super(const char *filename,
+ u64 sb_bytenr, int writes)
+{
+ int fp;
+ struct btrfs_fs_info *info;
+ int flags = O_CREAT | O_RDWR;
+
+ if (!writes)
+ flags = O_RDONLY;
+
+ fp = open(filename, flags, 0600);
+ if (fp < 0) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ return NULL;
+ }
+ info = __open_ctree_fd(fp, filename, sb_bytenr, 0,
+ writes, 0, 0, 1);
+ close(fp);
+ if (info)
+ return info->fs_root;
+ return NULL;
+}
+
struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
{
struct btrfs_fs_info *info;
@@ -1119,7 +1147,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);
+ info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, 0, 0, 0);
if (!info)
return NULL;
return info->fs_root;