[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH 2/2] nbd-client: Add support for setting /sys/block/nbdN/backend



In order for userspace apps to idempotently ensure that a
netlink-managed NBD device corresponds to the device that the app is
expecting, kernel 5.14 added a netlink backend string identifier.
Expose the ability for setting this identifier when binding to a
device; the user can then check with /sys/block/nbdN/backend to see if
the contents match expectations.

Signed-off-by: Eric Blake <eblake@redhat.com>

---

Given the syntax error present in nbd-client.8.sgml.in before my patch
(a </varlistentry without closing >), I'm not sure how to test that my
man page changes are correct.
---
 man/nbd-client.8.sgml.in | 24 +++++++++++++++++++++++-
 nbd-client.c             | 26 +++++++++++++++++++++-----
 nbd-netlink.h            |  7 +++++--
 3 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/man/nbd-client.8.sgml.in b/man/nbd-client.8.sgml.in
index c1f18624..b9478502 100644
--- a/man/nbd-client.8.sgml.in
+++ b/man/nbd-client.8.sgml.in
@@ -260,7 +260,29 @@ manpage.1: manpage.sgml
 	  <emphasis>require</emphasis> the use of netlink, but it has
 	  not yet been decided when that will be the case.</para>
         </listitem>
-      </varlistentry
+      </varlistentry>
+      <varlistentry>
+        <term><option>-identifier <replaceable>ident</replaceable></option></term>
+        <term><option>-i</option></term>
+        <listitem>
+	  <para>Added in 3.27, this tells &dhpackage; to set the
+	  netlink identifier (requires kernel 5.14 or newer), which
+	  can later be viewed
+	  at <command>/sys/block/nbdN/backend</command>. This prevents
+	  any process from using netlink to silently reconfigure the
+	  device to a different backend, making it easier to write
+	  idempotent code that is safe in the presence of
+	  configuration races.
+	  </para>
+	  <para>This option is only available if &dhpackage; was
+	  compiled against libnl-genl. If that is not the case,
+	  nbd-client will only be able to use the ioctl interface (and
+	  the option will not be available).</para>
+	  <para>Note that a future version of &dhpackage; will
+	  <emphasis>require</emphasis> the use of netlink, but it has
+	  not yet been decided when that will be the case.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
 	<term><option>-persist</option></term>
 	<term><option>-p</option></term>
diff --git a/nbd-client.c b/nbd-client.c
index e9a42009..2be3a4bc 100644
--- a/nbd-client.c
+++ b/nbd-client.c
@@ -164,7 +164,7 @@ static struct nl_sock *get_nbd_socket(int *driver_id) {

 static void netlink_configure(int index, int *sockfds, int num_connects,
 			      u64 size64, int blocksize, uint16_t flags,
-			      int timeout) {
+			      int timeout, const char *identifier) {
 	struct nl_sock *socket;
 	struct nlattr *sock_attr;
 	struct nl_msg *msg;
@@ -185,6 +185,8 @@ static void netlink_configure(int index, int *sockfds, int num_connects,
 	NLA_PUT_U64(msg, NBD_ATTR_SERVER_FLAGS, flags);
 	if (timeout)
 		NLA_PUT_U64(msg, NBD_ATTR_TIMEOUT, timeout);
+	if (identifier)
+		NLA_PUT_STRING(msg, NBD_ATTR_BACKEND_IDENTIFIER, identifier);

 	sock_attr = nla_nest_start(msg, NBD_ATTR_SOCKETS);
 	if (!sock_attr)
@@ -242,7 +244,7 @@ nla_put_failure:
 #else
 static void netlink_configure(int index, int *sockfds, int num_connects,
 			      u64 size64, int blocksize, uint16_t flags,
-			      int timeout)
+			      int timeout, const char *identifier)
 {
 }

@@ -871,7 +873,7 @@ void usage(char* errmsg, ...) {
 		fprintf(stderr, "%s version %s\n", PROG_NAME, PACKAGE_VERSION);
 	}
 #if HAVE_NETLINK
-	fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m] [-nonetlink|-L]\n\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
+	fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m] [-i ident|-nonetlink|-L]\n\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
 #else
 	fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m]\n\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
 #endif
@@ -910,7 +912,7 @@ void disconnect(char* device) {

 static const char *short_opts = "-B:b:c:d:gH:hlnN:PpRSst:uVxy:"
 #if HAVE_NETLINK
-	"L"
+	"i:L"
 #endif
 #if HAVE_GNUTLS
 	"A:C:F:K:"
@@ -931,6 +933,7 @@ int main(int argc, char *argv[]) {
 	uint32_t opts=0;
 	sigset_t block, old;
 	struct sigaction sa;
+	char *identifier = NULL;
 	int netlink = HAVE_NETLINK;
 	int need_disconnect = 0;
 	int *sockfds;
@@ -945,6 +948,9 @@ int main(int argc, char *argv[]) {
 		{ "no-optgo", no_argument, NULL, 'g' },
 		{ "help", no_argument, NULL, 'h' },
 		{ "tlshostname", required_argument, NULL, 'H' },
+#if HAVE_NETLINK
+		{ "identifier", required_argument, NULL, 'i' },
+#endif
 		{ "keyfile", required_argument, NULL, 'K' },
 		{ "list", no_argument, NULL, 'l' },
 #if HAVE_NETLINK
@@ -1049,6 +1055,11 @@ int main(int argc, char *argv[]) {
 		case 'h':
 			usage(NULL);
 			exit(EXIT_SUCCESS);
+#if HAVE_NETLINK
+		case 'i':
+			identifier = optarg;
+			break;
+#endif
 		case 'l':
 			needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
 			opts |= NBDC_DO_LIST;
@@ -1176,6 +1187,10 @@ int main(int argc, char *argv[]) {

 	if (netlink)
 		nofork = 1;
+	else if (identifier) {
+		fprintf(stderr, "E: identifier is only useful with netlink\n");
+		exit(EXIT_FAILURE);
+	}

 	if((cur_client->force_size64 % cur_client->bs) != 0) {
 		fprintf(stderr, "E: size (%" PRIu64 " bytes) is not a multiple of blocksize (%d)!\n", cur_client->force_size64, cur_client->bs);
@@ -1242,7 +1257,8 @@ int main(int argc, char *argv[]) {
 				err("Invalid nbd device target\n");
 		}
 		netlink_configure(index, sockfds, cur_client->nconn,
-				  cur_client->size64, cur_client->bs, flags, cur_client->timeout);
+				  cur_client->size64, cur_client->bs, flags, cur_client->timeout,
+				  identifier);
 		return 0;
 	}
 	/* Go daemon */
diff --git a/nbd-netlink.h b/nbd-netlink.h
index a9e68024..2d0b9096 100644
--- a/nbd-netlink.h
+++ b/nbd-netlink.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 /*
  * Copyright (C) 2017 Facebook.  All rights reserved.
  *
@@ -18,8 +19,9 @@
 #ifndef _UAPILINUX_NBD_NETLINK_H
 #define _UAPILINUX_NBD_NETLINK_H

-#define NBD_GENL_FAMILY_NAME	"nbd"
-#define NBD_GENL_VERSION	0x1
+#define NBD_GENL_FAMILY_NAME		"nbd"
+#define NBD_GENL_VERSION		0x1
+#define NBD_GENL_MCAST_GROUP_NAME	"nbd_mc_group"

 /* Configuration policy attributes, used for CONNECT */
 enum {
@@ -33,6 +35,7 @@ enum {
 	NBD_ATTR_SOCKETS,
 	NBD_ATTR_DEAD_CONN_TIMEOUT,
 	NBD_ATTR_DEVICE_LIST,
+	NBD_ATTR_BACKEND_IDENTIFIER,
 	__NBD_ATTR_MAX,
 };
 #define NBD_ATTR_MAX (__NBD_ATTR_MAX - 1)
-- 
2.47.0


Reply to: