Skip to content

Commit

Permalink
ublk: make sure ubq->canceling is set when queue is frozen
Browse files Browse the repository at this point in the history
Now ublk driver depends on `ubq->canceling` for deciding if the request
can be dispatched via uring_cmd & io_uring_cmd_complete_in_task().

Once ubq->canceling is set, the uring_cmd can be done via ublk_cancel_cmd()
and io_uring_cmd_done().

So set ubq->canceling when queue is frozen, this way makes sure that the
flag can be observed from ublk_queue_rq() reliably, and avoids
use-after-free on uring_cmd.

Fixes: 216c8f5 ("ublk: replace monitor with cancelable uring_cmd")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250327095123.179113-2-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
Ming Lei authored and Jens Axboe committed Mar 28, 2025
1 parent 0449173 commit 8741d07
Showing 1 changed file with 29 additions and 10 deletions.
39 changes: 29 additions & 10 deletions drivers/block/ublk_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,17 +1446,27 @@ static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq)
}
}

/* Must be called when queue is frozen */
static bool ublk_mark_queue_canceling(struct ublk_queue *ubq)
{
bool canceled;

spin_lock(&ubq->cancel_lock);
canceled = ubq->canceling;
if (!canceled)
ubq->canceling = true;
spin_unlock(&ubq->cancel_lock);

return canceled;
}

static bool ublk_abort_requests(struct ublk_device *ub, struct ublk_queue *ubq)
{
bool was_canceled = ubq->canceling;
struct gendisk *disk;

spin_lock(&ubq->cancel_lock);
if (ubq->canceling) {
spin_unlock(&ubq->cancel_lock);
if (was_canceled)
return false;
}
ubq->canceling = true;
spin_unlock(&ubq->cancel_lock);

spin_lock(&ub->lock);
disk = ub->ub_disk;
Expand All @@ -1468,14 +1478,23 @@ static bool ublk_abort_requests(struct ublk_device *ub, struct ublk_queue *ubq)
if (!disk)
return false;

/* Now we are serialized with ublk_queue_rq() */
/*
* Now we are serialized with ublk_queue_rq()
*
* Make sure that ubq->canceling is set when queue is frozen,
* because ublk_queue_rq() has to rely on this flag for avoiding to
* touch completed uring_cmd
*/
blk_mq_quiesce_queue(disk->queue);
/* abort queue is for making forward progress */
ublk_abort_queue(ub, ubq);
was_canceled = ublk_mark_queue_canceling(ubq);
if (!was_canceled) {
/* abort queue is for making forward progress */
ublk_abort_queue(ub, ubq);
}
blk_mq_unquiesce_queue(disk->queue);
put_device(disk_to_dev(disk));

return true;
return !was_canceled;
}

static void ublk_cancel_cmd(struct ublk_queue *ubq, struct ublk_io *io,
Expand Down

0 comments on commit 8741d07

Please sign in to comment.