[pve-devel] applied: [PATCH storage 2/5] import/export: new formats: raw, tar, qcow2, vmdk
Dietmar Maurer
dietmar at proxmox.com
Thu Jun 22 07:15:50 CEST 2017
comments inline
> On June 21, 2017 at 2:59 PM Wolfgang Bumiller <w.bumiller at proxmox.com> wrote:
>
>
> All of them have a `+size` prefix to show that they're not
> "pure raw" or "pure tar" streams, because some storage may
> need to know in advance how much storage to allocate.
> The formats are explained in comments.
>
> PVE::Storage::Plugin now has default implementations for
> these for non-incremental streams exporting the current
> (rather than a snapshot state).
> To use qcow2 or vmdk formats $with_snapshots must be true,
> otherwise raw/tar will be used where $with_snapshots must
> be false.
> ---
> PVE/CLI/pvesm.pm | 7 ++-
> PVE/Storage/Plugin.pm | 148
> ++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 148 insertions(+), 7 deletions(-)
>
> diff --git a/PVE/CLI/pvesm.pm b/PVE/CLI/pvesm.pm
> index 8af4e7f..9adc8ba 100755
> --- a/PVE/CLI/pvesm.pm
> +++ b/PVE/CLI/pvesm.pm
> @@ -3,6 +3,7 @@ package PVE::CLI::pvesm;
> use strict;
> use warnings;
>
> +use POSIX qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC);
> use Fcntl ':flock';
> use File::Path;
>
> @@ -21,7 +22,7 @@ use PVE::CLIHandler;
>
> use base qw(PVE::CLIHandler);
>
> -my $KNOWN_EXPORT_FORMATS = ['zfs'];
> +my $KNOWN_EXPORT_FORMATS = ['raw+size', 'tar+size', 'qcow2+size',
> 'vmdk+size', 'zfs'];
>
> my $nodename = PVE::INotify::nodename();
>
> @@ -202,7 +203,7 @@ __PACKAGE__->register_method ({
> if ($filename eq '-') {
> $outfh = \*STDOUT;
> } else {
> - open($outfh, '>', $filename)
> + sysopen($outfh, $filename, O_CREAT|O_WRONLY|O_TRUNC)
> or die "open($filename): $!\n";
why do we need sysopen here?
> }
>
> @@ -277,7 +278,7 @@ __PACKAGE__->register_method ({
> if ($filename eq '-') {
> $infh = \*STDIN;
> } else {
> - open($infh, '<', $filename)
> + sysopen($infh, $filename, O_RDONLY)
> or die "open($filename): $!\n";
> }
>
> diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm
> index cc4c7e7..7bde330 100644
> --- a/PVE/Storage/Plugin.pm
> +++ b/PVE/Storage/Plugin.pm
> @@ -888,26 +888,166 @@ sub check_connection {
> return 1;
> }
>
> +# Import/Export interface:
> +# Any path based storage is assumed to support 'raw' and 'tar' streams, so
> +# the default implementations will return this if $scfg->{path} is set,
> +# mimicking the old PVE::Storage::storage_migrate() function.
> +#
> +# Plugins may fall back to PVE::Storage::Plugin::volume_{export,import}...
> +# functions in case the format doesn't match their specialized
> +# implementations to reuse the raw/tar code.
> +#
> +# Format specification:
> +# The following formats are all prefixed with image information in the form
> +# of a 64 bit little endian unsigned integer (pack('Q<')) in order to be
> able
> +# to preallocate the image on storages which require it.
> +#
> +# raw+size: (image files only)
> +# A raw binary data stream such as produced via `dd if=TheImageFile`.
> +# qcow2+size, vmdk: (image files only)
> +# A raw qcow2/vmdk/... file such as produced via `dd if=some.qcow2` for
> +# files which are already in qcow2 format, or via `qemu-img convert`.
> +# Note that these formats are only valid with $with_snapshots being true.
> +# tar+size: (subvolumes only)
> +# A GNU tar stream with the inner contents of the subvolume put into the
> +# 'subvol/' directory.
> +
> +# Plugins may reuse these helpers. Changes to the header format should be
> +# reflected by changes to the function prototypes.
> +sub write_common_header($$) {
> + my ($fh, $image_size_in_bytes) = @_;
> + syswrite($fh, pack("Q<", $image_size_in_bytes), 8);
> +}
> +
> +sub read_common_header($) {
> + my ($fh) = @_;
> + sysread($fh, my $size, 8);
> + $size = unpack('Q<', $size);
> + die "got a bad size (not a multiple of 1K)\n" if ($size&1023);
> + # Size is in bytes!
> + return $size;
> +}
> +
> # Export a volume into a file handle as a stream of desired format.
> sub volume_export {
> my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot,
> $base_snapshot, $with_snapshots) = @_;
> - die "volume export not implemented for $class";
> + if ($scfg->{path} && !defined($snapshot) && !defined($base_snapshot)) {
> + my $file = $class->path($scfg, $volname, $storeid)
> + or goto unsupported;
> + my ($size, $file_format) = file_size_info($file);
> +
> + if ($format eq 'raw+size') {
> + goto unsupported if $with_snapshots || $file_format eq 'subvol';
> + write_common_header($fh, $size);
> + if ($file_format eq 'raw') {
> + run_command(['dd', "if=$file", "bs=4k"], output => '>&'.fileno($fh));
> + } else {
> + run_command(['qemu-img', 'convert', '-f', $file_format, '-O', 'raw', $file,
> '/dev/stdout'],
> + output => '>&'.fileno($fh));
is it worth to use two different command here? I guess quemu-img can handle both
cases?
> + }
> + return;
> + } elsif ($format =~ /^(qcow2|vmdk)\+size$/) {
> + my $data_format = $1;
> + goto unsupported if !$with_snapshots || $file_format ne $data_format;
> + write_common_header($fh, $size);
> + run_command(['dd', "if=$file", "bs=4k"], output => '>&'.fileno($fh));
> + return;
> + } elsif ($format eq 'tar+size') {
> + goto unsupported if $file_format ne 'subvol';
> + write_common_header($fh, $size);
> + run_command(['tar', '--xform=s,^\./,subvol/,S', '-cf', '-', '-C', $file,
> '.'],
> + output => '>&'.fileno($fh));
why do we need --xform here?
Also, is '-cf' good enough? We use the following flags for vzdump backups:
-cpf
--one-file-system
--warning=no-file-ignored
--sparse
--numeric-owner
--acls
--xattrs'
--xattrs-include=user.*
--xattrs-include=security.capability
--warning=no-xattr-write
?
More information about the pve-devel
mailing list