diff options
-rw-r--r-- | btrfs-convert.c | 7 | ||||
-rw-r--r-- | ctree.h | 1 | ||||
-rw-r--r-- | disk-io.c | 35 | ||||
-rw-r--r-- | disk-io.h | 11 | ||||
-rw-r--r-- | mkfs.c | 7 | ||||
-rw-r--r-- | utils.c | 10 |
6 files changed, 59 insertions, 12 deletions
diff --git a/btrfs-convert.c b/btrfs-convert.c index a8852d61..b34a413d 100644 --- a/btrfs-convert.c +++ b/btrfs-convert.c @@ -2345,7 +2345,7 @@ static int do_convert(const char *devname, int datacsum, int packing, } root = open_ctree_fd(fd, devname, mkfs_cfg.super_bytenr, - OPEN_CTREE_WRITES); + OPEN_CTREE_WRITES | OPEN_CTREE_FS_PARTIAL); if (!root) { fprintf(stderr, "unable to open ctree\n"); goto fail; @@ -2431,11 +2431,14 @@ static int do_convert(const char *devname, int datacsum, int packing, } is_btrfs = 1; - root = open_ctree_fd(fd, devname, 0, OPEN_CTREE_WRITES); + root = open_ctree_fd(fd, devname, 0, + OPEN_CTREE_WRITES | OPEN_CTREE_FS_PARTIAL); if (!root) { fprintf(stderr, "unable to open ctree\n"); goto fail; } + root->fs_info->finalize_on_close = 1; + close_ctree(root); close(fd); printf("conversion complete.\n"); @@ -1032,6 +1032,7 @@ struct btrfs_fs_info { unsigned int ignore_chunk_tree_error:1; unsigned int avoid_meta_chunk_alloc:1; unsigned int avoid_sys_chunk_alloc:1; + unsigned int finalize_on_close:1; int (*free_extent_hook)(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -1225,6 +1225,7 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, struct extent_buffer *eb; int ret; int oflags; + unsigned sbflags = SBREAD_DEFAULT; if (sb_bytenr == 0) sb_bytenr = BTRFS_SUPER_INFO_OFFSET; @@ -1247,9 +1248,18 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, if (flags & OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR) fs_info->ignore_chunk_tree_error = 1; - ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr, - (flags & OPEN_CTREE_RECOVER_SUPER) ? SBREAD_RECOVER : SBREAD_DEFAULT, - (flags & OPEN_CTREE_NO_DEVICES)); + if ((flags & OPEN_CTREE_RECOVER_SUPER) + && (flags & OPEN_CTREE_FS_PARTIAL)) { + fprintf(stderr, + "cannot open a partially created filesystem for recovery"); + goto out; + } + + if (flags & OPEN_CTREE_FS_PARTIAL) + sbflags = SBREAD_PARTIAL; + + ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr, sbflags, + (flags & OPEN_CTREE_NO_DEVICES)); if (ret) goto out; @@ -1272,7 +1282,7 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, sb_bytenr, SBREAD_RECOVER); else ret = btrfs_read_dev_super(fp, disk_super, sb_bytenr, - SBREAD_DEFAULT); + sbflags); if (ret) { printk("No valid btrfs found\n"); goto out_devices; @@ -1401,8 +1411,12 @@ static int check_super(struct btrfs_super_block *sb, unsigned sbflags) int csum_size; if (btrfs_super_magic(sb) != BTRFS_MAGIC) { - error("superblock magic doesn't match"); - return -EIO; + if (btrfs_super_magic(sb) == BTRFS_MAGIC_PARTIAL) { + if (!(sbflags & SBREAD_PARTIAL)) { + error("superblock magic doesn't match"); + return -EIO; + } + } } csum_type = btrfs_super_csum_type(sb); @@ -1747,6 +1761,15 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) write_ctree_super(trans, root); btrfs_free_transaction(root, trans); } + + if (fs_info->finalize_on_close) { + btrfs_set_super_magic(fs_info->super_copy, BTRFS_MAGIC); + root->fs_info->finalize_on_close = 0; + ret = write_all_supers(root); + if (ret) + fprintf(stderr, + "failed to write new super block err %d\n", ret); + } btrfs_free_block_groups(fs_info); free_fs_roots_tree(&fs_info->fs_root_tree); @@ -61,7 +61,10 @@ enum btrfs_open_ctree_flags { * It's useful for chunk corruption case. * Makes no sense for open_ctree variants returning btrfs_root. */ - OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR = (1 << 11) + OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR = (1 << 11), + + /* Allow to open a partially created filesystem */ + OPEN_CTREE_FS_PARTIAL = (1 << 12), }; /* @@ -71,6 +74,12 @@ enum btrfs_read_sb_flags { SBREAD_DEFAULT = 0, /* Reading superblock during recovery */ SBREAD_RECOVER = (1 << 0), + + /* + * Read superblock with the fake signature, cannot be used with + * SBREAD_RECOVER + */ + SBREAD_PARTIAL = (1 << 1), }; static inline u64 btrfs_sb_offset(int mirror) @@ -1708,7 +1708,7 @@ int main(int argc, char **argv) exit(1); } - root = open_ctree(file, 0, OPEN_CTREE_WRITES); + root = open_ctree(file, 0, OPEN_CTREE_WRITES | OPEN_CTREE_FS_PARTIAL); if (!root) { error("open ctree failed"); close(fd); @@ -1858,6 +1858,11 @@ raid_groups: list_all_devices(root); } + /* + * The filesystem is now fully set up, commit the remaining changes and + * fix the signature as the last step before closing the devices. + */ + root->fs_info->finalize_on_close = 1; out: ret = close_ctree(root); BUG_ON(ret); @@ -238,6 +238,9 @@ static inline int write_temp_super(int fd, struct btrfs_super_block *sb, * * For now sys chunk array will be empty and dev_item is empty too. * They will be re-initialized at temp chunk tree setup. + * + * The superblock signature is not valid, denotes a partially created + * filesystem, needs to be finalized. */ static int setup_temp_super(int fd, struct btrfs_mkfs_config *cfg, u64 root_bytenr, u64 chunk_bytenr) @@ -276,7 +279,7 @@ static int setup_temp_super(int fd, struct btrfs_mkfs_config *cfg, btrfs_set_super_bytenr(super, cfg->super_bytenr); btrfs_set_super_num_devices(super, 1); - btrfs_set_super_magic(super, BTRFS_MAGIC); + btrfs_set_super_magic(super, BTRFS_MAGIC_PARTIAL); btrfs_set_super_generation(super, 1); btrfs_set_super_root(super, root_bytenr); btrfs_set_super_chunk_root(super, chunk_bytenr); @@ -1004,6 +1007,9 @@ out: /* * @fs_uuid - if NULL, generates a UUID, returns back the new filesystem UUID + * + * The superblock signature is not valid, denotes a partially created + * filesystem, needs to be finalized. */ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg, struct btrfs_convert_context *cctx) @@ -1064,7 +1070,7 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg, btrfs_set_super_bytenr(&super, cfg->blocks[0]); btrfs_set_super_num_devices(&super, 1); - btrfs_set_super_magic(&super, BTRFS_MAGIC); + btrfs_set_super_magic(&super, BTRFS_MAGIC_PARTIAL); btrfs_set_super_generation(&super, 1); btrfs_set_super_root(&super, cfg->blocks[1]); btrfs_set_super_chunk_root(&super, cfg->blocks[3]); |