From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pve-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 0700E1FF17C for <inbox@lore.proxmox.com>; Wed, 2 Apr 2025 15:14:48 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 483BB1B216; Wed, 2 Apr 2025 15:14:25 +0200 (CEST) Date: Wed, 02 Apr 2025 15:14:10 +0200 From: Fabian =?iso-8859-1?q?Gr=FCnbichler?= <f.gruenbichler@proxmox.com> To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> References: <20250304115803.194820-1-m.frank@proxmox.com> <20250304115803.194820-3-m.frank@proxmox.com> In-Reply-To: <20250304115803.194820-3-m.frank@proxmox.com> MIME-Version: 1.0 User-Agent: astroid/0.16.0 (https://github.com/astroidmail/astroid) Message-Id: <1743597124.um0raw7cfp.astroid@yuna.none> X-SPAM-LEVEL: Spam detection results: 0 AWL 0.040 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record T_SPF_TEMPERROR 0.01 SPF: test of record failed (temperror) Subject: Re: [pve-devel] [PATCH guest-common v14 2/12] add dir mapping section config X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> On March 4, 2025 12:57 pm, Markus Frank wrote: > Adds a config file for directories by using a 'map' property string for > each node mapping. > > Next to node & path, there is the optional announce-submounts parameter > which forces virtiofsd to report a different device number for each > submount it encounters. Without it, duplicates may be created because > inode IDs are only unique on a single filesystem. some things about the announce-submounts option that might be worthwhile to consider: - does it hurt to set announce-submounts if there are none? - it sounds like not setting it if there are any is dangerous why don't we always set it? "announce-submounts" is also a really weird name if we extend this to managed bind-mounts for containers (which I'd very much like to do), if we keep it it should be a flag denoting that this directory contains further mountpoints (which means it requires/should default to announce-submounts for virtiofsd, and recursive bind mounting for LXC)? > > example config: > ``` > some-dir-id > map node=node1,path=/mnt/share/,announce-submounts=1 > map node=node2,path=/mnt/share/, > ``` > > Signed-off-by: Markus Frank <m.frank@proxmox.com> > --- > v14: > * disallow commas and equal signs in path until the path can be quoted > in property strings > * addressed style nits and improved formatting > > src/Makefile | 1 + > src/PVE/Mapping/Dir.pm | 196 +++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 197 insertions(+) > create mode 100644 src/PVE/Mapping/Dir.pm > > diff --git a/src/Makefile b/src/Makefile > index cbc40c1..030e7f7 100644 > --- a/src/Makefile > +++ b/src/Makefile > @@ -15,6 +15,7 @@ install: PVE > install -m 0644 PVE/StorageTunnel.pm ${PERL5DIR}/PVE/ > install -m 0644 PVE/Tunnel.pm ${PERL5DIR}/PVE/ > install -d ${PERL5DIR}/PVE/Mapping > + install -m 0644 PVE/Mapping/Dir.pm ${PERL5DIR}/PVE/Mapping/ > install -m 0644 PVE/Mapping/PCI.pm ${PERL5DIR}/PVE/Mapping/ > install -m 0644 PVE/Mapping/USB.pm ${PERL5DIR}/PVE/Mapping/ > install -d ${PERL5DIR}/PVE/VZDump > diff --git a/src/PVE/Mapping/Dir.pm b/src/PVE/Mapping/Dir.pm > new file mode 100644 > index 0000000..581ec39 > --- /dev/null > +++ b/src/PVE/Mapping/Dir.pm > @@ -0,0 +1,196 @@ > +package PVE::Mapping::Dir; > + > +use strict; > +use warnings; > + > +use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_lock_file cfs_write_file); > +use PVE::INotify; > +use PVE::JSONSchema qw(get_standard_option parse_property_string); > +use PVE::SectionConfig; > + > +use base qw(PVE::SectionConfig); > + > +my $FILENAME = 'mapping/dir.cfg'; > + > +cfs_register_file($FILENAME, > + sub { __PACKAGE__->parse_config(@_); }, > + sub { __PACKAGE__->write_config(@_); }); > + > + > +# so we don't have to repeat the type every time > +sub parse_section_header { > + my ($class, $line) = @_; > + > + if ($line =~ m/^(\S+)\s*$/) { > + my $id = $1; > + my $errmsg = undef; # set if you want to skip whole section > + eval { PVE::JSONSchema::pve_verify_configid($id) }; > + $errmsg = $@ if $@; > + my $config = {}; # to return additional attributes > + return ('dir', $id, $errmsg, $config); > + } > + return undef; > +} > + > +sub format_section_header { > + my ($class, $type, $sectionId, $scfg, $done_hash) = @_; > + > + return "$sectionId\n"; > +} > + > +sub type { > + return 'dir'; > +} > + > +# temporary path format that also disallows commas and equal signs > +# TODO: Remove this when property_string supports quotation of properties > +PVE::JSONSchema::register_format('pve-storage-path-in-property-string', \&verify_path); > +sub verify_path { > + my ($path, $noerr) = @_; > + > + if ($path !~ m|^/[^;,=\(\)]+|) { > + return undef if $noerr; > + die "Value does not look like a valid absolute path." > + ." These symbols are currently not allowed in path: ;,=())\n"; stray ')' in the error message > + } > + return $path; > +} > + > +my $map_fmt = { > + node => get_standard_option('pve-node'), > + path => { > + description => "Absolute directory path that should be shared with the guest.", > + type => 'string', > + format => 'pve-storage-path-in-property-string', > + }, > + 'announce-submounts' => { > + type => 'boolean', > + description => "Announce that the directory contains other mounted file systems." > + ." If this is not set and multiple file systems are mounted, the guest may" > + ." encounter duplicates due to file system specific inode IDs.", > + optional => 1, > + default => 1, > + }, > +}; > + > +my $defaultData = { > + propertyList => { > + id => { > + type => 'string', > + description => "The ID of the directory mapping", > + format => 'pve-configid', > + }, > + description => { > + type => 'string', > + description => "Description of the directory mapping", > + optional => 1, > + maxLength => 4096, > + }, > + map => { > + type => 'array', > + description => 'A list of maps for the cluster nodes.', > + optional => 1, > + items => { > + type => 'string', > + format => $map_fmt, > + }, > + }, > + }, > +}; > + > +sub private { > + return $defaultData; > +} > + > +sub options { > + return { > + description => { optional => 1 }, > + map => {}, > + }; > +} > + > +sub assert_valid { this is called below in assert_valid_map_list without filtering entries so that just those for the current node are considered.. > + my ($dir_cfg) = @_; > + > + my $path = $dir_cfg->{path}; > + > + verify_path($path); > + > + if (! -e $path) { > + die "Path $path does not exist\n"; > + } elsif (! -d $path) { > + die "Path $path exists, but is not a directory\n"; > + } so these checks don't make sense.. if the directory has to exist on all nodes, then the per-node mappings could just be dropped entirely ;) > + > + return 1; > +}; > + > +sub assert_valid_map_list { > + my ($map_list) = @_; > + > + my %count; > + for my $map (@$map_list) { > + my $entry = parse_property_string($map_fmt, $map); > + assert_valid($entry); > + $count{$entry->{node}}++; > + } > + for my $node (keys %count) { > + if ($count{$node} > 1) { > + die "Node '$node' is specified $count{$node} times.\n"; > + } > + } > +} > + > +sub config { > + return cfs_read_file($FILENAME); > +} > + > +sub lock_dir_config { > + my ($code, $errmsg) = @_; > + > + cfs_lock_file($FILENAME, undef, $code); > + if (my $err = $@) { > + $errmsg ? die "$errmsg: $err" : die $err; > + } > +} > + > +sub write_dir_config { > + my ($cfg) = @_; > + > + cfs_write_file($FILENAME, $cfg); > +} > + > +sub find_on_current_node { > + my ($id) = @_; > + > + my $cfg = config(); > + my $node = PVE::INotify::nodename(); > + > + my $node_mapping = get_node_mapping($cfg, $id, $node); > + if (@{$node_mapping} > 1) { > + die "More than than one directory mapping for node $node.\n"; > + } > + return $node_mapping->[0]; > +} > + > +sub get_node_mapping { > + my ($cfg, $id, $nodename) = @_; > + > + return undef if !defined($cfg->{ids}->{$id}); > + > + my $res = []; > + my $mapping_list = $cfg->{ids}->{$id}->{map}; > + for my $map (@{$mapping_list}) { > + my $entry = eval { parse_property_string($map_fmt, $map) }; > + warn $@ if $@; > + if ($entry && $entry->{node} eq $nodename) { > + push $res->@*, $entry; > + } > + } > + return $res; > +} > + > +PVE::Mapping::Dir->register(); > +PVE::Mapping::Dir->init(); > + > +1; > -- > 2.39.5 > > > > _______________________________________________ > pve-devel mailing list > pve-devel@lists.proxmox.com > https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > > > _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel