From: Markus Frank <m.frank@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH qemu-server v3 6/6] feature #1027: virtio-9p & virtio-fs support
Date: Fri, 31 Mar 2023 13:16:14 +0200 [thread overview]
Message-ID: <20230331111614.95981-7-m.frank@proxmox.com> (raw)
In-Reply-To: <20230331111614.95981-1-m.frank@proxmox.com>
adds support for sharing directorys with a guest vm
virtio-9p can be simply started with qemu
virtio-fs needs virtiofsd to be started
Signed-off-by: Markus Frank <m.frank@proxmox.com>
---
PVE/API2/Qemu.pm | 20 +++++-
PVE/QemuServer.pm | 158 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 587bb22..aaeefe2 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
} 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 => '',
@@ -875,7 +891,7 @@ __PACKAGE__->register_method({
&$check_storage_access($rpcenv, $authuser, $storecfg, $vmid, $param, $storage);
&$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 +1592,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..af47311 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -57,6 +57,7 @@ use PVE::QemuServer::Memory;
use PVE::QemuServer::Monitor qw(mon_cmd);
use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
use PVE::QemuServer::USB qw(parse_usb_device);
+use PVE::DirConfig;
my $have_sdn;
eval {
@@ -274,6 +275,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,
+ },
+ dirid => {
+ type => 'string',
+ description => "dirid of directory you want to share with the guest VM",
+ format_description => "virtio-sharedfiles-dirid",
+ optional => 1,
+ },
+ tag => {
+ type => 'string',
+ description => "tag name for mounting in the guest VM",
+ format_description => "virtio-sharedfiles-tag",
+ optional => 1,
+ },
+};
+
my $meta_info_fmt = {
'ctime' => {
type => 'integer',
@@ -832,6 +858,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 +1001,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 +1068,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 +2025,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 +4152,44 @@ sub config_to_command {
push @$devices, '-device', $netdevicefull;
}
+ my $onevirtiofs = 0;
+ 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;
+
+ 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};
+
+ if ($sharedfiles->{type} eq 'virtio-fs' && $conf->{numa}) {
+ die "disable numa to use virtio-fs or use virtio-9p instead";
+ }
+
+ my $path = 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 +4275,57 @@ sub config_to_command {
return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
}
+sub extract_dir_path {
+ my ($nodename, $dirid) = @_;
+ my $dir_config = PVE::DirConfig::load_config($nodename);
+ my $path = $dir_config->{$dirid};
+ if (!$path) {
+ die "Directory ID $dirid does not exist\n";
+ }
+ if (! -e $path) {
+ die "Path $path does not exist\n";
+ }
+ if ((-e $path) && (! -d $path)) {
+ die "Path $path exists but is not a directory\n"
+ }
+ return $path;
+}
+
+sub start_virtiofs {
+ 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 +5883,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 = 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 +6247,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
prev parent reply other threads:[~2023-03-31 11:16 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-31 11:16 [pve-devel] [PATCH docs/acces-control/manager/qemu-server v3 0/6] feature #1027 virtio-9p/virtio-fs Markus Frank
2023-03-31 11:16 ` [pve-devel] [PATCH docs v3 1/6] added shared filesystem doc for virtio-fs & virtio-9p Markus Frank
2023-03-31 11:16 ` [pve-devel] [PATCH access-control v3 2/6] added acls for Shared Files Directories Markus Frank
2023-03-31 11:16 ` [pve-devel] [PATCH manager v3 3/6] added Config for Shared Filesystem Directories Markus Frank
2023-03-31 11:16 ` [pve-devel] [PATCH manager v3 4/6] added Shared Files tab in Node Settings Markus Frank
2023-03-31 11:16 ` [pve-devel] [PATCH manager v3 5/6] added options to add virtio-9p & virtio-fs Shared Filesystems to qemu config Markus Frank
2023-03-31 11:16 ` Markus Frank [this message]
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=20230331111614.95981-7-m.frank@proxmox.com \
--to=m.frank@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.