[PATCH 2/2] nbd: Disallow ioctls on disconnected block device

From: Markus Pargmann
Date: Fri Jun 24 2016 - 05:29:50 EST


After NBD_DO_IT exited the block device may still be used. Make sure
that we handle intended disconnects differently and do not allow any
changed of the nbd device.

This patch should avoid that the nbd-client connects to a different server
and the users of the block device are suddenly reading/writing from a
different backend device.

For timeouts it is still possible to setup a new socket so that the
connection may be refreshed without creating problems for all users.

Signed-off-by: Markus Pargmann <mpa@xxxxxxxxxxxxxx>
---
drivers/block/nbd.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 620660f3ff0f..39358efac73e 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -708,6 +708,18 @@ static void nbd_dev_dbg_close(struct nbd_device *nbd);
static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
unsigned int cmd, unsigned long arg)
{
+ /*
+ * After a disconnect was instructed, do not allow any further actions
+ * on the block device that would lead to a new connected endpoint.
+ * This condition stays until nbd_reset was called either because all
+ * users closed the device or because of CLEAR_SOCK.
+ */
+ if (nbd->disconnect &&
+ cmd != NBD_CLEAR_SOCK && cmd != NBD_PRINT_DEBUG) {
+ dev_info(disk_to_dev(nbd->disk), "Device is still busy after instructing a disconnect\n");
+ return -EBUSY;
+ }
+
switch (cmd) {
case NBD_DISCONNECT: {
struct request sreq;
@@ -733,11 +745,15 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
}

case NBD_CLEAR_SOCK:
- sock_shutdown(nbd);
- nbd_clear_que(nbd);
- BUG_ON(!list_empty(&nbd->queue_head));
- BUG_ON(!list_empty(&nbd->waiting_queue));
- kill_bdev(bdev);
+ if (nbd->disconnect) {
+ nbd_reset(nbd);
+ } else {
+ sock_shutdown(nbd);
+ nbd_clear_que(nbd);
+ BUG_ON(!list_empty(&nbd->queue_head));
+ BUG_ON(!list_empty(&nbd->waiting_queue));
+ kill_bdev(bdev);
+ }
return 0;

case NBD_SET_SOCK: {
@@ -812,8 +828,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
mutex_lock(&nbd->tx_lock);
nbd->task_recv = NULL;

- if (nbd->disconnect) /* user requested, ignore socket errors */
+ if (nbd->disconnect) { /* user requested, ignore socket errors */
+ sock_shutdown(nbd);
error = 0;
+ }
if (nbd->timedout)
error = -ETIMEDOUT;

--
2.1.4