X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FStorage.pm;h=71d6ad78db1255286c64d48549f10894011b9094;hb=ac5c1af57cffb79ba18c6141b96131e5790c4b2d;hp=f2231f2f8c67beb40df19cc9ad907dc2badbbb72;hpb=823e8afe72a84f3abff884bd4b5c32d140ffdf62;p=pve-storage.git diff --git a/PVE/Storage.pm b/PVE/Storage.pm index f2231f2..71d6ad7 100755 --- a/PVE/Storage.pm +++ b/PVE/Storage.pm @@ -38,13 +38,14 @@ use PVE::Storage::GlusterfsPlugin; use PVE::Storage::ZFSPoolPlugin; use PVE::Storage::ZFSPlugin; use PVE::Storage::PBSPlugin; +use PVE::Storage::BTRFSPlugin; # Storage API version. Increment it on changes in storage API interface. -use constant APIVER => 8; +use constant APIVER => 9; # Age is the number of versions we're backward compatible with. # This is like having 'current=APIVER' and age='APIAGE' in libtool, # see https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html -use constant APIAGE => 7; +use constant APIAGE => 0; # load standard plugins PVE::Storage::DirPlugin->register(); @@ -60,6 +61,7 @@ PVE::Storage::GlusterfsPlugin->register(); PVE::Storage::ZFSPoolPlugin->register(); PVE::Storage::ZFSPlugin->register(); PVE::Storage::PBSPlugin->register(); +PVE::Storage::BTRFSPlugin->register(); # load third-party plugins if ( -d '/usr/share/perl5/PVE/Storage/Custom' ) { @@ -101,6 +103,8 @@ PVE::Storage::Plugin->init(); our $iso_extension_re = qr/\.(?:iso|img)/i; +our $vztmpl_extension_re = qr/\.tar\.(gz|xz|zst)/i; + # PVE::Storage utility functions sub config { @@ -190,7 +194,7 @@ sub storage_check_enabled { # storage_can_replicate: # return true if storage supports replication -# (volumes alocated with vdisk_alloc() has replication feature) +# (volumes allocated with vdisk_alloc() has replication feature) sub storage_can_replicate { my ($cfg, $storeid, $format) = @_; @@ -573,7 +577,7 @@ sub path_to_volume_id { } elsif ($path =~ m!^$isodir/([^/]+$iso_extension_re)$!) { my $name = $1; return ('iso', "$sid:iso/$name"); - } elsif ($path =~ m!^$tmpldir/([^/]+\.tar\.gz)$!) { + } elsif ($path =~ m!^$tmpldir/([^/]+$vztmpl_extension_re)$!) { my $name = $1; return ('vztmpl', "$sid:vztmpl/$name"); } elsif ($path =~ m!^$privatedir/(\d+)$!) { @@ -688,7 +692,7 @@ sub storage_migrate { my $migration_snapshot; if (!defined($snapshot)) { - if ($scfg->{type} eq 'zfspool') { + if ($scfg->{type} eq 'zfspool' || $scfg->{type} eq 'btrfs') { $migration_snapshot = 1; $snapshot = '__migration__'; } @@ -712,7 +716,8 @@ sub storage_migrate { my $send = ['pvesm', 'export', $volid, $format, '-', '-with-snapshots', $with_snapshots]; my $recv = [@$ssh, '--', 'pvesm', 'import', $target_volid, $format, $import_fn, '-with-snapshots', $with_snapshots]; if (defined($snapshot)) { - push @$send, '-snapshot', $snapshot + push @$send, '-snapshot', $snapshot; + push @$recv, '-snapshot', $snapshot; } if ($migration_snapshot) { push @$recv, '-delete-snapshot', $snapshot; @@ -722,7 +727,7 @@ sub storage_migrate { if (defined($base_snapshot)) { # Check if the snapshot exists on the remote side: push @$send, '-base', $base_snapshot; - push @$recv, '-base', $base_snapshot; + push @$recv, '-base', $base_snapshot if $target_apiver >= 9; } my $new_volid; @@ -934,7 +939,7 @@ sub vdisk_list { storage_check_enabled($cfg, $storeid) if ($storeid); - my $res = {}; + my $res = $storeid ? { $storeid => [] } : {}; # prepare/activate/refresh all storages @@ -961,12 +966,8 @@ sub vdisk_list { activate_storage_list($cfg, $storage_list, $cache); - # FIXME PVE 7.0: only scan storages with the correct content types - my $scan = defined($ctype) ? $storage_list : [ keys %{$ids} ]; - - foreach my $sid (@{$scan}) { + for my $sid ($storage_list->@*) { next if $storeid && $storeid ne $sid; - next if !storage_check_enabled($cfg, $sid, undef, 1); my $scfg = $ids->{$sid}; my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); @@ -1559,7 +1560,7 @@ sub extract_vzdump_config_vma { my $errstring; my $err = sub { my $output = shift; - if ($output =~ m/lzop: Broken pipe: / || $output =~ m/gzip: stdout: Broken pipe/ || $output =~ m/zstd: error 70 : Write error : Broken pipe/) { + if ($output =~ m/lzop: Broken pipe: / || $output =~ m/gzip: stdout: Broken pipe/ || $output =~ m/zstd: error 70 : Write error.*Broken pipe/) { $broken_pipe = 1; } elsif (!defined ($errstring) && $output !~ m/^\s*$/) { $errstring = "Failed to extract config from VMA archive: $output\n"; @@ -1665,10 +1666,9 @@ my $prune_mark = sub { sub prune_mark_backup_group { my ($backup_group, $keep) = @_; - my $keep_all = delete $keep->{'keep-all'}; + my @positive_opts = grep { $_ ne 'keep-all' && $keep->{$_} > 0 } keys $keep->%*; - if ($keep_all || !scalar(grep {$_ > 0} values %{$keep})) { - $keep = { 'keep-all' => 1 } if $keep_all; + if ($keep->{'keep-all'} || scalar(@positive_opts) == 0) { foreach my $prune_entry (@{$backup_group}) { $prune_entry->{mark} = 'keep'; } @@ -1714,7 +1714,7 @@ sub prune_mark_backup_group { } } -sub volume_export { +sub volume_export : prototype($$$$$$$) { my ($cfg, $fh, $volid, $format, $snapshot, $base_snapshot, $with_snapshots) = @_; my ($storeid, $volname) = parse_volume_id($volid, 1); @@ -1725,18 +1725,27 @@ sub volume_export { $snapshot, $base_snapshot, $with_snapshots); } -sub volume_import { - my ($cfg, $fh, $volid, $format, $base_snapshot, $with_snapshots, $allow_rename) = @_; +sub volume_import : prototype($$$$$$$$) { + my ($cfg, $fh, $volid, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_; my ($storeid, $volname) = parse_volume_id($volid, 1); die "cannot import into volume '$volid'\n" if !$storeid; my $scfg = storage_config($cfg, $storeid); my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); - return $plugin->volume_import($scfg, $storeid, $fh, $volname, $format, - $base_snapshot, $with_snapshots, $allow_rename) // $volid; -} - -sub volume_export_formats { + return $plugin->volume_import( + $scfg, + $storeid, + $fh, + $volname, + $format, + $snapshot, + $base_snapshot, + $with_snapshots, + $allow_rename, + ) // $volid; +} + +sub volume_export_formats : prototype($$$$$) { my ($cfg, $volid, $snapshot, $base_snapshot, $with_snapshots) = @_; my ($storeid, $volname) = parse_volume_id($volid, 1); @@ -1748,21 +1757,27 @@ sub volume_export_formats { $with_snapshots); } -sub volume_import_formats { - my ($cfg, $volid, $base_snapshot, $with_snapshots) = @_; +sub volume_import_formats : prototype($$$$$) { + my ($cfg, $volid, $snapshot, $base_snapshot, $with_snapshots) = @_; my ($storeid, $volname) = parse_volume_id($volid, 1); return if !$storeid; my $scfg = storage_config($cfg, $storeid); my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); - return $plugin->volume_import_formats($scfg, $storeid, $volname, - $base_snapshot, $with_snapshots); + return $plugin->volume_import_formats( + $scfg, + $storeid, + $volname, + $snapshot, + $base_snapshot, + $with_snapshots, + ); } sub volume_transfer_formats { my ($cfg, $src_volid, $dst_volid, $snapshot, $base_snapshot, $with_snapshots) = @_; my @export_formats = volume_export_formats($cfg, $src_volid, $snapshot, $base_snapshot, $with_snapshots); - my @import_formats = volume_import_formats($cfg, $dst_volid, $base_snapshot, $with_snapshots); + my @import_formats = volume_import_formats($cfg, $dst_volid, $snapshot, $base_snapshot, $with_snapshots); my %import_hash = map { $_ => 1 } @import_formats; my @common = grep { $import_hash{$_} } @export_formats; return @common; @@ -1850,7 +1865,7 @@ sub get_bandwidth_limit { my ($operation, $storage_list, $override) = @_; # called for each limit (global, per-storage) with the 'default' and the - # $operation limit and should udpate $override for every limit affecting + # $operation limit and should update $override for every limit affecting # us. my $use_global_limits = 0; my $apply_limit = sub { @@ -1929,4 +1944,16 @@ sub assert_sid_unused { return undef; } +# removes leading/trailing spaces and (back)slashes completely +# substitutes every non-ASCII-alphanumerical char with '_', except '_.-' +sub normalize_content_filename { + my ($filename) = @_; + + chomp $filename; + $filename =~ s/^.*[\/\\]//; + $filename =~ s/[^a-zA-Z0-9_.-]/_/g; + + return $filename; +} + 1;