diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-15 20:46:11 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-26 12:18:47 -0600 |
commit | 4a4c44190057cef139c2cde5c7258854caa7558b (patch) | |
tree | e3c06994f1100f8725d539f3255385619c61029c | |
parent | c52c36becff41c5a66f73744f727ad848035076b (diff) |
lib9p: Have separate IO objects, so they can have their own state
-rw-r--r-- | lib9p/include/lib9p/srv.h | 98 | ||||
-rw-r--r-- | lib9p/srv.c | 110 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 23 | ||||
-rw-r--r-- | lib9p_util/static.c | 49 |
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), |