Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b74145d8 authored by Xie Yongji's avatar Xie Yongji Committed by Greg Kroah-Hartman
Browse files

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: 96d97e17 ("nbd: clear_sock on netlink disconnect")
Reported-by: default avatarJiang Yadong <jiangyadong@bytedance.com>
Signed-off-by: default avatarXie Yongji <xieyongji@bytedance.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Link: https://lore.kernel.org/r/20210813151330.96-1-xieyongji@bytedance.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent ad955011
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -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);