162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/kernel.h> 362306a36Sopenharmony_ci#include <linux/errno.h> 462306a36Sopenharmony_ci#include <linux/fs.h> 562306a36Sopenharmony_ci#include <linux/file.h> 662306a36Sopenharmony_ci#include <linux/mm.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/namei.h> 962306a36Sopenharmony_ci#include <linux/io_uring.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <uapi/linux/fadvise.h> 1262306a36Sopenharmony_ci#include <uapi/linux/io_uring.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "io_uring.h" 1562306a36Sopenharmony_ci#include "advise.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct io_fadvise { 1862306a36Sopenharmony_ci struct file *file; 1962306a36Sopenharmony_ci u64 offset; 2062306a36Sopenharmony_ci u32 len; 2162306a36Sopenharmony_ci u32 advice; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct io_madvise { 2562306a36Sopenharmony_ci struct file *file; 2662306a36Sopenharmony_ci u64 addr; 2762306a36Sopenharmony_ci u32 len; 2862306a36Sopenharmony_ci u32 advice; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci#if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU) 3462306a36Sopenharmony_ci struct io_madvise *ma = io_kiocb_to_cmd(req, struct io_madvise); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (sqe->buf_index || sqe->off || sqe->splice_fd_in) 3762306a36Sopenharmony_ci return -EINVAL; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ma->addr = READ_ONCE(sqe->addr); 4062306a36Sopenharmony_ci ma->len = READ_ONCE(sqe->len); 4162306a36Sopenharmony_ci ma->advice = READ_ONCE(sqe->fadvise_advice); 4262306a36Sopenharmony_ci req->flags |= REQ_F_FORCE_ASYNC; 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci#else 4562306a36Sopenharmony_ci return -EOPNOTSUPP; 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciint io_madvise(struct io_kiocb *req, unsigned int issue_flags) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci#if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU) 5262306a36Sopenharmony_ci struct io_madvise *ma = io_kiocb_to_cmd(req, struct io_madvise); 5362306a36Sopenharmony_ci int ret; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ret = do_madvise(current->mm, ma->addr, ma->len, ma->advice); 5862306a36Sopenharmony_ci io_req_set_res(req, ret, 0); 5962306a36Sopenharmony_ci return IOU_OK; 6062306a36Sopenharmony_ci#else 6162306a36Sopenharmony_ci return -EOPNOTSUPP; 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic bool io_fadvise_force_async(struct io_fadvise *fa) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci switch (fa->advice) { 6862306a36Sopenharmony_ci case POSIX_FADV_NORMAL: 6962306a36Sopenharmony_ci case POSIX_FADV_RANDOM: 7062306a36Sopenharmony_ci case POSIX_FADV_SEQUENTIAL: 7162306a36Sopenharmony_ci return false; 7262306a36Sopenharmony_ci default: 7362306a36Sopenharmony_ci return true; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciint io_fadvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct io_fadvise *fa = io_kiocb_to_cmd(req, struct io_fadvise); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (sqe->buf_index || sqe->addr || sqe->splice_fd_in) 8262306a36Sopenharmony_ci return -EINVAL; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci fa->offset = READ_ONCE(sqe->off); 8562306a36Sopenharmony_ci fa->len = READ_ONCE(sqe->len); 8662306a36Sopenharmony_ci fa->advice = READ_ONCE(sqe->fadvise_advice); 8762306a36Sopenharmony_ci if (io_fadvise_force_async(fa)) 8862306a36Sopenharmony_ci req->flags |= REQ_F_FORCE_ASYNC; 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciint io_fadvise(struct io_kiocb *req, unsigned int issue_flags) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct io_fadvise *fa = io_kiocb_to_cmd(req, struct io_fadvise); 9562306a36Sopenharmony_ci int ret; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK && io_fadvise_force_async(fa)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = vfs_fadvise(req->file, fa->offset, fa->len, fa->advice); 10062306a36Sopenharmony_ci if (ret < 0) 10162306a36Sopenharmony_ci req_set_fail(req); 10262306a36Sopenharmony_ci io_req_set_res(req, ret, 0); 10362306a36Sopenharmony_ci return IOU_OK; 10462306a36Sopenharmony_ci} 105