From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH qemu-server v4 6/6] feature #1027: virtio-9p & virtio-fs support
Date: Thu, 04 May 2023 10:39:25 +0200 [thread overview]
Message-ID: <1683188359.qalzq3g083.astroid@yuna.none> (raw)
In-Reply-To: <20230425102136.85334-7-m.frank@proxmox.com>
On April 25, 2023 12:21 pm, Markus Frank wrote:
> adds support for sharing directorys with a guest vm
>
> virtio-9p can be simply started with qemu
9p is not really maintained anymore upstream AFAIK (only "Odd Fixes"),
and had security issues in the past. Is there a good reason for
supporting it (we didn't want to in the past ;)).
> virtio-fs needs virtiofsd to be started
it also is not compatible with migration, including savevm (so,
snapshots with RAM, suspend to disk). until that changes, checks need to
be added to error out early when attempting to do such an action.
>
> Signed-off-by: Markus Frank <m.frank@proxmox.com>
> ---
> PVE/API2/Qemu.pm | 19 +++++++
> PVE/QemuServer.pm | 141 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 160 insertions(+)
>
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 587bb22..810e124 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -639,6 +639,8 @@ my $check_vm_modify_config_perm = sub {
> # the user needs Disk and PowerMgmt privileges to change the vmstate
> # also needs privileges on the storage, that will be checked later
> $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Disk', 'VM.PowerMgmt' ]);
> + } elsif ($opt =~ m/^sharedfiles\d$/) {
> + # needs $param->{$opt} so checkout $check_vm_dir_perm
this is not quite correct - you should still check the permission for
modifying the VM config here (VM.Config.Options or VM.Config.Disk?). of
course, like for other things, there are extra checks later on to see
whether you are allowed to add/remove/modify a particular shareddir
usage. disks also require storage permissions which are not handled
here, for example, but the general 'allowed to change disk aspects of
VM' is.
> } else {
> # catches hostpci\d+, args, lock, etc.
> # new options will be checked here
> @@ -649,6 +651,20 @@ my $check_vm_modify_config_perm = sub {
> return 1;
> };
>
> +my $check_vm_dir_perm = sub {
> + my ($rpcenv, $authuser, $param) = @_;
> +
> + return 1 if $authuser eq 'root@pam';
> +
> + foreach my $opt (keys %{$param}) {
> + if ($opt =~ m/^sharedfiles\d$/) {
> + my $sharedfiles = PVE::QemuServer::parse_sharedfiles($param->{$opt});
> + $rpcenv->check_dir_perm($authuser, $sharedfiles->{dirid}, ['Map.Use']);
> + }
> + }
> + return 1;
> +};
> +
> __PACKAGE__->register_method({
> name => 'vmlist',
> path => '',
> @@ -876,6 +892,7 @@ __PACKAGE__->register_method({
>
> &$check_vm_modify_config_perm($rpcenv, $authuser, $vmid, $pool, [ keys %$param]);
>
> + &$check_vm_dir_perm($rpcenv, $authuser, $param);
> &$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param);
> &$check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param);
>
> @@ -1576,6 +1593,8 @@ my $update_vm_api = sub {
>
> &$check_vm_modify_config_perm($rpcenv, $authuser, $vmid, undef, [keys %$param]);
>
> + &$check_vm_dir_perm($rpcenv, $authuser, $param);
> +
> &$check_storage_access($rpcenv, $authuser, $storecfg, $vmid, $param);
>
> my $updatefn = sub {
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index c1d0fd2..fc07311 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -274,6 +274,31 @@ my $rng_fmt = {
> },
> };
>
> +my $sharedfiles_fmt = {
> + type => {
> + type => 'string',
> + default_key => 1,
> + enum => ['virtio-9p', 'virtio-fs'],
> + description => "sharedfiles via"
> + ." virtio-9p (https://www.linux-kvm.org/page/9p_virtio)"
> + ." or virtio-fs (https://virtio-fs.gitlab.io/howto-qemu.html)",
> + format_description => "virtio-sharedfiles-type",
> + optional => 1,
why is this optional?
> + },
> + dirid => {
> + type => 'string',
> + description => "dirid of directory you want to share with the guest VM",
> + format_description => "virtio-sharedfiles-dirid",
> + optional => 1,
why is this optional?
> + },
> + tag => {
> + type => 'string',
> + description => "tag name for mounting in the guest VM",
> + format_description => "virtio-sharedfiles-tag",
> + optional => 1,
is the tag actually optional?
> + },
see my comments in the manager patch, I think there are quite a few more
knobs that we might want to expose here.
> +};
> +
> my $meta_info_fmt = {
> 'ctime' => {
> type => 'integer',
> @@ -832,6 +857,7 @@ while (my ($k, $v) = each %$confdesc) {
>
> my $MAX_USB_DEVICES = 14;
> my $MAX_NETS = 32;
> +my $MAX_SHAREDFILES = 10;
> my $MAX_SERIAL_PORTS = 4;
> my $MAX_PARALLEL_PORTS = 3;
> my $MAX_NUMA = 8;
> @@ -974,6 +1000,12 @@ my $netdesc = {
> description => "Specify network devices.",
> };
>
> +my $sharedfilesdesc = {
> + optional => 1,
> + type => 'string', format => $sharedfiles_fmt,
> + description => "share files between host and guest",
> +};
> +
> PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
>
> my $ipconfig_fmt = {
> @@ -1035,6 +1067,10 @@ for (my $i = 0; $i < $MAX_NETS; $i++) {
> $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
> }
>
> +for (my $i = 0; $i < $MAX_SHAREDFILES; $i++) {
> + $confdesc->{"sharedfiles$i"} = $sharedfilesdesc;
> +}
> +
> foreach my $key (keys %$confdesc_cloudinit) {
> $confdesc->{$key} = $confdesc_cloudinit->{$key};
> }
> @@ -1988,6 +2024,16 @@ sub parse_net {
> return $res;
> }
>
> +sub parse_sharedfiles {
> + my ($value) = @_;
> +
> + return if !$value;
> + my $res = eval { parse_property_string($sharedfiles_fmt, $value) };
> +
> + warn $@ if $@;
> + return $res;
> +}
> +
> # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
> sub parse_ipconfig {
> my ($data) = @_;
> @@ -4105,6 +4151,44 @@ sub config_to_command {
> push @$devices, '-device', $netdevicefull;
> }
>
> + my $onevirtiofs = 0;
> + for (my $i = 0; $i < $MAX_SHAREDFILES; $i++) {
what about hotplug support?
> + my $sharedfilesstr = "sharedfiles$i";
> +
> + next if !$conf->{$sharedfilesstr};
> + my $sharedfiles = parse_sharedfiles($conf->{$sharedfilesstr});
> + next if !$sharedfiles;
> +
> + die $sharedfilesstr.' needs a type (virtio-9p or virtio-fs)' if !$sharedfiles->{type};
> + die $sharedfilesstr.' needs a dirid of a directory to share' if !$sharedfiles->{dirid};
> + die $sharedfilesstr.' needs a mount tag' if !$sharedfiles->{tag};
so I guess all three are not optional ;)
> +
> + if ($sharedfiles->{type} eq 'virtio-fs' && $conf->{numa}) {
> + die "disable numa to use virtio-fs or use virtio-9p instead";
> + }
okay, that is an interesting restriction. is that just because it
requires some other, complex changes, or is it not working at all?
> +
> + my $path = PVE::DirConfig::extract_dir_path($nodename, $sharedfiles->{dirid});
> +
> + if ($sharedfiles->{type} eq 'virtio-9p') {
> + push @$devices, '-fsdev', "local,security_model=passthrough,id=fsdev$i"
> + .",path=$path";
> + push @$devices, '-device', "virtio-9p-pci,id=fs9p$i,fsdev=fsdev$i"
> + .",mount_tag=$sharedfiles->{tag}";
> + }
> + if ($sharedfiles->{type} eq 'virtio-fs') {
> + push @$devices, '-chardev', "socket,id=virtfs$i,path=/var/run/virtiofsd/vm$vmid-fs$i";
> + push @$devices, '-device', 'vhost-user-fs-pci,queue-size=1024'
> + .",chardev=virtfs$i,tag=$sharedfiles->{tag}";
> + $onevirtiofs = 1;
> + }
> + }
> +
> + if ($onevirtiofs) {
> + push @$devices, '-object', 'memory-backend-file,id=mem'
> + .",size=$conf->{memory}M,mem-path=/dev/shm,share=on";
> + push @$devices, '-numa', 'node,memdev=mem';
> + }
> +
> if ($conf->{ivshmem}) {
> my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
>
> @@ -4190,6 +4274,41 @@ sub config_to_command {
> return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
> }
>
> +sub start_virtiofs {
how/when are they stopped again? :)
> + my ($vmid, $path, $fsid, $dirid) = @_;
> +
> + my $socket_path_root = "/var/run/virtiofsd";
> + mkdir $socket_path_root;
> + my $socket_path = "$socket_path_root/vm$vmid-fs$fsid";
> + unlink($socket_path);
> + my $socket = IO::Socket::UNIX->new(
> + Type => SOCK_STREAM,
> + Local => $socket_path,
> + Listen => 1,
> + ) or die "cannot create socket - $!\n";
> +
> + my $flags = fcntl($socket, F_GETFD, 0)
> + or die "failed to get file descriptor flags: $!\n";
> + fcntl($socket, F_SETFD, $flags & ~FD_CLOEXEC)
> + or die "failed to remove FD_CLOEXEC from file descriptor\n";
> +
> + my $fd = $socket->fileno();
> +
> + my $pid = fork();
> + if ($pid == 0) {
> + # TODO replace with rust implementation in bookworm
> + run_command(['/usr/lib/kvm/virtiofsd', "--fd=$fd",
> + '-o', "source=$path", '-o', 'cache=always']);
> + POSIX::_exit(0);
> + } elsif (!defined($pid)) {
> + die "could not fork to start virtiofsd";
> + }
> +
> + # return socket to keep it alive,
> + # so that qemu will wait for virtiofsd to start
> + return $socket;
> +}
> +
> sub check_rng_source {
> my ($source) = @_;
>
> @@ -5747,6 +5866,23 @@ sub vm_start_nolock {
> my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid,
> $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
>
> + my $nodename = nodename();
> + my @sockets;
> + for (my $i = 0; $i < $MAX_SHAREDFILES; $i++) {
> + my $sharedfilesstr = "sharedfiles$i";
> +
> + next if !$conf->{$sharedfilesstr};
> + my $sharedfiles = parse_sharedfiles($conf->{$sharedfilesstr});
> + next if !$sharedfiles;
> +
> + my $path = PVE::DirConfig::extract_dir_path($nodename, $sharedfiles->{dirid});
> +
> + if ($sharedfiles && $sharedfiles->{type} eq 'virtio-fs' && !$conf->{numa}) {
> + my $socket = start_virtiofs($vmid, $path, $i, $sharedfiles->{dirid});
> + push @sockets, $socket;
> + }
> + }
> +
> my $migration_ip;
> my $get_migration_ip = sub {
> my ($nodename) = @_;
> @@ -6094,6 +6230,11 @@ sub vm_start_nolock {
>
> PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
>
> + foreach my $socket (@sockets) {
> + shutdown($socket, 2);
> + close($socket);
> + }
> +
> return $res;
> }
>
> --
> 2.30.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
>
next prev parent reply other threads:[~2023-05-04 8:39 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-25 10:21 [pve-devel] [PATCH docs v4 0/6] feature #1027 virtio-9p/virtio-fs Markus Frank
2023-04-25 10:21 ` [pve-devel] [PATCH docs v4 1/6] added shared filesystem doc for virtio-fs & virtio-9p Markus Frank
2023-04-25 10:21 ` [pve-devel] [PATCH access-control v4 2/6] added acls for Shared Files Directories Markus Frank
2023-05-04 8:24 ` Fabian Grünbichler
2023-04-25 10:21 ` [pve-devel] [PATCH manager v4 3/6] added Config for Shared Filesystem Directories Markus Frank
2023-05-03 11:26 ` Dominik Csapak
2023-05-04 8:13 ` Thomas Lamprecht
2023-05-04 8:31 ` Dominik Csapak
2023-05-04 8:42 ` Thomas Lamprecht
2023-05-04 8:57 ` Dominik Csapak
2023-05-04 10:21 ` Thomas Lamprecht
2023-05-09 9:31 ` Dominik Csapak
2023-05-04 8:24 ` Fabian Grünbichler
2023-04-25 10:21 ` [pve-devel] [PATCH manager v4 4/6] added Shared Files tab in Node Settings Markus Frank
2023-04-25 10:21 ` [pve-devel] [PATCH manager v4 5/6] added options to add virtio-9p & virtio-fs Shared Filesystems to qemu config Markus Frank
2023-04-25 10:21 ` [pve-devel] [PATCH qemu-server v4 6/6] feature #1027: virtio-9p & virtio-fs support Markus Frank
2023-05-04 8:39 ` Fabian Grünbichler [this message]
2023-05-05 8:27 ` Markus Frank
2023-05-04 8:24 ` [pve-devel] [PATCH docs v4 0/6] feature #1027 virtio-9p/virtio-fs Fabian Grünbichler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1683188359.qalzq3g083.astroid@yuna.none \
--to=f.gruenbichler@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox