summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-15 20:46:11 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-26 12:18:47 -0600
commit4a4c44190057cef139c2cde5c7258854caa7558b (patch)
treee3c06994f1100f8725d539f3255385619c61029c
parentc52c36becff41c5a66f73744f727ad848035076b (diff)
lib9p: Have separate IO objects, so they can have their own state
-rw-r--r--lib9p/include/lib9p/srv.h98
-rw-r--r--lib9p/srv.c110
-rw-r--r--lib9p/tests/test_server/main.c23
-rw-r--r--lib9p_util/static.c49
4 files changed, 181 insertions, 99 deletions
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index 1057e42..f94fdf8 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -37,53 +37,69 @@ int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx);
/* interface definitions ******************************************************/
-#define lib9p_srv_file_LO_IFACE \
- /* all - resource management */ \
- LO_FUNC(void , free ) /* must not error */ \
- LO_FUNC(struct lib9p_qid , qid ) /* must not error */ \
- LO_FUNC(uint32_t , chio , struct lib9p_srv_ctx *, \
- bool rd, bool wr, \
- bool trunc) \
- \
- /* all - syscalls */ \
- LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \
- LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \
- struct lib9p_stat new) \
- LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
- \
- /* directories - base */ \
- LO_FUNC(lo_interface lib9p_srv_file, dopen , struct lib9p_srv_ctx *, \
- struct lib9p_s childname) \
- LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
- struct lib9p_s childname, \
- lib9p_dm_t perm, \
- lib9p_o_t flags) \
- \
- /* directories - once opened */ \
- LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \
- uint8_t *buf, \
- /* num bytes -> */ uint32_t byte_count, \
- /* starting at this object -> */ size_t obj_offset) \
- \
- /* non-directories - once opened */ \
- LO_FUNC(uint32_t , pread , struct lib9p_srv_ctx *, \
- void *buf, \
- uint32_t byte_count, \
- uint64_t byte_offset) \
- LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
- void *buf, \
- uint32_t byte_count, \
+lo_interface lib9p_srv_fio;
+lo_interface lib9p_srv_dio;
+
+#define lib9p_srv_file_LO_IFACE \
+ /* resource management **********************************************/ \
+ \
+ LO_FUNC(void , free ) \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ \
+ /* non-"opened" generic I/O *****************************************/ \
+ \
+ LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \
+ LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \
+ struct lib9p_stat new) \
+ LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
+ \
+ /* non-"opened" directory I/O ***************************************/ \
+ \
+ LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \
+ struct lib9p_s childname) \
+ LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
+ struct lib9p_s childname, \
+ lib9p_dm_t perm, \
+ lib9p_o_t flags) \
+ \
+ /* open() for I/O ***************************************************/ \
+ \
+ LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \
+ bool rd, bool wr, \
+ bool trunc) \
+ LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *)
+LO_INTERFACE(lib9p_srv_file);
+
+#define lib9p_srv_fio_LO_IFACE \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(uint32_t , iounit ) \
+ LO_FUNC(uint32_t , pread , struct lib9p_srv_ctx *, \
+ void *buf, \
+ uint32_t byte_count, \
+ uint64_t byte_offset) \
+ LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
+ void *buf, \
+ uint32_t byte_count, \
uint64_t byte_offset)
-LO_INTERFACE(lib9p_srv_file)
+LO_INTERFACE(lib9p_srv_fio);
+
+#define lib9p_srv_dio_LO_IFACE \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \
+ uint8_t *buf, \
+ /* num bytes -> */ uint32_t byte_count, \
+ /* starting at this object -> */ size_t obj_offset)
+LO_INTERFACE(lib9p_srv_dio);
#define LIB9P_SRV_NOTDIR(TYP, NAM) \
- static lo_interface lib9p_srv_file NAM##_dopen (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
+ static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, lib9p_dm_t, lib9p_o_t) { assert_notreached("not a directory"); } \
- static size_t NAM##_dread (TYP *, struct lib9p_srv_ctx *, uint8_t *, uint32_t, size_t) { assert_notreached("not a directory"); }
+ static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); }
#define LIB9P_SRV_NOTFILE(TYP, NAM) \
- static uint32_t NAM##_pread (TYP *, struct lib9p_srv_ctx *, void *, uint32_t, uint64_t) { assert_notreached("not a file"); } \
- static uint32_t NAM##_pwrite(TYP *, struct lib9p_srv_ctx *, void *, uint32_t, uint64_t) { assert_notreached("not a file"); }
+ static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); }
/* main server entrypoints ****************************************************/
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 2475baf..9c679b6 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -60,8 +60,7 @@ struct srv_pathinfo {
* from FIDs. */
unsigned int gc_refcount;
/* References from fids with FIDFLAG_OPEN_R/FIDFLAG_OPEN_W. */
- unsigned int rd_refcount;
- unsigned int wr_refcount;
+ unsigned int io_refcount;
};
#define NAME pathmap
@@ -77,11 +76,18 @@ struct srv_pathinfo {
#define FIDFLAG_OPEN (FIDFLAG_OPEN_R|FIDFLAG_OPEN_W)
struct _srv_fidinfo {
- srv_path_t path;
- uint8_t flags;
- uint32_t iounit;
- size_t dir_idx;
- uint64_t dir_off;
+ srv_path_t path;
+ uint8_t flags;
+ union {
+ struct {
+ lo_interface lib9p_srv_fio io;
+ } file;
+ struct {
+ lo_interface lib9p_srv_dio io;
+ size_t idx;
+ uint64_t off;
+ } dir;
+ };
};
#define NAME fidmap
@@ -122,9 +128,9 @@ struct _srv_sess {
/* mutable */
bool initialized;
bool closing;
- struct pathmap paths;
- struct reqmap reqs;
- struct fidmap fids;
+ struct pathmap paths; /* srv_path_t => lib9p_srv_file + metadata */
+ struct fidmap fids; /* lib9p_fid_t => lib9p_srv_{fio,dio} + metadata */
+ struct reqmap reqs; /* lib9p_tag_t => *_lib9p_srv_req */
};
struct _lib9p_srv_req {
@@ -463,8 +469,7 @@ static inline struct srv_pathinfo *srv_util_pathsave(struct _lib9p_srv_req *ctx,
.file = file,
.parent_dir = parent_path,
.gc_refcount = 0,
- .rd_refcount = 0,
- .wr_refcount = 0,
+ .io_refcount = 0,
});
assert(pathinfo);
if (parent_path != qid.path) {
@@ -515,6 +520,12 @@ static inline struct _srv_fidinfo *srv_util_fidsave(struct _lib9p_srv_req *ctx,
struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, fid);
if (fidinfo) {
if (overwrite) {
+ struct srv_pathinfo *old_pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(old_pathinfo);
+ if (srv_util_pathisdir(old_pathinfo))
+ LO_CALL(fidinfo->dir.io, iofree);
+ else
+ LO_CALL(fidinfo->file.io, iofree);
srv_util_pathfree(ctx, fidinfo->path);
} else {
lib9p_error(&ctx->ctx.basectx,
@@ -748,7 +759,7 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx,
break;
}
- lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dopen, &ctx->ctx, req->wname[resp->nwqid]);
+ lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, &ctx->ctx, req->wname[resp->nwqid]);
assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->ctx.basectx));
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
break;
@@ -774,6 +785,13 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx,
pathinfo = new_pathinfo;
}
if (resp->nwqid == req->nwname) {
+ if (req->newfid == req->fid) {
+ if (srv_util_pathisdir(pathinfo))
+ LO_CALL(fidinfo->dir.io, iofree);
+ else
+ LO_CALL(fidinfo->file.io, iofree);
+ fidinfo->flags = 0;
+ }
if (!srv_util_fidsave(ctx, req->newfid, pathinfo, req->newfid == req->fid))
srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path);
} else {
@@ -816,7 +834,6 @@ static void handle_Topen(struct _lib9p_srv_req *ctx,
/* Variables. */
lib9p_o_t reqmode = req->mode;
uint8_t fidflags = fidinfo->flags;
- uint32_t iounit = fidinfo->iounit;
/* Check permissions. */
if (reqmode & LIB9P_O_RCLOSE) {
@@ -831,13 +848,13 @@ static void handle_Topen(struct _lib9p_srv_req *ctx,
LINUX_EACCES, "permission denied to remove-on-close");
return;
}
- fidflags = fidflags | FIDFLAG_RCLOSE;
+ fidflags |= FIDFLAG_RCLOSE;
}
struct lib9p_stat stat = LO_CALL(pathinfo->file, stat, &ctx->ctx);
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
return;
lib9p_stat_assert(stat);
- if ((stat.file_mode & LIB9P_DM_EXCL) && (pathinfo->rd_refcount || pathinfo->wr_refcount)) {
+ if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
lib9p_error(&ctx->ctx.basectx,
LINUX_EEXIST, "exclusive file is already opened");
return;
@@ -870,26 +887,36 @@ static void handle_Topen(struct _lib9p_srv_req *ctx,
}
/* Actually make the call. */
- if ((reqmode & LIB9P_O_TRUNC) || (rd && !pathinfo->rd_refcount) || (wr && !pathinfo->wr_refcount) ) {
- iounit = LO_CALL(pathinfo->file, chio, &ctx->ctx,
- fidflags & FIDFLAG_OPEN_R,
- fidflags & FIDFLAG_OPEN_W,
- reqmode & LIB9P_O_TRUNC);
+ uint32_t iounit;
+ struct lib9p_qid qid;
+ if (srv_util_pathisdir(pathinfo)) {
+ fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, &ctx->ctx);
+ assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->ctx.basectx));
+ if (lib9p_ctx_has_error(&ctx->ctx.basectx))
+ return;
+ fidinfo->dir.idx = 0;
+ fidinfo->dir.off = 0;
+ qid = LO_CALL(fidinfo->dir.io, qid);
+ iounit = 0;
+ } else {
+ fidinfo->file.io = LO_CALL(pathinfo->file, fopen, &ctx->ctx,
+ rd, wr,
+ reqmode & LIB9P_O_TRUNC);
+ assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->ctx.basectx));
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
return;
+ qid = LO_CALL(fidinfo->file.io, qid);
+ iounit = LO_CALL(fidinfo->file.io, iounit);
}
/* Success. */
- if (rd) {
- fidflags = fidflags | FIDFLAG_OPEN_R;
- pathinfo->rd_refcount++;
- }
- if (wr) {
- fidflags = fidflags | FIDFLAG_OPEN_W;
- pathinfo->wr_refcount++;
- }
+ if (rd)
+ fidflags |= FIDFLAG_OPEN_R;
+ if (wr)
+ fidflags |= FIDFLAG_OPEN_W;
+ pathinfo->io_refcount++;
fidinfo->flags = fidflags;
- resp->qid = stat.file_qid;
+ resp->qid = qid;
resp->iounit = iounit;
}
@@ -931,16 +958,16 @@ static void handle_Tread(struct _lib9p_srv_req *ctx,
size_t idx;
if (req->offset == 0)
idx = 0;
- else if (req->offset == fidinfo->dir_off)
- idx = fidinfo->dir_idx;
+ else if (req->offset == fidinfo->dir.off)
+ idx = fidinfo->dir.idx;
else {
lib9p_errorf(&ctx->ctx.basectx,
LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64,
- fidinfo->dir_off, req->offset);
+ fidinfo->dir.off, req->offset);
return;
}
/* Do it. */
- size_t num = LO_CALL(pathinfo->file, dread, &ctx->ctx, (uint8_t *)resp->data, req->count, idx);
+ size_t num = LO_CALL(fidinfo->dir.io, dread, &ctx->ctx, (uint8_t *)resp->data, req->count, idx);
/* Translate object-count back to byte-count. */
uint32_t len = 0;
for (size_t i = 0; i < num; i++) {
@@ -950,10 +977,10 @@ static void handle_Tread(struct _lib9p_srv_req *ctx,
}
resp->count = len;
/* Remember. */
- fidinfo->dir_idx = idx+num;
- fidinfo->dir_off = req->offset + len;
+ fidinfo->dir.idx = idx+num;
+ fidinfo->dir.off = req->offset + len;
} else
- resp->count = LO_CALL(pathinfo->file, pread, &ctx->ctx, resp->data, req->count, req->offset);
+ resp->count = LO_CALL(fidinfo->file.io, pread, &ctx->ctx, resp->data, req->count, req->offset);
}
static void handle_Twrite(struct _lib9p_srv_req *ctx,
@@ -979,7 +1006,7 @@ static void handle_Twrite(struct _lib9p_srv_req *ctx,
assert(pathinfo);
/* Do it. */
- resp->count = LO_CALL(pathinfo->file, pwrite, &ctx->ctx, req->data, req->count, req->offset);
+ resp->count = LO_CALL(fidinfo->file.io, pwrite, &ctx->ctx, req->data, req->count, req->offset);
}
static void clunkremove(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, bool remove) {
@@ -1012,6 +1039,13 @@ static void clunkremove(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, bool remove
}
clunk:
+ if (fidinfo->flags & FIDFLAG_OPEN) {
+ if (srv_util_pathisdir(pathinfo))
+ LO_CALL(fidinfo->dir.io, iofree);
+ else
+ LO_CALL(fidinfo->file.io, iofree);
+ pathinfo->io_refcount--;
+ }
srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path);
fidmap_del(&ctx->parent_sess->fids, fid);
}
diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c
index 074dbe7..b993714 100644
--- a/lib9p/tests/test_server/main.c
+++ b/lib9p/tests/test_server/main.c
@@ -48,7 +48,10 @@ struct api_file {
uint64_t pathnum;
};
LO_IMPLEMENTATION_H(lib9p_srv_file, struct api_file, api)
+LO_IMPLEMENTATION_H(lib9p_srv_fio, struct api_file, api)
+
LO_IMPLEMENTATION_C(lib9p_srv_file, struct api_file, api, static)
+LO_IMPLEMENTATION_C(lib9p_srv_fio, struct api_file, api, static)
static void api_free(struct api_file *self) {
assert(self);
@@ -61,11 +64,6 @@ static struct lib9p_qid api_qid(struct api_file *self) {
.path = self->pathnum,
};
}
-static uint32_t api_chio(struct api_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
- assert(self);
- assert(ctx);
- return 0;
-}
static struct lib9p_stat api_stat(struct api_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
@@ -101,6 +99,21 @@ static void api_remove(struct api_file *self, struct lib9p_srv_ctx *ctx) {
LIB9P_SRV_NOTDIR(struct api_file, api)
+static lo_interface lib9p_srv_fio api_fopen(struct api_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+ assert(self);
+ assert(ctx);
+ return lo_box_api_as_lib9p_srv_fio(self);
+}
+
+static void api_iofree(struct api_file *self) {
+ assert(self);
+}
+
+static uint32_t api_iounit(struct api_file *self) {
+ assert(self);
+ return 0;
+}
+
static uint32_t api_pwrite(struct api_file *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t LM_UNUSED(offset)) {
assert(self);
assert(ctx);
diff --git a/lib9p_util/static.c b/lib9p_util/static.c
index a6ea8f6..50bb129 100644
--- a/lib9p_util/static.c
+++ b/lib9p_util/static.c
@@ -12,6 +12,12 @@
LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_dir, util9p_static_dir, static);
LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_file, util9p_static_file, static);
+LO_IMPLEMENTATION_H(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dir);
+LO_IMPLEMENTATION_C(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dir, static);
+
+LO_IMPLEMENTATION_H(lib9p_srv_fio, struct util9p_static_file, util9p_static_file);
+LO_IMPLEMENTATION_C(lib9p_srv_fio, struct util9p_static_file, util9p_static_file, static);
+
/* dir ************************************************************************/
static void util9p_static_dir_free(struct util9p_static_dir *self) {
@@ -26,11 +32,6 @@ static struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) {
.path = self->pathnum,
};
}
-static uint32_t util9p_static_dir_chio(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
- assert(self);
- assert(ctx);
- return 0;
-}
static struct lib9p_stat util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
assert(self);
@@ -68,7 +69,7 @@ static void util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9
lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem");
}
-static lo_interface lib9p_srv_file util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+static lo_interface lib9p_srv_file util9p_static_dir_dwalk(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
struct lib9p_s childname) {
assert(self);
assert(ctx);
@@ -97,6 +98,16 @@ static lo_interface lib9p_srv_file util9p_static_dir_dcreate(struct util9p_stati
return LO_NULL(lib9p_srv_file);
}
+LIB9P_SRV_NOTFILE(struct util9p_static_dir, util9p_static_dir);
+
+static lo_interface lib9p_srv_dio util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ return lo_box_util9p_static_dir_as_lib9p_srv_dio(self);
+}
+static void util9p_static_dir_iofree(struct util9p_static_dir *self) {
+ assert(self);
+}
static size_t util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
uint8_t *buf,
uint32_t byte_count,
@@ -126,8 +137,6 @@ static size_t util9p_static_dir_dread(struct util9p_static_dir *self, struct lib
return obj_offset - _obj_offset;
}
-LIB9P_SRV_NOTFILE(struct util9p_static_dir, util9p_static_dir)
-
/* file ***********************************************************************/
static void util9p_static_file_free(struct util9p_static_file *self) {
@@ -142,11 +151,6 @@ static struct lib9p_qid util9p_static_file_qid(struct util9p_static_file *self)
.path = self->pathnum,
};
}
-static uint32_t util9p_static_file_chio(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
- assert(self);
- assert(ctx);
- return 0;
-}
static inline size_t util9p_static_file_size(struct util9p_static_file *file) {
assert(file);
@@ -196,8 +200,24 @@ static void util9p_static_file_remove(struct util9p_static_file *self, struct li
lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem");
}
-LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file)
+LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file);
+static lo_interface lib9p_srv_fio util9p_static_file_fopen(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ bool rd, bool wr, bool trunc) {
+ assert(self);
+ assert(ctx);
+ assert(rd);
+ assert(!wr);
+ assert(!trunc);
+ return lo_box_util9p_static_file_as_lib9p_srv_fio(self);
+}
+static void util9p_static_file_iofree(struct util9p_static_file *self) {
+ assert(self);
+}
+static uint32_t util9p_static_file_iounit(struct util9p_static_file *self) {
+ assert(self);
+ return 0;
+}
static uint32_t util9p_static_file_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
void *buf,
uint32_t byte_count,
@@ -220,7 +240,6 @@ static uint32_t util9p_static_file_pread(struct util9p_static_file *self, struct
memcpy(buf, &self->data_start[beg_off], end_off-beg_off);
return (uint32_t)(end_off-beg_off);
}
-
static uint32_t util9p_static_file_pwrite(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
void *LM_UNUSED(buf),
uint32_t LM_UNUSED(byte_count),