LCOV - code coverage report
Current view: top level - io_uring - tctx.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 155 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 11 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/kernel.h>
       3             : #include <linux/errno.h>
       4             : #include <linux/file.h>
       5             : #include <linux/mm.h>
       6             : #include <linux/slab.h>
       7             : #include <linux/nospec.h>
       8             : #include <linux/io_uring.h>
       9             : 
      10             : #include <uapi/linux/io_uring.h>
      11             : 
      12             : #include "io_uring.h"
      13             : #include "tctx.h"
      14             : 
      15           0 : static struct io_wq *io_init_wq_offload(struct io_ring_ctx *ctx,
      16             :                                         struct task_struct *task)
      17             : {
      18             :         struct io_wq_hash *hash;
      19             :         struct io_wq_data data;
      20             :         unsigned int concurrency;
      21             : 
      22           0 :         mutex_lock(&ctx->uring_lock);
      23           0 :         hash = ctx->hash_map;
      24           0 :         if (!hash) {
      25           0 :                 hash = kzalloc(sizeof(*hash), GFP_KERNEL);
      26           0 :                 if (!hash) {
      27           0 :                         mutex_unlock(&ctx->uring_lock);
      28           0 :                         return ERR_PTR(-ENOMEM);
      29             :                 }
      30           0 :                 refcount_set(&hash->refs, 1);
      31           0 :                 init_waitqueue_head(&hash->wait);
      32           0 :                 ctx->hash_map = hash;
      33             :         }
      34           0 :         mutex_unlock(&ctx->uring_lock);
      35             : 
      36           0 :         data.hash = hash;
      37           0 :         data.task = task;
      38           0 :         data.free_work = io_wq_free_work;
      39           0 :         data.do_work = io_wq_submit_work;
      40             : 
      41             :         /* Do QD, or 4 * CPUS, whatever is smallest */
      42           0 :         concurrency = min(ctx->sq_entries, 4 * num_online_cpus());
      43             : 
      44           0 :         return io_wq_create(concurrency, &data);
      45             : }
      46             : 
      47           0 : void __io_uring_free(struct task_struct *tsk)
      48             : {
      49           0 :         struct io_uring_task *tctx = tsk->io_uring;
      50             : 
      51           0 :         WARN_ON_ONCE(!xa_empty(&tctx->xa));
      52           0 :         WARN_ON_ONCE(tctx->io_wq);
      53           0 :         WARN_ON_ONCE(tctx->cached_refs);
      54             : 
      55           0 :         percpu_counter_destroy(&tctx->inflight);
      56           0 :         kfree(tctx);
      57           0 :         tsk->io_uring = NULL;
      58           0 : }
      59             : 
      60           0 : __cold int io_uring_alloc_task_context(struct task_struct *task,
      61             :                                        struct io_ring_ctx *ctx)
      62             : {
      63             :         struct io_uring_task *tctx;
      64             :         int ret;
      65             : 
      66           0 :         tctx = kzalloc(sizeof(*tctx), GFP_KERNEL);
      67           0 :         if (unlikely(!tctx))
      68             :                 return -ENOMEM;
      69             : 
      70           0 :         ret = percpu_counter_init(&tctx->inflight, 0, GFP_KERNEL);
      71             :         if (unlikely(ret)) {
      72             :                 kfree(tctx);
      73             :                 return ret;
      74             :         }
      75             : 
      76           0 :         tctx->io_wq = io_init_wq_offload(ctx, task);
      77           0 :         if (IS_ERR(tctx->io_wq)) {
      78           0 :                 ret = PTR_ERR(tctx->io_wq);
      79           0 :                 percpu_counter_destroy(&tctx->inflight);
      80           0 :                 kfree(tctx);
      81           0 :                 return ret;
      82             :         }
      83             : 
      84           0 :         xa_init(&tctx->xa);
      85           0 :         init_waitqueue_head(&tctx->wait);
      86           0 :         atomic_set(&tctx->in_cancel, 0);
      87           0 :         atomic_set(&tctx->inflight_tracked, 0);
      88           0 :         task->io_uring = tctx;
      89           0 :         init_llist_head(&tctx->task_list);
      90           0 :         init_task_work(&tctx->task_work, tctx_task_work);
      91           0 :         return 0;
      92             : }
      93             : 
      94           0 : int __io_uring_add_tctx_node(struct io_ring_ctx *ctx)
      95             : {
      96           0 :         struct io_uring_task *tctx = current->io_uring;
      97             :         struct io_tctx_node *node;
      98             :         int ret;
      99             : 
     100           0 :         if (unlikely(!tctx)) {
     101           0 :                 ret = io_uring_alloc_task_context(current, ctx);
     102           0 :                 if (unlikely(ret))
     103             :                         return ret;
     104             : 
     105           0 :                 tctx = current->io_uring;
     106           0 :                 if (ctx->iowq_limits_set) {
     107           0 :                         unsigned int limits[2] = { ctx->iowq_limits[0],
     108           0 :                                                    ctx->iowq_limits[1], };
     109             : 
     110           0 :                         ret = io_wq_max_workers(tctx->io_wq, limits);
     111           0 :                         if (ret)
     112           0 :                                 return ret;
     113             :                 }
     114             :         }
     115           0 :         if (!xa_load(&tctx->xa, (unsigned long)ctx)) {
     116           0 :                 node = kmalloc(sizeof(*node), GFP_KERNEL);
     117           0 :                 if (!node)
     118             :                         return -ENOMEM;
     119           0 :                 node->ctx = ctx;
     120           0 :                 node->task = current;
     121             : 
     122           0 :                 ret = xa_err(xa_store(&tctx->xa, (unsigned long)ctx,
     123             :                                         node, GFP_KERNEL));
     124           0 :                 if (ret) {
     125           0 :                         kfree(node);
     126           0 :                         return ret;
     127             :                 }
     128             : 
     129           0 :                 mutex_lock(&ctx->uring_lock);
     130           0 :                 list_add(&node->ctx_node, &ctx->tctx_list);
     131           0 :                 mutex_unlock(&ctx->uring_lock);
     132             :         }
     133             :         return 0;
     134             : }
     135             : 
     136           0 : int __io_uring_add_tctx_node_from_submit(struct io_ring_ctx *ctx)
     137             : {
     138             :         int ret;
     139             : 
     140           0 :         if (ctx->flags & IORING_SETUP_SINGLE_ISSUER
     141           0 :             && ctx->submitter_task != current)
     142             :                 return -EEXIST;
     143             : 
     144           0 :         ret = __io_uring_add_tctx_node(ctx);
     145           0 :         if (ret)
     146             :                 return ret;
     147             : 
     148           0 :         current->io_uring->last = ctx;
     149           0 :         return 0;
     150             : }
     151             : 
     152             : /*
     153             :  * Remove this io_uring_file -> task mapping.
     154             :  */
     155           0 : __cold void io_uring_del_tctx_node(unsigned long index)
     156             : {
     157           0 :         struct io_uring_task *tctx = current->io_uring;
     158             :         struct io_tctx_node *node;
     159             : 
     160           0 :         if (!tctx)
     161             :                 return;
     162           0 :         node = xa_erase(&tctx->xa, index);
     163           0 :         if (!node)
     164             :                 return;
     165             : 
     166           0 :         WARN_ON_ONCE(current != node->task);
     167           0 :         WARN_ON_ONCE(list_empty(&node->ctx_node));
     168             : 
     169           0 :         mutex_lock(&node->ctx->uring_lock);
     170           0 :         list_del(&node->ctx_node);
     171           0 :         mutex_unlock(&node->ctx->uring_lock);
     172             : 
     173           0 :         if (tctx->last == node->ctx)
     174           0 :                 tctx->last = NULL;
     175           0 :         kfree(node);
     176             : }
     177             : 
     178           0 : __cold void io_uring_clean_tctx(struct io_uring_task *tctx)
     179             : {
     180           0 :         struct io_wq *wq = tctx->io_wq;
     181             :         struct io_tctx_node *node;
     182             :         unsigned long index;
     183             : 
     184           0 :         xa_for_each(&tctx->xa, index, node) {
     185           0 :                 io_uring_del_tctx_node(index);
     186           0 :                 cond_resched();
     187             :         }
     188           0 :         if (wq) {
     189             :                 /*
     190             :                  * Must be after io_uring_del_tctx_node() (removes nodes under
     191             :                  * uring_lock) to avoid race with io_uring_try_cancel_iowq().
     192             :                  */
     193           0 :                 io_wq_put_and_exit(wq);
     194           0 :                 tctx->io_wq = NULL;
     195             :         }
     196           0 : }
     197             : 
     198           0 : void io_uring_unreg_ringfd(void)
     199             : {
     200           0 :         struct io_uring_task *tctx = current->io_uring;
     201             :         int i;
     202             : 
     203           0 :         for (i = 0; i < IO_RINGFD_REG_MAX; i++) {
     204           0 :                 if (tctx->registered_rings[i]) {
     205           0 :                         fput(tctx->registered_rings[i]);
     206           0 :                         tctx->registered_rings[i] = NULL;
     207             :                 }
     208             :         }
     209           0 : }
     210             : 
     211           0 : static int io_ring_add_registered_fd(struct io_uring_task *tctx, int fd,
     212             :                                      int start, int end)
     213             : {
     214             :         struct file *file;
     215             :         int offset;
     216             : 
     217           0 :         for (offset = start; offset < end; offset++) {
     218           0 :                 offset = array_index_nospec(offset, IO_RINGFD_REG_MAX);
     219           0 :                 if (tctx->registered_rings[offset])
     220           0 :                         continue;
     221             : 
     222           0 :                 file = fget(fd);
     223           0 :                 if (!file) {
     224             :                         return -EBADF;
     225           0 :                 } else if (!io_is_uring_fops(file)) {
     226           0 :                         fput(file);
     227           0 :                         return -EOPNOTSUPP;
     228             :                 }
     229           0 :                 tctx->registered_rings[offset] = file;
     230           0 :                 return offset;
     231             :         }
     232             : 
     233             :         return -EBUSY;
     234             : }
     235             : 
     236             : /*
     237             :  * Register a ring fd to avoid fdget/fdput for each io_uring_enter()
     238             :  * invocation. User passes in an array of struct io_uring_rsrc_update
     239             :  * with ->data set to the ring_fd, and ->offset given for the desired
     240             :  * index. If no index is desired, application may set ->offset == -1U
     241             :  * and we'll find an available index. Returns number of entries
     242             :  * successfully processed, or < 0 on error if none were processed.
     243             :  */
     244           0 : int io_ringfd_register(struct io_ring_ctx *ctx, void __user *__arg,
     245             :                        unsigned nr_args)
     246             : {
     247           0 :         struct io_uring_rsrc_update __user *arg = __arg;
     248             :         struct io_uring_rsrc_update reg;
     249             :         struct io_uring_task *tctx;
     250             :         int ret, i;
     251             : 
     252           0 :         if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
     253             :                 return -EINVAL;
     254             : 
     255           0 :         mutex_unlock(&ctx->uring_lock);
     256           0 :         ret = __io_uring_add_tctx_node(ctx);
     257           0 :         mutex_lock(&ctx->uring_lock);
     258           0 :         if (ret)
     259             :                 return ret;
     260             : 
     261           0 :         tctx = current->io_uring;
     262           0 :         for (i = 0; i < nr_args; i++) {
     263             :                 int start, end;
     264             : 
     265           0 :                 if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
     266             :                         ret = -EFAULT;
     267             :                         break;
     268             :                 }
     269             : 
     270           0 :                 if (reg.resv) {
     271             :                         ret = -EINVAL;
     272             :                         break;
     273             :                 }
     274             : 
     275           0 :                 if (reg.offset == -1U) {
     276             :                         start = 0;
     277             :                         end = IO_RINGFD_REG_MAX;
     278             :                 } else {
     279           0 :                         if (reg.offset >= IO_RINGFD_REG_MAX) {
     280             :                                 ret = -EINVAL;
     281             :                                 break;
     282             :                         }
     283           0 :                         start = reg.offset;
     284           0 :                         end = start + 1;
     285             :                 }
     286             : 
     287           0 :                 ret = io_ring_add_registered_fd(tctx, reg.data, start, end);
     288           0 :                 if (ret < 0)
     289             :                         break;
     290             : 
     291           0 :                 reg.offset = ret;
     292           0 :                 if (copy_to_user(&arg[i], &reg, sizeof(reg))) {
     293           0 :                         fput(tctx->registered_rings[reg.offset]);
     294           0 :                         tctx->registered_rings[reg.offset] = NULL;
     295           0 :                         ret = -EFAULT;
     296           0 :                         break;
     297             :                 }
     298             :         }
     299             : 
     300           0 :         return i ? i : ret;
     301             : }
     302             : 
     303           0 : int io_ringfd_unregister(struct io_ring_ctx *ctx, void __user *__arg,
     304             :                          unsigned nr_args)
     305             : {
     306           0 :         struct io_uring_rsrc_update __user *arg = __arg;
     307           0 :         struct io_uring_task *tctx = current->io_uring;
     308             :         struct io_uring_rsrc_update reg;
     309           0 :         int ret = 0, i;
     310             : 
     311           0 :         if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
     312             :                 return -EINVAL;
     313           0 :         if (!tctx)
     314             :                 return 0;
     315             : 
     316           0 :         for (i = 0; i < nr_args; i++) {
     317           0 :                 if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
     318             :                         ret = -EFAULT;
     319             :                         break;
     320             :                 }
     321           0 :                 if (reg.resv || reg.data || reg.offset >= IO_RINGFD_REG_MAX) {
     322             :                         ret = -EINVAL;
     323             :                         break;
     324             :                 }
     325             : 
     326           0 :                 reg.offset = array_index_nospec(reg.offset, IO_RINGFD_REG_MAX);
     327           0 :                 if (tctx->registered_rings[reg.offset]) {
     328           0 :                         fput(tctx->registered_rings[reg.offset]);
     329           0 :                         tctx->registered_rings[reg.offset] = NULL;
     330             :                 }
     331             :         }
     332             : 
     333           0 :         return i ? i : ret;
     334             : }

Generated by: LCOV version 1.14