mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
repart: Add DefaultSubvolume= setting
We already have Subvolumes= to create subvolumes, let's add DefaultSubvolume= as well to set the default subvolume.
This commit is contained in:
committed by
Luca Boccassi
parent
e50bfc89ce
commit
3799fa803e
@@ -551,6 +551,22 @@
|
||||
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>DefaultSubvolume=</varname></term>
|
||||
|
||||
<listitem><para>Takes an absolute path specifying the default subvolume within the new filesystem.
|
||||
Note that this setting does not create the subvolume itself, that can be configured with
|
||||
<varname>Subvolumes=</varname>.</para>
|
||||
|
||||
<para>Note that this option only takes effect if the target filesystem supports subvolumes, such as
|
||||
<literal>btrfs</literal>.</para>
|
||||
|
||||
<para>Note that due to limitations of <literal>mkfs.btrfs</literal>, this option is only supported
|
||||
when running with <option>--offline=no</option>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Encrypt=</varname></term>
|
||||
|
||||
|
||||
@@ -300,6 +300,7 @@ typedef struct Partition {
|
||||
char **exclude_files_target;
|
||||
char **make_directories;
|
||||
char **subvolumes;
|
||||
char *default_subvolume;
|
||||
EncryptMode encrypt;
|
||||
VerityMode verity;
|
||||
char *verity_match_key;
|
||||
@@ -1668,6 +1669,41 @@ static int config_parse_make_dirs(
|
||||
}
|
||||
}
|
||||
|
||||
static int config_parse_default_subvolume(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
char **subvol = ASSERT_PTR(data);
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*subvol = mfree(*subvol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &p);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to expand specifiers in DefaultSubvolume= parameter, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
return free_and_replace(*subvol, p);
|
||||
}
|
||||
|
||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_encrypt, encrypt_mode, EncryptMode, ENCRYPT_OFF, "Invalid encryption mode");
|
||||
|
||||
static int config_parse_gpt_flags(
|
||||
@@ -1861,37 +1897,38 @@ static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mod
|
||||
static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
|
||||
|
||||
ConfigTableItem table[] = {
|
||||
{ "Partition", "Type", config_parse_type, 0, &p->type },
|
||||
{ "Partition", "Label", config_parse_label, 0, &p->new_label },
|
||||
{ "Partition", "UUID", config_parse_uuid, 0, p },
|
||||
{ "Partition", "Priority", config_parse_int32, 0, &p->priority },
|
||||
{ "Partition", "Weight", config_parse_weight, 0, &p->weight },
|
||||
{ "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
|
||||
{ "Partition", "SizeMinBytes", config_parse_size4096, -1, &p->size_min },
|
||||
{ "Partition", "SizeMaxBytes", config_parse_size4096, 1, &p->size_max },
|
||||
{ "Partition", "PaddingMinBytes", config_parse_size4096, -1, &p->padding_min },
|
||||
{ "Partition", "PaddingMaxBytes", config_parse_size4096, 1, &p->padding_max },
|
||||
{ "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
|
||||
{ "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
|
||||
{ "Partition", "Format", config_parse_fstype, 0, &p->format },
|
||||
{ "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
|
||||
{ "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
|
||||
{ "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
|
||||
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, &p->make_directories },
|
||||
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
|
||||
{ "Partition", "Verity", config_parse_verity, 0, &p->verity },
|
||||
{ "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
|
||||
{ "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
|
||||
{ "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
|
||||
{ "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
|
||||
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
|
||||
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
|
||||
{ "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
|
||||
{ "Partition", "Subvolumes", config_parse_make_dirs, 0, &p->subvolumes },
|
||||
{ "Partition", "VerityDataBlockSizeBytes", config_parse_block_size, 0, &p->verity_data_block_size },
|
||||
{ "Partition", "VerityHashBlockSizeBytes", config_parse_block_size, 0, &p->verity_hash_block_size },
|
||||
{ "Partition", "MountPoint", config_parse_mountpoint, 0, p },
|
||||
{ "Partition", "EncryptedVolume", config_parse_encrypted_volume, 0, p },
|
||||
{ "Partition", "Type", config_parse_type, 0, &p->type },
|
||||
{ "Partition", "Label", config_parse_label, 0, &p->new_label },
|
||||
{ "Partition", "UUID", config_parse_uuid, 0, p },
|
||||
{ "Partition", "Priority", config_parse_int32, 0, &p->priority },
|
||||
{ "Partition", "Weight", config_parse_weight, 0, &p->weight },
|
||||
{ "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
|
||||
{ "Partition", "SizeMinBytes", config_parse_size4096, -1, &p->size_min },
|
||||
{ "Partition", "SizeMaxBytes", config_parse_size4096, 1, &p->size_max },
|
||||
{ "Partition", "PaddingMinBytes", config_parse_size4096, -1, &p->padding_min },
|
||||
{ "Partition", "PaddingMaxBytes", config_parse_size4096, 1, &p->padding_max },
|
||||
{ "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
|
||||
{ "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
|
||||
{ "Partition", "Format", config_parse_fstype, 0, &p->format },
|
||||
{ "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
|
||||
{ "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
|
||||
{ "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
|
||||
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, &p->make_directories },
|
||||
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
|
||||
{ "Partition", "Verity", config_parse_verity, 0, &p->verity },
|
||||
{ "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
|
||||
{ "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
|
||||
{ "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
|
||||
{ "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
|
||||
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
|
||||
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
|
||||
{ "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
|
||||
{ "Partition", "Subvolumes", config_parse_make_dirs, 0, &p->subvolumes },
|
||||
{ "Partition", "DefaultSubvolume", config_parse_default_subvolume, 0, &p->default_subvolume },
|
||||
{ "Partition", "VerityDataBlockSizeBytes", config_parse_block_size, 0, &p->verity_data_block_size },
|
||||
{ "Partition", "VerityHashBlockSizeBytes", config_parse_block_size, 0, &p->verity_hash_block_size },
|
||||
{ "Partition", "MountPoint", config_parse_mountpoint, 0, p },
|
||||
{ "Partition", "EncryptedVolume", config_parse_encrypted_volume, 0, p },
|
||||
{}
|
||||
};
|
||||
int r;
|
||||
@@ -2018,6 +2055,14 @@ static int partition_read_definition(Partition *p, const char *path, const char
|
||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Subvolumes= cannot be used with --offline=yes");
|
||||
|
||||
if (p->default_subvolume && arg_offline > 0)
|
||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"DefaultSubvolume= cannot be used with --offline=yes");
|
||||
|
||||
if (p->default_subvolume && !path_strv_contains(p->subvolumes, p->default_subvolume))
|
||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
|
||||
"DefaultSubvolume= must be one of the paths in Subvolumes=");
|
||||
|
||||
/* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
|
||||
if ((IN_SET(p->type.designator,
|
||||
PARTITION_ROOT_VERITY,
|
||||
@@ -3736,6 +3781,11 @@ static int prepare_temporary_file(PartitionTarget *t, uint64_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool loop_device_error_is_fatal(const Partition *p, int r) {
|
||||
assert(p);
|
||||
return arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes) || p->default_subvolume;
|
||||
}
|
||||
|
||||
static int partition_target_prepare(
|
||||
Context *context,
|
||||
Partition *p,
|
||||
@@ -3775,7 +3825,7 @@ static int partition_target_prepare(
|
||||
|
||||
if (arg_offline <= 0) {
|
||||
r = loop_device_make(whole_fd, O_RDWR, p->offset, size, context->sector_size, 0, LOCK_EX, &d);
|
||||
if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
|
||||
if (r < 0 && loop_device_error_is_fatal(p, r))
|
||||
return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
|
||||
if (r >= 0) {
|
||||
t->loop = TAKE_PTR(d);
|
||||
@@ -4878,6 +4928,27 @@ static int do_make_directories(Partition *p, const char *root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_default_subvolume(Partition *p, const char *root) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(root);
|
||||
|
||||
if (!p->default_subvolume)
|
||||
return 0;
|
||||
|
||||
path = path_join(root, p->default_subvolume);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
r = btrfs_subvol_make_default(path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make '%s' the default subvolume: %m", p->default_subvolume);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool partition_needs_populate(Partition *p) {
|
||||
assert(p);
|
||||
return !strv_isempty(p->copy_files) || !strv_isempty(p->make_directories);
|
||||
@@ -4952,6 +5023,9 @@ static int partition_populate_filesystem(Context *context, Partition *p, const c
|
||||
if (do_make_directories(p, fs) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
if (set_default_subvolume(p, fs) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = syncfs_path(AT_FDCWD, fs);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to synchronize written files: %m");
|
||||
@@ -6547,7 +6621,7 @@ static int context_minimize(Context *context) {
|
||||
|
||||
if (arg_offline <= 0) {
|
||||
r = loop_device_make(fd, O_RDWR, 0, UINT64_MAX, context->sector_size, 0, LOCK_EX, &d);
|
||||
if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
|
||||
if (r < 0 && loop_device_error_is_fatal(p, r))
|
||||
return log_error_errno(r, "Failed to make loopback device of %s: %m", temp);
|
||||
}
|
||||
|
||||
|
||||
@@ -1785,6 +1785,24 @@ int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_i
|
||||
return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup);
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_default(const char *path) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
uint64_t id;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
fd = open(path, O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = btrfs_subvol_get_id_fd(fd, &id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return RET_NERRNO(ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &id));
|
||||
}
|
||||
|
||||
int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
|
||||
|
||||
struct btrfs_ioctl_search_args args = {
|
||||
|
||||
@@ -108,6 +108,8 @@ int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t
|
||||
int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup);
|
||||
int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup);
|
||||
|
||||
int btrfs_subvol_make_default(const char *path);
|
||||
|
||||
int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret);
|
||||
int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user