import libnbd-1.12.6-1.el9
This commit is contained in:
parent
1e65890c0f
commit
95f059319c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
SOURCES/libguestfs.keyring
|
||||
SOURCES/libnbd-1.10.5.tar.gz
|
||||
SOURCES/libnbd-1.12.6.tar.gz
|
||||
|
@ -1,2 +1,2 @@
|
||||
cc1b37b9cfafa515aab3eefd345ecc59aac2ce7b SOURCES/libguestfs.keyring
|
||||
ae15a534a451d34bfc13397b6ca7a7287cf2371a SOURCES/libnbd-1.10.5.tar.gz
|
||||
2d4eb0846d51c25fa7d04295972cbb5a617984ef SOURCES/libnbd-1.12.6.tar.gz
|
||||
|
1223
SOURCES/0001-Add-nbddump-tool.patch
Normal file
1223
SOURCES/0001-Add-nbddump-tool.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,469 +0,0 @@
|
||||
From c79706af4e7475bf58861a143b77b77a54e7a1cd Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 9 Feb 2022 15:39:49 -0600
|
||||
Subject: [PATCH] api: Add new API nbd_set_pread_initialize()
|
||||
|
||||
The recent patch series for CVE-2022-0485 demonstrated that when
|
||||
applications using libnbd are not careful about error checking, the
|
||||
difference on whether a data leak is at least sanitized (all zeroes,
|
||||
partial reads, or data leftover from a prior read) vs. a dangerous
|
||||
information leak (uninitialized data from the heap) was partly under
|
||||
libnbd's control. The previous two patches changed libnbd to always
|
||||
sanitize, as a security hardening technique that prevents heap leaks
|
||||
no matter how buggy the client app is. But a blind memset() also adds
|
||||
an execution delay, even if it doesn't show up as the hot spot in our
|
||||
profiling when compared to the time spent with network traffic.
|
||||
|
||||
At any rate, if client apps choose to pre-initialize their buffers, or
|
||||
otherwise audit their code to take on their own risk about not
|
||||
dereferencing a buffer on failure paths, then the time spent by libnbd
|
||||
doing memset() is wasted; so it is worth adding a knob to let a user
|
||||
opt in to faster execution at the expense of giving up our memset()
|
||||
hardening on their behalf.
|
||||
|
||||
In addition to adding two new APIs, this patch also causes changes to
|
||||
the four existing APIs nbd_{aio_,}pread{,_structured}, with those
|
||||
generated lib/api.c changes looking like:
|
||||
|
||||
| --- lib/api.c.bak 2022-02-10 08:17:09.973381979 -0600
|
||||
| +++ lib/api.c 2022-02-10 08:22:27.503428024 -0600
|
||||
| @@ -2871,7 +2914,8 @@ nbd_pread (struct nbd_handle *h, void *b
|
||||
| debug (h, "enter: buf=<buf> count=%zu offset=%" PRIu64 " flags=0x%x", count, offset, flags);
|
||||
| }
|
||||
|
|
||||
| - memset (buf, 0, count);
|
||||
| + if (h->pread_initialize)
|
||||
| + memset (buf, 0, count);
|
||||
| if (unlikely (!pread_in_permitted_state (h))) {
|
||||
| ret = -1;
|
||||
| goto out;
|
||||
|
||||
Message-Id: <20220209220726.1902761-4-eblake@redhat.com>
|
||||
Acked-by: Laszlo Ersek <lersek@redhat.com>
|
||||
[eblake: enhance commit message to show generated file diff, mention CVE
|
||||
in doc text]
|
||||
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
|
||||
|
||||
(cherry picked from commit e0953cb71250947bb97b25e34ff1ea34bd504bf3)
|
||||
---
|
||||
generator/API.ml | 90 ++++++++++++++++---
|
||||
generator/C.ml | 3 +-
|
||||
.../libnbd/libnbd_110_defaults_test.go | 10 ++-
|
||||
.../libnbd_120_set_non_defaults_test.go | 12 +++
|
||||
lib/handle.c | 17 +++-
|
||||
lib/internal.h | 5 +-
|
||||
ocaml/tests/test_110_defaults.ml | 4 +-
|
||||
ocaml/tests/test_120_set_non_defaults.ml | 5 +-
|
||||
python/t/110-defaults.py | 3 +-
|
||||
python/t/120-set-non-defaults.py | 4 +-
|
||||
tests/errors.c | 25 +++++-
|
||||
11 files changed, 156 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/generator/API.ml b/generator/API.ml
|
||||
index d8df7c8..00ab34f 100644
|
||||
--- a/generator/API.ml
|
||||
+++ b/generator/API.ml
|
||||
@@ -778,6 +778,49 @@ the time of compilation.";
|
||||
Link "aio_is_created"; Link "aio_is_ready"];
|
||||
};
|
||||
|
||||
+ "set_pread_initialize", {
|
||||
+ default_call with
|
||||
+ args = [Bool "request"]; ret = RErr;
|
||||
+ shortdesc = "control whether libnbd pre-initializes read buffers";
|
||||
+ longdesc = "\
|
||||
+By default, libnbd will pre-initialize the contents of a buffer
|
||||
+passed to calls such as L<nbd_pread(3)> to all zeroes prior to
|
||||
+checking for any other errors, so that even if a client application
|
||||
+passed in an uninitialized buffer but fails to check for errors, it
|
||||
+will not result in a potential security risk caused by an accidental
|
||||
+leak of prior heap contents (see CVE-2022-0485 in
|
||||
+L<libnbd-security(3)> for an example of a security hole in an
|
||||
+application built against an earlier version of libnbd that lacked
|
||||
+consistent pre-initialization). However, for a client application
|
||||
+that has audited that an uninitialized buffer is never dereferenced,
|
||||
+or which performs its own pre-initialization, libnbd's sanitization
|
||||
+efforts merely pessimize performance (although the time spent in
|
||||
+pre-initialization may pale in comparison to time spent waiting on
|
||||
+network packets).
|
||||
+
|
||||
+Calling this function with C<request> set to false tells libnbd to
|
||||
+skip the buffer initialization step in read commands.";
|
||||
+ see_also = [Link "get_pread_initialize";
|
||||
+ Link "set_strict_mode";
|
||||
+ Link "pread"; Link "pread_structured"; Link "aio_pread";
|
||||
+ Link "aio_pread_structured"];
|
||||
+ };
|
||||
+
|
||||
+ "get_pread_initialize", {
|
||||
+ default_call with
|
||||
+ args = []; ret = RBool;
|
||||
+ may_set_error = false;
|
||||
+ shortdesc = "see whether libnbd pre-initializes read buffers";
|
||||
+ longdesc = "\
|
||||
+Return whether libnbd performs a pre-initialization of a buffer passed
|
||||
+to L<nbd_pread(3)> and similar to all zeroes, as set by
|
||||
+L<nbd_set_pread_initialize(3)>.";
|
||||
+ see_also = [Link "set_pread_initialize";
|
||||
+ Link "set_strict_mode";
|
||||
+ Link "pread"; Link "pread_structured"; Link "aio_pread";
|
||||
+ Link "aio_pread_structured"];
|
||||
+ };
|
||||
+
|
||||
"set_strict_mode", {
|
||||
default_call with
|
||||
args = [ Flags ("flags", strict_flags) ]; ret = RErr;
|
||||
@@ -1825,11 +1868,16 @@ C<LIBNBD_CMD_FLAG_DF>.
|
||||
The C<flags> parameter must be C<0> for now (it exists for future NBD
|
||||
protocol extensions).
|
||||
|
||||
-Note that if this command fails, it is unspecified whether the contents
|
||||
-of C<buf> will read as zero or as partial results from the server."
|
||||
+Note that if this command fails, and L<nbd_get_pread_initialize(3)>
|
||||
+returns true, then libnbd sanitized C<buf>, but it is unspecified
|
||||
+whether the contents of C<buf> will read as zero or as partial results
|
||||
+from the server. If L<nbd_get_pread_initialize(3)> returns false,
|
||||
+then libnbd did not sanitize C<buf>, and the contents are undefined
|
||||
+on failure."
|
||||
^ strict_call_description;
|
||||
see_also = [Link "aio_pread"; Link "pread_structured";
|
||||
- Link "get_block_size"; Link "set_strict_mode"];
|
||||
+ Link "get_block_size"; Link "set_strict_mode";
|
||||
+ Link "set_pread_initialize"];
|
||||
example = Some "examples/fetch-first-sector.c";
|
||||
};
|
||||
|
||||
@@ -1907,12 +1955,16 @@ more than one fragment (if that is supported - some servers cannot do
|
||||
this, see L<nbd_can_df(3)>). Libnbd does not validate that the server
|
||||
actually obeys the flag.
|
||||
|
||||
-Note that if this command fails, it is unspecified whether the contents
|
||||
-of C<buf> will read as zero or as partial results from the server."
|
||||
+Note that if this command fails, and L<nbd_get_pread_initialize(3)>
|
||||
+returns true, then libnbd sanitized C<buf>, but it is unspecified
|
||||
+whether the contents of C<buf> will read as zero or as partial results
|
||||
+from the server. If L<nbd_get_pread_initialize(3)> returns false,
|
||||
+then libnbd did not sanitize C<buf>, and the contents are undefined
|
||||
+on failure."
|
||||
^ strict_call_description;
|
||||
see_also = [Link "can_df"; Link "pread";
|
||||
Link "aio_pread_structured"; Link "get_block_size";
|
||||
- Link "set_strict_mode"];
|
||||
+ Link "set_strict_mode"; Link "set_pread_initialize"];
|
||||
};
|
||||
|
||||
"pwrite", {
|
||||
@@ -2420,14 +2472,19 @@ as described in L<libnbd(3)/Completion callbacks>.
|
||||
Note that you must ensure C<buf> is valid until the command has
|
||||
completed. Furthermore, if the C<error> parameter to
|
||||
C<completion_callback> is set or if L<nbd_aio_command_completed(3)>
|
||||
-reports failure, it is unspecified whether the contents
|
||||
-of C<buf> will read as zero or as partial results from the server.
|
||||
+reports failure, and if L<nbd_get_pread_initialize(3)> returns true,
|
||||
+then libnbd sanitized C<buf>, but it is unspecified whether the
|
||||
+contents of C<buf> will read as zero or as partial results from the
|
||||
+server. If L<nbd_get_pread_initialize(3)> returns false, then
|
||||
+libnbd did not sanitize C<buf>, and the contents are undefined
|
||||
+on failure.
|
||||
+
|
||||
Other parameters behave as documented in L<nbd_pread(3)>."
|
||||
^ strict_call_description;
|
||||
example = Some "examples/aio-connect-read.c";
|
||||
see_also = [SectionLink "Issuing asynchronous commands";
|
||||
Link "aio_pread_structured"; Link "pread";
|
||||
- Link "set_strict_mode"];
|
||||
+ Link "set_strict_mode"; Link "set_pread_initialize"];
|
||||
};
|
||||
|
||||
"aio_pread_structured", {
|
||||
@@ -2449,13 +2506,18 @@ as described in L<libnbd(3)/Completion callbacks>.
|
||||
Note that you must ensure C<buf> is valid until the command has
|
||||
completed. Furthermore, if the C<error> parameter to
|
||||
C<completion_callback> is set or if L<nbd_aio_command_completed(3)>
|
||||
-reports failure, it is unspecified whether the contents
|
||||
-of C<buf> will read as zero or as partial results from the server.
|
||||
+reports failure, and if L<nbd_get_pread_initialize(3)> returns true,
|
||||
+then libnbd sanitized C<buf>, but it is unspecified whether the
|
||||
+contents of C<buf> will read as zero or as partial results from the
|
||||
+server. If L<nbd_get_pread_initialize(3)> returns false, then
|
||||
+libnbd did not sanitize C<buf>, and the contents are undefined
|
||||
+on failure.
|
||||
+
|
||||
Other parameters behave as documented in L<nbd_pread_structured(3)>."
|
||||
^ strict_call_description;
|
||||
see_also = [SectionLink "Issuing asynchronous commands";
|
||||
Link "aio_pread"; Link "pread_structured";
|
||||
- Link "set_strict_mode"];
|
||||
+ Link "set_strict_mode"; Link "set_pread_initialize"];
|
||||
};
|
||||
|
||||
"aio_pwrite", {
|
||||
@@ -3093,6 +3155,10 @@ let first_version = [
|
||||
"get_private_data", (1, 8);
|
||||
"get_uri", (1, 8);
|
||||
|
||||
+ (* Added in 1.11.x development cycle, will be stable and supported in 1.12. *)
|
||||
+ "set_pread_initialize", (1, 12);
|
||||
+ "get_pread_initialize", (1, 12);
|
||||
+
|
||||
(* These calls are proposed for a future version of libnbd, but
|
||||
* have not been added to any released version so far.
|
||||
"get_tls_certificates", (1, ??);
|
||||
diff --git a/generator/C.ml b/generator/C.ml
|
||||
index 4a5bb58..2b6198c 100644
|
||||
--- a/generator/C.ml
|
||||
+++ b/generator/C.ml
|
||||
@@ -496,7 +496,8 @@ let generate_lib_api_c () =
|
||||
function
|
||||
| BytesOut (n, count)
|
||||
| BytesPersistOut (n, count) ->
|
||||
- pr " memset (%s, 0, %s);\n" n count
|
||||
+ pr " if (h->pread_initialize)\n";
|
||||
+ pr " memset (%s, 0, %s);\n" n count
|
||||
| _ -> ()
|
||||
) args;
|
||||
|
||||
diff --git a/golang/src/libguestfs.org/libnbd/libnbd_110_defaults_test.go b/golang/src/libguestfs.org/libnbd/libnbd_110_defaults_test.go
|
||||
index b3ceb45..ca7c1c4 100644
|
||||
--- a/golang/src/libguestfs.org/libnbd/libnbd_110_defaults_test.go
|
||||
+++ b/golang/src/libguestfs.org/libnbd/libnbd_110_defaults_test.go
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libnbd golang tests
|
||||
- * Copyright (C) 2013-2021 Red Hat Inc.
|
||||
+ * Copyright (C) 2013-2022 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -59,6 +59,14 @@ func Test110Defaults(t *testing.T) {
|
||||
t.Fatalf("unexpected structured replies state")
|
||||
}
|
||||
|
||||
+ init, err := h.GetPreadInitialize()
|
||||
+ if err != nil {
|
||||
+ t.Fatalf("could not get pread initialize state: %s", err)
|
||||
+ }
|
||||
+ if init != true {
|
||||
+ t.Fatalf("unexpected pread initialize state")
|
||||
+ }
|
||||
+
|
||||
flags, err := h.GetHandshakeFlags()
|
||||
if err != nil {
|
||||
t.Fatalf("could not get handshake flags: %s", err)
|
||||
diff --git a/golang/src/libguestfs.org/libnbd/libnbd_120_set_non_defaults_test.go b/golang/src/libguestfs.org/libnbd/libnbd_120_set_non_defaults_test.go
|
||||
index f112456..029f0db 100644
|
||||
--- a/golang/src/libguestfs.org/libnbd/libnbd_120_set_non_defaults_test.go
|
||||
+++ b/golang/src/libguestfs.org/libnbd/libnbd_120_set_non_defaults_test.go
|
||||
@@ -93,6 +93,18 @@ func Test120SetNonDefaults(t *testing.T) {
|
||||
t.Fatalf("unexpected structured replies state")
|
||||
}
|
||||
|
||||
+ err = h.SetPreadInitialize(false)
|
||||
+ if err != nil {
|
||||
+ t.Fatalf("could not set pread initialize state: %s", err)
|
||||
+ }
|
||||
+ init, err := h.GetPreadInitialize()
|
||||
+ if err != nil {
|
||||
+ t.Fatalf("could not get pread initialize state: %s", err)
|
||||
+ }
|
||||
+ if init != false {
|
||||
+ t.Fatalf("unexpected pread initialize state")
|
||||
+ }
|
||||
+
|
||||
err = h.SetHandshakeFlags(HANDSHAKE_FLAG_MASK + 1)
|
||||
if err == nil {
|
||||
t.Fatalf("expect failure for out-of-range flags")
|
||||
diff --git a/lib/handle.c b/lib/handle.c
|
||||
index 67aa875..ac6c16e 100644
|
||||
--- a/lib/handle.c
|
||||
+++ b/lib/handle.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/* NBD client library in userspace
|
||||
- * Copyright (C) 2013-2020 Red Hat Inc.
|
||||
+ * Copyright (C) 2013-2022 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -64,6 +64,7 @@ nbd_create (void)
|
||||
h->unique = 1;
|
||||
h->tls_verify_peer = true;
|
||||
h->request_sr = true;
|
||||
+ h->pread_initialize = true;
|
||||
|
||||
h->uri_allow_transports = LIBNBD_ALLOW_TRANSPORT_MASK;
|
||||
h->uri_allow_tls = LIBNBD_TLS_ALLOW;
|
||||
@@ -393,6 +394,20 @@ nbd_unlocked_get_handshake_flags (struct nbd_handle *h)
|
||||
return h->gflags;
|
||||
}
|
||||
|
||||
+int
|
||||
+nbd_unlocked_set_pread_initialize (struct nbd_handle *h, bool request)
|
||||
+{
|
||||
+ h->pread_initialize = request;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* NB: may_set_error = false. */
|
||||
+int
|
||||
+nbd_unlocked_get_pread_initialize (struct nbd_handle *h)
|
||||
+{
|
||||
+ return h->pread_initialize;
|
||||
+}
|
||||
+
|
||||
int
|
||||
nbd_unlocked_set_strict_mode (struct nbd_handle *h, uint32_t flags)
|
||||
{
|
||||
diff --git a/lib/internal.h b/lib/internal.h
|
||||
index 0e205ab..525499a 100644
|
||||
--- a/lib/internal.h
|
||||
+++ b/lib/internal.h
|
||||
@@ -1,5 +1,5 @@
|
||||
/* nbd client library in userspace: internal definitions
|
||||
- * Copyright (C) 2013-2020 Red Hat Inc.
|
||||
+ * Copyright (C) 2013-2022 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -123,6 +123,9 @@ struct nbd_handle {
|
||||
/* Full info mode. */
|
||||
bool full_info;
|
||||
|
||||
+ /* Sanitization for pread. */
|
||||
+ bool pread_initialize;
|
||||
+
|
||||
/* Global flags from the server. */
|
||||
uint16_t gflags;
|
||||
|
||||
diff --git a/ocaml/tests/test_110_defaults.ml b/ocaml/tests/test_110_defaults.ml
|
||||
index b36949f..04aa744 100644
|
||||
--- a/ocaml/tests/test_110_defaults.ml
|
||||
+++ b/ocaml/tests/test_110_defaults.ml
|
||||
@@ -1,6 +1,6 @@
|
||||
(* hey emacs, this is OCaml code: -*- tuareg -*- *)
|
||||
(* libnbd OCaml test case
|
||||
- * Copyright (C) 2013-2020 Red Hat Inc.
|
||||
+ * Copyright (C) 2013-2022 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -28,6 +28,8 @@ let () =
|
||||
assert (tls = NBD.TLS.DISABLE);
|
||||
let sr = NBD.get_request_structured_replies nbd in
|
||||
assert (sr = true);
|
||||
+ let init = NBD.get_pread_initialize nbd in
|
||||
+ assert (init = true);
|
||||
let flags = NBD.get_handshake_flags nbd in
|
||||
assert (flags = NBD.HANDSHAKE_FLAG.mask);
|
||||
let opt = NBD.get_opt_mode nbd in
|
||||
diff --git a/ocaml/tests/test_120_set_non_defaults.ml b/ocaml/tests/test_120_set_non_defaults.ml
|
||||
index 67928bb..f949807 100644
|
||||
--- a/ocaml/tests/test_120_set_non_defaults.ml
|
||||
+++ b/ocaml/tests/test_120_set_non_defaults.ml
|
||||
@@ -1,6 +1,6 @@
|
||||
(* hey emacs, this is OCaml code: -*- tuareg -*- *)
|
||||
(* libnbd OCaml test case
|
||||
- * Copyright (C) 2013-2020 Red Hat Inc.
|
||||
+ * Copyright (C) 2013-2022 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -42,6 +42,9 @@ let () =
|
||||
NBD.set_request_structured_replies nbd false;
|
||||
let sr = NBD.get_request_structured_replies nbd in
|
||||
assert (sr = false);
|
||||
+ NBD.set_pread_initialize nbd false;
|
||||
+ let init = NBD.get_pread_initialize nbd in
|
||||
+ assert (init = false);
|
||||
(try
|
||||
NBD.set_handshake_flags nbd [ NBD.HANDSHAKE_FLAG.UNKNOWN 2 ];
|
||||
assert false
|
||||
diff --git a/python/t/110-defaults.py b/python/t/110-defaults.py
|
||||
index fb961cf..a4262da 100644
|
||||
--- a/python/t/110-defaults.py
|
||||
+++ b/python/t/110-defaults.py
|
||||
@@ -1,5 +1,5 @@
|
||||
# libnbd Python bindings
|
||||
-# Copyright (C) 2010-2020 Red Hat Inc.
|
||||
+# Copyright (C) 2010-2022 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
|
||||
@@ -22,5 +22,6 @@ assert h.get_export_name() == ""
|
||||
assert h.get_full_info() is False
|
||||
assert h.get_tls() == nbd.TLS_DISABLE
|
||||
assert h.get_request_structured_replies() is True
|
||||
+assert h.get_pread_initialize() is True
|
||||
assert h.get_handshake_flags() == nbd.HANDSHAKE_FLAG_MASK
|
||||
assert h.get_opt_mode() is False
|
||||
diff --git a/python/t/120-set-non-defaults.py b/python/t/120-set-non-defaults.py
|
||||
index 3da0c23..e71c6ad 100644
|
||||
--- a/python/t/120-set-non-defaults.py
|
||||
+++ b/python/t/120-set-non-defaults.py
|
||||
@@ -1,5 +1,5 @@
|
||||
# libnbd Python bindings
|
||||
-# Copyright (C) 2010-2020 Red Hat Inc.
|
||||
+# Copyright (C) 2010-2022 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
|
||||
@@ -33,6 +33,8 @@ if h.supports_tls():
|
||||
assert h.get_tls() == nbd.TLS_ALLOW
|
||||
h.set_request_structured_replies(False)
|
||||
assert h.get_request_structured_replies() is False
|
||||
+h.set_pread_initialize(False)
|
||||
+assert h.get_pread_initialize() is False
|
||||
try:
|
||||
h.set_handshake_flags(nbd.HANDSHAKE_FLAG_MASK + 1)
|
||||
assert False
|
||||
diff --git a/tests/errors.c b/tests/errors.c
|
||||
index f597b7e..0298da8 100644
|
||||
--- a/tests/errors.c
|
||||
+++ b/tests/errors.c
|
||||
@@ -213,7 +213,15 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
- /* Issue a connected command when not connected. */
|
||||
+ /* Issue a connected command when not connected. pread_initialize defaults
|
||||
+ * to set.
|
||||
+ */
|
||||
+ if (nbd_get_pread_initialize (nbd) != 1) {
|
||||
+ fprintf (stderr, "%s: test failed: "
|
||||
+ "nbd_get_pread_initialize gave unexpected result\n",
|
||||
+ argv[0]);
|
||||
+ exit (EXIT_FAILURE);
|
||||
+ }
|
||||
buf[0] = '1';
|
||||
if (nbd_pread (nbd, buf, 512, 0, 0) != -1) {
|
||||
fprintf (stderr, "%s: test failed: "
|
||||
@@ -294,7 +302,14 @@ main (int argc, char *argv[])
|
||||
}
|
||||
check (EINVAL, "nbd_aio_command_completed: ");
|
||||
|
||||
- /* Read from an invalid offset, client-side */
|
||||
+ /* Read from an invalid offset, client-side. When pread_initialize is off,
|
||||
+ * libnbd should not have touched our buffer.
|
||||
+ */
|
||||
+ if (nbd_set_pread_initialize (nbd, false) == -1) {
|
||||
+ fprintf (stderr, "%s\n", nbd_get_error ());
|
||||
+ exit (EXIT_FAILURE);
|
||||
+ }
|
||||
+ buf[0] = '1';
|
||||
strict = nbd_get_strict_mode (nbd) | LIBNBD_STRICT_BOUNDS;
|
||||
if (nbd_set_strict_mode (nbd, strict) == -1) {
|
||||
fprintf (stderr, "%s\n", nbd_get_error ());
|
||||
@@ -307,6 +322,12 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
check (EINVAL, "nbd_aio_pread: ");
|
||||
+ if (buf[0] != '1') {
|
||||
+ fprintf (stderr, "%s: test failed: "
|
||||
+ "nbd_pread incorrectly sanitized buffer on client-side error\n",
|
||||
+ argv[0]);
|
||||
+ exit (EXIT_FAILURE);
|
||||
+ }
|
||||
|
||||
/* We guarantee callbacks will be freed even on all error paths. */
|
||||
if (nbd_aio_pread_structured (nbd, buf, 512, -1,
|
||||
--
|
||||
2.31.1
|
||||
|
153
SOURCES/0002-dump-Visually-separate-columns-0-7-and-8-15.patch
Normal file
153
SOURCES/0002-dump-Visually-separate-columns-0-7-and-8-15.patch
Normal file
@ -0,0 +1,153 @@
|
||||
From ec947323528725fcf12b5b9ba32b02d36dbd9621 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Thu, 30 Jun 2022 21:09:39 +0100
|
||||
Subject: [PATCH] dump: Visually separate columns 0-7 and 8-15
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Before:
|
||||
|
||||
0000090000: 68 65 72 65 20 77 65 20 61 72 65 00 68 65 72 65 │...
|
||||
0000090010: 20 77 65 20 61 72 65 00 68 65 72 65 20 77 65 20 │...
|
||||
0000090020: 61 72 65 00 68 65 72 65 20 77 65 20 61 72 65 00 │...
|
||||
|
||||
After:
|
||||
|
||||
0000090000: 68 65 72 65 20 77 65 20 61 72 65 00 68 65 72 65 │...
|
||||
0000090010: 20 77 65 20 61 72 65 00 68 65 72 65 20 77 65 20 │...
|
||||
0000090020: 61 72 65 00 68 65 72 65 20 77 65 20 61 72 65 00 │...
|
||||
|
||||
Updates: commit c4107b9a40d6451630dcccf1bf6596c8e56420be
|
||||
(cherry picked from commit 315a637d3eae003c1d84eb1b88a7b47b534f1e80)
|
||||
---
|
||||
dump/dump-data.sh | 22 +++++++++++-----------
|
||||
dump/dump-empty-qcow2.sh | 4 ++--
|
||||
dump/dump-pattern.sh | 38 +++++++++++++++++++-------------------
|
||||
dump/dump.c | 5 ++++-
|
||||
4 files changed, 36 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/dump/dump-data.sh b/dump/dump-data.sh
|
||||
index 23d09da..955cd3b 100755
|
||||
--- a/dump/dump-data.sh
|
||||
+++ b/dump/dump-data.sh
|
||||
@@ -37,21 +37,21 @@ nbdkit -U - data data='
|
||||
|
||||
cat $output
|
||||
|
||||
-if [ "$(cat $output)" != '0000000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
+if [ "$(cat $output)" != '0000000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
*
|
||||
-0000008000: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
-0000008010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
+0000008000: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
+0000008010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
*
|
||||
-000000fff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 |...............h|
|
||||
-0000010000: 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 00 00 00 00 |ello, world!....|
|
||||
-0000010010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
+000000fff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 |...............h|
|
||||
+0000010000: 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 00 00 00 00 |ello, world!....|
|
||||
+0000010010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
*
|
||||
-00010ffff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 70 |..............sp|
|
||||
-0001100000: 61 6e 6e 69 6e 67 20 62 75 66 66 65 72 20 62 6f |anning buffer bo|
|
||||
-0001100010: 75 6e 64 61 72 79 00 00 00 00 00 00 00 00 00 00 |undary..........|
|
||||
-0001100020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
+00010ffff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 70 |..............sp|
|
||||
+0001100000: 61 6e 6e 69 6e 67 20 62 75 66 66 65 72 20 62 6f |anning buffer bo|
|
||||
+0001100010: 75 6e 64 61 72 79 00 00 00 00 00 00 00 00 00 00 |undary..........|
|
||||
+0001100020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
*
|
||||
-0001312d00: 00 |. |' ]; then
|
||||
+0001312d00: 00 |. |' ]; then
|
||||
echo "$0: unexpected output from nbddump command"
|
||||
exit 1
|
||||
fi
|
||||
diff --git a/dump/dump-empty-qcow2.sh b/dump/dump-empty-qcow2.sh
|
||||
index c9e583b..472b6eb 100755
|
||||
--- a/dump/dump-empty-qcow2.sh
|
||||
+++ b/dump/dump-empty-qcow2.sh
|
||||
@@ -38,9 +38,9 @@ qemu-img create -f qcow2 $file $size
|
||||
nbddump -- [ $QEMU_NBD -r -f qcow2 $file ] > $output
|
||||
cat $output
|
||||
|
||||
-if [ "$(cat $output)" != '0000000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
+if [ "$(cat $output)" != '0000000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
*
|
||||
-003ffffff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|' ]; then
|
||||
+003ffffff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|' ]; then
|
||||
echo "$0: unexpected output from nbddump command"
|
||||
exit 1
|
||||
fi
|
||||
diff --git a/dump/dump-pattern.sh b/dump/dump-pattern.sh
|
||||
index e4016a8..d512b77 100755
|
||||
--- a/dump/dump-pattern.sh
|
||||
+++ b/dump/dump-pattern.sh
|
||||
@@ -32,25 +32,25 @@ nbdkit -U - pattern size=299 --run 'nbddump "$uri"' > $output
|
||||
|
||||
cat $output
|
||||
|
||||
-if [ "$(cat $output)" != '0000000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 |................|
|
||||
-0000000010: 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 18 |................|
|
||||
-0000000020: 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 28 |....... .......(|
|
||||
-0000000030: 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 38 |.......0.......8|
|
||||
-0000000040: 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 48 |.......@.......H|
|
||||
-0000000050: 00 00 00 00 00 00 00 50 00 00 00 00 00 00 00 58 |.......P.......X|
|
||||
-0000000060: 00 00 00 00 00 00 00 60 00 00 00 00 00 00 00 68 |.......`.......h|
|
||||
-0000000070: 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 78 |.......p.......x|
|
||||
-0000000080: 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 88 |................|
|
||||
-0000000090: 00 00 00 00 00 00 00 90 00 00 00 00 00 00 00 98 |................|
|
||||
-00000000a0: 00 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 a8 |................|
|
||||
-00000000b0: 00 00 00 00 00 00 00 b0 00 00 00 00 00 00 00 b8 |................|
|
||||
-00000000c0: 00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 c8 |................|
|
||||
-00000000d0: 00 00 00 00 00 00 00 d0 00 00 00 00 00 00 00 d8 |................|
|
||||
-00000000e0: 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 e8 |................|
|
||||
-00000000f0: 00 00 00 00 00 00 00 f0 00 00 00 00 00 00 00 f8 |................|
|
||||
-0000000100: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 08 |................|
|
||||
-0000000110: 00 00 00 00 00 00 01 10 00 00 00 00 00 00 01 18 |................|
|
||||
-0000000120: 00 00 00 00 00 00 01 20 00 00 00 |....... ... |' ]; then
|
||||
+if [ "$(cat $output)" != '0000000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 |................|
|
||||
+0000000010: 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 18 |................|
|
||||
+0000000020: 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 28 |....... .......(|
|
||||
+0000000030: 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 38 |.......0.......8|
|
||||
+0000000040: 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 48 |.......@.......H|
|
||||
+0000000050: 00 00 00 00 00 00 00 50 00 00 00 00 00 00 00 58 |.......P.......X|
|
||||
+0000000060: 00 00 00 00 00 00 00 60 00 00 00 00 00 00 00 68 |.......`.......h|
|
||||
+0000000070: 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 78 |.......p.......x|
|
||||
+0000000080: 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 88 |................|
|
||||
+0000000090: 00 00 00 00 00 00 00 90 00 00 00 00 00 00 00 98 |................|
|
||||
+00000000a0: 00 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 a8 |................|
|
||||
+00000000b0: 00 00 00 00 00 00 00 b0 00 00 00 00 00 00 00 b8 |................|
|
||||
+00000000c0: 00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 c8 |................|
|
||||
+00000000d0: 00 00 00 00 00 00 00 d0 00 00 00 00 00 00 00 d8 |................|
|
||||
+00000000e0: 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 e8 |................|
|
||||
+00000000f0: 00 00 00 00 00 00 00 f0 00 00 00 00 00 00 00 f8 |................|
|
||||
+0000000100: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 08 |................|
|
||||
+0000000110: 00 00 00 00 00 00 01 10 00 00 00 00 00 00 01 18 |................|
|
||||
+0000000120: 00 00 00 00 00 00 01 20 00 00 00 |....... ... |' ]; then
|
||||
echo "$0: unexpected output from nbddump command"
|
||||
exit 1
|
||||
fi
|
||||
diff --git a/dump/dump.c b/dump/dump.c
|
||||
index 76af04c..7818f1f 100644
|
||||
--- a/dump/dump.c
|
||||
+++ b/dump/dump.c
|
||||
@@ -429,10 +429,13 @@ do_dump (void)
|
||||
else
|
||||
ansi_grey ();
|
||||
printf ("%02x ", buffer[j]);
|
||||
+ if ((j - i) == 7) printf (" ");
|
||||
}
|
||||
ansi_grey ();
|
||||
- for (; j < i+16; ++j)
|
||||
+ for (; j < i+16; ++j) {
|
||||
printf (" ");
|
||||
+ if ((j - i) == 7) printf (" ");
|
||||
+ }
|
||||
|
||||
/* Print the ASCII codes. */
|
||||
printf ("%s", pipe);
|
||||
--
|
||||
2.31.1
|
||||
|
38
SOURCES/0003-dump-Fix-build-on-i686.patch
Normal file
38
SOURCES/0003-dump-Fix-build-on-i686.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 590e3a010d2c840314702883e44ec9841e3383c6 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Thu, 30 Jun 2022 22:27:43 +0100
|
||||
Subject: [PATCH] dump: Fix build on i686
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Because we used the wrong printf format, the build would fail on
|
||||
32 bit architectures but succeed on 64 bit:
|
||||
|
||||
dump.c: In function ‘do_dump’:
|
||||
dump.c:421:21: error: format ‘%zx’ expects argument of type ‘size_t’, but argument 2 has type ‘uint64_t’ {aka ‘long long unsigned int’} [-Werror=format=]
|
||||
printf ("%010zx", offset + i);
|
||||
~~~~~^ ~~~~~~~~~~
|
||||
%010llx
|
||||
|
||||
(cherry picked from commit ce004c329c7fcd6c60d11673b7a5c5ce3414413b)
|
||||
---
|
||||
dump/dump.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dump/dump.c b/dump/dump.c
|
||||
index 7818f1f..8bf62f9 100644
|
||||
--- a/dump/dump.c
|
||||
+++ b/dump/dump.c
|
||||
@@ -418,7 +418,7 @@ do_dump (void)
|
||||
|
||||
/* Print the offset. */
|
||||
ansi_green ();
|
||||
- printf ("%010zx", offset + i);
|
||||
+ printf ("%010" PRIx64, offset + i);
|
||||
ansi_grey ();
|
||||
printf (": ");
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
41
SOURCES/0004-dump-Fix-tests-on-Debian-10.patch
Normal file
41
SOURCES/0004-dump-Fix-tests-on-Debian-10.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From e7a2815412891d5c13b5b5f0e9aa61882880c87f Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Thu, 30 Jun 2022 22:31:00 +0100
|
||||
Subject: [PATCH] dump: Fix tests on Debian 10
|
||||
|
||||
The version of nbdkit on Debian 10 does not set $uri. Check for this
|
||||
or skip the test.
|
||||
|
||||
(cherry picked from commit 083b1ca30fb5e6e0dc0e4b0eea9ebe8474d3f864)
|
||||
---
|
||||
dump/dump-data.sh | 1 +
|
||||
dump/dump-pattern.sh | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/dump/dump-data.sh b/dump/dump-data.sh
|
||||
index 955cd3b..46e4d1e 100755
|
||||
--- a/dump/dump-data.sh
|
||||
+++ b/dump/dump-data.sh
|
||||
@@ -23,6 +23,7 @@ set -x
|
||||
|
||||
requires nbdkit --version
|
||||
requires nbdkit data --dump-plugin
|
||||
+requires nbdkit -U - null --run 'test "$uri" != ""'
|
||||
|
||||
output=dump-data.out
|
||||
rm -f $output
|
||||
diff --git a/dump/dump-pattern.sh b/dump/dump-pattern.sh
|
||||
index d512b77..e2188ac 100755
|
||||
--- a/dump/dump-pattern.sh
|
||||
+++ b/dump/dump-pattern.sh
|
||||
@@ -23,6 +23,7 @@ set -x
|
||||
|
||||
requires nbdkit --version
|
||||
requires nbdkit pattern --dump-plugin
|
||||
+requires nbdkit -U - null --run 'test "$uri" != ""'
|
||||
|
||||
output=dump-pattern.out
|
||||
rm -f $output
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,31 @@
|
||||
From 7c669783b1b3fab902ce34d7914b62617ed8b263 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Thu, 30 Jun 2022 22:35:05 +0100
|
||||
Subject: [PATCH] dump/dump-data.sh: Test requires nbdkit 1.22
|
||||
|
||||
Ubuntu 20.04 has nbdkit 1.16 which lacks support for strings. These
|
||||
were added in nbdkit 1.22.
|
||||
|
||||
(cherry picked from commit a8fa05ffb8b85f41276ffb52498e4528c08e5f21)
|
||||
---
|
||||
dump/dump-data.sh | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/dump/dump-data.sh b/dump/dump-data.sh
|
||||
index 46e4d1e..11145b0 100755
|
||||
--- a/dump/dump-data.sh
|
||||
+++ b/dump/dump-data.sh
|
||||
@@ -25,6 +25,10 @@ requires nbdkit --version
|
||||
requires nbdkit data --dump-plugin
|
||||
requires nbdkit -U - null --run 'test "$uri" != ""'
|
||||
|
||||
+# This test requires nbdkit >= 1.22.
|
||||
+minor=$( nbdkit --dump-config | grep ^version_minor | cut -d= -f2 )
|
||||
+requires test $minor -ge 22
|
||||
+
|
||||
output=dump-data.out
|
||||
rm -f $output
|
||||
cleanup_fn rm -f $output
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,163 @@
|
||||
From 8dce43a3ea7a529bc37cbe5607a8d52186cc8169 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Tue, 28 Jun 2022 18:27:58 +0100
|
||||
Subject: [PATCH] copy: Store the preferred block size in the operations struct
|
||||
|
||||
This will be used in a subsequent commit. At the moment the preferred
|
||||
block size for all sources / destinations is simply calculated and
|
||||
stored.
|
||||
|
||||
(cherry picked from commit e6c42f8b2d447bbcc659d6dd33be67335834b2e5)
|
||||
---
|
||||
copy/file-ops.c | 4 +++-
|
||||
copy/main.c | 29 +++++++++++++++++++++++------
|
||||
copy/nbd-ops.c | 10 ++++++++++
|
||||
copy/nbdcopy.h | 4 +++-
|
||||
copy/null-ops.c | 1 +
|
||||
copy/pipe-ops.c | 1 +
|
||||
6 files changed, 41 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/copy/file-ops.c b/copy/file-ops.c
|
||||
index ab37875..34f08e5 100644
|
||||
--- a/copy/file-ops.c
|
||||
+++ b/copy/file-ops.c
|
||||
@@ -241,13 +241,15 @@ seek_hole_supported (int fd)
|
||||
|
||||
struct rw *
|
||||
file_create (const char *name, int fd,
|
||||
- off_t st_size, bool is_block, direction d)
|
||||
+ off_t st_size, uint64_t preferred,
|
||||
+ bool is_block, direction d)
|
||||
{
|
||||
struct rw_file *rwf = calloc (1, sizeof *rwf);
|
||||
if (rwf == NULL) { perror ("calloc"); exit (EXIT_FAILURE); }
|
||||
|
||||
rwf->rw.ops = &file_ops;
|
||||
rwf->rw.name = name;
|
||||
+ rwf->rw.preferred = preferred;
|
||||
rwf->fd = fd;
|
||||
rwf->is_block = is_block;
|
||||
|
||||
diff --git a/copy/main.c b/copy/main.c
|
||||
index cc379e9..19ec384 100644
|
||||
--- a/copy/main.c
|
||||
+++ b/copy/main.c
|
||||
@@ -512,10 +512,26 @@ open_local (const char *filename, direction d)
|
||||
fprintf (stderr, "%s: %s: %m\n", prog, filename);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
- if (S_ISBLK (stat.st_mode) || S_ISREG (stat.st_mode))
|
||||
- return file_create (filename, fd, stat.st_size, S_ISBLK (stat.st_mode), d);
|
||||
- else {
|
||||
- /* Probably stdin/stdout, a pipe or a socket. */
|
||||
+ if (S_ISREG (stat.st_mode)) /* Regular file. */
|
||||
+ return file_create (filename, fd,
|
||||
+ stat.st_size, (uint64_t) stat.st_blksize, false, d);
|
||||
+ else if (S_ISBLK (stat.st_mode)) { /* Block device. */
|
||||
+ unsigned int blkioopt;
|
||||
+
|
||||
+#ifdef BLKIOOPT
|
||||
+ if (ioctl (fd, BLKIOOPT, &blkioopt) == -1) {
|
||||
+ fprintf (stderr, "warning: cannot get optimal I/O size: %s: %m",
|
||||
+ filename);
|
||||
+ blkioopt = 4096;
|
||||
+ }
|
||||
+#else
|
||||
+ blkioopt = 4096;
|
||||
+#endif
|
||||
+
|
||||
+ return file_create (filename, fd,
|
||||
+ stat.st_size, (uint64_t) blkioopt, true, d);
|
||||
+ }
|
||||
+ else { /* Probably stdin/stdout, a pipe or a socket. */
|
||||
synchronous = true; /* Force synchronous mode for pipes. */
|
||||
return pipe_create (filename, fd);
|
||||
}
|
||||
@@ -528,8 +544,9 @@ print_rw (struct rw *rw, const char *prefix, FILE *fp)
|
||||
char buf[HUMAN_SIZE_LONGEST];
|
||||
|
||||
fprintf (fp, "%s: %s \"%s\"\n", prefix, rw->ops->ops_name, rw->name);
|
||||
- fprintf (fp, "%s: size=%" PRIi64 " (%s)\n",
|
||||
- prefix, rw->size, human_size (buf, rw->size, NULL));
|
||||
+ fprintf (fp, "%s: size=%" PRIi64 " (%s), preferred block size=%" PRIu64 "\n",
|
||||
+ prefix, rw->size, human_size (buf, rw->size, NULL),
|
||||
+ rw->preferred);
|
||||
}
|
||||
|
||||
/* Default implementation of rw->ops->get_extents for backends which
|
||||
diff --git a/copy/nbd-ops.c b/copy/nbd-ops.c
|
||||
index 3bc26ba..0988634 100644
|
||||
--- a/copy/nbd-ops.c
|
||||
+++ b/copy/nbd-ops.c
|
||||
@@ -112,12 +112,22 @@ open_one_nbd_handle (struct rw_nbd *rwn)
|
||||
* the same way.
|
||||
*/
|
||||
if (rwn->handles.len == 0) {
|
||||
+ int64_t block_size;
|
||||
+
|
||||
rwn->can_zero = nbd_can_zero (nbd) > 0;
|
||||
+
|
||||
rwn->rw.size = nbd_get_size (nbd);
|
||||
if (rwn->rw.size == -1) {
|
||||
fprintf (stderr, "%s: %s: %s\n", prog, rwn->rw.name, nbd_get_error ());
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
+
|
||||
+ block_size = nbd_get_block_size (nbd, LIBNBD_SIZE_PREFERRED);
|
||||
+ if (block_size == -1) {
|
||||
+ fprintf (stderr, "%s: %s: %s\n", prog, rwn->rw.name, nbd_get_error ());
|
||||
+ exit (EXIT_FAILURE);
|
||||
+ }
|
||||
+ rwn->rw.preferred = block_size == 0 ? 4096 : block_size;
|
||||
}
|
||||
|
||||
if (handles_append (&rwn->handles, nbd) == -1) {
|
||||
diff --git a/copy/nbdcopy.h b/copy/nbdcopy.h
|
||||
index 19797df..9438cce 100644
|
||||
--- a/copy/nbdcopy.h
|
||||
+++ b/copy/nbdcopy.h
|
||||
@@ -43,6 +43,7 @@ struct rw {
|
||||
struct rw_ops *ops; /* Operations. */
|
||||
const char *name; /* Printable name, for error messages etc. */
|
||||
int64_t size; /* May be -1 for streams. */
|
||||
+ uint64_t preferred; /* Preferred block size. */
|
||||
/* Followed by private data for the particular subtype. */
|
||||
};
|
||||
|
||||
@@ -53,7 +54,8 @@ typedef enum { READING, WRITING } direction;
|
||||
|
||||
/* Create subtypes. */
|
||||
extern struct rw *file_create (const char *name, int fd,
|
||||
- off_t st_size, bool is_block, direction d);
|
||||
+ off_t st_size, uint64_t preferred,
|
||||
+ bool is_block, direction d);
|
||||
extern struct rw *nbd_rw_create_uri (const char *name,
|
||||
const char *uri, direction d);
|
||||
extern struct rw *nbd_rw_create_subprocess (const char **argv, size_t argc,
|
||||
diff --git a/copy/null-ops.c b/copy/null-ops.c
|
||||
index 1218a62..99cc9a7 100644
|
||||
--- a/copy/null-ops.c
|
||||
+++ b/copy/null-ops.c
|
||||
@@ -45,6 +45,7 @@ null_create (const char *name)
|
||||
rw->rw.ops = &null_ops;
|
||||
rw->rw.name = name;
|
||||
rw->rw.size = INT64_MAX;
|
||||
+ rw->rw.preferred = 4096;
|
||||
return &rw->rw;
|
||||
}
|
||||
|
||||
diff --git a/copy/pipe-ops.c b/copy/pipe-ops.c
|
||||
index 3c8b6c2..3815f82 100644
|
||||
--- a/copy/pipe-ops.c
|
||||
+++ b/copy/pipe-ops.c
|
||||
@@ -43,6 +43,7 @@ pipe_create (const char *name, int fd)
|
||||
rwp->rw.ops = &pipe_ops;
|
||||
rwp->rw.name = name;
|
||||
rwp->rw.size = -1;
|
||||
+ rwp->rw.preferred = 4096;
|
||||
rwp->fd = fd;
|
||||
return &rwp->rw;
|
||||
}
|
||||
--
|
||||
2.31.1
|
||||
|
457
SOURCES/0007-copy-Use-preferred-block-size-for-copying.patch
Normal file
457
SOURCES/0007-copy-Use-preferred-block-size-for-copying.patch
Normal file
@ -0,0 +1,457 @@
|
||||
From c8626acc63c4ae1c6cf5d1505e0209ac10f44e81 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Tue, 28 Jun 2022 21:58:55 +0100
|
||||
Subject: [PATCH] copy: Use preferred block size for copying
|
||||
|
||||
You're not supposed to read or write NBD servers at a granularity less
|
||||
than the advertised minimum block size. nbdcopy has ignored this
|
||||
requirement, and this is usually fine because the NBD servers we care
|
||||
about support 512-byte sector granularity, and never advertise sizes /
|
||||
extents less granular than sectors (even if it's a bit suboptimal in a
|
||||
few cases).
|
||||
|
||||
However there is one new case where we do care: When writing to a
|
||||
compressed qcow2 file, qemu advertises a minimum and preferred block
|
||||
size of 64K, and it really means it. You cannot write blocks smaller
|
||||
than this because of the way qcow2 compression is implemented.
|
||||
|
||||
This commit attempts to do the least work possible to fix this.
|
||||
|
||||
The previous multi-thread-copying loop was driven by the extent map
|
||||
received from the source. I have modified the loop so that it
|
||||
iterates over request_size blocks. request_size is set from the
|
||||
command line (--request-size) but will be adjusted upwards if either
|
||||
the source or destination preferred block size is larger. So this
|
||||
will always copy blocks which are at least the preferred block size
|
||||
(except for the very last block of the disk).
|
||||
|
||||
While copying these blocks we consult the source extent map. If it
|
||||
contains only zero regions covering the whole block (only_zeroes
|
||||
function) then we can skip straight to zeroing the target
|
||||
(fill_dst_range_with_zeroes), else we do read + write as before.
|
||||
|
||||
I only modified the multi-thread-copying loop, not the synchronous
|
||||
loop. That should be updated in the same way later.
|
||||
|
||||
One side effect of this change is it always makes larger requests,
|
||||
even for regions we know are sparse. This is clear in the
|
||||
copy-sparse.sh and copy-sparse-allocated.sh tests which were
|
||||
previously driven by the 32K sparse map granularity of the source.
|
||||
Without changing these tests, they would make make 256K reads & writes
|
||||
(and also read from areas of the disk even though we know they are
|
||||
sparse). I adjusted these tests to use --request-size=32768 to force
|
||||
the existing behaviour.
|
||||
|
||||
Note this doesn't attempt to limit the maximum block size when reading
|
||||
or writing. That is for future work.
|
||||
|
||||
This is a partial fix for https://bugzilla.redhat.com/2047660.
|
||||
Further changes will be required in virt-v2v.
|
||||
|
||||
Link: https://lists.gnu.org/archive/html/qemu-block/2022-01/threads.html#00729
|
||||
Link: https://bugzilla.redhat.com/show_bug.cgi?id=2047660
|
||||
(cherry picked from commit 4058fe1ff03fb41156b67302ba1006b9d06b0218)
|
||||
---
|
||||
TODO | 4 +-
|
||||
copy/Makefile.am | 6 +-
|
||||
copy/copy-file-to-qcow2-compressed.sh | 64 +++++++++++
|
||||
copy/copy-sparse-allocated.sh | 4 +-
|
||||
copy/copy-sparse.sh | 7 +-
|
||||
copy/main.c | 13 +++
|
||||
copy/multi-thread-copying.c | 149 +++++++++++++++++++-------
|
||||
copy/nbdcopy.pod | 5 +-
|
||||
8 files changed, 202 insertions(+), 50 deletions(-)
|
||||
create mode 100755 copy/copy-file-to-qcow2-compressed.sh
|
||||
|
||||
diff --git a/TODO b/TODO
|
||||
index 7c9c15e..bc38d70 100644
|
||||
--- a/TODO
|
||||
+++ b/TODO
|
||||
@@ -28,7 +28,9 @@ Performance: Chart it over various buffer sizes and threads, as that
|
||||
Examine other fuzzers: https://gitlab.com/akihe/radamsa
|
||||
|
||||
nbdcopy:
|
||||
- - Minimum/preferred/maximum block size.
|
||||
+ - Enforce maximum block size.
|
||||
+ - Synchronous loop should be adjusted to take into account
|
||||
+ the NBD preferred block size, as was done for multi-thread loop.
|
||||
- Benchmark.
|
||||
- Better page cache usage, see nbdkit-file-plugin options
|
||||
fadvise=sequential cache=none.
|
||||
diff --git a/copy/Makefile.am b/copy/Makefile.am
|
||||
index e729f86..25f75c5 100644
|
||||
--- a/copy/Makefile.am
|
||||
+++ b/copy/Makefile.am
|
||||
@@ -23,6 +23,7 @@ EXTRA_DIST = \
|
||||
copy-file-to-nbd.sh \
|
||||
copy-file-to-null.sh \
|
||||
copy-file-to-qcow2.sh \
|
||||
+ copy-file-to-qcow2-compressed.sh \
|
||||
copy-nbd-to-block.sh \
|
||||
copy-nbd-to-file.sh \
|
||||
copy-nbd-to-hexdump.sh \
|
||||
@@ -142,7 +143,10 @@ TESTS += \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_QEMU_NBD
|
||||
-TESTS += copy-file-to-qcow2.sh
|
||||
+TESTS += \
|
||||
+ copy-file-to-qcow2.sh \
|
||||
+ copy-file-to-qcow2-compressed.sh \
|
||||
+ $(NULL)
|
||||
endif
|
||||
|
||||
if HAVE_GNUTLS
|
||||
diff --git a/copy/copy-file-to-qcow2-compressed.sh b/copy/copy-file-to-qcow2-compressed.sh
|
||||
new file mode 100755
|
||||
index 0000000..dfe4fa5
|
||||
--- /dev/null
|
||||
+++ b/copy/copy-file-to-qcow2-compressed.sh
|
||||
@@ -0,0 +1,64 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# nbd client library in userspace
|
||||
+# Copyright (C) 2020-2022 Red Hat Inc.
|
||||
+#
|
||||
+# This library is free software; you can redistribute it and/or
|
||||
+# modify it under the terms of the GNU Lesser General Public
|
||||
+# License as published by the Free Software Foundation; either
|
||||
+# version 2 of the License, or (at your option) any later version.
|
||||
+#
|
||||
+# This library 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
|
||||
+# Lesser General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU Lesser General Public
|
||||
+# License along with this library; if not, write to the Free Software
|
||||
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
+
|
||||
+. ../tests/functions.sh
|
||||
+
|
||||
+set -e
|
||||
+set -x
|
||||
+
|
||||
+requires $QEMU_NBD --version
|
||||
+requires nbdkit --exit-with-parent --version
|
||||
+requires nbdkit sparse-random --dump-plugin
|
||||
+requires qemu-img --version
|
||||
+requires stat --version
|
||||
+
|
||||
+file1=copy-file-to-qcow2-compressed.file1
|
||||
+file2=copy-file-to-qcow2-compressed.file2
|
||||
+rm -f $file1 $file2
|
||||
+cleanup_fn rm -f $file1 $file2
|
||||
+
|
||||
+size=1G
|
||||
+seed=$RANDOM
|
||||
+
|
||||
+# Create a compressed qcow2 file1.
|
||||
+#
|
||||
+# sparse-random files should compress easily because by default each
|
||||
+# block uses repeated bytes.
|
||||
+qemu-img create -f qcow2 $file1 $size
|
||||
+nbdcopy -- [ nbdkit --exit-with-parent sparse-random $size seed=$seed ] \
|
||||
+ [ $QEMU_NBD --image-opts driver=compress,file.driver=qcow2,file.file.driver=file,file.file.filename=$file1 ]
|
||||
+
|
||||
+ls -l $file1
|
||||
+
|
||||
+# Create an uncompressed qcow2 file2 with the same data.
|
||||
+qemu-img create -f qcow2 $file2 $size
|
||||
+nbdcopy -- [ nbdkit --exit-with-parent sparse-random $size seed=$seed ] \
|
||||
+ [ $QEMU_NBD --image-opts driver=qcow2,file.driver=file,file.filename=$file2 ]
|
||||
+
|
||||
+ls -l $file2
|
||||
+
|
||||
+# file1 < file2 (shows the compression is having some effect).
|
||||
+size1="$( stat -c %s $file1 )"
|
||||
+size2="$( stat -c %s $file2 )"
|
||||
+if [ $size1 -ge $size2 ]; then
|
||||
+ echo "$0: qcow2 compression did not make the file smaller"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+# Logical content of the files should be identical.
|
||||
+qemu-img compare -f qcow2 $file1 -F qcow2 $file2
|
||||
diff --git a/copy/copy-sparse-allocated.sh b/copy/copy-sparse-allocated.sh
|
||||
index 203c3b9..465e347 100755
|
||||
--- a/copy/copy-sparse-allocated.sh
|
||||
+++ b/copy/copy-sparse-allocated.sh
|
||||
@@ -17,8 +17,6 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# Adapted from copy-sparse.sh.
|
||||
-#
|
||||
-# This test depends on the nbdkit default sparse block size (32K).
|
||||
|
||||
. ../tests/functions.sh
|
||||
|
||||
@@ -33,7 +31,7 @@ requires nbdkit eval --version
|
||||
out=copy-sparse-allocated.out
|
||||
cleanup_fn rm -f $out
|
||||
|
||||
-$VG nbdcopy --allocated -- \
|
||||
+$VG nbdcopy --allocated --request-size=32768 -- \
|
||||
[ nbdkit --exit-with-parent data data='
|
||||
1
|
||||
@1073741823 1
|
||||
diff --git a/copy/copy-sparse.sh b/copy/copy-sparse.sh
|
||||
index 1a6da86..7912a21 100755
|
||||
--- a/copy/copy-sparse.sh
|
||||
+++ b/copy/copy-sparse.sh
|
||||
@@ -16,8 +16,6 @@
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-# This test depends on the nbdkit default sparse block size (32K).
|
||||
-
|
||||
. ../tests/functions.sh
|
||||
|
||||
set -e
|
||||
@@ -34,8 +32,9 @@ cleanup_fn rm -f $out
|
||||
# Copy from a sparse data disk to an nbdkit-eval-plugin instance which
|
||||
# is logging everything. This allows us to see exactly what nbdcopy
|
||||
# is writing, to ensure it is writing and zeroing the target as
|
||||
-# expected.
|
||||
-$VG nbdcopy -S 0 -- \
|
||||
+# expected. Force request size to match nbdkit default sparse
|
||||
+# allocator block size (32K).
|
||||
+$VG nbdcopy -S 0 --request-size=32768 -- \
|
||||
[ nbdkit --exit-with-parent data data='
|
||||
1
|
||||
@1073741823 1
|
||||
diff --git a/copy/main.c b/copy/main.c
|
||||
index 19ec384..0e27db8 100644
|
||||
--- a/copy/main.c
|
||||
+++ b/copy/main.c
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
#include "ispowerof2.h"
|
||||
#include "human-size.h"
|
||||
+#include "minmax.h"
|
||||
#include "version.h"
|
||||
#include "nbdcopy.h"
|
||||
|
||||
@@ -379,10 +380,22 @@ main (int argc, char *argv[])
|
||||
if (threads < connections)
|
||||
connections = threads;
|
||||
|
||||
+ /* request_size must always be at least as large as the preferred
|
||||
+ * size of source & destination.
|
||||
+ */
|
||||
+ request_size = MAX (request_size, src->preferred);
|
||||
+ request_size = MAX (request_size, dst->preferred);
|
||||
+
|
||||
/* Adapt queue to size to request size if needed. */
|
||||
if (request_size > queue_size)
|
||||
queue_size = request_size;
|
||||
|
||||
+ /* Sparse size (if using) must not be smaller than the destination
|
||||
+ * preferred size, otherwise we end up creating too small requests.
|
||||
+ */
|
||||
+ if (sparse_size > 0 && sparse_size < dst->preferred)
|
||||
+ sparse_size = dst->preferred;
|
||||
+
|
||||
/* Truncate the destination to the same size as the source. Only
|
||||
* has an effect on regular files.
|
||||
*/
|
||||
diff --git a/copy/multi-thread-copying.c b/copy/multi-thread-copying.c
|
||||
index 06cdb8e..9267545 100644
|
||||
--- a/copy/multi-thread-copying.c
|
||||
+++ b/copy/multi-thread-copying.c
|
||||
@@ -166,6 +166,62 @@ decrease_queue_size (struct worker *worker, size_t len)
|
||||
worker->queue_size -= len;
|
||||
}
|
||||
|
||||
+/* Using the extents map 'exts', check if the region
|
||||
+ * [offset..offset+len-1] intersects only with zero extents.
|
||||
+ *
|
||||
+ * The invariant for '*i' is always an extent which starts before or
|
||||
+ * equal to the current offset.
|
||||
+ */
|
||||
+static bool
|
||||
+only_zeroes (const extent_list exts, size_t *i,
|
||||
+ uint64_t offset, unsigned len)
|
||||
+{
|
||||
+ size_t j;
|
||||
+
|
||||
+ /* Invariant. */
|
||||
+ assert (*i < exts.len);
|
||||
+ assert (exts.ptr[*i].offset <= offset);
|
||||
+
|
||||
+ /* Update the invariant. Search for the last possible extent in the
|
||||
+ * list which is <= offset.
|
||||
+ */
|
||||
+ for (j = *i + 1; j < exts.len; ++j) {
|
||||
+ if (exts.ptr[j].offset <= offset)
|
||||
+ *i = j;
|
||||
+ else
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Check invariant again. */
|
||||
+ assert (*i < exts.len);
|
||||
+ assert (exts.ptr[*i].offset <= offset);
|
||||
+
|
||||
+ /* If *i is not the last extent, then the next extent starts
|
||||
+ * strictly beyond our current offset.
|
||||
+ */
|
||||
+ assert (*i == exts.len - 1 || exts.ptr[*i + 1].offset > offset);
|
||||
+
|
||||
+ /* Search forward, look for any non-zero extents overlapping the region. */
|
||||
+ for (j = *i; j < exts.len; ++j) {
|
||||
+ uint64_t start, end;
|
||||
+
|
||||
+ /* [start..end-1] is the current extent. */
|
||||
+ start = exts.ptr[j].offset;
|
||||
+ end = exts.ptr[j].offset + exts.ptr[j].length;
|
||||
+
|
||||
+ assert (end > offset);
|
||||
+
|
||||
+ if (start >= offset + len)
|
||||
+ break;
|
||||
+
|
||||
+ /* Non-zero extent covering this region => test failed. */
|
||||
+ if (!exts.ptr[j].zero)
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
/* There are 'threads' worker threads, each copying work ranges from
|
||||
* src to dst until there are no more work ranges.
|
||||
*/
|
||||
@@ -177,7 +233,10 @@ worker_thread (void *wp)
|
||||
extent_list exts = empty_vector;
|
||||
|
||||
while (get_next_offset (&offset, &count)) {
|
||||
- size_t i;
|
||||
+ struct command *command;
|
||||
+ size_t extent_index;
|
||||
+ bool is_zeroing = false;
|
||||
+ uint64_t zeroing_start = 0; /* initialized to avoid bogus GCC warning */
|
||||
|
||||
assert (0 < count && count <= THREAD_WORK_SIZE);
|
||||
if (extents)
|
||||
@@ -185,52 +244,64 @@ worker_thread (void *wp)
|
||||
else
|
||||
default_get_extents (src, w->index, offset, count, &exts);
|
||||
|
||||
- for (i = 0; i < exts.len; ++i) {
|
||||
- struct command *command;
|
||||
- size_t len;
|
||||
+ extent_index = 0; // index into extents array used to optimize only_zeroes
|
||||
+ while (count) {
|
||||
+ const size_t len = MIN (count, request_size);
|
||||
|
||||
- if (exts.ptr[i].zero) {
|
||||
+ if (only_zeroes (exts, &extent_index, offset, len)) {
|
||||
/* The source is zero so we can proceed directly to skipping,
|
||||
- * fast zeroing, or writing zeroes at the destination.
|
||||
+ * fast zeroing, or writing zeroes at the destination. Defer
|
||||
+ * zeroing so we can send it as a single large command.
|
||||
*/
|
||||
- command = create_command (exts.ptr[i].offset, exts.ptr[i].length,
|
||||
- true, w);
|
||||
- fill_dst_range_with_zeroes (command);
|
||||
+ if (!is_zeroing) {
|
||||
+ is_zeroing = true;
|
||||
+ zeroing_start = offset;
|
||||
+ }
|
||||
}
|
||||
-
|
||||
else /* data */ {
|
||||
- /* As the extent might be larger than permitted for a single
|
||||
- * command, we may have to split this into multiple read
|
||||
- * requests.
|
||||
- */
|
||||
- while (exts.ptr[i].length > 0) {
|
||||
- len = exts.ptr[i].length;
|
||||
- if (len > request_size)
|
||||
- len = request_size;
|
||||
-
|
||||
- command = create_command (exts.ptr[i].offset, len,
|
||||
- false, w);
|
||||
-
|
||||
- wait_for_request_slots (w);
|
||||
-
|
||||
- /* NOTE: Must increase the queue size after waiting. */
|
||||
- increase_queue_size (w, len);
|
||||
-
|
||||
- /* Begin the asynch read operation. */
|
||||
- src->ops->asynch_read (src, command,
|
||||
- (nbd_completion_callback) {
|
||||
- .callback = finished_read,
|
||||
- .user_data = command,
|
||||
- });
|
||||
-
|
||||
- exts.ptr[i].offset += len;
|
||||
- exts.ptr[i].length -= len;
|
||||
+ /* If we were in the middle of deferred zeroing, do it now. */
|
||||
+ if (is_zeroing) {
|
||||
+ /* Note that offset-zeroing_start can never exceed
|
||||
+ * THREAD_WORK_SIZE, so there is no danger of overflowing
|
||||
+ * size_t.
|
||||
+ */
|
||||
+ command = create_command (zeroing_start, offset-zeroing_start,
|
||||
+ true, w);
|
||||
+ fill_dst_range_with_zeroes (command);
|
||||
+ is_zeroing = false;
|
||||
}
|
||||
+
|
||||
+ /* Issue the asynchronous read command. */
|
||||
+ command = create_command (offset, len, false, w);
|
||||
+
|
||||
+ wait_for_request_slots (w);
|
||||
+
|
||||
+ /* NOTE: Must increase the queue size after waiting. */
|
||||
+ increase_queue_size (w, len);
|
||||
+
|
||||
+ /* Begin the asynch read operation. */
|
||||
+ src->ops->asynch_read (src, command,
|
||||
+ (nbd_completion_callback) {
|
||||
+ .callback = finished_read,
|
||||
+ .user_data = command,
|
||||
+ });
|
||||
}
|
||||
|
||||
- offset += count;
|
||||
- count = 0;
|
||||
- } /* for extents */
|
||||
+ offset += len;
|
||||
+ count -= len;
|
||||
+ } /* while (count) */
|
||||
+
|
||||
+ /* If we were in the middle of deferred zeroing, do it now. */
|
||||
+ if (is_zeroing) {
|
||||
+ /* Note that offset-zeroing_start can never exceed
|
||||
+ * THREAD_WORK_SIZE, so there is no danger of overflowing
|
||||
+ * size_t.
|
||||
+ */
|
||||
+ command = create_command (zeroing_start, offset - zeroing_start,
|
||||
+ true, w);
|
||||
+ fill_dst_range_with_zeroes (command);
|
||||
+ is_zeroing = false;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Wait for in flight NBD requests to finish. */
|
||||
diff --git a/copy/nbdcopy.pod b/copy/nbdcopy.pod
|
||||
index fd10f7c..f06d112 100644
|
||||
--- a/copy/nbdcopy.pod
|
||||
+++ b/copy/nbdcopy.pod
|
||||
@@ -182,8 +182,9 @@ Set the maximum number of requests in flight per NBD connection.
|
||||
=item B<--sparse=>N
|
||||
|
||||
Detect all zero blocks of size N (bytes) and make them sparse on the
|
||||
-output. You can also turn off sparse detection using S<I<-S 0>>.
|
||||
-The default is 4096 bytes.
|
||||
+output. You can also turn off sparse detection using S<I<-S 0>>. The
|
||||
+default is 4096 bytes, or the destination preferred block size,
|
||||
+whichever is larger.
|
||||
|
||||
=item B<--synchronous>
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
29
SOURCES/0008-dump-Add-another-example-to-the-manual.patch
Normal file
29
SOURCES/0008-dump-Add-another-example-to-the-manual.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From 5d21b00dbdd1e1a04317bf16afb8f4d2ceaa470f Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Sat, 2 Jul 2022 17:12:46 +0100
|
||||
Subject: [PATCH] dump: Add another example to the manual
|
||||
|
||||
(cherry picked from commit be3768b077c9542aba34eb821016c36f31d234af)
|
||||
---
|
||||
dump/nbddump.pod | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/dump/nbddump.pod b/dump/nbddump.pod
|
||||
index 5d7864d..656a965 100644
|
||||
--- a/dump/nbddump.pod
|
||||
+++ b/dump/nbddump.pod
|
||||
@@ -57,6 +57,11 @@ For example, to dump out a qcow2 file as raw data:
|
||||
|
||||
nbddump -- [ qemu-nbd -r -f qcow2 file.qcow2 ]
|
||||
|
||||
+To dump out an empty floppy disk created by L<nbdkit-floppy-plugin(1)>:
|
||||
+
|
||||
+ mkdir /var/tmp/empty
|
||||
+ nbddump -- [ nbdkit floppy /var/tmp/empty ]
|
||||
+
|
||||
Note that S<C<[ ... ]>> are separate parameters, and must be
|
||||
surrounded by spaces. C<--> separates nbddump parameters from
|
||||
subprocess parameters.
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,93 @@
|
||||
From a432e773e0cdc24cb27ccdda4111744ea2c3b819 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Wed, 27 Jul 2022 17:08:14 +0100
|
||||
Subject: [PATCH] lib/crypto: Use GNUTLS_NO_SIGNAL if available
|
||||
|
||||
libnbd has long used MSG_NOSIGNAL to avoid receiving SIGPIPE if we
|
||||
accidentally write on a closed socket, which is a nice alternative to
|
||||
using a SIGPIPE signal handler. However with TLS connections, gnutls
|
||||
did not use this flag and so programs using libnbd + TLS would receive
|
||||
SIGPIPE in some situations, notably if the server closed the
|
||||
connection abruptly while we were trying to write something.
|
||||
|
||||
GnuTLS 3.4.2 introduces GNUTLS_NO_SIGNAL which does the same thing.
|
||||
Use this flag if available.
|
||||
|
||||
RHEL 7 has an older gnutls which lacks this flag. To avoid qemu-nbd
|
||||
interop tests failing (rarely, but more often with a forthcoming
|
||||
change to TLS shutdown behaviour), register a SIGPIPE signal handler
|
||||
in the test if the flag is missing.
|
||||
---
|
||||
configure.ac | 15 +++++++++++++++
|
||||
interop/interop.c | 10 ++++++++++
|
||||
lib/crypto.c | 7 ++++++-
|
||||
3 files changed, 31 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 49ca8ab..6bd9e1b 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -179,6 +179,21 @@ AS_IF([test "$GNUTLS_LIBS" != ""],[
|
||||
gnutls_session_set_verify_cert \
|
||||
gnutls_transport_is_ktls_enabled \
|
||||
])
|
||||
+ AC_MSG_CHECKING([if gnutls has GNUTLS_NO_SIGNAL])
|
||||
+ AC_COMPILE_IFELSE(
|
||||
+ [AC_LANG_PROGRAM([
|
||||
+ #include <gnutls/gnutls.h>
|
||||
+ gnutls_session_t session;
|
||||
+ ], [
|
||||
+ gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_NO_SIGNAL);
|
||||
+ ])
|
||||
+ ], [
|
||||
+ AC_MSG_RESULT([yes])
|
||||
+ AC_DEFINE([HAVE_GNUTLS_NO_SIGNAL], [1],
|
||||
+ [GNUTLS_NO_SIGNAL found at compile time])
|
||||
+ ], [
|
||||
+ AC_MSG_RESULT([no])
|
||||
+ ])
|
||||
LIBS="$old_LIBS"
|
||||
])
|
||||
|
||||
diff --git a/interop/interop.c b/interop/interop.c
|
||||
index b41f3ca..036545b 100644
|
||||
--- a/interop/interop.c
|
||||
+++ b/interop/interop.c
|
||||
@@ -84,6 +84,16 @@ main (int argc, char *argv[])
|
||||
REQUIRES
|
||||
#endif
|
||||
|
||||
+ /* Ignore SIGPIPE. We only need this for GnuTLS < 3.4.2, since
|
||||
+ * newer GnuTLS has the GNUTLS_NO_SIGNAL flag which adds
|
||||
+ * MSG_NOSIGNAL to each write call.
|
||||
+ */
|
||||
+#if !HAVE_GNUTLS_NO_SIGNAL
|
||||
+#if TLS
|
||||
+ signal (SIGPIPE, SIG_IGN);
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
/* Create a large sparse temporary file. */
|
||||
#ifdef NEEDS_TMPFILE
|
||||
int fd = mkstemp (TMPFILE);
|
||||
diff --git a/lib/crypto.c b/lib/crypto.c
|
||||
index 1272888..ca9520e 100644
|
||||
--- a/lib/crypto.c
|
||||
+++ b/lib/crypto.c
|
||||
@@ -588,7 +588,12 @@ nbd_internal_crypto_create_session (struct nbd_handle *h,
|
||||
gnutls_psk_client_credentials_t pskcreds = NULL;
|
||||
gnutls_certificate_credentials_t xcreds = NULL;
|
||||
|
||||
- err = gnutls_init (&session, GNUTLS_CLIENT|GNUTLS_NONBLOCK);
|
||||
+ err = gnutls_init (&session,
|
||||
+ GNUTLS_CLIENT | GNUTLS_NONBLOCK
|
||||
+#if HAVE_GNUTLS_NO_SIGNAL
|
||||
+ | GNUTLS_NO_SIGNAL
|
||||
+#endif
|
||||
+ );
|
||||
if (err < 0) {
|
||||
set_error (errno, "gnutls_init: %s", gnutls_strerror (err));
|
||||
return NULL;
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,100 @@
|
||||
From 8bbee9c0ff052cf8ab5ba81fd1b67e3c45e7012a Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Wed, 27 Jul 2022 16:07:37 +0100
|
||||
Subject: [PATCH] lib/crypto.c: Ignore TLS premature termination after write
|
||||
shutdown
|
||||
|
||||
qemu-nbd doesn't call gnutls_bye to cleanly shut down the connection
|
||||
after we send NBD_CMD_DISC. When copying from a qemu-nbd server (or
|
||||
any operation which calls nbd_shutdown) you will see errors like this:
|
||||
|
||||
$ nbdcopy nbds://foo?tls-certificates=/var/tmp/pki null:
|
||||
nbds://foo?tls-certificates=/var/tmp/pki: nbd_shutdown: gnutls_record_recv: The TLS connection was non-properly terminated.
|
||||
|
||||
Relatedly you may also see:
|
||||
|
||||
nbd_shutdown: gnutls_record_recv: Error in the pull function.
|
||||
|
||||
This commit suppresses the error in the case where we know that we
|
||||
have shut down writes (which happens after NBD_CMD_DISC has been sent
|
||||
on the wire).
|
||||
---
|
||||
interop/interop.c | 9 ---------
|
||||
lib/crypto.c | 17 +++++++++++++++++
|
||||
lib/internal.h | 1 +
|
||||
3 files changed, 18 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/interop/interop.c b/interop/interop.c
|
||||
index 036545b..cce9407 100644
|
||||
--- a/interop/interop.c
|
||||
+++ b/interop/interop.c
|
||||
@@ -226,19 +226,10 @@ main (int argc, char *argv[])
|
||||
|
||||
/* XXX In future test more operations here. */
|
||||
|
||||
-#if !TLS
|
||||
- /* XXX qemu doesn't shut down the connection nicely (using
|
||||
- * gnutls_bye) and because of this the following call will fail
|
||||
- * with:
|
||||
- *
|
||||
- * nbd_shutdown: gnutls_record_recv: The TLS connection was
|
||||
- * non-properly terminated.
|
||||
- */
|
||||
if (nbd_shutdown (nbd, 0) == -1) {
|
||||
fprintf (stderr, "%s\n", nbd_get_error ());
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
-#endif
|
||||
|
||||
nbd_close (nbd);
|
||||
|
||||
diff --git a/lib/crypto.c b/lib/crypto.c
|
||||
index ca9520e..aa5d820 100644
|
||||
--- a/lib/crypto.c
|
||||
+++ b/lib/crypto.c
|
||||
@@ -187,6 +187,22 @@ tls_recv (struct nbd_handle *h, struct socket *sock, void *buf, size_t len)
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
+ if (h->tls_shut_writes &&
|
||||
+ (r == GNUTLS_E_PULL_ERROR || r == GNUTLS_E_PREMATURE_TERMINATION)) {
|
||||
+ /* qemu-nbd doesn't call gnutls_bye to cleanly shut down the
|
||||
+ * connection after we send NBD_CMD_DISC, instead it simply
|
||||
+ * closes the connection. On the client side we see
|
||||
+ * "gnutls_record_recv: The TLS connection was non-properly
|
||||
+ * terminated" or "gnutls_record_recv: Error in the pull
|
||||
+ * function.".
|
||||
+ *
|
||||
+ * If we see these errors after we shut down the write side
|
||||
+ * (h->tls_shut_writes), which happens after we have sent
|
||||
+ * NBD_CMD_DISC on the wire, downgrade them to a debug message.
|
||||
+ */
|
||||
+ debug (h, "gnutls_record_recv: %s", gnutls_strerror (r));
|
||||
+ return 0; /* EOF */
|
||||
+ }
|
||||
set_error (0, "gnutls_record_recv: %s", gnutls_strerror (r));
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@@ -234,6 +250,7 @@ tls_shut_writes (struct nbd_handle *h, struct socket *sock)
|
||||
return false;
|
||||
if (r != 0)
|
||||
debug (h, "ignoring gnutls_bye failure: %s", gnutls_strerror (r));
|
||||
+ h->tls_shut_writes = true;
|
||||
return sock->u.tls.oldsock->ops->shut_writes (h, sock->u.tls.oldsock);
|
||||
}
|
||||
|
||||
diff --git a/lib/internal.h b/lib/internal.h
|
||||
index 6aaced3..f1b4c63 100644
|
||||
--- a/lib/internal.h
|
||||
+++ b/lib/internal.h
|
||||
@@ -307,6 +307,7 @@ struct nbd_handle {
|
||||
struct command *reply_cmd;
|
||||
|
||||
bool disconnect_request; /* True if we've queued NBD_CMD_DISC */
|
||||
+ bool tls_shut_writes; /* Used by lib/crypto.c to track disconnect. */
|
||||
};
|
||||
|
||||
struct meta_context {
|
||||
--
|
||||
2.31.1
|
||||
|
@ -6,7 +6,7 @@ set -e
|
||||
# directory. Use it like this:
|
||||
# ./copy-patches.sh
|
||||
|
||||
rhel_version=9.0
|
||||
rhel_version=9.1
|
||||
|
||||
# Check we're in the right directory.
|
||||
if [ ! -f libnbd.spec ]; then
|
||||
|
@ -1,17 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmIFM4YRHHJpY2hAYW5u
|
||||
ZXhpYS5vcmcACgkQkXOPc+G3aKDrPhAAjwTeg6XxTtPAbBFqwgYeux742i4ufnrL
|
||||
xdCQgtmyF4jFhW6E0q/dYKr32iUxL6BabswcbmHHhjU4XEa16mSPbkbYAMNvsPJa
|
||||
FpzW4KMJh+vHCarqm3UFiBwVKEEu+VXbOVh9bVjpCdJRx+jE6hbr5tlR9CHQuNQY
|
||||
3LoZ7YU+QvQyIVQDOzDSD/8swyfOeX1c4D4Wok0w9qgHsT54GQmT4VTQ93Z/8RXK
|
||||
D3vCNOt2J+bnJx9WNkboNIfS/FI4L6j4TpuB7tucJlk8Wtfj7LI526LBZwaLYO8E
|
||||
MH63xr0dvbSA19kNY8M3Sff+YqOEKcufZREt5pX6LJLM/ARXKc0KwmaXR+U2zoNy
|
||||
gFomzICsvhGusP6mgLc60VYSUO+od9qZDYsmGZ0mtNL18ISKqIjRRxEXWG6z6mT7
|
||||
kkbifoZC4tOQqKzvswzlWb0upaC5IOju8tGSwpuZosoVcAs63CmU71/CIA7CT4s0
|
||||
qUw+g0ISJYXMFGp3gNzkie9d/a8fAhaCYQKuSxtb5bCNaFegc/6djLy5/MAa65x0
|
||||
difLH3sHYEtB4CzPQnQ8wM5khZ/D789CtqGFtI4fz1aMShW0AJfnsUU8DtAi9pAg
|
||||
3wcjR0N8wQLq68Evj0+VO2rzq/2FSKaR9P7r2cobHC+ucAdvZRAzWOMcHIzfszkN
|
||||
vMYr5xX3G8o=
|
||||
=1qAE
|
||||
-----END PGP SIGNATURE-----
|
17
SOURCES/libnbd-1.12.6.tar.gz.sig
Normal file
17
SOURCES/libnbd-1.12.6.tar.gz.sig
Normal file
@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmLhNK4RHHJpY2hAYW5u
|
||||
ZXhpYS5vcmcACgkQkXOPc+G3aKDzmxAArFrR/cOyqyGZXuYORFRVi7AobCjum4dP
|
||||
A93R43shnSXXB1CTww5O+LjIghSLs4TEQAOcmcsjsE98X2cz0BuW6gIfGxTpN3WP
|
||||
fGPDlvezLXGo5zX5WGFkP6oQY97TuGHXKNxStZtWRtDNfrWPWJQuwlm5GSIHdYYr
|
||||
dFssmDNtIoh/zQz2www9JKspMfehFbTGZswtRjfDwa2Pl69cMy3pH/k4EZZnDx9n
|
||||
tguzQHOapJJx8RkIwUwFirCBOwdVNbLX+KrGroLcB6MjO6Uhh2C/iYUQDM/xX2r6
|
||||
1SugssAmXwZ4/RIDtwBLdQdEoNjSAV7OW1yizTl5P9qFkiPr+Lpnpt4gci9bTZKK
|
||||
oIy0RtgJOgW5R2tuRlMXkx/7kcGjhUb3Zbux7d7dgrYq16FUPC1dFgub7WSPSqWe
|
||||
+17iUD+n3NO2MHtR215nKDjuPR59wnvATO6QS+InOb4imyf47Ic7TeEvVuDhb+M3
|
||||
+DvIor2WyXWX9kO165Fx9jAicgZJt2L1UvKM1GzGjwBdL0GYbCFltzzhyi4Pd/7x
|
||||
ijV2QYbyOLXYEpsgmKYrT6MwwXUAye2PkXSv8MaOs3IiFz0bVy3Bfgx4UYNbKo1x
|
||||
zwVGtIBz39tXpgyS7+F9rvQILVmENGmyTx+GXrv/lE1mFmTt/EEyf+iHMSN1lIkt
|
||||
59o9LBpOajI=
|
||||
=idnt
|
||||
-----END PGP SIGNATURE-----
|
@ -1,3 +1,6 @@
|
||||
# Do this until the feature is fixed in Fedora.
|
||||
%undefine _package_note_flags
|
||||
|
||||
# If we should verify tarball signature with GPGv2.
|
||||
%global verify_tarball_signature 1
|
||||
|
||||
@ -5,10 +8,10 @@
|
||||
%global patches_touch_autotools 1
|
||||
|
||||
# The source directory.
|
||||
%global source_directory 1.10-stable
|
||||
%global source_directory 1.12-stable
|
||||
|
||||
Name: libnbd
|
||||
Version: 1.10.5
|
||||
Version: 1.12.6
|
||||
Release: 1%{?dist}
|
||||
Summary: NBD client library in userspace
|
||||
|
||||
@ -26,10 +29,19 @@ Source2: libguestfs.keyring
|
||||
Source3: copy-patches.sh
|
||||
|
||||
# Patches are stored in the upstream repository:
|
||||
# https://gitlab.com/nbdkit/libnbd/-/commits/rhel-9.0/
|
||||
# https://gitlab.com/nbdkit/libnbd/-/commits/rhel-9.1/
|
||||
|
||||
# Patches.
|
||||
Patch0001: 0001-api-Add-new-API-nbd_set_pread_initialize.patch
|
||||
Patch0001: 0001-Add-nbddump-tool.patch
|
||||
Patch0002: 0002-dump-Visually-separate-columns-0-7-and-8-15.patch
|
||||
Patch0003: 0003-dump-Fix-build-on-i686.patch
|
||||
Patch0004: 0004-dump-Fix-tests-on-Debian-10.patch
|
||||
Patch0005: 0005-dump-dump-data.sh-Test-requires-nbdkit-1.22.patch
|
||||
Patch0006: 0006-copy-Store-the-preferred-block-size-in-the-operation.patch
|
||||
Patch0007: 0007-copy-Use-preferred-block-size-for-copying.patch
|
||||
Patch0008: 0008-dump-Add-another-example-to-the-manual.patch
|
||||
Patch0009: 0009-lib-crypto-Use-GNUTLS_NO_SIGNAL-if-available.patch
|
||||
Patch0010: 0010-lib-crypto.c-Ignore-TLS-premature-termination-after-.patch
|
||||
|
||||
%if 0%{patches_touch_autotools}
|
||||
BuildRequires: autoconf, automake, libtool
|
||||
@ -260,9 +272,11 @@ make %{?_smp_mflags} check || {
|
||||
%doc README
|
||||
%license COPYING.LIB
|
||||
%{_bindir}/nbdcopy
|
||||
%{_bindir}/nbddump
|
||||
%{_bindir}/nbdinfo
|
||||
%{_libdir}/libnbd.so.*
|
||||
%{_mandir}/man1/nbdcopy.1*
|
||||
%{_mandir}/man1/nbddump.1*
|
||||
%{_mandir}/man1/nbdinfo.1*
|
||||
|
||||
|
||||
@ -317,12 +331,23 @@ make %{?_smp_mflags} check || {
|
||||
%files bash-completion
|
||||
%dir %{_datadir}/bash-completion/completions
|
||||
%{_datadir}/bash-completion/completions/nbdcopy
|
||||
%{_datadir}/bash-completion/completions/nbddump
|
||||
%{_datadir}/bash-completion/completions/nbdfuse
|
||||
%{_datadir}/bash-completion/completions/nbdinfo
|
||||
%{_datadir}/bash-completion/completions/nbdsh
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Jul 28 2022 Richard W.M. Jones <rjones@redhat.com> - 1.12.6-1
|
||||
- Rebase to new stable branch version 1.12.6
|
||||
resolves: rhbz#2059288
|
||||
- New tool: nbddump
|
||||
- nbdcopy: Use preferred block size for copying
|
||||
related: rhbz#2047660
|
||||
- Fix remote TLS failures
|
||||
resolves: rhbz#2111524
|
||||
(and 2111813)
|
||||
|
||||
* Thu Feb 10 2022 Richard W.M. Jones <rjones@redhat.com> - 1.10.5-1
|
||||
- Rebase to new stable branch version 1.10.5
|
||||
resolves: rhbz#2011708
|
||||
|
Loading…
Reference in New Issue
Block a user