vmspawn: implement io.systemd.MachineInstance.AddStorage / RemoveStorage
Wire up the runtime hotplug Varlink methods on the per-VM control
socket:
AddStorage → take fd from the link, look up the DiskType from the
'config' field, build a DriveInfo flagged
QMP_DRIVE_REMOVABLE, dispatch to
vmspawn_qmp_add_block_device(). Reply delivered async
by on_add_device_add_complete() once the guest sees
the device.
RemoveStorage → forward the user-visible name to
vmspawn_qmp_remove_block_device(); the existing
device_del / DEVICE_DELETED / blockdev-del chain
replies on the link.
Add SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT to the server flags so
clients can push storage fds across via sd_varlink_push_fd().
Maps -EEXIST → StorageExists and -EOPNOTSUPP/-EINVAL →
ConfigNotSupported in the AddStorage handler so callers see the
specific MachineInstance errors.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "log.h"
|
||||
#include "path-util.h"
|
||||
@@ -11,6 +12,7 @@
|
||||
#include "varlink-io.systemd.MachineInstance.h"
|
||||
#include "varlink-io.systemd.VirtualMachineInstance.h"
|
||||
#include "varlink-util.h"
|
||||
#include "vmspawn-bind-volume.h"
|
||||
#include "vmspawn-qmp.h"
|
||||
#include "vmspawn-varlink.h"
|
||||
|
||||
@@ -168,6 +170,77 @@ static int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_
|
||||
return qmp_execute_varlink_async(ctx, link, "query-status", /* arguments= */ NULL, on_qmp_describe_complete);
|
||||
}
|
||||
|
||||
static int vl_method_add_storage(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
VmspawnVarlinkContext *ctx = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
struct {
|
||||
int fd_index;
|
||||
const char *name;
|
||||
const char *config;
|
||||
} p = {
|
||||
.fd_index = -1,
|
||||
};
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "fileDescriptorIndex", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, voffsetof(p, fd_index), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(p, name), SD_JSON_MANDATORY },
|
||||
{ "config", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(p, config), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (machine_storage_name_split(p.name, /* ret_provider= */ NULL, /* ret_volume= */ NULL) < 0)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "name");
|
||||
|
||||
if (disk_type_from_bind_volume_config(p.config) < 0)
|
||||
return sd_varlink_error(link, "io.systemd.MachineInstance.BadConfig", NULL);
|
||||
|
||||
if (p.fd_index < 0)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "fileDescriptorIndex");
|
||||
|
||||
_cleanup_close_ int fd = sd_varlink_take_fd(link, p.fd_index);
|
||||
if (fd < 0)
|
||||
return sd_varlink_error_errno(link, fd);
|
||||
|
||||
r = vmspawn_bind_volume_attach_fd(ctx->bridge, link, TAKE_FD(fd), p.name, p.config);
|
||||
if (r == -EEXIST)
|
||||
return sd_varlink_error(link, "io.systemd.MachineInstance.StorageExists", NULL);
|
||||
if (r == -EOPNOTSUPP)
|
||||
return sd_varlink_error(link, "io.systemd.MachineInstance.ConfigNotSupported", NULL);
|
||||
if (r < 0)
|
||||
return sd_varlink_error_errno(link, r);
|
||||
|
||||
/* Async reply via on_add_device_add_complete. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl_method_remove_storage(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
VmspawnVarlinkContext *ctx = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
} p = {};
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(p, name), SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (machine_storage_name_split(p.name, /* ret_provider= */ NULL, /* ret_volume= */ NULL) < 0)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "name");
|
||||
|
||||
return vmspawn_qmp_remove_block_device(ctx->bridge, link, p.name);
|
||||
}
|
||||
|
||||
static int vl_method_subscribe_events(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
VmspawnVarlinkContext *ctx = ASSERT_PTR(userdata);
|
||||
_cleanup_strv_free_ char **filter = NULL;
|
||||
@@ -380,9 +453,10 @@ int vmspawn_varlink_setup(
|
||||
if (!ctx)
|
||||
return log_oom();
|
||||
|
||||
/* Create varlink server for VM control */
|
||||
/* AddStorage receives an fd from the caller. */
|
||||
r = varlink_server_new(&ctx->varlink_server,
|
||||
SD_VARLINK_SERVER_INHERIT_USERDATA,
|
||||
SD_VARLINK_SERVER_INHERIT_USERDATA |
|
||||
SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT,
|
||||
ctx);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create varlink server: %m");
|
||||
@@ -402,7 +476,9 @@ int vmspawn_varlink_setup(
|
||||
"io.systemd.MachineInstance.Resume", vl_method_resume,
|
||||
"io.systemd.MachineInstance.Reboot", vl_method_reboot,
|
||||
"io.systemd.MachineInstance.Describe", vl_method_describe,
|
||||
"io.systemd.MachineInstance.SubscribeEvents", vl_method_subscribe_events);
|
||||
"io.systemd.MachineInstance.SubscribeEvents", vl_method_subscribe_events,
|
||||
"io.systemd.MachineInstance.AddStorage", vl_method_add_storage,
|
||||
"io.systemd.MachineInstance.RemoveStorage", vl_method_remove_storage);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind varlink methods: %m");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user