mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-12-16 23:48:14 +01:00
for-6.8/io_uring-2024-01-18
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmWpoAYQHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgphZ5D/47nZdRZq1dKWDxn8qQiVjjgXtu9F8z1cXo AKZ5pWR44i/bIvyk7RT8dtNS1OGR88hKdF15ZoKg701AnciAHvl03Inb2Mbnpocb 3g54WPKSlRR1qhepjXicrr5onQiqC6jKw6/CMa6z+qtKtTu+LNAh2+k1TqfDZRA/ oXCxBHH0P0LmfRzMiJaoDwwd8UnIzd7r09qdzsvzKL5bEs64vpTKQkS5D8l2ftIf 4PMRfkvCIPzyEsZR4jz0PTgRsVbShKVxDJaaiAQfqYxVmSGQBc0S9yvhsSe7domE Xodx3qJxIXrqXAaT5sOQDoo5J985Z6JDaZzK3dp1ULk+F4gXLtG1YelPd5QoMFUW CKfqXEby9P3JljhyIokB+3eaUEjjKBSXw7vWW2GfrMEAfp1nHzDRAGKOUz66/L+8 R/b3WsN1CDNgHviOPhcxOVaQ5ysdIT8vVFGpYiNCb5X4hXZQS2CBY1gVN1fpLhuV 4bj5mV8/qUPlHVs+HegCqROLX2rThASGZea1XXrrYVakTBmKWnm4s+G2Ir+wup6s 9Xtn+v32BodfbJmipsW0/jxVuTJsCq2mcCU2ltOiXO4xwcJhw+dx8Alb1cwSvP37 E+Sr3XVEgtsywiCrl42ndXes/ztE6v9v+WZNlP82OwMMYMlDhPAjyi/r7YWwtWT9 r6bXKfcOfQ== =rd3Y -----END PGP SIGNATURE----- Merge tag 'for-6.8/io_uring-2024-01-18' of git://git.kernel.dk/linux Pull io_uring fixes from Jens Axboe: "Nothing major in here, just a few fixes and cleanups that arrived after the initial merge window pull request got finalized, as well as a fix for a patch that got merged earlier" * tag 'for-6.8/io_uring-2024-01-18' of git://git.kernel.dk/linux: io_uring: combine cq_wait_nr checks io_uring: clean *local_work_add var naming io_uring: clean up local tw add-wait sync io_uring: adjust defer tw counting io_uring/register: guard compat syscall with CONFIG_COMPAT io_uring/rsrc: improve code generation for fixed file assignment io_uring/rw: cleanup io_rw_done()
This commit is contained in:
commit
e9a5a78d1a
|
|
@ -137,6 +137,14 @@ struct io_defer_entry {
|
||||||
#define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL)
|
#define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL)
|
||||||
#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
|
#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No waiters. It's larger than any valid value of the tw counter
|
||||||
|
* so that tests against ->cq_wait_nr would fail and skip wake_up().
|
||||||
|
*/
|
||||||
|
#define IO_CQ_WAKE_INIT (-1U)
|
||||||
|
/* Forced wake up if there is a waiter regardless of ->cq_wait_nr */
|
||||||
|
#define IO_CQ_WAKE_FORCE (IO_CQ_WAKE_INIT >> 1)
|
||||||
|
|
||||||
static bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
|
static bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
|
||||||
struct task_struct *task,
|
struct task_struct *task,
|
||||||
bool cancel_all);
|
bool cancel_all);
|
||||||
|
|
@ -303,6 +311,7 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ctx->flags = p->flags;
|
ctx->flags = p->flags;
|
||||||
|
atomic_set(&ctx->cq_wait_nr, IO_CQ_WAKE_INIT);
|
||||||
init_waitqueue_head(&ctx->sqo_sq_wait);
|
init_waitqueue_head(&ctx->sqo_sq_wait);
|
||||||
INIT_LIST_HEAD(&ctx->sqd_list);
|
INIT_LIST_HEAD(&ctx->sqd_list);
|
||||||
INIT_LIST_HEAD(&ctx->cq_overflow_list);
|
INIT_LIST_HEAD(&ctx->cq_overflow_list);
|
||||||
|
|
@ -1304,16 +1313,23 @@ static inline void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
|
||||||
{
|
{
|
||||||
struct io_ring_ctx *ctx = req->ctx;
|
struct io_ring_ctx *ctx = req->ctx;
|
||||||
unsigned nr_wait, nr_tw, nr_tw_prev;
|
unsigned nr_wait, nr_tw, nr_tw_prev;
|
||||||
struct llist_node *first;
|
struct llist_node *head;
|
||||||
|
|
||||||
|
/* See comment above IO_CQ_WAKE_INIT */
|
||||||
|
BUILD_BUG_ON(IO_CQ_WAKE_FORCE <= IORING_MAX_CQ_ENTRIES);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't know how many reuqests is there in the link and whether
|
||||||
|
* they can even be queued lazily, fall back to non-lazy.
|
||||||
|
*/
|
||||||
if (req->flags & (REQ_F_LINK | REQ_F_HARDLINK))
|
if (req->flags & (REQ_F_LINK | REQ_F_HARDLINK))
|
||||||
flags &= ~IOU_F_TWQ_LAZY_WAKE;
|
flags &= ~IOU_F_TWQ_LAZY_WAKE;
|
||||||
|
|
||||||
first = READ_ONCE(ctx->work_llist.first);
|
head = READ_ONCE(ctx->work_llist.first);
|
||||||
do {
|
do {
|
||||||
nr_tw_prev = 0;
|
nr_tw_prev = 0;
|
||||||
if (first) {
|
if (head) {
|
||||||
struct io_kiocb *first_req = container_of(first,
|
struct io_kiocb *first_req = container_of(head,
|
||||||
struct io_kiocb,
|
struct io_kiocb,
|
||||||
io_task_work.node);
|
io_task_work.node);
|
||||||
/*
|
/*
|
||||||
|
|
@ -1322,17 +1338,29 @@ static inline void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
|
||||||
*/
|
*/
|
||||||
nr_tw_prev = READ_ONCE(first_req->nr_tw);
|
nr_tw_prev = READ_ONCE(first_req->nr_tw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Theoretically, it can overflow, but that's fine as one of
|
||||||
|
* previous adds should've tried to wake the task.
|
||||||
|
*/
|
||||||
nr_tw = nr_tw_prev + 1;
|
nr_tw = nr_tw_prev + 1;
|
||||||
/* Large enough to fail the nr_wait comparison below */
|
|
||||||
if (!(flags & IOU_F_TWQ_LAZY_WAKE))
|
if (!(flags & IOU_F_TWQ_LAZY_WAKE))
|
||||||
nr_tw = -1U;
|
nr_tw = IO_CQ_WAKE_FORCE;
|
||||||
|
|
||||||
req->nr_tw = nr_tw;
|
req->nr_tw = nr_tw;
|
||||||
req->io_task_work.node.next = first;
|
req->io_task_work.node.next = head;
|
||||||
} while (!try_cmpxchg(&ctx->work_llist.first, &first,
|
} while (!try_cmpxchg(&ctx->work_llist.first, &head,
|
||||||
&req->io_task_work.node));
|
&req->io_task_work.node));
|
||||||
|
|
||||||
if (!first) {
|
/*
|
||||||
|
* cmpxchg implies a full barrier, which pairs with the barrier
|
||||||
|
* in set_current_state() on the io_cqring_wait() side. It's used
|
||||||
|
* to ensure that either we see updated ->cq_wait_nr, or waiters
|
||||||
|
* going to sleep will observe the work added to the list, which
|
||||||
|
* is similar to the wait/wawke task state sync.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!head) {
|
||||||
if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
|
if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
|
||||||
atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
|
atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
|
||||||
if (ctx->has_evfd)
|
if (ctx->has_evfd)
|
||||||
|
|
@ -1340,14 +1368,12 @@ static inline void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
nr_wait = atomic_read(&ctx->cq_wait_nr);
|
nr_wait = atomic_read(&ctx->cq_wait_nr);
|
||||||
/* no one is waiting */
|
/* not enough or no one is waiting */
|
||||||
if (!nr_wait)
|
if (nr_tw < nr_wait)
|
||||||
return;
|
return;
|
||||||
/* either not enough or the previous add has already woken it up */
|
/* the previous add has already woken it up */
|
||||||
if (nr_wait > nr_tw || nr_tw_prev >= nr_wait)
|
if (nr_tw_prev >= nr_wait)
|
||||||
return;
|
return;
|
||||||
/* pairs with set_current_state() in io_cqring_wait() */
|
|
||||||
smp_mb__after_atomic();
|
|
||||||
wake_up_state(ctx->submitter_task, TASK_INTERRUPTIBLE);
|
wake_up_state(ctx->submitter_task, TASK_INTERRUPTIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2000,9 +2026,10 @@ inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
|
||||||
goto out;
|
goto out;
|
||||||
fd = array_index_nospec(fd, ctx->nr_user_files);
|
fd = array_index_nospec(fd, ctx->nr_user_files);
|
||||||
slot = io_fixed_file_slot(&ctx->file_table, fd);
|
slot = io_fixed_file_slot(&ctx->file_table, fd);
|
||||||
file = io_slot_file(slot);
|
if (!req->rsrc_node)
|
||||||
|
__io_req_set_rsrc_node(req, ctx);
|
||||||
req->flags |= io_slot_flags(slot);
|
req->flags |= io_slot_flags(slot);
|
||||||
io_req_set_rsrc_node(req, ctx, 0);
|
file = io_slot_file(slot);
|
||||||
out:
|
out:
|
||||||
io_ring_submit_unlock(ctx, issue_flags);
|
io_ring_submit_unlock(ctx, issue_flags);
|
||||||
return file;
|
return file;
|
||||||
|
|
@ -2613,7 +2640,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
|
||||||
|
|
||||||
ret = io_cqring_wait_schedule(ctx, &iowq);
|
ret = io_cqring_wait_schedule(ctx, &iowq);
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
atomic_set(&ctx->cq_wait_nr, 0);
|
atomic_set(&ctx->cq_wait_nr, IO_CQ_WAKE_INIT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run task_work after scheduling and before io_should_wake().
|
* Run task_work after scheduling and before io_should_wake().
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/nospec.h>
|
#include <linux/nospec.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/io_uring.h>
|
#include <linux/io_uring.h>
|
||||||
#include <linux/io_uring_types.h>
|
#include <linux/io_uring_types.h>
|
||||||
|
|
||||||
|
|
@ -278,13 +279,14 @@ static __cold int io_register_iowq_aff(struct io_ring_ctx *ctx,
|
||||||
if (len > cpumask_size())
|
if (len > cpumask_size())
|
||||||
len = cpumask_size();
|
len = cpumask_size();
|
||||||
|
|
||||||
if (in_compat_syscall()) {
|
#ifdef CONFIG_COMPAT
|
||||||
|
if (in_compat_syscall())
|
||||||
ret = compat_get_bitmap(cpumask_bits(new_mask),
|
ret = compat_get_bitmap(cpumask_bits(new_mask),
|
||||||
(const compat_ulong_t __user *)arg,
|
(const compat_ulong_t __user *)arg,
|
||||||
len * 8 /* CHAR_BIT */);
|
len * 8 /* CHAR_BIT */);
|
||||||
} else {
|
else
|
||||||
|
#endif
|
||||||
ret = copy_from_user(new_mask, arg, len);
|
ret = copy_from_user(new_mask, arg, len);
|
||||||
}
|
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
free_cpumask_var(new_mask);
|
free_cpumask_var(new_mask);
|
||||||
|
|
|
||||||
|
|
@ -102,17 +102,21 @@ static inline void io_charge_rsrc_node(struct io_ring_ctx *ctx,
|
||||||
node->refs++;
|
node->refs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void __io_req_set_rsrc_node(struct io_kiocb *req,
|
||||||
|
struct io_ring_ctx *ctx)
|
||||||
|
{
|
||||||
|
lockdep_assert_held(&ctx->uring_lock);
|
||||||
|
req->rsrc_node = ctx->rsrc_node;
|
||||||
|
io_charge_rsrc_node(ctx, ctx->rsrc_node);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void io_req_set_rsrc_node(struct io_kiocb *req,
|
static inline void io_req_set_rsrc_node(struct io_kiocb *req,
|
||||||
struct io_ring_ctx *ctx,
|
struct io_ring_ctx *ctx,
|
||||||
unsigned int issue_flags)
|
unsigned int issue_flags)
|
||||||
{
|
{
|
||||||
if (!req->rsrc_node) {
|
if (!req->rsrc_node) {
|
||||||
io_ring_submit_lock(ctx, issue_flags);
|
io_ring_submit_lock(ctx, issue_flags);
|
||||||
|
__io_req_set_rsrc_node(req, ctx);
|
||||||
lockdep_assert_held(&ctx->uring_lock);
|
|
||||||
|
|
||||||
req->rsrc_node = ctx->rsrc_node;
|
|
||||||
io_charge_rsrc_node(ctx, ctx->rsrc_node);
|
|
||||||
io_ring_submit_unlock(ctx, issue_flags);
|
io_ring_submit_unlock(ctx, issue_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,27 +168,6 @@ void io_readv_writev_cleanup(struct io_kiocb *req)
|
||||||
kfree(io->free_iovec);
|
kfree(io->free_iovec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
|
|
||||||
{
|
|
||||||
switch (ret) {
|
|
||||||
case -EIOCBQUEUED:
|
|
||||||
break;
|
|
||||||
case -ERESTARTSYS:
|
|
||||||
case -ERESTARTNOINTR:
|
|
||||||
case -ERESTARTNOHAND:
|
|
||||||
case -ERESTART_RESTARTBLOCK:
|
|
||||||
/*
|
|
||||||
* We can't just restart the syscall, since previously
|
|
||||||
* submitted sqes may already be in progress. Just fail this
|
|
||||||
* IO with EINTR.
|
|
||||||
*/
|
|
||||||
ret = -EINTR;
|
|
||||||
fallthrough;
|
|
||||||
default:
|
|
||||||
kiocb->ki_complete(kiocb, ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req)
|
static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req)
|
||||||
{
|
{
|
||||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||||
|
|
@ -371,6 +350,33 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
|
||||||
smp_store_release(&req->iopoll_completed, 1);
|
smp_store_release(&req->iopoll_completed, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
|
||||||
|
{
|
||||||
|
/* IO was queued async, completion will happen later */
|
||||||
|
if (ret == -EIOCBQUEUED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* transform internal restart error codes */
|
||||||
|
if (unlikely(ret < 0)) {
|
||||||
|
switch (ret) {
|
||||||
|
case -ERESTARTSYS:
|
||||||
|
case -ERESTARTNOINTR:
|
||||||
|
case -ERESTARTNOHAND:
|
||||||
|
case -ERESTART_RESTARTBLOCK:
|
||||||
|
/*
|
||||||
|
* We can't just restart the syscall, since previously
|
||||||
|
* submitted sqes may already be in progress. Just fail
|
||||||
|
* this IO with EINTR.
|
||||||
|
*/
|
||||||
|
ret = -EINTR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INDIRECT_CALL_2(kiocb->ki_complete, io_complete_rw_iopoll,
|
||||||
|
io_complete_rw, kiocb, ret);
|
||||||
|
}
|
||||||
|
|
||||||
static int kiocb_done(struct io_kiocb *req, ssize_t ret,
|
static int kiocb_done(struct io_kiocb *req, ssize_t ret,
|
||||||
unsigned int issue_flags)
|
unsigned int issue_flags)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user