Commit 0c9d5ccd authored by Jens Axboe's avatar Jens Axboe
Browse files

io-wq: add support for uncancellable work



Not all work can be cancelled, some of it we may need to guarantee
that it runs to completion. Allow the caller to set IO_WQ_WORK_NO_CANCEL
on work that must not be cancelled. Note that the caller work function
must also check for IO_WQ_WORK_NO_CANCEL on work that is marked
IO_WQ_WORK_CANCEL.

Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 6e802a4b
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -456,6 +456,10 @@ next:
		}
		if (!worker->creds)
			worker->creds = override_creds(wq->creds);
		/*
		 * OK to set IO_WQ_WORK_CANCEL even for uncancellable work,
		 * the worker function will do the right thing.
		 */
		if (test_bit(IO_WQ_BIT_CANCEL, &wq->state))
			work->flags |= IO_WQ_WORK_CANCEL;
		if (worker->mm)
@@ -828,6 +832,7 @@ static bool io_work_cancel(struct io_worker *worker, void *cancel_data)
	 */
	spin_lock_irqsave(&worker->lock, flags);
	if (worker->cur_work &&
	    !(worker->cur_work->flags & IO_WQ_WORK_NO_CANCEL) &&
	    data->cancel(worker->cur_work, data->caller_data)) {
		send_sig(SIGINT, worker->task, 1);
		ret = true;
@@ -902,7 +907,8 @@ static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
		return false;

	spin_lock_irqsave(&worker->lock, flags);
	if (worker->cur_work == work) {
	if (worker->cur_work == work &&
	    !(worker->cur_work->flags & IO_WQ_WORK_NO_CANCEL)) {
		send_sig(SIGINT, worker->task, 1);
		ret = true;
	}
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ enum {
	IO_WQ_WORK_UNBOUND	= 32,
	IO_WQ_WORK_INTERNAL	= 64,
	IO_WQ_WORK_CB		= 128,
	IO_WQ_WORK_NO_CANCEL	= 256,

	IO_WQ_HASH_SHIFT	= 24,	/* upper 8 bits are used for hash key */
};
+4 −1
Original line number Diff line number Diff line
@@ -3460,8 +3460,11 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
	struct io_kiocb *nxt = NULL;
	int ret = 0;

	if (work->flags & IO_WQ_WORK_CANCEL)
	/* if NO_CANCEL is set, we must still run the work */
	if ((work->flags & (IO_WQ_WORK_CANCEL|IO_WQ_WORK_NO_CANCEL)) ==
				IO_WQ_WORK_CANCEL) {
		ret = -ECANCELED;
	}

	if (!ret) {
		req->has_user = (work->flags & IO_WQ_WORK_HAS_MM) != 0;