mirror of https://gitee.com/openkylin/linux.git
nbd: Aovid double completion of a request
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: 96d97e1782
("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>
This commit is contained in:
parent
454bb67752
commit
cddce01160
|
@ -818,6 +818,10 @@ static bool nbd_clear_req(struct request *req, void *data, bool reserved)
|
||||||
{
|
{
|
||||||
struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
|
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);
|
mutex_lock(&cmd->lock);
|
||||||
cmd->status = BLK_STS_IOERR;
|
cmd->status = BLK_STS_IOERR;
|
||||||
mutex_unlock(&cmd->lock);
|
mutex_unlock(&cmd->lock);
|
||||||
|
@ -2004,15 +2008,19 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd)
|
||||||
{
|
{
|
||||||
mutex_lock(&nbd->config_lock);
|
mutex_lock(&nbd->config_lock);
|
||||||
nbd_disconnect(nbd);
|
nbd_disconnect(nbd);
|
||||||
nbd_clear_sock(nbd);
|
sock_shutdown(nbd);
|
||||||
mutex_unlock(&nbd->config_lock);
|
|
||||||
/*
|
/*
|
||||||
* Make sure recv thread has finished, so it does not drop the last
|
* 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
|
* 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)
|
if (nbd->recv_workq)
|
||||||
flush_workqueue(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,
|
if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
|
||||||
&nbd->config->runtime_flags))
|
&nbd->config->runtime_flags))
|
||||||
nbd_config_put(nbd);
|
nbd_config_put(nbd);
|
||||||
|
|
Loading…
Reference in New Issue