diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 122 |
1 files changed, 82 insertions, 40 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index 2475baf..50d0b78 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; } @@ -923,7 +950,6 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, /* Variables. */ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); assert(pathinfo); - resp->data = (char *)(&resp[1]); /* Do it. */ if (srv_util_pathisdir(pathinfo)) { @@ -931,16 +957,17 @@ 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); + resp->data = (char *)(&resp[1]); + 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,18 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, } resp->count = len; /* Remember. */ - 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); + fidinfo->dir.idx = idx+num; + fidinfo->dir.off = req->offset + len; + } else { + struct iovec iov; + LO_CALL(fidinfo->file.io, pread, &ctx->ctx, req->count, req->offset, &iov); + if (!lib9p_ctx_has_error(&ctx->ctx.basectx)) { + resp->count = iov.iov_len; + resp->data = iov.iov_base; + if (resp->count > req->count) + resp->count = req->count; + } + } } static void handle_Twrite(struct _lib9p_srv_req *ctx, @@ -979,7 +1014,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 +1047,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); } |