'pbs',
);
+our $QCOW2_PREALLOCATION = {
+ off => 1,
+ metadata => 1,
+ falloc => 1,
+ full => 1,
+};
+
+our $RAW_PREALLOCATION = {
+ off => 1,
+ falloc => 1,
+ full => 1,
+};
+
our $MAX_VOLUMES_PER_GUEST = 1024;
cfs_register_file ('storage.cfg',
sub validate_prune_backups {
my ($prune_backups) = @_;
- my $keep_all = delete $prune_backups->{'keep-all'};
+ my $res = { $prune_backups->%* };
+
+ my $keep_all = delete $res->{'keep-all'};
- if (!scalar(grep {$_ > 0} values %{$prune_backups})) {
- $prune_backups = { 'keep-all' => 1 };
+ if (scalar(grep { $_ > 0 } values %{$res}) == 0) {
+ $res = { 'keep-all' => 1 };
} elsif ($keep_all) {
die "keep-all cannot be set together with other options.\n";
}
- return $prune_backups;
+ return $res;
}
register_standard_option('prune-backups', {
description => "The retention options with shorter intervals are processed first " .
type => 'string', format => 'pve-storage-format',
optional => 1,
},
+ preallocation => {
+ description => "Preallocation mode for raw and qcow2 images. " .
+ "Using 'metadata' on raw images results in preallocation=off.",
+ type => 'string', enum => ['off', 'metadata', 'falloc', 'full'],
+ default => 'metadata',
+ optional => 1,
+ },
},
};
return $cfg;
}
+sub preallocation_cmd_option {
+ my ($scfg, $fmt) = @_;
+
+ my $prealloc = $scfg->{preallocation};
+
+ if ($fmt eq 'qcow2') {
+ $prealloc = $prealloc // 'metadata';
+
+ die "preallocation mode '$prealloc' not supported by format '$fmt'\n"
+ if !$QCOW2_PREALLOCATION->{$prealloc};
+
+ return "preallocation=$prealloc";
+ } elsif ($fmt eq 'raw') {
+ $prealloc = $prealloc // 'off';
+ $prealloc = 'off' if $prealloc eq 'metadata';
+
+ die "preallocation mode '$prealloc' not supported by format '$fmt'\n"
+ if !$RAW_PREALLOCATION->{$prealloc};
+
+ return "preallocation=$prealloc";
+ }
+
+ return;
+}
+
# Storage implementation
# called during addition of storage (before the new storage config got written)
return ('images', $name, $vmid, undef, undef, $isBase, $format);
} elsif ($volname =~ m!^iso/([^/]+$PVE::Storage::iso_extension_re)$!) {
return ('iso', $1);
- } elsif ($volname =~ m!^vztmpl/([^/]+\.tar\.[gx]z)$!) {
+ } elsif ($volname =~ m!^vztmpl/([^/]+$PVE::Storage::vztmpl_extension_re)$!) {
return ('vztmpl', $1);
} elsif ($volname =~ m!^rootdir/(\d+)$!) {
return ('rootdir', $1, $1);
} else {
my $cmd = ['/usr/bin/qemu-img', 'create'];
- push @$cmd, '-o', 'preallocation=metadata' if $fmt eq 'qcow2';
+ my $prealloc_opt = preallocation_cmd_option($scfg, $fmt);
+ push @$cmd, '-o', $prealloc_opt if defined($prealloc_opt);
push @$cmd, '-f', $fmt, $path, "${size}K";
return undef;
}
+# Asserts that a rollback to $snap on $volname is possible.
+# If certain snapshots are preventing the rollback and $blockers is an array
+# reference, the snapshot names can be pushed onto $blockers prior to dying.
sub volume_rollback_is_possible {
- my ($class, $scfg, $storeid, $volname, $snap) = @_;
+ my ($class, $scfg, $storeid, $volname, $snap, $blockers) = @_;
return 1;
}
$info = { volid => "$sid:iso/$1", format => 'iso' };
} elsif ($tt eq 'vztmpl') {
- next if $fn !~ m!/([^/]+\.tar\.([gx]z))$!;
+ next if $fn !~ m!/([^/]+$PVE::Storage::vztmpl_extension_re)$!;
$info = { volid => "$sid:vztmpl/$1", format => "t$2" };
return ($res->{total}, $res->{avail}, $res->{used}, 1);
}
+# Returns a hash with the snapshot names as keys and the following data:
+# id - Unique id to distinguish different snapshots even if the have the same name.
+# timestamp - Creation time of the snapshot (seconds since epoch).
+# Returns an empty hash if the volume does not exist.
+sub volume_snapshot_info {
+ my ($class, $scfg, $storeid, $volname) = @_;
+
+ die "volume_snapshot_info is not implemented for $class";
+}
+
sub volume_snapshot_list {
my ($class, $scfg, $storeid, $volname) = @_;
sysread($fh, my $size, 8);
$size = unpack('Q<', $size);
die "import: no size found in export header, aborting.\n" if !defined($size);
- die "import: got a bad size (not a multiple of 1K), aborting.\n" if ($size&1023);
# Size is in bytes!
return $size;
}
# Import data from a stream, creating a new or replacing or adding to an existing volume.
sub volume_import {
- my ($class, $scfg, $storeid, $fh, $volname, $format, $base_snapshot, $with_snapshots, $allow_rename) = @_;
+ my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_;
die "volume import format '$format' not available for $class\n"
if $format !~ /^(raw|tar|qcow2|vmdk)\+size$/;
}
sub volume_import_formats {
- my ($class, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots) = @_;
+ my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_;
if ($scfg->{path} && !defined($base_snapshot)) {
my $format = ($class->parse_volname($volname))[6];
if ($with_snapshots) {