Re: [Libguestfs] Debian 10 with libguestfs
by Richard W.M. Jones
On Tue, Aug 20, 2019 at 03:25:01PM +0200, Julian Hyordey wrote:
> If you want a test, let me know when it's done and I'll try it immediately.
OK it's uploaded. I have only boot tested it, but it
works for me.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top
5 years, 4 months
[PATCH 0/6] p2v: start making it independent
by Pino Toscano
As preliminary steps in splitting virt-p2v to an own repository,
start making p2v more independent within libguestfs. This is
accomplished by the following changes:
- generate the p2v kernel config sources & docs at build time using a
Perl script, rather than the generator (so no need for OCaml when
building from git, and no generated sources in dist tarballs)
- create two local test images: instead of a phony Windows image there
is a real Fedora guest, to avoid requiring hivex (for Windows) or more
copied phony test data (for Fedora)
- create an own .gitignore for p2v
This is still not complete, although it does a number of important
changes, and it still makes p2v usable within libguestfs.
Pino Toscano (6):
p2v: move kernel config to perl script
p2v: move kernel config POD docs to perl script
generator: remove p2v_config
p2v: split gitignore
p2v: tests: switch windows image with local fedora one
p2v: tests: use a local blank-part disk image
.gitignore | 37 --
configure.ac | 5 +
docs/C_SOURCE_FILES | 3 -
generator/Makefile.am | 3 -
generator/main.ml | 9 -
generator/p2v_config.ml | 835 --------------------------------
generator/p2v_config.mli | 22 -
p2v/.gitignore | 48 ++
p2v/Makefile.am | 36 +-
p2v/generate-p2v-config.pl | 915 ++++++++++++++++++++++++++++++++++++
p2v/test-virt-p2v-nbdkit.sh | 18 +-
p2v/test-virt-p2v-pxe.sh | 16 +-
p2v/test-virt-p2v.sh | 18 +-
13 files changed, 1014 insertions(+), 951 deletions(-)
delete mode 100644 generator/p2v_config.ml
delete mode 100644 generator/p2v_config.mli
create mode 100644 p2v/.gitignore
create mode 100755 p2v/generate-p2v-config.pl
--
2.21.0
5 years, 4 months
Re: [Libguestfs] Can virt-v2v-copy-to-local be used? (#41)
by Richard W.M. Jones
On Wed, Aug 21, 2019 at 12:13:52AM -0700, asmi10 wrote:
> Hello Currently I am using virt-v2v-copy-to-local on SLES for
> fetching disks from vmware ESXI hosts and converting them to kvm, it
> works fine so far. But I see this tool status is deprecated in
> github.
>
> Should I expect any possible issue with this tool?
It's kind of obsolete and I expect we'll remove it at some point.
There are several alternative methods that can be used.
If you just want to copy the disks, enable SSH access to your hosts
and simply scp them. You will have to copy the *.vmx and *.vmdk files
from under /vmfs/... These can be converted locally using the
virt-v2v -i vmx mode.
However even easier than that, virt-v2v -i vmx mode has a subflag -it
ssh which will copy and convert from ssh automatically (and more
efficiently too because it doesn't need to copy everything).
This is all covered in the virt-v2v-input-vmware(1) manual page.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top
5 years, 4 months
[nbdkit PATCH v2] main: Add option to disable SR advertisement
by Eric Blake
When we added support for .extents, we had nbdkit unconditionally
support structured replies if the client requests them, and the
plugin's .can_extents has no impact on what the server advertises.
However, while the plugin API doesn't care whether the client
requested SR, there are still integration situations where not
advertising SR can be useful (such as comparison on what a client does
with no block status vs. a block status that always reports
allocated). We already have the command line options -o/-n for
tweaking core server functionality; add --no-sr to the mix.
In particular, doing this found that 'qemu-nbd --list' from qemu 4.2
is rather picky: it hangs up on a server that replies with
NBD_REP_ERR_POLICY, rather than silently proceeding without SR support
(at least libnbd is more tolerant).
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Looks much different as a command line option instead of a hack to
the noextents filter, but I like the result a lot better.
I'm open to bike-shed opinions on the option name, or even if we want
to emulate a tri-state option --protocol=[old|no-sr|new] (with -o and
-n remaining synonyms for 2 of the 3 options for back-compat). I
purposefully did not burn a short-option letter on the new option, as
it is unlikely to be commonly needed.
docs/nbdkit-plugin.pod | 5 +++-
docs/nbdkit-protocol.pod | 21 ++++++++++++----
docs/nbdkit.pod | 12 ++++++++--
docs/synopsis.txt | 2 +-
server/internal.h | 1 +
server/options.h | 4 +++-
server/main.c | 5 ++++
server/protocol-handshake-newstyle.c | 14 +++++++++++
tests/test-eflags.sh | 36 ++++++++++++++++++++++++++++
9 files changed, 91 insertions(+), 9 deletions(-)
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index 423cccdb..bc3d9749 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -833,7 +833,10 @@ allocated, sparse and zeroed regions of the disk.
This function will not be called if C<.can_extents> returned false.
nbdkit's default behaviour in this case is to treat the whole virtual
-disk as if it was allocated.
+disk as if it was allocated. Also, this function will not be called
+by a client that does not request structured replies (the I<--no-sr>
+option of nbdkit can be used to test behavior when C<.extents> is
+unavailable to the client).
The callback should detect and return the list of extents overlapping
the range C<[offset...offset+count-1]>. The C<extents> parameter
diff --git a/docs/nbdkit-protocol.pod b/docs/nbdkit-protocol.pod
index ad470bd4..35db07b3 100644
--- a/docs/nbdkit-protocol.pod
+++ b/docs/nbdkit-protocol.pod
@@ -4,7 +4,7 @@ nbdkit - which parts of the NBD protocol nbdkit supports
=head1 SYNOPSIS
- nbdkit [-n|--newstyle] [-o|--oldstyle] [-e|--exportname EXPORTNAME]
+ nbdkit [-n|--newstyle] [--no-sr] [-o|--oldstyle] [-e|--exportname EXPORTNAME]
[...]
=head1 DESCRIPTION
@@ -21,11 +21,17 @@ be negotiated from the server side.
nbdkit defaults to the newstyle protocol since nbdkit E<ge> 1.3. The
newstyle protocol is better in every respect than the oldstyle
-protocol and you should prefer it if possible.
+protocol and you should prefer it if possible. The newstyle protocol
+also includes an extension where a client may request structured
+replies for even more capabilities, such as sparse reads or obtaining
+block status.
Use the I<-e> or I<--exportname> flag to set the optional exportname
for the newstyle protocol.
+Use the I<--no-sr> flag to force the newstyle protocol to decline any
+client request for structured replies.
+
Use the I<-o> or I<--oldstyle> flag to force the oldstyle protocol.
=head2 Common clients and the protocol they require
@@ -35,10 +41,13 @@ Use the I<-o> or I<--oldstyle> flag to force the oldstyle protocol.
qemu <= 2.5 without exportname oldstyle
qemu <= 2.5 with exportname newstyle
qemu >= 2.6 client can talk either protocol
+ qemu >= 2.11 client tries structured replies
nbd-client < 3.10 client can talk either protocol
- nbd-client >= 3.10 newstyle
+ nbd-client >= 3.10 newstyle, no structured replies
any TLS (encrypted) client newstyle
nbdkit nbd plugin client can talk either protocol
+ nbdkit >= 1.13.3 nbd plugin tries structured replies
+ libnbd either protocol, tries structured replies
=head2 Errors seen if using the wrong protocol
@@ -128,6 +137,10 @@ However we don’t expose the capability to send structured replies to
plugins yet, nor do we send human-readable error messages using this
facility.
+In nbdkit E<ge> 1.13.9>, the command-line option I<--no-rc> can be
+used to disable server support for structured replies, for testing
+client fallbacks.
+
=item Metadata Querying
Supported in nbdkit E<ge> 1.11.8.
@@ -182,4 +195,4 @@ Pino Toscano
=head1 COPYRIGHT
-Copyright (C) 2013-2018 Red Hat Inc.
+Copyright (C) 2013-2019 Red Hat Inc.
diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod
index 21a5207f..367a164d 100644
--- a/docs/nbdkit.pod
+++ b/docs/nbdkit.pod
@@ -264,10 +264,18 @@ For more details see L<nbdkit-service(1)/LOGGING>.
=item B<--newstyle>
-Use the newstyle NBD protocol protocol. This is the default in nbdkit
+Use the newstyle NBD protocol. This is the default in nbdkit
E<ge> 1.3. In earlier versions the default was oldstyle.
See L<nbdkit-protocol(1)>.
+=item B<--no-sr>
+
+Do not advertise structured replies. A client must request structured
+replies to take advantage of block status and potential sparse reads;
+however, as structured reads are not a mandatory part of the newstyle
+NBD protocol, this option can be used to debug client fallbacks for
+dealing with older servers. See L<nbdkit-protocol(1)>.
+
=item B<-o>
=item B<--old-style>
@@ -622,4 +630,4 @@ Pino Toscano
=head1 COPYRIGHT
-Copyright (C) 2013-2018 Red Hat Inc.
+Copyright (C) 2013-2019 Red Hat Inc.
diff --git a/docs/synopsis.txt b/docs/synopsis.txt
index 1a9d33d8..04cd136d 100644
--- a/docs/synopsis.txt
+++ b/docs/synopsis.txt
@@ -3,7 +3,7 @@ nbdkit [-D|--debug PLUGIN|FILTER.FLAG=N]
[--filter FILTER ...] [-f|--foreground]
[-g|--group GROUP] [-i|--ipaddr IPADDR]
[--log stderr|syslog]
- [-n|--newstyle] [-o|--oldstyle]
+ [-n|--newstyle] [--no-sr] [-o|--oldstyle]
[-P|--pidfile PIDFILE]
[-p|--port PORT] [-r|--readonly]
[--run CMD] [-s|--single] [--selinux-label LABEL]
diff --git a/server/internal.h b/server/internal.h
index 29a89606..22e13b6d 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -88,6 +88,7 @@ extern bool foreground;
extern const char *ipaddr;
extern enum log_to log_to;
extern bool newstyle;
+extern bool no_sr;
extern const char *port;
extern bool readonly;
extern const char *run;
diff --git a/server/options.h b/server/options.h
index 0be19f15..a69f413a 100644
--- a/server/options.h
+++ b/server/options.h
@@ -1,5 +1,5 @@
/* nbdkit
- * Copyright (C) 2013-2018 Red Hat Inc.
+ * Copyright (C) 2013-2019 Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -46,6 +46,7 @@ enum {
FILTER_OPTION,
LOG_OPTION,
LONG_OPTIONS_OPTION,
+ NO_SR_OPTION,
RUN_OPTION,
SELINUX_LABEL_OPTION,
SHORT_OPTIONS_OPTION,
@@ -75,6 +76,7 @@ static const struct option long_options[] = {
{ "long-options", no_argument, NULL, LONG_OPTIONS_OPTION },
{ "new-style", no_argument, NULL, 'n' },
{ "newstyle", no_argument, NULL, 'n' },
+ { "no-sr", no_argument, NULL, NO_SR_OPTION },
{ "old-style", no_argument, NULL, 'o' },
{ "oldstyle", no_argument, NULL, 'o' },
{ "pid-file", required_argument, NULL, 'P' },
diff --git a/server/main.c b/server/main.c
index 963a4871..65025a62 100644
--- a/server/main.c
+++ b/server/main.c
@@ -68,6 +68,7 @@ bool foreground; /* -f */
const char *ipaddr; /* -i */
enum log_to log_to = LOG_TO_DEFAULT; /* --log */
bool newstyle = true; /* false = -o, true = -n */
+bool no_sr; /* --no-sr */
char *pidfile; /* -P */
const char *port; /* -p */
bool readonly; /* -r */
@@ -341,6 +342,10 @@ main (int argc, char *argv[])
newstyle = true;
break;
+ case NO_SR_OPTION:
+ no_sr = true;
+ break;
+
case 'o':
newstyle = false;
break;
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index e0136de1..6ccb76f3 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -481,6 +481,17 @@ negotiate_handshake_newstyle_options (struct connection *conn)
debug ("newstyle negotiation: %s: client requested structured replies",
name_of_nbd_opt (option));
+ if (no_sr) {
+ /* Must fail with ERR_UNSUP for qemu 4.2 to remain happy;
+ * but failing with ERR_POLICY would have been nicer.
+ */
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
+ return -1;
+ debug ("newstyle negotiation: %s: structured replies are disabled",
+ name_of_nbd_opt (option));
+ break;
+ }
+
if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
return -1;
@@ -499,6 +510,9 @@ negotiate_handshake_newstyle_options (struct connection *conn)
if (conn_recv_full (conn, data, optlen, "read: %s: %m", optname) == -1)
return -1;
+ /* Note that we support base:allocation whether or not the plugin
+ * supports can_extents.
+ */
if (!conn->structured_replies) {
if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
== -1)
diff --git a/tests/test-eflags.sh b/tests/test-eflags.sh
index 6cc61631..f5cd43ed 100755
--- a/tests/test-eflags.sh
+++ b/tests/test-eflags.sh
@@ -87,6 +87,8 @@ fail ()
#----------------------------------------------------------------------
# can_write=false
+#
+# nbdkit supports DF if client requests SR.
do_nbdkit <<'EOF'
case "$1" in
@@ -98,6 +100,22 @@ EOF
[ $eflags -eq $(( HAS_FLAGS|READ_ONLY|SEND_DF )) ] ||
fail "$LINENO: expected HAS_FLAGS|READ_ONLY|SEND_DF"
+#----------------------------------------------------------------------
+# --no-sr
+# can_write=false
+#
+# When SR is disabled, so is the DF flag.
+
+do_nbdkit --no-sr <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY )) ] ||
+ fail "$LINENO: expected HAS_FLAGS|READ_ONLY"
+
#----------------------------------------------------------------------
# -r
# can_write=false
@@ -147,6 +165,24 @@ EOF
[ $eflags -eq $(( HAS_FLAGS|SEND_DF )) ] ||
fail "$LINENO: expected HAS_FLAGS|SEND_DF"
+#----------------------------------------------------------------------
+# --no=sr
+# --filter=nozero
+# can_write=true
+#
+# Absolute minimum in flags.
+
+do_nbdkit --no-sr --filter=nozero <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS )) ] ||
+ fail "$LINENO: expected HAS_FLAGS"
+
#----------------------------------------------------------------------
# -r
# can_write=true
--
2.21.0
5 years, 4 months
A libguestfs-test-tool output
by farzad azizsoltani
libguestfs: trace: set_verbose true
libguestfs: trace: set_verbose = 0
libguestfs: trace: set_verbose true
libguestfs: trace: set_verbose = 0
LIBGUESTFS_TRACE=1
LIBVIRT_DEFAULT_URI=qemu:///system
LIBGUESTFS_DEBUG=1
PATH=/home/farzad//.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
XDG_RUNTIME_DIR=/run/user/1000
SELinux: sh: 1: getenforce: not found
libguestfs: trace: add_drive_scratch 104857600
libguestfs: trace: get_tmpdir
libguestfs: trace: get_tmpdir = "/tmp"
libguestfs: trace: disk_create "/tmp/libguestfsf9YvJG/scratch1.img" "raw"
104857600
libguestfs: trace: disk_create = 0
libguestfs: trace: add_drive "/tmp/libguestfsf9YvJG/scratch1.img"
"format:raw" "cachemode:unsafe"
libguestfs: trace: add_drive = 0
libguestfs: trace: add_drive_scratch = 0
libguestfs: trace: get_append
libguestfs: trace: get_append = "NULL"
guestfs_get_append: (null)
libguestfs: trace: get_autosync
libguestfs: trace: get_autosync = 1
guestfs_get_autosync: 1
libguestfs: trace: get_backend
libguestfs: trace: get_backend = "direct"
guestfs_get_backend: direct
libguestfs: trace: get_backend_settings
libguestfs: trace: get_backend_settings = []
guestfs_get_backend_settings: []
libguestfs: trace: get_cachedir
libguestfs: trace: get_cachedir = "/var/tmp"
guestfs_get_cachedir: /var/tmp
libguestfs: trace: get_direct
libguestfs: trace: get_direct = 0
guestfs_get_direct: 0
libguestfs: trace: get_hv
libguestfs: trace: get_hv = "/usr/bin/qemu-system-x86_64"
guestfs_get_hv: /usr/bin/qemu-system-x86_64
libguestfs: trace: get_memsize
libguestfs: trace: get_memsize = 500
guestfs_get_memsize: 500
libguestfs: trace: get_network
libguestfs: trace: get_network = 0
guestfs_get_network: 0
libguestfs: trace: get_path
libguestfs: trace: get_path = "/usr/lib/x86_64-linux-gnu/guestfs"
guestfs_get_path: /usr/lib/x86_64-linux-gnu/guestfs
libguestfs: trace: get_pgroup
libguestfs: trace: get_pgroup = 0
guestfs_get_pgroup: 0
libguestfs: trace: get_program
libguestfs: trace: get_program = "libguestfs-test-tool"
guestfs_get_program: libguestfs-test-tool
libguestfs: trace: get_recovery_proc
libguestfs: trace: get_recovery_proc = 1
guestfs_get_recovery_proc: 1
libguestfs: trace: get_smp
libguestfs: trace: get_smp = 1
guestfs_get_smp: 1
libguestfs: trace: get_sockdir
libguestfs: trace: get_sockdir = "/run/user/1000"
guestfs_get_sockdir: /run/user/1000
libguestfs: trace: get_tmpdir
libguestfs: trace: get_tmpdir = "/tmp"
guestfs_get_tmpdir: /tmp
libguestfs: trace: get_trace
libguestfs: trace: get_trace = 1
guestfs_get_trace: 1
libguestfs: trace: get_verbose
libguestfs: trace: get_verbose = 1
guestfs_get_verbose: 1
host_cpu: x86_64
Launching appliance, timeout set to 600 seconds.
libguestfs: trace: launch
libguestfs: trace: version
libguestfs: trace: version = <struct guestfs_version = major: 1, minor: 36,
release: 13, extra: , >
libguestfs: trace: get_backend
libguestfs: trace: get_backend = "direct"
libguestfs: launch: program=libguestfs-test-tool
libguestfs: launch: version=1.36.13
libguestfs: launch: backend registered: unix
libguestfs: launch: backend registered: uml
libguestfs: launch: backend registered: libvirt
libguestfs: launch: backend registered: direct
libguestfs: launch: backend=direct
libguestfs: launch: tmpdir=/tmp/libguestfsf9YvJG
libguestfs: launch: umask=0002
libguestfs: launch: euid=1000
libguestfs: trace: get_backend_setting "force_tcg"
libguestfs: trace: get_backend_setting = NULL (error)
libguestfs: trace: get_cachedir
libguestfs: trace: get_cachedir = "/var/tmp"
libguestfs: begin building supermin appliance
libguestfs: run supermin
libguestfs: command: run: /usr/bin/supermin
libguestfs: command: run: \ --build
libguestfs: command: run: \ --verbose
libguestfs: command: run: \ --if-newer
libguestfs: command: run: \ --lock /var/tmp/.guestfs-1000/lock
libguestfs: command: run: \ --copy-kernel
libguestfs: command: run: \ -f ext2
libguestfs: command: run: \ --host-cpu x86_64
libguestfs: command: run: \ /usr/lib/x86_64-linux-gnu/guestfs/supermin.d
libguestfs: command: run: \ -o /var/tmp/.guestfs-1000/appliance.d
supermin: version: 5.1.19
supermin: package handler: debian/dpkg
supermin: acquiring lock on /var/tmp/.guestfs-1000/lock
supermin: build: /usr/lib/x86_64-linux-gnu/guestfs/supermin.d
supermin: reading the supermin appliance
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/base.tar.gz type gzip base
image (tar)
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/daemon.tar.gz type gzip base
image (tar)
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/excludefiles type uncompressed
excludefiles
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/hostfiles type uncompressed
hostfiles
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/init.tar.gz type gzip base
image (tar)
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/packages type uncompressed
packages
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/packages-hfsplus type
uncompressed packages
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/packages-reiserfs type
uncompressed packages
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/packages-xfs type uncompressed
packages
supermin: build: visiting
/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/udev-rules.tar.gz type gzip
base image (tar)
supermin: mapping package names to installed packages
supermin: resolving full list of package dependencies
supermin: build: 213 packages, including dependencies
supermin: build: 9947 files
supermin: build: 6727 files, after matching excludefiles
supermin: build: 6738 files, after adding hostfiles
supermin: build: 6735 files, after removing unreadable files
supermin: build: 6738 files, after munging
supermin: kernel: looking for kernel using environment variables ...
supermin: kernel: looking for kernels in /lib/modules/*/vmlinuz ...
supermin: kernel: looking for kernels in /boot ...
supermin: kernel: kernel version of /boot/vmlinuz-5.0.0-25-generic =
5.0.0-25-generic (from filename)
supermin: kernel: picked modules path /lib/modules/5.0.0-25-generic
supermin: kernel: kernel version of /boot/vmlinuz-5.0.0-23-generic =
5.0.0-23-generic (from filename)
supermin: kernel: picked modules path /lib/modules/5.0.0-23-generic
supermin: kernel: picked vmlinuz /boot/vmlinuz-5.0.0-25-generic
supermin: kernel: kernel_version 5.0.0-25-generic
supermin: kernel: modpath /lib/modules/5.0.0-25-generic
cp: cannot open '/boot/vmlinuz-5.0.0-25-generic' for reading: Permission
denied
supermin: cp -p '/boot/vmlinuz-5.0.0-25-generic'
'/var/tmp/.guestfs-1000/appliance.d.2qibquc6/kernel': command failed, see
earlier errors
libguestfs: error: /usr/bin/supermin exited with error status 1, see debug
messages above
libguestfs: trace: launch = -1 (error)
libguestfs: trace: close
libguestfs: closing guestfs handle 0x55c38943c140 (state 0)
libguestfs: command: run: rm
libguestfs: command: run: \ -rf /tmp/libguestfsf9YvJG
5 years, 4 months
[nbdkit PATCH 0/2] rust: Implement some missing v2 callbacks
by Eric Blake
Similar to what I just did for OCaml (this IS an API break, requiring
recompilation of any existing Rust plugin), and done because I want to
add fast_zero support to both languages as part of my upcoming fast
zero series.
Figuring out how to get extents working was hard enough that I punted
that, still.
Eric Blake (2):
rust: Implement can_cache
rust: Add support for dynamic .thread_model
plugins/rust/nbdkit-rust-plugin.pod | 29 ++++++++++++++++++++++++-----
plugins/rust/examples/ramdisk.rs | 8 ++++++--
plugins/rust/src/lib.rs | 23 ++++++++++++++++++++---
3 files changed, 50 insertions(+), 10 deletions(-)
--
2.20.1
5 years, 4 months
Re: [Libguestfs] Debian 10 with libguestfs
by Richard W.M. Jones
On Tue, Aug 20, 2019 at 03:07:13PM +0200, Julian Hyordey wrote:
> I'd like to know if you are planning to release soon Debian 10 with
> libguestfs (using virt-builder), if so, approximatively when ?
Yes, you're the second person who's asked in fact. It's building
now, so if it doesn't fail then it should be uploaded by end today.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top
5 years, 4 months
[nbdkit PATCH] noextents: Add hook to cripple SR advertisement
by Eric Blake
When we added support for .extents, we had nbdkit unconditionally
support structured replies if the client requests them, and the
plugin's .can_extents has no impact on what the server advertises.
However, while the plugin API doesn't care whether the client
requested SR, there is still a case to be made for allowing a filter
to prevent SR, at least for testing purposese (such as comparison on
what a client does with no block status vs. a block status that always
reports allocated). Enhance the filter API to allow an SR inhibit,
and wire up the existing noextents filter to expose this option.
In particular, doing this found that 'qemu-nbd --list' from qemu 4.2
is rather picky: it hangs up on a server that replies with
NBD_REP_ERR_POLICY, rather than silently proceeding without SR support
(at least libnbd is more tolerant).
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
docs/nbdkit-filter.pod | 22 ++++++++++++
filters/noextents/nbdkit-noextents-filter.pod | 17 ++++++---
server/internal.h | 1 +
server/filters.c | 24 +++++++++++++
server/plugins.c | 12 +++++++
server/protocol-handshake-newstyle.c | 18 ++++++++++
server/protocol-handshake.c | 11 +++---
include/nbdkit-filter.h | 3 ++
filters/noextents/noextents.c | 28 +++++++++++++++
TODO | 4 ++-
tests/test-eflags.sh | 36 +++++++++++++++++++
11 files changed, 167 insertions(+), 9 deletions(-)
diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index 6e2bea61..cd8ba255 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -419,4 +419,26 @@ 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_sr>
+
+ int (*can_sr) (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle);
+
+This function exists to allow a filter to prevent a client from seeing
+support for structured replies, which in turn prevents clients from
+attempting sparse reads or querying extents. This function has no
+counterpart in plugins, because none of the version 2 API callbacks
+change semantics based on whether the client requested structured
+replies (the C<.extents> callback can still be used by filters
+regardless of whether the client enables structured replies or
+requests the "base:allocation" context for querying extents).
+
+If there is an error, the callback should call C<nbdkit_error> with an
+error message and return C<-1>. If this function is called more than
+once for the same connection, it should return the same value;
+similarly, the filter may cache the result of the counterpart in
+C<next_ops> for a given connection rather than repeating calls.
+
+This function is optional, and defaults to true if omitted.
+
=head2 C<.pread>
int (*pread) (struct nbdkit_next_ops *next_ops, void *nxdata,
diff --git a/filters/noextents/nbdkit-noextents-filter.pod b/filters/noextents/nbdkit-noextents-filter.pod
index 47223928..1a74e203 100644
--- a/filters/noextents/nbdkit-noextents-filter.pod
+++ b/filters/noextents/nbdkit-noextents-filter.pod
@@ -11,7 +11,8 @@ nbdkit-noextents-filter - disable extents in the underlying plugin
“Extents” are a feature of the NBD protocol / nbdkit which allow the
client to detect sparse regions of the underlying disk.
C<nbdkit-noextents-filter> disables this so that the plugin appears to
-be fully allocated.
+be fully allocated. The effects of this filter are only observable
+from a client which is able to request structured replies.
This filter can be useful when combined with L<nbdkit-file-plugin(1)>
serving a file from a file system known to have poor C<lseek(2)>
@@ -19,9 +20,17 @@ performance (C<tmpfs> is known to be one such system).
=head1 PARAMETERS
-There are no parameters specific to nbdkit-noextents-filter. Any
-parameters are passed through to and processed by the underlying
-plugin in the normal way.
+=over 4
+
+=item B<structured=false>
+
+Controls whether a client can request structured replies, which are a
+pre-requisite for supporting sparse reads and extent queries. The
+parameter defaults to true (so that a client that requests extent
+support sees a fully-allocated image), but can be set to false to
+force the client to be unable to query extents at all.
+
+=back
=head1 SEE ALSO
diff --git a/server/internal.h b/server/internal.h
index 29a89606..c115c50f 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -274,6 +274,7 @@ struct backend {
int (*is_rotational) (struct backend *, struct connection *conn);
int (*can_trim) (struct backend *, struct connection *conn);
int (*can_zero) (struct backend *, struct connection *conn);
+ int (*can_sr) (struct backend *, struct connection *conn);
int (*can_extents) (struct backend *, struct connection *conn);
int (*can_fua) (struct backend *, struct connection *conn);
int (*can_multi_conn) (struct backend *, struct connection *conn);
diff --git a/server/filters.c b/server/filters.c
index 14ca0cc6..17403e89 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -314,6 +314,13 @@ next_can_zero (void *nxdata)
return b_conn->b->can_zero (b_conn->b, b_conn->conn);
}
+static int
+next_can_sr (void *nxdata)
+{
+ struct b_conn *b_conn = nxdata;
+ return b_conn->b->can_sr (b_conn->b, b_conn->conn);
+}
+
static int
next_can_extents (void *nxdata)
{
@@ -442,6 +449,7 @@ static struct nbdkit_next_ops next_ops = {
.is_rotational = next_is_rotational,
.can_trim = next_can_trim,
.can_zero = next_can_zero,
+ .can_sr = next_can_sr,
.can_extents = next_can_extents,
.can_fua = next_can_fua,
.can_multi_conn = next_can_multi_conn,
@@ -586,6 +594,21 @@ filter_can_zero (struct backend *b, struct connection *conn)
return f->backend.next->can_zero (f->backend.next, conn);
}
+static int
+filter_can_sr (struct backend *b, struct connection *conn)
+{
+ struct backend_filter *f = container_of (b, struct backend_filter, backend);
+ void *handle = connection_get_handle (conn, f->backend.i);
+ struct b_conn nxdata = { .b = f->backend.next, .conn = conn };
+
+ debug ("%s: can_sr", f->name);
+
+ if (f->filter.can_sr)
+ return f->filter.can_sr (&next_ops, &nxdata, handle);
+ else
+ return f->backend.next->can_sr (f->backend.next, conn);
+}
+
static int
filter_can_extents (struct backend *b, struct connection *conn)
{
@@ -818,6 +841,7 @@ static struct backend filter_functions = {
.is_rotational = filter_is_rotational,
.can_trim = filter_can_trim,
.can_zero = filter_can_zero,
+ .can_sr = filter_can_sr,
.can_extents = filter_can_extents,
.can_fua = filter_can_fua,
.can_multi_conn = filter_can_multi_conn,
diff --git a/server/plugins.c b/server/plugins.c
index e217e6b8..d83af78a 100644
--- a/server/plugins.c
+++ b/server/plugins.c
@@ -401,6 +401,17 @@ plugin_can_zero (struct backend *b, struct connection *conn)
return plugin_can_write (b, conn);
}
+static int
+plugin_can_sr (struct backend *b, struct connection *conn)
+{
+ /* Nothing in the v2 API depends on whether the client uses or
+ * avoids structured replies; .extents is still useful to filters
+ * even without SR. So this is hard-coded to true, with no exposure
+ * to the plugin interface; only filters can change it.
+ */
+ return 1;
+}
+
static int
plugin_can_extents (struct backend *b, struct connection *conn)
{
@@ -761,6 +772,7 @@ static struct backend plugin_functions = {
.is_rotational = plugin_is_rotational,
.can_trim = plugin_can_trim,
.can_zero = plugin_can_zero,
+ .can_sr = plugin_can_sr,
.can_extents = plugin_can_extents,
.can_fua = plugin_can_fua,
.can_multi_conn = plugin_can_multi_conn,
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index e0136de1..518de703 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -233,6 +233,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
char data[MAX_OPTION_LENGTH+1];
struct new_handshake_finish handshake_finish;
const char *optname;
+ int r;
for (nr_options = 0; nr_options < MAX_NR_OPTIONS; ++nr_options) {
if (conn_recv_full (conn, &new_option, sizeof new_option,
@@ -481,6 +482,20 @@ negotiate_handshake_newstyle_options (struct connection *conn)
debug ("newstyle negotiation: %s: client requested structured replies",
name_of_nbd_opt (option));
+ r = backend->can_sr (backend, conn);
+ if (r == -1)
+ return -1;
+ if (!r) {
+ /* Must fail with ERR_UNSUP for qemu 4.2 to remain happy;
+ * but failing with ERR_POLICY would have been nicer.
+ */
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
+ return -1;
+ debug ("newstyle negotiation: %s: filter disabled structured replies",
+ name_of_nbd_opt (option));
+ break;
+ }
+
if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
return -1;
@@ -499,6 +514,9 @@ negotiate_handshake_newstyle_options (struct connection *conn)
if (conn_recv_full (conn, data, optlen, "read: %s: %m", optname) == -1)
return -1;
+ /* Note that we support base:allocation whether or not the plugin
+ * supports can_extents.
+ */
if (!conn->structured_replies) {
if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
== -1)
diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c
index 0f3bd280..2cd9f01f 100644
--- a/server/protocol-handshake.c
+++ b/server/protocol-handshake.c
@@ -122,10 +122,13 @@ protocol_compute_eflags (struct connection *conn, uint16_t *flags)
conn->emulate_cache = fl == NBDKIT_CACHE_EMULATE;
}
- /* The result of this is not returned to callers here (or at any
- * time during the handshake). However it makes sense to do it once
- * per connection and store the result in the handle anyway. This
- * protocol_compute_eflags function is a bit misnamed XXX.
+ /* The result of this is not returned to callers here (in fact,
+ * earlier in the handshake, we unconditionally advertise
+ * base:allocation support to a client that asks). However it makes
+ * sense to learn once per connection whether filters can use
+ * extents, regardless of whether the client will do so, so store
+ * the result in the handle anyway. This protocol_compute_eflags
+ * function is a bit misnamed XXX.
*/
fl = backend->can_extents (backend, conn);
if (fl == -1)
diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h
index 94f17789..83ff3aae 100644
--- a/include/nbdkit-filter.h
+++ b/include/nbdkit-filter.h
@@ -71,6 +71,7 @@ struct nbdkit_next_ops {
int (*is_rotational) (void *nxdata);
int (*can_trim) (void *nxdata);
int (*can_zero) (void *nxdata);
+ int (*can_sr) (void *nxdata);
int (*can_extents) (void *nxdata);
int (*can_fua) (void *nxdata);
int (*can_multi_conn) (void *nxdata);
@@ -139,6 +140,8 @@ struct nbdkit_filter {
void *handle);
int (*can_zero) (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle);
+ int (*can_sr) (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle);
int (*can_extents) (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle);
int (*can_fua) (struct nbdkit_next_ops *next_ops, void *nxdata,
diff --git a/filters/noextents/noextents.c b/filters/noextents/noextents.c
index e39723cd..c95b7e53 100644
--- a/filters/noextents/noextents.c
+++ b/filters/noextents/noextents.c
@@ -32,8 +32,33 @@
#include <config.h>
+#include <string.h>
+
#include <nbdkit-filter.h>
+/* Whether to permit SR */
+static int structured = 1;
+
+static int
+noextents_config (nbdkit_next_config *next, void *nxdata,
+ const char *key, const char *value)
+{
+ if (strcmp (key, "structured") == 0)
+ return structured = nbdkit_parse_bool (value);
+
+ return next (nxdata, key, value);
+}
+
+#define noextents_config_help \
+ "structured=<BOOL> Set to false to inhibit structured replies (default true).\n"
+
+static int
+noextents_can_sr (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle)
+{
+ return structured;
+}
+
static int
noextents_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle)
@@ -45,6 +70,9 @@ static struct nbdkit_filter filter = {
.name = "noextents",
.longname = "nbdkit noextents filter",
.version = PACKAGE_VERSION,
+ .config = noextents_config,
+ .config_help = noextents_config_help,
+ .can_sr = noextents_can_sr,
.can_extents = noextents_can_extents,
};
diff --git a/TODO b/TODO
index 332400b3..87621791 100644
--- a/TODO
+++ b/TODO
@@ -198,4 +198,5 @@ using ‘#define NBDKIT_API_VERSION <version>’.
that supports .extents, the v2 protocol would allow us to at least
synthesize NBD_REPLY_TYPE_OFFSET_HOLE for less network traffic, even
though the plugin will still have to fully populate the .pread
- buffer; the v3 protocol should make sparse reads more direct.
+ buffer; the v3 protocol should make sparse reads more direct. Also,
+ the filter callback .can_sr may make sense for a v3 plugin.
* Parameters should be systematized so that they aren't just (key,
value) strings. nbdkit should know the possible keys for the plugin
diff --git a/tests/test-eflags.sh b/tests/test-eflags.sh
index b3724170..7a064bbb 100755
--- a/tests/test-eflags.sh
+++ b/tests/test-eflags.sh
@@ -87,6 +87,8 @@ fail ()
#----------------------------------------------------------------------
# can_write=false
+#
+# nbdkit supports DF if client requests SR.
do_nbdkit <<'EOF'
case "$1" in
@@ -98,6 +100,22 @@ EOF
[ $eflags -eq $(( HAS_FLAGS|READ_ONLY|SEND_DF )) ] ||
fail "expected HAS_FLAGS|READ_ONLY|SEND_DF"
+#----------------------------------------------------------------------
+# --filter=noextents structured=false
+# can_write=false
+#
+# The noextents filter can force no SR, and thus no DF.
+
+late_args="structured=false" do_nbdkit --filter=noextents <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY )) ] ||
+ fail "expected HAS_FLAGS|READ_ONLY"
+
#----------------------------------------------------------------------
# -r
# can_write=false
@@ -147,6 +165,24 @@ EOF
[ $eflags -eq $(( HAS_FLAGS|SEND_DF )) ] ||
fail "expected HAS_FLAGS|SEND_DF"
+#----------------------------------------------------------------------
+# --filter=nozero
+# --filter=noextents structured=false
+# can_write=true
+#
+# Absolute minimum in flags.
+
+late_args="structured=false" do_nbdkit --filter=nozero --filter=noextents <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS )) ] ||
+ fail "expected HAS_FLAGS"
+
#----------------------------------------------------------------------
# -r
# can_write=true
--
2.20.1
5 years, 4 months
[nbdkit PATCH] ocaml: Map more errno values
by Eric Blake
Mapping of EOVERFLOW was missed in commit 6f8c8084.
Mapping of EOPNOTSUPP is essential for .zero to trigger a fallback to
.pwrite, missed in commit 6c0e00e9 (not to mention that it becomes a
valid protocol failure once fast zero support is added). There is no
Unix.ENOTSUP, or that would get the same treatment per commit
abb2b47c.
Preserving EROFS and EFBIG is useful because protocol.c special-cases
those (by merging them into EPERM and ENOSPC over the wire). There is
no Unix.EDQUOT, or that would get the same treatment.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
plugins/ocaml/ocaml.c | 7 +++++++
plugins/ocaml/NBDKit.ml | 4 ++++
2 files changed, 11 insertions(+)
diff --git a/plugins/ocaml/ocaml.c b/plugins/ocaml/ocaml.c
index 064cdedb..5161775f 100644
--- a/plugins/ocaml/ocaml.c
+++ b/plugins/ocaml/ocaml.c
@@ -849,12 +849,19 @@ ocaml_nbdkit_set_error (value nv)
int err;
switch (Int_val (nv)) {
+ /* On-the-wire values */
case 1: err = EPERM; break;
case 2: err = EIO; break;
case 3: err = ENOMEM; break;
case 4: err = EINVAL; break;
case 5: err = ENOSPC; break;
case 6: err = ESHUTDOWN; break;
+ case 7: err = EOVERFLOW; break;
+ /* Necessary for .zero support */
+ case 8: err = ENOTSUP; break;
+ /* Other errno that server/protocol.c treats specially */
+ case 9: err = EROFS; break;
+ case 10: err = EFBIG; break;
default: abort ();
}
diff --git a/plugins/ocaml/NBDKit.ml b/plugins/ocaml/NBDKit.ml
index 68d15836..e54a7705 100644
--- a/plugins/ocaml/NBDKit.ml
+++ b/plugins/ocaml/NBDKit.ml
@@ -267,6 +267,10 @@ let set_error unix_error =
| Unix.EINVAL -> 4
| Unix.ENOSPC -> 5
| Unix.ESHUTDOWN -> 6
+ | Unix.EOVERFLOW -> 7
+ | Unix.EOPNOTSUPP -> 8
+ | Unix.EROFS -> 9
+ | Unix.EFBIG -> 10
| _ -> 4 (* EINVAL *) in
_set_error nbd_error
--
2.20.1
5 years, 4 months
[nbdkit PATCH] ocaml: Add support for dynamic .thread_model
by Eric Blake
We do not promise API stability for non-C languages; this is an API
break as follows: instead of calling 'NBDKit.register_plugin model
plugin' with a static model, you can now add .thread_model :(unit ->
thread_model) to plugin or default to PARALLEL.
Since all existing OCaml plugins will have already thought about
thread models, they can convert their existing model into the new
plugin field (and thus, I don't feel too bad making PARALLEL the
default, even if it is not always the safest).
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
I'm still looking at two followups:
1) ./nbdkit doesn't set LD_LIBRARY_PATH=plugins/ocaml/.libs:$LD_LIBRARY_PATH
(making ./nbdkit --dump-plugin tests/test-ocaml-plugin.so fail to load
when the system nbdkit is too old)
2) although --dump-plugin shows thread model, ./nbdkit -v log does not;
I need to add a debug() statement for that in server/locks.c
But I was quite pleased that I got this working in under 3 hours (I'm
getting better at OCaml).
plugins/ocaml/nbdkit-ocaml-plugin.pod | 13 ++++++-----
plugins/ocaml/ocaml.c | 33 +++++++++++++++++++++------
plugins/ocaml/NBDKit.ml | 28 ++++++++++++++---------
plugins/ocaml/NBDKit.mli | 19 ++++++++-------
plugins/ocaml/example.ml | 9 +++++---
tests/test_ocaml_plugin.ml | 5 ++--
6 files changed, 69 insertions(+), 38 deletions(-)
diff --git a/plugins/ocaml/nbdkit-ocaml-plugin.pod b/plugins/ocaml/nbdkit-ocaml-plugin.pod
index a66cf26e..4b349612 100644
--- a/plugins/ocaml/nbdkit-ocaml-plugin.pod
+++ b/plugins/ocaml/nbdkit-ocaml-plugin.pod
@@ -36,12 +36,11 @@ Your OCaml code should call C<NBDKit.register_plugin> like this:
open_connection = Some myplugin_open;
get_size = Some myplugin_get_size;
pread = Some myplugin_pread;
+ thread_model = Some (fun () -> NBDKit.THREAD_MODEL_SERIALIZE_CONNECTIONS);
(* etc *)
}
- let thread_model = NBDKit.THREAD_MODEL_SERIALIZE_CONNECTIONS
-
- let () = NBDKit.register_plugin thread_model plugin
+ let () = NBDKit.register_plugin plugin
Your plugin must call C<register_plugin> exactly once when the plugin
is loaded.
@@ -108,9 +107,11 @@ to control this.
=head2 Threads
-The first parameter of C<NBDKit.register_plugin> is the thread model,
-which can be one of the values in the table below. For more
-information on thread models, see L<nbdkit-plugin(3)/THREADS>. Note
+One of the members in the plugin record passed to
+C<NBDKit.register_plugin> is C<thread model>, which must return one of
+the values in the table below. For more information on thread models,
+see L<nbdkit-plugin(3)/THREADS>. If this optional function is not
+provided, the thread model defaults to THREAD_MODEL_PARALLEL. Note
that because of the garbage collector lock in OCaml, callbacks are
never truly concurrent.
diff --git a/plugins/ocaml/ocaml.c b/plugins/ocaml/ocaml.c
index f664a7fb..01f4448f 100644
--- a/plugins/ocaml/ocaml.c
+++ b/plugins/ocaml/ocaml.c
@@ -72,6 +72,7 @@ static void remove_roots (void);
static struct nbdkit_plugin plugin = {
._struct_size = sizeof (plugin),
._api_version = NBDKIT_API_VERSION,
+ ._thread_model = NBDKIT_THREAD_MODEL_PARALLEL,
/* The following field is used as a canary to detect whether the
* OCaml code started up and called us back successfully. If it's
@@ -131,6 +132,8 @@ static value extents_fn;
static value can_cache_fn;
static value cache_fn;
+static value thread_model_fn;
+
/*----------------------------------------------------------------------*/
/* Wrapper functions that translate calls from C (ie. nbdkit) to OCaml. */
@@ -683,18 +686,30 @@ cache_wrapper (void *h, uint32_t count, uint64_t offset, uint32_t flags)
CAMLreturnT (int, 0);
}
+static int
+thread_model_wrapper (void)
+{
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ caml_leave_blocking_section ();
+
+ rv = caml_callback_exn (config_complete_fn, Val_unit);
+ if (Is_exception_result (rv)) {
+ nbdkit_error ("%s", caml_format_exception (Extract_exception (rv)));
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, -1);
+ }
+
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, Int_val (rv));
+}
+
/*----------------------------------------------------------------------*/
/* set_* functions called from OCaml code at load time to initialize
* fields in the plugin struct.
*/
-value
-ocaml_nbdkit_set_thread_model (value modelv)
-{
- plugin._thread_model = Int_val (modelv);
- return Val_unit;
-}
-
value
ocaml_nbdkit_set_name (value namev)
{
@@ -775,6 +790,8 @@ SET(extents)
SET(can_cache)
SET(cache)
+SET(thread_model)
+
#undef SET
static void
@@ -817,6 +834,8 @@ remove_roots (void)
REMOVE (can_cache);
REMOVE (cache);
+ REMOVE (thread_model);
+
#undef REMOVE
}
diff --git a/plugins/ocaml/NBDKit.ml b/plugins/ocaml/NBDKit.ml
index 02aa2001..57e57a46 100644
--- a/plugins/ocaml/NBDKit.ml
+++ b/plugins/ocaml/NBDKit.ml
@@ -1,3 +1,4 @@
+(* hey emacs, this is OCaml code: -*- tuareg -*- *)
(* nbdkit OCaml interface
* Copyright (C) 2014-2019 Red Hat Inc.
*
@@ -39,6 +40,12 @@ type fua_flag = FuaNone | FuaEmulate | FuaNative
type cache_flag = CacheNone | CacheEmulate | CacheNop
+type thread_model =
+| THREAD_MODEL_SERIALIZE_CONNECTIONS
+| THREAD_MODEL_SERIALIZE_ALL_REQUESTS
+| THREAD_MODEL_SERIALIZE_REQUESTS
+| THREAD_MODEL_PARALLEL
+
type extent = {
offset : int64;
length : int64;
@@ -87,6 +94,8 @@ type 'a plugin = {
can_cache : ('a -> cache_flag) option;
cache : ('a -> int32 -> int64 -> flags -> unit) option;
+
+ thread_model : (unit -> thread_model) option;
}
let default_callbacks = {
@@ -130,16 +139,10 @@ let default_callbacks = {
can_cache = None;
cache = None;
+
+ thread_model = None;
}
-type thread_model =
-| THREAD_MODEL_SERIALIZE_CONNECTIONS
-| THREAD_MODEL_SERIALIZE_ALL_REQUESTS
-| THREAD_MODEL_SERIALIZE_REQUESTS
-| THREAD_MODEL_PARALLEL
-
-external set_thread_model : int -> unit = "ocaml_nbdkit_set_thread_model" "noalloc"
-
external set_name : string -> unit = "ocaml_nbdkit_set_name" "noalloc"
external set_longname : string -> unit = "ocaml_nbdkit_set_longname" "noalloc"
external set_version : string -> unit = "ocaml_nbdkit_set_version" "noalloc"
@@ -181,9 +184,11 @@ external set_extents : ('a -> int32 -> int64 -> flags -> extent list) -> unit =
external set_can_cache : ('a -> cache_flag) -> unit = "ocaml_nbdkit_set_can_cache"
external set_cache : ('a -> int32 -> int64 -> flags -> unit) -> unit = "ocaml_nbdkit_set_cache"
+external set_thread_model : (unit -> thread_model) -> unit = "ocaml_nbdkit_set_thread_model" "noalloc"
+
let may f = function None -> () | Some a -> f a
-let register_plugin thread_model plugin =
+let register_plugin plugin =
(* Check the required fields have been set by the caller. *)
if plugin.name = "" then
failwith "'.name' field in NBDKit.plugin structure must be set";
@@ -198,7 +203,6 @@ let register_plugin thread_model plugin =
plugin.name);
(* Set the fields in the C code. *)
- set_thread_model (Obj.magic thread_model);
set_name plugin.name;
if plugin.longname <> "" then
@@ -243,7 +247,9 @@ let register_plugin thread_model plugin =
may set_extents plugin.extents;
may set_can_cache plugin.can_cache;
- may set_cache plugin.cache
+ may set_cache plugin.cache;
+
+ may set_thread_model plugin.thread_model
external _set_error : int -> unit = "ocaml_nbdkit_set_error" "noalloc"
diff --git a/plugins/ocaml/NBDKit.mli b/plugins/ocaml/NBDKit.mli
index bab8f7f6..778250ef 100644
--- a/plugins/ocaml/NBDKit.mli
+++ b/plugins/ocaml/NBDKit.mli
@@ -1,3 +1,4 @@
+(* hey emacs, this is OCaml code: -*- tuareg -*- *)
(* nbdkit OCaml interface
* Copyright (C) 2014-2019 Red Hat Inc.
*
@@ -50,6 +51,13 @@ type extent = {
}
(** The type of the extent list returned by [.extents]. *)
+type thread_model =
+| THREAD_MODEL_SERIALIZE_CONNECTIONS
+| THREAD_MODEL_SERIALIZE_ALL_REQUESTS
+| THREAD_MODEL_SERIALIZE_REQUESTS
+| THREAD_MODEL_PARALLEL
+(** The type of the thread model returned by [.thread_model]. *)
+
type 'a plugin = {
name : string; (* required *)
longname : string;
@@ -91,6 +99,8 @@ type 'a plugin = {
can_cache : ('a -> cache_flag) option;
cache : ('a -> int32 -> int64 -> flags -> unit) option;
+
+ thread_model : (unit -> thread_model) option;
}
(** The plugin fields and callbacks. ['a] is the handle type. *)
@@ -98,14 +108,7 @@ val default_callbacks : 'a plugin
(** The plugin with all fields set to [None], so you can write
[{ defaults_callbacks with field1 = Some foo1; field2 = Some foo2 }] *)
-type thread_model =
-| THREAD_MODEL_SERIALIZE_CONNECTIONS
-| THREAD_MODEL_SERIALIZE_ALL_REQUESTS
-| THREAD_MODEL_SERIALIZE_REQUESTS
-| THREAD_MODEL_PARALLEL
-(** The thread model. *)
-
-val register_plugin : thread_model -> 'a plugin -> unit
+val register_plugin : 'a plugin -> unit
(** Register the plugin with nbdkit. *)
val set_error : Unix.error -> unit
diff --git a/plugins/ocaml/example.ml b/plugins/ocaml/example.ml
index 8ec6f063..45de035f 100644
--- a/plugins/ocaml/example.ml
+++ b/plugins/ocaml/example.ml
@@ -71,6 +71,9 @@ let ocamlexample_pwrite h buf offset _ =
let offset = Int64.to_int offset in
String.blit buf 0 !disk offset len
+let ocamlexample_thread_model () =
+ NBDKit.THREAD_MODEL_SERIALIZE_CONNECTIONS
+
let plugin = {
NBDKit.default_callbacks with
(* name, open_connection, get_size and pread are required,
@@ -88,8 +91,8 @@ let plugin = {
get_size = Some ocamlexample_get_size;
pread = Some ocamlexample_pread;
pwrite = Some ocamlexample_pwrite;
+
+ thread_model = Some ocamlexample_thread_model;
}
-let thread_model = NBDKit.THREAD_MODEL_SERIALIZE_CONNECTIONS
-
-let () = NBDKit.register_plugin thread_model plugin
+let () = NBDKit.register_plugin plugin
diff --git a/tests/test_ocaml_plugin.ml b/tests/test_ocaml_plugin.ml
index eb0d9319..3cf8fd90 100644
--- a/tests/test_ocaml_plugin.ml
+++ b/tests/test_ocaml_plugin.ml
@@ -75,8 +75,7 @@ let plugin = {
pwrite = Some test_pwrite;
extents = Some test_extents;
+ thread_model = Some (fun () -> NBDKit.THREAD_MODEL_SERIALIZE_CONNECTIONS);
}
-let thread_model = NBDKit.THREAD_MODEL_SERIALIZE_CONNECTIONS
-
-let () = NBDKit.register_plugin thread_model plugin
+let () = NBDKit.register_plugin plugin
--
2.20.1
5 years, 4 months