summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bftw.c3
-rw-r--r--src/ioq.c100
-rw-r--r--src/ioq.h31
3 files changed, 124 insertions, 10 deletions
diff --git a/src/bftw.c b/src/bftw.c
index 952b090..02dd051 100644
--- a/src/bftw.c
+++ b/src/bftw.c
@@ -631,6 +631,9 @@ static int bftw_ioq_pop(struct bftw_state *state, bool block) {
SLIST_APPEND(&state->to_read, file, to_read);
}
break;
+
+ case IOQ_STAT:
+ break;
}
ioq_free(ioq, ent);
diff --git a/src/ioq.c b/src/ioq.c
index 3d32dfe..3172f0a 100644
--- a/src/ioq.c
+++ b/src/ioq.c
@@ -131,6 +131,7 @@
#include "diag.h"
#include "dir.h"
#include "sanity.h"
+#include "stat.h"
#include "thread.h"
#include <assert.h>
#include <errno.h>
@@ -432,6 +433,10 @@ struct ioq {
/** ioq_ent arena. */
struct arena ents;
+#if BFS_USE_LIBURING && BFS_USE_STATX
+ /** struct statx arena. */
+ struct arena xbufs;
+#endif
/** Pending I/O requests. */
struct ioqq *pending;
@@ -479,6 +484,12 @@ static void ioq_dispatch_sync(struct ioq *ioq, struct ioq_ent *ent) {
case IOQ_CLOSEDIR:
ent->result = try(bfs_closedir(ent->closedir.dir));
return;
+
+ case IOQ_STAT: {
+ struct ioq_stat *args = &ent->stat;
+ ent->result = try(bfs_stat(args->dfd, args->path, args->flags, args->buf));
+ return;
+ }
}
bfs_bug("Unknown ioq_op %d", (int)ent->op);
@@ -549,6 +560,17 @@ static struct io_uring_sqe *ioq_dispatch_async(struct io_uring *ring, struct ioq
io_uring_prep_close(sqe, bfs_unwrapdir(ent->closedir.dir));
#endif
return sqe;
+
+ case IOQ_STAT: {
+#if BFS_USE_STATX
+ sqe = io_uring_get_sqe(ring);
+ struct ioq_stat *args = &ent->stat;
+ int flags = bfs_statx_flags(args->flags);
+ unsigned int mask = STATX_BASIC_STATS | STATX_BTIME;
+ io_uring_prep_statx(sqe, args->dfd, args->path, flags, mask, args->xbuf);
+#endif
+ return sqe;
+ }
}
bfs_bug("Unknown ioq_op %d", (int)ent->op);
@@ -597,21 +619,41 @@ static void ioq_reap_cqe(struct ioq_ring_state *state, struct io_uring_cqe *cqe)
io_uring_cqe_seen(ring, cqe);
--state->submitted;
- if (ent->op == IOQ_OPENDIR && ent->result >= 0) {
- int fd = ent->result;
- if (ioq_check_cancel(ioq, ent)) {
- xclose(fd);
- return;
+ if (ent->result < 0) {
+ goto push;
+ }
+
+ switch (ent->op) {
+ case IOQ_OPENDIR: {
+ int fd = ent->result;
+ if (ioq_check_cancel(ioq, ent)) {
+ xclose(fd);
+ return;
+ }
+
+ struct ioq_opendir *args = &ent->opendir;
+ ent->result = try(bfs_opendir(args->dir, fd, NULL, args->flags));
+ if (ent->result >= 0) {
+ // TODO: io_uring_prep_getdents()
+ bfs_polldir(args->dir);
+ }
+
+ break;
}
- struct ioq_opendir *args = &ent->opendir;
- ent->result = try(bfs_opendir(args->dir, fd, NULL, args->flags));
- if (ent->result >= 0) {
- // TODO: io_uring_prep_getdents()
- bfs_polldir(args->dir);
+#if BFS_USE_STATX
+ case IOQ_STAT: {
+ struct ioq_stat *args = &ent->stat;
+ ent->result = try(bfs_statx_convert(args->buf, args->xbuf));
+ break;
}
+#endif
+
+ default:
+ break;
}
+push:
ioqq_push(ioq->ready, ent);
}
@@ -689,8 +731,13 @@ struct ioq *ioq_create(size_t depth, size_t nthreads) {
}
ioq->depth = depth;
+
ARENA_INIT(&ioq->ents, struct ioq_ent);
+#if BFS_USE_LIBURING && BFS_USE_STATX
+ ARENA_INIT(&ioq->xbufs, struct statx);
+#endif
+
ioq->pending = ioqq_create(depth);
if (!ioq->pending) {
goto fail;
@@ -807,6 +854,30 @@ int ioq_closedir(struct ioq *ioq, struct bfs_dir *dir, void *ptr) {
return 0;
}
+int ioq_stat(struct ioq *ioq, int dfd, const char *path, enum bfs_stat_flags flags, struct bfs_stat *buf, void *ptr) {
+ struct ioq_ent *ent = ioq_request(ioq, IOQ_STAT, ptr);
+ if (!ent) {
+ return -1;
+ }
+
+ struct ioq_stat *args = &ent->stat;
+ args->dfd = dfd;
+ args->path = path;
+ args->flags = flags;
+ args->buf = buf;
+
+#if BFS_USE_LIBURING && BFS_USE_STATX
+ args->xbuf = arena_alloc(&ioq->xbufs);
+ if (!args->xbuf) {
+ ioq_free(ioq, ent);
+ return -1;
+ }
+#endif
+
+ ioqq_push(ioq->pending, ent);
+ return 0;
+}
+
struct ioq_ent *ioq_pop(struct ioq *ioq, bool block) {
if (ioq->size == 0) {
return NULL;
@@ -819,6 +890,12 @@ void ioq_free(struct ioq *ioq, struct ioq_ent *ent) {
bfs_assert(ioq->size > 0);
--ioq->size;
+#if BFS_USE_LIBURING && BFS_USE_STATX
+ if (ent->op == IOQ_STAT) {
+ arena_free(&ioq->xbufs, ent->stat.xbuf);
+ }
+#endif
+
arena_free(&ioq->ents, ent);
}
@@ -848,6 +925,9 @@ void ioq_destroy(struct ioq *ioq) {
ioqq_destroy(ioq->ready);
ioqq_destroy(ioq->pending);
+#if BFS_USE_LIBURING && BFS_USE_STATX
+ arena_destroy(&ioq->xbufs);
+#endif
arena_destroy(&ioq->ents);
free(ioq);
diff --git a/src/ioq.h b/src/ioq.h
index e1e5052..77aabaa 100644
--- a/src/ioq.h
+++ b/src/ioq.h
@@ -10,6 +10,7 @@
#include "config.h"
#include "dir.h"
+#include "stat.h"
#include <stddef.h>
/**
@@ -27,6 +28,8 @@ enum ioq_op {
IOQ_OPENDIR,
/** ioq_closedir(). */
IOQ_CLOSEDIR,
+ /** ioq_stat(). */
+ IOQ_STAT,
};
/**
@@ -59,6 +62,14 @@ struct ioq_ent {
struct ioq_closedir {
struct bfs_dir *dir;
} closedir;
+ /** ioq_stat() args. */
+ struct ioq_stat {
+ int dfd;
+ const char *path;
+ enum bfs_stat_flags flags;
+ struct bfs_stat *buf;
+ void *xbuf;
+ } stat;
};
};
@@ -128,6 +139,26 @@ int ioq_opendir(struct ioq *ioq, struct bfs_dir *dir, int dfd, const char *path,
int ioq_closedir(struct ioq *ioq, struct bfs_dir *dir, void *ptr);
/**
+ * Asynchronous bfs_stat().
+ *
+ * @param ioq
+ * The I/O queue.
+ * @param dfd
+ * The base file descriptor.
+ * @param path
+ * The path to stat, relative to dfd.
+ * @param flags
+ * Flags that affect the lookup.
+ * @param buf
+ * A place to store the stat buffer, if successful.
+ * @param ptr
+ * An arbitrary pointer to associate with the request.
+ * @return
+ * 0 on success, or -1 on failure.
+ */
+int ioq_stat(struct ioq *ioq, int dfd, const char *path, enum bfs_stat_flags flags, struct bfs_stat *buf, void *ptr);
+
+/**
* Pop a response from the queue.
*
* @param ioq