Skip to content

Commit 91a4311

Browse files
maharmstoneadam900710
authored andcommitted
btrfs-progs: mkfs: add default flag to --subvol
Change --subvol that it can accept flags, and add a "default" flag that allows you to mark a subvolume as the default. Signed-off-by: Mark Harmstone <maharmstone@fb.com>
1 parent 2688073 commit 91a4311

File tree

4 files changed

+137
-5
lines changed

4 files changed

+137
-5
lines changed

Documentation/mkfs.btrfs.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,15 @@ OPTIONS
155155
contain the files from *rootdir*. Since version 4.14.1 the filesystem size is
156156
not minimized. Please see option *--shrink* if you need that functionality.
157157

158-
-u|--subvol <subdir>
158+
-u|--subvol <subdir>:<flags>
159159
Specify that *subdir* is to be created as a subvolume rather than a regular
160160
directory. The option *--rootdir* must also be specified, and *subdir* must be an
161161
existing subdirectory within it. This option can be specified multiple times.
162162

163+
*flags* is an optional comma-separated list of modifiers. Valid choices are:
164+
165+
* *default*: create as default subvolume (this can only be specified once)
166+
163167
--shrink
164168
Shrink the filesystem to its minimal size, only works with *--rootdir* option.
165169

mkfs/main.c

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ static const char * const mkfs_usage[] = {
440440
"Creation:",
441441
OPTLINE("-b|--byte-count SIZE", "set size of each device to SIZE (filesystem size is sum of all device sizes)"),
442442
OPTLINE("-r|--rootdir DIR", "copy files from DIR to the image root directory"),
443-
OPTLINE("-u|--subvol SUBDIR", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
443+
OPTLINE("-u|--subvol SUBDIR:FLAGS", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
444444
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
445445
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
446446
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
@@ -1015,6 +1015,46 @@ static void *prepare_one_device(void *ctx)
10151015
return NULL;
10161016
}
10171017

1018+
static int parse_subvol_flags(struct rootdir_subvol *subvol, const char *flags)
1019+
{
1020+
char *buf, *orig_buf;
1021+
int ret;
1022+
1023+
buf = orig_buf = strdup(flags);
1024+
1025+
if (!buf) {
1026+
error_msg(ERROR_MSG_MEMORY, NULL);
1027+
ret = -ENOMEM;
1028+
goto out;
1029+
}
1030+
1031+
while (true) {
1032+
char *comma = strstr(buf, ",");
1033+
1034+
if (comma)
1035+
*comma = 0;
1036+
1037+
if (!strcmp(buf, "default")) {
1038+
subvol->is_default = true;
1039+
} else if (buf[0] != 0) {
1040+
error("unrecognized subvol flag \"%s\"", buf);
1041+
ret = 1;
1042+
goto out;
1043+
}
1044+
1045+
if (comma)
1046+
buf = comma + 1;
1047+
else
1048+
break;
1049+
}
1050+
1051+
ret = 0;
1052+
1053+
out:
1054+
free(orig_buf);
1055+
return ret;
1056+
}
1057+
10181058
int BOX_MAIN(mkfs)(int argc, char **argv)
10191059
{
10201060
char *file;
@@ -1058,6 +1098,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
10581098
char *source_dir = NULL;
10591099
size_t source_dir_len = 0;
10601100
struct rootdir_subvol *rds;
1101+
bool has_default_subvol = false;
10611102
LIST_HEAD(subvols);
10621103

10631104
cpu_detect_flags();
@@ -1215,16 +1256,49 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
12151256
break;
12161257
case 'u': {
12171258
struct rootdir_subvol *subvol;
1259+
char *colon;
12181260

1219-
subvol = malloc(sizeof(struct rootdir_subvol));
1261+
subvol = calloc(1, sizeof(struct rootdir_subvol));
12201262
if (!subvol) {
12211263
error_msg(ERROR_MSG_MEMORY, NULL);
12221264
ret = 1;
12231265
goto error;
12241266
}
12251267

1226-
subvol->dir = strdup(optarg);
1227-
subvol->full_path = NULL;
1268+
colon = strstr(optarg, ":");
1269+
1270+
if (colon) {
1271+
/* Make sure we choose the last colon in
1272+
* optarg, in case the subvol name
1273+
* itself contains a colon. */
1274+
do {
1275+
char *colon2;
1276+
1277+
colon2 = strstr(colon + 1, ":");
1278+
1279+
if (colon2)
1280+
colon = colon2;
1281+
else
1282+
break;
1283+
} while (true);
1284+
1285+
subvol->dir = strndup(optarg, colon - optarg);
1286+
if (parse_subvol_flags(subvol, colon + 1)) {
1287+
ret = 1;
1288+
goto error;
1289+
}
1290+
} else {
1291+
subvol->dir = strdup(optarg);
1292+
}
1293+
1294+
if (subvol->is_default) {
1295+
if (has_default_subvol) {
1296+
error("subvol default flag can only be specified once");
1297+
ret = 1;
1298+
goto error;
1299+
}
1300+
has_default_subvol = true;
1301+
}
12281302

12291303
list_add_tail(&subvol->list, &subvols);
12301304
break;

mkfs/rootdir.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static u64 g_hardlink_count;
9999
static struct btrfs_trans_handle *g_trans = NULL;
100100
static struct list_head *g_subvols;
101101
static u64 next_subvol_id = BTRFS_FIRST_FREE_OBJECTID;
102+
static u64 default_subvol_id;
102103

103104
static inline struct inode_entry *rootdir_path_last(struct rootdir_path *path)
104105
{
@@ -436,6 +437,9 @@ static int ftw_add_subvol(const char *full_path, const struct stat *st,
436437
return ret;
437438
}
438439

440+
if (subvol->is_default)
441+
default_subvol_id = subvol_id;
442+
439443
key.objectid = subvol_id;
440444
key.type = BTRFS_ROOT_ITEM_KEY;
441445
key.offset = (u64)-1;
@@ -701,6 +705,47 @@ static int ftw_add_inode(const char *full_path, const struct stat *st,
701705
return 0;
702706
};
703707

708+
static int set_default_subvolume(struct btrfs_trans_handle *trans)
709+
{
710+
struct btrfs_path path = { 0 };
711+
struct btrfs_dir_item *di;
712+
struct btrfs_key location;
713+
struct extent_buffer *leaf;
714+
struct btrfs_disk_key disk_key;
715+
u64 features;
716+
717+
di = btrfs_lookup_dir_item(trans, trans->fs_info->tree_root, &path,
718+
btrfs_super_root_dir(trans->fs_info->super_copy),
719+
"default", 7, 1);
720+
if (IS_ERR_OR_NULL(di)) {
721+
btrfs_release_path(&path);
722+
723+
if (di)
724+
return PTR_ERR(di);
725+
else
726+
return -ENOENT;
727+
}
728+
729+
leaf = path.nodes[0];
730+
731+
location.objectid = default_subvol_id;
732+
location.type = BTRFS_ROOT_ITEM_KEY;
733+
location.offset = 0;
734+
735+
btrfs_cpu_key_to_disk(&disk_key, &location);
736+
btrfs_set_dir_item_key(leaf, di, &disk_key);
737+
738+
btrfs_mark_buffer_dirty(leaf);
739+
740+
btrfs_release_path(&path);
741+
742+
features = btrfs_super_incompat_flags(trans->fs_info->super_copy);
743+
features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL;
744+
btrfs_set_super_incompat_flags(trans->fs_info->super_copy, features);
745+
746+
return 0;
747+
}
748+
704749
int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
705750
struct btrfs_root *root, struct list_head *subvols)
706751
{
@@ -732,6 +777,14 @@ int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir
732777
while (current_path.level > 0)
733778
rootdir_path_pop(&current_path);
734779

780+
if (default_subvol_id != 0) {
781+
ret = set_default_subvolume(trans);
782+
if (ret < 0) {
783+
error("error setting default subvolume: %d", ret);
784+
return ret;
785+
}
786+
}
787+
735788
return 0;
736789
}
737790

mkfs/rootdir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct rootdir_subvol {
3232
struct list_head list;
3333
char *dir;
3434
char *full_path;
35+
bool is_default;
3536
};
3637

3738
int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,

0 commit comments

Comments
 (0)