Commit 66d3af8d authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe
Browse files

ublk: check list membership before cancelling batch fetch command



Add !list_empty(&fcmd->node) check in ublk_batch_cancel_cmd() to ensure
the fcmd hasn't already been removed from the list. Once an fcmd is
removed from the list, it's considered claimed by whoever removed it
and will be freed by that path.

Meantime switch to list_del_init() for deleting it from list.

Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 373df2c0
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -738,7 +738,7 @@ static void ublk_batch_deinit_fetch_buf(struct ublk_queue *ubq,
					int res)
{
	spin_lock(&ubq->evts_lock);
	list_del(&fcmd->node);
	list_del_init(&fcmd->node);
	WARN_ON_ONCE(fcmd != ubq->active_fcmd);
	__ublk_release_fcmd(ubq);
	spin_unlock(&ubq->evts_lock);
@@ -2693,6 +2693,16 @@ static void ublk_cancel_cmd(struct ublk_queue *ubq, unsigned tag,
		io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, issue_flags);
}

/*
 * Cancel a batch fetch command if it hasn't been claimed by another path.
 *
 * An fcmd can only be cancelled if:
 * 1. It's not the active_fcmd (which is currently being processed)
 * 2. It's still on the list (!list_empty check) - once removed from the list,
 *    the fcmd is considered claimed and will be freed by whoever removed it
 *
 * Use list_del_init() so subsequent list_empty() checks work correctly.
 */
static void ublk_batch_cancel_cmd(struct ublk_queue *ubq,
				  struct ublk_batch_fetch_cmd *fcmd,
				  unsigned int issue_flags)
@@ -2700,9 +2710,9 @@ static void ublk_batch_cancel_cmd(struct ublk_queue *ubq,
	bool done;

	spin_lock(&ubq->evts_lock);
	done = (READ_ONCE(ubq->active_fcmd) != fcmd);
	done = (READ_ONCE(ubq->active_fcmd) != fcmd) && !list_empty(&fcmd->node);
	if (done)
		list_del(&fcmd->node);
		list_del_init(&fcmd->node);
	spin_unlock(&ubq->evts_lock);

	if (done) {