162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/kernel.h>
362306a36Sopenharmony_ci#include <linux/errno.h>
462306a36Sopenharmony_ci#include <linux/file.h>
562306a36Sopenharmony_ci#include <linux/io_uring.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <uapi/linux/io_uring.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "../fs/internal.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "io_uring.h"
1262306a36Sopenharmony_ci#include "statx.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct io_statx {
1562306a36Sopenharmony_ci	struct file			*file;
1662306a36Sopenharmony_ci	int				dfd;
1762306a36Sopenharmony_ci	unsigned int			mask;
1862306a36Sopenharmony_ci	unsigned int			flags;
1962306a36Sopenharmony_ci	struct filename			*filename;
2062306a36Sopenharmony_ci	struct statx __user		*buffer;
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ciint io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
2662306a36Sopenharmony_ci	const char __user *path;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (sqe->buf_index || sqe->splice_fd_in)
2962306a36Sopenharmony_ci		return -EINVAL;
3062306a36Sopenharmony_ci	if (req->flags & REQ_F_FIXED_FILE)
3162306a36Sopenharmony_ci		return -EBADF;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	sx->dfd = READ_ONCE(sqe->fd);
3462306a36Sopenharmony_ci	sx->mask = READ_ONCE(sqe->len);
3562306a36Sopenharmony_ci	path = u64_to_user_ptr(READ_ONCE(sqe->addr));
3662306a36Sopenharmony_ci	sx->buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2));
3762306a36Sopenharmony_ci	sx->flags = READ_ONCE(sqe->statx_flags);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	sx->filename = getname_flags(path,
4062306a36Sopenharmony_ci				     getname_statx_lookup_flags(sx->flags),
4162306a36Sopenharmony_ci				     NULL);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (IS_ERR(sx->filename)) {
4462306a36Sopenharmony_ci		int ret = PTR_ERR(sx->filename);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		sx->filename = NULL;
4762306a36Sopenharmony_ci		return ret;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	req->flags |= REQ_F_NEED_CLEANUP;
5162306a36Sopenharmony_ci	req->flags |= REQ_F_FORCE_ASYNC;
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciint io_statx(struct io_kiocb *req, unsigned int issue_flags)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
5862306a36Sopenharmony_ci	int ret;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	ret = do_statx(sx->dfd, sx->filename, sx->flags, sx->mask, sx->buffer);
6362306a36Sopenharmony_ci	io_req_set_res(req, ret, 0);
6462306a36Sopenharmony_ci	return IOU_OK;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_civoid io_statx_cleanup(struct io_kiocb *req)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (sx->filename)
7262306a36Sopenharmony_ci		putname(sx->filename);
7362306a36Sopenharmony_ci}
74