summaryrefslogtreecommitdiff
path: root/lib9p/srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r--lib9p/srv.c122
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);
}