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