Merge: io_uring: pull in fixes from upstream

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/2000

With these patches (and the one from MR!1989), all liburing tests pass (head commit 3756b3de4cf2e16a5a727c9feefafd7b8c026042).

JIRA: https://issues.redhat.com/browse/RHEL-140845

Signed-off-by: Jeff Moyer <jmoyer@redhat.com>

Approved-by: Brian Foster <bfoster@redhat.com>
Approved-by: Ming Lei <ming.lei@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
CKI KWF Bot
2026-02-05 12:59:41 +00:00
26 changed files with 208 additions and 173 deletions
+3
View File
@@ -7,6 +7,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/blk-integrity.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mpage.h> #include <linux/mpage.h>
#include <linux/uio.h> #include <linux/uio.h>
@@ -684,6 +685,8 @@ static int blkdev_open(struct inode *inode, struct file *filp)
if (bdev_can_atomic_write(bdev)) if (bdev_can_atomic_write(bdev))
filp->f_mode |= FMODE_CAN_ATOMIC_WRITE; filp->f_mode |= FMODE_CAN_ATOMIC_WRITE;
if (blk_get_integrity(bdev->bd_disk))
filp->f_mode |= FMODE_HAS_METADATA;
ret = bdev_open(bdev, mode, filp->private_data, NULL, filp); ret = bdev_open(bdev, mode, filp->private_data, NULL, filp);
if (ret) if (ret)
+2 -1
View File
@@ -147,7 +147,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
/* Expect random access pattern */ /* Expect random access pattern */
#define FMODE_RANDOM ((__force fmode_t)(1 << 12)) #define FMODE_RANDOM ((__force fmode_t)(1 << 12))
/* FMODE_* bit 13 */ /* Supports IOCB_HAS_METADATA */
#define FMODE_HAS_METADATA ((__force fmode_t)(1 << 13))
/* File is opened with O_PATH; almost nothing can be done with it */ /* File is opened with O_PATH; almost nothing can be done with it */
#define FMODE_PATH ((__force fmode_t)(1 << 14)) #define FMODE_PATH ((__force fmode_t)(1 << 14))
-3
View File
@@ -415,9 +415,6 @@ struct io_ring_ctx {
struct callback_head poll_wq_task_work; struct callback_head poll_wq_task_work;
struct list_head defer_list; struct list_head defer_list;
struct io_alloc_cache msg_cache;
spinlock_t msg_lock;
#ifdef CONFIG_NET_RX_BUSY_POLL #ifdef CONFIG_NET_RX_BUSY_POLL
struct list_head napi_list; /* track busy poll napi_id */ struct list_head napi_list; /* track busy poll napi_id */
spinlock_t napi_lock; /* napi_list lock */ spinlock_t napi_lock; /* napi_list lock */
+1 -1
View File
@@ -50,7 +50,7 @@ struct io_uring_sqe {
}; };
__u32 len; /* buffer size or number of iovecs */ __u32 len; /* buffer size or number of iovecs */
union { union {
__kernel_rwf_t rw_flags; __u32 rw_flags;
__u32 fsync_flags; __u32 fsync_flags;
__u16 poll_events; /* compatibility */ __u16 poll_events; /* compatibility */
__u32 poll32_events; /* word-reversed for BE */ __u32 poll32_events; /* word-reversed for BE */
+2 -1
View File
@@ -11,9 +11,10 @@ obj-$(CONFIG_IO_URING) += io_uring.o opdef.o kbuf.o rsrc.o notif.o \
eventfd.o uring_cmd.o openclose.o \ eventfd.o uring_cmd.o openclose.o \
sqpoll.o xattr.o nop.o fs.o splice.o \ sqpoll.o xattr.o nop.o fs.o splice.o \
sync.o msg_ring.o advise.o openclose.o \ sync.o msg_ring.o advise.o openclose.o \
epoll.o statx.o timeout.o fdinfo.o \ epoll.o statx.o timeout.o \
cancel.o waitid.o register.o \ cancel.o waitid.o register.o \
truncate.o memmap.o alloc_cache.o truncate.o memmap.o alloc_cache.o
obj-$(CONFIG_IO_WQ) += io-wq.o obj-$(CONFIG_IO_WQ) += io-wq.o
obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_NET_RX_BUSY_POLL) += napi.o obj-$(CONFIG_NET_RX_BUSY_POLL) += napi.o
obj-$(CONFIG_PROC_FS) += fdinfo.o
+13 -45
View File
@@ -15,37 +15,6 @@
#include "cancel.h" #include "cancel.h"
#include "rsrc.h" #include "rsrc.h"
#ifdef CONFIG_PROC_FS
static __cold int io_uring_show_cred(struct seq_file *m, unsigned int id,
const struct cred *cred)
{
struct user_namespace *uns = seq_user_ns(m);
struct group_info *gi;
kernel_cap_t cap;
int g;
seq_printf(m, "%5d\n", id);
seq_put_decimal_ull(m, "\tUid:\t", from_kuid_munged(uns, cred->uid));
seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->euid));
seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->suid));
seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->fsuid));
seq_put_decimal_ull(m, "\n\tGid:\t", from_kgid_munged(uns, cred->gid));
seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->egid));
seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->sgid));
seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->fsgid));
seq_puts(m, "\n\tGroups:\t");
gi = cred->group_info;
for (g = 0; g < gi->ngroups; g++) {
seq_put_decimal_ull(m, g ? " " : "",
from_kgid_munged(uns, gi->gid[g]));
}
seq_puts(m, "\n\tCapEff:\t");
cap = cred->cap_effective;
seq_put_hex_ll(m, NULL, cap.val, 16);
seq_putc(m, '\n');
return 0;
}
#ifdef CONFIG_NET_RX_BUSY_POLL #ifdef CONFIG_NET_RX_BUSY_POLL
static __cold void common_tracking_show_fdinfo(struct io_ring_ctx *ctx, static __cold void common_tracking_show_fdinfo(struct io_ring_ctx *ctx,
struct seq_file *m, struct seq_file *m,
@@ -90,7 +59,6 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
{ {
struct io_overflow_cqe *ocqe; struct io_overflow_cqe *ocqe;
struct io_rings *r = ctx->rings; struct io_rings *r = ctx->rings;
struct rusage sq_usage;
unsigned int sq_mask = ctx->sq_entries - 1, cq_mask = ctx->cq_entries - 1; unsigned int sq_mask = ctx->sq_entries - 1, cq_mask = ctx->cq_entries - 1;
unsigned int sq_head = READ_ONCE(r->sq.head); unsigned int sq_head = READ_ONCE(r->sq.head);
unsigned int sq_tail = READ_ONCE(r->sq.tail); unsigned int sq_tail = READ_ONCE(r->sq.tail);
@@ -172,18 +140,27 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
if (ctx->flags & IORING_SETUP_SQPOLL) { if (ctx->flags & IORING_SETUP_SQPOLL) {
struct io_sq_data *sq = ctx->sq_data; struct io_sq_data *sq = ctx->sq_data;
struct task_struct *tsk;
rcu_read_lock();
tsk = rcu_dereference(sq->thread);
/* /*
* sq->thread might be NULL if we raced with the sqpoll * sq->thread might be NULL if we raced with the sqpoll
* thread termination. * thread termination.
*/ */
if (sq->thread) { if (tsk) {
u64 usec;
get_task_struct(tsk);
rcu_read_unlock();
usec = io_sq_cpu_usec(tsk);
put_task_struct(tsk);
sq_pid = sq->task_pid; sq_pid = sq->task_pid;
sq_cpu = sq->sq_cpu; sq_cpu = sq->sq_cpu;
getrusage(sq->thread, RUSAGE_SELF, &sq_usage); sq_total_time = usec;
sq_total_time = (sq_usage.ru_stime.tv_sec * 1000000
+ sq_usage.ru_stime.tv_usec);
sq_work_time = sq->work_time; sq_work_time = sq->work_time;
} else {
rcu_read_unlock();
} }
} }
@@ -214,14 +191,6 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
else else
seq_printf(m, "%5u: <none>\n", i); seq_printf(m, "%5u: <none>\n", i);
} }
if (!xa_empty(&ctx->personalities)) {
unsigned long index;
const struct cred *cred;
seq_printf(m, "Personalities:\n");
xa_for_each(&ctx->personalities, index, cred)
io_uring_show_cred(m, index, cred);
}
seq_puts(m, "PollList:\n"); seq_puts(m, "PollList:\n");
for (i = 0; i < (1U << ctx->cancel_table.hash_bits); i++) { for (i = 0; i < (1U << ctx->cancel_table.hash_bits); i++) {
@@ -264,4 +233,3 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *file)
mutex_unlock(&ctx->uring_lock); mutex_unlock(&ctx->uring_lock);
} }
} }
#endif
+1 -1
View File
@@ -57,7 +57,7 @@ void io_free_file_tables(struct io_ring_ctx *ctx, struct io_file_table *table)
static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file, static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
u32 slot_index) u32 slot_index)
__must_hold(&req->ctx->uring_lock) __must_hold(&ctx->uring_lock)
{ {
struct io_rsrc_node *node; struct io_rsrc_node *node;
+3 -3
View File
@@ -916,11 +916,11 @@ static bool io_wq_for_each_worker(struct io_wq *wq,
void *data) void *data)
{ {
for (int i = 0; i < IO_WQ_ACCT_NR; i++) { for (int i = 0; i < IO_WQ_ACCT_NR; i++) {
if (!io_acct_for_each_worker(&wq->acct[i], func, data)) if (io_acct_for_each_worker(&wq->acct[i], func, data))
return false; return true;
} }
return true; return false;
} }
static bool io_wq_worker_wake(struct io_worker *worker, void *data) static bool io_wq_worker_wake(struct io_worker *worker, void *data)
+15 -12
View File
@@ -290,7 +290,6 @@ static void io_free_alloc_caches(struct io_ring_ctx *ctx)
io_alloc_cache_free(&ctx->netmsg_cache, io_netmsg_cache_free); io_alloc_cache_free(&ctx->netmsg_cache, io_netmsg_cache_free);
io_alloc_cache_free(&ctx->rw_cache, io_rw_cache_free); io_alloc_cache_free(&ctx->rw_cache, io_rw_cache_free);
io_alloc_cache_free(&ctx->cmd_cache, io_cmd_cache_free); io_alloc_cache_free(&ctx->cmd_cache, io_cmd_cache_free);
io_alloc_cache_free(&ctx->msg_cache, kfree);
io_futex_cache_free(ctx); io_futex_cache_free(ctx);
io_rsrc_cache_free(ctx); io_rsrc_cache_free(ctx);
} }
@@ -337,9 +336,6 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
ret |= io_alloc_cache_init(&ctx->cmd_cache, IO_ALLOC_CACHE_MAX, ret |= io_alloc_cache_init(&ctx->cmd_cache, IO_ALLOC_CACHE_MAX,
sizeof(struct io_async_cmd), sizeof(struct io_async_cmd),
sizeof(struct io_async_cmd)); sizeof(struct io_async_cmd));
spin_lock_init(&ctx->msg_lock);
ret |= io_alloc_cache_init(&ctx->msg_cache, IO_ALLOC_CACHE_MAX,
sizeof(struct io_kiocb), 0);
ret |= io_futex_cache_init(ctx); ret |= io_futex_cache_init(ctx);
ret |= io_rsrc_cache_init(ctx); ret |= io_rsrc_cache_init(ctx);
if (ret) if (ret)
@@ -1359,8 +1355,10 @@ static void io_req_task_cancel(struct io_kiocb *req, io_tw_token_t tw)
void io_req_task_submit(struct io_kiocb *req, io_tw_token_t tw) void io_req_task_submit(struct io_kiocb *req, io_tw_token_t tw)
{ {
io_tw_lock(req->ctx, tw); struct io_ring_ctx *ctx = req->ctx;
if (unlikely(io_should_terminate_tw()))
io_tw_lock(ctx, tw);
if (unlikely(io_should_terminate_tw(ctx)))
io_req_defer_failed(req, -EFAULT); io_req_defer_failed(req, -EFAULT);
else if (req->flags & REQ_F_FORCE_ASYNC) else if (req->flags & REQ_F_FORCE_ASYNC)
io_queue_iowq(req); io_queue_iowq(req);
@@ -2444,6 +2442,9 @@ static enum hrtimer_restart io_cqring_min_timer_wakeup(struct hrtimer *timer)
goto out_wake; goto out_wake;
} }
/* any generated CQE posted past this time should wake us up */
iowq->cq_tail = iowq->cq_min_tail;
hrtimer_update_function(&iowq->t, io_cqring_timer_wakeup); hrtimer_update_function(&iowq->t, io_cqring_timer_wakeup);
hrtimer_set_expires(timer, iowq->timeout); hrtimer_set_expires(timer, iowq->timeout);
return HRTIMER_RESTART; return HRTIMER_RESTART;
@@ -2901,7 +2902,7 @@ static __cold void io_ring_exit_work(struct work_struct *work)
struct task_struct *tsk; struct task_struct *tsk;
io_sq_thread_park(sqd); io_sq_thread_park(sqd);
tsk = sqd->thread; tsk = sqpoll_task_locked(sqd);
if (tsk && tsk->io_uring && tsk->io_uring->io_wq) if (tsk && tsk->io_uring && tsk->io_uring->io_wq)
io_wq_cancel_cb(tsk->io_uring->io_wq, io_wq_cancel_cb(tsk->io_uring->io_wq,
io_cancel_ctx_cb, ctx, true); io_cancel_ctx_cb, ctx, true);
@@ -3138,7 +3139,7 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
s64 inflight; s64 inflight;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
WARN_ON_ONCE(sqd && sqd->thread != current); WARN_ON_ONCE(sqd && sqpoll_task_locked(sqd) != current);
if (!current->io_uring) if (!current->io_uring)
return; return;
@@ -3504,10 +3505,6 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx,
if (!(ctx->flags & IORING_SETUP_NO_SQARRAY)) if (!(ctx->flags & IORING_SETUP_NO_SQARRAY))
ctx->sq_array = (u32 *)((char *)rings + sq_array_offset); ctx->sq_array = (u32 *)((char *)rings + sq_array_offset);
rings->sq_ring_mask = p->sq_entries - 1;
rings->cq_ring_mask = p->cq_entries - 1;
rings->sq_ring_entries = p->sq_entries;
rings->cq_ring_entries = p->cq_entries;
if (p->flags & IORING_SETUP_SQE128) if (p->flags & IORING_SETUP_SQE128)
size = array_size(2 * sizeof(struct io_uring_sqe), p->sq_entries); size = array_size(2 * sizeof(struct io_uring_sqe), p->sq_entries);
@@ -3530,6 +3527,12 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx,
return ret; return ret;
} }
ctx->sq_sqes = io_region_get_ptr(&ctx->sq_region); ctx->sq_sqes = io_region_get_ptr(&ctx->sq_region);
memset(rings, 0, sizeof(*rings));
WRITE_ONCE(rings->sq_ring_mask, ctx->sq_entries - 1);
WRITE_ONCE(rings->cq_ring_mask, ctx->cq_entries - 1);
WRITE_ONCE(rings->sq_ring_entries, ctx->sq_entries);
WRITE_ONCE(rings->cq_ring_entries, ctx->cq_entries);
return 0; return 0;
} }
+2 -2
View File
@@ -464,9 +464,9 @@ static inline bool io_allowed_run_tw(struct io_ring_ctx *ctx)
* 2) PF_KTHREAD is set, in which case the invoker of the task_work is * 2) PF_KTHREAD is set, in which case the invoker of the task_work is
* our fallback task_work. * our fallback task_work.
*/ */
static inline bool io_should_terminate_tw(void) static inline bool io_should_terminate_tw(struct io_ring_ctx *ctx)
{ {
return current->flags & (PF_KTHREAD | PF_EXITING); return (current->flags & (PF_KTHREAD | PF_EXITING)) || percpu_ref_is_dying(&ctx->refs);
} }
static inline void io_req_queue_tw_complete(struct io_kiocb *req, s32 res) static inline void io_req_queue_tw_complete(struct io_kiocb *req, s32 res)
+5 -5
View File
@@ -44,7 +44,7 @@ static bool io_kbuf_inc_commit(struct io_buffer_list *bl, int len)
buf_len -= this_len; buf_len -= this_len;
/* Stop looping for invalid buffer length of 0 */ /* Stop looping for invalid buffer length of 0 */
if (buf_len || !this_len) { if (buf_len || !this_len) {
buf->addr += this_len; buf->addr = READ_ONCE(buf->addr) + this_len;
buf->len = buf_len; buf->len = buf_len;
return false; return false;
} }
@@ -178,8 +178,8 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
*len = buf_len; *len = buf_len;
req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT; req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT;
req->buf_list = bl; req->buf_list = bl;
req->buf_index = buf->bid; req->buf_index = READ_ONCE(buf->bid);
ret = u64_to_user_ptr(buf->addr); ret = u64_to_user_ptr(READ_ONCE(buf->addr));
if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) { if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) {
/* /*
@@ -269,7 +269,7 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg,
if (!arg->max_len) if (!arg->max_len)
arg->max_len = INT_MAX; arg->max_len = INT_MAX;
req->buf_index = buf->bid; req->buf_index = READ_ONCE(buf->bid);
do { do {
u32 len = READ_ONCE(buf->len); u32 len = READ_ONCE(buf->len);
@@ -280,7 +280,7 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg,
buf->len = len; buf->len = len;
} }
iov->iov_base = u64_to_user_ptr(buf->addr); iov->iov_base = u64_to_user_ptr(READ_ONCE(buf->addr));
iov->iov_len = len; iov->iov_len = len;
iov++; iov++;
+1 -1
View File
@@ -134,7 +134,7 @@ static int io_region_pin_pages(struct io_ring_ctx *ctx,
struct io_mapped_region *mr, struct io_mapped_region *mr,
struct io_uring_region_desc *reg) struct io_uring_region_desc *reg)
{ {
unsigned long size = mr->nr_pages << PAGE_SHIFT; unsigned long size = (size_t) mr->nr_pages << PAGE_SHIFT;
struct page **pages; struct page **pages;
int nr_pages; int nr_pages;
+2 -22
View File
@@ -11,7 +11,6 @@
#include "io_uring.h" #include "io_uring.h"
#include "rsrc.h" #include "rsrc.h"
#include "filetable.h" #include "filetable.h"
#include "alloc_cache.h"
#include "msg_ring.h" #include "msg_ring.h"
/* All valid masks for MSG_RING */ /* All valid masks for MSG_RING */
@@ -76,13 +75,7 @@ static void io_msg_tw_complete(struct io_kiocb *req, io_tw_token_t tw)
struct io_ring_ctx *ctx = req->ctx; struct io_ring_ctx *ctx = req->ctx;
io_add_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, req->cqe.flags); io_add_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, req->cqe.flags);
if (spin_trylock(&ctx->msg_lock)) { kfree_rcu(req, rcu_head);
if (io_alloc_cache_put(&ctx->msg_cache, req))
req = NULL;
spin_unlock(&ctx->msg_lock);
}
if (req)
kfree_rcu(req, rcu_head);
percpu_ref_put(&ctx->refs); percpu_ref_put(&ctx->refs);
} }
@@ -104,26 +97,13 @@ static int io_msg_remote_post(struct io_ring_ctx *ctx, struct io_kiocb *req,
return 0; return 0;
} }
static struct io_kiocb *io_msg_get_kiocb(struct io_ring_ctx *ctx)
{
struct io_kiocb *req = NULL;
if (spin_trylock(&ctx->msg_lock)) {
req = io_alloc_cache_get(&ctx->msg_cache);
spin_unlock(&ctx->msg_lock);
if (req)
return req;
}
return kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
}
static int io_msg_data_remote(struct io_ring_ctx *target_ctx, static int io_msg_data_remote(struct io_ring_ctx *target_ctx,
struct io_msg *msg) struct io_msg *msg)
{ {
struct io_kiocb *target; struct io_kiocb *target;
u32 flags = 0; u32 flags = 0;
target = io_msg_get_kiocb(target_ctx); target = kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO) ;
if (unlikely(!target)) if (unlikely(!target))
return -ENOMEM; return -ENOMEM;
+15 -12
View File
@@ -468,6 +468,15 @@ static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret)
return nbufs; return nbufs;
} }
static int io_net_kbuf_recyle(struct io_kiocb *req,
struct io_async_msghdr *kmsg, int len)
{
req->flags |= REQ_F_BL_NO_RECYCLE;
if (req->flags & REQ_F_BUFFERS_COMMIT)
io_kbuf_commit(req, req->buf_list, len, io_bundle_nbufs(kmsg, len));
return IOU_RETRY;
}
static inline bool io_send_finish(struct io_kiocb *req, int *ret, static inline bool io_send_finish(struct io_kiocb *req, int *ret,
struct io_async_msghdr *kmsg, struct io_async_msghdr *kmsg,
unsigned issue_flags) unsigned issue_flags)
@@ -536,8 +545,7 @@ int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
kmsg->msg.msg_controllen = 0; kmsg->msg.msg_controllen = 0;
kmsg->msg.msg_control = NULL; kmsg->msg.msg_control = NULL;
sr->done_io += ret; sr->done_io += ret;
req->flags |= REQ_F_BL_NO_RECYCLE; return io_net_kbuf_recyle(req, kmsg, ret);
return -EAGAIN;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
ret = -EINTR; ret = -EINTR;
@@ -647,8 +655,7 @@ retry_bundle:
sr->len -= ret; sr->len -= ret;
sr->buf += ret; sr->buf += ret;
sr->done_io += ret; sr->done_io += ret;
req->flags |= REQ_F_BL_NO_RECYCLE; return io_net_kbuf_recyle(req, kmsg, ret);
return -EAGAIN;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
ret = -EINTR; ret = -EINTR;
@@ -1020,8 +1027,7 @@ retry_multishot:
} }
if (ret > 0 && io_net_retry(sock, flags)) { if (ret > 0 && io_net_retry(sock, flags)) {
sr->done_io += ret; sr->done_io += ret;
req->flags |= REQ_F_BL_NO_RECYCLE; return io_net_kbuf_recyle(req, kmsg, ret);
return IOU_RETRY;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
ret = -EINTR; ret = -EINTR;
@@ -1158,8 +1164,7 @@ retry_multishot:
sr->len -= ret; sr->len -= ret;
sr->buf += ret; sr->buf += ret;
sr->done_io += ret; sr->done_io += ret;
req->flags |= REQ_F_BL_NO_RECYCLE; return io_net_kbuf_recyle(req, kmsg, ret);
return -EAGAIN;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
ret = -EINTR; ret = -EINTR;
@@ -1377,8 +1382,7 @@ int io_send_zc(struct io_kiocb *req, unsigned int issue_flags)
zc->len -= ret; zc->len -= ret;
zc->buf += ret; zc->buf += ret;
zc->done_io += ret; zc->done_io += ret;
req->flags |= REQ_F_BL_NO_RECYCLE; return io_net_kbuf_recyle(req, kmsg, ret);
return -EAGAIN;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
ret = -EINTR; ret = -EINTR;
@@ -1450,8 +1454,7 @@ int io_sendmsg_zc(struct io_kiocb *req, unsigned int issue_flags)
if (ret > 0 && io_net_retry(sock, flags)) { if (ret > 0 && io_net_retry(sock, flags)) {
sr->done_io += ret; sr->done_io += ret;
req->flags |= REQ_F_BL_NO_RECYCLE; return io_net_kbuf_recyle(req, kmsg, ret);
return -EAGAIN;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
ret = -EINTR; ret = -EINTR;
+1 -1
View File
@@ -85,7 +85,7 @@ static int io_link_skb(struct sk_buff *skb, struct ubuf_info *uarg)
return -EEXIST; return -EEXIST;
prev_nd = container_of(prev_uarg, struct io_notif_data, uarg); prev_nd = container_of(prev_uarg, struct io_notif_data, uarg);
prev_notif = cmd_to_io_kiocb(nd); prev_notif = cmd_to_io_kiocb(prev_nd);
/* make sure all noifications can be finished in the same task_work */ /* make sure all noifications can be finished in the same task_work */
if (unlikely(notif->ctx != prev_notif->ctx || if (unlikely(notif->ctx != prev_notif->ctx ||
+1 -1
View File
@@ -70,13 +70,13 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
open->filename = NULL; open->filename = NULL;
return ret; return ret;
} }
req->flags |= REQ_F_NEED_CLEANUP;
open->file_slot = READ_ONCE(sqe->file_index); open->file_slot = READ_ONCE(sqe->file_index);
if (open->file_slot && (open->how.flags & O_CLOEXEC)) if (open->file_slot && (open->how.flags & O_CLOEXEC))
return -EINVAL; return -EINVAL;
open->nofile = rlimit(RLIMIT_NOFILE); open->nofile = rlimit(RLIMIT_NOFILE);
req->flags |= REQ_F_NEED_CLEANUP;
if (io_openat_force_async(open)) if (io_openat_force_async(open))
req->flags |= REQ_F_FORCE_ASYNC; req->flags |= REQ_F_FORCE_ASYNC;
return 0; return 0;
+8 -3
View File
@@ -224,7 +224,7 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
{ {
int v; int v;
if (unlikely(io_should_terminate_tw())) if (unlikely(io_should_terminate_tw(req->ctx)))
return -ECANCELED; return -ECANCELED;
do { do {
@@ -930,12 +930,17 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
ret2 = io_poll_add(preq, issue_flags & ~IO_URING_F_UNLOCKED); ret2 = io_poll_add(preq, issue_flags & ~IO_URING_F_UNLOCKED);
/* successfully updated, don't complete poll request */ /* successfully updated, don't complete poll request */
if (!ret2 || ret2 == -EIOCBQUEUED) if (ret2 == IOU_ISSUE_SKIP_COMPLETE)
goto out; goto out;
/* request completed as part of the update, complete it */
else if (ret2 == IOU_COMPLETE)
goto complete;
} }
req_set_fail(preq);
io_req_set_res(preq, -ECANCELED, 0); io_req_set_res(preq, -ECANCELED, 0);
complete:
if (preq->cqe.res < 0)
req_set_fail(preq);
preq->io_task_work.func = io_req_task_complete; preq->io_task_work.func = io_req_task_complete;
io_req_task_work_add(preq); io_req_task_work_add(preq);
out: out:
+6 -2
View File
@@ -272,6 +272,8 @@ static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
if (ctx->flags & IORING_SETUP_SQPOLL) { if (ctx->flags & IORING_SETUP_SQPOLL) {
sqd = ctx->sq_data; sqd = ctx->sq_data;
if (sqd) { if (sqd) {
struct task_struct *tsk;
/* /*
* Observe the correct sqd->lock -> ctx->uring_lock * Observe the correct sqd->lock -> ctx->uring_lock
* ordering. Fine to drop uring_lock here, we hold * ordering. Fine to drop uring_lock here, we hold
@@ -281,8 +283,9 @@ static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
mutex_unlock(&ctx->uring_lock); mutex_unlock(&ctx->uring_lock);
mutex_lock(&sqd->lock); mutex_lock(&sqd->lock);
mutex_lock(&ctx->uring_lock); mutex_lock(&ctx->uring_lock);
if (sqd->thread) tsk = sqpoll_task_locked(sqd);
tctx = sqd->thread->io_uring; if (tsk)
tctx = tsk->io_uring;
} }
} else { } else {
tctx = current->io_uring; tctx = current->io_uring;
@@ -614,6 +617,7 @@ static int io_register_mem_region(struct io_ring_ctx *ctx, void __user *uarg)
if (ret) if (ret)
return ret; return ret;
if (copy_to_user(rd_uptr, &rd, sizeof(rd))) { if (copy_to_user(rd_uptr, &rd, sizeof(rd))) {
guard(mutex)(&ctx->mmap_lock);
io_free_region(ctx, &ctx->param_region); io_free_region(ctx, &ctx->param_region);
return -EFAULT; return -EFAULT;
} }
+32 -12
View File
@@ -55,7 +55,7 @@ int __io_account_mem(struct user_struct *user, unsigned long nr_pages)
return 0; return 0;
} }
static void io_unaccount_mem(struct io_ring_ctx *ctx, unsigned long nr_pages) void io_unaccount_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
{ {
if (ctx->user) if (ctx->user)
__io_unaccount_mem(ctx->user, nr_pages); __io_unaccount_mem(ctx->user, nr_pages);
@@ -64,7 +64,7 @@ static void io_unaccount_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
atomic64_sub(nr_pages, &ctx->mm_account->pinned_vm); atomic64_sub(nr_pages, &ctx->mm_account->pinned_vm);
} }
static int io_account_mem(struct io_ring_ctx *ctx, unsigned long nr_pages) int io_account_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
{ {
int ret; int ret;
@@ -931,8 +931,8 @@ int io_buffer_register_bvec(struct io_uring_cmd *cmd, struct request *rq,
struct req_iterator rq_iter; struct req_iterator rq_iter;
struct io_mapped_ubuf *imu; struct io_mapped_ubuf *imu;
struct io_rsrc_node *node; struct io_rsrc_node *node;
struct bio_vec bv, *bvec; struct bio_vec bv;
u16 nr_bvecs; unsigned int nr_bvecs = 0;
int ret = 0; int ret = 0;
io_ring_submit_lock(ctx, issue_flags); io_ring_submit_lock(ctx, issue_flags);
@@ -953,8 +953,11 @@ int io_buffer_register_bvec(struct io_uring_cmd *cmd, struct request *rq,
goto unlock; goto unlock;
} }
nr_bvecs = blk_rq_nr_phys_segments(rq); /*
imu = io_alloc_imu(ctx, nr_bvecs); * blk_rq_nr_phys_segments() may overestimate the number of bvecs
* but avoids needing to iterate over the bvecs
*/
imu = io_alloc_imu(ctx, blk_rq_nr_phys_segments(rq));
if (!imu) { if (!imu) {
kfree(node); kfree(node);
ret = -ENOMEM; ret = -ENOMEM;
@@ -965,16 +968,15 @@ int io_buffer_register_bvec(struct io_uring_cmd *cmd, struct request *rq,
imu->len = blk_rq_bytes(rq); imu->len = blk_rq_bytes(rq);
imu->acct_pages = 0; imu->acct_pages = 0;
imu->folio_shift = PAGE_SHIFT; imu->folio_shift = PAGE_SHIFT;
imu->nr_bvecs = nr_bvecs;
refcount_set(&imu->refs, 1); refcount_set(&imu->refs, 1);
imu->release = release; imu->release = release;
imu->priv = rq; imu->priv = rq;
imu->is_kbuf = true; imu->is_kbuf = true;
imu->dir = 1 << rq_data_dir(rq); imu->dir = 1 << rq_data_dir(rq);
bvec = imu->bvec;
rq_for_each_bvec(bv, rq, rq_iter) rq_for_each_bvec(bv, rq, rq_iter)
*bvec++ = bv; imu->bvec[nr_bvecs++] = bv;
imu->nr_bvecs = nr_bvecs;
node->buf = imu; node->buf = imu;
data->nodes[index] = node; data->nodes[index] = node;
@@ -1043,6 +1045,7 @@ static int io_import_kbuf(int ddir, struct iov_iter *iter,
if (count < imu->len) { if (count < imu->len) {
const struct bio_vec *bvec = iter->bvec; const struct bio_vec *bvec = iter->bvec;
len += iter->iov_offset;
while (len > bvec->bv_len) { while (len > bvec->bv_len) {
len -= bvec->bv_len; len -= bvec->bv_len;
bvec++; bvec++;
@@ -1181,7 +1184,7 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
if (ret) if (ret)
return ret; return ret;
/* Fill entries in data from dst that won't overlap with src */ /* Copy original dst nodes from before the cloned range */
for (i = 0; i < min(arg->dst_off, ctx->buf_table.nr); i++) { for (i = 0; i < min(arg->dst_off, ctx->buf_table.nr); i++) {
struct io_rsrc_node *src_node = ctx->buf_table.nodes[i]; struct io_rsrc_node *src_node = ctx->buf_table.nodes[i];
@@ -1236,6 +1239,16 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
i++; i++;
} }
/* Copy original dst nodes from after the cloned range */
for (i = nbufs; i < ctx->buf_table.nr; i++) {
struct io_rsrc_node *node = ctx->buf_table.nodes[i];
if (node) {
data.nodes[i] = node;
node->refs++;
}
}
/* /*
* If asked for replace, put the old table. data->nodes[] holds both * If asked for replace, put the old table. data->nodes[] holds both
* old and new nodes at this point. * old and new nodes at this point.
@@ -1387,8 +1400,11 @@ static int io_estimate_bvec_size(struct iovec *iov, unsigned nr_iovs,
size_t max_segs = 0; size_t max_segs = 0;
unsigned i; unsigned i;
for (i = 0; i < nr_iovs; i++) for (i = 0; i < nr_iovs; i++) {
max_segs += (iov[i].iov_len >> shift) + 2; max_segs += (iov[i].iov_len >> shift) + 2;
if (max_segs > INT_MAX)
return -EOVERFLOW;
}
return max_segs; return max_segs;
} }
@@ -1494,7 +1510,11 @@ int io_import_reg_vec(int ddir, struct iov_iter *iter,
if (unlikely(ret)) if (unlikely(ret))
return ret; return ret;
} else { } else {
nr_segs = io_estimate_bvec_size(iov, nr_iovs, imu); int ret = io_estimate_bvec_size(iov, nr_iovs, imu);
if (ret < 0)
return ret;
nr_segs = ret;
} }
if (sizeof(struct bio_vec) > sizeof(struct iovec)) { if (sizeof(struct bio_vec) > sizeof(struct iovec)) {
+2
View File
@@ -144,6 +144,8 @@ int io_files_update(struct io_kiocb *req, unsigned int issue_flags);
int io_files_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe); int io_files_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
int __io_account_mem(struct user_struct *user, unsigned long nr_pages); int __io_account_mem(struct user_struct *user, unsigned long nr_pages);
int io_account_mem(struct io_ring_ctx *ctx, unsigned long nr_pages);
void io_unaccount_mem(struct io_ring_ctx *ctx, unsigned long nr_pages);
static inline void __io_unaccount_mem(struct user_struct *user, static inline void __io_unaccount_mem(struct user_struct *user,
unsigned long nr_pages) unsigned long nr_pages)
+8 -2
View File
@@ -285,7 +285,7 @@ static int __io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe,
rw->addr = READ_ONCE(sqe->addr); rw->addr = READ_ONCE(sqe->addr);
rw->len = READ_ONCE(sqe->len); rw->len = READ_ONCE(sqe->len);
rw->flags = READ_ONCE(sqe->rw_flags); rw->flags = (__force rwf_t) READ_ONCE(sqe->rw_flags);
attr_type_mask = READ_ONCE(sqe->attr_type_mask); attr_type_mask = READ_ONCE(sqe->attr_type_mask);
if (attr_type_mask) { if (attr_type_mask) {
@@ -458,7 +458,10 @@ int io_read_mshot_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
void io_readv_writev_cleanup(struct io_kiocb *req) void io_readv_writev_cleanup(struct io_kiocb *req)
{ {
struct io_async_rw *rw = req->async_data;
lockdep_assert_held(&req->ctx->uring_lock); lockdep_assert_held(&req->ctx->uring_lock);
io_vec_free(&rw->vec);
io_rw_recycle(req, 0); io_rw_recycle(req, 0);
} }
@@ -537,7 +540,7 @@ static void __io_complete_rw_common(struct io_kiocb *req, long res)
{ {
if (res == req->cqe.res) if (res == req->cqe.res)
return; return;
if (res == -EAGAIN && io_rw_should_reissue(req)) { if ((res == -EOPNOTSUPP || res == -EAGAIN) && io_rw_should_reissue(req)) {
req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE; req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE;
} else { } else {
req_set_fail(req); req_set_fail(req);
@@ -883,6 +886,9 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type)
if (req->flags & REQ_F_HAS_METADATA) { if (req->flags & REQ_F_HAS_METADATA) {
struct io_async_rw *io = req->async_data; struct io_async_rw *io = req->async_data;
if (!(file->f_mode & FMODE_HAS_METADATA))
return -EINVAL;
/* /*
* We have a union of meta fields with wpq used for buffered-io * We have a union of meta fields with wpq used for buffered-io
* in io_async_rw, so fail it here. * in io_async_rw, so fail it here.
+74 -39
View File
@@ -11,6 +11,7 @@
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/cpuset.h> #include <linux/cpuset.h>
#include <linux/sched/cputime.h>
#include <linux/io_uring.h> #include <linux/io_uring.h>
#include <uapi/linux/io_uring.h> #include <uapi/linux/io_uring.h>
@@ -30,7 +31,7 @@ enum {
void io_sq_thread_unpark(struct io_sq_data *sqd) void io_sq_thread_unpark(struct io_sq_data *sqd)
__releases(&sqd->lock) __releases(&sqd->lock)
{ {
WARN_ON_ONCE(sqd->thread == current); WARN_ON_ONCE(sqpoll_task_locked(sqd) == current);
/* /*
* Do the dance but not conditional clear_bit() because it'd race with * Do the dance but not conditional clear_bit() because it'd race with
@@ -46,24 +47,32 @@ void io_sq_thread_unpark(struct io_sq_data *sqd)
void io_sq_thread_park(struct io_sq_data *sqd) void io_sq_thread_park(struct io_sq_data *sqd)
__acquires(&sqd->lock) __acquires(&sqd->lock)
{ {
WARN_ON_ONCE(data_race(sqd->thread) == current); struct task_struct *tsk;
atomic_inc(&sqd->park_pending); atomic_inc(&sqd->park_pending);
set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state); set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
mutex_lock(&sqd->lock); mutex_lock(&sqd->lock);
if (sqd->thread)
wake_up_process(sqd->thread); tsk = sqpoll_task_locked(sqd);
if (tsk) {
WARN_ON_ONCE(tsk == current);
wake_up_process(tsk);
}
} }
void io_sq_thread_stop(struct io_sq_data *sqd) void io_sq_thread_stop(struct io_sq_data *sqd)
{ {
WARN_ON_ONCE(sqd->thread == current); struct task_struct *tsk;
WARN_ON_ONCE(test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state)); WARN_ON_ONCE(test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state));
set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state); set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
mutex_lock(&sqd->lock); mutex_lock(&sqd->lock);
if (sqd->thread) tsk = sqpoll_task_locked(sqd);
wake_up_process(sqd->thread); if (tsk) {
WARN_ON_ONCE(tsk == current);
wake_up_process(tsk);
}
mutex_unlock(&sqd->lock); mutex_unlock(&sqd->lock);
wait_for_completion(&sqd->exited); wait_for_completion(&sqd->exited);
} }
@@ -168,7 +177,38 @@ static inline bool io_sqd_events_pending(struct io_sq_data *sqd)
return READ_ONCE(sqd->state); return READ_ONCE(sqd->state);
} }
static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries) struct io_sq_time {
bool started;
u64 usec;
};
u64 io_sq_cpu_usec(struct task_struct *tsk)
{
u64 utime, stime;
task_cputime_adjusted(tsk, &utime, &stime);
do_div(stime, 1000);
return stime;
}
static void io_sq_update_worktime(struct io_sq_data *sqd, struct io_sq_time *ist)
{
if (!ist->started)
return;
ist->started = false;
sqd->work_time += io_sq_cpu_usec(current) - ist->usec;
}
static void io_sq_start_worktime(struct io_sq_time *ist)
{
if (ist->started)
return;
ist->started = true;
ist->usec = io_sq_cpu_usec(current);
}
static int __io_sq_thread(struct io_ring_ctx *ctx, struct io_sq_data *sqd,
bool cap_entries, struct io_sq_time *ist)
{ {
unsigned int to_submit; unsigned int to_submit;
int ret = 0; int ret = 0;
@@ -181,6 +221,8 @@ static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries)
if (to_submit || !wq_list_empty(&ctx->iopoll_list)) { if (to_submit || !wq_list_empty(&ctx->iopoll_list)) {
const struct cred *creds = NULL; const struct cred *creds = NULL;
io_sq_start_worktime(ist);
if (ctx->sq_creds != current_cred()) if (ctx->sq_creds != current_cred())
creds = override_creds(ctx->sq_creds); creds = override_creds(ctx->sq_creds);
@@ -254,23 +296,11 @@ static bool io_sq_tw_pending(struct llist_node *retry_list)
return retry_list || !llist_empty(&tctx->task_list); return retry_list || !llist_empty(&tctx->task_list);
} }
static void io_sq_update_worktime(struct io_sq_data *sqd, struct rusage *start)
{
struct rusage end;
getrusage(current, RUSAGE_SELF, &end);
end.ru_stime.tv_sec -= start->ru_stime.tv_sec;
end.ru_stime.tv_usec -= start->ru_stime.tv_usec;
sqd->work_time += end.ru_stime.tv_usec + end.ru_stime.tv_sec * 1000000;
}
static int io_sq_thread(void *data) static int io_sq_thread(void *data)
{ {
struct llist_node *retry_list = NULL; struct llist_node *retry_list = NULL;
struct io_sq_data *sqd = data; struct io_sq_data *sqd = data;
struct io_ring_ctx *ctx; struct io_ring_ctx *ctx;
struct rusage start;
unsigned long timeout = 0; unsigned long timeout = 0;
char buf[TASK_COMM_LEN] = {}; char buf[TASK_COMM_LEN] = {};
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
@@ -278,7 +308,8 @@ static int io_sq_thread(void *data)
/* offload context creation failed, just exit */ /* offload context creation failed, just exit */
if (!current->io_uring) { if (!current->io_uring) {
mutex_lock(&sqd->lock); mutex_lock(&sqd->lock);
sqd->thread = NULL; rcu_assign_pointer(sqd->thread, NULL);
put_task_struct(current);
mutex_unlock(&sqd->lock); mutex_unlock(&sqd->lock);
goto err_out; goto err_out;
} }
@@ -307,6 +338,7 @@ static int io_sq_thread(void *data)
mutex_lock(&sqd->lock); mutex_lock(&sqd->lock);
while (1) { while (1) {
bool cap_entries, sqt_spin = false; bool cap_entries, sqt_spin = false;
struct io_sq_time ist = { };
if (io_sqd_events_pending(sqd) || signal_pending(current)) { if (io_sqd_events_pending(sqd) || signal_pending(current)) {
if (io_sqd_handle_event(sqd)) if (io_sqd_handle_event(sqd))
@@ -315,9 +347,8 @@ static int io_sq_thread(void *data)
} }
cap_entries = !list_is_singular(&sqd->ctx_list); cap_entries = !list_is_singular(&sqd->ctx_list);
getrusage(current, RUSAGE_SELF, &start);
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) { list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
int ret = __io_sq_thread(ctx, cap_entries); int ret = __io_sq_thread(ctx, sqd, cap_entries, &ist);
if (!sqt_spin && (ret > 0 || !wq_list_empty(&ctx->iopoll_list))) if (!sqt_spin && (ret > 0 || !wq_list_empty(&ctx->iopoll_list)))
sqt_spin = true; sqt_spin = true;
@@ -325,15 +356,18 @@ static int io_sq_thread(void *data)
if (io_sq_tw(&retry_list, IORING_TW_CAP_ENTRIES_VALUE)) if (io_sq_tw(&retry_list, IORING_TW_CAP_ENTRIES_VALUE))
sqt_spin = true; sqt_spin = true;
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
if (io_napi(ctx)) if (io_napi(ctx)) {
io_sq_start_worktime(&ist);
io_napi_sqpoll_busy_poll(ctx); io_napi_sqpoll_busy_poll(ctx);
}
}
io_sq_update_worktime(sqd, &ist);
if (sqt_spin || !time_after(jiffies, timeout)) { if (sqt_spin || !time_after(jiffies, timeout)) {
if (sqt_spin) { if (sqt_spin)
io_sq_update_worktime(sqd, &start);
timeout = jiffies + sqd->sq_thread_idle; timeout = jiffies + sqd->sq_thread_idle;
}
if (unlikely(need_resched())) { if (unlikely(need_resched())) {
mutex_unlock(&sqd->lock); mutex_unlock(&sqd->lock);
cond_resched(); cond_resched();
@@ -387,7 +421,8 @@ static int io_sq_thread(void *data)
io_sq_tw(&retry_list, UINT_MAX); io_sq_tw(&retry_list, UINT_MAX);
io_uring_cancel_generic(true, sqd); io_uring_cancel_generic(true, sqd);
sqd->thread = NULL; rcu_assign_pointer(sqd->thread, NULL);
put_task_struct(current);
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
atomic_or(IORING_SQ_NEED_WAKEUP, &ctx->rings->sq_flags); atomic_or(IORING_SQ_NEED_WAKEUP, &ctx->rings->sq_flags);
io_run_task_work(); io_run_task_work();
@@ -417,7 +452,6 @@ void io_sqpoll_wait_sq(struct io_ring_ctx *ctx)
__cold int io_sq_offload_create(struct io_ring_ctx *ctx, __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
struct io_uring_params *p) struct io_uring_params *p)
{ {
struct task_struct *task_to_put = NULL;
int ret; int ret;
/* Retain compatibility with failing for an invalid attach attempt */ /* Retain compatibility with failing for an invalid attach attempt */
@@ -497,8 +531,11 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
goto err_sqpoll; goto err_sqpoll;
} }
sqd->thread = tsk; mutex_lock(&sqd->lock);
task_to_put = get_task_struct(tsk); rcu_assign_pointer(sqd->thread, tsk);
mutex_unlock(&sqd->lock);
get_task_struct(tsk);
ret = io_uring_alloc_task_context(tsk, ctx); ret = io_uring_alloc_task_context(tsk, ctx);
wake_up_new_task(tsk); wake_up_new_task(tsk);
if (ret) if (ret)
@@ -508,16 +545,11 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
if (task_to_put)
put_task_struct(task_to_put);
return 0; return 0;
err_sqpoll: err_sqpoll:
complete(&ctx->sq_data->exited); complete(&ctx->sq_data->exited);
err: err:
io_sq_thread_finish(ctx); io_sq_thread_finish(ctx);
if (task_to_put)
put_task_struct(task_to_put);
return ret; return ret;
} }
@@ -528,10 +560,13 @@ __cold int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx,
int ret = -EINVAL; int ret = -EINVAL;
if (sqd) { if (sqd) {
struct task_struct *tsk;
io_sq_thread_park(sqd); io_sq_thread_park(sqd);
/* Don't set affinity for a dying thread */ /* Don't set affinity for a dying thread */
if (sqd->thread) tsk = sqpoll_task_locked(sqd);
ret = io_wq_cpu_affinity(sqd->thread->io_uring, mask); if (tsk)
ret = io_wq_cpu_affinity(tsk->io_uring, mask);
io_sq_thread_unpark(sqd); io_sq_thread_unpark(sqd);
} }
+8 -1
View File
@@ -8,7 +8,7 @@ struct io_sq_data {
/* ctx's that are using this sqd */ /* ctx's that are using this sqd */
struct list_head ctx_list; struct list_head ctx_list;
struct task_struct *thread; struct task_struct __rcu *thread;
struct wait_queue_head wait; struct wait_queue_head wait;
unsigned sq_thread_idle; unsigned sq_thread_idle;
@@ -29,3 +29,10 @@ void io_sq_thread_unpark(struct io_sq_data *sqd);
void io_put_sq_data(struct io_sq_data *sqd); void io_put_sq_data(struct io_sq_data *sqd);
void io_sqpoll_wait_sq(struct io_ring_ctx *ctx); void io_sqpoll_wait_sq(struct io_ring_ctx *ctx);
int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx, cpumask_var_t mask); int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx, cpumask_var_t mask);
static inline struct task_struct *sqpoll_task_locked(struct io_sq_data *sqd)
{
return rcu_dereference_protected(sqd->thread,
lockdep_is_held(&sqd->lock));
}
u64 io_sq_cpu_usec(struct task_struct *tsk);
+1 -1
View File
@@ -319,7 +319,7 @@ static void io_req_task_link_timeout(struct io_kiocb *req, io_tw_token_t tw)
int ret; int ret;
if (prev) { if (prev) {
if (!io_should_terminate_tw()) { if (!io_should_terminate_tw(req->ctx)) {
struct io_cancel_data cd = { struct io_cancel_data cd = {
.ctx = req->ctx, .ctx = req->ctx,
.data = prev->cqe.user_data, .data = prev->cqe.user_data,
+1 -1
View File
@@ -126,7 +126,7 @@ static void io_uring_cmd_work(struct io_kiocb *req, io_tw_token_t tw)
struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd); struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
unsigned int flags = IO_URING_F_COMPLETE_DEFER; unsigned int flags = IO_URING_F_COMPLETE_DEFER;
if (io_should_terminate_tw()) if (io_should_terminate_tw(req->ctx))
flags |= IO_URING_F_TASK_DEAD; flags |= IO_URING_F_TASK_DEAD;
/* task_work executor checks the deffered list completion */ /* task_work executor checks the deffered list completion */
+1 -1
View File
@@ -252,7 +252,7 @@ int io_waitid_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return -EINVAL; return -EINVAL;
iwa = io_uring_alloc_async_data(NULL, req); iwa = io_uring_alloc_async_data(NULL, req);
if (!unlikely(iwa)) if (unlikely(!iwa))
return -ENOMEM; return -ENOMEM;
iwa->req = req; iwa->req = req;