commit a8e7ed87318a9b388a7866741175b89d00776f48
parent 890d073d9da414458d62f5aaca7509b299f5b9c1
Author: Pavel Renev <an2qzavok@gmail.org>
Date: Sun, 11 Feb 2024 17:53:30 +0000
start implementing separate fs backend
Diffstat:
A | fs.c | | | 133 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | mkfile | | | 9 | +++++---- |
A | pages.c | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | pages.h | | | 29 | +++++++++++++++++++++++++++++ |
4 files changed, 255 insertions(+), 4 deletions(-)
diff --git a/fs.c b/fs.c
@@ -0,0 +1,133 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+
+#include "pages.h"
+
+enum {
+ FrameSize = sizeof(s16int) * 2,
+};
+
+PBuf pg;
+
+struct {
+ int min;
+ int max;
+ char str[32];
+} sel;
+
+void fs_read(Req *r);
+void fs_write(Req *r);
+
+void normalize_sel(void);
+void update_selstr(void);
+
+Srv ampsrv = {
+ .read = fs_read,
+ .write = fs_write,
+ // .open/.create (???) for handling truncating
+};
+
+File *fdata, *fcut, *fctl;
+
+void
+usage(void)
+{
+ fprint(2,"usage: %s\n", argv0);
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ ARGBEGIN {
+ case 'D':
+ chatty9p++;
+ break;
+ default: usage();
+ } ARGEND
+ if (argc != 0) usage();
+
+ update_selstr();
+
+ ampsrv.tree = alloctree("amp", "amp", DMDIR|0555, nil);
+ fdata = createfile(ampsrv.tree->root, "data", "amp", 0666, nil);
+ fcut = createfile(ampsrv.tree->root, "cut", "amp", 0666, nil);
+ fctl = createfile(ampsrv.tree->root, "ctl", "amp", 0666, nil);
+ threadpostmountsrv(&srv, "amp", "/mnt/amp", MREPL);
+}
+
+void
+fs_read(Req *r)
+{
+ if (r->fid->file == fdata) {
+ r->ofcall.count = pbread(&pg, r->ofcall.data,
+ r->ifcall.count, r->ifcall.offset);
+ respond(r, nil);
+ } else if (r->fid->file == fcut) {
+ respond(r, "fcut nope");
+ } else if (r->fid->file == fctl) {
+ readstr(r, sel.str);
+ respond(r, nil);
+ } else {
+ respond(r, "nope");
+ }
+}
+
+void
+fs_write(Req *r)
+{
+ if (r->fid->file == fdata) {
+ r->ofcall.count = pbwrite(&pg, r->ifcall.data,
+ r->ifcall.count, r->ifcall.offset);
+ if (pg.count > fdata->length) fdata->length = pg.count;
+ respond(r, nil);
+ } else if (r->fid->file == fcut) {
+ respond(r, "fcut nope");
+ } else if (r->fid->file == fctl) {
+ int newmin, newmax;
+ char *np, *rp;
+ np = r->ifcall.data;
+ newmin = strtol(np, &rp, 10);
+ if (rp <= np) {
+ respond(r, "bad first value");
+ return;
+ }
+ newmax = strtol(rp, &rp, 10);
+ if (rp <= np) {
+ respond(r, "bad second value");
+ return;
+ }
+ if (rp - np > r->ifcall.count) {
+ respond(r, "somehow buffer overrun");
+ return;
+ }
+ sel.min = newmin;
+ sel.max = newmax;
+ normalize_sel();
+ update_selstr();
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
+ } else {
+ respond(r, "nope");
+ }
+}
+
+void
+normalize_sel(void)
+{
+ if (sel.min > sel.max) {
+ int x = sel.max;
+ sel.max = sel.min;
+ sel.min = x;
+ };
+ // TODO: should check max is not bigger than total buffer size
+}
+
+void
+update_selstr(void)
+{
+ snprint(sel.str, sizeof(sel.str), "%11d %11d ", sel.min, sel.max);
+}
diff --git a/mkfile b/mkfile
@@ -1,9 +1,10 @@
</$objtype/mkfile
-TARG=amp
+TARG=fs
-OFILES=\
- amp.$O\
+OFILES=pages.$O
+HFILES=pages.h
BIN=/$objtype/bin
-</sys/src/cmd/mkone
+
+</sys/src/cmd/mkmany
diff --git a/pages.c b/pages.c
@@ -0,0 +1,88 @@
+#include <u.h>
+#include <libc.h>
+
+#include "pages.h"
+
+Page *
+allocpage(void)
+{
+ Page *new = mallocz(sizeof(Page), 1);
+ new->count = PageSize;
+ new->buf = mallocz(PageSize, 1);
+ return new;
+}
+
+long
+pbwrite(PBuf *pb, void *buf, long nbytes, vlong offset)
+{
+ Page *pgpt;
+ vlong page_offset = 0;
+ long n, nwritten = 0;
+ while (offset + nbytes > pb->size) {
+ addpage(pb);
+ }
+ pgpt = pb->start;
+ if (pb->count < offset + nbytes) pb->count = offset + nbytes;
+ while (nbytes > 0) {
+ assert(page_offset <= offset);
+ if (page_offset + pgpt->count > offset) {
+ n = page_offset + pgpt->count - offset;
+ if (n > nbytes) n = nbytes;
+ memcpy(pgpt->buf, buf, n);
+ nwritten += n;
+ buf = (char *)buf + n;
+ offset +=n;
+ nbytes -= n;
+ }
+ page_offset += pgpt->count;
+ pgpt = pgpt->next;
+ }
+ if (offset > pb->size) {
+ pb->size = offset;
+ }
+ return nwritten;
+}
+
+long
+pbread(PBuf *pb, void *buf, long nbytes, vlong offset)
+{
+ Page *pgpt = pb->start;
+ long n, nread = 0;
+ if (offset >= pb->count) nbytes = 0;
+ if (offset + nbytes >= pb->count) {
+ nbytes = (pb->count - offset);
+ }
+ while (nbytes > 0) {
+ if (pgpt == nil) {
+ break;
+ }
+ if (offset >= pgpt->count) {
+ offset -= pgpt->count;
+ pgpt = pgpt->next;
+ continue;
+ }
+ n = nbytes;
+ if (pgpt->count - offset < n) n = pgpt->count - offset;
+ memcpy(buf, pgpt->buf + offset, n);
+ nread += n;
+ buf = (char *)buf + n;
+ offset += n;
+ nbytes -= n;
+ }
+ return nread;
+}
+
+Page *
+addpage(PBuf *pb)
+{
+ Page *new = allocpage();
+ if (pb->start == nil) pb->start = new;
+ if (pb->end == nil) pb->end = new;
+ else {
+ new->prev = pb->end;
+ pb->end->next = new;
+ pb->end = new;
+ }
+ pb->size += new->count;
+ return new;
+}
diff --git a/pages.h b/pages.h
@@ -0,0 +1,29 @@
+// managing paginated memory buffers
+
+enum {
+ PageSize = 2048,
+};
+
+typedef struct Page Page;
+struct Page {
+ Page *prev;
+ Page *next;
+ vlong count;
+ char *buf;
+};
+
+Page *allocpage(void);
+
+typedef struct PBuf PBuf;
+struct PBuf {
+ Page *start;
+ Page *end;
+ vlong size; // how many bytes were allocated in total
+ vlong count; // how many bytes are used for storage
+ // count <= size
+};
+
+long pbwrite(PBuf *pb, void *buf, long nbytes, vlong offset);
+long pbread(PBuf *pb, void *buf, long nbytes, vlong offset);
+
+Page * addpage(PBuf *pb);