Skip to content

Commit

Permalink
btrfs-progs: add --default-subvol option to mkfs.btrfs
Browse files Browse the repository at this point in the history
Adds a --default-subvol option to mkfs.btrfs, which works the same way
as --subvol but also marks the subvolume as the default.

Signed-off-by: Mark Harmstone <[email protected]>
  • Loading branch information
maharmstone committed Aug 14, 2024
1 parent 58663fa commit e0dfe20
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 5 deletions.
4 changes: 4 additions & 0 deletions Documentation/mkfs.btrfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ OPTIONS
directory. The option *--rootdir* must also be specified, and *subdir* must be an
existing subdirectory within it. This option can be specified multiple times.

-D|--default-subvol <subdir>
As *--subvol*, except that it also sets the subvolume as the default for the
filesystem. This option can only be specified once.

--shrink
Shrink the filesystem to its minimal size, only works with *--rootdir* option.

Expand Down
34 changes: 31 additions & 3 deletions mkfs/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ static const char * const mkfs_usage[] = {
OPTLINE("-b|--byte-count SIZE", "set size of each device to SIZE (filesystem size is sum of all device sizes)"),
OPTLINE("-r|--rootdir DIR", "copy files from DIR to the image root directory"),
OPTLINE("-u|--subvol SUBDIR", "create SUBDIR as subvolume rather than normal directory"),
OPTLINE("-D|--default-subvol SUBDIR", "create SUBDIR as subvolume rather than normal directory, and set it as the default"),
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
Expand Down Expand Up @@ -1058,6 +1059,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
char *source_dir = NULL;
size_t source_dir_len = 0;
struct rootdir_subvol *rds;
bool has_default_subvol = false;
LIST_HEAD(subvols);

cpu_detect_flags();
Expand Down Expand Up @@ -1090,6 +1092,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
{ "version", no_argument, NULL, 'V' },
{ "rootdir", required_argument, NULL, 'r' },
{ "subvol", required_argument, NULL, 'u' },
{ "default-subvol", required_argument, NULL, 'D' },
{ "nodiscard", no_argument, NULL, 'K' },
{ "features", required_argument, NULL, 'O' },
{ "runtime-features", required_argument, NULL, 'R' },
Expand All @@ -1107,7 +1110,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
{ NULL, 0, NULL, 0}
};

c = getopt_long(argc, argv, "A:b:fl:n:s:m:d:L:R:O:r:U:VvMKqu:",
c = getopt_long(argc, argv, "A:b:fl:n:s:m:d:L:R:O:r:U:VvMKqu:D:",
long_options, NULL);
if (c < 0)
break;
Expand Down Expand Up @@ -1213,7 +1216,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
free(source_dir);
source_dir = strdup(optarg);
break;
case 'u': {
case 'u':
case 'D': {
struct rootdir_subvol *s;

s = malloc(sizeof(struct rootdir_subvol));
Expand All @@ -1226,6 +1230,19 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
s->dir = strdup(optarg);
s->full_path = NULL;

if (c == 'D') {
if (has_default_subvol) {
error("--default-subvol can only be specified once");
ret = 1;
goto error;
}

has_default_subvol = true;
s->is_default = true;
} else {
s->is_default = false;
}

list_add_tail(&s->list, &subvols);
break;
}
Expand Down Expand Up @@ -1928,6 +1945,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
}

if (source_dir) {
u64 default_subvol_id;

pr_verbose(LOG_DEFAULT, "Rootdir from: %s\n", source_dir);

trans = btrfs_start_transaction(root, 1);
Expand All @@ -1938,7 +1957,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
}

ret = btrfs_mkfs_fill_dir(trans, source_dir, root,
&subvols);
&subvols, &default_subvol_id);
if (ret) {
error("error while filling filesystem: %d", ret);
btrfs_abort_transaction(trans, ret);
Expand Down Expand Up @@ -1969,6 +1988,15 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
} else {
pr_verbose(LOG_DEFAULT, " Shrink: no\n");
}

if (has_default_subvol) {
ret = btrfs_set_default_subvolume(fs_info,
default_subvol_id);
if (ret < 0) {
error("error setting default subvolume: %d", ret);
goto out;
}
}
}

ret = btrfs_rebuild_uuid_tree(fs_info);
Expand Down
58 changes: 57 additions & 1 deletion mkfs/rootdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ static struct rootdir_path current_path = {

static struct btrfs_trans_handle *g_trans = NULL;
static struct list_head *g_subvols;
static u64 *g_default_subvol_id;
static u64 next_subvol_id = BTRFS_FIRST_FREE_OBJECTID;

static inline struct inode_entry *rootdir_path_last(struct rootdir_path *path)
Expand Down Expand Up @@ -435,6 +436,9 @@ static int ftw_add_subvol(const char *full_path, const struct stat *st,
return ret;
}

if (s->is_default)
*g_default_subvol_id = subvol_id;

key.objectid = subvol_id;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
Expand Down Expand Up @@ -697,7 +701,8 @@ static int ftw_add_inode(const char *full_path, const struct stat *st,
};

int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
struct btrfs_root *root, struct list_head *subvols)
struct btrfs_root *root, struct list_head *subvols,
u64 *default_subvol_id)
{
int ret;
struct stat root_st;
Expand All @@ -710,6 +715,7 @@ int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir

g_trans = trans;
g_subvols = subvols;
g_default_subvol_id = default_subvol_id;
INIT_LIST_HEAD(&current_path.inode_list);

ret = nftw(source_dir, ftw_add_inode, 32, FTW_PHYS);
Expand Down Expand Up @@ -992,3 +998,53 @@ int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,
}
return ret;
}

int btrfs_set_default_subvolume(struct btrfs_fs_info *fs_info, u64 objectid)
{
struct btrfs_trans_handle *trans;
struct btrfs_path path = { 0 };
struct btrfs_dir_item *di;
struct btrfs_key location;
struct extent_buffer *leaf;
struct btrfs_disk_key disk_key;
u64 features;
int ret;

trans = btrfs_start_transaction(fs_info->tree_root, 1);
if (IS_ERR(trans))
return -PTR_ERR(trans);

di = btrfs_lookup_dir_item(trans, fs_info->tree_root, &path,
btrfs_super_root_dir(fs_info->super_copy),
"default", 7, 1);
if (!di || IS_ERR(di)) {
btrfs_release_path(&path);

if (di)
ret = PTR_ERR(di);
else
ret = -ENOENT;

btrfs_abort_transaction(trans, ret);
return ret;
}

leaf = path.nodes[0];

location.objectid = objectid;
location.type = BTRFS_ROOT_ITEM_KEY;
location.offset = 0;

btrfs_cpu_key_to_disk(&disk_key, &location);
btrfs_set_dir_item_key(leaf, di, &disk_key);

btrfs_mark_buffer_dirty(leaf);

btrfs_release_path(&path);

features = btrfs_super_incompat_flags(fs_info->super_copy);
features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL;
btrfs_set_super_incompat_flags(fs_info->super_copy, features);

return btrfs_commit_transaction(trans, fs_info->tree_root);
}
5 changes: 4 additions & 1 deletion mkfs/rootdir.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ struct rootdir_subvol {
struct list_head list;
char *dir;
char *full_path;
bool is_default;
};

int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
struct btrfs_root *root, struct list_head *subvols);
struct btrfs_root *root, struct list_head *subvols,
u64 *default_subvol_id);
u64 btrfs_mkfs_size_dir(const char *dir_name, u32 sectorsize, u64 min_dev_size,
u64 meta_profile, u64 data_profile);
int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,
bool shrink_file_size);
int btrfs_set_default_subvolume(struct btrfs_fs_info *fs_info, u64 objectid);

#endif

0 comments on commit e0dfe20

Please sign in to comment.