Commit 509b5b11 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'io_uring-6.19-20260102' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull io_uring fixes from Jens Axboe:

 - Removed dead argument length for io_uring_validate_mmap_request()

 - Use GFP_NOWAIT for overflow CQEs on legacy ring setups rather than
   GFP_ATOMIC, which makes it play nicer with memcg limits

 - Fix a potential circular locking issue with tctx node removal and
   exec based cancelations

* tag 'io_uring-6.19-20260102' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux:
  io_uring/memmap: drop unused sz param in io_uring_validate_mmap_request()
  io_uring/tctx: add separate lock for list of tctx's in ctx
  io_uring: use GFP_NOWAIT for overflow CQEs on legacy rings
parents 71b62ed6 70eafc74
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -424,11 +424,17 @@ struct io_ring_ctx {
	struct user_struct		*user;
	struct mm_struct		*mm_account;

	/*
	 * List of tctx nodes for this ctx, protected by tctx_lock. For
	 * cancelation purposes, nests under uring_lock.
	 */
	struct list_head		tctx_list;
	struct mutex			tctx_lock;

	/* ctx exit and cancelation */
	struct llist_head		fallback_llist;
	struct delayed_work		fallback_work;
	struct work_struct		exit_work;
	struct list_head		tctx_list;
	struct completion		ref_comp;

	/* io-wq management, e.g. thread count */
+5 −0
Original line number Diff line number Diff line
@@ -184,7 +184,9 @@ static int __io_async_cancel(struct io_cancel_data *cd,
	} while (1);

	/* slow path, try all io-wq's */
	__set_current_state(TASK_RUNNING);
	io_ring_submit_lock(ctx, issue_flags);
	mutex_lock(&ctx->tctx_lock);
	ret = -ENOENT;
	list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
		ret = io_async_cancel_one(node->task->io_uring, cd);
@@ -194,6 +196,7 @@ static int __io_async_cancel(struct io_cancel_data *cd,
			nr++;
		}
	}
	mutex_unlock(&ctx->tctx_lock);
	io_ring_submit_unlock(ctx, issue_flags);
	return all ? nr : ret;
}
@@ -484,6 +487,7 @@ static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
	bool ret = false;

	mutex_lock(&ctx->uring_lock);
	mutex_lock(&ctx->tctx_lock);
	list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
		struct io_uring_task *tctx = node->task->io_uring;

@@ -496,6 +500,7 @@ static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
		cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_ctx_cb, ctx, true);
		ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
	}
	mutex_unlock(&ctx->tctx_lock);
	mutex_unlock(&ctx->uring_lock);

	return ret;
+6 −1
Original line number Diff line number Diff line
@@ -340,6 +340,7 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
	INIT_LIST_HEAD(&ctx->ltimeout_list);
	init_llist_head(&ctx->work_llist);
	INIT_LIST_HEAD(&ctx->tctx_list);
	mutex_init(&ctx->tctx_lock);
	ctx->submit_state.free_list.next = NULL;
	INIT_HLIST_HEAD(&ctx->waitid_list);
	xa_init_flags(&ctx->zcrx_ctxs, XA_FLAGS_ALLOC);
@@ -864,7 +865,7 @@ static __cold bool io_cqe_overflow_locked(struct io_ring_ctx *ctx,
{
	struct io_overflow_cqe *ocqe;

	ocqe = io_alloc_ocqe(ctx, cqe, big_cqe, GFP_ATOMIC);
	ocqe = io_alloc_ocqe(ctx, cqe, big_cqe, GFP_NOWAIT);
	return io_cqring_add_overflow(ctx, ocqe);
}

@@ -3045,6 +3046,7 @@ static __cold void io_ring_exit_work(struct work_struct *work)
	exit.ctx = ctx;

	mutex_lock(&ctx->uring_lock);
	mutex_lock(&ctx->tctx_lock);
	while (!list_empty(&ctx->tctx_list)) {
		WARN_ON_ONCE(time_after(jiffies, timeout));

@@ -3056,6 +3058,7 @@ static __cold void io_ring_exit_work(struct work_struct *work)
		if (WARN_ON_ONCE(ret))
			continue;

		mutex_unlock(&ctx->tctx_lock);
		mutex_unlock(&ctx->uring_lock);
		/*
		 * See comment above for
@@ -3064,7 +3067,9 @@ static __cold void io_ring_exit_work(struct work_struct *work)
		 */
		wait_for_completion_interruptible(&exit.completion);
		mutex_lock(&ctx->uring_lock);
		mutex_lock(&ctx->tctx_lock);
	}
	mutex_unlock(&ctx->tctx_lock);
	mutex_unlock(&ctx->uring_lock);
	spin_lock(&ctx->completion_lock);
	spin_unlock(&ctx->completion_lock);
+4 −5
Original line number Diff line number Diff line
@@ -268,8 +268,7 @@ static void *io_region_validate_mmap(struct io_ring_ctx *ctx,
	return io_region_get_ptr(mr);
}

static void *io_uring_validate_mmap_request(struct file *file, loff_t pgoff,
					    size_t sz)
static void *io_uring_validate_mmap_request(struct file *file, loff_t pgoff)
{
	struct io_ring_ctx *ctx = file->private_data;
	struct io_mapped_region *region;
@@ -304,7 +303,7 @@ __cold int io_uring_mmap(struct file *file, struct vm_area_struct *vma)

	guard(mutex)(&ctx->mmap_lock);

	ptr = io_uring_validate_mmap_request(file, vma->vm_pgoff, sz);
	ptr = io_uring_validate_mmap_request(file, vma->vm_pgoff);
	if (IS_ERR(ptr))
		return PTR_ERR(ptr);

@@ -336,7 +335,7 @@ unsigned long io_uring_get_unmapped_area(struct file *filp, unsigned long addr,

	guard(mutex)(&ctx->mmap_lock);

	ptr = io_uring_validate_mmap_request(filp, pgoff, len);
	ptr = io_uring_validate_mmap_request(filp, pgoff);
	if (IS_ERR(ptr))
		return -ENOMEM;

@@ -386,7 +385,7 @@ unsigned long io_uring_get_unmapped_area(struct file *file, unsigned long addr,

	guard(mutex)(&ctx->mmap_lock);

	ptr = io_uring_validate_mmap_request(file, pgoff, len);
	ptr = io_uring_validate_mmap_request(file, pgoff);
	if (IS_ERR(ptr))
		return PTR_ERR(ptr);

+2 −0
Original line number Diff line number Diff line
@@ -320,6 +320,7 @@ static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
		return 0;

	/* now propagate the restriction to all registered users */
	mutex_lock(&ctx->tctx_lock);
	list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
		tctx = node->task->io_uring;
		if (WARN_ON_ONCE(!tctx->io_wq))
@@ -330,6 +331,7 @@ static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
		/* ignore errors, it always returns zero anyway */
		(void)io_wq_max_workers(tctx->io_wq, new_count);
	}
	mutex_unlock(&ctx->tctx_lock);
	return 0;
err:
	if (sqd) {
Loading