···9898#include "splice.h"9999#include "sync.h"100100#include "advise.h"101101+#include "openclose.h"101102102103#define IORING_MAX_ENTRIES 32768103104#define IORING_MAX_CQ_ENTRIES (2 * IORING_MAX_ENTRIES)···284283 bool update_user_data;285284};286285287287-struct io_close {288288- struct file *file;289289- int fd;290290- u32 file_slot;291291-};292292-293286struct io_timeout_data {294287 struct io_kiocb *req;295288 struct hrtimer timer;···364369 size_t len;365370 size_t done_io;366371 unsigned int flags;367367-};368368-369369-struct io_open {370370- struct file *file;371371- int dfd;372372- u32 file_slot;373373- struct filename *filename;374374- struct open_how how;375375- unsigned long nofile;376372};377373378374struct io_rsrc_update {···541555542556static int io_install_fixed_file(struct io_kiocb *req, struct file *file,543557 unsigned int issue_flags, u32 slot_index);544544-static int __io_close_fixed(struct io_kiocb *req, unsigned int issue_flags,545545- unsigned int offset);546546-static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags);547558548559static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer);549560static void io_eventfd_signal(struct io_ring_ctx *ctx);···653670 return "INVALID";654671}655672673673+bool io_is_uring_fops(struct file *file)674674+{675675+ return file->f_op == &io_uring_fops;676676+}677677+656678struct sock *io_uring_get_socket(struct file *file)657679{658680#if defined(CONFIG_UNIX)659659- if (file->f_op == &io_uring_fops) {681681+ if (io_is_uring_fops(file)) {660682 struct io_ring_ctx *ctx = file->private_data;661683662684 return ctx->ring_sock->sk;···686698 return false;687699}688700#endif689689-690690-static void io_ring_submit_unlock(struct io_ring_ctx *ctx, unsigned issue_flags)691691-{692692- lockdep_assert_held(&ctx->uring_lock);693693- if (issue_flags & IO_URING_F_UNLOCKED)694694- mutex_unlock(&ctx->uring_lock);695695-}696696-697697-static void io_ring_submit_lock(struct io_ring_ctx *ctx, unsigned issue_flags)698698-{699699- /*700700- * "Normal" inline submissions always hold the uring_lock, since we701701- * grab it from the system call. Same is true for the SQPOLL offload.702702- * The only exception is when we've detached the request and issue it703703- * from an async worker thread, grab the lock for that case.704704- */705705- if (issue_flags & IO_URING_F_UNLOCKED)706706- mutex_lock(&ctx->uring_lock);707707- lockdep_assert_held(&ctx->uring_lock);708708-}709701710702static inline void io_tw_lock(struct io_ring_ctx *ctx, bool *locked)711703{···38673899 return IOU_OK;38683900}3869390138703870-static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)38713871-{38723872- struct io_open *open = io_kiocb_to_cmd(req);38733873- const char __user *fname;38743874- int ret;38753875-38763876- if (unlikely(sqe->buf_index))38773877- return -EINVAL;38783878- if (unlikely(req->flags & REQ_F_FIXED_FILE))38793879- return -EBADF;38803880-38813881- /* open.how should be already initialised */38823882- if (!(open->how.flags & O_PATH) && force_o_largefile())38833883- open->how.flags |= O_LARGEFILE;38843884-38853885- open->dfd = READ_ONCE(sqe->fd);38863886- fname = u64_to_user_ptr(READ_ONCE(sqe->addr));38873887- open->filename = getname(fname);38883888- if (IS_ERR(open->filename)) {38893889- ret = PTR_ERR(open->filename);38903890- open->filename = NULL;38913891- return ret;38923892- }38933893-38943894- open->file_slot = READ_ONCE(sqe->file_index);38953895- if (open->file_slot && (open->how.flags & O_CLOEXEC))38963896- return -EINVAL;38973897-38983898- open->nofile = rlimit(RLIMIT_NOFILE);38993899- req->flags |= REQ_F_NEED_CLEANUP;39003900- return 0;39013901-}39023902-39033903-static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)39043904-{39053905- struct io_open *open = io_kiocb_to_cmd(req);39063906- u64 mode = READ_ONCE(sqe->len);39073907- u64 flags = READ_ONCE(sqe->open_flags);39083908-39093909- open->how = build_open_how(flags, mode);39103910- return __io_openat_prep(req, sqe);39113911-}39123912-39133913-static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)39143914-{39153915- struct io_open *open = io_kiocb_to_cmd(req);39163916- struct open_how __user *how;39173917- size_t len;39183918- int ret;39193919-39203920- how = u64_to_user_ptr(READ_ONCE(sqe->addr2));39213921- len = READ_ONCE(sqe->len);39223922- if (len < OPEN_HOW_SIZE_VER0)39233923- return -EINVAL;39243924-39253925- ret = copy_struct_from_user(&open->how, sizeof(open->how), how, len);39263926- if (ret)39273927- return ret;39283928-39293929- return __io_openat_prep(req, sqe);39303930-}39313931-39323902/*39333903 * Note when io_fixed_fd_install() returns error value, it will ensure39343904 * fput() is called correspondingly.39353905 */39363936-static int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,39373937- struct file *file, unsigned int file_slot)39063906+int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,39073907+ struct file *file, unsigned int file_slot)39383908{39393909 bool alloc_slot = file_slot == IORING_FILE_INDEX_ALLOC;39403910 struct io_ring_ctx *ctx = req->ctx;···38973991 if (unlikely(ret < 0))38983992 fput(file);38993993 return ret;39003900-}39013901-39023902-static int io_openat2(struct io_kiocb *req, unsigned int issue_flags)39033903-{39043904- struct io_open *open = io_kiocb_to_cmd(req);39053905- struct open_flags op;39063906- struct file *file;39073907- bool resolve_nonblock, nonblock_set;39083908- bool fixed = !!open->file_slot;39093909- int ret;39103910-39113911- ret = build_open_flags(&open->how, &op);39123912- if (ret)39133913- goto err;39143914- nonblock_set = op.open_flag & O_NONBLOCK;39153915- resolve_nonblock = open->how.resolve & RESOLVE_CACHED;39163916- if (issue_flags & IO_URING_F_NONBLOCK) {39173917- /*39183918- * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open,39193919- * it'll always -EAGAIN39203920- */39213921- if (open->how.flags & (O_TRUNC | O_CREAT | O_TMPFILE))39223922- return -EAGAIN;39233923- op.lookup_flags |= LOOKUP_CACHED;39243924- op.open_flag |= O_NONBLOCK;39253925- }39263926-39273927- if (!fixed) {39283928- ret = __get_unused_fd_flags(open->how.flags, open->nofile);39293929- if (ret < 0)39303930- goto err;39313931- }39323932-39333933- file = do_filp_open(open->dfd, open->filename, &op);39343934- if (IS_ERR(file)) {39353935- /*39363936- * We could hang on to this 'fd' on retrying, but seems like39373937- * marginal gain for something that is now known to be a slower39383938- * path. So just put it, and we'll get a new one when we retry.39393939- */39403940- if (!fixed)39413941- put_unused_fd(ret);39423942-39433943- ret = PTR_ERR(file);39443944- /* only retry if RESOLVE_CACHED wasn't already set by application */39453945- if (ret == -EAGAIN &&39463946- (!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))39473947- return -EAGAIN;39483948- goto err;39493949- }39503950-39513951- if ((issue_flags & IO_URING_F_NONBLOCK) && !nonblock_set)39523952- file->f_flags &= ~O_NONBLOCK;39533953- fsnotify_open(file);39543954-39553955- if (!fixed)39563956- fd_install(ret, file);39573957- else39583958- ret = io_fixed_fd_install(req, issue_flags, file,39593959- open->file_slot);39603960-err:39613961- putname(open->filename);39623962- req->flags &= ~REQ_F_NEED_CLEANUP;39633963- if (ret < 0)39643964- req_set_fail(req);39653965- io_req_set_res(req, ret, 0);39663966- return IOU_OK;39673967-}39683968-39693969-static int io_openat(struct io_kiocb *req, unsigned int issue_flags)39703970-{39713971- return io_openat2(req, issue_flags);39723972-}39733973-39743974-static void io_open_cleanup(struct io_kiocb *req)39753975-{39763976- struct io_open *open = io_kiocb_to_cmd(req);39773977-39783978- if (open->filename)39793979- putname(open->filename);39803994}3981399539823996static int io_remove_buffers_prep(struct io_kiocb *req,···4248442242494423 if (sx->filename)42504424 putname(sx->filename);42514251-}42524252-42534253-static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)42544254-{42554255- struct io_close *close = io_kiocb_to_cmd(req);42564256-42574257- if (sqe->off || sqe->addr || sqe->len || sqe->rw_flags || sqe->buf_index)42584258- return -EINVAL;42594259- if (req->flags & REQ_F_FIXED_FILE)42604260- return -EBADF;42614261-42624262- close->fd = READ_ONCE(sqe->fd);42634263- close->file_slot = READ_ONCE(sqe->file_index);42644264- if (close->file_slot && close->fd)42654265- return -EINVAL;42664266-42674267- return 0;42684268-}42694269-42704270-static int io_close(struct io_kiocb *req, unsigned int issue_flags)42714271-{42724272- struct files_struct *files = current->files;42734273- struct io_close *close = io_kiocb_to_cmd(req);42744274- struct fdtable *fdt;42754275- struct file *file;42764276- int ret = -EBADF;42774277-42784278- if (close->file_slot) {42794279- ret = io_close_fixed(req, issue_flags);42804280- goto err;42814281- }42824282-42834283- spin_lock(&files->file_lock);42844284- fdt = files_fdtable(files);42854285- if (close->fd >= fdt->max_fds) {42864286- spin_unlock(&files->file_lock);42874287- goto err;42884288- }42894289- file = rcu_dereference_protected(fdt->fd[close->fd],42904290- lockdep_is_held(&files->file_lock));42914291- if (!file || file->f_op == &io_uring_fops) {42924292- spin_unlock(&files->file_lock);42934293- goto err;42944294- }42954295-42964296- /* if the file has a flush method, be safe and punt to async */42974297- if (file->f_op->flush && (issue_flags & IO_URING_F_NONBLOCK)) {42984298- spin_unlock(&files->file_lock);42994299- return -EAGAIN;43004300- }43014301-43024302- file = __close_fd_get_file(close->fd);43034303- spin_unlock(&files->file_lock);43044304- if (!file)43054305- goto err;43064306-43074307- /* No ->flush() or already async, safely close from here */43084308- ret = filp_close(file, current->files);43094309-err:43104310- if (ret < 0)43114311- req_set_fail(req);43124312- io_req_set_res(req, ret, 0);43134313- return IOU_OK;43144425}4315442643164427#if defined(CONFIG_NET)···75077744 return ref_node;75087745}7509774675107510-static void io_rsrc_node_switch(struct io_ring_ctx *ctx,75117511- struct io_rsrc_data *data_to_kill)77477747+void io_rsrc_node_switch(struct io_ring_ctx *ctx,77487748+ struct io_rsrc_data *data_to_kill)75127749 __must_hold(&ctx->uring_lock)75137750{75147751 WARN_ON_ONCE(!ctx->rsrc_backup_node);···75357772 }75367773}7537777475387538-static int io_rsrc_node_switch_start(struct io_ring_ctx *ctx)77757775+int io_rsrc_node_switch_start(struct io_ring_ctx *ctx)75397776{75407777 if (ctx->rsrc_backup_node)75417778 return 0;···80828319 return ret;80838320}8084832180858085-static int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,80868086- struct io_rsrc_node *node, void *rsrc)83228322+int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,83238323+ struct io_rsrc_node *node, void *rsrc)80878324{80888325 u64 *tag_slot = io_get_tag_slot(data, idx);80898326 struct io_rsrc_put *prsrc;···81478384 if (ret)81488385 fput(file);81498386 return ret;81508150-}81518151-81528152-static int __io_close_fixed(struct io_kiocb *req, unsigned int issue_flags,81538153- unsigned int offset)81548154-{81558155- struct io_ring_ctx *ctx = req->ctx;81568156- struct io_fixed_file *file_slot;81578157- struct file *file;81588158- int ret;81598159-81608160- io_ring_submit_lock(ctx, issue_flags);81618161- ret = -ENXIO;81628162- if (unlikely(!ctx->file_data))81638163- goto out;81648164- ret = -EINVAL;81658165- if (offset >= ctx->nr_user_files)81668166- goto out;81678167- ret = io_rsrc_node_switch_start(ctx);81688168- if (ret)81698169- goto out;81708170-81718171- offset = array_index_nospec(offset, ctx->nr_user_files);81728172- file_slot = io_fixed_file_slot(&ctx->file_table, offset);81738173- ret = -EBADF;81748174- if (!file_slot->file_ptr)81758175- goto out;81768176-81778177- file = (struct file *)(file_slot->file_ptr & FFS_MASK);81788178- ret = io_queue_rsrc_removal(ctx->file_data, offset, ctx->rsrc_node, file);81798179- if (ret)81808180- goto out;81818181-81828182- file_slot->file_ptr = 0;81838183- io_file_bitmap_clear(&ctx->file_table, offset);81848184- io_rsrc_node_switch(ctx, ctx->file_data);81858185- ret = 0;81868186-out:81878187- io_ring_submit_unlock(ctx, issue_flags);81888188- return ret;81898189-}81908190-81918191-static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags)81928192-{81938193- struct io_close *close = io_kiocb_to_cmd(req);81948194-81958195- return __io_close_fixed(req, issue_flags, close->file_slot - 1);81968387}8197838881988389static int __io_sqe_files_update(struct io_ring_ctx *ctx,
+32
io_uring/io_uring.h
···22#define IOU_CORE_H3344#include <linux/errno.h>55+#include <linux/lockdep.h>56#include "io_uring_types.h"6778enum {···3130 fput(file);3231}33323333+static inline void io_ring_submit_unlock(struct io_ring_ctx *ctx,3434+ unsigned issue_flags)3535+{3636+ lockdep_assert_held(&ctx->uring_lock);3737+ if (issue_flags & IO_URING_F_UNLOCKED)3838+ mutex_unlock(&ctx->uring_lock);3939+}4040+4141+static inline void io_ring_submit_lock(struct io_ring_ctx *ctx,4242+ unsigned issue_flags)4343+{4444+ /*4545+ * "Normal" inline submissions always hold the uring_lock, since we4646+ * grab it from the system call. Same is true for the SQPOLL offload.4747+ * The only exception is when we've detached the request and issue it4848+ * from an async worker thread, grab the lock for that case.4949+ */5050+ if (issue_flags & IO_URING_F_UNLOCKED)5151+ mutex_lock(&ctx->uring_lock);5252+ lockdep_assert_held(&ctx->uring_lock);5353+}5454+3455struct file *io_file_get_normal(struct io_kiocb *req, int fd);3556struct file *io_file_get_fixed(struct io_kiocb *req, int fd,3657 unsigned issue_flags);5858+int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,5959+ struct file *file, unsigned int file_slot);6060+6161+int io_rsrc_node_switch_start(struct io_ring_ctx *ctx);6262+int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,6363+ struct io_rsrc_node *node, void *rsrc);6464+void io_rsrc_node_switch(struct io_ring_ctx *ctx,6565+ struct io_rsrc_data *data_to_kill);6666+bool io_is_uring_fops(struct file *file);37673868#endif
+283
io_uring/openclose.c
···11+// SPDX-License-Identifier: GPL-2.022+#include <linux/kernel.h>33+#include <linux/errno.h>44+#include <linux/fs.h>55+#include <linux/file.h>66+#include <linux/fdtable.h>77+#include <linux/fsnotify.h>88+#include <linux/namei.h>99+#include <linux/io_uring.h>1010+1111+#include <uapi/linux/io_uring.h>1212+1313+#include "../fs/internal.h"1414+1515+#include "io_uring_types.h"1616+#include "io_uring.h"1717+#include "openclose.h"1818+1919+struct io_open {2020+ struct file *file;2121+ int dfd;2222+ u32 file_slot;2323+ struct filename *filename;2424+ struct open_how how;2525+ unsigned long nofile;2626+};2727+2828+struct io_close {2929+ struct file *file;3030+ int fd;3131+ u32 file_slot;3232+};3333+3434+static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)3535+{3636+ struct io_open *open = io_kiocb_to_cmd(req);3737+ const char __user *fname;3838+ int ret;3939+4040+ if (unlikely(sqe->buf_index))4141+ return -EINVAL;4242+ if (unlikely(req->flags & REQ_F_FIXED_FILE))4343+ return -EBADF;4444+4545+ /* open.how should be already initialised */4646+ if (!(open->how.flags & O_PATH) && force_o_largefile())4747+ open->how.flags |= O_LARGEFILE;4848+4949+ open->dfd = READ_ONCE(sqe->fd);5050+ fname = u64_to_user_ptr(READ_ONCE(sqe->addr));5151+ open->filename = getname(fname);5252+ if (IS_ERR(open->filename)) {5353+ ret = PTR_ERR(open->filename);5454+ open->filename = NULL;5555+ return ret;5656+ }5757+5858+ open->file_slot = READ_ONCE(sqe->file_index);5959+ if (open->file_slot && (open->how.flags & O_CLOEXEC))6060+ return -EINVAL;6161+6262+ open->nofile = rlimit(RLIMIT_NOFILE);6363+ req->flags |= REQ_F_NEED_CLEANUP;6464+ return 0;6565+}6666+6767+int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)6868+{6969+ struct io_open *open = io_kiocb_to_cmd(req);7070+ u64 mode = READ_ONCE(sqe->len);7171+ u64 flags = READ_ONCE(sqe->open_flags);7272+7373+ open->how = build_open_how(flags, mode);7474+ return __io_openat_prep(req, sqe);7575+}7676+7777+int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)7878+{7979+ struct io_open *open = io_kiocb_to_cmd(req);8080+ struct open_how __user *how;8181+ size_t len;8282+ int ret;8383+8484+ how = u64_to_user_ptr(READ_ONCE(sqe->addr2));8585+ len = READ_ONCE(sqe->len);8686+ if (len < OPEN_HOW_SIZE_VER0)8787+ return -EINVAL;8888+8989+ ret = copy_struct_from_user(&open->how, sizeof(open->how), how, len);9090+ if (ret)9191+ return ret;9292+9393+ return __io_openat_prep(req, sqe);9494+}9595+9696+int io_openat2(struct io_kiocb *req, unsigned int issue_flags)9797+{9898+ struct io_open *open = io_kiocb_to_cmd(req);9999+ struct open_flags op;100100+ struct file *file;101101+ bool resolve_nonblock, nonblock_set;102102+ bool fixed = !!open->file_slot;103103+ int ret;104104+105105+ ret = build_open_flags(&open->how, &op);106106+ if (ret)107107+ goto err;108108+ nonblock_set = op.open_flag & O_NONBLOCK;109109+ resolve_nonblock = open->how.resolve & RESOLVE_CACHED;110110+ if (issue_flags & IO_URING_F_NONBLOCK) {111111+ /*112112+ * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open,113113+ * it'll always -EAGAIN114114+ */115115+ if (open->how.flags & (O_TRUNC | O_CREAT | O_TMPFILE))116116+ return -EAGAIN;117117+ op.lookup_flags |= LOOKUP_CACHED;118118+ op.open_flag |= O_NONBLOCK;119119+ }120120+121121+ if (!fixed) {122122+ ret = __get_unused_fd_flags(open->how.flags, open->nofile);123123+ if (ret < 0)124124+ goto err;125125+ }126126+127127+ file = do_filp_open(open->dfd, open->filename, &op);128128+ if (IS_ERR(file)) {129129+ /*130130+ * We could hang on to this 'fd' on retrying, but seems like131131+ * marginal gain for something that is now known to be a slower132132+ * path. So just put it, and we'll get a new one when we retry.133133+ */134134+ if (!fixed)135135+ put_unused_fd(ret);136136+137137+ ret = PTR_ERR(file);138138+ /* only retry if RESOLVE_CACHED wasn't already set by application */139139+ if (ret == -EAGAIN &&140140+ (!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))141141+ return -EAGAIN;142142+ goto err;143143+ }144144+145145+ if ((issue_flags & IO_URING_F_NONBLOCK) && !nonblock_set)146146+ file->f_flags &= ~O_NONBLOCK;147147+ fsnotify_open(file);148148+149149+ if (!fixed)150150+ fd_install(ret, file);151151+ else152152+ ret = io_fixed_fd_install(req, issue_flags, file,153153+ open->file_slot);154154+err:155155+ putname(open->filename);156156+ req->flags &= ~REQ_F_NEED_CLEANUP;157157+ if (ret < 0)158158+ req_set_fail(req);159159+ io_req_set_res(req, ret, 0);160160+ return IOU_OK;161161+}162162+163163+int io_openat(struct io_kiocb *req, unsigned int issue_flags)164164+{165165+ return io_openat2(req, issue_flags);166166+}167167+168168+void io_open_cleanup(struct io_kiocb *req)169169+{170170+ struct io_open *open = io_kiocb_to_cmd(req);171171+172172+ if (open->filename)173173+ putname(open->filename);174174+}175175+176176+int __io_close_fixed(struct io_kiocb *req, unsigned int issue_flags,177177+ unsigned int offset)178178+{179179+ struct io_ring_ctx *ctx = req->ctx;180180+ struct io_fixed_file *file_slot;181181+ struct file *file;182182+ int ret;183183+184184+ io_ring_submit_lock(ctx, issue_flags);185185+ ret = -ENXIO;186186+ if (unlikely(!ctx->file_data))187187+ goto out;188188+ ret = -EINVAL;189189+ if (offset >= ctx->nr_user_files)190190+ goto out;191191+ ret = io_rsrc_node_switch_start(ctx);192192+ if (ret)193193+ goto out;194194+195195+ offset = array_index_nospec(offset, ctx->nr_user_files);196196+ file_slot = io_fixed_file_slot(&ctx->file_table, offset);197197+ ret = -EBADF;198198+ if (!file_slot->file_ptr)199199+ goto out;200200+201201+ file = (struct file *)(file_slot->file_ptr & FFS_MASK);202202+ ret = io_queue_rsrc_removal(ctx->file_data, offset, ctx->rsrc_node, file);203203+ if (ret)204204+ goto out;205205+206206+ file_slot->file_ptr = 0;207207+ io_file_bitmap_clear(&ctx->file_table, offset);208208+ io_rsrc_node_switch(ctx, ctx->file_data);209209+ ret = 0;210210+out:211211+ io_ring_submit_unlock(ctx, issue_flags);212212+ return ret;213213+}214214+215215+static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags)216216+{217217+ struct io_close *close = io_kiocb_to_cmd(req);218218+219219+ return __io_close_fixed(req, issue_flags, close->file_slot - 1);220220+}221221+222222+int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)223223+{224224+ struct io_close *close = io_kiocb_to_cmd(req);225225+226226+ if (sqe->off || sqe->addr || sqe->len || sqe->rw_flags || sqe->buf_index)227227+ return -EINVAL;228228+ if (req->flags & REQ_F_FIXED_FILE)229229+ return -EBADF;230230+231231+ close->fd = READ_ONCE(sqe->fd);232232+ close->file_slot = READ_ONCE(sqe->file_index);233233+ if (close->file_slot && close->fd)234234+ return -EINVAL;235235+236236+ return 0;237237+}238238+239239+int io_close(struct io_kiocb *req, unsigned int issue_flags)240240+{241241+ struct files_struct *files = current->files;242242+ struct io_close *close = io_kiocb_to_cmd(req);243243+ struct fdtable *fdt;244244+ struct file *file;245245+ int ret = -EBADF;246246+247247+ if (close->file_slot) {248248+ ret = io_close_fixed(req, issue_flags);249249+ goto err;250250+ }251251+252252+ spin_lock(&files->file_lock);253253+ fdt = files_fdtable(files);254254+ if (close->fd >= fdt->max_fds) {255255+ spin_unlock(&files->file_lock);256256+ goto err;257257+ }258258+ file = rcu_dereference_protected(fdt->fd[close->fd],259259+ lockdep_is_held(&files->file_lock));260260+ if (!file || io_is_uring_fops(file)) {261261+ spin_unlock(&files->file_lock);262262+ goto err;263263+ }264264+265265+ /* if the file has a flush method, be safe and punt to async */266266+ if (file->f_op->flush && (issue_flags & IO_URING_F_NONBLOCK)) {267267+ spin_unlock(&files->file_lock);268268+ return -EAGAIN;269269+ }270270+271271+ file = __close_fd_get_file(close->fd);272272+ spin_unlock(&files->file_lock);273273+ if (!file)274274+ goto err;275275+276276+ /* No ->flush() or already async, safely close from here */277277+ ret = filp_close(file, current->files);278278+err:279279+ if (ret < 0)280280+ req_set_fail(req);281281+ io_req_set_res(req, ret, 0);282282+ return IOU_OK;283283+}