1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-24 14:50:17 +03:00

core/mount: rework GracefulOptions= as x-systemd.graceful-option= (#36356)

Prompted by #36337
This commit is contained in:
Yu Watanabe 2025-02-14 13:01:14 +09:00 committed by GitHub
commit 4053af87bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 121 additions and 187 deletions

View File

@ -7048,10 +7048,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b ReadWriteOnly = ...;
readonly s Result = '...';
readonly s ReloadResult = '...';
readonly s CleanResult = '...';
readonly u UID = ...;
readonly u GID = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as GracefulOptions = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
readonly a(sasbttttuii) ExecMount = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
@ -7652,12 +7652,14 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<!--property ReadWriteOnly is not documented!-->
<!--property ReloadResult is not documented!-->
<!--property CleanResult is not documented!-->
<!--property UID is not documented!-->
<!--property GID is not documented!-->
<!--property GracefulOptions is not documented!-->
<!--property ExecUnmount is not documented!-->
<!--property ExecRemount is not documented!-->
@ -8200,12 +8202,14 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<variablelist class="dbus-property" generated="True" extra-ref="Result"/>
<variablelist class="dbus-property" generated="True" extra-ref="ReloadResult"/>
<variablelist class="dbus-property" generated="True" extra-ref="CleanResult"/>
<variablelist class="dbus-property" generated="True" extra-ref="UID"/>
<variablelist class="dbus-property" generated="True" extra-ref="GID"/>
<variablelist class="dbus-property" generated="True" extra-ref="GracefulOptions"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMount"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecUnmount"/>
@ -12462,8 +12466,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>ProtectControlGroupsEx</varname>, and
<varname>PrivatePIDs</varname> were added in version 257.</para>
<para><varname>ProtectHostnameEx</varname>,
<function>RemoveSubgroup()</function>, and
<varname>GracefulOptions</varname> were added in version 258.</para>
<function>RemoveSubgroup()</function>,
<varname>ReloadResult</varname>, and
<varname>CleanResult</varname> were added in version 258.</para>
</refsect2>
<refsect2>
<title>Swap Unit Objects</title>

View File

@ -284,6 +284,19 @@
<xi:include href="version-info.xml" xpointer="v220"/></listitem>
</varlistentry>
<varlistentry>
<term><option>x-systemd.graceful-option=</option></term>
<listitem><para>Additional mount option that shall be appended if supported by the kernel.
This may be used to configure mount options that are optional and only enabled on kernels that
support them. Note that this is supported only for native kernel mount options (i.e. explicitly not
for mount options implemented in userspace, such as those processed by
<command>/usr/bin/mount</command> itself, by FUSE or by mount helpers such as
<command>mount.nfs</command>). This option may be specified more than once.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><option>x-systemd.device-bound=</option></term>
@ -650,22 +663,6 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>GracefulOptions=</varname></term>
<listitem><para>Additional mount options that shall be appended to <varname>Options=</varname> if
supported by the kernel. This may be used to configure mount options that are optional and only
enabled on kernels that support them. Note that this is supported only for native kernel mount
options (i.e. explicitly not for mount options implemented in userspace, such as those processed by
<command>/usr/bin/mount</command> itself, by FUSE or by mount helpers such as
<command>mount.nfs</command>).</para>
<para>May be specified multiple times. If specified multiple times, all listed, supported mount
options are combined. If an empty string is assigned, the list is reset.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
<xi:include href="systemd.service.xml" xpointer="shared-unit-options" />

View File

@ -797,14 +797,10 @@ int mount_option_supported(const char *fstype, const char *key, const char *valu
assert(key);
fd = fsopen(fstype, FSOPEN_CLOEXEC);
if (fd < 0) {
if (ERRNO_IS_NOT_SUPPORTED(errno))
return -EAGAIN; /* new mount API not available → don't know */
if (fd < 0)
return log_debug_errno(errno, "Failed to open superblock context for '%s': %m", fstype);
}
/* Various file systems have not been converted to the new mount API yet. For such file systems
/* Various file systems support fs context only in recent kernels (e.g. btrfs). For older kernels
* fsconfig() with FSCONFIG_SET_STRING/FSCONFIG_SET_FLAG never fail. Which sucks, because we want to
* use it for testing support, after all. Let's hence do a check if the file system got converted yet
* first. */
@ -813,9 +809,9 @@ int mount_option_supported(const char *fstype, const char *key, const char *valu
* the new mount API yet. If it returns EINVAL the mount option doesn't exist, but the fstype
* is converted. */
if (errno == EOPNOTSUPP)
return -EAGAIN; /* FSCONFIG_SET_FD not supported on the fs, hence not converted to new mount API → don't know */
return -EAGAIN; /* fs not converted to new mount API → don't know */
if (errno != EINVAL)
return log_debug_errno(errno, "Failed to check if file system has been converted to new mount API: %m");
return log_debug_errno(errno, "Failed to check if file system '%s' has been converted to new mount API: %m", fstype);
/* So FSCONFIG_SET_FD worked, but the option didn't exist (we got EINVAL), this means the fs
* is converted. Let's now ask the actual question we wonder about. */

View File

@ -73,9 +73,11 @@ const sd_bus_vtable bus_mount_vtable[] = {
SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReadWriteOnly", "b", bus_property_get_bool, offsetof(Mount, read_write_only), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ReloadResult", "s", property_get_result, offsetof(Mount, reload_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CleanResult", "s", property_get_result, offsetof(Mount, clean_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("GracefulOptions", "as", NULL, offsetof(Mount, graceful_options), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_VTABLE("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@ -151,30 +153,6 @@ static int bus_mount_set_transient_property(
if (streq(name, "ReadWriteOnly"))
return bus_set_transient_bool(u, name, &m->read_write_only, message, flags, error);
if (streq(name, "GracefulOptions")) {
_cleanup_strv_free_ char **add = NULL;
r = sd_bus_message_read_strv(message, &add);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (strv_isempty(add)) {
m->graceful_options = strv_free(m->graceful_options);
unit_write_settingf(u, flags, name, "GracefulOptions=");
} else {
r = strv_extend_strv(&m->graceful_options, add, /* filter_duplicates= */ false);
if (r < 0)
return r;
STRV_FOREACH(a, add)
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "GracefulOptions=%s", *a);
}
}
return 1;
}
return 0;
}

View File

@ -393,10 +393,10 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("MountImage",
SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir, "a(ss)", options),
SD_BUS_NO_RESULT,
bus_service_method_mount_image,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir, "a(ss)", options),
SD_BUS_NO_RESULT,
bus_service_method_mount_image,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("DumpFileDescriptorStore",
SD_BUS_NO_ARGS,

View File

@ -549,7 +549,6 @@ Mount.SloppyOptions, config_parse_bool,
Mount.LazyUnmount, config_parse_bool, 0, offsetof(Mount, lazy_unmount)
Mount.ForceUnmount, config_parse_bool, 0, offsetof(Mount, force_unmount)
Mount.ReadWriteOnly, config_parse_bool, 0, offsetof(Mount, read_write_only)
Mount.GracefulOptions, config_parse_mount_graceful_options, 0, offsetof(Mount, graceful_options)
{{ EXEC_CONTEXT_CONFIG_ITEMS('Mount') }}
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Mount') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Mount') }}

View File

@ -6131,51 +6131,6 @@ int config_parse_mount_node(
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, path, data, userdata);
}
int config_parse_mount_graceful_options(
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) {
const Unit *u = ASSERT_PTR(userdata);
char ***sv = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*sv = strv_free(*sv);
return 1;
}
_cleanup_free_ char *resolved = NULL;
r = unit_full_printf(u, rvalue, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
_cleanup_strv_free_ char **strv = NULL;
r = strv_split_full(&strv, resolved, ",", EXTRACT_RETAIN_ESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ false);
if (r < 0)
return log_oom();
return 1;
}
static int merge_by_names(Unit *u, Set *names, const char *id) {
char *k;
int r;

View File

@ -165,7 +165,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_open_file);
CONFIG_PARSER_PROTOTYPE(config_parse_memory_pressure_watch);
CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
CONFIG_PARSER_PROTOTYPE(config_parse_mount_node);
CONFIG_PARSER_PROTOTYPE(config_parse_mount_graceful_options);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);

View File

@ -45,9 +45,9 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
[MOUNT_MOUNTING_DONE] = UNIT_ACTIVATING,
[MOUNT_MOUNTED] = UNIT_ACTIVE,
[MOUNT_REMOUNTING] = UNIT_RELOADING,
[MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
[MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
[MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
[MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
[MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
[MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
[MOUNT_FAILED] = UNIT_FAILED,
@ -231,8 +231,6 @@ static void mount_done(Unit *u) {
mount_unwatch_control_pid(m);
m->timer_event_source = sd_event_source_disable_unref(m->timer_event_source);
m->graceful_options = strv_free(m->graceful_options);
}
static int update_parameters_proc_self_mountinfo(
@ -1056,6 +1054,8 @@ static void mount_enter_unmounting(Mount *m) {
MOUNT_UNMOUNTING_SIGKILL))
m->n_retry_umount = 0;
mount_unwatch_control_pid(m);
m->control_command_id = MOUNT_EXEC_UNMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
@ -1065,8 +1065,6 @@ static void mount_enter_unmounting(Mount *m) {
goto fail;
}
mount_unwatch_control_pid(m);
r = mount_spawn(m, m->control_command, mount_exec_flags(MOUNT_UNMOUNTING), &m->control_pid);
if (r < 0) {
log_unit_warning_errno(UNIT(m), r, "Failed to spawn 'umount' task: %m");
@ -1074,29 +1072,31 @@ static void mount_enter_unmounting(Mount *m) {
}
mount_set_state(m, MOUNT_UNMOUNTING);
return;
fail:
mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES, /* flush_result = */ false);
}
static int mount_append_graceful_options(Mount *m, const MountParameters *p, char **opts) {
static int mount_apply_graceful_options(Mount *m, const MountParameters *p, char **opts) {
_cleanup_strv_free_ char **graceful = NULL;
_cleanup_free_ char *filtered = NULL;
int r;
assert(m);
assert(p);
assert(opts);
if (strv_isempty(m->graceful_options))
return 0;
r = fstab_filter_options(*opts, "x-systemd.graceful-option\0", NULL, NULL, &graceful, &filtered);
if (r <= 0)
return r;
if (!p->fstype) {
log_unit_warning(UNIT(m), "GracefulOptions= used but file system type not known, suppressing all graceful options.");
log_unit_warning(UNIT(m), "x-systemd.graceful-option= used but file system type not known, suppressing all graceful options.");
return 0;
}
STRV_FOREACH(o, m->graceful_options) {
STRV_FOREACH(o, graceful) {
_cleanup_free_ char *k = NULL, *v = NULL;
r = split_pair(*o, "=", &k, &v);
@ -1104,22 +1104,29 @@ static int mount_append_graceful_options(Mount *m, const MountParameters *p, cha
return r;
r = mount_option_supported(p->fstype, k ?: *o, v);
if (r == -EAGAIN) {
log_unit_warning_errno(UNIT(m), r,
"x-systemd.graceful-option= used but not supported by file system %s, suppressing all.",
p->fstype);
break;
}
if (r < 0)
log_unit_warning_errno(UNIT(m), r, "GracefulOptions=%s specified, but cannot determine availability, suppressing.", *o);
log_unit_warning_errno(UNIT(m), r,
"x-systemd.graceful-option=%s specified, but cannot determine availability, suppressing: %m", *o);
else if (r == 0)
log_unit_info(UNIT(m), "GracefulOptions=%s specified, but option is not available, suppressing.", *o);
log_unit_info(UNIT(m), "x-systemd.graceful-option=%s specified, but option is not available, suppressing.", *o);
else {
log_unit_debug(UNIT(m), "GracefulOptions=%s specified and supported, appending to mount option string.", *o);
log_unit_debug(UNIT(m), "x-systemd.graceful-option=%s specified and supported, appending to mount option string.", *o);
if (!strextend_with_separator(opts, ",", *o))
if (!strextend_with_separator(&filtered, ",", *o))
return -ENOMEM;
}
}
return 0;
return free_and_replace(*opts, filtered);
}
static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParameters *p) {
static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParameters *p, bool remount) {
int r;
assert(m);
@ -1149,14 +1156,23 @@ static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParamete
}
_cleanup_free_ char *opts = NULL;
r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts);
r = fstab_filter_options(p->options, "nofail\0" "fail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts);
if (r < 0)
return r;
r = mount_append_graceful_options(m, p, &opts);
r = mount_apply_graceful_options(m, p, &opts);
if (r < 0)
return r;
if (remount) {
if (isempty(opts)) {
opts = strdup("remount");
if (!opts)
return -ENOMEM;
} else if (!strprepend(&opts, "remount,"))
return -ENOMEM;
}
if (!isempty(opts)) {
r = exec_command_append(c, "-o", opts, NULL);
if (r < 0)
@ -1178,7 +1194,12 @@ static void mount_enter_mounting(Mount *m) {
goto fail;
p = get_mount_parameters_fragment(m);
if (p && mount_is_bind(p)) {
if (!p) {
r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
goto fail;
}
if (mount_is_bind(p)) {
r = is_dir(p->what, /* follow = */ true);
if (r < 0 && r != -ENOENT)
log_unit_info_errno(UNIT(m), r, "Failed to determine type of bind mount source '%s', ignoring: %m", p->what);
@ -1194,7 +1215,7 @@ static void mount_enter_mounting(Mount *m) {
log_unit_warning_errno(UNIT(m), r, "Failed to create mount point '%s', ignoring: %m", m->where);
/* If we are asked to create an OverlayFS, create the upper/work directories if they are missing */
if (p && streq_ptr(p->fstype, "overlay")) {
if (streq_ptr(p->fstype, "overlay")) {
_cleanup_strv_free_ char **dirs = NULL;
r = fstab_filter_options(
@ -1223,13 +1244,9 @@ static void mount_enter_mounting(Mount *m) {
if (source_is_dir)
unit_warn_if_dir_nonempty(UNIT(m), m->where);
unit_warn_leftover_processes(UNIT(m), /* start = */ true);
m->control_command_id = MOUNT_EXEC_MOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
/* Create the source directory for bind-mounts if needed */
if (p && mount_is_bind(p)) {
if (mount_is_bind(p)) {
r = mkdir_p_label(p->what, m->directory_mode);
/* mkdir_p_label() can return -EEXIST if the target path exists and is not a directory - which is
* totally OK, in case the user wants us to overmount a non-directory inode. Also -EROFS can be
@ -1241,19 +1258,18 @@ static void mount_enter_mounting(Mount *m) {
r, "Failed to make bind mount source '%s', ignoring: %m", p->what);
}
if (p) {
r = mount_set_mount_command(m, m->control_command, p);
if (r < 0) {
log_unit_warning_errno(UNIT(m), r, "Failed to prepare mount command line: %m");
goto fail;
}
} else {
r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
mount_unwatch_control_pid(m);
unit_warn_leftover_processes(UNIT(m), /* start = */ true);
m->control_command_id = MOUNT_EXEC_MOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
r = mount_set_mount_command(m, m->control_command, p, /* remount = */ false);
if (r < 0) {
log_unit_error_errno(UNIT(m), r, "Failed to prepare mount command line: %m");
goto fail;
}
mount_unwatch_control_pid(m);
r = mount_spawn(m, m->control_command, mount_exec_flags(MOUNT_MOUNTING), &m->control_pid);
if (r < 0) {
log_unit_warning_errno(UNIT(m), r, "Failed to spawn 'mount' task: %m");
@ -1283,41 +1299,23 @@ static void mount_enter_remounting(Mount *m) {
assert(m);
/* Reset reload result when we are about to start a new remount operation */
m->reload_result = MOUNT_SUCCESS;
m->control_command_id = MOUNT_EXEC_REMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
p = get_mount_parameters_fragment(m);
if (p) {
const char *o;
if (p->options)
o = strjoina("remount,", p->options);
else
o = "remount";
r = exec_command_set(m->control_command, MOUNT_PATH,
p->what, m->where,
"-o", o, NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
if (r >= 0 && m->read_write_only)
r = exec_command_append(m->control_command, "-w", NULL);
if (r >= 0 && p->fstype)
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
if (r < 0) {
log_unit_warning_errno(UNIT(m), r, "Failed to prepare remount command line: %m");
goto fail;
}
} else {
if (!p) {
r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
goto fail;
}
mount_unwatch_control_pid(m);
m->reload_result = MOUNT_SUCCESS;
m->control_command_id = MOUNT_EXEC_REMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
r = mount_set_mount_command(m, m->control_command, p, /* remount = */ true);
if (r < 0) {
log_unit_error_errno(UNIT(m), r, "Failed to prepare remount command line: %m");
goto fail;
}
r = mount_spawn(m, m->control_command, mount_exec_flags(MOUNT_REMOUNTING), &m->control_pid);
if (r < 0) {
@ -1427,6 +1425,12 @@ static int mount_reload(Unit *u) {
return 1;
}
static bool mount_can_reload(Unit *u) {
Mount *m = ASSERT_PTR(MOUNT(u));
return get_mount_parameters_fragment(m);
}
static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
Mount *m = ASSERT_PTR(MOUNT(u));
@ -2364,6 +2368,9 @@ static int mount_can_start(Unit *u) {
return r;
}
if (!get_mount_parameters_fragment(m))
return -ENOENT;
return 1;
}
@ -2478,7 +2485,9 @@ const UnitVTable mount_vtable = {
.start = mount_start,
.stop = mount_stop,
.reload = mount_reload,
.can_reload = mount_can_reload,
.clean = mount_clean,
.can_clean = mount_can_clean,

View File

@ -81,15 +81,13 @@ struct Mount {
MountState state, deserialized_state;
ExecCommand* control_command;
ExecCommand *control_command;
MountExecCommand control_command_id;
PidRef control_pid;
sd_event_source *timer_event_source;
unsigned n_retry_umount;
char **graceful_options;
};
extern const UnitVTable mount_vtable;

View File

@ -148,9 +148,11 @@ static int bus_append_string(sd_bus_message *m, const char *field, const char *e
}
static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
const char *p;
int r;
assert(m);
assert(field);
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return bus_log_create_error(r);
@ -167,16 +169,16 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq,
if (r < 0)
return bus_log_create_error(r);
for (p = eq;;) {
for (const char *p = eq;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, separator, flags);
if (r == 0)
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Invalid syntax: %s", eq);
if (r == 0)
break;
r = sd_bus_message_append_basic(m, 's', word);
if (r < 0)
@ -2333,9 +2335,6 @@ static int bus_append_mount_property(sd_bus_message *m, const char *field, const
"ReadwriteOnly"))
return bus_append_parse_boolean(m, field, eq);
if (streq(field, "GracefulOptions"))
return bus_append_strv(m, field, eq, /* separator= */ ",", 0);
return 0;
}

View File

@ -181,9 +181,9 @@ touch "$WORK_DIR/mnt/hello"
[[ "$(stat -c "%U:%G" "$WORK_DIR/mnt/hello")" == "testuser:testuser" ]]
systemd-umount LABEL=owner-vfat
# Mkae sure that graceful mount options work
# Make sure that graceful mount options work
GRACEFULTEST="/tmp/graceful/$RANDOM"
systemd-mount --tmpfs -p GracefulOptions=idefinitelydontexist,nr_inodes=4711,idonexisteither "$GRACEFULTEST"
systemd-mount --tmpfs --options="x-systemd.graceful-option=idefinitelydontexist,x-systemd.graceful-option=nr_inodes=4711,x-systemd.graceful-option=idonexisteither" "$GRACEFULTEST"
findmnt -n -o options "$GRACEFULTEST"
findmnt -n -o options "$GRACEFULTEST" | grep -q nr_inodes=4711
umount "$GRACEFULTEST"

View File

@ -22,5 +22,4 @@ After=swap.target
What=tmpfs
Where=/tmp
Type=tmpfs
Options=mode=1777,strictatime,nosuid,nodev,size=50%%,nr_inodes=1m
GracefulOptions=usrquota
Options=mode=1777,strictatime,nosuid,nodev,size=50%%,nr_inodes=1m,x-systemd.graceful-option=usrquota