LCOV - code coverage report
Current view: top level - io_uring - openclose.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 114 0.0 %
Date: 2023-07-19 18:55:55 Functions: 0 9 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/fs.h>
       5             : #include <linux/file.h>
       6             : #include <linux/fdtable.h>
       7             : #include <linux/fsnotify.h>
       8             : #include <linux/namei.h>
       9             : #include <linux/io_uring.h>
      10             : 
      11             : #include <uapi/linux/io_uring.h>
      12             : 
      13             : #include "../fs/internal.h"
      14             : 
      15             : #include "io_uring.h"
      16             : #include "rsrc.h"
      17             : #include "openclose.h"
      18             : 
      19             : struct io_open {
      20             :         struct file                     *file;
      21             :         int                             dfd;
      22             :         u32                             file_slot;
      23             :         struct filename                 *filename;
      24             :         struct open_how                 how;
      25             :         unsigned long                   nofile;
      26             : };
      27             : 
      28             : struct io_close {
      29             :         struct file                     *file;
      30             :         int                             fd;
      31             :         u32                             file_slot;
      32             : };
      33             : 
      34             : static bool io_openat_force_async(struct io_open *open)
      35             : {
      36             :         /*
      37             :          * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open,
      38             :          * it'll always -EAGAIN
      39             :          */
      40           0 :         return open->how.flags & (O_TRUNC | O_CREAT | O_TMPFILE);
      41             : }
      42             : 
      43           0 : static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
      44             : {
      45           0 :         struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
      46             :         const char __user *fname;
      47             :         int ret;
      48             : 
      49           0 :         if (unlikely(sqe->buf_index))
      50             :                 return -EINVAL;
      51           0 :         if (unlikely(req->flags & REQ_F_FIXED_FILE))
      52             :                 return -EBADF;
      53             : 
      54             :         /* open.how should be already initialised */
      55           0 :         if (!(open->how.flags & O_PATH) && force_o_largefile())
      56           0 :                 open->how.flags |= O_LARGEFILE;
      57             : 
      58           0 :         open->dfd = READ_ONCE(sqe->fd);
      59           0 :         fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
      60           0 :         open->filename = getname(fname);
      61           0 :         if (IS_ERR(open->filename)) {
      62           0 :                 ret = PTR_ERR(open->filename);
      63           0 :                 open->filename = NULL;
      64           0 :                 return ret;
      65             :         }
      66             : 
      67           0 :         open->file_slot = READ_ONCE(sqe->file_index);
      68           0 :         if (open->file_slot && (open->how.flags & O_CLOEXEC))
      69             :                 return -EINVAL;
      70             : 
      71           0 :         open->nofile = rlimit(RLIMIT_NOFILE);
      72           0 :         req->flags |= REQ_F_NEED_CLEANUP;
      73           0 :         if (io_openat_force_async(open))
      74           0 :                 req->flags |= REQ_F_FORCE_ASYNC;
      75             :         return 0;
      76             : }
      77             : 
      78           0 : int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
      79             : {
      80           0 :         struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
      81           0 :         u64 mode = READ_ONCE(sqe->len);
      82           0 :         u64 flags = READ_ONCE(sqe->open_flags);
      83             : 
      84           0 :         open->how = build_open_how(flags, mode);
      85           0 :         return __io_openat_prep(req, sqe);
      86             : }
      87             : 
      88           0 : int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
      89             : {
      90           0 :         struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
      91             :         struct open_how __user *how;
      92             :         size_t len;
      93             :         int ret;
      94             : 
      95           0 :         how = u64_to_user_ptr(READ_ONCE(sqe->addr2));
      96           0 :         len = READ_ONCE(sqe->len);
      97           0 :         if (len < OPEN_HOW_SIZE_VER0)
      98             :                 return -EINVAL;
      99             : 
     100           0 :         ret = copy_struct_from_user(&open->how, sizeof(open->how), how, len);
     101           0 :         if (ret)
     102             :                 return ret;
     103             : 
     104           0 :         return __io_openat_prep(req, sqe);
     105             : }
     106             : 
     107           0 : int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
     108             : {
     109           0 :         struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
     110             :         struct open_flags op;
     111             :         struct file *file;
     112             :         bool resolve_nonblock, nonblock_set;
     113           0 :         bool fixed = !!open->file_slot;
     114             :         int ret;
     115             : 
     116           0 :         ret = build_open_flags(&open->how, &op);
     117           0 :         if (ret)
     118             :                 goto err;
     119           0 :         nonblock_set = op.open_flag & O_NONBLOCK;
     120           0 :         resolve_nonblock = open->how.resolve & RESOLVE_CACHED;
     121           0 :         if (issue_flags & IO_URING_F_NONBLOCK) {
     122           0 :                 WARN_ON_ONCE(io_openat_force_async(open));
     123           0 :                 op.lookup_flags |= LOOKUP_CACHED;
     124           0 :                 op.open_flag |= O_NONBLOCK;
     125             :         }
     126             : 
     127           0 :         if (!fixed) {
     128           0 :                 ret = __get_unused_fd_flags(open->how.flags, open->nofile);
     129           0 :                 if (ret < 0)
     130             :                         goto err;
     131             :         }
     132             : 
     133           0 :         file = do_filp_open(open->dfd, open->filename, &op);
     134           0 :         if (IS_ERR(file)) {
     135             :                 /*
     136             :                  * We could hang on to this 'fd' on retrying, but seems like
     137             :                  * marginal gain for something that is now known to be a slower
     138             :                  * path. So just put it, and we'll get a new one when we retry.
     139             :                  */
     140           0 :                 if (!fixed)
     141           0 :                         put_unused_fd(ret);
     142             : 
     143           0 :                 ret = PTR_ERR(file);
     144             :                 /* only retry if RESOLVE_CACHED wasn't already set by application */
     145           0 :                 if (ret == -EAGAIN &&
     146           0 :                     (!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))
     147             :                         return -EAGAIN;
     148             :                 goto err;
     149             :         }
     150             : 
     151           0 :         if ((issue_flags & IO_URING_F_NONBLOCK) && !nonblock_set)
     152           0 :                 file->f_flags &= ~O_NONBLOCK;
     153           0 :         fsnotify_open(file);
     154             : 
     155           0 :         if (!fixed)
     156           0 :                 fd_install(ret, file);
     157             :         else
     158           0 :                 ret = io_fixed_fd_install(req, issue_flags, file,
     159             :                                                 open->file_slot);
     160             : err:
     161           0 :         putname(open->filename);
     162           0 :         req->flags &= ~REQ_F_NEED_CLEANUP;
     163           0 :         if (ret < 0)
     164           0 :                 req_set_fail(req);
     165           0 :         io_req_set_res(req, ret, 0);
     166           0 :         return IOU_OK;
     167             : }
     168             : 
     169           0 : int io_openat(struct io_kiocb *req, unsigned int issue_flags)
     170             : {
     171           0 :         return io_openat2(req, issue_flags);
     172             : }
     173             : 
     174           0 : void io_open_cleanup(struct io_kiocb *req)
     175             : {
     176           0 :         struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
     177             : 
     178           0 :         if (open->filename)
     179           0 :                 putname(open->filename);
     180           0 : }
     181             : 
     182           0 : int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
     183             :                      unsigned int offset)
     184             : {
     185             :         int ret;
     186             : 
     187           0 :         io_ring_submit_lock(ctx, issue_flags);
     188           0 :         ret = io_fixed_fd_remove(ctx, offset);
     189           0 :         io_ring_submit_unlock(ctx, issue_flags);
     190             : 
     191           0 :         return ret;
     192             : }
     193             : 
     194             : static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags)
     195             : {
     196           0 :         struct io_close *close = io_kiocb_to_cmd(req, struct io_close);
     197             : 
     198           0 :         return __io_close_fixed(req->ctx, issue_flags, close->file_slot - 1);
     199             : }
     200             : 
     201           0 : int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
     202             : {
     203           0 :         struct io_close *close = io_kiocb_to_cmd(req, struct io_close);
     204             : 
     205           0 :         if (sqe->off || sqe->addr || sqe->len || sqe->rw_flags || sqe->buf_index)
     206             :                 return -EINVAL;
     207           0 :         if (req->flags & REQ_F_FIXED_FILE)
     208             :                 return -EBADF;
     209             : 
     210           0 :         close->fd = READ_ONCE(sqe->fd);
     211           0 :         close->file_slot = READ_ONCE(sqe->file_index);
     212           0 :         if (close->file_slot && close->fd)
     213             :                 return -EINVAL;
     214             : 
     215           0 :         return 0;
     216             : }
     217             : 
     218           0 : int io_close(struct io_kiocb *req, unsigned int issue_flags)
     219             : {
     220           0 :         struct files_struct *files = current->files;
     221           0 :         struct io_close *close = io_kiocb_to_cmd(req, struct io_close);
     222             :         struct fdtable *fdt;
     223             :         struct file *file;
     224           0 :         int ret = -EBADF;
     225             : 
     226           0 :         if (close->file_slot) {
     227           0 :                 ret = io_close_fixed(req, issue_flags);
     228           0 :                 goto err;
     229             :         }
     230             : 
     231           0 :         spin_lock(&files->file_lock);
     232           0 :         fdt = files_fdtable(files);
     233           0 :         if (close->fd >= fdt->max_fds) {
     234           0 :                 spin_unlock(&files->file_lock);
     235             :                 goto err;
     236             :         }
     237           0 :         file = rcu_dereference_protected(fdt->fd[close->fd],
     238             :                         lockdep_is_held(&files->file_lock));
     239           0 :         if (!file || io_is_uring_fops(file)) {
     240           0 :                 spin_unlock(&files->file_lock);
     241             :                 goto err;
     242             :         }
     243             : 
     244             :         /* if the file has a flush method, be safe and punt to async */
     245           0 :         if (file->f_op->flush && (issue_flags & IO_URING_F_NONBLOCK)) {
     246           0 :                 spin_unlock(&files->file_lock);
     247           0 :                 return -EAGAIN;
     248             :         }
     249             : 
     250           0 :         file = __close_fd_get_file(close->fd);
     251           0 :         spin_unlock(&files->file_lock);
     252           0 :         if (!file)
     253             :                 goto err;
     254             : 
     255             :         /* No ->flush() or already async, safely close from here */
     256           0 :         ret = filp_close(file, current->files);
     257             : err:
     258           0 :         if (ret < 0)
     259           0 :                 req_set_fail(req);
     260           0 :         io_req_set_res(req, ret, 0);
     261           0 :         return IOU_OK;
     262             : }

Generated by: LCOV version 1.14