Skip to content

Commit 0b584bf

Browse files
Mike Christiegregkh
authored andcommitted
nbd: fix max number of supported devs
[ Upstream commit e9e006f ] This fixes a bug added in 4.10 with commit: commit 9561a7a Author: Josef Bacik <[email protected]> Date: Tue Nov 22 14:04:40 2016 -0500 nbd: add multi-connection support that limited the number of devices to 256. Before the patch we could create 1000s of devices, but the patch switched us from using our own thread to using a work queue which has a default limit of 256 active works. The problem is that our recv_work function sits in a loop until disconnection but only handles IO for one connection. The work is started when the connection is started/restarted, but if we end up creating 257 or more connections, the queue_work call just queues connection257+'s recv_work and that waits for connection 1 - 256's recv_work to be disconnected and that work instance completing. Instead of reverting back to kthreads, this has us allocate a workqueue_struct per device, so we can block in the work. Cc: [email protected] Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Mike Christie <[email protected]> Signed-off-by: Jens Axboe <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent dd36e72 commit 0b584bf

File tree

1 file changed

+25
-14
lines changed

1 file changed

+25
-14
lines changed

drivers/block/nbd.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ struct nbd_device {
106106
struct nbd_config *config;
107107
struct mutex config_lock;
108108
struct gendisk *disk;
109+
struct workqueue_struct *recv_workq;
109110

110111
struct list_head list;
111112
struct task_struct *task_recv;
@@ -136,7 +137,6 @@ static struct dentry *nbd_dbg_dir;
136137

137138
static unsigned int nbds_max = 16;
138139
static int max_part = 16;
139-
static struct workqueue_struct *recv_workqueue;
140140
static int part_shift;
141141

142142
static int nbd_dev_dbg_init(struct nbd_device *nbd);
@@ -1015,7 +1015,7 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
10151015
/* We take the tx_mutex in an error path in the recv_work, so we
10161016
* need to queue_work outside of the tx_mutex.
10171017
*/
1018-
queue_work(recv_workqueue, &args->work);
1018+
queue_work(nbd->recv_workq, &args->work);
10191019

10201020
atomic_inc(&config->live_connections);
10211021
wake_up(&config->conn_wait);
@@ -1120,6 +1120,10 @@ static void nbd_config_put(struct nbd_device *nbd)
11201120
kfree(nbd->config);
11211121
nbd->config = NULL;
11221122

1123+
if (nbd->recv_workq)
1124+
destroy_workqueue(nbd->recv_workq);
1125+
nbd->recv_workq = NULL;
1126+
11231127
nbd->tag_set.timeout = 0;
11241128
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue);
11251129

@@ -1145,6 +1149,14 @@ static int nbd_start_device(struct nbd_device *nbd)
11451149
return -EINVAL;
11461150
}
11471151

1152+
nbd->recv_workq = alloc_workqueue("knbd%d-recv",
1153+
WQ_MEM_RECLAIM | WQ_HIGHPRI |
1154+
WQ_UNBOUND, 0, nbd->index);
1155+
if (!nbd->recv_workq) {
1156+
dev_err(disk_to_dev(nbd->disk), "Could not allocate knbd recv work queue.\n");
1157+
return -ENOMEM;
1158+
}
1159+
11481160
blk_mq_update_nr_hw_queues(&nbd->tag_set, config->num_connections);
11491161
nbd->task_recv = current;
11501162

@@ -1175,7 +1187,7 @@ static int nbd_start_device(struct nbd_device *nbd)
11751187
INIT_WORK(&args->work, recv_work);
11761188
args->nbd = nbd;
11771189
args->index = i;
1178-
queue_work(recv_workqueue, &args->work);
1190+
queue_work(nbd->recv_workq, &args->work);
11791191
}
11801192
nbd_size_update(nbd);
11811193
return error;
@@ -1195,8 +1207,10 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b
11951207
mutex_unlock(&nbd->config_lock);
11961208
ret = wait_event_interruptible(config->recv_wq,
11971209
atomic_read(&config->recv_threads) == 0);
1198-
if (ret)
1210+
if (ret) {
11991211
sock_shutdown(nbd);
1212+
flush_workqueue(nbd->recv_workq);
1213+
}
12001214
mutex_lock(&nbd->config_lock);
12011215
bd_set_size(bdev, 0);
12021216
/* user requested, ignore socket errors */
@@ -1836,6 +1850,12 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd)
18361850
mutex_lock(&nbd->config_lock);
18371851
nbd_disconnect(nbd);
18381852
mutex_unlock(&nbd->config_lock);
1853+
/*
1854+
* Make sure recv thread has finished, so it does not drop the last
1855+
* config ref and try to destroy the workqueue from inside the work
1856+
* queue.
1857+
*/
1858+
flush_workqueue(nbd->recv_workq);
18391859
if (test_and_clear_bit(NBD_HAS_CONFIG_REF,
18401860
&nbd->config->runtime_flags))
18411861
nbd_config_put(nbd);
@@ -2216,20 +2236,12 @@ static int __init nbd_init(void)
22162236

22172237
if (nbds_max > 1UL << (MINORBITS - part_shift))
22182238
return -EINVAL;
2219-
recv_workqueue = alloc_workqueue("knbd-recv",
2220-
WQ_MEM_RECLAIM | WQ_HIGHPRI |
2221-
WQ_UNBOUND, 0);
2222-
if (!recv_workqueue)
2223-
return -ENOMEM;
22242239

2225-
if (register_blkdev(NBD_MAJOR, "nbd")) {
2226-
destroy_workqueue(recv_workqueue);
2240+
if (register_blkdev(NBD_MAJOR, "nbd"))
22272241
return -EIO;
2228-
}
22292242

22302243
if (genl_register_family(&nbd_genl_family)) {
22312244
unregister_blkdev(NBD_MAJOR, "nbd");
2232-
destroy_workqueue(recv_workqueue);
22332245
return -EINVAL;
22342246
}
22352247
nbd_dbg_init();
@@ -2271,7 +2283,6 @@ static void __exit nbd_cleanup(void)
22712283

22722284
idr_destroy(&nbd_index_idr);
22732285
genl_unregister_family(&nbd_genl_family);
2274-
destroy_workqueue(recv_workqueue);
22752286
unregister_blkdev(NBD_MAJOR, "nbd");
22762287
}
22772288

0 commit comments

Comments
 (0)