summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--btrfs-convert.c7
-rw-r--r--ctree.h1
-rw-r--r--disk-io.c35
-rw-r--r--disk-io.h11
-rw-r--r--mkfs.c7
-rw-r--r--utils.c10
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");
diff --git a/ctree.h b/ctree.h
index 89e47abd..d0569835 100644
--- a/ctree.h
+++ b/ctree.h
@@ -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,
diff --git a/disk-io.c b/disk-io.c
index 4874f068..ca4578f7 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -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);
diff --git a/disk-io.h b/disk-io.h
index 153ef1f4..a73dede1 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -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)
diff --git a/mkfs.c b/mkfs.c
index 0b081dd4..ee5a30da 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -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);
diff --git a/utils.c b/utils.c
index e7195b53..cec7c738 100644
--- a/utils.c
+++ b/utils.c
@@ -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]);