* [PATCH 1/2] nbd: protect cmd->status with cmd->lock
2019-10-21 19:56 [PATCH 0/2] fix double completion of timed out commands Josef Bacik
@ 2019-10-21 19:56 ` Josef Bacik
2019-10-21 19:56 ` [PATCH 2/2] nbd: handle racing with error'ed out commands Josef Bacik
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Josef Bacik @ 2019-10-21 19:56 UTC (permalink / raw)
To: axboe, nbd, linux-block, kernel-team, mchristi
We already do this for the most part, except in timeout and clear_req.
For the timeout case we take the lock after we grab a ref on the config,
but that isn't really necessary because we're safe to touch the cmd at
this point, so just move the order around.
For the clear_req cause this is initiated by the user, so again is safe.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
drivers/block/nbd.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index a8e3815295fe..8fb8913074b8 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -368,17 +368,16 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
struct nbd_device *nbd = cmd->nbd;
struct nbd_config *config;
+ if (!mutex_trylock(&cmd->lock))
+ return BLK_EH_RESET_TIMER;
+
if (!refcount_inc_not_zero(&nbd->config_refs)) {
cmd->status = BLK_STS_TIMEOUT;
+ mutex_unlock(&cmd->lock);
goto done;
}
config = nbd->config;
- if (!mutex_trylock(&cmd->lock)) {
- nbd_config_put(nbd);
- return BLK_EH_RESET_TIMER;
- }
-
if (config->num_connections > 1) {
dev_err_ratelimited(nbd_to_dev(nbd),
"Connection timed out, retrying (%d/%d alive)\n",
@@ -775,7 +774,10 @@ static bool nbd_clear_req(struct request *req, void *data, bool reserved)
{
struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
+ mutex_lock(&cmd->lock);
cmd->status = BLK_STS_IOERR;
+ mutex_unlock(&cmd->lock);
+
blk_mq_complete_request(req);
return true;
}
--
2.21.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] nbd: handle racing with error'ed out commands
2019-10-21 19:56 [PATCH 0/2] fix double completion of timed out commands Josef Bacik
2019-10-21 19:56 ` [PATCH 1/2] nbd: protect cmd->status with cmd->lock Josef Bacik
@ 2019-10-21 19:56 ` Josef Bacik
2019-10-21 21:43 ` [PATCH 0/2] fix double completion of timed " Mike Christie
2019-10-25 20:20 ` Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Josef Bacik @ 2019-10-21 19:56 UTC (permalink / raw)
To: axboe, nbd, linux-block, kernel-team, mchristi
We hit the following warning in production
print_req_error: I/O error, dev nbd0, sector 7213934408 flags 80700
------------[ cut here ]------------
refcount_t: underflow; use-after-free.
WARNING: CPU: 25 PID: 32407 at lib/refcount.c:190 refcount_sub_and_test_checked+0x53/0x60
Workqueue: knbd-recv recv_work [nbd]
RIP: 0010:refcount_sub_and_test_checked+0x53/0x60
Call Trace:
blk_mq_free_request+0xb7/0xf0
blk_mq_complete_request+0x62/0xf0
recv_work+0x29/0xa1 [nbd]
process_one_work+0x1f5/0x3f0
worker_thread+0x2d/0x3d0
? rescuer_thread+0x340/0x340
kthread+0x111/0x130
? kthread_create_on_node+0x60/0x60
ret_from_fork+0x1f/0x30
---[ end trace b079c3c67f98bb7c ]---
This was preceded by us timing out everything and shutting down the
sockets for the device. The problem is we had a request in the queue at
the same time, so we completed the request twice. This can actually
happen in a lot of cases, we fail to get a ref on our config, we only
have one connection and just error out the command, etc.
Fix this by checking cmd->status in nbd_read_stat. We only change this
under the cmd->lock, so we are safe to check this here and see if we've
already error'ed this command out, which would indicate that we've
completed it as well.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
drivers/block/nbd.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8fb8913074b8..e9f5d4e476e7 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -693,6 +693,12 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
ret = -ENOENT;
goto out;
}
+ if (cmd->status != BLK_STS_OK) {
+ dev_err(disk_to_dev(nbd->disk), "Command already handled %p\n",
+ req);
+ ret = -ENOENT;
+ goto out;
+ }
if (test_bit(NBD_CMD_REQUEUED, &cmd->flags)) {
dev_err(disk_to_dev(nbd->disk), "Raced with timeout on req %p\n",
req);
--
2.21.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH 0/2] fix double completion of timed out commands
2019-10-21 19:56 [PATCH 0/2] fix double completion of timed out commands Josef Bacik
2019-10-21 19:56 ` [PATCH 1/2] nbd: protect cmd->status with cmd->lock Josef Bacik
2019-10-21 19:56 ` [PATCH 2/2] nbd: handle racing with error'ed out commands Josef Bacik
@ 2019-10-21 21:43 ` Mike Christie
2019-10-25 20:20 ` Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Mike Christie @ 2019-10-21 21:43 UTC (permalink / raw)
To: Josef Bacik, axboe, nbd, linux-block, kernel-team
On 10/21/2019 02:56 PM, Josef Bacik wrote:
> We noticed a problem where NBD sometimes double completes the same request when
> things go wrong and we time out the request. If the other side goes out to
> lunch but happens to reply just as we're timing out the requests we can end up
> with a double completion on the request.
>
> We already keep track of the command status, we just need to make sure we
> protect all cases where we set cmd->status with the cmd->lock, which is patch
> #1. Patch #2 is the fix for the problem, which catches the case where we race
> with the timeout handler and the reply handler. Thanks,
>
Patches look ok and tested ok for me.
Reviewed-by: Mike Christie <mchristi@redhat.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 0/2] fix double completion of timed out commands
2019-10-21 19:56 [PATCH 0/2] fix double completion of timed out commands Josef Bacik
` (2 preceding siblings ...)
2019-10-21 21:43 ` [PATCH 0/2] fix double completion of timed " Mike Christie
@ 2019-10-25 20:20 ` Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2019-10-25 20:20 UTC (permalink / raw)
To: Josef Bacik, nbd, linux-block, kernel-team, mchristi
On 10/21/19 1:56 PM, Josef Bacik wrote:
> We noticed a problem where NBD sometimes double completes the same request when
> things go wrong and we time out the request. If the other side goes out to
> lunch but happens to reply just as we're timing out the requests we can end up
> with a double completion on the request.
>
> We already keep track of the command status, we just need to make sure we
> protect all cases where we set cmd->status with the cmd->lock, which is patch
> #1. Patch #2 is the fix for the problem, which catches the case where we race
> with the timeout handler and the reply handler. Thanks,
Applied, thanks.
--
Jens Axboe
^ permalink raw reply [flat|nested] 5+ messages in thread