* [PATCH v6 1/3] fs: split off do_iterate_dir from iterate_dir function
2021-12-15 21:59 [PATCH v6 0/3] io_uring: add getdents64 support Stefan Roesch
@ 2021-12-15 21:59 ` Stefan Roesch
2021-12-15 21:59 ` [PATCH v6 2/3] fs: split off vfs_getdents function of getdents64 syscall Stefan Roesch
2021-12-15 21:59 ` [PATCH v6 3/3] io_uring: add support for getdents64 Stefan Roesch
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Roesch @ 2021-12-15 21:59 UTC (permalink / raw)
To: io-uring, linux-fsdevel; +Cc: viro, shr
This splits of the function do_iterate_dir() from the iterate_dir()
function and adds a new parameter. The new parameter allows the
caller to specify if the position is the file position or the
position stored in the buffer context.
The function iterate_dir is calling the new function do_iterate_dir().
This change is required to support getdents in io_uring.
Signed-off-by: Stefan Roesch <[email protected]>
---
fs/readdir.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/fs/readdir.c b/fs/readdir.c
index 09e8ed7d4161..e9c197edf73a 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -36,8 +36,15 @@
unsafe_copy_to_user(dst, src, len, label); \
} while (0)
-
-int iterate_dir(struct file *file, struct dir_context *ctx)
+/**
+ * do_iterate_dir - iterate over directory
+ * @file : pointer to file struct of directory
+ * @ctx : pointer to directory ctx structure
+ * @use_fpos: true : use file offset
+ * false: use pos in ctx structure
+ */
+static int do_iterate_dir(struct file *file, struct dir_context *ctx,
+ bool use_fpos)
{
struct inode *inode = file_inode(file);
bool shared = false;
@@ -60,12 +67,17 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
res = -ENOENT;
if (!IS_DEADDIR(inode)) {
- ctx->pos = file->f_pos;
+ if (use_fpos)
+ ctx->pos = file->f_pos;
+
if (shared)
res = file->f_op->iterate_shared(file, ctx);
else
res = file->f_op->iterate(file, ctx);
- file->f_pos = ctx->pos;
+
+ if (use_fpos)
+ file->f_pos = ctx->pos;
+
fsnotify_access(file);
file_accessed(file);
}
@@ -76,6 +88,11 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
out:
return res;
}
+
+int iterate_dir(struct file *file, struct dir_context *ctx)
+{
+ return do_iterate_dir(file, ctx, true);
+}
EXPORT_SYMBOL(iterate_dir);
/*
--
2.30.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v6 2/3] fs: split off vfs_getdents function of getdents64 syscall
2021-12-15 21:59 [PATCH v6 0/3] io_uring: add getdents64 support Stefan Roesch
2021-12-15 21:59 ` [PATCH v6 1/3] fs: split off do_iterate_dir from iterate_dir function Stefan Roesch
@ 2021-12-15 21:59 ` Stefan Roesch
2021-12-15 21:59 ` [PATCH v6 3/3] io_uring: add support for getdents64 Stefan Roesch
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Roesch @ 2021-12-15 21:59 UTC (permalink / raw)
To: io-uring, linux-fsdevel; +Cc: viro, shr, Christian Brauner
This splits off the vfs_getdents function from the getdents64 system
call. This allows io_uring to call the function.
Signed-off-by: Stefan Roesch <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/internal.h | 8 ++++++++
fs/readdir.c | 37 +++++++++++++++++++++++++++++--------
2 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/fs/internal.h b/fs/internal.h
index 7979ff8d168c..355be993b9f1 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -194,3 +194,11 @@ long splice_file_to_pipe(struct file *in,
struct pipe_inode_info *opipe,
loff_t *offset,
size_t len, unsigned int flags);
+
+/*
+ * fs/readdir.c
+ */
+struct linux_dirent64;
+
+int vfs_getdents(struct file *file, struct linux_dirent64 __user *dirent,
+ unsigned int count, s64 pos);
diff --git a/fs/readdir.c b/fs/readdir.c
index e9c197edf73a..5c3af16a6178 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -21,6 +21,7 @@
#include <linux/unistd.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
+#include "internal.h"
#include <asm/unaligned.h>
@@ -368,22 +369,26 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
return -EFAULT;
}
-SYSCALL_DEFINE3(getdents64, unsigned int, fd,
- struct linux_dirent64 __user *, dirent, unsigned int, count)
+/**
+ * vfs_getdents - getdents without fdget
+ * @file : pointer to file struct of directory
+ * @dirent : pointer to user directory structure
+ * @count : size of buffer
+ * @ctx_pos : if file pos is used, pass -1,
+ * if ctx pos is used, pass ctx pos
+ */
+int vfs_getdents(struct file *file, struct linux_dirent64 __user *dirent,
+ unsigned int count, s64 ctx_pos)
{
- struct fd f;
struct getdents_callback64 buf = {
.ctx.actor = filldir64,
+ .ctx.pos = ctx_pos,
.count = count,
.current_dir = dirent
};
int error;
- f = fdget_pos(fd);
- if (!f.file)
- return -EBADF;
-
- error = iterate_dir(f.file, &buf.ctx);
+ error = do_iterate_dir(file, &buf.ctx, ctx_pos < 0);
if (error >= 0)
error = buf.error;
if (buf.prev_reclen) {
@@ -396,6 +401,22 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
else
error = count - buf.count;
}
+
+ return error;
+}
+
+SYSCALL_DEFINE3(getdents64, unsigned int, fd,
+ struct linux_dirent64 __user *, dirent, unsigned int, count)
+{
+ struct fd f;
+ int error;
+
+ f = fdget_pos(fd);
+ if (!f.file)
+ return -EBADF;
+
+ error = vfs_getdents(f.file, dirent, count, -1);
+
fdput_pos(f);
return error;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v6 3/3] io_uring: add support for getdents64
2021-12-15 21:59 [PATCH v6 0/3] io_uring: add getdents64 support Stefan Roesch
2021-12-15 21:59 ` [PATCH v6 1/3] fs: split off do_iterate_dir from iterate_dir function Stefan Roesch
2021-12-15 21:59 ` [PATCH v6 2/3] fs: split off vfs_getdents function of getdents64 syscall Stefan Roesch
@ 2021-12-15 21:59 ` Stefan Roesch
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Roesch @ 2021-12-15 21:59 UTC (permalink / raw)
To: io-uring, linux-fsdevel; +Cc: viro, shr, Pavel Begunkov
This adds support for getdents64 to io_uring.
Signed-off-by: Stefan Roesch <[email protected]>
Reviewed-by: Pavel Begunkov <[email protected]>
---
fs/io_uring.c | 52 +++++++++++++++++++++++++++++++++++
include/uapi/linux/io_uring.h | 1 +
2 files changed, 53 insertions(+)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 5092dfe56da6..bbc00761f5fe 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -693,6 +693,13 @@ struct io_hardlink {
int flags;
};
+struct io_getdents {
+ struct file *file;
+ struct linux_dirent64 __user *dirent;
+ unsigned int count;
+ loff_t pos;
+};
+
struct io_async_connect {
struct sockaddr_storage address;
};
@@ -858,6 +865,7 @@ struct io_kiocb {
struct io_mkdir mkdir;
struct io_symlink symlink;
struct io_hardlink hardlink;
+ struct io_getdents getdents;
};
u8 opcode;
@@ -1107,6 +1115,9 @@ static const struct io_op_def io_op_defs[] = {
[IORING_OP_MKDIRAT] = {},
[IORING_OP_SYMLINKAT] = {},
[IORING_OP_LINKAT] = {},
+ [IORING_OP_GETDENTS] = {
+ .needs_file = 1,
+ },
};
/* requests with any of those set should undergo io_disarm_next() */
@@ -4068,6 +4079,42 @@ static int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
return 0;
}
+static int io_getdents_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+ struct io_getdents *getdents = &req->getdents;
+
+ if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+ return -EINVAL;
+ if (sqe->ioprio || sqe->rw_flags || sqe->buf_index)
+ return -EINVAL;
+
+ getdents->pos = READ_ONCE(sqe->off);
+ getdents->dirent = u64_to_user_ptr(READ_ONCE(sqe->addr));
+ getdents->count = READ_ONCE(sqe->len);
+
+ return 0;
+}
+
+static int io_getdents(struct io_kiocb *req, unsigned int issue_flags)
+{
+ struct io_getdents *getdents = &req->getdents;
+ int ret;
+
+ if (issue_flags & IO_URING_F_NONBLOCK)
+ return -EAGAIN;
+
+ ret = vfs_getdents(req->file, getdents->dirent, getdents->count, getdents->pos);
+ if (ret < 0) {
+ if (ret == -ERESTARTSYS)
+ ret = -EINTR;
+
+ req_set_fail(req);
+ }
+
+ io_req_complete(req, ret);
+ return 0;
+}
+
static int io_shutdown_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
@@ -6574,6 +6621,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return io_symlinkat_prep(req, sqe);
case IORING_OP_LINKAT:
return io_linkat_prep(req, sqe);
+ case IORING_OP_GETDENTS:
+ return io_getdents_prep(req, sqe);
}
printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6857,6 +6906,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
case IORING_OP_LINKAT:
ret = io_linkat(req, issue_flags);
break;
+ case IORING_OP_GETDENTS:
+ ret = io_getdents(req, issue_flags);
+ break;
default:
ret = -EINVAL;
break;
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 787f491f0d2a..57dc88db5793 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -143,6 +143,7 @@ enum {
IORING_OP_MKDIRAT,
IORING_OP_SYMLINKAT,
IORING_OP_LINKAT,
+ IORING_OP_GETDENTS,
/* this goes last, obviously */
IORING_OP_LAST,
--
2.30.2
^ permalink raw reply related [flat|nested] 4+ messages in thread