* [PATCH liburing] IORING_OP_GETDENTS: add opcode, prep function, test, man page section
@ 2021-02-18 12:28 Lennert Buytenhek
2021-03-30 11:22 ` Lennert Buytenhek
0 siblings, 1 reply; 2+ messages in thread
From: Lennert Buytenhek @ 2021-02-18 12:28 UTC (permalink / raw)
To: Jens Axboe, io-uring
Signed-off-by: Lennert Buytenhek <[email protected]>
---
man/io_uring_enter.2 | 26 +++++
src/include/liburing.h | 7 ++
src/include/liburing/io_uring.h | 1 +
test/Makefile | 1 +
test/getdents.c | 180 ++++++++++++++++++++++++++++++++
5 files changed, 215 insertions(+)
create mode 100644 test/getdents.c
diff --git a/man/io_uring_enter.2 b/man/io_uring_enter.2
index 086207d..e0bd638 100644
--- a/man/io_uring_enter.2
+++ b/man/io_uring_enter.2
@@ -759,6 +759,32 @@ being passed in to
.BR unlinkat(2).
Available since 5.11.
+.TP
+.B IORING_OP_GETDENTS
+Issue the equivalent of an
+.BR lseek(2)
+system call plus a
+.BR getdents64(2)
+system call.
+.I fd
+should be set to the fd of the directory being operated on,
+.I off
+should be set to the offset in the directory to start reading from,
+.I addr
+should be set to the
+.I dirp,
+and
+.I len
+should be set to the
+.I count.
+
+.B IORING_OP_GETDENTS
+may or may not change the specified directory's file offset, and the
+file offset should not be relied upon having any particular value during
+or after an
+.B IORING_OP_GETDENTS
+operation.
+
.PP
The
.I flags
diff --git a/src/include/liburing.h b/src/include/liburing.h
index 5b96e02..1769cda 100644
--- a/src/include/liburing.h
+++ b/src/include/liburing.h
@@ -535,6 +535,13 @@ static inline void io_uring_prep_sync_file_range(struct io_uring_sqe *sqe,
sqe->sync_range_flags = flags;
}
+static inline void io_uring_prep_getdents(struct io_uring_sqe *sqe, int fd,
+ void *buf, unsigned int count,
+ uint64_t off)
+{
+ io_uring_prep_rw(IORING_OP_GETDENTS, sqe, fd, buf, count, off);
+}
+
/*
* Returns number of unconsumed (if SQPOLL) or unsubmitted entries exist in
* the SQ ring
diff --git a/src/include/liburing/io_uring.h b/src/include/liburing/io_uring.h
index 1d47389..8abc0af 100644
--- a/src/include/liburing/io_uring.h
+++ b/src/include/liburing/io_uring.h
@@ -142,6 +142,7 @@ enum {
IORING_OP_RENAMEAT,
IORING_OP_UNLINKAT,
IORING_OP_MKDIRAT,
+ IORING_OP_GETDENTS,
/* this goes last, obviously */
IORING_OP_LAST,
diff --git a/test/Makefile b/test/Makefile
index 7751eff..c76987a 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -55,6 +55,7 @@ test_targets += \
files-exit-hang-timeout \
fixed-link \
fsync \
+ getdents \
io-cancel \
io_uring_enter \
io_uring_register \
diff --git a/test/getdents.c b/test/getdents.c
new file mode 100644
index 0000000..3ca7b05
--- /dev/null
+++ b/test/getdents.c
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: run various getdents tests
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "liburing.h"
+
+/*
+ * This struct isn't exported via include/uapi/ , so we define it by hand.
+ */
+struct linux_dirent64 {
+ uint64_t d_ino;
+ int64_t d_off;
+ uint16_t d_reclen;
+ uint8_t d_type;
+ char d_name[];
+};
+
+#define BUFSZ 65536
+
+static int dirfd;
+
+static int test_getdents(struct io_uring *ring, void *buf,
+ unsigned int count, uint64_t off)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ int ret;
+
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "get sqe failed\n");
+ goto err;
+ }
+ io_uring_prep_getdents(sqe, dirfd, buf, count, off);
+
+ ret = io_uring_submit(ring);
+ if (ret <= 0) {
+ fprintf(stderr, "sqe submit failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret < 0) {
+ fprintf(stderr, "wait completion %d\n", ret);
+ goto err;
+ }
+
+ ret = cqe->res;
+
+ io_uring_cqe_seen(ring, cqe);
+
+ return ret;
+
+err:
+ return -1;
+}
+
+static void dump_dents(const uint8_t *buf, int len)
+{
+ const uint8_t *end;
+
+ fprintf(stderr, "inode offset type path\n");
+
+ end = buf + len;
+ while (buf < end) {
+ struct linux_dirent64 *dent;
+
+ dent = (struct linux_dirent64 *)buf;
+
+ fprintf(stderr, "%" PRId64 " %" PRId64 " %d %s\n", dent->d_ino,
+ dent->d_off, dent->d_type, dent->d_name);
+
+ buf += dent->d_reclen;
+ }
+
+ fprintf(stderr, "\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ int ret;
+ uint8_t buf[BUFSZ];
+ bool found_dot;
+ bool found_dotdot;
+ uint8_t *bufp;
+ uint8_t *end;
+
+ if (argc > 1)
+ return 0;
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ dirfd = open(".", O_DIRECTORY);
+ if (dirfd < 0) {
+ fprintf(stderr, "opening \".\" failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = test_getdents(&ring, buf, sizeof(buf), 0);
+ if (ret < 0) {
+ if (ret == -EINVAL) {
+ fprintf(stdout, "getdents not supported, skipping\n");
+ return 0;
+ }
+ fprintf(stderr, "getdents: %s\n", strerror(-ret));
+ return 1;
+ }
+
+ found_dot = false;
+ found_dotdot = false;
+
+ bufp = buf;
+ end = bufp + ret;
+
+ while (bufp < end) {
+ struct linux_dirent64 *dent;
+ uint8_t buf2[BUFSZ];
+
+ dent = (struct linux_dirent64 *)bufp;
+
+ if (!found_dot && !strcmp(dent->d_name, "."))
+ found_dot = true;
+ else if (!found_dotdot && !strcmp(dent->d_name, ".."))
+ found_dotdot = true;
+
+ bufp += dent->d_reclen;
+
+ /*
+ * Now try to read the directory starting from the given
+ * offset, and make sure we end up with the same data.
+ */
+ memset(buf2, 0, sizeof(buf2));
+
+ ret = test_getdents(&ring, buf2, sizeof(buf2), dent->d_off);
+ if (ret < 0) {
+ fprintf(stderr, "getdents: %s\n", strerror(-ret));
+ return 1;
+ }
+
+ if (ret != end - bufp || memcmp(bufp, buf2, ret)) {
+ fprintf(stderr, "getdents: read from offset "
+ "%" PRId64 " returned unexpected "
+ "data\n\n", (uint64_t)dent->d_off);
+
+ fprintf(stderr, "read from offset zero:\n");
+ dump_dents(bufp, end - bufp);
+
+ fprintf(stderr, "offsetted read:\n");
+ dump_dents(buf2, ret);
+
+ return 1;
+ }
+ }
+
+ if (!found_dot)
+ fprintf(stderr, "getdents didn't return \".\" entry\n");
+
+ if (!found_dotdot)
+ fprintf(stderr, "getdents didn't return \"..\" entry\n");
+
+ if (!found_dot || !found_dotdot)
+ return 1;
+
+ return 0;
+}
--
2.29.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH liburing] IORING_OP_GETDENTS: add opcode, prep function, test, man page section
2021-02-18 12:28 [PATCH liburing] IORING_OP_GETDENTS: add opcode, prep function, test, man page section Lennert Buytenhek
@ 2021-03-30 11:22 ` Lennert Buytenhek
0 siblings, 0 replies; 2+ messages in thread
From: Lennert Buytenhek @ 2021-03-30 11:22 UTC (permalink / raw)
To: Jens Axboe, io-uring
On Thu, Feb 18, 2021 at 02:28:42PM +0200, Lennert Buytenhek wrote:
> Signed-off-by: Lennert Buytenhek <[email protected]>
> ---
I'll shortly send a v2 of this that will:
- update the man page to specify that the file offset is updated
unconditionally by IORING_OP_GETDENTS;
- update the man pages to indicate that IORING_FEAT_RW_CUR_POS
also applies to IORING_OP_GETDENTS;
- update the getdents test to verify that offset == -1 reads from
the current directory offset.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-03-30 11:23 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-02-18 12:28 [PATCH liburing] IORING_OP_GETDENTS: add opcode, prep function, test, man page section Lennert Buytenhek
2021-03-30 11:22 ` Lennert Buytenhek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox