Linux block layer
 help / color / mirror / Atom feed
From: Yun Zhou <yun.zhou@windriver.com>
To: <josef@toxicpanda.com>, <axboe@kernel.dk>
Cc: <linux-block@vger.kernel.org>, <nbd@other.debian.org>,
	<linux-kernel@vger.kernel.org>, <yun.zhou@windriver.com>
Subject: [PATCH 2/2] nbd: detect management process exit via netlink notifier
Date: Tue, 7 Jul 2026 18:27:24 +0800	[thread overview]
Message-ID: <20260707102724.3838638-2-yun.zhou@windriver.com> (raw)
In-Reply-To: <20260707102724.3838638-1-yun.zhou@windriver.com>

Register a netlink notifier to detect when the NBD management process
closes its netlink socket (on exit or crash).

Without this, in-flight I/O waits for socket timeout while udevd holds
disk->open_mutex for partition scanning, blocking poweroff's
sync_bdevs() and causing a hung task during shutdown.

Fix this by tracking the management process's netlink portid and, on
NETLINK_URELEASE, calling sock_shutdown() on all devices it owns.
This fails in-flight I/O immediately so shutdown can proceed.

Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
---
 drivers/block/nbd.c | 59 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 43aa4121f0c5..3bf88f7b3535 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -45,6 +45,7 @@
 #include <linux/nbd.h>
 #include <linux/nbd-netlink.h>
 #include <net/genetlink.h>
+#include <linux/netlink.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/nbd.h>
@@ -131,6 +132,7 @@ struct nbd_device {
 
 	unsigned long flags;
 	pid_t pid; /* pid of nbd-client, if attached */
+	u32 owner_portid; /* netlink portid of management process */
 
 	char *backend;
 };
@@ -2331,12 +2333,19 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
 	}
 	set_bit(NBD_RT_HAS_BACKEND_FILE, &config->runtime_flags);
 
+	/*
+	 * Set owner before starting device so that the netlink notifier
+	 * can clean up if the management process exits during setup.
+	 */
+	nbd->owner_portid = info->snd_portid;
 	ret = nbd_start_device(nbd);
 out:
 	if (!ret) {
 		set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags);
 		refcount_inc(&nbd->config_refs);
 		nbd_connect_reply(info, nbd->index);
+	} else {
+		nbd->owner_portid = 0;
 	}
 	mutex_unlock(&nbd->config_lock);
 
@@ -2541,6 +2550,12 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
 		}
 	}
 out:
+	/*
+	 * Update owner to the reconfiguring process so the notifier
+	 * tracks the correct management process.
+	 */
+	if (!ret)
+		nbd->owner_portid = info->snd_portid;
 	mutex_unlock(&nbd->config_lock);
 	nbd_config_put(nbd);
 	nbd_put(nbd);
@@ -2743,6 +2758,48 @@ static void nbd_dead_link_work(struct work_struct *work)
 	kfree(args);
 }
 
+/*
+ * Detect when the management process (the one that issued NBD_CMD_CONNECT)
+ * closes its netlink socket (e.g., exit or crash).  When this happens,
+ * no one can reconnect, so mark all its devices as disconnected to stop
+ * waiting for reconnect and fail pending I/O promptly.
+ */
+static int nbd_netlink_event(struct notifier_block *this,
+			     unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+	struct nbd_device *nbd;
+	int id;
+
+	if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
+		return NOTIFY_DONE;
+
+	mutex_lock(&nbd_index_mutex);
+	idr_for_each_entry(&nbd_index_idr, nbd, id) {
+		if (nbd->owner_portid != n->portid)
+			continue;
+
+		nbd->owner_portid = 0;
+		if (refcount_inc_not_zero(&nbd->config_refs)) {
+			/*
+			 * Shut down all sockets.  sock_shutdown() holds
+			 * tx_lock for each socket, preventing races with
+			 * reconnect, and sets NBD_RT_DISCONNECTED so that
+			 * nbd_reconnect_possible() fails immediately.
+			 */
+			sock_shutdown(nbd);
+			nbd_config_put(nbd);
+		}
+	}
+	mutex_unlock(&nbd_index_mutex);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nbd_netlink_notifier = {
+	.notifier_call = nbd_netlink_event,
+};
+
 static int __init nbd_init(void)
 {
 	int i;
@@ -2789,6 +2846,7 @@ static int __init nbd_init(void)
 		unregister_blkdev(NBD_MAJOR, "nbd");
 		return -EINVAL;
 	}
+	netlink_register_notifier(&nbd_netlink_notifier);
 	nbd_dbg_init();
 
 	for (i = 0; i < nbds_max; i++)
@@ -2818,6 +2876,7 @@ static void __exit nbd_cleanup(void)
 	 * for the completion of netlink commands.
 	 */
 	genl_unregister_family(&nbd_genl_family);
+	netlink_unregister_notifier(&nbd_netlink_notifier);
 
 	nbd_dbg_close();
 
-- 
2.43.0


      reply	other threads:[~2026-07-07 10:28 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-07 10:27 [PATCH 1/2] nbd: replace wait_for_reconnect with non-blocking retry Yun Zhou
2026-07-07 10:27 ` Yun Zhou [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260707102724.3838638-2-yun.zhou@windriver.com \
    --to=yun.zhou@windriver.com \
    --cc=axboe@kernel.dk \
    --cc=josef@toxicpanda.com \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nbd@other.debian.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox