diff --git a/Documentation/mkfs.btrfs.rst b/Documentation/mkfs.btrfs.rst index 629231a2..a4817e77 100644 --- a/Documentation/mkfs.btrfs.rst +++ b/Documentation/mkfs.btrfs.rst @@ -163,6 +163,7 @@ OPTIONS *flags* is an optional comma-separated list of modifiers. Valid choices are: * *default*: create as default subvolume (this can only be specified once) + * *ro*: create as readonly subvolume --shrink Shrink the filesystem to its minimal size, only works with *--rootdir* option. diff --git a/common/root-tree-utils.c b/common/root-tree-utils.c index 09b9ada0..a416fceb 100644 --- a/common/root-tree-utils.c +++ b/common/root-tree-utils.c @@ -66,7 +66,8 @@ error: * The created tree root would have its root_ref as 1. * Thus for subvolumes caller needs to properly add ROOT_BACKREF items. */ -int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid) +int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid, + bool readonly) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root; @@ -98,6 +99,13 @@ int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid) ret = btrfs_make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID); if (ret < 0) goto error; + + btrfs_set_stack_inode_flags(&root->root_item.inode, + BTRFS_INODE_ROOT_ITEM_INIT); + + if (readonly) + btrfs_set_root_flags(&root->root_item, BTRFS_ROOT_SUBVOL_RDONLY); + ret = btrfs_update_root(trans, fs_info->tree_root, &root->root_key, &root->root_item); if (ret < 0) diff --git a/common/root-tree-utils.h b/common/root-tree-utils.h index 3cb50802..c4964a36 100644 --- a/common/root-tree-utils.h +++ b/common/root-tree-utils.h @@ -21,7 +21,8 @@ int btrfs_make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid); -int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid); +int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid, + bool readonly); int btrfs_link_subvolume(struct btrfs_trans_handle *trans, struct btrfs_root *parent_root, u64 parent_dir, const char *name, diff --git a/convert/main.c b/convert/main.c index b2cfbcef..a227cc6f 100644 --- a/convert/main.c +++ b/convert/main.c @@ -1022,13 +1022,14 @@ static int init_btrfs(struct btrfs_mkfs_config *cfg, struct btrfs_root *root, BTRFS_FIRST_FREE_OBJECTID); /* subvol for fs image file */ - ret = btrfs_make_subvolume(trans, CONV_IMAGE_SUBVOL_OBJECTID); + ret = btrfs_make_subvolume(trans, CONV_IMAGE_SUBVOL_OBJECTID, false); if (ret < 0) { error("failed to create subvolume image root: %d", ret); goto err; } /* subvol for data relocation tree */ - ret = btrfs_make_subvolume(trans, BTRFS_DATA_RELOC_TREE_OBJECTID); + ret = btrfs_make_subvolume(trans, BTRFS_DATA_RELOC_TREE_OBJECTID, + false); if (ret < 0) { error("failed to create DATA_RELOC root: %d", ret); goto err; diff --git a/mkfs/main.c b/mkfs/main.c index b0d4fd0b..06cc2484 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1036,6 +1036,8 @@ static int parse_subvol_flags(struct rootdir_subvol *subvol, const char *flags) if (!strcmp(buf, "default")) { subvol->is_default = true; + } else if (!strcmp(buf, "ro")) { + subvol->readonly = true; } else if (buf[0] != 0) { error("unrecognized subvol flag \"%s\"", buf); ret = 1; @@ -1988,7 +1990,8 @@ raid_groups: goto out; } - ret = btrfs_make_subvolume(trans, BTRFS_DATA_RELOC_TREE_OBJECTID); + ret = btrfs_make_subvolume(trans, BTRFS_DATA_RELOC_TREE_OBJECTID, + false); if (ret) { error("unable to create data reloc tree: %d", ret); goto out; diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c index c31651d0..5e80b871 100644 --- a/mkfs/rootdir.c +++ b/mkfs/rootdir.c @@ -430,7 +430,7 @@ static int ftw_add_subvol(const char *full_path, const struct stat *st, subvol_id = next_subvol_id++; - ret = btrfs_make_subvolume(g_trans, subvol_id); + ret = btrfs_make_subvolume(g_trans, subvol_id, subvol->readonly); if (ret < 0) { errno = -ret; error("failed to create subvolume: %m"); diff --git a/mkfs/rootdir.h b/mkfs/rootdir.h index 871889d9..44817374 100644 --- a/mkfs/rootdir.h +++ b/mkfs/rootdir.h @@ -33,6 +33,7 @@ struct rootdir_subvol { char *dir; char *full_path; bool is_default; + bool readonly; }; int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,