[libnbd PATCH v4 00/25] enable 64-bit extensions
by Eric Blake
Continuation of my v4 patches which started here:
https://listman.redhat.com/archives/libguestfs/2023-July/032077.html
and compared to my v3 patches here:
https://listman.redhat.com/archives/libguestfs/2023-May/031617.html
Most of the differences from the earlier version is in the front end:
Laszlo had some good suggestions about reworking how 64-bit server
replies are handled without doing an in-place widening or narrowing,
and without introducing a callback shim. I also split up the OCaml
patches to focus on one language binding at a time, instead of all at
once. Many of the later patches are unchanged because the API
addition is still the same, all that differs was how it was
implemented internally. Also new at the end is an additional
strictness flag that can be cleared to intentionally send or omit the
PAYLOAD_LEN flag for the purposes of server integration testing.
001/25:[down] 'block_status: Add some sanity checking of server lengths'
002/25:[down] 'generator: Add Extent64 arg type for upcoming use'
003/25:[down] 'generator: Support Extent64 arg in C code'
004/25:[down] 'generator: Support Extent64 arg in Python code'
005/25:[down] 'golang: Change logic of copy_uint32_array'
006/25:[down] 'generator: Support Extent64 arg in Go code'
007/25:[down] 'generator: Support Extent64 arg in OCaml code'
008/25:[0214] [FC] 'block_status: Accept 64-bit extents during block status'
009/25:[down] 'generator: Prepare for extent64 callback'
010/25:[0387] [FC] 'api: Add [aio_]nbd_block_status_64'
011/25:[down] 'api: Add tests for [aio_]nbd_block_status_64'
012/25:[----] [--] 'api: Add several functions for controlling extended headers'
013/25:[----] [--] 'copy: Update nbdcopy to use 64-bit block status'
014/25:[----] [--] 'dump: Update nbddump to use 64-bit block status'
015/25:[down] 'info: Add --has alias for --can'
016/25:[0016] [FC] 'info: Expose extended-headers support through nbdinfo'
017/25:[----] [--] 'info: Update nbdinfo --map to use 64-bit block status'
018/25:[----] [--] 'examples: Update copy-libev to use 64-bit block status'
019/25:[----] [--] 'ocaml: Add example for 64-bit extents'
020/25:[----] [--] 'generator: Actually request extended headers'
021/25:[----] [--] 'api: Add nbd_[aio_]opt_extended_headers()'
022/25:[0012] [FC] 'interop: Add test of 64-bit block status'
023/25:[0040] [FC] 'api: Add nbd_can_block_status_payload()'
024/25:[0010] [FC] 'api: Add nbd_[aio_]block_status_filter()'
025/25:[down] 'api: Add LIBNBD_STRICT_AUTO_FLAG control to nbd_set_strict'
Eric Blake (25):
block_status: Add some sanity checking of server lengths
generator: Add Extent64 arg type for upcoming use
generator: Support Extent64 arg in C code
generator: Support Extent64 arg in Python code
golang: Change logic of copy_uint32_array
generator: Support Extent64 arg in Go code
generator: Support Extent64 arg in OCaml code
block_status: Accept 64-bit extents during block status
generator: Prepare for extent64 callback
api: Add [aio_]nbd_block_status_64
api: Add tests for [aio_]nbd_block_status_64
api: Add several functions for controlling extended headers
copy: Update nbdcopy to use 64-bit block status
dump: Update nbddump to use 64-bit block status
info: Add --has alias for --can
info: Expose extended-headers support through nbdinfo
info: Update nbdinfo --map to use 64-bit block status
examples: Update copy-libev to use 64-bit block status
ocaml: Add example for 64-bit extents
generator: Actually request extended headers
api: Add nbd_[aio_]opt_extended_headers()
interop: Add test of 64-bit block status
api: Add nbd_can_block_status_payload()
api: Add nbd_[aio_]block_status_filter()
api: Add LIBNBD_STRICT_AUTO_FLAG control to nbd_set_strict
docs/libnbd.pod | 18 +-
info/nbdinfo.pod | 46 +-
sh/nbdsh.pod | 2 +-
lib/internal.h | 26 +-
lib/nbd-protocol.h | 7 +
generator/API.mli | 1 +
generator/API.ml | 542 +++++++++++++++---
generator/state_machine.ml | 41 ++
generator/states-newstyle.c | 3 +
.../states-newstyle-opt-extended-headers.c | 110 ++++
generator/states-newstyle-opt-starttls.c | 7 +-
.../states-newstyle-opt-structured-reply.c | 3 +-
generator/states-issue-command.c | 4 +-
generator/states-reply-chunk.c | 213 +++++--
generator/C.ml | 19 +
generator/GoLang.ml | 40 +-
generator/Makefile.am | 1 +
generator/OCaml.ml | 20 +-
generator/Python.ml | 23 +-
lib/aio.c | 12 +-
lib/flags.c | 12 +
lib/handle.c | 26 +-
lib/opt.c | 44 ++
lib/rw.c | 240 +++++++-
python/t/110-defaults.py | 1 +
python/t/120-set-non-defaults.py | 2 +
python/t/465-block-status-64.py | 56 ++
ocaml/examples/Makefile.am | 1 +
ocaml/examples/extents64.ml | 42 ++
ocaml/helpers.c | 21 +
ocaml/nbd-c.h | 1 +
ocaml/tests/Makefile.am | 1 +
ocaml/tests/test_110_defaults.ml | 2 +
ocaml/tests/test_120_set_non_defaults.ml | 3 +
ocaml/tests/test_465_block_status_64.ml | 58 ++
tests/meta-base-allocation.c | 104 +++-
examples/copy-libev.c | 21 +-
examples/server-flags.c | 7 +-
interop/Makefile.am | 18 +
interop/block-status-64.c | 186 ++++++
interop/block-status-64.sh | 49 ++
interop/block-status-payload.c | 241 ++++++++
interop/block-status-payload.sh | 80 +++
interop/opt-extended-headers.c | 153 +++++
interop/opt-extended-headers.sh | 29 +
.gitignore | 3 +
copy/nbd-ops.c | 22 +-
dump/dump.c | 27 +-
fuzzing/libnbd-fuzz-wrapper.c | 20 +-
golang/Makefile.am | 1 +
golang/handle.go | 6 +
golang/libnbd_110_defaults_test.go | 8 +
golang/libnbd_120_set_non_defaults_test.go | 12 +
golang/libnbd_465_block_status_64_test.go | 119 ++++
info/can.c | 16 +-
info/info-can.sh | 36 +-
info/info-packets.sh | 17 +-
info/main.c | 11 +-
info/map.c | 65 ++-
info/show.c | 9 +-
60 files changed, 2632 insertions(+), 276 deletions(-)
create mode 100644 generator/states-newstyle-opt-extended-headers.c
create mode 100644 python/t/465-block-status-64.py
create mode 100644 ocaml/examples/extents64.ml
create mode 100644 ocaml/tests/test_465_block_status_64.ml
create mode 100644 interop/block-status-64.c
create mode 100755 interop/block-status-64.sh
create mode 100644 interop/block-status-payload.c
create mode 100755 interop/block-status-payload.sh
create mode 100644 interop/opt-extended-headers.c
create mode 100755 interop/opt-extended-headers.sh
create mode 100644 golang/libnbd_465_block_status_64_test.go
base-commit: 70329e9585297bc42cf3db3bf508263137dade8d
--
2.41.0
1 year, 2 months
[libnbd PATCH 0/3] Simplify nbd_shutdown vs. opt mode
by Eric Blake
While working on a larger set of patches to make nbdinfo favor
NBD_OPT_INFO over NBD_OPT_GO where possible (which requires use of
nbd_set_opt_mode(,true) in more cases), I noticed that it got unwieldy
to have to pick the correct shutdown function in all code paths. So I
propose making the API smarter, by adding an opt-in flag that does the
right thing on my behalf.
If you have an idea for a better name for the flag, or think this
functionality should be enabled by default, let me know. Part of the
reason for choosing a new flag is that it becomes a compile-time
witness of whether nbd_shutdown has the desired capability (if we
allow it to auto-opt_abort without a flag, it's harder to tell whether
we are running against an older libnbd where it errors out instead).
Eric Blake (3):
tests: Test behavior of nbd_shutdown during opt mode
api: Add new COVER_OPT_MODE flag to nbd_shutdown
info: Simplify shutdown calls
generator/API.ml | 21 ++++--
lib/disconnect.c | 15 ++++
tests/Makefile.am | 5 ++
tests/shutdown-opt-mode.c | 149 ++++++++++++++++++++++++++++++++++++++
.gitignore | 1 +
info/list.c | 8 +-
info/main.c | 4 +-
7 files changed, 188 insertions(+), 15 deletions(-)
create mode 100644 tests/shutdown-opt-mode.c
--
2.41.0
1 year, 2 months
[libnbd PATCH 0/2] (Attempt to) fix Rust on BSD-based builds
by Eric Blake
I managed to get a build of the async Rust handle compiling on FreeBSD
(although the cirrus CI appears to not actually run 'make check' on
non-Linux machines, at least when run on my fork):
https://gitlab.com/ebblake/libnbd/-/jobs/4985192286
However, I'd really like Tage's review on patch 2 to see if my Rust
makes sense.
Eric Blake (2):
maint: Favor 4-space indent in .rs files
rust: Use mio::poll instead of requiring epoll
rust/Cargo.toml | 2 +-
rust/src/async_handle.rs | 46 +++++++++++++++++++++++++---------------
.editorconfig | 4 ++++
3 files changed, 34 insertions(+), 18 deletions(-)
--
2.41.0
1 year, 2 months
[libnbd PATCH v9 0/7] Rust Bindings for Libnbd
by Tage Johansson
Compared to v8, this patch series corrects some grammatical errors in
patch 1 and 2. Some unrelated formatting has also been removed from
patch 2. Finally, a patch has been added wich extends the Rust test
suite by checking that the Rust crate compiles even with all features
disabled.
--
Best regards,
Tage
Tage Johansson (7):
generator: Add information about asynchronous handle calls
rust: async: Create an async friendly handle type
generator: Add `modifies_fd` flag to the [call] structure
rust: async: Use the modifies_fd flag to exclude calls
rust: async: Add a couple of integration tests
rust: async: Add an example
rust: Check that compilation works with default features disabled
generator/API.ml | 64 +++++
generator/API.mli | 18 ++
generator/Rust.ml | 231 +++++++++++++++
generator/Rust.mli | 2 +
generator/generator.ml | 2 +
rust/Cargo.toml | 6 +-
rust/Makefile.am | 2 +
rust/examples/concurrent-read-write.rs | 149 ++++++++++
rust/run-tests.sh.in | 3 +
rust/src/async_handle.rs | 266 ++++++++++++++++++
rust/src/lib.rs | 9 +
rust/src/utils.rs | 9 +
rust/tests/test_async_100_handle.rs | 25 ++
rust/tests/test_async_200_connect_command.rs | 26 ++
rust/tests/test_async_210_opt_abort.rs | 32 +++
rust/tests/test_async_220_opt_list.rs | 86 ++++++
rust/tests/test_async_230_opt_info.rs | 122 ++++++++
rust/tests/test_async_240_opt_list_meta.rs | 150 ++++++++++
.../test_async_245_opt_list_meta_queries.rs | 94 +++++++
rust/tests/test_async_250_opt_set_meta.rs | 125 ++++++++
.../test_async_255_opt_set_meta_queries.rs | 110 ++++++++
rust/tests/test_async_400_pread.rs | 40 +++
rust/tests/test_async_405_pread_structured.rs | 84 ++++++
rust/tests/test_async_410_pwrite.rs | 59 ++++
rust/tests/test_async_460_block_status.rs | 98 +++++++
rust/tests/test_async_620_stats.rs | 69 +++++
scripts/git.orderfile | 1 +
27 files changed, 1881 insertions(+), 1 deletion(-)
create mode 100644 rust/examples/concurrent-read-write.rs
create mode 100644 rust/src/async_handle.rs
create mode 100644 rust/tests/test_async_100_handle.rs
create mode 100644 rust/tests/test_async_200_connect_command.rs
create mode 100644 rust/tests/test_async_210_opt_abort.rs
create mode 100644 rust/tests/test_async_220_opt_list.rs
create mode 100644 rust/tests/test_async_230_opt_info.rs
create mode 100644 rust/tests/test_async_240_opt_list_meta.rs
create mode 100644 rust/tests/test_async_245_opt_list_meta_queries.rs
create mode 100644 rust/tests/test_async_250_opt_set_meta.rs
create mode 100644 rust/tests/test_async_255_opt_set_meta_queries.rs
create mode 100644 rust/tests/test_async_400_pread.rs
create mode 100644 rust/tests/test_async_405_pread_structured.rs
create mode 100644 rust/tests/test_async_410_pwrite.rs
create mode 100644 rust/tests/test_async_460_block_status.rs
create mode 100644 rust/tests/test_async_620_stats.rs
base-commit: f2dac1102884e3dea1cfb33479b34dd689fbb670
prerequisite-patch-id: ce5d2f65bb12ecda61c97fdf22255e188016b3fc
prerequisite-patch-id: cb5e3f05b600a4953e2a77bd53067bb51903aecd
prerequisite-patch-id: 7613cb6ebcc41fb45da587fc9487eb6c643a14a4
prerequisite-patch-id: 397ff0bea47242cf549a894ce519b3702f072c44
prerequisite-patch-id: e0024d76b8f30c22981fa7410d3ba6935aa3fde4
prerequisite-patch-id: 8228f280bd7dc331ba6e59b3b39209ae3eca0ed3
prerequisite-patch-id: 0bfbfc74216958994f80c7363e4473090bd8bab3
prerequisite-patch-id: 02d5d810150c2042a7b4dbd4f4991fa3f69a7039
prerequisite-patch-id: c55d4346bf391f61d0f836d4d2a8818366d2a701
prerequisite-patch-id: b79c88f8e664526bff63d22faa2b8b4e068d6d85
prerequisite-patch-id: a596c70f96938e496b92d4c99e3e8004c4b3c725
prerequisite-patch-id: d6bcb838a1875541f3f125b95f346c21a7d614ea
--
2.42.0
1 year, 3 months
[nbdkit PATCH] sh: Allow pwrite to not consume all data
by Eric Blake
I hit another transient failure in libnbd CI when a poorly-written
eval script did not consume all of stdin during .pwrite. As behaving
as a data sink can be a somewhat reasonable feature of a
quickly-written sh or eval plugin, we should not be so insistent as
treating an EPIPE failure as an immediate return of EIO to the client.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
I probably need to add unit test coverage of this before committing
(although proving that I win the data race on a client process exiting
faster than the parent can write enough data to hit EPIPE is hard).
plugins/sh/nbdkit-sh-plugin.pod | 8 +++++++
plugins/sh/call.c | 38 ++++++++++++++++++++++-----------
2 files changed, 34 insertions(+), 12 deletions(-)
diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index b2c946a0..8b83a5b3 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -505,6 +505,14 @@ Unlike in other languages, if you provide a C<pwrite> method you
B<must> also provide a C<can_write> method which exits with code C<0>
(true).
+With nbdkit E<ge> 1.36, this method may return C<0> without consuming
+any data from stdin, and without producing any output, in order to
+behave as an intentional data sink. But in older versions, nbdkit
+would treat any C<EPIPE> failure in writing to your script as an error
+condition even if your script returns success; to avoid unintended
+failures, you may want to include C<"cat >/dev/null"> in a script
+intending to ignore the client's write requests.
+
=item C<flush>
/path/to/script flush <handle>
diff --git a/plugins/sh/call.c b/plugins/sh/call.c
index 888c6459..79c67a04 100644
--- a/plugins/sh/call.c
+++ b/plugins/sh/call.c
@@ -34,6 +34,7 @@
#include <assert.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
@@ -130,6 +131,7 @@ debug_call (const char **argv)
*/
static int
call3 (const char *wbuf, size_t wbuflen, /* sent to stdin (can be NULL) */
+ bool *pipe_full, /* set if wbuf not fully written */
string *rbuf, /* read from stdout */
string *ebuf, /* read from stderr */
const char **argv) /* script + parameters */
@@ -275,15 +277,8 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin (can be NULL) */
r = write (pfds[0].fd, wbuf, wbuflen);
if (r == -1) {
if (errno == EPIPE) {
- /* We tried to write to the script but it didn't consume
- * the data. Probably the script exited without reading
- * from stdin. This is an error in the script.
- */
- nbdkit_error ("%s: write to script failed because of a broken pipe: "
- "this can happen if the script exits without "
- "consuming stdin, which usually indicates a bug "
- "in the script",
- argv0);
+ *pipe_full = true;
+ r = wbuflen;
}
else
nbdkit_error ("%s: write: %m", argv0);
@@ -555,7 +550,7 @@ call (const char **argv)
CLEANUP_FREE_STRING string rbuf = empty_vector;
CLEANUP_FREE_STRING string ebuf = empty_vector;
- r = call3 (NULL, 0, &rbuf, &ebuf, argv);
+ r = call3 (NULL, 0, NULL, &rbuf, &ebuf, argv);
return handle_script_error (argv[0], &ebuf, r);
}
@@ -568,7 +563,7 @@ call_read (string *rbuf, const char **argv)
int r;
CLEANUP_FREE_STRING string ebuf = empty_vector;
- r = call3 (NULL, 0, rbuf, &ebuf, argv);
+ r = call3 (NULL, 0, NULL, rbuf, &ebuf, argv);
r = handle_script_error (argv[0], &ebuf, r);
if (r == ERROR)
string_reset (rbuf);
@@ -584,7 +579,26 @@ call_write (const char *wbuf, size_t wbuflen, const char **argv)
int r;
CLEANUP_FREE_STRING string rbuf = empty_vector;
CLEANUP_FREE_STRING string ebuf = empty_vector;
+ bool pipe_full = false;
- r = call3 (wbuf, wbuflen, &rbuf, &ebuf, argv);
+ r = call3 (wbuf, wbuflen, &pipe_full, &rbuf, &ebuf, argv);
+ if (pipe_full && r == OK) {
+ /* We allow scripts to intentionally ignore data, but they must
+ * have no output when doing so.
+ */
+ if (rbuf.len > 0 || ebuf.len > 0) {
+ nbdkit_error ("%s: write to script failed because of a broken pipe: "
+ "this can happen if the script exits without "
+ "consuming stdin, which usually indicates a bug "
+ "in the script",
+ argv[0]);
+ r = ERROR;
+ }
+ else
+ nbdkit_debug ("%s: write to script failed because of a broken pipe; "
+ "assuming this was an intentional data sink, although it "
+ "may indicate a bug in the script",
+ argv[0]);
+ }
return handle_script_error (argv[0], &ebuf, r);
}
--
2.41.0
1 year, 3 months
[PATCH nbdkit] sh: In pwrite, allow scripts to ignore stdin
by Richard W.M. Jones
See comment for explanation and
https://listman.redhat.com/archives/libguestfs/2023-August/032468.html
---
tests/Makefile.am | 2 +
plugins/sh/call.c | 33 +++++++-----
tests/test-sh-pwrite-ignore-stdin.sh | 77 ++++++++++++++++++++++++++++
3 files changed, 100 insertions(+), 12 deletions(-)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d57eb01b8..e69893e0d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1325,11 +1325,13 @@ test-shell.img:
TESTS += \
test-sh-errors.sh \
test-sh-extents.sh \
+ test-sh-pwrite-ignore-stdin.sh \
test-sh-tmpdir-leak.sh \
$(NULL)
EXTRA_DIST += \
test-sh-errors.sh \
test-sh-extents.sh \
+ test-sh-pwrite-ignore-stdin.sh \
test-sh-tmpdir-leak.sh \
$(NULL)
diff --git a/plugins/sh/call.c b/plugins/sh/call.c
index 888c6459a..621465252 100644
--- a/plugins/sh/call.c
+++ b/plugins/sh/call.c
@@ -275,22 +275,31 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin (can be NULL) */
r = write (pfds[0].fd, wbuf, wbuflen);
if (r == -1) {
if (errno == EPIPE) {
- /* We tried to write to the script but it didn't consume
- * the data. Probably the script exited without reading
- * from stdin. This is an error in the script.
+ /* In nbdkit <= 1.35.11 we gave an error here, arguing that
+ * scripts must always consume or discard their full input
+ * when 'pwrite' is called. Previously we had many cases
+ * where scripts forgot to discard the data on a path out of
+ * pwrite (such as an error or where the script is not
+ * interested in the data being written), resulting in
+ * intermittent test failures.
+ *
+ * It is valid for a script to ignore the written data
+ * (plenty of non-sh plugins do this), or for a script to be
+ * gradually processing the data, encounter an error and
+ * wish to exit immediately. Therefore ignore this error.
*/
- nbdkit_error ("%s: write to script failed because of a broken pipe: "
- "this can happen if the script exits without "
- "consuming stdin, which usually indicates a bug "
- "in the script",
- argv0);
+ nbdkit_debug ("%s: write: %m (ignored)", argv0);
+ wbuflen = 0; /* discard the rest */
}
- else
+ else {
nbdkit_error ("%s: write: %m", argv0);
- goto error;
+ goto error;
+ }
+ }
+ else {
+ wbuf += r;
+ wbuflen -= r;
}
- wbuf += r;
- wbuflen -= r;
/* After writing all the data we close the pipe so that
* the reader on the other end doesn't wait for more.
*/
diff --git a/tests/test-sh-pwrite-ignore-stdin.sh b/tests/test-sh-pwrite-ignore-stdin.sh
new file mode 100755
index 000000000..3448eca17
--- /dev/null
+++ b/tests/test-sh-pwrite-ignore-stdin.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright Red Hat
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Test that pwrite is allowed to ignore stdin (in nbdkit >= 1.36).
+
+source ./functions.sh
+set -e
+set -x
+
+requires_plugin sh
+requires_nbdsh_uri
+
+sock=$(mktemp -u /tmp/nbdkit-test-sock.XXXXXX)
+pid=sh-pwrite-ignore-stdin.pid
+files="$sock $pid"
+rm -f $files
+cleanup_fn rm -f $files
+
+start_nbdkit -P $pid -U $sock sh - <<'EOF'
+case "$1" in
+ can_write) echo 0 ;;
+ pwrite)
+ # Always ignore the input. If the offset >= 32M return an error.
+ if [ $4 -ge 33554432 ]; then
+ echo 'ENOSPC Out of space' >&2
+ exit 1
+ fi
+ ;;
+ get_size)
+ echo 64M
+ ;;
+ pread)
+ ;;
+ *) exit 2 ;;
+esac
+EOF
+
+nbdsh -u "nbd+unix://?socket=$sock" -c '
+buf = bytearray(16*1024*1024)
+h.pwrite(buf, 0)
+
+try:
+ h.pwrite(buf, 32*1024*1024)
+ assert False
+except nbd.Error:
+ # Expect an error here.
+ pass
+'
--
2.41.0
1 year, 3 months