Compare commits
	
		
			No commits in common. "c9" and "c8-stream-rhel" have entirely different histories.
		
	
	
		
			c9
			...
			c8-stream-
		
	
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,2 @@
 | 
			
		||||
SOURCES/libguestfs.keyring
 | 
			
		||||
SOURCES/nbdkit-1.38.5.tar.gz
 | 
			
		||||
SOURCES/nbdkit-1.24.0.tar.gz
 | 
			
		||||
 | 
			
		||||
@ -1,2 +1,2 @@
 | 
			
		||||
cc1b37b9cfafa515aab3eefd345ecc59aac2ce7b SOURCES/libguestfs.keyring
 | 
			
		||||
c70e24853a2bd5eee4546014991a9487c2a4dcdb SOURCES/nbdkit-1.38.5.tar.gz
 | 
			
		||||
1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring
 | 
			
		||||
069720cc0d1502b007652101d293a57d7b4d7c41 SOURCES/nbdkit-1.24.0.tar.gz
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,82 @@
 | 
			
		||||
From 99788909d9ec36e3210cf85976fe5b18da690ddd Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Wed, 4 Aug 2021 20:24:59 +0100
 | 
			
		||||
Subject: [PATCH] cache, cow: Fix data corruption in zero and trim on unaligned
 | 
			
		||||
 tail
 | 
			
		||||
 | 
			
		||||
Commit eb6009b092 ("cache, cow: Reduce use of bounce-buffer") first
 | 
			
		||||
introduced in nbdkit 1.14 added an optimization of the
 | 
			
		||||
read-modify-write mechanism used for unaligned heads and tails when
 | 
			
		||||
zeroing in the cache layer.
 | 
			
		||||
 | 
			
		||||
Unfortunately the part applied to the tail contained a mistake: It
 | 
			
		||||
zeroes the end of the buffer rather than the beginning.  This causes
 | 
			
		||||
data corruption when you use the zero or trim function with an offset
 | 
			
		||||
and count which is not aligned to the block size.
 | 
			
		||||
 | 
			
		||||
Although the bug has been around for years, a recent change made it
 | 
			
		||||
more likely to happen.  Commit c1905b0a28 ("cache, cow: Use a 64K
 | 
			
		||||
block size by default") increased the default block size from 4K to
 | 
			
		||||
64K.  Most filesystems use a 4K block size so operations like fstrim
 | 
			
		||||
will make 4K-aligned requests, and with a 4K block size also in the
 | 
			
		||||
cache or cow filter the unaligned case would never have been hit
 | 
			
		||||
before.
 | 
			
		||||
 | 
			
		||||
We can demonstrate the bug simply by filling a buffer with data
 | 
			
		||||
(100000 bytes in the example), and then trimming that data, which
 | 
			
		||||
ought to zero it out.
 | 
			
		||||
 | 
			
		||||
Before this commit there is data visible after the trim:
 | 
			
		||||
 | 
			
		||||
$ nbdkit --filter=cow data "0x21 * 100000" --run 'nbdsh -u $uri -c "h.trim(100000, 0)" ; nbdcopy $uri - | hexdump -C'
 | 
			
		||||
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 | 
			
		||||
*
 | 
			
		||||
00018000  21 21 21 21 21 21 21 21  21 21 21 21 21 21 21 21  |!!!!!!!!!!!!!!!!|
 | 
			
		||||
*
 | 
			
		||||
000186a0
 | 
			
		||||
 | 
			
		||||
After this commit the trim completely clears the data:
 | 
			
		||||
 | 
			
		||||
$ nbdkit --filter=cow data "0x21 * 100000" --run 'nbdsh -u $uri -c "h.trim(100000, 0)" ; nbdcopy $uri - | hexdump -C'
 | 
			
		||||
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 | 
			
		||||
*
 | 
			
		||||
000186a0
 | 
			
		||||
 | 
			
		||||
Thanks: Ming Xie for finding the bug
 | 
			
		||||
Fixes: commit eb6009b092ae642ed25f133d487dd40ef7bf70f8
 | 
			
		||||
(cherry picked from commit a0ae7b2158598ce48ac31706319007f716d01c87)
 | 
			
		||||
(cherry picked from commit c0b15574647672cb5c48178333acdd07424692ef)
 | 
			
		||||
---
 | 
			
		||||
 filters/cache/cache.c | 2 +-
 | 
			
		||||
 filters/cow/cow.c     | 2 +-
 | 
			
		||||
 2 files changed, 2 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/filters/cache/cache.c b/filters/cache/cache.c
 | 
			
		||||
index 91dcc43d..0616cc7b 100644
 | 
			
		||||
--- a/filters/cache/cache.c
 | 
			
		||||
+++ b/filters/cache/cache.c
 | 
			
		||||
@@ -493,7 +493,7 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
 | 
			
		||||
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
 | 
			
		||||
     r = blk_read (next_ops, nxdata, blknum, block, err);
 | 
			
		||||
     if (r != -1) {
 | 
			
		||||
-      memset (&block[count], 0, blksize - count);
 | 
			
		||||
+      memset (block, 0, count);
 | 
			
		||||
       r = blk_write (next_ops, nxdata, blknum, block, flags, err);
 | 
			
		||||
     }
 | 
			
		||||
     if (r == -1)
 | 
			
		||||
diff --git a/filters/cow/cow.c b/filters/cow/cow.c
 | 
			
		||||
index 51ca64a4..1cfcc4e7 100644
 | 
			
		||||
--- a/filters/cow/cow.c
 | 
			
		||||
+++ b/filters/cow/cow.c
 | 
			
		||||
@@ -419,7 +419,7 @@ cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
 | 
			
		||||
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
 | 
			
		||||
     r = blk_read (next_ops, nxdata, blknum, block, err);
 | 
			
		||||
     if (r != -1) {
 | 
			
		||||
-      memset (&block[count], 0, BLKSIZE - count);
 | 
			
		||||
+      memset (block, 0, count);
 | 
			
		||||
       r = blk_write (blknum, block, err);
 | 
			
		||||
     }
 | 
			
		||||
     if (r == -1)
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
@ -1,151 +0,0 @@
 | 
			
		||||
From e97b5ec6e7e7406688f68a5828e66ef46046fd9f Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Tue, 23 Jul 2024 14:46:41 +0100
 | 
			
		||||
Subject: [PATCH] server: log: Move preserve errno to log_verror function
 | 
			
		||||
 | 
			
		||||
This neutral code refactoring just moves the place where we preserve
 | 
			
		||||
errno out one layer, but should have no other effect.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit f2c644d4495d5e75883ff729936102c90489e8d8)
 | 
			
		||||
---
 | 
			
		||||
 server/internal.h   |  8 ++++----
 | 
			
		||||
 server/log-stderr.c |  9 ++-------
 | 
			
		||||
 server/log-syslog.c | 13 ++++---------
 | 
			
		||||
 server/log.c        | 12 ++++++++----
 | 
			
		||||
 4 files changed, 18 insertions(+), 24 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/server/internal.h b/server/internal.h
 | 
			
		||||
index 7eba3bce..57e777e9 100644
 | 
			
		||||
--- a/server/internal.h
 | 
			
		||||
+++ b/server/internal.h
 | 
			
		||||
@@ -339,10 +339,10 @@ extern void free_debug_flags (void);
 | 
			
		||||
 extern void log_verror (const char *fs, va_list args);
 | 
			
		||||
 
 | 
			
		||||
 /* log-*.c */
 | 
			
		||||
-extern void log_stderr_verror (const char *fs, va_list args)
 | 
			
		||||
-  ATTRIBUTE_FORMAT_PRINTF (1, 0);
 | 
			
		||||
-extern void log_syslog_verror (const char *fs, va_list args)
 | 
			
		||||
-  ATTRIBUTE_FORMAT_PRINTF (1, 0);
 | 
			
		||||
+extern void log_stderr_verror (int orig_errno, const char *fs, va_list args)
 | 
			
		||||
+  ATTRIBUTE_FORMAT_PRINTF (2, 0);
 | 
			
		||||
+extern void log_syslog_verror (int orig_errno, const char *fs, va_list args)
 | 
			
		||||
+  ATTRIBUTE_FORMAT_PRINTF (2, 0);
 | 
			
		||||
 
 | 
			
		||||
 /* vfprintf.c */
 | 
			
		||||
 #if !HAVE_VFPRINTF_PERCENT_M
 | 
			
		||||
diff --git a/server/log-stderr.c b/server/log-stderr.c
 | 
			
		||||
index 8a55f5df..4d8b09da 100644
 | 
			
		||||
--- a/server/log-stderr.c
 | 
			
		||||
+++ b/server/log-stderr.c
 | 
			
		||||
@@ -43,12 +43,9 @@
 | 
			
		||||
 
 | 
			
		||||
 #include "internal.h"
 | 
			
		||||
 
 | 
			
		||||
-/* Note: preserves the previous value of errno. */
 | 
			
		||||
 void
 | 
			
		||||
-log_stderr_verror (const char *fs, va_list args)
 | 
			
		||||
+log_stderr_verror (int orig_errno, const char *fs, va_list args)
 | 
			
		||||
 {
 | 
			
		||||
-  int err = errno;              /* must be first line of function */
 | 
			
		||||
-
 | 
			
		||||
   const char *name = threadlocal_get_name ();
 | 
			
		||||
   size_t instance_num = threadlocal_get_instance_num ();
 | 
			
		||||
   int tty;
 | 
			
		||||
@@ -69,7 +66,7 @@ log_stderr_verror (const char *fs, va_list args)
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   fprintf (stderr, "error: ");
 | 
			
		||||
-  errno = err;                  /* must restore in case fs contains %m */
 | 
			
		||||
+  errno = orig_errno;        /* must restore in case fs contains %m */
 | 
			
		||||
   vfprintf (stderr, fs, args);
 | 
			
		||||
   fprintf (stderr, "\n");
 | 
			
		||||
 
 | 
			
		||||
@@ -78,6 +75,4 @@ log_stderr_verror (const char *fs, va_list args)
 | 
			
		||||
 #ifdef HAVE_FUNLOCKFILE
 | 
			
		||||
   funlockfile (stderr);
 | 
			
		||||
 #endif
 | 
			
		||||
-
 | 
			
		||||
-  errno = err;                  /* must be last line of function */
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/server/log-syslog.c b/server/log-syslog.c
 | 
			
		||||
index 76c5035b..29a7a825 100644
 | 
			
		||||
--- a/server/log-syslog.c
 | 
			
		||||
+++ b/server/log-syslog.c
 | 
			
		||||
@@ -45,11 +45,9 @@
 | 
			
		||||
 /* Tempted to use LOG_FTP instead of LOG_DAEMON! */
 | 
			
		||||
 static const int PRIORITY = LOG_DAEMON|LOG_ERR;
 | 
			
		||||
 
 | 
			
		||||
-/* Note: preserves the previous value of errno. */
 | 
			
		||||
 void
 | 
			
		||||
-log_syslog_verror (const char *fs, va_list args)
 | 
			
		||||
+log_syslog_verror (int orig_errno, const char *fs, va_list args)
 | 
			
		||||
 {
 | 
			
		||||
-  int err = errno;
 | 
			
		||||
   const char *name = threadlocal_get_name ();
 | 
			
		||||
   size_t instance_num = threadlocal_get_instance_num ();
 | 
			
		||||
   CLEANUP_FREE char *msg = NULL;
 | 
			
		||||
@@ -59,9 +57,9 @@ log_syslog_verror (const char *fs, va_list args)
 | 
			
		||||
   fp = open_memstream (&msg, &len);
 | 
			
		||||
   if (fp == NULL) {
 | 
			
		||||
     /* Fallback to logging using fs, args directly. */
 | 
			
		||||
-    errno = err; /* Must restore in case fs contains %m */
 | 
			
		||||
+    errno = orig_errno;      /* must restore in case fs contains %m */
 | 
			
		||||
     vsyslog (PRIORITY, fs, args);
 | 
			
		||||
-    goto out;
 | 
			
		||||
+    return;
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   if (name) {
 | 
			
		||||
@@ -71,12 +69,9 @@ log_syslog_verror (const char *fs, va_list args)
 | 
			
		||||
     fprintf (fp, ": ");
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
-  errno = err; /* Must restore in case fs contains %m */
 | 
			
		||||
+  errno = orig_errno;        /* must restore in case fs contains %m */
 | 
			
		||||
   vfprintf (fp, fs, args);
 | 
			
		||||
   close_memstream (fp);
 | 
			
		||||
 
 | 
			
		||||
   syslog (PRIORITY, "%s", msg);
 | 
			
		||||
-
 | 
			
		||||
- out:
 | 
			
		||||
-  errno = err;
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/server/log.c b/server/log.c
 | 
			
		||||
index 464e4f9a..9c1f667a 100644
 | 
			
		||||
--- a/server/log.c
 | 
			
		||||
+++ b/server/log.c
 | 
			
		||||
@@ -46,23 +46,27 @@
 | 
			
		||||
 void
 | 
			
		||||
 log_verror (const char *fs, va_list args)
 | 
			
		||||
 {
 | 
			
		||||
+  int orig_errno = errno;
 | 
			
		||||
+
 | 
			
		||||
   switch (log_to) {
 | 
			
		||||
   case LOG_TO_DEFAULT:
 | 
			
		||||
     if (forked_into_background)
 | 
			
		||||
-      log_syslog_verror (fs, args);
 | 
			
		||||
+      log_syslog_verror (orig_errno, fs, args);
 | 
			
		||||
     else
 | 
			
		||||
-      log_stderr_verror (fs, args);
 | 
			
		||||
+      log_stderr_verror (orig_errno, fs, args);
 | 
			
		||||
     break;
 | 
			
		||||
   case LOG_TO_SYSLOG:
 | 
			
		||||
-    log_syslog_verror (fs, args);
 | 
			
		||||
+    log_syslog_verror (orig_errno, fs, args);
 | 
			
		||||
     break;
 | 
			
		||||
   case LOG_TO_STDERR:
 | 
			
		||||
-    log_stderr_verror (fs, args);
 | 
			
		||||
+    log_stderr_verror (orig_errno, fs, args);
 | 
			
		||||
     break;
 | 
			
		||||
   case LOG_TO_NULL:
 | 
			
		||||
     /* nothing */
 | 
			
		||||
     break;
 | 
			
		||||
   }
 | 
			
		||||
+
 | 
			
		||||
+  errno = orig_errno; /* Restore errno before leaving the function. */
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Note: preserves the previous value of errno. */
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,94 @@
 | 
			
		||||
From 6b9d4380df9bd0be91f49aad8c4f47b4e672adde Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Eric Blake <eblake@redhat.com>
 | 
			
		||||
Date: Mon, 16 Aug 2021 13:43:29 -0500
 | 
			
		||||
Subject: [PATCH] server: CVE-2021-3716 reset structured replies on starttls
 | 
			
		||||
 | 
			
		||||
https://nostarttls.secvuln.info/ pointed out a series of CVEs in
 | 
			
		||||
common implementation flaw in various SMTP and IMAP clients and
 | 
			
		||||
servers, all with a common thread of improperly caching plaintext
 | 
			
		||||
state across the STARTTLS encryption boundary; and recommended that
 | 
			
		||||
other protocols with a STARTTLS operation perform a similar audit.
 | 
			
		||||
 | 
			
		||||
It turns out that nbdkit has the same vulnerability in regards to the
 | 
			
		||||
NBD protocol: when nbdkit is run in opportunistic TLS mode, an
 | 
			
		||||
attacker is able to inject a plaintext NBD_OPT_STRUCTURED_REPLY before
 | 
			
		||||
proxying everything else a client sends to the server; if the server
 | 
			
		||||
then acts on that plaintext request (as nbdkit did before this patch),
 | 
			
		||||
then the server ends up sending structured replies to at least
 | 
			
		||||
NBD_CMD_READ, even though the client was assuming that the transition
 | 
			
		||||
to TLS has ruled out a MitM attack.
 | 
			
		||||
 | 
			
		||||
On the bright side, nbdkit's behavior on a second
 | 
			
		||||
NBD_OPT_STRUCTURED_REPLY was to still reply with success, so a client
 | 
			
		||||
that always requests structured replies after starting TLS sees no
 | 
			
		||||
difference in behavior (that is, qemu 2.12 and later are immune) (had
 | 
			
		||||
nbdkit given an error to the second request, that may have caused
 | 
			
		||||
confusion to more clients).  And there is always the mitigation of
 | 
			
		||||
using --tls=require, which lets nbdkit reject the MitM message
 | 
			
		||||
pre-encryption.  However, nbd-client 3.15 to the present do not
 | 
			
		||||
understand structured replies, and I have confirmed that a MitM
 | 
			
		||||
attacker can thus cause a denial-of-service attack that does not
 | 
			
		||||
trigger until the client does its first encrypted NBD_CMD_READ.
 | 
			
		||||
 | 
			
		||||
The NBD spec has been recently tightened to declare the nbdkit
 | 
			
		||||
behavior to be a security hole:
 | 
			
		||||
https://github.com/NetworkBlockDevice/nbd/commit/77e55378096aa
 | 
			
		||||
Fixes: eaa4c6e9a2c4bd (server: Minimal implementation of NBD Structured Replies.)
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 09a13dafb7bb3a38ab52eb5501cba786365ba7fd)
 | 
			
		||||
(cherry picked from commit 6185b15a81e6915734d678f0781e31d45a7941a1)
 | 
			
		||||
---
 | 
			
		||||
 docs/nbdkit-security.pod             | 11 +++++++++--
 | 
			
		||||
 server/protocol-handshake-newstyle.c |  3 ++-
 | 
			
		||||
 2 files changed, 11 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/docs/nbdkit-security.pod b/docs/nbdkit-security.pod
 | 
			
		||||
index 3a28e54d..5a4e6da8 100644
 | 
			
		||||
--- a/docs/nbdkit-security.pod
 | 
			
		||||
+++ b/docs/nbdkit-security.pod
 | 
			
		||||
@@ -10,7 +10,7 @@ For how to report new security issues, see the C<SECURITY> file in the
 | 
			
		||||
 top level source directory, also available online here:
 | 
			
		||||
 L<https://github.com/libguestfs/nbdkit/blob/master/SECURITY>
 | 
			
		||||
 
 | 
			
		||||
-=head2 CVE-2019-14850 
 | 
			
		||||
+=head2 CVE-2019-14850
 | 
			
		||||
 denial of service due to premature opening of back-end connection
 | 
			
		||||
 
 | 
			
		||||
 See the full announcement and links to mitigation, tests and fixes
 | 
			
		||||
@@ -26,6 +26,13 @@ See the full announcement and links to mitigation, tests and fixes
 | 
			
		||||
 here:
 | 
			
		||||
 https://www.redhat.com/archives/libguestfs/2019-September/msg00272.html
 | 
			
		||||
 
 | 
			
		||||
+=head2 CVE-2021-3716
 | 
			
		||||
+structured read denial of service attack against starttls
 | 
			
		||||
+
 | 
			
		||||
+See the full announcement and links to mitigation, tests and fixes
 | 
			
		||||
+here:
 | 
			
		||||
+https://www.redhat.com/archives/libguestfs/2021-August/msg00083.html
 | 
			
		||||
+
 | 
			
		||||
 =head1 SEE ALSO
 | 
			
		||||
 
 | 
			
		||||
 L<nbdkit(1)>.
 | 
			
		||||
@@ -38,4 +45,4 @@ Richard W.M. Jones
 | 
			
		||||
 
 | 
			
		||||
 =head1 COPYRIGHT
 | 
			
		||||
 
 | 
			
		||||
-Copyright (C) 2013-2020 Red Hat Inc.
 | 
			
		||||
+Copyright (C) 2013-2021 Red Hat Inc.
 | 
			
		||||
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
 | 
			
		||||
index 0a76a814..b94950e2 100644
 | 
			
		||||
--- a/server/protocol-handshake-newstyle.c
 | 
			
		||||
+++ b/server/protocol-handshake-newstyle.c
 | 
			
		||||
@@ -495,7 +495,8 @@ negotiate_handshake_newstyle_options (void)
 | 
			
		||||
           return -1;
 | 
			
		||||
         conn->using_tls = true;
 | 
			
		||||
         debug ("using TLS on this connection");
 | 
			
		||||
-        /* Wipe out any cached default export name. */
 | 
			
		||||
+        /* Wipe out any cached state. */
 | 
			
		||||
+        conn->structured_replies = false;
 | 
			
		||||
         for_each_backend (b) {
 | 
			
		||||
           struct handle *h = get_handle (conn, b->i);
 | 
			
		||||
           free (h->default_exportname);
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
@ -1,177 +0,0 @@
 | 
			
		||||
From ae28c97079cce7792c5954f67a418402a48ed0cf Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Wed, 24 Jul 2024 10:29:13 +0100
 | 
			
		||||
Subject: [PATCH] server: Rename threadlocal_{set,get}_error to .._errno
 | 
			
		||||
 | 
			
		||||
A simple mechanical change, to avoid confusion with
 | 
			
		||||
threadlocal_{set,get}_last_error introduced in the following commit.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 1d7f655726ad3483d0e8086741182aada7ae8595)
 | 
			
		||||
---
 | 
			
		||||
 server/internal.h    |  4 ++--
 | 
			
		||||
 server/plugins.c     | 27 +++++++++++++--------------
 | 
			
		||||
 server/protocol.c    |  5 +++--
 | 
			
		||||
 server/threadlocal.c |  4 ++--
 | 
			
		||||
 4 files changed, 20 insertions(+), 20 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/server/internal.h b/server/internal.h
 | 
			
		||||
index 57e777e9..6549c87b 100644
 | 
			
		||||
--- a/server/internal.h
 | 
			
		||||
+++ b/server/internal.h
 | 
			
		||||
@@ -568,8 +568,8 @@ extern void threadlocal_set_name (const char *name)
 | 
			
		||||
 extern const char *threadlocal_get_name (void);
 | 
			
		||||
 extern void threadlocal_set_instance_num (size_t instance_num);
 | 
			
		||||
 extern size_t threadlocal_get_instance_num (void);
 | 
			
		||||
-extern void threadlocal_set_error (int err);
 | 
			
		||||
-extern int threadlocal_get_error (void);
 | 
			
		||||
+extern void threadlocal_set_errno (int err);
 | 
			
		||||
+extern int threadlocal_get_errno (void);
 | 
			
		||||
 extern void *threadlocal_buffer (size_t size);
 | 
			
		||||
 extern void threadlocal_set_conn (struct connection *conn);
 | 
			
		||||
 extern struct connection *threadlocal_get_conn (void);
 | 
			
		||||
diff --git a/server/plugins.c b/server/plugins.c
 | 
			
		||||
index ca89ac7a..3c7df0d2 100644
 | 
			
		||||
--- a/server/plugins.c
 | 
			
		||||
+++ b/server/plugins.c
 | 
			
		||||
@@ -633,15 +633,14 @@ plugin_can_cache (struct context *c)
 | 
			
		||||
 NBDKIT_DLL_PUBLIC void
 | 
			
		||||
 nbdkit_set_error (int err)
 | 
			
		||||
 {
 | 
			
		||||
-  threadlocal_set_error (err);
 | 
			
		||||
+  threadlocal_set_errno (err);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-/* Grab the appropriate error value.
 | 
			
		||||
- */
 | 
			
		||||
+/* Grab the appropriate error value. */
 | 
			
		||||
 static int
 | 
			
		||||
-get_error (struct backend_plugin *p)
 | 
			
		||||
+get_errno (struct backend_plugin *p)
 | 
			
		||||
 {
 | 
			
		||||
-  int ret = threadlocal_get_error ();
 | 
			
		||||
+  int ret = threadlocal_get_errno ();
 | 
			
		||||
 
 | 
			
		||||
   if (!ret && p->plugin.errno_is_preserved != 0)
 | 
			
		||||
     ret = errno;
 | 
			
		||||
@@ -664,7 +663,7 @@ plugin_pread (struct context *c,
 | 
			
		||||
   else
 | 
			
		||||
     r = p->plugin._pread_v1 (c->handle, buf, count, offset);
 | 
			
		||||
   if (r == -1)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -685,7 +684,7 @@ plugin_flush (struct context *c,
 | 
			
		||||
     return -1;
 | 
			
		||||
   }
 | 
			
		||||
   if (r == -1)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -715,7 +714,7 @@ plugin_pwrite (struct context *c,
 | 
			
		||||
   if (r != -1 && need_flush)
 | 
			
		||||
     r = plugin_flush (c, 0, err);
 | 
			
		||||
   if (r == -1 && !*err)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -744,7 +743,7 @@ plugin_trim (struct context *c,
 | 
			
		||||
   if (r != -1 && need_flush)
 | 
			
		||||
     r = plugin_flush (c, 0, err);
 | 
			
		||||
   if (r == -1 && !*err)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -782,7 +781,7 @@ plugin_zero (struct context *c,
 | 
			
		||||
     else
 | 
			
		||||
       emulate = true;
 | 
			
		||||
     if (r == -1)
 | 
			
		||||
-      *err = emulate ? EOPNOTSUPP : get_error (p);
 | 
			
		||||
+      *err = emulate ? EOPNOTSUPP : get_errno (p);
 | 
			
		||||
     if (r == 0 || (*err != EOPNOTSUPP && *err != ENOTSUP))
 | 
			
		||||
       goto done;
 | 
			
		||||
   }
 | 
			
		||||
@@ -794,7 +793,7 @@ plugin_zero (struct context *c,
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   flags &= ~NBDKIT_FLAG_MAY_TRIM;
 | 
			
		||||
-  threadlocal_set_error (0);
 | 
			
		||||
+  threadlocal_set_errno (0);
 | 
			
		||||
   *err = 0;
 | 
			
		||||
 
 | 
			
		||||
   while (count) {
 | 
			
		||||
@@ -814,7 +813,7 @@ plugin_zero (struct context *c,
 | 
			
		||||
   if (r != -1 && need_flush)
 | 
			
		||||
     r = plugin_flush (c, 0, err);
 | 
			
		||||
   if (r == -1 && !*err)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -839,7 +838,7 @@ plugin_extents (struct context *c,
 | 
			
		||||
     r = -1;
 | 
			
		||||
   }
 | 
			
		||||
   if (r == -1)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -859,7 +858,7 @@ plugin_cache (struct context *c,
 | 
			
		||||
 
 | 
			
		||||
   r = p->plugin.cache (c->handle, count, offset, flags);
 | 
			
		||||
   if (r == -1)
 | 
			
		||||
-    *err = get_error (p);
 | 
			
		||||
+    *err = get_errno (p);
 | 
			
		||||
   return r;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/server/protocol.c b/server/protocol.c
 | 
			
		||||
index 9b63f789..677da05c 100644
 | 
			
		||||
--- a/server/protocol.c
 | 
			
		||||
+++ b/server/protocol.c
 | 
			
		||||
@@ -235,8 +235,9 @@ handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
 | 
			
		||||
   int err = 0;
 | 
			
		||||
 
 | 
			
		||||
   /* Clear the error, so that we know if the plugin calls
 | 
			
		||||
-   * nbdkit_set_error() or relied on errno.  */
 | 
			
		||||
-  threadlocal_set_error (0);
 | 
			
		||||
+   * nbdkit_set_error() or relied on errno.
 | 
			
		||||
+   */
 | 
			
		||||
+  threadlocal_set_errno (0);
 | 
			
		||||
 
 | 
			
		||||
   switch (cmd) {
 | 
			
		||||
   case NBD_CMD_READ:
 | 
			
		||||
diff --git a/server/threadlocal.c b/server/threadlocal.c
 | 
			
		||||
index 088fe55a..9bb656bc 100644
 | 
			
		||||
--- a/server/threadlocal.c
 | 
			
		||||
+++ b/server/threadlocal.c
 | 
			
		||||
@@ -154,7 +154,7 @@ threadlocal_get_instance_num (void)
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 void
 | 
			
		||||
-threadlocal_set_error (int err)
 | 
			
		||||
+threadlocal_set_errno (int err)
 | 
			
		||||
 {
 | 
			
		||||
   struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
 | 
			
		||||
 
 | 
			
		||||
@@ -167,7 +167,7 @@ threadlocal_set_error (int err)
 | 
			
		||||
 /* This preserves errno, for convenience.
 | 
			
		||||
  */
 | 
			
		||||
 int
 | 
			
		||||
-threadlocal_get_error (void)
 | 
			
		||||
+threadlocal_get_errno (void)
 | 
			
		||||
 {
 | 
			
		||||
   int err = errno;
 | 
			
		||||
   struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,95 +0,0 @@
 | 
			
		||||
From 00107f9d36fc6a1b33a1bde25e3239c520b82ab1 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Wed, 24 Jul 2024 10:37:58 +0100
 | 
			
		||||
Subject: [PATCH] server: Introduce threadlocal_{set,get}_last_error
 | 
			
		||||
 | 
			
		||||
Plus a function to clear the last_error field.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit fa5055ae2b9f96af941d697de39198c96ee2580a)
 | 
			
		||||
---
 | 
			
		||||
 server/internal.h    |  3 +++
 | 
			
		||||
 server/threadlocal.c | 40 ++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 2 files changed, 43 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/server/internal.h b/server/internal.h
 | 
			
		||||
index 6549c87b..da19fb99 100644
 | 
			
		||||
--- a/server/internal.h
 | 
			
		||||
+++ b/server/internal.h
 | 
			
		||||
@@ -570,6 +570,9 @@ extern void threadlocal_set_instance_num (size_t instance_num);
 | 
			
		||||
 extern size_t threadlocal_get_instance_num (void);
 | 
			
		||||
 extern void threadlocal_set_errno (int err);
 | 
			
		||||
 extern int threadlocal_get_errno (void);
 | 
			
		||||
+extern void threadlocal_set_last_error (char *msg);
 | 
			
		||||
+extern void threadlocal_clear_last_error (void);
 | 
			
		||||
+extern const char *threadlocal_get_last_error (void);
 | 
			
		||||
 extern void *threadlocal_buffer (size_t size);
 | 
			
		||||
 extern void threadlocal_set_conn (struct connection *conn);
 | 
			
		||||
 extern struct connection *threadlocal_get_conn (void);
 | 
			
		||||
diff --git a/server/threadlocal.c b/server/threadlocal.c
 | 
			
		||||
index 9bb656bc..74a3c4e5 100644
 | 
			
		||||
--- a/server/threadlocal.c
 | 
			
		||||
+++ b/server/threadlocal.c
 | 
			
		||||
@@ -56,6 +56,7 @@ struct threadlocal {
 | 
			
		||||
   char *name;                   /* Can be NULL. */
 | 
			
		||||
   size_t instance_num;          /* Can be 0. */
 | 
			
		||||
   int err;
 | 
			
		||||
+  char *last_error;             /* Can be NULL. */
 | 
			
		||||
   void *buffer;                 /* Can be NULL. */
 | 
			
		||||
   size_t buffer_size;
 | 
			
		||||
   struct connection *conn;      /* Can be NULL. */
 | 
			
		||||
@@ -70,6 +71,7 @@ free_threadlocal (void *threadlocalv)
 | 
			
		||||
   struct threadlocal *threadlocal = threadlocalv;
 | 
			
		||||
 
 | 
			
		||||
   free (threadlocal->name);
 | 
			
		||||
+  free (threadlocal->last_error);
 | 
			
		||||
   free (threadlocal->buffer);
 | 
			
		||||
   free (threadlocal);
 | 
			
		||||
 }
 | 
			
		||||
@@ -176,6 +178,44 @@ threadlocal_get_errno (void)
 | 
			
		||||
   return threadlocal ? threadlocal->err : 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+/* Set the last_error field.  The ownership of the 'msg' string is
 | 
			
		||||
+ * passed to the threadlocal and will be freed here.
 | 
			
		||||
+ */
 | 
			
		||||
+void
 | 
			
		||||
+threadlocal_set_last_error (char *msg)
 | 
			
		||||
+{
 | 
			
		||||
+  struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
 | 
			
		||||
+
 | 
			
		||||
+  if (threadlocal) {
 | 
			
		||||
+    free (threadlocal->last_error);
 | 
			
		||||
+    threadlocal->last_error = msg;
 | 
			
		||||
+  }
 | 
			
		||||
+  else {
 | 
			
		||||
+    /* ... otherwise throw it away, it's informational. */
 | 
			
		||||
+    free (msg);
 | 
			
		||||
+  }
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void
 | 
			
		||||
+threadlocal_clear_last_error (void)
 | 
			
		||||
+{
 | 
			
		||||
+  threadlocal_set_last_error (NULL);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+/* Get the last_error field.  If successful, this returns a non-NULL
 | 
			
		||||
+ * string.  This is valid until something calls nbdkit_error() in the
 | 
			
		||||
+ * same thread, so it should be used quickly.  Returning NULL is not
 | 
			
		||||
+ * necessarily an error.  The last_error is informational and may not
 | 
			
		||||
+ * be available.
 | 
			
		||||
+ */
 | 
			
		||||
+const char *
 | 
			
		||||
+threadlocal_get_last_error (void)
 | 
			
		||||
+{
 | 
			
		||||
+  struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
 | 
			
		||||
+
 | 
			
		||||
+  return threadlocal ? threadlocal->last_error : NULL;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* Return the single pread/pwrite buffer for this thread.  The buffer
 | 
			
		||||
  * size is increased to ‘size’ bytes if required.
 | 
			
		||||
  *
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
From add9b794b9dc697a1b52115c997fcfb6e06bf64c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Eric Blake <eblake@redhat.com>
 | 
			
		||||
Date: Mon, 16 Aug 2021 13:43:29 -0500
 | 
			
		||||
Subject: [PATCH] server: reset meta context replies on starttls
 | 
			
		||||
 | 
			
		||||
Related to CVE-2021-3716, but not as severe.  No compliant client will
 | 
			
		||||
send NBD_CMD_BLOCK_STATUS unless it first negotiates
 | 
			
		||||
NBD_OPT_SET_META_CONTEXT.  If an attacker injects a premature
 | 
			
		||||
SET_META_CONTEXT, either the client will never notice (because it
 | 
			
		||||
never uses BLOCK_STATUS), or the client will overwrite the attacker's
 | 
			
		||||
attempt with the client's own SET_META_CONTEXT request after
 | 
			
		||||
encryption is enabled.  So I don't class this as having the potential
 | 
			
		||||
to trigger denial-of-service due to any protocol mismatch between
 | 
			
		||||
compliant client and server (I don't care what happens with
 | 
			
		||||
non-compliant clients).
 | 
			
		||||
 | 
			
		||||
Fixes: 26455d45 (server: protocol: Implement Block Status "base:allocation".)
 | 
			
		||||
(cherry picked from commit 6c5faac6a37077cf2366388a80862bb00616d0d8)
 | 
			
		||||
(cherry picked from commit 814d8103fb4b581dc01dfd25d2cd81596576f211)
 | 
			
		||||
---
 | 
			
		||||
 server/protocol-handshake-newstyle.c | 3 +++
 | 
			
		||||
 1 file changed, 3 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
 | 
			
		||||
index b94950e2..eb0f3961 100644
 | 
			
		||||
--- a/server/protocol-handshake-newstyle.c
 | 
			
		||||
+++ b/server/protocol-handshake-newstyle.c
 | 
			
		||||
@@ -497,6 +497,9 @@ negotiate_handshake_newstyle_options (void)
 | 
			
		||||
         debug ("using TLS on this connection");
 | 
			
		||||
         /* Wipe out any cached state. */
 | 
			
		||||
         conn->structured_replies = false;
 | 
			
		||||
+        free (conn->exportname_from_set_meta_context);
 | 
			
		||||
+        conn->exportname_from_set_meta_context = NULL;
 | 
			
		||||
+        conn->meta_context_base_allocation = false;
 | 
			
		||||
         for_each_backend (b) {
 | 
			
		||||
           struct handle *h = get_handle (conn, b->i);
 | 
			
		||||
           free (h->default_exportname);
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,59 @@
 | 
			
		||||
From 3c2879a38c299b725091cea45329879e3f46fc99 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Tue, 31 Aug 2021 11:23:27 +0100
 | 
			
		||||
Subject: [PATCH] cow: Fix for qemu 6.1 which requires backing format
 | 
			
		||||
 | 
			
		||||
The diffing example in the manual created a qcow2 file with a backing
 | 
			
		||||
file but did not specify the backing format.  However qemu 6.1 now
 | 
			
		||||
requires this and fails with:
 | 
			
		||||
 | 
			
		||||
  qemu-img: cow-diff.qcow2: Backing file specified without backing format
 | 
			
		||||
 | 
			
		||||
or:
 | 
			
		||||
 | 
			
		||||
  qemu-img: Could not change the backing file to 'cow-base.img': backing format must be specified
 | 
			
		||||
 | 
			
		||||
Fix the example by adding the -F option to the command line.
 | 
			
		||||
 | 
			
		||||
Also there was a test of this rebasing sequence which failed, so this
 | 
			
		||||
commit updates the test too.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 618290ef33ce13b75c1a79fea1f1ffb327b5ba07)
 | 
			
		||||
---
 | 
			
		||||
 filters/cow/nbdkit-cow-filter.pod | 4 ++--
 | 
			
		||||
 tests/test-cow.sh                 | 4 ++--
 | 
			
		||||
 2 files changed, 4 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/filters/cow/nbdkit-cow-filter.pod b/filters/cow/nbdkit-cow-filter.pod
 | 
			
		||||
index 4d5ae856..510bdd40 100644
 | 
			
		||||
--- a/filters/cow/nbdkit-cow-filter.pod
 | 
			
		||||
+++ b/filters/cow/nbdkit-cow-filter.pod
 | 
			
		||||
@@ -101,8 +101,8 @@ At the end, disconnect the client.
 | 
			
		||||
 Run these C<qemu-img> commands to construct a qcow2 file containing
 | 
			
		||||
 the differences:
 | 
			
		||||
 
 | 
			
		||||
- qemu-img create -f qcow2 -b nbd:localhost diff.qcow2
 | 
			
		||||
- qemu-img rebase -b disk.img diff.qcow2
 | 
			
		||||
+ qemu-img create -F raw -b nbd:localhost -f qcow2 diff.qcow2
 | 
			
		||||
+ qemu-img rebase -F raw -b disk.img -f qcow2 diff.qcow2
 | 
			
		||||
 
 | 
			
		||||
 F<diff.qcow2> now contains the differences between the base
 | 
			
		||||
 (F<disk.img>) and the changes stored in nbdkit-cow-filter.  C<nbdkit>
 | 
			
		||||
diff --git a/tests/test-cow.sh b/tests/test-cow.sh
 | 
			
		||||
index 8772afd7..edc4c223 100755
 | 
			
		||||
--- a/tests/test-cow.sh
 | 
			
		||||
+++ b/tests/test-cow.sh
 | 
			
		||||
@@ -72,8 +72,8 @@ fi
 | 
			
		||||
 # If we have qemu-img, try the hairy rebase operation documented
 | 
			
		||||
 # in the nbdkit-cow-filter manual.
 | 
			
		||||
 if qemu-img --version >/dev/null 2>&1; then
 | 
			
		||||
-    qemu-img create -f qcow2 -b nbd:unix:$sock cow-diff.qcow2
 | 
			
		||||
-    time qemu-img rebase -b cow-base.img cow-diff.qcow2
 | 
			
		||||
+    qemu-img create -F raw -b nbd:unix:$sock -f qcow2 cow-diff.qcow2
 | 
			
		||||
+    time qemu-img rebase -F raw -b cow-base.img -f qcow2 cow-diff.qcow2
 | 
			
		||||
     qemu-img info cow-diff.qcow2
 | 
			
		||||
 
 | 
			
		||||
     # This checks the file we created exists.
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
@ -1,95 +0,0 @@
 | 
			
		||||
From 4cde9d78c4293e294f80376266cfce420f15a6ff Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Tue, 23 Jul 2024 15:28:06 +0100
 | 
			
		||||
Subject: [PATCH] server: Take a thread-local copy of the last call to
 | 
			
		||||
 nbdkit_error
 | 
			
		||||
 | 
			
		||||
nbdkit_error has traditionally been a "fancy wrapper around fprintf"
 | 
			
		||||
(kind of, don't take that literally).  It is encouraged that plugins
 | 
			
		||||
and filters do something like:
 | 
			
		||||
 | 
			
		||||
  if (error) {
 | 
			
		||||
    nbdkit_error ("oops, a bad thing happened");
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
but we don't enforce this.  Plugins might call nbdkit_error more than
 | 
			
		||||
once or not at all.
 | 
			
		||||
 | 
			
		||||
The point where we get to sending an error back over the wire to the
 | 
			
		||||
NBD client is long after the plugin returned above, and after
 | 
			
		||||
nbdkit_error was called.
 | 
			
		||||
 | 
			
		||||
Therefore in order to send errors back to the NBD client, we must keep
 | 
			
		||||
the last error message around.
 | 
			
		||||
 | 
			
		||||
This change simply modifies nbdkit_error to make a best-effort attempt
 | 
			
		||||
to save the last error message in thread-local storage.
 | 
			
		||||
 | 
			
		||||
We also clear the last error when a new request starts, to ensure that
 | 
			
		||||
we don't leak errors across different callbacks or connections.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit bfa6d4064cb74f429149d14ab4025b258fc95ec4)
 | 
			
		||||
---
 | 
			
		||||
 server/log.c      | 21 +++++++++++++++++++++
 | 
			
		||||
 server/protocol.c |  5 +++++
 | 
			
		||||
 2 files changed, 26 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/server/log.c b/server/log.c
 | 
			
		||||
index 9c1f667a..acf14d57 100644
 | 
			
		||||
--- a/server/log.c
 | 
			
		||||
+++ b/server/log.c
 | 
			
		||||
@@ -40,6 +40,25 @@
 | 
			
		||||
 
 | 
			
		||||
 #include "internal.h"
 | 
			
		||||
 
 | 
			
		||||
+/* Copy the error message to threadlocal.  This is sent to callers
 | 
			
		||||
+ * which are using structured replies, but is for extra information
 | 
			
		||||
+ * only so don't fail if we are unable to copy it.
 | 
			
		||||
+ */
 | 
			
		||||
+static void
 | 
			
		||||
+copy_error_to_threadlocal (int orig_errno, const char *fs, va_list args)
 | 
			
		||||
+{
 | 
			
		||||
+  va_list args_copy;
 | 
			
		||||
+  char *msg;
 | 
			
		||||
+  int r;
 | 
			
		||||
+
 | 
			
		||||
+  va_copy (args_copy, args);
 | 
			
		||||
+  errno = orig_errno;        /* must restore in case fs contains %m */
 | 
			
		||||
+  r = vasprintf (&msg, fs, args_copy);
 | 
			
		||||
+  va_end (args_copy);
 | 
			
		||||
+  if (r != -1 && msg)
 | 
			
		||||
+    threadlocal_set_last_error (msg); /* ownership passed to threadlocal */
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* Call the right log_*_verror function depending on log_sink.
 | 
			
		||||
  * Note: preserves the previous value of errno.
 | 
			
		||||
  */
 | 
			
		||||
@@ -48,6 +67,8 @@ log_verror (const char *fs, va_list args)
 | 
			
		||||
 {
 | 
			
		||||
   int orig_errno = errno;
 | 
			
		||||
 
 | 
			
		||||
+  copy_error_to_threadlocal (orig_errno, fs, args);
 | 
			
		||||
+
 | 
			
		||||
   switch (log_to) {
 | 
			
		||||
   case LOG_TO_DEFAULT:
 | 
			
		||||
     if (forked_into_background)
 | 
			
		||||
diff --git a/server/protocol.c b/server/protocol.c
 | 
			
		||||
index 677da05c..d428bfc8 100644
 | 
			
		||||
--- a/server/protocol.c
 | 
			
		||||
+++ b/server/protocol.c
 | 
			
		||||
@@ -239,6 +239,11 @@ handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
 | 
			
		||||
    */
 | 
			
		||||
   threadlocal_set_errno (0);
 | 
			
		||||
 
 | 
			
		||||
+  /* Also clear the last error in this thread so we will only save
 | 
			
		||||
+   * nbdkit_error() from this request.
 | 
			
		||||
+   */
 | 
			
		||||
+  threadlocal_clear_last_error ();
 | 
			
		||||
+
 | 
			
		||||
   switch (cmd) {
 | 
			
		||||
   case NBD_CMD_READ:
 | 
			
		||||
     if (backend_pread (c, buf, count, offset, 0, &err) == -1)
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,177 +0,0 @@
 | 
			
		||||
From e121d8e1d39605043317cbdf28f60056e6681d56 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Tue, 23 Jul 2024 15:45:04 +0100
 | 
			
		||||
Subject: [PATCH] server: Send the last error to the NBD client
 | 
			
		||||
 | 
			
		||||
This sends the last error saved in the connection handle back to the
 | 
			
		||||
NBD client.  This is informational and best effort.
 | 
			
		||||
 | 
			
		||||
qemu reports the error already, for example:
 | 
			
		||||
 | 
			
		||||
  $ nbdkit --log=null \
 | 
			
		||||
           eval open=' echo EPERM Go Away >&2; exit 1 ' get_size=' echo 100 ' \
 | 
			
		||||
           --run 'qemu-img info "$uri"'
 | 
			
		||||
  qemu-img: Could not open 'nbd+unix://?socket=/tmp/nbdkitIDl6iy/socket': Requested export not available
 | 
			
		||||
  server reported: /tmp/nbdkitRDAfXH/open: Go Away
 | 
			
		||||
 | 
			
		||||
This goes back to at least qemu 2.12.0 (RHEL 7) and possibly earlier,
 | 
			
		||||
so we can just assume that qemu does this for the test.
 | 
			
		||||
 | 
			
		||||
libnbd requires a patch to display this information.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 46484ca8e6a35c45fe96b6c972ceba8984d401e8)
 | 
			
		||||
---
 | 
			
		||||
 server/protocol-handshake-newstyle.c | 43 ++++++++++++++++------
 | 
			
		||||
 tests/Makefile.am                    |  2 +
 | 
			
		||||
 tests/test-last-error.sh             | 55 ++++++++++++++++++++++++++++
 | 
			
		||||
 3 files changed, 88 insertions(+), 12 deletions(-)
 | 
			
		||||
 create mode 100755 tests/test-last-error.sh
 | 
			
		||||
 | 
			
		||||
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
 | 
			
		||||
index 6b3bc76f..c18d32e5 100644
 | 
			
		||||
--- a/server/protocol-handshake-newstyle.c
 | 
			
		||||
+++ b/server/protocol-handshake-newstyle.c
 | 
			
		||||
@@ -57,28 +57,47 @@ send_newstyle_option_reply (uint32_t option, uint32_t reply)
 | 
			
		||||
 {
 | 
			
		||||
   GET_CONN;
 | 
			
		||||
   struct nbd_fixed_new_option_reply fixed_new_option_reply;
 | 
			
		||||
+  const char *last_error = NULL;
 | 
			
		||||
+  uint32_t replylen = 0;
 | 
			
		||||
+
 | 
			
		||||
+  if (NBD_REP_IS_ERR (reply)) {
 | 
			
		||||
+    last_error = threadlocal_get_last_error ();
 | 
			
		||||
+    /* Note that calling nbdkit_error will invalidate last_error, so
 | 
			
		||||
+     * be careful below.
 | 
			
		||||
+     */
 | 
			
		||||
+    if (last_error) {
 | 
			
		||||
+      size_t len = strlen (last_error);
 | 
			
		||||
+      if (len <= NBD_MAX_STRING)
 | 
			
		||||
+        replylen = len;
 | 
			
		||||
+    }
 | 
			
		||||
+  }
 | 
			
		||||
 
 | 
			
		||||
   fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
 | 
			
		||||
   fixed_new_option_reply.option = htobe32 (option);
 | 
			
		||||
   fixed_new_option_reply.reply = htobe32 (reply);
 | 
			
		||||
-  fixed_new_option_reply.replylen = htobe32 (0);
 | 
			
		||||
+  fixed_new_option_reply.replylen = htobe32 (replylen);
 | 
			
		||||
 
 | 
			
		||||
   debug ("replying to %s with %s", name_of_nbd_opt (option),
 | 
			
		||||
          name_of_nbd_rep (reply));
 | 
			
		||||
   if (conn->send (&fixed_new_option_reply,
 | 
			
		||||
-                  sizeof fixed_new_option_reply, 0) == -1) {
 | 
			
		||||
-    /* The protocol document says that the client is allowed to simply
 | 
			
		||||
-     * drop the connection after sending NBD_OPT_ABORT, or may read
 | 
			
		||||
-     * the reply.
 | 
			
		||||
-     */
 | 
			
		||||
-    if (option == NBD_OPT_ABORT)
 | 
			
		||||
-      debug ("write: %s: %m", name_of_nbd_opt (option));
 | 
			
		||||
-    else
 | 
			
		||||
-      nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
 | 
			
		||||
-    return -1;
 | 
			
		||||
-  }
 | 
			
		||||
+                  sizeof fixed_new_option_reply,
 | 
			
		||||
+                  replylen > 0 ? SEND_MORE : 0) == -1)
 | 
			
		||||
+    goto err;
 | 
			
		||||
+  if (replylen > 0 && conn->send (last_error, replylen, 0) == -1)
 | 
			
		||||
+    goto err;
 | 
			
		||||
 
 | 
			
		||||
   return 0;
 | 
			
		||||
+
 | 
			
		||||
+err:
 | 
			
		||||
+  /* The protocol document says that the client is allowed to simply
 | 
			
		||||
+   * drop the connection after sending NBD_OPT_ABORT, or may read
 | 
			
		||||
+   * the reply.
 | 
			
		||||
+   */
 | 
			
		||||
+  if (option == NBD_OPT_ABORT)
 | 
			
		||||
+    debug ("write: %s: %m", name_of_nbd_opt (option));
 | 
			
		||||
+  else
 | 
			
		||||
+    nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
 | 
			
		||||
+  return -1;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Reply to NBD_OPT_LIST with the plugin's list of export names.
 | 
			
		||||
diff --git a/tests/Makefile.am b/tests/Makefile.am
 | 
			
		||||
index b670fbf9..d510807c 100644
 | 
			
		||||
--- a/tests/Makefile.am
 | 
			
		||||
+++ b/tests/Makefile.am
 | 
			
		||||
@@ -276,6 +276,7 @@ TESTS += \
 | 
			
		||||
 	test-read-password-interactive.sh \
 | 
			
		||||
 	test-nbd-client.sh \
 | 
			
		||||
 	test-nbd-client-tls.sh \
 | 
			
		||||
+	test-last-error.sh \
 | 
			
		||||
 	$(NULL)
 | 
			
		||||
 if !IS_WINDOWS
 | 
			
		||||
 TESTS += \
 | 
			
		||||
@@ -301,6 +302,7 @@ EXTRA_DIST += \
 | 
			
		||||
 	test-plugin-docs.sh \
 | 
			
		||||
 	test-ipv4-lo.sh \
 | 
			
		||||
 	test-ipv6-lo.sh \
 | 
			
		||||
+	test-last-error.sh \
 | 
			
		||||
 	test-long-name.sh \
 | 
			
		||||
 	test-nbd-client.sh \
 | 
			
		||||
 	test-nbd-client-tls.sh \
 | 
			
		||||
diff --git a/tests/test-last-error.sh b/tests/test-last-error.sh
 | 
			
		||||
new file mode 100755
 | 
			
		||||
index 00000000..fc720606
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/tests/test-last-error.sh
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
+#!/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.
 | 
			
		||||
+
 | 
			
		||||
+source ./functions.sh
 | 
			
		||||
+set -e
 | 
			
		||||
+set -x
 | 
			
		||||
+
 | 
			
		||||
+# Test informational error messages sent to the NBD client.
 | 
			
		||||
+# qemu-img supports this since at least 2.12.0.
 | 
			
		||||
+
 | 
			
		||||
+requires_run
 | 
			
		||||
+requires_plugin eval
 | 
			
		||||
+requires qemu-img --version
 | 
			
		||||
+
 | 
			
		||||
+out=last-error.out
 | 
			
		||||
+rm -f $out
 | 
			
		||||
+cleanup_fn rm -f $out
 | 
			
		||||
+
 | 
			
		||||
+export out
 | 
			
		||||
+
 | 
			
		||||
+nbdkit eval \
 | 
			
		||||
+       open=' echo EPERM Go Away >&2; exit 1 ' get_size=' echo 0 ' \
 | 
			
		||||
+       --run ' qemu-img info "$uri" > $out 2>&1 ||: '
 | 
			
		||||
+cat $out
 | 
			
		||||
+
 | 
			
		||||
+grep "Go Away" $out
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,141 @@
 | 
			
		||||
From 9e20e2696fdb68008c9b4f1c36298f813320e381 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Sat, 23 Oct 2021 16:16:39 +0100
 | 
			
		||||
Subject: [PATCH] vddk: Include VDDK major library version in --dump-plugin
 | 
			
		||||
 output
 | 
			
		||||
 | 
			
		||||
Although it doesn't seem to be possible to get the precise VDDK
 | 
			
		||||
version, With a relatively simple change we can at least return the
 | 
			
		||||
VDDK major version.  Currently this can be 5, 6 or 7.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 8700649d147948897f3b97810a1dff37924bdd6e)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/nbdkit-vddk-plugin.pod |  4 ++++
 | 
			
		||||
 plugins/vddk/vddk.c                 | 29 +++++++++++++++++++----------
 | 
			
		||||
 tests/test-vddk-real-dump-plugin.sh |  2 ++
 | 
			
		||||
 3 files changed, 25 insertions(+), 10 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/nbdkit-vddk-plugin.pod b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
index 8b14eda0..822b96be 100644
 | 
			
		||||
--- a/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
+++ b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
@@ -417,6 +417,10 @@ at runtime.
 | 
			
		||||
 If this is printed then the C<nfchostport=PORT> parameter is supported
 | 
			
		||||
 by this build.
 | 
			
		||||
 
 | 
			
		||||
+=item C<vddk_library_version=...>
 | 
			
		||||
+
 | 
			
		||||
+The VDDK major library version: 5, 6, 7, ...
 | 
			
		||||
+
 | 
			
		||||
 =item C<vddk_dll=...>
 | 
			
		||||
 
 | 
			
		||||
 Prints the full path to the VDDK shared library.  Since this requires
 | 
			
		||||
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
 | 
			
		||||
index 69193504..291283f4 100644
 | 
			
		||||
--- a/plugins/vddk/vddk.c
 | 
			
		||||
+++ b/plugins/vddk/vddk.c
 | 
			
		||||
@@ -77,6 +77,7 @@ int vddk_debug_datapath = 1;
 | 
			
		||||
 static void *dl;                           /* dlopen handle */
 | 
			
		||||
 static bool init_called;                   /* was InitEx called */
 | 
			
		||||
 static __thread int error_suppression;     /* threadlocal error suppression */
 | 
			
		||||
+static int library_version;                /* VDDK major: 5, 6, 7, ... */
 | 
			
		||||
 
 | 
			
		||||
 static enum { NONE = 0, ZLIB, FASTLZ, SKIPZ } compression; /* compression */
 | 
			
		||||
 static char *config;                       /* config */
 | 
			
		||||
@@ -297,7 +298,10 @@ vddk_config (const char *key, const char *value)
 | 
			
		||||
 static void
 | 
			
		||||
 load_library (bool load_error_is_fatal)
 | 
			
		||||
 {
 | 
			
		||||
-  static const char *sonames[] = {
 | 
			
		||||
+  static struct {
 | 
			
		||||
+    const char *soname;
 | 
			
		||||
+    int library_version;
 | 
			
		||||
+  } libs[] = {
 | 
			
		||||
     /* Prefer the newest library in case multiple exist.  Check two
 | 
			
		||||
      * possible directories: the usual VDDK installation puts .so
 | 
			
		||||
      * files in an arch-specific subdirectory of $libdir (our minimum
 | 
			
		||||
@@ -305,12 +309,13 @@ load_library (bool load_error_is_fatal)
 | 
			
		||||
      * but our testsuite is easier to write if we point libdir
 | 
			
		||||
      * directly to a stub .so.
 | 
			
		||||
      */
 | 
			
		||||
-    "lib64/libvixDiskLib.so.7",
 | 
			
		||||
-    "libvixDiskLib.so.7",
 | 
			
		||||
-    "lib64/libvixDiskLib.so.6",
 | 
			
		||||
-    "libvixDiskLib.so.6",
 | 
			
		||||
-    "lib64/libvixDiskLib.so.5",
 | 
			
		||||
-    "libvixDiskLib.so.5",
 | 
			
		||||
+    { "lib64/libvixDiskLib.so.7", 7 },
 | 
			
		||||
+    { "libvixDiskLib.so.7",       7 },
 | 
			
		||||
+    { "lib64/libvixDiskLib.so.6", 6 },
 | 
			
		||||
+    { "libvixDiskLib.so.6",       6 },
 | 
			
		||||
+    { "lib64/libvixDiskLib.so.5", 5 },
 | 
			
		||||
+    { "libvixDiskLib.so.5",       5 },
 | 
			
		||||
+    { NULL }
 | 
			
		||||
   };
 | 
			
		||||
   size_t i;
 | 
			
		||||
   CLEANUP_FREE char *orig_error = NULL;
 | 
			
		||||
@@ -323,19 +328,20 @@ load_library (bool load_error_is_fatal)
 | 
			
		||||
     }
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
-  for (i = 0; i < sizeof sonames / sizeof sonames[0]; ++i) {
 | 
			
		||||
+  for (i = 0; libs[i].soname != NULL; ++i) {
 | 
			
		||||
     CLEANUP_FREE char *path;
 | 
			
		||||
 
 | 
			
		||||
     /* Set the full path so that dlopen will preferentially load the
 | 
			
		||||
      * system libraries from the same directory.
 | 
			
		||||
      */
 | 
			
		||||
-    if (asprintf (&path, "%s/%s", libdir, sonames[i]) == -1) {
 | 
			
		||||
+    if (asprintf (&path, "%s/%s", libdir, libs[i].soname) == -1) {
 | 
			
		||||
       nbdkit_error ("asprintf: %m");
 | 
			
		||||
       exit (EXIT_FAILURE);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     dl = dlopen (path, RTLD_NOW);
 | 
			
		||||
     if (dl != NULL) {
 | 
			
		||||
+      library_version = libs[i].library_version;
 | 
			
		||||
       /* Now that we found the library, ensure that LD_LIBRARY_PATH
 | 
			
		||||
        * includes its directory for all future loads.  This may modify
 | 
			
		||||
        * path in-place and/or re-exec nbdkit, but that's okay.
 | 
			
		||||
@@ -356,10 +362,12 @@ load_library (bool load_error_is_fatal)
 | 
			
		||||
                   "If '%s' is located on a non-standard path you may need to\n"
 | 
			
		||||
                   "set libdir=/path/to/vmware-vix-disklib-distrib.\n\n"
 | 
			
		||||
                   "See nbdkit-vddk-plugin(1) man page section \"LIBRARY LOCATION\" for details.",
 | 
			
		||||
-                  orig_error ? : "(unknown error)", sonames[0]);
 | 
			
		||||
+                  orig_error ? : "(unknown error)", libs[0].soname);
 | 
			
		||||
     exit (EXIT_FAILURE);
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
+  assert (library_version >= 5);
 | 
			
		||||
+
 | 
			
		||||
   /* Load symbols. */
 | 
			
		||||
 #define STUB(fn,ret,args)                                         \
 | 
			
		||||
   do {                                                            \
 | 
			
		||||
@@ -474,6 +482,7 @@ vddk_dump_plugin (void)
 | 
			
		||||
 
 | 
			
		||||
   printf ("vddk_default_libdir=%s\n", VDDK_LIBDIR);
 | 
			
		||||
   printf ("vddk_has_nfchostport=1\n");
 | 
			
		||||
+  printf ("vddk_library_version=%d\n", library_version);
 | 
			
		||||
 
 | 
			
		||||
 #if defined(HAVE_DLADDR)
 | 
			
		||||
   /* It would be nice to print the version of VDDK from the shared
 | 
			
		||||
diff --git a/tests/test-vddk-real-dump-plugin.sh b/tests/test-vddk-real-dump-plugin.sh
 | 
			
		||||
index 1479e416..59c79693 100755
 | 
			
		||||
--- a/tests/test-vddk-real-dump-plugin.sh
 | 
			
		||||
+++ b/tests/test-vddk-real-dump-plugin.sh
 | 
			
		||||
@@ -51,10 +51,12 @@ rm -f $files
 | 
			
		||||
 cleanup_fn rm -f $files
 | 
			
		||||
 
 | 
			
		||||
 nbdkit -f -v vddk libdir="$vddkdir" --dump-plugin > $out
 | 
			
		||||
+cat $out
 | 
			
		||||
 
 | 
			
		||||
 # Check the vddk_* entries are set.
 | 
			
		||||
 grep ^vddk_default_libdir= $out
 | 
			
		||||
 grep ^vddk_has_nfchostport= $out
 | 
			
		||||
+grep ^vddk_library_version= $out
 | 
			
		||||
 grep ^vddk_dll= $out
 | 
			
		||||
 
 | 
			
		||||
 dll="$(grep ^vddk_dll $out | cut -d= -f2)"
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
@ -1,28 +0,0 @@
 | 
			
		||||
From 47345a7a56c343e2cd559b736df685214ed75a9b Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Mon, 6 Jan 2025 15:22:05 +0000
 | 
			
		||||
Subject: [PATCH] vddk: Include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
Since this file uses booleans.
 | 
			
		||||
 | 
			
		||||
Acked-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
(cherry picked from commit fe855addae44e45e2344a33bd3857c561587f12e)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/worker.c | 1 +
 | 
			
		||||
 1 file changed, 1 insertion(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/worker.c b/plugins/vddk/worker.c
 | 
			
		||||
index 467d00ca..5982fcea 100644
 | 
			
		||||
--- a/plugins/vddk/worker.c
 | 
			
		||||
+++ b/plugins/vddk/worker.c
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
 
 | 
			
		||||
 #include <stdio.h>
 | 
			
		||||
 #include <stdlib.h>
 | 
			
		||||
+#include <stdbool.h>
 | 
			
		||||
 #include <stdint.h>
 | 
			
		||||
 #include <inttypes.h>
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,55 @@
 | 
			
		||||
From b8b376cf39d97c9f523a9867612126088b43c523 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Sat, 23 Oct 2021 19:50:52 +0100
 | 
			
		||||
Subject: [PATCH] vddk: Only print vddk_library_version when we managed to load
 | 
			
		||||
 the library
 | 
			
		||||
 | 
			
		||||
Because --dump-plugin calls load_library (false) it won't fail if we
 | 
			
		||||
didn't manage to load the library.  This results in library_version
 | 
			
		||||
being 0, which we printed incorrectly.
 | 
			
		||||
 | 
			
		||||
Resolve this problem by not printing the vddk_library_version entry in
 | 
			
		||||
this case.
 | 
			
		||||
 | 
			
		||||
Fixes: commit 8700649d147948897f3b97810a1dff37924bdd6e
 | 
			
		||||
(cherry picked from commit a3fba12c3e9c2113009f556360ae0bd04c45f6bb)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/nbdkit-vddk-plugin.pod | 1 +
 | 
			
		||||
 plugins/vddk/vddk.c                 | 9 ++++++++-
 | 
			
		||||
 2 files changed, 9 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/nbdkit-vddk-plugin.pod b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
index 822b96be..c56faddc 100644
 | 
			
		||||
--- a/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
+++ b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
@@ -420,6 +420,7 @@ by this build.
 | 
			
		||||
 =item C<vddk_library_version=...>
 | 
			
		||||
 
 | 
			
		||||
 The VDDK major library version: 5, 6, 7, ...
 | 
			
		||||
+If this is omitted it means the library could not be loaded.
 | 
			
		||||
 
 | 
			
		||||
 =item C<vddk_dll=...>
 | 
			
		||||
 
 | 
			
		||||
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
 | 
			
		||||
index 291283f4..96615749 100644
 | 
			
		||||
--- a/plugins/vddk/vddk.c
 | 
			
		||||
+++ b/plugins/vddk/vddk.c
 | 
			
		||||
@@ -482,7 +482,14 @@ vddk_dump_plugin (void)
 | 
			
		||||
 
 | 
			
		||||
   printf ("vddk_default_libdir=%s\n", VDDK_LIBDIR);
 | 
			
		||||
   printf ("vddk_has_nfchostport=1\n");
 | 
			
		||||
-  printf ("vddk_library_version=%d\n", library_version);
 | 
			
		||||
+
 | 
			
		||||
+  /* Because load_library (false) we might not have loaded VDDK, in
 | 
			
		||||
+   * which case we didn't set library_version.  Note this cannot
 | 
			
		||||
+   * happen in the normal (non-debug-plugin) path because there we use
 | 
			
		||||
+   * load_library (true).
 | 
			
		||||
+   */
 | 
			
		||||
+  if (library_version > 0)
 | 
			
		||||
+    printf ("vddk_library_version=%d\n", library_version);
 | 
			
		||||
 
 | 
			
		||||
 #if defined(HAVE_DLADDR)
 | 
			
		||||
   /* It would be nice to print the version of VDDK from the shared
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										53
									
								
								SOURCES/0007-vddk-Add-support-for-VDDK-8.0.0.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								SOURCES/0007-vddk-Add-support-for-VDDK-8.0.0.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
From e850f65053d89ad54c27280f48506da5eb631a68 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Fri, 18 Nov 2022 09:43:19 +0000
 | 
			
		||||
Subject: [PATCH] vddk: Add support for VDDK 8.0.0
 | 
			
		||||
 | 
			
		||||
There are no changes in any of the structures or enums that we rely on.
 | 
			
		||||
 | 
			
		||||
Reported-by: Ming Xie
 | 
			
		||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2143889
 | 
			
		||||
(cherry picked from commit dbe12ed499baeea94d603db55cad9e971e0ebcf0)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/nbdkit-vddk-plugin.pod | 2 +-
 | 
			
		||||
 plugins/vddk/vddk.c                 | 4 +++-
 | 
			
		||||
 2 files changed, 4 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/nbdkit-vddk-plugin.pod b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
index c56faddc..c94c41eb 100644
 | 
			
		||||
--- a/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
+++ b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
@@ -419,7 +419,7 @@ by this build.
 | 
			
		||||
 
 | 
			
		||||
 =item C<vddk_library_version=...>
 | 
			
		||||
 
 | 
			
		||||
-The VDDK major library version: 5, 6, 7, ...
 | 
			
		||||
+The VDDK major library version: 5, 6, 7, 8, ...
 | 
			
		||||
 If this is omitted it means the library could not be loaded.
 | 
			
		||||
 
 | 
			
		||||
 =item C<vddk_dll=...>
 | 
			
		||||
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
 | 
			
		||||
index 96615749..2140789a 100644
 | 
			
		||||
--- a/plugins/vddk/vddk.c
 | 
			
		||||
+++ b/plugins/vddk/vddk.c
 | 
			
		||||
@@ -77,7 +77,7 @@ int vddk_debug_datapath = 1;
 | 
			
		||||
 static void *dl;                           /* dlopen handle */
 | 
			
		||||
 static bool init_called;                   /* was InitEx called */
 | 
			
		||||
 static __thread int error_suppression;     /* threadlocal error suppression */
 | 
			
		||||
-static int library_version;                /* VDDK major: 5, 6, 7, ... */
 | 
			
		||||
+static int library_version;                /* VDDK major: 5, 6, 7, 8, ... */
 | 
			
		||||
 
 | 
			
		||||
 static enum { NONE = 0, ZLIB, FASTLZ, SKIPZ } compression; /* compression */
 | 
			
		||||
 static char *config;                       /* config */
 | 
			
		||||
@@ -309,6 +309,8 @@ load_library (bool load_error_is_fatal)
 | 
			
		||||
      * but our testsuite is easier to write if we point libdir
 | 
			
		||||
      * directly to a stub .so.
 | 
			
		||||
      */
 | 
			
		||||
+    { "lib64/libvixDiskLib.so.8", 8 },
 | 
			
		||||
+    { "libvixDiskLib.so.8",       8 },
 | 
			
		||||
     { "lib64/libvixDiskLib.so.7", 7 },
 | 
			
		||||
     { "libvixDiskLib.so.7",       7 },
 | 
			
		||||
     { "lib64/libvixDiskLib.so.6", 6 },
 | 
			
		||||
-- 
 | 
			
		||||
2.31.1
 | 
			
		||||
 | 
			
		||||
@ -1,59 +0,0 @@
 | 
			
		||||
From 927cb4063da464aa2605ae87d1b1157146551a47 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Mon, 6 Jan 2025 16:47:55 +0000
 | 
			
		||||
Subject: [PATCH] vddk: Cache the disk size in the handle
 | 
			
		||||
 | 
			
		||||
No functional change here, we're just making sure we have the disk
 | 
			
		||||
size (in bytes) available in the handle.
 | 
			
		||||
 | 
			
		||||
Acked-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
(cherry picked from commit 2ba76db4a048471e997e508715081a70356f94f3)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/vddk.c | 6 +++---
 | 
			
		||||
 plugins/vddk/vddk.h | 3 +++
 | 
			
		||||
 2 files changed, 6 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
 | 
			
		||||
index 27d53bd6..2a787453 100644
 | 
			
		||||
--- a/plugins/vddk/vddk.c
 | 
			
		||||
+++ b/plugins/vddk/vddk.c
 | 
			
		||||
@@ -875,19 +875,19 @@ vddk_get_size (void *handle)
 | 
			
		||||
 {
 | 
			
		||||
   struct vddk_handle *h = handle;
 | 
			
		||||
   VixDiskLibInfo *info;
 | 
			
		||||
-  int64_t size;
 | 
			
		||||
   struct command info_cmd = { .type = INFO, .ptr = &info };
 | 
			
		||||
 
 | 
			
		||||
   if (send_command_and_wait (h, &info_cmd) == -1)
 | 
			
		||||
     return -1;
 | 
			
		||||
 
 | 
			
		||||
-  size = info->capacity * (int64_t)VIXDISKLIB_SECTOR_SIZE;
 | 
			
		||||
+  /* Compute the size and cache it into the handle. */
 | 
			
		||||
+  h->size = info->capacity * VIXDISKLIB_SECTOR_SIZE;
 | 
			
		||||
 
 | 
			
		||||
   VDDK_CALL_START (VixDiskLib_FreeInfo, "info")
 | 
			
		||||
     VixDiskLib_FreeInfo (info);
 | 
			
		||||
   VDDK_CALL_END (VixDiskLib_FreeInfo, 0);
 | 
			
		||||
 
 | 
			
		||||
-  return size;
 | 
			
		||||
+  return h->size;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Advertise most efficient block sizes. */
 | 
			
		||||
diff --git a/plugins/vddk/vddk.h b/plugins/vddk/vddk.h
 | 
			
		||||
index fb0c79a8..1d1069cc 100644
 | 
			
		||||
--- a/plugins/vddk/vddk.h
 | 
			
		||||
+++ b/plugins/vddk/vddk.h
 | 
			
		||||
@@ -165,6 +165,9 @@ struct vddk_handle {
 | 
			
		||||
   command_queue commands;          /* command queue */
 | 
			
		||||
   pthread_cond_t commands_cond;    /* condition (queue size 0 -> 1) */
 | 
			
		||||
   uint64_t id;                     /* next command ID */
 | 
			
		||||
+
 | 
			
		||||
+  /* Cached disk size in bytes (set in get_size()). */
 | 
			
		||||
+  uint64_t size;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /* reexec.c */
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
From 0ba2e0d3c53efd49309d9e274e0cb6c2e6720cbd Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Mon, 6 Jan 2025 15:37:54 +0000
 | 
			
		||||
Subject: [PATCH] vddk: do_extents: Mark some local variables const
 | 
			
		||||
 | 
			
		||||
These are never changed in the code (they are fields copied out from
 | 
			
		||||
the *cmd struct), so mark them as const.
 | 
			
		||||
 | 
			
		||||
Acked-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
(cherry picked from commit 24fd7df460ae31fe3f72b5100ca3dbe138bbadbe)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/worker.c | 6 +++---
 | 
			
		||||
 1 file changed, 3 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/worker.c b/plugins/vddk/worker.c
 | 
			
		||||
index 5982fcea..bc015d16 100644
 | 
			
		||||
--- a/plugins/vddk/worker.c
 | 
			
		||||
+++ b/plugins/vddk/worker.c
 | 
			
		||||
@@ -388,9 +388,9 @@ add_extent (struct nbdkit_extents *extents,
 | 
			
		||||
 static int
 | 
			
		||||
 do_extents (struct command *cmd, struct vddk_handle *h)
 | 
			
		||||
 {
 | 
			
		||||
-  uint32_t count = cmd->count;
 | 
			
		||||
-  uint64_t offset = cmd->offset;
 | 
			
		||||
-  bool req_one = cmd->req_one;
 | 
			
		||||
+  const uint32_t count = cmd->count;
 | 
			
		||||
+  const uint64_t offset = cmd->offset;
 | 
			
		||||
+  const bool req_one = cmd->req_one;
 | 
			
		||||
   struct nbdkit_extents *extents = cmd->ptr;
 | 
			
		||||
   uint64_t position, end, start_sector;
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,31 +0,0 @@
 | 
			
		||||
From 6dd8b5eb14c0723764dd39597d64f62162ca3ab3 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Mon, 6 Jan 2025 16:39:51 +0000
 | 
			
		||||
Subject: [PATCH] vddk: do_extents: Exit the function if we hit req_one
 | 
			
		||||
 condition
 | 
			
		||||
 | 
			
		||||
No change to the functionality, since the code previously called
 | 
			
		||||
'return 0' immediately following the loop.
 | 
			
		||||
 | 
			
		||||
Acked-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
(cherry picked from commit 2f4d71f8f704d89d69cd635791c3239d2f44d631)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/worker.c | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/worker.c b/plugins/vddk/worker.c
 | 
			
		||||
index bc015d16..112111e3 100644
 | 
			
		||||
--- a/plugins/vddk/worker.c
 | 
			
		||||
+++ b/plugins/vddk/worker.c
 | 
			
		||||
@@ -471,7 +471,7 @@ do_extents (struct command *cmd, struct vddk_handle *h)
 | 
			
		||||
      * overlapping the original offset we're done.
 | 
			
		||||
      */
 | 
			
		||||
     if (req_one && position > offset)
 | 
			
		||||
-      break;
 | 
			
		||||
+      return 0;
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   return 0;
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,202 +0,0 @@
 | 
			
		||||
From fdc2a6a9818aad25ee606118d5f6a32fa0739912 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Mon, 6 Jan 2025 15:45:35 +0000
 | 
			
		||||
Subject: [PATCH] vddk: do_extents: Avoid reading partial chunk beyond the end
 | 
			
		||||
 of the disk
 | 
			
		||||
 | 
			
		||||
The QueryAllocatedBlocks API has (another) frustrating feature.  It
 | 
			
		||||
can only query whole "chunks" (128 sectors).  If the disk size is not
 | 
			
		||||
aligned to the chunk size (say the size was 129 sectors) then there's
 | 
			
		||||
a bit at the end which cannot be queried.  Furthermore, the API gives
 | 
			
		||||
an error in this case instead of being helpful:
 | 
			
		||||
 | 
			
		||||
  VixDiskLib_QueryAllocatedBlocks: One of the parameters was invalid
 | 
			
		||||
 | 
			
		||||
Fixes: https://issues.redhat.com/browse/RHEL-71694
 | 
			
		||||
Reported-by: Ming Xie <mxie@redhat.com>
 | 
			
		||||
Acked-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
(cherry picked from commit fd918f3d1a185fd996999766c75acb9d6e22395d)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/worker.c                   | 29 ++++++++-
 | 
			
		||||
 tests/Makefile.am                       |  5 +-
 | 
			
		||||
 tests/test-vddk-real-unaligned-chunk.sh | 82 +++++++++++++++++++++++++
 | 
			
		||||
 3 files changed, 113 insertions(+), 3 deletions(-)
 | 
			
		||||
 create mode 100755 tests/test-vddk-real-unaligned-chunk.sh
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/worker.c b/plugins/vddk/worker.c
 | 
			
		||||
index 112111e3..8a91250a 100644
 | 
			
		||||
--- a/plugins/vddk/worker.c
 | 
			
		||||
+++ b/plugins/vddk/worker.c
 | 
			
		||||
@@ -392,10 +392,9 @@ do_extents (struct command *cmd, struct vddk_handle *h)
 | 
			
		||||
   const uint64_t offset = cmd->offset;
 | 
			
		||||
   const bool req_one = cmd->req_one;
 | 
			
		||||
   struct nbdkit_extents *extents = cmd->ptr;
 | 
			
		||||
-  uint64_t position, end, start_sector;
 | 
			
		||||
+  uint64_t position, start_sector, size_sectors, last_queryable_sector, end;
 | 
			
		||||
 
 | 
			
		||||
   position = offset;
 | 
			
		||||
-  end = offset + count;
 | 
			
		||||
 
 | 
			
		||||
   /* We can only query whole chunks.  Therefore start with the
 | 
			
		||||
    * first chunk before offset.
 | 
			
		||||
@@ -403,6 +402,21 @@ do_extents (struct command *cmd, struct vddk_handle *h)
 | 
			
		||||
   start_sector =
 | 
			
		||||
     ROUND_DOWN (offset, VIXDISKLIB_MIN_CHUNK_SIZE * VIXDISKLIB_SECTOR_SIZE)
 | 
			
		||||
     / VIXDISKLIB_SECTOR_SIZE;
 | 
			
		||||
+
 | 
			
		||||
+  /* Calculate the end byte + 1 that we're going to query, normally
 | 
			
		||||
+   * this is offset + count.
 | 
			
		||||
+   *
 | 
			
		||||
+   * However since chunks are larger than sectors, for a disk which
 | 
			
		||||
+   * has size which is not aligned to the chunk size there is a part
 | 
			
		||||
+   * of the disk at the end that we can never query.  Reduce 'end' to
 | 
			
		||||
+   * the maximum possible queryable part of the disk, and we'll deal
 | 
			
		||||
+   * with the unaligned bit after the loop (RHEL-71694).
 | 
			
		||||
+   */
 | 
			
		||||
+  end = offset + count;
 | 
			
		||||
+  size_sectors = h->size / VIXDISKLIB_SECTOR_SIZE;
 | 
			
		||||
+  last_queryable_sector = ROUND_DOWN (size_sectors, VIXDISKLIB_MIN_CHUNK_SIZE);
 | 
			
		||||
+  end = MIN (end, last_queryable_sector * VIXDISKLIB_SECTOR_SIZE);
 | 
			
		||||
+
 | 
			
		||||
   while (start_sector * VIXDISKLIB_SECTOR_SIZE < end) {
 | 
			
		||||
     VixError err;
 | 
			
		||||
     uint32_t i;
 | 
			
		||||
@@ -474,6 +488,17 @@ do_extents (struct command *cmd, struct vddk_handle *h)
 | 
			
		||||
       return 0;
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
+  /* If 'end' spanned beyond the last chunk of the disk, then we
 | 
			
		||||
+   * reduced it above to avoid reading a chunk that extends beyond the
 | 
			
		||||
+   * end of the underlying disk.  We have to synthesize an allocated
 | 
			
		||||
+   * block here, which is what VDDK's example code does
 | 
			
		||||
+   * (doc/samples/diskLib/vixDiskLibSample.cpp: DoGetAllocatedBlocks).
 | 
			
		||||
+   */
 | 
			
		||||
+  if (end < offset + count) {
 | 
			
		||||
+    if (add_extent (extents, &position, offset + count, false) == -1)
 | 
			
		||||
+      return -1;
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
   return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/tests/Makefile.am b/tests/Makefile.am
 | 
			
		||||
index d510807c..0aa36846 100644
 | 
			
		||||
--- a/tests/Makefile.am
 | 
			
		||||
+++ b/tests/Makefile.am
 | 
			
		||||
@@ -178,7 +178,8 @@ if HAVE_VDDK
 | 
			
		||||
 check-vddk:
 | 
			
		||||
 	$(MAKE) check TESTS="test-vddk-real.sh \
 | 
			
		||||
 	                     test-vddk-real-dump-plugin.sh \
 | 
			
		||||
-	                     test-vddk-real-create.sh"
 | 
			
		||||
+	                     test-vddk-real-create.sh \
 | 
			
		||||
+	                     test-vddk-real-unaligned-chunk.sh"
 | 
			
		||||
 endif HAVE_VDDK
 | 
			
		||||
 
 | 
			
		||||
 #----------------------------------------------------------------------
 | 
			
		||||
@@ -1145,6 +1146,7 @@ TESTS += \
 | 
			
		||||
 	test-vddk-password-interactive.sh \
 | 
			
		||||
 	test-vddk-real-create.sh \
 | 
			
		||||
 	test-vddk-real-dump-plugin.sh \
 | 
			
		||||
+	test-vddk-real-unaligned-chunk.sh \
 | 
			
		||||
 	test-vddk-real.sh \
 | 
			
		||||
 	test-vddk-reexec.sh \
 | 
			
		||||
 	test-vddk-run.sh \
 | 
			
		||||
@@ -1177,6 +1179,7 @@ EXTRA_DIST += \
 | 
			
		||||
 	test-vddk-password-interactive.sh \
 | 
			
		||||
 	test-vddk-real-create.sh \
 | 
			
		||||
 	test-vddk-real-dump-plugin.sh \
 | 
			
		||||
+	test-vddk-real-unaligned-chunk.sh \
 | 
			
		||||
 	test-vddk-real.sh \
 | 
			
		||||
 	test-vddk-reexec.sh \
 | 
			
		||||
 	test-vddk-run.sh \
 | 
			
		||||
diff --git a/tests/test-vddk-real-unaligned-chunk.sh b/tests/test-vddk-real-unaligned-chunk.sh
 | 
			
		||||
new file mode 100755
 | 
			
		||||
index 00000000..28fccd6c
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/tests/test-vddk-real-unaligned-chunk.sh
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
+#!/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.
 | 
			
		||||
+
 | 
			
		||||
+# Regression test for https://issues.redhat.com/browse/RHEL-71694
 | 
			
		||||
+
 | 
			
		||||
+source ./functions.sh
 | 
			
		||||
+set -e
 | 
			
		||||
+set -x
 | 
			
		||||
+
 | 
			
		||||
+requires_run
 | 
			
		||||
+requires test "x$vddkdir" != "x"
 | 
			
		||||
+requires test -d "$vddkdir"
 | 
			
		||||
+requires test -f "$vddkdir/lib64/libvixDiskLib.so"
 | 
			
		||||
+requires qemu-img --version
 | 
			
		||||
+requires_nbdinfo
 | 
			
		||||
+requires $TRUNCATE --version
 | 
			
		||||
+requires dd --version
 | 
			
		||||
+requires test -r /dev/urandom
 | 
			
		||||
+skip_if_valgrind "because setting LD_LIBRARY_PATH breaks valgrind"
 | 
			
		||||
+
 | 
			
		||||
+# VDDK > 5.1.1 only supports x86_64.
 | 
			
		||||
+if [ `uname -m` != "x86_64" ]; then
 | 
			
		||||
+    echo "$0: unsupported architecture"
 | 
			
		||||
+    exit 77
 | 
			
		||||
+fi
 | 
			
		||||
+
 | 
			
		||||
+d=vddk-real-unaligned-chunk.d
 | 
			
		||||
+cleanup_fn rm -rf $d
 | 
			
		||||
+rm -rf $d
 | 
			
		||||
+mkdir $d
 | 
			
		||||
+
 | 
			
		||||
+# Create a vmdk disk which is partially sparse and the size is NOT
 | 
			
		||||
+# aligned to 128 sectors (chunk size).
 | 
			
		||||
+dd if=/dev/urandom of=$d/test.raw bs=512 count=$(( 3*128 ))
 | 
			
		||||
+$TRUNCATE -s $(( (4*128 + 3) * 512)) $d/test.raw
 | 
			
		||||
+qemu-img convert -f raw $d/test.raw -O vmdk $d/test.vmdk
 | 
			
		||||
+
 | 
			
		||||
+# Read the map using VDDK.
 | 
			
		||||
+export d
 | 
			
		||||
+nbdkit -rfv vddk libdir="$vddkdir" \
 | 
			
		||||
+       $PWD/$d/test.vmdk \
 | 
			
		||||
+       --run 'nbdinfo --map "$uri" > $d/map'
 | 
			
		||||
+cat $d/map
 | 
			
		||||
+
 | 
			
		||||
+# Note a few features of the expected map.  The first 3 chunks (3*128
 | 
			
		||||
+# sectors) are allocated, followed by a single hole chunk.  Then the
 | 
			
		||||
+# last 3 unaligned sectors appear allocated (even though they are not)
 | 
			
		||||
+# because we could not read them using the QueryAllocatedBlocks API so
 | 
			
		||||
+# we had to assume allocated.
 | 
			
		||||
+test "$(cat $d/map)" = "\
 | 
			
		||||
+         0      196608    0  data
 | 
			
		||||
+    196608       65536    3  hole,zero
 | 
			
		||||
+    262144        1536    0  data"
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
From 700c3c26a1d20a9e658f7c4eadf1122bc58807df Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:03:06 +0100
 | 
			
		||||
Subject: [PATCH] file: Fix minor typo in debug message
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit a75db5636b94c9184f8eb02fd51182d935df64a6)
 | 
			
		||||
(cherry picked from commit a79bf57c8ec805516e8dbe7995aa2bd46b83ade3)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index 2bad6480..7ed4e71b 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -901,7 +901,7 @@ file_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
 | 
			
		||||
     r = do_fallocate (h->fd, FALLOC_FL_ZERO_RANGE, offset, count);
 | 
			
		||||
     if (r == 0) {
 | 
			
		||||
       if (file_debug_zero)
 | 
			
		||||
-        nbdkit_debug ("h->can_zero-range: "
 | 
			
		||||
+        nbdkit_debug ("h->can_zero_range: "
 | 
			
		||||
                       "zero succeeded using fallocate");
 | 
			
		||||
       goto out;
 | 
			
		||||
     }
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,37 +0,0 @@
 | 
			
		||||
From eebfe03293d7fd08e167bdbb2ab8b8e448393bdf Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:21:23 +0100
 | 
			
		||||
Subject: [PATCH] file: Add more debugging when -D file.zero=1 is used
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit ecf6b15fa84a02b74ea969f06552c82ee418b9b4)
 | 
			
		||||
(cherry picked from commit 1cb341e75c1a17553b69ea8d9889662e6d09ae78)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c | 12 +++++++++++-
 | 
			
		||||
 1 file changed, 11 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index 7ed4e71b..3668fa4b 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -856,7 +856,17 @@ file_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
 | 
			
		||||
 static int
 | 
			
		||||
 do_fallocate (int fd, int mode_, off_t offset, off_t len)
 | 
			
		||||
 {
 | 
			
		||||
-  int r = fallocate (fd, mode_, offset, len);
 | 
			
		||||
+  int r;
 | 
			
		||||
+
 | 
			
		||||
+  r = fallocate (fd, mode_, offset, len);
 | 
			
		||||
+
 | 
			
		||||
+  if (file_debug_zero)
 | 
			
		||||
+    nbdkit_debug ("fallocate ([%s%s ], %" PRIu64 ", %" PRIu64") => %d (%d)",
 | 
			
		||||
+                  mode_ & FALLOC_FL_PUNCH_HOLE ? " FALLOC_FL_PUNCH_HOLE" : "",
 | 
			
		||||
+                  mode_ & FALLOC_FL_ZERO_RANGE ? " FALLOC_FL_ZERO_RANGE" : "",
 | 
			
		||||
+                  (uint64_t) offset, (uint64_t) len, r,
 | 
			
		||||
+                  r == -1 ? errno : 0);
 | 
			
		||||
+
 | 
			
		||||
   if (r == -1 && errno == ENODEV) {
 | 
			
		||||
     /* kernel 3.10 fails with ENODEV for block device. Kernel >= 4.9 fails
 | 
			
		||||
        with EOPNOTSUPP in this case. Normalize errno to simplify callers. */
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
From fc302722b01afbf498746c7baf065d8103ce6ac7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:32:17 +0100
 | 
			
		||||
Subject: [PATCH] file: Fix comment style in a few places
 | 
			
		||||
 | 
			
		||||
No actual change here.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 0df4142c4be2b059c4d17aae0ec71f16ffc9ba35)
 | 
			
		||||
(cherry picked from commit 664e447d858a21304610db3023cc728db0c974bd)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c | 10 ++++++----
 | 
			
		||||
 1 file changed, 6 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index 3668fa4b..8b63184f 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -869,7 +869,8 @@ do_fallocate (int fd, int mode_, off_t offset, off_t len)
 | 
			
		||||
 
 | 
			
		||||
   if (r == -1 && errno == ENODEV) {
 | 
			
		||||
     /* kernel 3.10 fails with ENODEV for block device. Kernel >= 4.9 fails
 | 
			
		||||
-       with EOPNOTSUPP in this case. Normalize errno to simplify callers. */
 | 
			
		||||
+     * with EOPNOTSUPP in this case. Normalize errno to simplify callers.
 | 
			
		||||
+     */
 | 
			
		||||
     errno = EOPNOTSUPP;
 | 
			
		||||
   }
 | 
			
		||||
   return r;
 | 
			
		||||
@@ -926,9 +927,10 @@ file_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 #ifdef FALLOC_FL_PUNCH_HOLE
 | 
			
		||||
-  /* If we can punch hole but may not trim, we can combine punching hole and
 | 
			
		||||
-   * fallocate to zero a range. This is expected to be more efficient than
 | 
			
		||||
-   * writing zeroes manually. */
 | 
			
		||||
+  /* If we can punch hole but may not trim, we can combine punching
 | 
			
		||||
+   * hole and fallocate to zero a range. This is expected to be more
 | 
			
		||||
+   * efficient than writing zeroes manually.
 | 
			
		||||
+   */
 | 
			
		||||
   if (h->can_punch_hole && h->can_fallocate) {
 | 
			
		||||
     int r;
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,61 +0,0 @@
 | 
			
		||||
From 5dfd68ac3fde66113c0044c07679138dd72325b4 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:59:17 +0100
 | 
			
		||||
Subject: [PATCH] file: Fix do_fallocate debugging on Alpine
 | 
			
		||||
 | 
			
		||||
Alpine has some weird/old kernel that doesn't support
 | 
			
		||||
FALLOC_FL_ZERO_RANGE but does support FALLOC_FL_PUNCH_HOLE, so the
 | 
			
		||||
debugging I added in commit ecf6b15fa8 failed to compile with:
 | 
			
		||||
 | 
			
		||||
  file.c: In function 'do_fallocate':
 | 
			
		||||
  file.c:958:27: error: 'FALLOC_FL_ZERO_RANGE' undeclared (first use in this function)
 | 
			
		||||
    958 |                   mode_ & FALLOC_FL_ZERO_RANGE ? " FALLOC_FL_ZERO_RANGE" : "",
 | 
			
		||||
        |                           ^~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
  file.c:958:27: note: each undeclared identifier is reported only once for each function it appears in
 | 
			
		||||
  make[3]: *** [Makefile:666: nbdkit_file_plugin_la-file.lo] Error 1
 | 
			
		||||
 | 
			
		||||
Fixes: commit ecf6b15fa84a02b74ea969f06552c82ee418b9b4
 | 
			
		||||
(cherry picked from commit 419a347054f81c53706637feddbc5008beab77d3)
 | 
			
		||||
(cherry picked from commit 4c02ff62f40497335da185cc4b45c2ba43fb609b)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c | 15 +++++++++++++--
 | 
			
		||||
 1 file changed, 13 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index 8b63184f..d94d5b78 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -852,7 +852,7 @@ file_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
 | 
			
		||||
   return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-#if defined (FALLOC_FL_PUNCH_HOLE) || defined (FALLOC_FL_ZERO_RANGE)
 | 
			
		||||
+#if defined(FALLOC_FL_PUNCH_HOLE) || defined(FALLOC_FL_ZERO_RANGE)
 | 
			
		||||
 static int
 | 
			
		||||
 do_fallocate (int fd, int mode_, off_t offset, off_t len)
 | 
			
		||||
 {
 | 
			
		||||
@@ -861,9 +861,20 @@ do_fallocate (int fd, int mode_, off_t offset, off_t len)
 | 
			
		||||
   r = fallocate (fd, mode_, offset, len);
 | 
			
		||||
 
 | 
			
		||||
   if (file_debug_zero)
 | 
			
		||||
-    nbdkit_debug ("fallocate ([%s%s ], %" PRIu64 ", %" PRIu64") => %d (%d)",
 | 
			
		||||
+    nbdkit_debug ("fallocate (["
 | 
			
		||||
+#if defined(FALLOC_FL_PUNCH_HOLE)
 | 
			
		||||
+                  "%s"
 | 
			
		||||
+#endif
 | 
			
		||||
+#if defined(FALLOC_FL_ZERO_RANGE)
 | 
			
		||||
+                  "%s"
 | 
			
		||||
+#endif
 | 
			
		||||
+                  " ], %" PRIu64 ", %" PRIu64") => %d (%d)",
 | 
			
		||||
+#if defined(FALLOC_FL_PUNCH_HOLE)
 | 
			
		||||
                   mode_ & FALLOC_FL_PUNCH_HOLE ? " FALLOC_FL_PUNCH_HOLE" : "",
 | 
			
		||||
+#endif
 | 
			
		||||
+#if defined(FALLOC_FL_ZERO_RANGE)
 | 
			
		||||
                   mode_ & FALLOC_FL_ZERO_RANGE ? " FALLOC_FL_ZERO_RANGE" : "",
 | 
			
		||||
+#endif
 | 
			
		||||
                   (uint64_t) offset, (uint64_t) len, r,
 | 
			
		||||
                   r == -1 ? errno : 0);
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,66 +0,0 @@
 | 
			
		||||
From a41be72f9d2fe9a8ba6ee4f0549dd0c149bd2c96 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:26:41 +0100
 | 
			
		||||
Subject: [PATCH] file: Rename h->can_zeroout to h->can_blkzeroout to reflect
 | 
			
		||||
 ioctl
 | 
			
		||||
 | 
			
		||||
Since we're calling the blockdev-specific BLKZEROOUT ioctl when this
 | 
			
		||||
flag is set, rename the flag.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit fba20ce06c2f0e7c4be7e52e8e1934933851dfbc)
 | 
			
		||||
(cherry picked from commit bc4598f3d2d1ef2f4ebdf5b365ed08eff14d5654)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c | 10 +++++-----
 | 
			
		||||
 1 file changed, 5 insertions(+), 5 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index d94d5b78..55941bb8 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -476,7 +476,7 @@ struct handle {
 | 
			
		||||
   bool can_punch_hole;
 | 
			
		||||
   bool can_zero_range;
 | 
			
		||||
   bool can_fallocate;
 | 
			
		||||
-  bool can_zeroout;
 | 
			
		||||
+  bool can_blkzeroout;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /* Common code for opening a file by name, used by mode_filename and
 | 
			
		||||
@@ -682,7 +682,7 @@ file_open (int readonly)
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
   h->can_fallocate = true;
 | 
			
		||||
-  h->can_zeroout = h->is_block_device;
 | 
			
		||||
+  h->can_blkzeroout = h->is_block_device;
 | 
			
		||||
 
 | 
			
		||||
   return h;
 | 
			
		||||
 }
 | 
			
		||||
@@ -975,14 +975,14 @@ file_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
 | 
			
		||||
 
 | 
			
		||||
 #ifdef BLKZEROOUT
 | 
			
		||||
   /* For aligned range and block device, we can use BLKZEROOUT. */
 | 
			
		||||
-  if (h->can_zeroout && IS_ALIGNED (offset | count, h->sector_size)) {
 | 
			
		||||
+  if (h->can_blkzeroout && IS_ALIGNED (offset | count, h->sector_size)) {
 | 
			
		||||
     int r;
 | 
			
		||||
     uint64_t range[2] = {offset, count};
 | 
			
		||||
 
 | 
			
		||||
     r = ioctl (h->fd, BLKZEROOUT, &range);
 | 
			
		||||
     if (r == 0) {
 | 
			
		||||
       if (file_debug_zero)
 | 
			
		||||
-        nbdkit_debug ("h->can_zeroout && IS_ALIGNED: "
 | 
			
		||||
+        nbdkit_debug ("h->can_blkzeroout && IS_ALIGNED: "
 | 
			
		||||
                       "zero succeeded using BLKZEROOUT");
 | 
			
		||||
       goto out;
 | 
			
		||||
     }
 | 
			
		||||
@@ -992,7 +992,7 @@ file_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
 | 
			
		||||
       return -1;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    h->can_zeroout = false;
 | 
			
		||||
+    h->can_blkzeroout = false;
 | 
			
		||||
   }
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,39 +0,0 @@
 | 
			
		||||
From 8322b16cd13979f7c872d5ce50517688fc7220bd Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:30:41 +0100
 | 
			
		||||
Subject: [PATCH] file: zero: Document implicit order that we will try zeroing
 | 
			
		||||
 methods
 | 
			
		||||
 | 
			
		||||
There's no substantive change here.  I just pulled out the test (flags
 | 
			
		||||
& NBDKIT_FLAG_MAY_TRIM) into a boolean variable, and documented that
 | 
			
		||||
we (will) try zero-with-trim methods first.
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 61fc023f235b17f8a19302885d1613dd0a7a3793)
 | 
			
		||||
(cherry picked from commit c1984ddcc6497c4446d1bf0e8828d1259852eb74)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c | 7 ++++++-
 | 
			
		||||
 1 file changed, 6 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index 55941bb8..e5fd864f 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -893,9 +893,14 @@ static int
 | 
			
		||||
 file_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
 | 
			
		||||
 {
 | 
			
		||||
   struct handle *h __attribute__ ((unused)) = handle;
 | 
			
		||||
+  const bool may_trim __attribute__ ((unused)) = flags & NBDKIT_FLAG_MAY_TRIM;
 | 
			
		||||
 
 | 
			
		||||
+  /* These alternate zeroing methods are ordered.  Methods which can
 | 
			
		||||
+   * trim (if may_trim is set) are tried first.  Methods which can
 | 
			
		||||
+   * only zero are tried last.
 | 
			
		||||
+   */
 | 
			
		||||
 #ifdef FALLOC_FL_PUNCH_HOLE
 | 
			
		||||
-  if (h->can_punch_hole && (flags & NBDKIT_FLAG_MAY_TRIM)) {
 | 
			
		||||
+  if (may_trim && h->can_punch_hole) {
 | 
			
		||||
     int r;
 | 
			
		||||
 
 | 
			
		||||
     r = do_fallocate (h->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,123 +0,0 @@
 | 
			
		||||
From 26598004453d1d35c70229ade48a085a74b3dada Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Thu, 1 May 2025 10:36:23 +0100
 | 
			
		||||
Subject: [PATCH] file: zero: Use BLKDISCARD method if may_trim is set
 | 
			
		||||
 | 
			
		||||
If we're allowed to trim and we're writing to a block device,
 | 
			
		||||
previously we hit the case fallocate(FALLOC_FL_ZERO_RANGE) first.
 | 
			
		||||
This succeeds in Linux, zeroing (not trimming) the range.
 | 
			
		||||
 | 
			
		||||
However it would be better to trim in this case.  Linux supports
 | 
			
		||||
ioctl(BLKDISCARD) on block devices, so try this method first.
 | 
			
		||||
 | 
			
		||||
Fixes: https://issues.redhat.com/browse/RHEL-89353
 | 
			
		||||
Reported-by: Germano Veit Michel
 | 
			
		||||
Thanks: Eric Blake
 | 
			
		||||
(cherry picked from commit 7a9ecda24906c64d9f8c7238a96cb3f686e894eb)
 | 
			
		||||
(cherry picked from commit 396e8a97835155a620cabbcf1aabaaa1fa4a08f1)
 | 
			
		||||
---
 | 
			
		||||
 plugins/file/file.c                 | 50 +++++++++++++++++++++++++++++
 | 
			
		||||
 plugins/file/nbdkit-file-plugin.pod |  5 +++
 | 
			
		||||
 2 files changed, 55 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/file/file.c b/plugins/file/file.c
 | 
			
		||||
index e5fd864f..41b23457 100644
 | 
			
		||||
--- a/plugins/file/file.c
 | 
			
		||||
+++ b/plugins/file/file.c
 | 
			
		||||
@@ -376,6 +376,9 @@ file_dump_plugin (void)
 | 
			
		||||
 #ifdef BLKSSZGET
 | 
			
		||||
   printf ("file_blksszget=yes\n");
 | 
			
		||||
 #endif
 | 
			
		||||
+#ifdef BLKDISCARD
 | 
			
		||||
+  printf ("file_blkdiscard=yes\n");
 | 
			
		||||
+#endif
 | 
			
		||||
 #ifdef BLKZEROOUT
 | 
			
		||||
   printf ("file_blkzeroout=yes\n");
 | 
			
		||||
 #endif
 | 
			
		||||
@@ -476,6 +479,7 @@ struct handle {
 | 
			
		||||
   bool can_punch_hole;
 | 
			
		||||
   bool can_zero_range;
 | 
			
		||||
   bool can_fallocate;
 | 
			
		||||
+  bool can_blkdiscard;
 | 
			
		||||
   bool can_blkzeroout;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
@@ -683,6 +687,7 @@ file_open (int readonly)
 | 
			
		||||
 
 | 
			
		||||
   h->can_fallocate = true;
 | 
			
		||||
   h->can_blkzeroout = h->is_block_device;
 | 
			
		||||
+  h->can_blkdiscard = h->is_block_device;
 | 
			
		||||
 
 | 
			
		||||
   return h;
 | 
			
		||||
 }
 | 
			
		||||
@@ -921,6 +926,51 @@ file_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
 | 
			
		||||
   }
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#if defined(BLKDISCARD) && defined(FALLOC_FL_ZERO_RANGE)
 | 
			
		||||
+  /* For aligned range and block device, we can use BLKDISCARD to
 | 
			
		||||
+   * trim.  However BLKDISCARD doesn't necessarily zero (eg for local
 | 
			
		||||
+   * disk) so we have to zero first and then discard.
 | 
			
		||||
+   *
 | 
			
		||||
+   * In future all Linux block devices may understand
 | 
			
		||||
+   * FALLOC_FL_PUNCH_HOLE which means this case would no longer be
 | 
			
		||||
+   * necessary, since the case above will handle it.
 | 
			
		||||
+   */
 | 
			
		||||
+  if (may_trim && h->can_blkdiscard && h->can_zero_range &&
 | 
			
		||||
+      IS_ALIGNED (offset | count, h->sector_size)) {
 | 
			
		||||
+    int r;
 | 
			
		||||
+    uint64_t range[2] = {offset, count};
 | 
			
		||||
+
 | 
			
		||||
+    r = do_fallocate (h->fd, FALLOC_FL_ZERO_RANGE, offset, count);
 | 
			
		||||
+    if (r == 0) {
 | 
			
		||||
+      /* We could use FALLOC_FL_PUNCH_HOLE here instead, but currently
 | 
			
		||||
+       * thin LVs do not support it (XXX 2025-04).
 | 
			
		||||
+       */
 | 
			
		||||
+      r = ioctl (h->fd, BLKDISCARD, &range);
 | 
			
		||||
+      if (r == 0) {
 | 
			
		||||
+        if (file_debug_zero)
 | 
			
		||||
+          nbdkit_debug ("h->can_blkdiscard && may_trim && IS_ALIGNED: "
 | 
			
		||||
+                        "zero succeeded using BLKDISCARD");
 | 
			
		||||
+        goto out;
 | 
			
		||||
+      }
 | 
			
		||||
+
 | 
			
		||||
+      if (!is_enotsup (errno)) {
 | 
			
		||||
+        nbdkit_error ("zero: %m");
 | 
			
		||||
+        return -1;
 | 
			
		||||
+      }
 | 
			
		||||
+
 | 
			
		||||
+      h->can_blkdiscard = false;
 | 
			
		||||
+    }
 | 
			
		||||
+    else {
 | 
			
		||||
+      if (!is_enotsup (errno)) {
 | 
			
		||||
+        nbdkit_error ("zero: %m");
 | 
			
		||||
+        return -1;
 | 
			
		||||
+      }
 | 
			
		||||
+
 | 
			
		||||
+      h->can_fallocate = false;
 | 
			
		||||
+    }
 | 
			
		||||
+  }
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
 #ifdef FALLOC_FL_ZERO_RANGE
 | 
			
		||||
   if (h->can_zero_range) {
 | 
			
		||||
     int r;
 | 
			
		||||
diff --git a/plugins/file/nbdkit-file-plugin.pod b/plugins/file/nbdkit-file-plugin.pod
 | 
			
		||||
index a50bef2d..0e260b7f 100644
 | 
			
		||||
--- a/plugins/file/nbdkit-file-plugin.pod
 | 
			
		||||
+++ b/plugins/file/nbdkit-file-plugin.pod
 | 
			
		||||
@@ -227,6 +227,11 @@ future.
 | 
			
		||||
 If both set, the plugin may be able to efficiently zero ranges of
 | 
			
		||||
 block devices, where the driver and block device itself supports this.
 | 
			
		||||
 
 | 
			
		||||
+=item C<file_blkdiscard=yes>
 | 
			
		||||
+
 | 
			
		||||
+If set, the plugin may be able to efficiently trim ranges of block
 | 
			
		||||
+devices, where the driver and block device itself supports this.
 | 
			
		||||
+
 | 
			
		||||
 =item C<file_extents=yes>
 | 
			
		||||
 
 | 
			
		||||
 If set, the plugin can read file extents.
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,40 +0,0 @@
 | 
			
		||||
From 37c234f30706958a63d45aeea0ffa8ffa8ba10d9 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Wed, 2 Jul 2025 16:18:19 +0100
 | 
			
		||||
Subject: [PATCH] server: Fix .zero fallback path
 | 
			
		||||
 | 
			
		||||
When no efficient zero method is supported, we fall back to writing a
 | 
			
		||||
buffer of actual zeroes.  However because of an omitted update to
 | 
			
		||||
'offset' we would only zero out (up to) the first 64M of each range.
 | 
			
		||||
nbdcopy defaults to working on blocks of 128M, leaving the second 64M
 | 
			
		||||
unzeroed.
 | 
			
		||||
 | 
			
		||||
This affects only backing filesystems which do not support fallocate
 | 
			
		||||
FALLOC_FL_PUNCH_HOLE or FALLOC_FL_ZERO_RANGE, which turns out to be
 | 
			
		||||
rare, but it does include some NFS-mounted filesystems which is where
 | 
			
		||||
I saw this problem.
 | 
			
		||||
 | 
			
		||||
Fixes: commit 19184d3eb6356ae3b14da0fbaa9c9bdc7743a448
 | 
			
		||||
Thanks: Alex Kalenyuk
 | 
			
		||||
(cherry picked from commit 20b23fc9838faeddfd42664a7f497a9b29dc5921)
 | 
			
		||||
(cherry picked from commit 3c8d0812e7a7b6a1f9e5cceab7bee6e25b9cd7cd)
 | 
			
		||||
(cherry picked from commit e947a2a55cb018711b7f4ede5b5cec291ed5cf24)
 | 
			
		||||
---
 | 
			
		||||
 server/plugins.c | 1 +
 | 
			
		||||
 1 file changed, 1 insertion(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/server/plugins.c b/server/plugins.c
 | 
			
		||||
index 3c7df0d2..db36ce42 100644
 | 
			
		||||
--- a/server/plugins.c
 | 
			
		||||
+++ b/server/plugins.c
 | 
			
		||||
@@ -807,6 +807,7 @@ plugin_zero (struct context *c,
 | 
			
		||||
     if (r == -1)
 | 
			
		||||
       break;
 | 
			
		||||
     count -= limit;
 | 
			
		||||
+    offset += limit;
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
  done:
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
@ -1,50 +0,0 @@
 | 
			
		||||
From 4e36ca88232609a0b15c3533328c93c0d41beab0 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: "Richard W.M. Jones" <rjones@redhat.com>
 | 
			
		||||
Date: Mon, 23 Jun 2025 13:05:51 +0100
 | 
			
		||||
Subject: [PATCH] vddk: Add support for VDDK 9.0.0.0
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit c966fe7d05ed7e992e1bf725d4625434c74eaf8d)
 | 
			
		||||
(cherry picked from commit c33178791b9f66cb49082a496b5e65c6027f5ebd)
 | 
			
		||||
---
 | 
			
		||||
 plugins/vddk/nbdkit-vddk-plugin.pod | 2 +-
 | 
			
		||||
 plugins/vddk/vddk.c                 | 4 +++-
 | 
			
		||||
 2 files changed, 4 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/plugins/vddk/nbdkit-vddk-plugin.pod b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
index 19f25423..dc71431c 100644
 | 
			
		||||
--- a/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
+++ b/plugins/vddk/nbdkit-vddk-plugin.pod
 | 
			
		||||
@@ -407,7 +407,7 @@ This is the first version that supported the
 | 
			
		||||
 C<VixDiskLib_QueryAllocatedBlocks> API.  This is required to provide
 | 
			
		||||
 sparseness (extent) information over NBD.
 | 
			
		||||
 
 | 
			
		||||
-=item VDDK 8.0.2.1 (released Feb 2024)
 | 
			
		||||
+=item VDDK 9.0.0.0 (released Jun 2025)
 | 
			
		||||
 
 | 
			
		||||
 This is the latest version of VDDK that we have tested at the time of
 | 
			
		||||
 writing, but the plugin should work with future versions.
 | 
			
		||||
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
 | 
			
		||||
index 2a787453..367366c0 100644
 | 
			
		||||
--- a/plugins/vddk/vddk.c
 | 
			
		||||
+++ b/plugins/vddk/vddk.c
 | 
			
		||||
@@ -78,7 +78,7 @@ NBDKIT_DLL_PUBLIC int vddk_debug_datapath = 1;
 | 
			
		||||
 void *dl;                              /* dlopen handle */
 | 
			
		||||
 bool init_called;                      /* was InitEx called */
 | 
			
		||||
 __thread int error_suppression;        /* threadlocal error suppression */
 | 
			
		||||
-int library_version;                   /* VDDK major: 6, 7, 8, ... */
 | 
			
		||||
+int library_version;                   /* VDDK major: 6, 7, 8, 9 */
 | 
			
		||||
 bool is_remote;                        /* true if remote connection */
 | 
			
		||||
 
 | 
			
		||||
 enum compression_type compression;     /* compression */
 | 
			
		||||
@@ -407,6 +407,8 @@ load_library (bool load_error_is_fatal)
 | 
			
		||||
      * our testsuite is easier to write if we point libdir directly to
 | 
			
		||||
      * a stub .so.
 | 
			
		||||
      */
 | 
			
		||||
+    { "lib64/libvixDiskLib.so.9", 9 },
 | 
			
		||||
+    { "libvixDiskLib.so.9",       9 },
 | 
			
		||||
     { "lib64/libvixDiskLib.so.8", 8 },
 | 
			
		||||
     { "libvixDiskLib.so.8",       8 },
 | 
			
		||||
     { "lib64/libvixDiskLib.so.7", 7 },
 | 
			
		||||
-- 
 | 
			
		||||
2.47.1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								SOURCES/copy-patches.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								SOURCES/copy-patches.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -6,7 +6,7 @@ set -e
 | 
			
		||||
# directory.  Use it like this:
 | 
			
		||||
#   ./copy-patches.sh
 | 
			
		||||
 | 
			
		||||
rhel_version=9.6
 | 
			
		||||
rhel_version=8.8
 | 
			
		||||
 | 
			
		||||
# Check we're in the right directory.
 | 
			
		||||
if [ ! -f nbdkit.spec ]; then
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								SOURCES/nbdkit-1.24.0.tar.gz.sig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								SOURCES/nbdkit-1.24.0.tar.gz.sig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
-----BEGIN PGP SIGNATURE-----
 | 
			
		||||
 | 
			
		||||
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAl/3RBgRHHJpY2hAYW5u
 | 
			
		||||
ZXhpYS5vcmcACgkQkXOPc+G3aKBIIRAAmgoGrmJ8aYO7z+kKgNFjd/p0QxRTZhS/
 | 
			
		||||
ol59ojG6jIzN2x/C2PFbRmPB6HJTEg4anrDX04WrP6R+lID1RrH9pTFQabv0YDQC
 | 
			
		||||
z49oeXAqINYHvAqgFUJCwlymd7BHEYUudLlK3yu7gQKxMM+J/2v0glpxrtLM7KlD
 | 
			
		||||
vvSZkVfbvHlCWIbMWLWIaRHeoWZIXNOjsAp3uEWN2YgikDoxbXVKoh07JoQx5tJ5
 | 
			
		||||
2U+a/zo4BQuRspjnhmWc252ZF/8d954/L8J+2mKvbRRf2iAmsqPgS+MNi7WKWO4K
 | 
			
		||||
w7/urKn0osuOaArs5xYHJnApmJ9U88CzZpoHQkYhcGgnDOipW9ByJRzT41vVQPW5
 | 
			
		||||
IluQODpZUuawWtRIwV/Eoi+LaV2gINAL48Afr02UFYj4gmYQ5TeayLP7NKRQO0VL
 | 
			
		||||
jwL4Z3a0cDyUX4i1OArn2ll8THfiog38HfLb70AG1l3P1BVoVVBYWCYbs4xgC9IK
 | 
			
		||||
LWkjPKuGXvkGVfZi0nCGdPTOoB1CqCXUvKHXm52FCHg12uJMrBQEivodBoCTbtl0
 | 
			
		||||
fSjULQcfrovUEb4d/rDAX7EgJbFS+1jDnodaFHsmNToo3CqfkMBdhLkxG3XExwjy
 | 
			
		||||
OOR34wZssjTLsLlWH/RPucWD25RDy1vdPBska9QvvO7W0p+aOtFbnttkTh5cqs45
 | 
			
		||||
rHg/sDEiaLA=
 | 
			
		||||
=OrsS
 | 
			
		||||
-----END PGP SIGNATURE-----
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
-----BEGIN PGP SIGNATURE-----
 | 
			
		||||
 | 
			
		||||
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmb3vXwRHHJpY2hAYW5u
 | 
			
		||||
ZXhpYS5vcmcACgkQkXOPc+G3aKD5MQ/+NnAunC2qzgUZFzeTf5gilj/xlk3M7LbA
 | 
			
		||||
LDtrAMacpq88CvoxKBcvKvW47/loaL9GBxp0rvly7DQ0vm3WaYMIMj9A25vDFqKC
 | 
			
		||||
IN16/6DDmzMOPkWsDgqAx+VXRMEv/KjtJUxl9jbvZdlmUNGlag/MftVryNqr654w
 | 
			
		||||
NPDeJnL0jN87/S28LHRhuleVMV9SozSb9iG87S1Z6ipXpHu8MzcXYWWiR4P4eecD
 | 
			
		||||
0Rbg+HpBQJJnoVtsBBf35V5HEFtpqg4GvCTMQH0lfLsleE1vTi5Yueq4cpE6YVY9
 | 
			
		||||
Bo5qXUHYy6kVuKcAX6Prvycrh3A847Wh/4M6KfKw4RQgP3FFGMJp+/+M9PzG14gK
 | 
			
		||||
HtL0moKlS/q78kkpyPvAdKDEpD/U+kSrlv2fwugu403o/XrvLaSzhdWSWBgbaB/0
 | 
			
		||||
x3pENPe+UIF+VdNikOa2S3hY4mh7/lx2BpTsGN38qFIiK7TZsAY9aAR2z8Er5/O4
 | 
			
		||||
iubxuPUDsDOTFxCGDS6rxWQKwKVynhEbMzce9R+fKY7XfpRf3RWmplKYyLtAhKbT
 | 
			
		||||
rQoecPj5fIPpUdWIos8FbiQaC5EeBOEq+ZndTSumyKmkHorSI/VpCRio8DAjXdBd
 | 
			
		||||
bXDC1CfXSe9VeScTMYFjim8BcFsLexdrJweYANCCURvOG0drgjWxHAlJ+Ou3Beka
 | 
			
		||||
ygBLbICcbJM=
 | 
			
		||||
=oY/3
 | 
			
		||||
-----END PGP SIGNATURE-----
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
#!/bin/bash -
 | 
			
		||||
 | 
			
		||||
# Generate RPM provides automatically for nbdkit packages and filters.
 | 
			
		||||
# Copyright (C) 2009-2022 Red Hat Inc.
 | 
			
		||||
 | 
			
		||||
# To test:
 | 
			
		||||
# find /usr/lib64/nbdkit/plugins | ./nbdkit-find-provides VER REL
 | 
			
		||||
# find /usr/lib64/nbdkit/filters | ./nbdkit-find-provides VER REL
 | 
			
		||||
 | 
			
		||||
ver="$1"
 | 
			
		||||
rel="$2"
 | 
			
		||||
 | 
			
		||||
function process_file
 | 
			
		||||
{
 | 
			
		||||
    if [[ $1 =~ /plugins/nbdkit-.*-plugin ]] ||
 | 
			
		||||
       [[ $1 =~ /filters/nbdkit-.*-filter ]]; then
 | 
			
		||||
        echo "Provides:" "$(basename $1 .so)" "=" "$ver-$rel"
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
while read line; do
 | 
			
		||||
    process_file "$line"
 | 
			
		||||
done
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
%__nbdkit_provides %{_rpmconfigdir}/nbdkit-find-provides %{version} %{release}
 | 
			
		||||
%__nbdkit_path     %{_libdir}/nbdkit/(plugins|filters)/nbdkit-.*-(plugin|filter)(\.so)?$
 | 
			
		||||
%__nbdkit_flags    exeonly
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
/usr/sbin/nbdkit	 --    gen_context(system_u:object_r:nbdkit_exec_t,s0)
 | 
			
		||||
 | 
			
		||||
/usr/lib/systemd/system/nbdkit.*	gen_context(system_u:object_r:nbdkit_unit_file_t,s0)
 | 
			
		||||
@ -1,207 +0,0 @@
 | 
			
		||||
## <summary>policy for nbdkit</summary>
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##    Execute nbdkit_exec_t in the nbdkit domain.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
## <summary>
 | 
			
		||||
##    Domain allowed to transition.
 | 
			
		||||
## </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
interface(`nbdkit_domtrans',`
 | 
			
		||||
	gen_require(`
 | 
			
		||||
		type nbdkit_t, nbdkit_exec_t;
 | 
			
		||||
	')
 | 
			
		||||
 | 
			
		||||
	corecmd_search_bin($1)
 | 
			
		||||
	domtrans_pattern($1, nbdkit_exec_t, nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
######################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##    Execute nbdkit in the caller domain.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##    <summary>
 | 
			
		||||
##    Domain allowed access.
 | 
			
		||||
##    </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
interface(`nbdkit_exec',`
 | 
			
		||||
	gen_require(`
 | 
			
		||||
		type nbdkit_exec_t;
 | 
			
		||||
	')
 | 
			
		||||
    
 | 
			
		||||
	corecmd_search_bin($1)
 | 
			
		||||
	can_exec($1, nbdkit_exec_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##    Execute nbdkit in the nbdkit domain, and
 | 
			
		||||
##    allow the specified role the nbdkit domain.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##    <summary>
 | 
			
		||||
##    Domain allowed to transition
 | 
			
		||||
##    </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
## <param name="role">
 | 
			
		||||
##    <summary>
 | 
			
		||||
##    The role to be allowed the nbdkit domain.
 | 
			
		||||
##    </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
interface(`nbdkit_run',`
 | 
			
		||||
	gen_require(`
 | 
			
		||||
		type nbdkit_t;
 | 
			
		||||
		attribute_role nbdkit_roles;
 | 
			
		||||
	')
 | 
			
		||||
 | 
			
		||||
	nbdkit_domtrans($1)
 | 
			
		||||
	roleattribute $2 nbdkit_roles;
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##    Role access for nbdkit
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="role">
 | 
			
		||||
##    <summary>
 | 
			
		||||
##    Role allowed access
 | 
			
		||||
##    </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##    <summary>
 | 
			
		||||
##    User domain for the role
 | 
			
		||||
##    </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
interface(`nbdkit_role',`
 | 
			
		||||
	gen_require(`
 | 
			
		||||
		type nbdkit_t;
 | 
			
		||||
		attribute_role nbdkit_roles;
 | 
			
		||||
	')
 | 
			
		||||
 | 
			
		||||
	roleattribute $1 nbdkit_roles;
 | 
			
		||||
 | 
			
		||||
	nbdkit_domtrans($2)
 | 
			
		||||
 | 
			
		||||
	ps_process_pattern($2, nbdkit_t)
 | 
			
		||||
	allow $2 nbdkit_t:process { signull signal sigkill };
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##	Allow attempts to connect to nbdkit
 | 
			
		||||
##	with a unix stream socket.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##	<summary>
 | 
			
		||||
##	Domain to not audit.
 | 
			
		||||
##	</summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
interface(`nbdkit_stream_connect',`
 | 
			
		||||
	gen_require(`
 | 
			
		||||
		type nbdkit_t;
 | 
			
		||||
	')
 | 
			
		||||
 | 
			
		||||
	allow $1 nbdkit_t:unix_stream_socket connectto;
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##      Allow nbdkit_exec_t to be an entrypoint
 | 
			
		||||
##      of the specified domain
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##      <summary>
 | 
			
		||||
##      Domain allowed access.
 | 
			
		||||
##      </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
## <rolecap/>
 | 
			
		||||
#
 | 
			
		||||
interface(`nbdkit_entrypoint',`
 | 
			
		||||
        gen_require(`
 | 
			
		||||
                type nbdkit_exec_t;
 | 
			
		||||
        ')
 | 
			
		||||
        allow $1 nbdkit_exec_t:file entrypoint;
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
# ----------------------------------------------------------------------
 | 
			
		||||
# RWMJ: See:
 | 
			
		||||
# https://issues.redhat.com/browse/RHEL-5174?focusedId=23387259&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-23387259
 | 
			
		||||
# Remove this when virt.if gets updated.
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
#
 | 
			
		||||
# Interface compatibility blocks
 | 
			
		||||
#
 | 
			
		||||
# The following definitions ensure compatibility with distribution policy
 | 
			
		||||
# versions that do not contain given interfaces (epel, or older Fedora
 | 
			
		||||
# releases).
 | 
			
		||||
# Each block tests for existence of given interface and defines it if needed.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##      Read and write to svirt_image dirs.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##      <summary>
 | 
			
		||||
##      Domain allowed access.
 | 
			
		||||
##      </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
ifndef(`virt_rw_svirt_image_dirs',`
 | 
			
		||||
	interface(`virt_rw_svirt_image_dirs',`
 | 
			
		||||
		gen_require(`
 | 
			
		||||
			type svirt_image_t;
 | 
			
		||||
		')
 | 
			
		||||
 | 
			
		||||
		allow $1 svirt_image_t:dir rw_dir_perms;
 | 
			
		||||
	')
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
##      Create svirt_image sock_files.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
##      <summary>
 | 
			
		||||
##      Domain allowed access.
 | 
			
		||||
##      </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
ifndef(`virt_create_svirt_image_sock_files',`
 | 
			
		||||
	interface(`virt_create_svirt_image_sock_files',`
 | 
			
		||||
		gen_require(`
 | 
			
		||||
			type svirt_image_t;
 | 
			
		||||
		')
 | 
			
		||||
 | 
			
		||||
		allow $1 svirt_image_t:sock_file create_sock_file_perms;
 | 
			
		||||
	')
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
## <summary>
 | 
			
		||||
## 	Read and write virtlogd pipes.
 | 
			
		||||
## </summary>
 | 
			
		||||
## <param name="domain">
 | 
			
		||||
## <summary>
 | 
			
		||||
##      Domain allowed access.
 | 
			
		||||
## </summary>
 | 
			
		||||
## </param>
 | 
			
		||||
#
 | 
			
		||||
ifndef(`virtlogd_rw_pipes',`
 | 
			
		||||
	interface(`virtlogd_rw_pipes',`
 | 
			
		||||
	        gen_require(`
 | 
			
		||||
	                type virtlogd_t;
 | 
			
		||||
	        ')
 | 
			
		||||
 | 
			
		||||
	        allow $1 virtlogd_t:fifo_file rw_fifo_file_perms;
 | 
			
		||||
	')
 | 
			
		||||
')
 | 
			
		||||
@ -1,100 +0,0 @@
 | 
			
		||||
policy_module(nbdkit, 1.0.0)
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
#
 | 
			
		||||
# Declarations
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
gen_require(`
 | 
			
		||||
    type unconfined_t;
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
type nbdkit_t;
 | 
			
		||||
type nbdkit_exec_t;
 | 
			
		||||
application_domain(nbdkit_t, nbdkit_exec_t)
 | 
			
		||||
mcs_constrained(nbdkit_t)
 | 
			
		||||
role system_r types nbdkit_t;
 | 
			
		||||
 | 
			
		||||
type nbdkit_home_t;
 | 
			
		||||
userdom_user_home_content(nbdkit_home_t)
 | 
			
		||||
 | 
			
		||||
type nbdkit_tmp_t;
 | 
			
		||||
files_tmp_file(nbdkit_tmp_t)
 | 
			
		||||
 | 
			
		||||
type nbdkit_unit_file_t;
 | 
			
		||||
systemd_unit_file(nbdkit_unit_file_t)
 | 
			
		||||
 | 
			
		||||
permissive nbdkit_t;
 | 
			
		||||
 | 
			
		||||
########################################
 | 
			
		||||
#
 | 
			
		||||
# nbdkit local policy
 | 
			
		||||
#
 | 
			
		||||
allow nbdkit_t self:capability { setgid setuid };
 | 
			
		||||
allow nbdkit_t self:fifo_file rw_fifo_file_perms;
 | 
			
		||||
allow nbdkit_t self:netlink_route_socket rw_netlink_socket_perms;
 | 
			
		||||
allow nbdkit_t self:process { fork setsockcreate signal_perms };
 | 
			
		||||
allow nbdkit_t self:tcp_socket create_stream_socket_perms;
 | 
			
		||||
allow nbdkit_t self:udp_socket create_socket_perms;
 | 
			
		||||
 | 
			
		||||
manage_dirs_pattern(nbdkit_t, nbdkit_tmp_t, nbdkit_tmp_t)
 | 
			
		||||
manage_files_pattern(nbdkit_t, nbdkit_tmp_t, nbdkit_tmp_t) 
 | 
			
		||||
userdom_user_tmp_filetrans(nbdkit_t, nbdkit_tmp_t, { dir file })
 | 
			
		||||
 | 
			
		||||
manage_dirs_pattern(nbdkit_t, nbdkit_home_t, nbdkit_home_t)
 | 
			
		||||
manage_files_pattern(nbdkit_t, nbdkit_home_t, nbdkit_home_t) 
 | 
			
		||||
userdom_user_home_dir_filetrans(nbdkit_t, nbdkit_home_t, { dir file })
 | 
			
		||||
 | 
			
		||||
corenet_tcp_connect_http_port(nbdkit_t)
 | 
			
		||||
corenet_tcp_connect_ssh_port(nbdkit_t)
 | 
			
		||||
corenet_tcp_connect_tftp_port(nbdkit_t)
 | 
			
		||||
corenet_tcp_bind_generic_port(nbdkit_t)
 | 
			
		||||
corenet_tcp_bind_generic_node(nbdkit_t)
 | 
			
		||||
 | 
			
		||||
domain_use_interactive_fds(nbdkit_t)
 | 
			
		||||
 | 
			
		||||
files_read_etc_files(nbdkit_t)
 | 
			
		||||
 | 
			
		||||
init_abstract_socket_activation(nbdkit_t)
 | 
			
		||||
init_ioctl_stream_sockets(nbdkit_t)
 | 
			
		||||
init_rw_stream_sockets(nbdkit_t)
 | 
			
		||||
 | 
			
		||||
optional_policy(`
 | 
			
		||||
	auth_use_nsswitch(nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
optional_policy(`
 | 
			
		||||
	logging_send_syslog_msg(nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
optional_policy(`
 | 
			
		||||
	miscfiles_read_localization(nbdkit_t)
 | 
			
		||||
	miscfiles_read_generic_certs(nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
optional_policy(`
 | 
			
		||||
	sysnet_dns_name_resolve(nbdkit_t)
 | 
			
		||||
	sysnet_read_config(nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
optional_policy(`
 | 
			
		||||
	userdom_read_user_home_content_files(nbdkit_t)
 | 
			
		||||
	userdom_use_inherited_user_ptys(nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
optional_policy(`
 | 
			
		||||
	virt_create_svirt_image_sock_files(nbdkit_t)
 | 
			
		||||
	virt_read_qemu_pid_files(nbdkit_t)
 | 
			
		||||
	virtlogd_rw_pipes(nbdkit_t)
 | 
			
		||||
	virt_rw_svirt_image(nbdkit_t)
 | 
			
		||||
	virt_rw_svirt_image_dirs(nbdkit_t)
 | 
			
		||||
	virt_search_lib(nbdkit_t)
 | 
			
		||||
	virt_stream_connect_svirt(nbdkit_t)
 | 
			
		||||
')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# FIXME: It would be nice to allow libvirt to transition nbdkit_exec_t to 
 | 
			
		||||
# nbdkit_t when libvirtd was started manually from the commandline (i.e. in 
 | 
			
		||||
# unconfined_t), but we don't want this transition to happen automatically 
 | 
			
		||||
# when starting directly from the shell. I'm not sure how to achieve this...  
 | 
			
		||||
#nbdkit_domtrans(unconfined_t, nbdkit_exec_t, nbdkit_t)
 | 
			
		||||
							
								
								
									
										1826
									
								
								SPECS/nbdkit.spec
									
									
									
									
									
								
							
							
						
						
									
										1826
									
								
								SPECS/nbdkit.spec
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user