[PATCH FOR DISCUSSION ONLY] v2v: Add -o kubevirt output mode.
by Richard W.M. Jones
XXX
No documentation.
Only handles one disk.
Network cards?
Do we need to escape YAML format?
What firmware types does kubevirt support.
---
v2v/Makefile.am | 2 +
v2v/cmdline.ml | 21 ++++++++++
v2v/output_kubevirt.ml | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
v2v/output_kubevirt.mli | 24 +++++++++++
4 files changed, 150 insertions(+)
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index f36731750..2f6953463 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -66,6 +66,7 @@ SOURCES_MLI = \
modules_list.mli \
name_from_disk.mli \
output_glance.mli \
+ output_kubevirt.mli \
output_libvirt.mli \
output_local.mli \
output_null.mli \
@@ -132,6 +133,7 @@ SOURCES_ML = \
output_rhv_upload_precheck_source.ml \
output_rhv_upload.ml \
output_vdsm.ml \
+ output_kubevirt.ml \
inspect_source.ml \
target_bus_assignment.ml \
cmdline.ml \
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index a8da63f71..a9608b330 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -131,6 +131,7 @@ let parse_cmdline () =
error (f_"%s option used more than once on the command line") "-o";
match mode with
| "glance" -> output_mode := `Glance
+ | "kubevirt" -> output_mode := `Kubevirt
| "libvirt" -> output_mode := `Libvirt
| "disk" | "local" -> output_mode := `Local
| "null" -> output_mode := `Null
@@ -394,6 +395,7 @@ read the man page virt-v2v(1).
match output_mode with
| `Not_set -> no_options (); `Not_set
| `Glance -> no_options (); `Glance
+ | `Kubevirt -> no_options (); `Kubevirt
| `Libvirt -> no_options (); `Libvirt
| `Local -> no_options (); `Local
| `Null -> no_options (); `Null
@@ -521,6 +523,25 @@ read the man page virt-v2v(1).
Output_glance.output_glance (),
output_format, output_alloc
+ | `Kubevirt ->
+ if output_conn <> None then
+ error_option_cannot_be_used_in_output_mode "glance" "-oc";
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "glance" "-op";
+ let os =
+ match output_storage with
+ | None ->
+ error (f_"-o local: output directory was not specified, use '-os /dir'")
+ | Some d when not (is_directory d) ->
+ error (f_"-os %s: output directory does not exist or is not a directory") d
+ | Some d -> d in
+ if qemu_boot then
+ error_option_cannot_be_used_in_output_mode "glance" "--qemu-boot";
+ if not do_copy then
+ error_option_cannot_be_used_in_output_mode "libvirt" "--no-copy";
+ Output_kubevirt.output_kubevirt os,
+ output_format, output_alloc
+
| `Not_set
| `Libvirt ->
if output_password <> None then
diff --git a/v2v/output_kubevirt.ml b/v2v/output_kubevirt.ml
new file mode 100644
index 000000000..a6747fd06
--- /dev/null
+++ b/v2v/output_kubevirt.ml
@@ -0,0 +1,103 @@
+(* virt-v2v
+ * Copyright (C) 2018 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Printf
+
+open Std_utils
+open Tools_utils
+open Unix_utils
+open Common_gettext.Gettext
+
+open Types
+open Utils
+
+class output_kubevirt dir = object
+ inherit output
+
+ method as_options =
+ sprintf "-o kubevirt -os %s" dir
+
+ method supported_firmware = [ TargetBIOS; TargetUEFI ] (* XXX GUESS *)
+
+ val mutable name = ""
+
+ method prepare_targets source targets =
+ (* Only one disk is supported at present. XXX *)
+ if List.length targets <> 1 then
+ error (f_"-o kubevirt: this output mode only supports a single disk");
+
+ (* Don't use the source name directly, it must be munged
+ * for DNS (RFC 1123).
+ *)
+ name <- PCRE.replace ~global:true (PCRE.compile "[_.]+") "-"
+ source.s_name;
+
+ List.mapi (
+ fun i t ->
+ (* This is the PVC name which is generated by the
+ * script that calls virt-v2v.
+ *)
+ let target_file =
+ TargetFile (dir // sprintf "%s-disk-%d" name i) in
+ { t with target_file }
+ ) targets
+
+ method create_metadata source targets target_buses
+ guestcaps inspect target_firmware =
+ (* Create the YAML-format metadata. *)
+ (* XXX ESCAPING? *)
+ with_open_out (dir // name ^ ".yaml") (
+ fun chan ->
+ let fpf fs = fprintf chan fs in
+ fpf "apiVersion: kubevirt.io/v1alpha1\n";
+ fpf "kind: OfflineVirtualMachine\n";
+ fpf "metadata:\n";
+ fpf " name: %s\n" name;
+ fpf "domain:\n";
+ fpf " cpu:\n";
+ fpf " cores: %d\n" source.s_vcpu;
+ fpf " resources:\n";
+ fpf " requests:\n";
+ fpf " memory: %Ld%s\n" (source.s_memory /^ 1024_L) "KiB";
+ fpf " devices:\n";
+
+ (* virt-v2v (and indeed hardware) doesn't really work this way,
+ * in that there are several buses which may have multiple disks,
+ * and we're throwing all that careful mapping away, but here we
+ * are ... XXX
+ *)
+ let disk_bus =
+ match guestcaps.gcaps_block_bus with
+ | Virtio_blk -> "virtio"
+ | Virtio_SCSI -> "scsi"
+ | IDE -> "ide" in
+
+ fpf " disks:\n";
+ fpf " - name: disk-1\n";
+ fpf " disk:\n";
+ fpf " bus: %s\n" disk_bus;
+ fpf " volumeName: volume-1\n";
+ fpf " volumes:\n";
+ fpf " - name: volume-1\n";
+ fpf " persistentVolumeClaim:\n";
+ fpf " name: %s-disk-1\n" name;
+ )
+end
+
+let output_kubevirt = new output_kubevirt
+let () = Modules_list.register_output_module "kubevirt"
diff --git a/v2v/output_kubevirt.mli b/v2v/output_kubevirt.mli
new file mode 100644
index 000000000..3ff0041c7
--- /dev/null
+++ b/v2v/output_kubevirt.mli
@@ -0,0 +1,24 @@
+(* virt-v2v
+ * Copyright (C) 2018 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** [-o kubevirt] target. *)
+
+val output_kubevirt : string -> Types.output
+(** [output_kubevirt dir] creates and returns a new
+ {!Types.output} object specialized for writing output to
+ KubeVirt. *)
--
2.13.2
6 years, 7 months
Issue with libguestfs-test-tool on a guest hosted on VMWare ESXi
by Tanmoy Sinha
I am using a debian 9 guest, hosted on a ESXi platform with nested
virtualisation enabled.
On this debian 9 guest when I run libguesfs-test-tool, it fails with an
error:
"qemu-system-x86_64:
/build/qemu-DqynNa/qemu-2.8+dfsg/target-i386/kvm.c:1805: kvm_put_msrs:
Assertion `ret == cpu->kvm_msr_buf->nmsrs' failed."
Instead when I use a wrapper script and hook it with the env
variable LIBGUESTFS_HV=/tmp/qemu.wrapper, things work fine, as in the
script I just spawn the guest with the specific machine type pc-i440fx-2.1
over KVM.
exec qemu-system-x86_64 -enable-kvm -machine *pc-i440fx-2.**1*,accel
=kvm,dump-guest-core=off "${args[@]}"
The script is attached as well as the libguestfs-test-tool logs.
Can anybody help me on this. Why is the latest machine type, i.e.
pc-i440fx-2.8 on my debian 9 guest not working out? If I do a force_tcg it
works even with the latest machine type, but that is not what I desire, I
don't intend libguestfs to run on emulation.
=========================================================================================================================
System configuration:
*$> uname -a*
Linux XXXX 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) x86_64
GNU/Linux
*$> kvm -machine help*
Supported machines are:
pc Standard PC (i440FX + PIIX, 1996) (alias of
pc-i440fx-2.8)
pc-i440fx-2.8 Standard PC (i440FX + PIIX, 1996) (default)
pc-i440fx-2.7 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.6 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.5 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.4 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.3 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.2 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.1 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-2.0 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-1.7 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-1.6 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-1.5 Standard PC (i440FX + PIIX, 1996)
pc-i440fx-1.4 Standard PC (i440FX + PIIX, 1996)
pc-1.3 Standard PC (i440FX + PIIX, 1996)
pc-1.2 Standard PC (i440FX + PIIX, 1996)
pc-1.1 Standard PC (i440FX + PIIX, 1996)
pc-1.0 Standard PC (i440FX + PIIX, 1996)
pc-0.15 Standard PC (i440FX + PIIX, 1996)
pc-0.14 Standard PC (i440FX + PIIX, 1996)
pc-0.13 Standard PC (i440FX + PIIX, 1996)
pc-0.12 Standard PC (i440FX + PIIX, 1996)
pc-0.11 Standard PC (i440FX + PIIX, 1996)
pc-0.10 Standard PC (i440FX + PIIX, 1996)
q35 Standard PC (Q35 + ICH9, 2009) (alias of pc-q35-2.8)
pc-q35-2.8 Standard PC (Q35 + ICH9, 2009)
pc-q35-2.7 Standard PC (Q35 + ICH9, 2009)
pc-q35-2.6 Standard PC (Q35 + ICH9, 2009)
pc-q35-2.5 Standard PC (Q35 + ICH9, 2009)
pc-q35-2.4 Standard PC (Q35 + ICH9, 2009)
isapc ISA-only PC
none empty machine
xenfv Xen Fully-virtualized PC
xenpv Xen Para-virtualized PC
*$> kvm -cpu help*
Available CPUs:
x86 486
x86 Broadwell-noTSX Intel Core Processor (Broadwell, no TSX)
x86 Broadwell Intel Core Processor (Broadwell)
x86 Conroe Intel Celeron_4x0 (Conroe/Merom Class Core 2)
x86 Haswell-noTSX Intel Core Processor (Haswell, no TSX)
x86 Haswell Intel Core Processor (Haswell)
x86 IvyBridge Intel Xeon E3-12xx v2 (Ivy Bridge)
x86 Nehalem Intel Core i7 9xx (Nehalem Class Core i7)
x86 Opteron_G1 AMD Opteron 240 (Gen 1 Class Opteron)
x86 Opteron_G2 AMD Opteron 22xx (Gen 2 Class Opteron)
x86 Opteron_G3 AMD Opteron 23xx (Gen 3 Class Opteron)
x86 Opteron_G4 AMD Opteron 62xx class CPU
x86 Opteron_G5 AMD Opteron 63xx class CPU
x86 Penryn Intel Core 2 Duo P9xxx (Penryn Class Core 2)
x86 SandyBridge Intel Xeon E312xx (Sandy Bridge)
x86 Skylake-Client Intel Core Processor (Skylake)
x86 Westmere Westmere E56xx/L56xx/X56xx (Nehalem-C)
x86 athlon QEMU Virtual CPU version 2.5+
x86 core2duo Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz
x86 coreduo Genuine Intel(R) CPU T2600 @ 2.16GHz
x86 kvm32 Common 32-bit KVM processor
x86 kvm64 Common KVM processor
x86 n270 Intel(R) Atom(TM) CPU N270 @ 1.60GHz
x86 pentium
x86 pentium2
x86 pentium3
x86 phenom AMD Phenom(tm) 9550 Quad-Core Processor
x86 qemu32 QEMU Virtual CPU version 2.5+
x86 qemu64 QEMU Virtual CPU version 2.5+
x86 host KVM processor with all supported host features (only
available in KVM mode)
Recognized CPUID flags:
fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36
pn clflush ds acpi mmx fxsr sse sse2 ss ht tm ia64 pbe
pni pclmulqdq dtes64 monitor ds-cpl vmx smx est tm2 ssse3 cid fma cx16
xtpr pdcm pcid dca sse4.1 sse4.2 x2apic movbe popcnt tsc-deadline aes xsave
osxsave avx f16c rdrand hypervisor
fsgsbase tsc-adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f
avx512dq rdseed adx smap avx512ifma pcommit clflushopt clwb avx512pf
avx512er avx512cd avx512bw avx512vl
avx512vbmi umip pku ospke rdpid
avx512-4vnniw avx512-4fmaps
syscall nx mmxext fxsr-opt pdpe1gb rdtscp lm 3dnowext 3dnow
lahf-lm cmp-legacy svm extapic cr8legacy abm sse4a misalignsse
3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid-msr tbm topoext
perfctr-core perfctr-nb
invtsc
xstore xstore-en xcrypt xcrypt-en ace2 ace2-en phe phe-en pmm pmm-en
kvmclock kvm-nopiodelay kvm-mmu kvmclock kvm-asyncpf kvm-steal-time
kvm-pv-eoi kvm-pv-unhalt kvmclock-stable-bit
npt lbrv svm-lock nrip-save tsc-scale vmcb-clean flushbyasid
decodeassists pause-filter pfthreshold
xsaveopt xsavec xgetbv1 xsaves
arat
6 years, 7 months
[nbdkit PATCH] plugins: Add .can_zero callback
by Eric Blake
Originally, I thought that since the plugin always emulates
.zero with a fallback to .pwrite, we didn't need to expose the
backend's .can_zero to plugins. But there is another
consideration, as shown at least in the nbd plugin: a plugin
may implement a .zero callback that depends on support from
a remote endpoint. If the remote endpoint doesn't support
zeroes, then the plugin HAS to fail .zero with EOPNOTSUPP to
get the automatic fallback to .pwrite; this is slightly
wasteful to just telling nbdkit to not use the .zero callback
when it won't work.
At the same time, we still want to advertise zero support to
the client, even if we won't be calling .zero, since handling
NBD_CMD_WRITE_ZEROES allows for less network traffic; if it
is ever truly necessary to avoid advertising to the guest, the
nozero filter can accomplish that task.
So, this patch exposes a .can_zero callback for plugins,
which can usually be omitted, but which can be used to short-
circuit calls to .zero, with the nbd plugin as the first user;
while plugins.c continues to report true (well, the same result
as .can_write) to the backend regardless of the plugin's
answer, unless the plugin hits an error.
Testing of the nbd changes (and thus of the general nbdkit
handling of plugin .can_zero) is best done as part of the
nozero filter: using the filter on the server side means the
nbd plugin won't see a zero advertisement, and thus the client
side does not call nbd's .zero, but still advertises zero to
the client.
Now that the set of feature callbacks is the same for plugins
and filters, we can consolidate the documentation for filters
and merely focus on the slight differences.
This patch breaks ABI from the earlier exposure of .can_fua to
plugins a few patches ago, but that is okay as there has not
been a release in the meantime (the logical grouping was nicer
this way). Had a release happened, .can_zero would have to
be placed after .zero in struct nbdkit_plugin. Also, in
plugins.c, rearrange get_error() to a more logical location.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
This sort of fell out from the v2v rhv-upload conversation on
the list, although Rich's v7 patch there demonstrates that
even when oVirt lacks zero support, the rhv-upload plugin still
wants .zero to be called (because it can optimize zeros done
beyond the highest write), so that particular plugin would not
be able to take advantage of this change. At any rate, in
writing it up, I noticed that the nbd plugin benefits from it,
so it's still useful in that right.
docs/nbdkit-filter.pod | 79 ++++++++++++++++++-------------------------------
docs/nbdkit-plugin.pod | 22 +++++++++++++-
include/nbdkit-plugin.h | 1 +
src/plugins.c | 72 ++++++++++++++++++++++++++++----------------
plugins/nbd/nbd.c | 15 ++++++----
tests/test-nozero.sh | 34 +++++++++++++++++----
6 files changed, 135 insertions(+), 88 deletions(-)
diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index e6bf0c3..9bdc690 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -343,6 +343,10 @@ calls.
=head2 C<.can_trim>
+=head2 C<.can_zero>
+
+=head2 C<.can_fua>
+
int (*can_write) (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle);
int (*can_flush) (struct nbdkit_next_ops *next_ops, void *nxdata,
@@ -352,66 +356,39 @@ calls.
void *handle);
int (*can_trim) (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle);
+ int (*can_zero) (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle);
+ int (*can_fua) (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle);
These intercept the corresponding plugin methods, and control feature
bits advertised to the client.
+Of note, the C<.can_zero> callback in the filter controls whether the
+server advertises zero support to the client, which is slightly
+different semantics than the plugin; that is,
+C<next_ops-E<gt>can_zero> always returns true for a plugin, even when
+the plugin's own C<.can_zero> callback returned false, because nbdkit
+implements a fallback to C<.pwrite> at the plugin layer.
+
+Remember that most of the feature check functions return merely a
+boolean success value, while C<.can_fua> has three success values.
+The difference between values may affect choices made in the filter:
+when splitting a write request that requested FUA from the client, if
+C<next_ops-E<gt>can_fua> returns C<NBDKIT_FUA_NATIVE>, then the filter
+should pass the FUA flag on to each sub-request; while if it is known
+that FUA is emulated by a flush because of a return of
+C<NBDKIT_FUA_EMULATE>, it is more efficient to only flush once after
+all sub-requests have completed (often by passing C<NBDKIT_FLAG_FUA>
+on to only the final sub-request, or by dropping the flag and ending
+with a direct call to C<next_ops-E<gt>flush>).
+
If there is an error, the callback should call C<nbdkit_error> with an
error message and return C<-1>. If these functions are called more
than once for the same connection, they should return the same value;
similarly, the filter may cache the results of each counterpart in
C<next_ops> for a given connection rather than repeating calls.
-=head2 C<.can_zero>
-
- int (*can_zero) (struct nbdkit_next_ops *next_ops, void *nxdata,
- void *handle);
-
-This controls whether write zero support will be advertised to the
-client. This function has no counterpart in plugins, because nbdkit
-can always emulate zero by using pwrite; but a filter may want to
-force different handling than the nbdkit implementation. If this
-callback is omitted, the default returned for the plugin layer is
-true.
-
-If there is an error, the callback should call C<nbdkit_error> with an
-error message and return C<-1>. Like the other initial queries
-documented above, per-connection caching the of return value of this
-function is allowed.
-
-=head2 C<.can_fua>
-
- int (*can_fua) (struct nbdkit_next_ops *next_ops, void *nxdata,
- void *handle);
-
-This controls how the Forced Unit Access flag will be handled; it is
-only relevant for connections that are not read-only. This intercepts
-the corresponding plugin method, to control feature bits advertised to
-the client. Unlike other feature functions with just two success
-states, this one returns three success values: C<NBDKIT_FUA_NONE> to
-avoid advertising FUA support to the client, C<NBDKIT_FUA_EMULATE> if
-FUA is emulated by nbdkit calling flush after a write transaction, and
-C<NBDKIT_FUA_NATIVE> if FUA semantics are handled by the plugin
-without the overhead of an extra flush from nbdkit.
-
-The difference between the two non-zero values may affect choices made
-in the filter: when splitting a write request that requested FUA from
-the client, native support should pass the FUA flag on to each
-sub-request; while if it is known that FUA is emulated by a flush, it
-is more efficient to only flush once after all sub-requests have
-completed (often by passing C<NBDKIT_FLAG_FUA> on to only the final
-sub-request, or by dropping the flag and ending with a direct call to
-C<next_ops-E<gt>flush>).
-
-If this callback is omitted, the default returned for the plugin layer
-is C<NBDKIT_FUA_EMULATE> if C<can_flush> returned true, otherwise it
-is C<NBDKIT_FUA_NONE>.
-
-If there is an error, the callback should call C<nbdkit_error> with an
-error message and return C<-1>. Like the other initial queries
-documented above, per-connection caching of the return value of this
-function is allowed.
-
=head2 C<.pread>
int (*pread) (struct nbdkit_next_ops *next_ops, void *nxdata,
@@ -505,7 +482,7 @@ value to return to the client.
This intercepts the plugin C<.zero> method and can be used to modify
zero requests.
-This function will not be called if C<.can_write> returned false; in
+This function will not be called if C<.can_zero> returned false; in
turn, the filter should not call C<next_ops-E<gt>zero> if
C<next_ops-E<gt>can_zero> did not return true.
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index d6d080a..6e89315 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -487,6 +487,25 @@ error message and return C<-1>.
This callback is not required. If omitted, then we return true iff a
C<.trim> callback has been defined.
+=head2 C<.can_zero>
+
+ int can_zero (void *handle);
+
+This is called during the option negotiation phase to find out if the
+plugin wants the C<.zero> callback to be utilized. Support for
+writing zeros is still advertised to the client (unless the nbdkit
+filter nozero is also used), so returning false merely serves as a way
+to avoid complicating the C<.zero> callback to have to fail with
+C<EOPNOTSUPP> on the connections where it will never be more efficient
+than using C<.pwrite> up front.
+
+If there is an error, C<.can_zero> should call C<nbdkit_error> with an
+error message and return C<-1>.
+
+This callback is not required. If omitted, then nbdkit always tries
+C<.zero> first if it is present, and gracefully falls back to
+C<.pwrite> if C<.zero> was absent or failed with C<EOPNOTSUPP>.
+
=head2 C<.can_fua>
int can_fua (void *handle);
@@ -601,7 +620,7 @@ error message, and C<nbdkit_set_error> to record an appropriate error
During the data serving phase, this callback is used to write C<count>
bytes of zeroes at C<offset> in the backing store.
-This function will not be called if C<.can_write> returned false. On
+This function will not be called if C<.can_zero> returned false. On
input, the parameter C<flags> may include C<NBDKIT_FLAG_MAY_TRIM>
unconditionally, and C<NBDKIT_FLAG_FUA> based on the result of
C<.can_fua>.
@@ -826,6 +845,7 @@ and then users will be able to run it like this:
L<nbdkit(1)>,
L<nbdkit-filter(3)>,
+L<nbdkit-nozero-filter(3)>,
L<nbdkit-example1-plugin(1)>,
L<nbdkit-example2-plugin(1)>,
L<nbdkit-example3-plugin(1)>,
diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h
index 3f541a1..65a2e0c 100644
--- a/include/nbdkit-plugin.h
+++ b/include/nbdkit-plugin.h
@@ -104,6 +104,7 @@ struct nbdkit_plugin {
void (*dump_plugin) (void);
+ int (*can_zero) (void *handle);
int (*can_fua) (void *handle);
#if NBDKIT_API_VERSION == 1
int (*_unused1) (void *, void *, uint32_t, uint64_t);
diff --git a/src/plugins.c b/src/plugins.c
index d44e724..ff4facf 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -355,25 +355,24 @@ plugin_can_trim (struct backend *b, struct connection *conn)
return p->plugin.trim || p->plugin._trim_old;
}
-/* Grab the appropriate error value.
- */
-static int
-get_error (struct backend_plugin *p)
-{
- int ret = threadlocal_get_error ();
-
- if (!ret && p->plugin.errno_is_preserved)
- ret = errno;
- return ret ? ret : EIO;
-}
-
static int
plugin_can_zero (struct backend *b, struct connection *conn)
{
+ struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
+
+ assert (connection_get_handle (conn, 0));
+
debug ("can_zero");
- /* We always allow .zero to fall back to .write, so plugins don't
- * need to override this. */
+ /* Note the special case here: the plugin's .can_zero controls only
+ * whether we call .zero; while the backend expects .can_zero to
+ * return whether to advertise zero support. Since we ALWAYS know
+ * how to fall back to .pwrite in plugin_zero(), we ignore the
+ * difference between the plugin's true or false return, and only
+ * call it to catch a -1 failure during negotiation. */
+ if (p->plugin.can_zero &&
+ p->plugin.can_zero (connection_get_handle (conn, 0)) == -1)
+ return -1;
return plugin_can_write (b, conn);
}
@@ -401,6 +400,18 @@ plugin_can_fua (struct backend *b, struct connection *conn)
return NBDKIT_FUA_EMULATE;
}
+/* Grab the appropriate error value.
+ */
+static int
+get_error (struct backend_plugin *p)
+{
+ int ret = threadlocal_get_error ();
+
+ if (!ret && p->plugin.errno_is_preserved)
+ ret = errno;
+ return ret ? ret : EIO;
+}
+
static int
plugin_pread (struct backend *b, struct connection *conn,
void *buf, uint32_t count, uint64_t offset, uint32_t flags,
@@ -534,6 +545,7 @@ plugin_zero (struct backend *b, struct connection *conn,
bool fua = flags & NBDKIT_FLAG_FUA;
bool emulate = false;
bool need_flush = false;
+ int can_zero = 1; /* TODO cache this per-connection? */
assert (connection_get_handle (conn, 0));
assert (!(flags & ~(NBDKIT_FLAG_MAY_TRIM | NBDKIT_FLAG_FUA)));
@@ -547,18 +559,26 @@ plugin_zero (struct backend *b, struct connection *conn,
}
if (!count)
return 0;
- errno = 0;
- if (p->plugin.zero)
- r = p->plugin.zero (connection_get_handle (conn, 0), count, offset, flags);
- else if (p->plugin._zero_old)
- r = p->plugin._zero_old (connection_get_handle (conn, 0), count, offset,
- may_trim);
- else
- emulate = true;
- if (r == -1)
- *err = emulate ? EOPNOTSUPP : get_error (p);
- if (r == 0 || *err != EOPNOTSUPP)
- goto done;
+ if (p->plugin.can_zero) {
+ can_zero = p->plugin.can_zero (connection_get_handle (conn, 0));
+ assert (can_zero != -1);
+ }
+
+ if (can_zero) {
+ errno = 0;
+ if (p->plugin.zero)
+ r = p->plugin.zero (connection_get_handle (conn, 0), count, offset,
+ flags);
+ else if (p->plugin._zero_old)
+ r = p->plugin._zero_old (connection_get_handle (conn, 0), count, offset,
+ may_trim);
+ else
+ emulate = true;
+ if (r == -1)
+ *err = emulate ? EOPNOTSUPP : get_error (p);
+ if (r == 0 || *err != EOPNOTSUPP)
+ goto done;
+ }
assert (p->plugin.pwrite || p->plugin._pwrite_old);
flags &= ~NBDKIT_FLAG_MAY_TRIM;
diff --git a/plugins/nbd/nbd.c b/plugins/nbd/nbd.c
index dd84b04..51de178 100644
--- a/plugins/nbd/nbd.c
+++ b/plugins/nbd/nbd.c
@@ -618,6 +618,14 @@ nbd_can_trim (void *handle)
return h->flags & NBD_FLAG_SEND_TRIM;
}
+static int
+nbd_can_zero (void *handle)
+{
+ struct handle *h = handle;
+
+ return h->flags & NBD_FLAG_SEND_WRITE_ZEROES;
+}
+
static int
nbd_can_fua (void *handle)
{
@@ -662,11 +670,7 @@ nbd_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
int f = 0;
assert (!(flags & ~(NBDKIT_FLAG_FUA | NBDKIT_FLAG_MAY_TRIM)));
- if (!(h->flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
- /* Trigger a fall back to regular writing */
- errno = EOPNOTSUPP;
- return -1;
- }
+ assert (h->flags & NBD_FLAG_SEND_WRITE_ZEROES);
if (!(flags & NBDKIT_FLAG_MAY_TRIM))
f |= NBD_CMD_FLAG_NO_HOLE;
@@ -716,6 +720,7 @@ static struct nbdkit_plugin plugin = {
.can_flush = nbd_can_flush,
.is_rotational = nbd_is_rotational,
.can_trim = nbd_can_trim,
+ .can_zero = nbd_can_zero,
.can_fua = nbd_can_fua,
.pread = nbd_pread,
.pwrite = nbd_pwrite,
diff --git a/tests/test-nozero.sh b/tests/test-nozero.sh
index 95ed045..57c4452 100755
--- a/tests/test-nozero.sh
+++ b/tests/test-nozero.sh
@@ -36,7 +36,9 @@ set -e
files="nozero1.img nozero1.log nozero1.sock nozero1.pid
nozero2.img nozero2.log nozero2.sock nozero2.pid
nozero3.img nozero3.log nozero3.sock nozero3.pid
- nozero4.img nozero4.log nozero4.sock nozero4.pid"
+ nozero4.img nozero4.log nozero4.sock nozero4.pid
+ nozero5.img nozero5a.log nozero5b.log nozero5a.sock nozero5b.sock
+ nozero5a.pid nozero5b.pid"
rm -f $files
# Prep images, and check that qemu-io understands the actions we plan on
@@ -45,6 +47,7 @@ for f in {0..1023}; do printf '%1024s' . >> nozero1.img; done
cp nozero1.img nozero2.img
cp nozero1.img nozero3.img
cp nozero1.img nozero4.img
+cp nozero1.img nozero5.img
if ! qemu-io -f raw -d unmap -c 'w -z -u 0 1M' nozero1.img; then
echo "$0: missing or broken qemu-io"
rm nozero?.img
@@ -57,7 +60,7 @@ if test "$(stat -c %b nozero1.img)" = "$(stat -c %b nozero2.img)"; then
fi
cp nozero2.img nozero1.img
-pid1= pid2= pid3= pid4=
+pid1= pid2= pid3= pid4= pid5a= pid5b=
# Kill any nbdkit processes on exit.
cleanup ()
@@ -68,6 +71,8 @@ cleanup ()
test "$pid2" && kill $pid2
test "$pid3" && kill $pid3
test "$pid4" && kill $pid4
+ test "$pid5a" && kill $pid5a
+ test "$pid5b" && kill $pid5b
# For easier debugging, dump the final log files before removing them.
echo "Log 1 file contents:"
cat nozero1.log || :
@@ -77,6 +82,10 @@ cleanup ()
cat nozero3.log || :
echo "Log 4 file contents:"
cat nozero4.log || :
+ echo "Log 5a file contents:"
+ cat nozero5a.log || :
+ echo "Log 5b file contents:"
+ cat nozero5b.log || :
rm -f $files
exit $status
@@ -88,6 +97,8 @@ trap cleanup INT QUIT TERM EXIT ERR
# 2: log before filter with zeromode=none (default), to ensure no ZERO request
# 3: log before filter with zeromode=emulate, to ensure ZERO from client
# 4: log after filter with zeromode=emulate, to ensure no ZERO to plugin
+# 5a/b: both sides of nbd plugin: even though server side does not advertise
+# ZERO, the client side still exposes it, and just skips calling nbd's .zero
nbdkit -P nozero1.pid -U nozero1.sock --filter=log \
file logfile=nozero1.log file=nozero1.img
nbdkit -P nozero2.pid -U nozero2.sock --filter=log --filter=nozero \
@@ -96,11 +107,15 @@ nbdkit -P nozero3.pid -U nozero3.sock --filter=log --filter=nozero \
file logfile=nozero3.log file=nozero3.img zeromode=emulate
nbdkit -P nozero4.pid -U nozero4.sock --filter=nozero --filter=log \
file logfile=nozero4.log file=nozero4.img zeromode=emulate
+nbdkit -P nozero5a.pid -U nozero5a.sock --filter=log --filter=nozero \
+ file logfile=nozero5a.log file=nozero5.img
+nbdkit -P nozero5b.pid -U nozero5b.sock --filter=log \
+ nbd logfile=nozero5b.log socket=nozero5a.sock
# We may have to wait a short time for the pid files to appear.
for i in `seq 1 10`; do
if test -f nozero1.pid && test -f nozero2.pid && test -f nozero3.pid &&
- test -f nozero4.pid; then
+ test -f nozero4.pid && test -f nozero5a.pid && test -f nozero5b.pid; then
break
fi
sleep 1
@@ -110,9 +125,11 @@ pid1="$(cat nozero1.pid)" || :
pid2="$(cat nozero2.pid)" || :
pid3="$(cat nozero3.pid)" || :
pid4="$(cat nozero4.pid)" || :
+pid5a="$(cat nozero5a.pid)" || :
+pid5b="$(cat nozero5b.pid)" || :
if ! test -f nozero1.pid || ! test -f nozero2.pid || ! test -f nozero3.pid ||
- ! test -f nozero4.pid; then
+ ! test -f nozero4.pid || ! test -f nozero5a.pid || ! test -f nozero5b.pid; then
echo "$0: PID files were not created"
exit 1
fi
@@ -122,6 +139,7 @@ qemu-io -f raw -c 'w -z -u 0 1M' 'nbd+unix://?socket=nozero1.sock'
qemu-io -f raw -c 'w -z -u 0 1M' 'nbd+unix://?socket=nozero2.sock'
qemu-io -f raw -c 'w -z -u 0 1M' 'nbd+unix://?socket=nozero3.sock'
qemu-io -f raw -c 'w -z -u 0 1M' 'nbd+unix://?socket=nozero4.sock'
+qemu-io -f raw -c 'w -z -u 0 1M' 'nbd+unix://?socket=nozero5b.sock'
# Check for expected ZERO vs. WRITE results
grep 'connection=1 Zero' nozero1.log
@@ -134,10 +152,16 @@ if grep 'connection=1 Zero' nozero4.log; then
echo "filter should have converted zero into write"
exit 1
fi
+grep 'connection=1 Zero' nozero5b.log
+if grep 'connection=1 Zero' nozero5a.log; then
+ echo "nbdkit should have converted zero into write before nbd plugin"
+ exit 1
+fi
-# Sanity check on contents - all 4 files should read identically
+# Sanity check on contents - all 5 files should read identically
cmp nozero1.img nozero2.img
cmp nozero2.img nozero3.img
cmp nozero3.img nozero4.img
+cmp nozero4.img nozero5.img
# The cleanup() function is called implicitly on exit.
--
2.14.3
6 years, 7 months
[PATCH] v2v: ova: convert E1000 network interfaces as such
by Pino Toscano
So far v2v did not read the model of network interfaces, resulting in
"virtio" as the model for such interfaces.
Start reading the model, if available, mapping only E1000 for now.
There are also other models, e.g. PCNet32 or VmxNet3, but they are
ignored for now: reading them as Source_other_nic would result in v2v
rejecting OVAs previously converted.
---
v2v/parse_ovf_from_ova.ml | 7 ++++++-
v2v/test-v2v-i-ova-formats.expected | 2 +-
v2v/test-v2v-i-ova-gz.expected | 2 +-
v2v/test-v2v-i-ova-subfolders.expected | 2 +-
v2v/test-v2v-i-ova-subfolders.expected2 | 2 +-
v2v/test-v2v-i-ova-tar.expected | 2 +-
v2v/test-v2v-i-ova-tar.expected2 | 2 +-
v2v/test-v2v-i-ova-two-disks.expected | 2 +-
v2v/test-v2v-i-ova-two-disks.expected2 | 2 +-
9 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/v2v/parse_ovf_from_ova.ml b/v2v/parse_ovf_from_ova.ml
index 24cd29d42..631d7d7f6 100644
--- a/v2v/parse_ovf_from_ova.ml
+++ b/v2v/parse_ovf_from_ova.ml
@@ -235,9 +235,14 @@ let parse_ovf_from_ova ovf_filename =
| Some connection -> connection, Bridge
| None -> sprintf "eth%d" i, Network in
let mac = xpath_string "rasd:Address/text()" in
+ let nic_model =
+ match xpath_string "rasd:ResourceSubType/text()" with
+ | Some "E1000" -> Some Source_e1000
+ | Some _ -> None (* Warn? *)
+ | None -> None in
let nic = {
s_mac = mac;
- s_nic_model = None;
+ s_nic_model = nic_model;
s_vnet = vnet;
s_vnet_orig = vnet;
s_vnet_type = vnet_type;
diff --git a/v2v/test-v2v-i-ova-formats.expected b/v2v/test-v2v-i-ova-formats.expected
index 5e2fabfa9..f7b79d7bc 100644
--- a/v2v/test-v2v-i-ova-formats.expected
+++ b/v2v/test-v2v-i-ova-formats.expected
@@ -17,5 +17,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-gz.expected b/v2v/test-v2v-i-ova-gz.expected
index 31ad9e1f3..9cf048f30 100644
--- a/v2v/test-v2v-i-ova-gz.expected
+++ b/v2v/test-v2v-i-ova-gz.expected
@@ -17,5 +17,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-subfolders.expected b/v2v/test-v2v-i-ova-subfolders.expected
index fc60b06ca..44ec3b2b8 100644
--- a/v2v/test-v2v-i-ova-subfolders.expected
+++ b/v2v/test-v2v-i-ova-subfolders.expected
@@ -17,5 +17,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-subfolders.expected2 b/v2v/test-v2v-i-ova-subfolders.expected2
index a280c4637..f42fc924f 100644
--- a/v2v/test-v2v-i-ova-subfolders.expected2
+++ b/v2v/test-v2v-i-ova-subfolders.expected2
@@ -17,5 +17,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-tar.expected b/v2v/test-v2v-i-ova-tar.expected
index 5e2fabfa9..f7b79d7bc 100644
--- a/v2v/test-v2v-i-ova-tar.expected
+++ b/v2v/test-v2v-i-ova-tar.expected
@@ -17,5 +17,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-tar.expected2 b/v2v/test-v2v-i-ova-tar.expected2
index edc07f363..83928c23e 100644
--- a/v2v/test-v2v-i-ova-tar.expected2
+++ b/v2v/test-v2v-i-ova-tar.expected2
@@ -17,5 +17,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-two-disks.expected b/v2v/test-v2v-i-ova-two-disks.expected
index 232ec5446..61eab9cf6 100644
--- a/v2v/test-v2v-i-ova-two-disks.expected
+++ b/v2v/test-v2v-i-ova-two-disks.expected
@@ -18,5 +18,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
diff --git a/v2v/test-v2v-i-ova-two-disks.expected2 b/v2v/test-v2v-i-ova-two-disks.expected2
index 03377cb18..5a218f5d5 100644
--- a/v2v/test-v2v-i-ova-two-disks.expected2
+++ b/v2v/test-v2v-i-ova-two-disks.expected2
@@ -18,5 +18,5 @@ disks:
removable media:
CD-ROM [ide] in slot 0
NICs:
- Bridge "PG-VLAN60"
+ Bridge "PG-VLAN60" [e1000]
--
2.14.3
6 years, 7 months
[PATCH] v2v: Fix parsing of OVA files and documentation for --network and --bridge (RHBZ#1559027).
by Richard W.M. Jones
When parsing OVA files we have to work backwards to whether the
original VMware object was a network or a bridge. It seems as if the
presence of <rasd:Connection> is sufficient. I dropped the use of
<rasd:ElementName> since it is literally just an internal name for the
network element, and is not significant in how the network is used.
Also update documentation because you must use ‘--bridge’ when
converting VMware guests to RHV.
For a full explanation see:
https://bugzilla.redhat.com/show_bug.cgi?id=1559027#c2
---
v2v/parse_ovf_from_ova.ml | 9 +++++----
v2v/virt-v2v.pod | 31 +++++++++++++------------------
2 files changed, 18 insertions(+), 22 deletions(-)
diff --git a/v2v/parse_ovf_from_ova.ml b/v2v/parse_ovf_from_ova.ml
index d8de0cea1..82d7adf8c 100644
--- a/v2v/parse_ovf_from_ova.ml
+++ b/v2v/parse_ovf_from_ova.ml
@@ -230,16 +230,17 @@ let parse_ovf_from_ova ovf_filename =
for i = 0 to nr_nodes-1 do
let n = Xml.xpathobj_node obj i in
Xml.xpathctx_set_current_context xpathctx n;
- let vnet =
- Option.default (sprintf"eth%d" i)
- (xpath_string "rasd:ElementName/text()") in
+ let vnet, vnet_type =
+ match xpath_string "rasd:Connection/text()" with
+ | Some connection -> connection, Bridge
+ | None -> sprintf"eth%d" i, Network in
let mac = xpath_string "rasd:Address/text()" in
let nic = {
s_mac = mac;
s_nic_model = None;
s_vnet = vnet;
s_vnet_orig = vnet;
- s_vnet_type = Network;
+ s_vnet_type = vnet_type;
} in
List.push_front nic nics
done;
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index caf9c983e..097bab453 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -16,7 +16,7 @@ virt-v2v - Convert a guest to use KVM
-o rhv-upload -oc https://ovirt-engine.example.com/ovirt-engine/api \
-os ovirt-data -op /tmp/ovirt-admin-password \
-oo rhv-cafile=/tmp/ca.pem -oo rhv-direct \
- --network ovirtmgmt
+ --bridge ovirtmgmt
virt-v2v -ic qemu:///system qemu_guest --in-place
@@ -62,7 +62,7 @@ interface(s) are connected to the target network called C<ovirtmgmt>.
-o rhv-upload -oc https://ovirt-engine.example.com/ovirt-engine/api \
-os ovirt-data -op /tmp/ovirt-admin-password \
-oo rhv-cafile=/tmp/ca.pem -oo rhv-direct \
- --network ovirtmgmt
+ --bridge ovirtmgmt
In this case the host running virt-v2v acts as a B<conversion server>.
@@ -1134,27 +1134,22 @@ guest’s Network Interface Cards (NICs):
NICs:
Network "default" mac: 52:54:00:d0:cf:0e
-This is typical of a libvirt guest: It has a single network interface
-connected to a network called C<default>.
-
-To map a specific network to a target network, for example C<default>
-on the source to C<ovirtmgmt> on the target, use:
-
- virt-v2v [...] --network default:ovirtmgmt
-
-To map every network to a target network, use:
-
- virt-v2v [...] --network ovirtmgmt
-
-Bridges are handled in the same way, but you have to use the
-I<--bridge> option instead. For example:
+Bridges are special classes of network devices which are attached to a
+named external network on the source hypervisor, for example:
$ virt-v2v [-i ...] --print-source name
[...]
NICs:
Bridge "br0"
-
- $ virt-v2v [...] --bridge br0:targetbr
+
+To map a specific bridge to a target network, for example C<br0> on
+the source to C<ovirtmgmt> on the target, use:
+
+ virt-v2v [...] --bridge br0:ovirtmgmt
+
+To map every bridge to a target network, use:
+
+ virt-v2v [...] --bridge ovirtmgmt
=head1 INPUT FROM VMWARE VCENTER SERVER
--
2.13.2
6 years, 7 months
[PATCH INCOMPLETE 0/4] v2v: Add general mechanism for input and output options.
by Richard W.M. Jones
This patch isn't quite complete (see ‘assert false’).
Currently we have a bunch of ad hoc options like --vddk* and --vdsm*
(and proposed to add --rhv*) to handle extra parameters for input and
output modes/transports. This complicates the command line parsing
and also the clarity of the command line (becauseit's not very obvious
which options apply to which side of the conversion).
Replace these with a general mechanism for handling input and output
options.
Thus (for example):
--vddk-thumbprint=... becomes -io vddk-thumbprint=...
--vdsm-compat=0.10 -oo vdsm-compat=0.10
The responsibility for parsing input and output options moves into the
input and output drivers.
This improves error checking so it's harder now for wrong flags to be
included on the command line when they don't apply to the current mode.
The old option names are preserved for compatibility.
Rich.
6 years, 7 months
[PATCH] tests: regressions: make test-big-heap use a temporary empty file
by Pino Toscano
Newer versions of qemu use file locking for the images by default, and
apparently that does not work with /dev/null. Since this test just
calls qemu-img to get the format of an empty image, create a temporary
one instead.
---
tests/regressions/test-big-heap.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/tests/regressions/test-big-heap.c b/tests/regressions/test-big-heap.c
index b841fba70..5c0948252 100644
--- a/tests/regressions/test-big-heap.c
+++ b/tests/regressions/test-big-heap.c
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#include <unistd.h>
#include "guestfs.h"
#include "guestfs-utils.h"
@@ -41,6 +42,8 @@ main (int argc, char *argv[])
const char *s;
guestfs_h *g;
char *mem, *fmt;
+ char tmpfile[32];
+ int tmpfilefd;
/* Allow the test to be skipped. */
s = getenv ("SKIP_TEST_BIG_HEAP");
@@ -50,6 +53,8 @@ main (int argc, char *argv[])
exit (77);
}
+ snprintf (tmpfile, sizeof tmpfile, "test-big-heap.XXXXXX");
+
/* Make sure we're using > 1GB in the main process. This test won't
* work on 32 bit platforms, because we can't allocate 2GB of
* contiguous memory. Therefore skip the test if the calloc call
@@ -68,10 +73,19 @@ main (int argc, char *argv[])
exit (77);
}
+ /* Create an empty temporary file for qemu-img. */
+ tmpfilefd = mkstemp (tmpfile);
+ if (tmpfilefd == -1) {
+ fprintf (stderr, "%s: mkstemp failed: %m\n", argv[0]);
+ exit (EXIT_FAILURE);
+ }
+ close (tmpfilefd);
+
g = guestfs_create ();
/* Do something which forks qemu-img subprocess. */
- fmt = guestfs_disk_format (g, "/dev/null");
+ fmt = guestfs_disk_format (g, tmpfile);
+ unlink (tmpfile);
if (fmt == NULL) {
/* Test failed. */
fprintf (stderr, "%s: unexpected failure of test, see earlier messages\n",
--
2.14.3
6 years, 7 months