summaryrefslogtreecommitdiff
path: root/drivers/block
diff options
context:
space:
mode:
authorXie Yongji <xieyongji@bytedance.com>2021-08-13 23:13:30 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-08-18 08:57:01 +0200
commitb74145d858a837dd0bdc19aa24f32aa9948fec18 (patch)
tree6a60402858e824fd77a3a901475e88a17fe16641 /drivers/block
parentad9550114d4ce8396123f25cb4287a1b2f220c8f (diff)
downloadlinux-b74145d858a837dd0bdc19aa24f32aa9948fec18.tar.gz
linux-b74145d858a837dd0bdc19aa24f32aa9948fec18.tar.bz2
linux-b74145d858a837dd0bdc19aa24f32aa9948fec18.zip
nbd: Aovid double completion of a request
[ Upstream commit cddce01160582a5f52ada3da9626c052d852ec42 ] There is a race between iterating over requests in nbd_clear_que() and completing requests in recv_work(), which can lead to double completion of a request. To fix it, flush the recv worker before iterating over the requests and don't abort the completed request while iterating. Fixes: 96d97e17828f ("nbd: clear_sock on netlink disconnect") Reported-by: Jiang Yadong <jiangyadong@bytedance.com> Signed-off-by: Xie Yongji <xieyongji@bytedance.com> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Link: https://lore.kernel.org/r/20210813151330.96-1-xieyongji@bytedance.com Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nbd.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 839364371f9a..25e81b1a59a5 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -797,6 +797,10 @@ static bool nbd_clear_req(struct request *req, void *data, bool reserved)
{
struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
+ /* don't abort one completed request */
+ if (blk_mq_request_completed(req))
+ return true;
+
mutex_lock(&cmd->lock);
cmd->status = BLK_STS_IOERR;
mutex_unlock(&cmd->lock);
@@ -2009,15 +2013,19 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd)
{
mutex_lock(&nbd->config_lock);
nbd_disconnect(nbd);
- nbd_clear_sock(nbd);
- mutex_unlock(&nbd->config_lock);
+ sock_shutdown(nbd);
/*
* Make sure recv thread has finished, so it does not drop the last
* config ref and try to destroy the workqueue from inside the work
- * queue.
+ * queue. And this also ensure that we can safely call nbd_clear_que()
+ * to cancel the inflight I/Os.
*/
if (nbd->recv_workq)
flush_workqueue(nbd->recv_workq);
+ nbd_clear_que(nbd);
+ nbd->task_setup = NULL;
+ mutex_unlock(&nbd->config_lock);
+
if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
&nbd->config->runtime_flags))
nbd_config_put(nbd);