settings: support setting a connection as volatile via Update2()

Extend the Update2 flags to allow marking a connection as volatile.
Making a connection as volatile means that the connection stays alive
as long as an active connection references it.

It is correct that Update2() returns before the connection is actually
deleted. It might take an arbitrary long time until the volatile
mechanism cleans up the connection.

Also add two more IN_MEMORY flags: "detached" and "only".

The existing NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY would not detach nor
delete the possible file on disk. That is, the mode only changes what NM
thinks is the current content of the connection profile. It would not delete
the file on disk nor would it detach the profile in-memory from the file.
As such, later persisting the connection again to disk would overwrite
the file, and deleting the profile, would delete the file.

Now add two new IN_MEMORY modes.

NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACH is like making the connection
in-memory only, but forgetting that there might be any profile on disk.
That means, a later Delete() would not delete the file. Similarly, a
later Update2() that persists the connection again, would not overwrite
the existing file on disk, instead it would choose a new file name.

On the other hand, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY would delete
a potential file from disk right away.

It's clear that "volatile" only makes sense with either "in-memory-detached"
or "in-memory-only". That is, the file on disk should be deleted right away
(before the in-memory part is garbage collected) or the file on disk should
be forgotten.
This commit is contained in:
Thomas Haller 2017-12-01 12:56:09 +01:00
parent cfced599ca
commit 35dc6421de
4 changed files with 110 additions and 43 deletions

View file

@ -108,6 +108,9 @@
@flags: optional flags argument. Currently supported flags are:
"0x1" (to-disk),
"0x2" (in-memory),
"0x4" (in-memory-detached),
"0x8" (in-memory-only),
"0x10" (volatile),
"0x20" (block-autoconnect).
Unknown flags cause the call to fail.
@args: optional arguments dictionary, for extensibility. Currently no

View file

@ -901,6 +901,28 @@ typedef enum { /*< flags >*/
* @NM_SETTINGS_UPDATE2_FLAG_NONE: an alias for numeric zero, no flags set.
* @NM_SETTINGS_UPDATE2_FLAG_TO_DISK: to persist the connection to disk.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY: to make the connection in-memory only.
* If the connection was previously persistent, the corresponding file on disk
* is not deleted but merely the connection is decoupled from the file
* on disk. If you later delete an in-memory connection, the connection
* on disk will be deleted as well.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED: this is like @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY,
* but if the connection has a corresponding file on disk, the association between
* the connection and the file is forgotten but the file is not modified.
* The difference to %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY is if you later
* save the connection again to disk, a new file name will be chosen without
* overwriting the remaining file on disk. Also, if you delete the connection
* later, the file on disk will not be deleted.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY: this is like @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY,
* but if the connection has a corresponding file on disk, the file on
* disk will be deleted.
* @NM_SETTINGS_UPDATE2_FLAG_VOLATILE: This can be specified with either
* %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED or %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY.
* After making the connection in-memory only, the connection is marked
* as volatile. That means, if the connection is currently not active
* it will be deleted right away. Otherwise, it is marked to for deletion
* once the connection deactivates. A volatile connection cannot autoactivate
* again (because it's about to be deleted), but a manual activation will
* clear the volatile flag.
* @NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT: usually, when the connection
* has autoconnect enabled and is modified, it becomes elegible to autoconnect
* right away. Setting this flag, disables autoconnect until the connection
@ -912,6 +934,9 @@ typedef enum { /*< flags >*/
NM_SETTINGS_UPDATE2_FLAG_NONE = 0,
NM_SETTINGS_UPDATE2_FLAG_TO_DISK = (1LL << 0),
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY = (1LL << 1),
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED = (1LL << 2),
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY = (1LL << 3),
NM_SETTINGS_UPDATE2_FLAG_VOLATILE = (1LL << 4),
NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT = (1LL << 5),
} NMSettingsUpdate2Flags;

View file

@ -488,26 +488,41 @@ secrets_cleared_cb (NMSettingsConnection *self)
}
static void
set_unsaved (NMSettingsConnection *self, gboolean now_unsaved)
set_persist_mode (NMSettingsConnection *self, NMSettingsConnectionPersistMode persist_mode)
{
NMSettingsConnectionFlags flags;
NMSettingsConnectionFlags flags = NM_SETTINGS_CONNECTION_FLAGS_NONE;
const NMSettingsConnectionFlags ALL = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED
| NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED
| NM_SETTINGS_CONNECTION_FLAGS_VOLATILE;
if (NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != !!now_unsaved) {
if (now_unsaved)
flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED;
else
flags = NM_SETTINGS_CONNECTION_FLAGS_NONE;
nm_settings_connection_set_flags_full (self, ALL, flags);
if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP)
return;
switch (persist_mode) {
case NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK:
flags = NM_SETTINGS_CONNECTION_FLAGS_NONE;
break;
case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY:
case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED:
case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY:
flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED;
break;
case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED:
case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY:
flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED |
NM_SETTINGS_CONNECTION_FLAGS_VOLATILE;
break;
case NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP:
g_return_if_reached ();
}
nm_settings_connection_set_flags_full (self, ALL, flags);
}
static void
connection_changed_cb (NMSettingsConnection *self, gpointer unused)
{
set_unsaved (self, TRUE);
set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY);
_emit_updated (self, FALSE);
}
@ -515,23 +530,34 @@ static gboolean
_delete (NMSettingsConnection *self, GError **error)
{
NMSettingsConnectionClass *klass;
GError *local = NULL;
const char *filename;
nm_assert (NM_IS_SETTINGS_CONNECTION (self));
klass = NM_SETTINGS_CONNECTION_GET_CLASS (self);
if (!klass->delete) {
g_set_error (error,
g_set_error (&local,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_FAILED,
"delete not supported");
return FALSE;
goto fail;
}
if (!klass->delete (self,
error))
return FALSE;
&local))
goto fail;
nm_settings_connection_set_filename (self, NULL);
filename = nm_settings_connection_get_filename (self);
if (filename) {
_LOGD ("delete: success deleting connection (\"%s\")", filename);
nm_settings_connection_set_filename (self, NULL);
} else
_LOGT ("delete: success deleting connection (no-file)");
return TRUE;
fail:
_LOGD ("delete: failure deleting connection: %s", local->message);
g_propagate_error (error, local);
return FALSE;
}
static gboolean
@ -576,18 +602,17 @@ nm_settings_connection_update (NMSettingsConnection *self,
gboolean replaced = FALSE;
gs_free char *logmsg_change = NULL;
GError *local = NULL;
gboolean save_to_disk;
g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE);
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP) {
persist_mode = nm_settings_connection_get_unsaved (self)
? NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY
: NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
}
save_to_disk = (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK)
|| ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP
&& !nm_settings_connection_get_unsaved (self));
if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) {
if (save_to_disk) {
klass = NM_SETTINGS_CONNECTION_GET_CLASS (self);
if (!klass->commit_changes) {
g_set_error (&local,
@ -604,7 +629,7 @@ nm_settings_connection_update (NMSettingsConnection *self,
&local))
goto out;
if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) {
if (save_to_disk) {
if (!klass->commit_changes (self,
new_connection ?: NM_CONNECTION (self),
commit_reason,
@ -666,19 +691,14 @@ nm_settings_connection_update (NMSettingsConnection *self,
nm_settings_connection_recheck_visibility (self);
/* Manually emit changed signal since we disconnected the handler, but
* only update Unsaved if the caller wanted us to.
*/
switch (persist_mode) {
case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY:
set_unsaved (self, TRUE);
break;
case NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK:
set_unsaved (self, FALSE);
break;
case NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP:
break;
}
set_persist_mode (self, persist_mode);
if (NM_IN_SET (persist_mode, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY))
_delete (self, NULL);
else if (NM_IN_SET (persist_mode, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED,
NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED))
nm_settings_connection_set_filename (self, NULL);
g_signal_handlers_unblock_by_func (self, G_CALLBACK (connection_changed_cb), NULL);
@ -1700,15 +1720,23 @@ update_auth_cb (NMSettingsConnection *self,
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY))
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY;
else
else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED)) {
persist_mode = NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE)
? NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED
: NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED;
} else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY)) {
persist_mode = NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE)
? NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY
: NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY;
} else
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP;
if ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY
if ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK
|| ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP
&& nm_settings_connection_get_unsaved (self)))
log_diff_name = info->new_settings ? "update-unsaved" : "make-unsaved";
else
&& !nm_settings_connection_get_unsaved (self)))
log_diff_name = info->new_settings ? "update-settings" : "write-out-to-disk";
else
log_diff_name = info->new_settings ? "update-unsaved" : "make-unsaved";
if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)) {
nm_settings_connection_autoconnect_blocked_reason_set (self,
@ -1887,9 +1915,13 @@ impl_settings_connection_update2 (NMSettingsConnection *self,
GVariantIter iter;
const char *args_name;
const NMSettingsUpdate2Flags flags = (NMSettingsUpdate2Flags) flags_u;
const NMSettingsUpdate2Flags ALL_PERSIST_MODES = NM_SETTINGS_UPDATE2_FLAG_TO_DISK
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY;
if (NM_FLAGS_ANY (flags_u, ~((guint32) (NM_SETTINGS_UPDATE2_FLAG_TO_DISK |
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY |
if (NM_FLAGS_ANY (flags_u, ~((guint32) (ALL_PERSIST_MODES |
NM_SETTINGS_UPDATE2_FLAG_VOLATILE |
NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)))) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
@ -1898,8 +1930,11 @@ impl_settings_connection_update2 (NMSettingsConnection *self,
return;
}
if (NM_FLAGS_ALL (flags, NM_SETTINGS_UPDATE2_FLAG_TO_DISK |
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY)) {
if ( ( NM_FLAGS_ANY (flags, ALL_PERSIST_MODES)
&& !nm_utils_is_power_of_two (flags & ALL_PERSIST_MODES))
|| ( NM_FLAGS_HAS (flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE)
&& !NM_FLAGS_ANY (flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED |
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY))) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Conflicting flags");

View file

@ -139,6 +139,10 @@ typedef enum {
NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP,
NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED,
NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY,
} NMSettingsConnectionPersistMode;
gboolean nm_settings_connection_update (NMSettingsConnection *self,