ublk_drv: cancel device even though disk isn't up
authorMing Lei <ming.lei@redhat.com>
Sat, 30 Jul 2022 09:27:47 +0000 (17:27 +0800)
committerJens Axboe <axboe@kernel.dk>
Wed, 3 Aug 2022 03:13:40 +0000 (21:13 -0600)
Each ublk queue is started before adding disk, we have to cancel queues in
ublk_stop_dev() so that ubq daemon can be exited, otherwise DEL_DEV command
may hang forever.

Also avoid to cancel queues two times by checking if queue is ready,
otherwise use-after-free on io_uring may be triggered because ublk_stop_dev
is called by ublk_remove() too.

Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20220730092750.1118167-2-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/ublk_drv.c

index 3f19069..7ece4c2 100644 (file)
@@ -788,16 +788,27 @@ static void ublk_daemon_monitor_work(struct work_struct *work)
                                UBLK_DAEMON_MONITOR_PERIOD);
 }
 
+static inline bool ublk_queue_ready(struct ublk_queue *ubq)
+{
+       return ubq->nr_io_ready == ubq->q_depth;
+}
+
 static void ublk_cancel_queue(struct ublk_queue *ubq)
 {
        int i;
 
+       if (!ublk_queue_ready(ubq))
+               return;
+
        for (i = 0; i < ubq->q_depth; i++) {
                struct ublk_io *io = &ubq->ios[i];
 
                if (io->flags & UBLK_IO_FLAG_ACTIVE)
                        io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, 0);
        }
+
+       /* all io commands are canceled */
+       ubq->nr_io_ready = 0;
 }
 
 /* Cancel all pending commands, must be called after del_gendisk() returns */
@@ -818,19 +829,14 @@ static void ublk_stop_dev(struct ublk_device *ub)
        del_gendisk(ub->ub_disk);
        ub->dev_info.state = UBLK_S_DEV_DEAD;
        ub->dev_info.ublksrv_pid = -1;
-       ublk_cancel_dev(ub);
        put_disk(ub->ub_disk);
        ub->ub_disk = NULL;
  unlock:
+       ublk_cancel_dev(ub);
        mutex_unlock(&ub->mutex);
        cancel_delayed_work_sync(&ub->monitor_work);
 }
 
-static inline bool ublk_queue_ready(struct ublk_queue *ubq)
-{
-       return ubq->nr_io_ready == ubq->q_depth;
-}
-
 /* device can only be started after all IOs are ready */
 static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq)
 {