[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: