From 5be4ead0a7930b82adb10355cbac13d84869e0cb Mon Sep 17 00:00:00 2001 From: David Boddie Date: Sat, 25 May 2019 17:15:03 +0200 Subject: Include devds in the hosted build. --- emu/Linux/emu | 1 + emu/Linux/mkfile | 1 + emu/port/devds.c | 594 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 596 insertions(+) create mode 100644 emu/port/devds.c diff --git a/emu/Linux/emu b/emu/Linux/emu index 29267dfd..0af201a2 100644 --- a/emu/Linux/emu +++ b/emu/Linux/emu @@ -13,6 +13,7 @@ dev fs cmd cmd indir + ds draw win-x11a pointer diff --git a/emu/Linux/mkfile b/emu/Linux/mkfile index 3b072d5e..ff586bcc 100644 --- a/emu/Linux/mkfile +++ b/emu/Linux/mkfile @@ -51,3 +51,4 @@ install:V: $O.$CONF <../port/portmkfile devfs.$O: ../port/devfs-posix.c +devds.$O: ../port/devds.c diff --git a/emu/port/devds.c b/emu/port/devds.c new file mode 100644 index 00000000..480a24d7 --- /dev/null +++ b/emu/port/devds.c @@ -0,0 +1,594 @@ +/* + * (file system) device subsystems + * '#k'. + * Follows device config in Ken's file server. + * Builds mirrors, device cats, interleaving, and partition of devices out of + * other (inner) devices. + * + * This code is from Plan 9, and subject to the Lucent Public License 1.02. + * Only the name changed for Inferno (name clash). + */ + +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +enum { + Fmirror, // mirror of others + Fcat, // catenation of others + Finter, // interleaving of others + Fpart, // part of others + + Blksize = 8*1024, // for Finter only + Maxconf = 1024, // max length for config + + Nfsdevs = 64, + Ndevs = 8, + + Qtop = 0, // top dir (contains "ds") + Qdir = 1, // actual dir + Qctl = 2, // ctl file + Qfirst = 3, // first fs file +}; + +#define Cfgstr "fsdev:\n" + +typedef struct Fsdev Fsdev; + +struct Fsdev +{ + int type; + char *name; // name for this fsdev + vlong start; // start address (for Fpart) + vlong size; // min(idev sizes) + int ndevs; // number of inner devices + char *iname[Ndevs]; // inner device names + Chan *idev[Ndevs]; // inner devices + vlong isize[Ndevs]; // sizes for inneer devices +}; + +/* + * Once configured, a fsdev is never removed. The name of those + * configured is never nil. We have no locks here. + */ +static Fsdev fsdev[Nfsdevs]; + +static Qid tqid = {Qtop, 0, QTDIR}; +static Qid dqid = {Qdir, 0, QTDIR}; +static Qid cqid = {Qctl, 0, 0}; + +static Cmdtab configs[] = { + Fmirror,"mirror", 0, + Fcat, "cat", 0, + Finter, "inter", 0, + Fpart, "part", 5, +}; + +static char _confstr[Maxconf]; +static int configed; + + +static Fsdev* +path2dev(int i, int mustexist) +{ + if (i < 0 || i >= nelem(fsdev)) + error("bug: bad index in devfsdev"); + if (mustexist && fsdev[i].name == nil) + error(Enonexist); + + if (fsdev[i].name == nil) + return nil; + else + return &fsdev[i]; +} + +static Fsdev* +devalloc(void) +{ + int i; + + for (i = 0; i < nelem(fsdev); i++) + if (fsdev[i].name == nil) + break; + if (i == nelem(fsdev)) + error(Enodev); + + return &fsdev[i]; +} + +static void +setdsize(Fsdev* mp) +{ + uchar buf[128]; /* old DIRLEN plus a little should be plenty */ + int i; + Chan *mc; + Dir d; + long l; + + if (mp->type != Fpart){ + mp->start= 0; + mp->size = 0LL; + } + for (i = 0; i < mp->ndevs; i++){ + mc = mp->idev[i]; + l = devtab[mc->type]->stat(mc, buf, sizeof(buf)); + convM2D(buf, l, &d, nil); + mp->isize[i] = d.length; + switch(mp->type){ + case Fmirror: + if (mp->size == 0LL || mp->size > d.length) + mp->size = d.length; + break; + case Fcat: + mp->size += d.length; + break; + case Finter: + // truncate to multiple of Blksize + d.length = (d.length & ~(Blksize-1)); + mp->isize[i] = d.length; + mp->size += d.length; + break; + case Fpart: + // should raise errors here? + if (mp->start > d.length) + mp->start = d.length; + if (d.length < mp->start + mp->size) + mp->size = d.length - mp->start; + break; + } + } +} + +static void +mpshut(Fsdev *mp) +{ + int i; + char *nm; + + nm = mp->name; + mp->name = nil; // prevent others from using this. + if (nm) + free(nm); + for (i = 0; i < mp->ndevs; i++){ + if (mp->idev[i] != nil) + cclose(mp->idev[i]); + if (mp->iname[i]) + free(mp->iname[i]); + } + memset(mp, 0, sizeof(*mp)); +} + + +static void +mconfig(char* a, long n) // "name idev0 idev1" +{ + static QLock lck; + Cmdbuf *cb; + Cmdtab *ct; + Fsdev *mp; + int i; + char *oldc; + char *c; + vlong size, start; + + size = 0; + start = 0; + if (_confstr[0] == 0) + seprint(_confstr, _confstr+sizeof(_confstr), Cfgstr); + oldc = _confstr + strlen(_confstr); + qlock(&lck); + if (waserror()){ + *oldc = 0; + qunlock(&lck); + nexterror(); + } + cb = parsecmd(a, n); + if(waserror()){ + free(cb); + nexterror(); + } + c = oldc; + for (i = 0; i < cb->nf; i++) + c = seprint(c, _confstr+sizeof(_confstr), "%s ", cb->f[i]); + *(c-1) = '\n'; + ct = lookupcmd(cb, configs, nelem(configs)); + cb->f++; // skip command + cb->nf--; + if (ct->index == Fpart){ + size = strtoll(cb->f[3], nil, 10); + cb->nf--; + start = strtoll(cb->f[2], nil, 10); + cb->nf--; + } + for (i = 0; i < nelem(fsdev); i++) + if (fsdev[i].name != nil && strcmp(fsdev[i].name, cb->f[0])==0) + error(Eexist); + if (cb->nf - 1 > Ndevs) + error("too many devices; fix me"); + for (i = 0; i < cb->nf; i++) + validname(cb->f[i], (i != 0)); + mp = devalloc(); + if(waserror()){ + mpshut(mp); + nexterror(); + } + mp->type = ct->index; + if (mp->type == Fpart){ + mp->size = size; + mp->start = start; + } + kstrdup(&mp->name, cb->f[0]); + for (i = 1; i < cb->nf; i++){ + kstrdup(&mp->iname[i-1], cb->f[i]); + mp->idev[i-1] = namec(mp->iname[i-1], Aopen, ORDWR, 0); + if (mp->idev[i-1] == nil) + error(Egreg); + mp->ndevs++; + } + setdsize(mp); + poperror(); + free(cb); + poperror(); + poperror(); + configed = 1; + qunlock(&lck); + +} + +static void +rdconf(void) +{ + int mustrd; + char *s; + char *c; + char *p; + char *e; + Chan *cc; + + mustrd = 0; + s = "/dev/sdC0/fscfg"; + if (waserror()){ + configed = 1; + if (!mustrd) + return; + nexterror(); + } + cc = namec(s, Aopen, OREAD, 0); + if(waserror()){ + cclose(cc); + nexterror(); + } + devtab[cc->type]->read(cc, _confstr, sizeof(_confstr), 0); + poperror(); + cclose(cc); + if (strncmp(_confstr, Cfgstr, strlen(Cfgstr)) != 0) + error("config string must start with `fsdev:'"); + kstrdup(&c, _confstr + strlen(Cfgstr)); + if(waserror()){ + free(c); + nexterror(); + } + memset(_confstr, 0, sizeof(_confstr)); + for (p = c; p != nil && *p != 0; p = e){ + e = strchr(p, '\n'); + if (e == p){ + e++; + continue; + } + if (e == nil) + e = p + strlen(p); + mconfig(p, e - p); + } + poperror(); + poperror(); +} + + +static int +mgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) +{ + Qid qid; + Fsdev *mp; + + if (c->qid.path == Qtop){ + switch(i){ + case DEVDOTDOT: + devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp); + return 1; + case 0: + devdir(c, dqid, "ds", 0, eve, DMDIR|0775, dp); + return 1; + default: + return -1; + } + } + if (c->qid.path != Qdir){ + switch(i){ + case DEVDOTDOT: + devdir(c, dqid, "ds", 0, eve, DMDIR|0775, dp); + return 1; + default: + return -1; + } + } + switch(i){ + case DEVDOTDOT: + devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp); + return 1; + case 0: + devdir(c, cqid, "ctl", 0, eve, 0664, dp); + return 1; + } + i--; // for ctl + qid.path = Qfirst + i; + qid.vers = 0; + qid.type = 0; + mp = path2dev(i, 0); + if (mp == nil) + return -1; + kstrcpy(up->genbuf, mp->name, sizeof(up->genbuf)); + devdir(c, qid, up->genbuf, mp->size, eve, 0664, dp); + return 1; +} + +static Chan* +mattach(char *spec) +{ + *_confstr = 0; + return devattach(L'k', spec); +} + +static Walkqid* +mwalk(Chan *c, Chan *nc, char **name, int nname) +{ + if (!configed) + rdconf(); + return devwalk(c, nc, name, nname, 0, 0, mgen); +} + +static int +mstat(Chan *c, uchar *db, int n) +{ + Dir d; + Fsdev *mp; + int p; + + p = c->qid.path; + memset(&d, 0, sizeof(d)); + switch(p){ + case Qtop: + devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d); + break; + case Qdir: + devdir(c, dqid, "ds", 0, eve, DMDIR|0775, &d); + break; + case Qctl: + devdir(c, cqid, "ctl", 0, eve, 0664, &d); + break; + default: + mp = path2dev(p - Qfirst, 1); + devdir(c, c->qid, mp->name, mp->size, eve, 0664, &d); + } + n = convD2M(&d, db, n); + if (n == 0) + error(Ebadarg); + return n; +} + +static Chan* +mopen(Chan *c, int omode) +{ + if((c->qid.type & QTDIR) && omode != OREAD) + error(Eperm); + if (omode & OTRUNC) + omode &= ~OTRUNC; + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +static void +mclose(Chan *c) +{ + // that's easy +} + +static long +catio(Fsdev *mp, int isread, void *a, long n, vlong off) +{ + int i; + Chan* mc; + long l, wl, res; + //print("catio %d %p %ld %lld\n", isread, a, n, off); + res = n; + for (i = 0; n >= 0 && i < mp->ndevs ; i++){ + mc = mp->idev[i]; + if (off > mp->isize[i]){ + off -= mp->isize[i]; + continue; + } + if (off + n > mp->isize[i]) + l = mp->isize[i] - off; + else + l = n; + //print("\tdev %d %p %ld %lld\n", i, a, l, off); + + if (isread) + wl = devtab[mc->type]->read(mc, a, l, off); + else + wl = devtab[mc->type]->write(mc, a, l, off); + if (wl != l) + error("#k: write failed"); + a = (char*)a + l; + off = 0; + n -= l; + } + //print("\tres %ld\n", res - n); + return res - n; +} + +static long +interio(Fsdev *mp, int isread, void *a, long n, vlong off) +{ + int i; + Chan* mc; + long l, wl, wsz; + vlong woff, blk, mblk; + long boff, res; + + blk = off / Blksize; + boff = off % Blksize; + wsz = Blksize - boff; + res = n; + while(n > 0){ + i = blk % mp->ndevs; + mc = mp->idev[i]; + mblk = blk / mp->ndevs; + woff = mblk * Blksize + boff; + if (n > wsz) + l = wsz; + else + l = n; + if (isread) + wl = devtab[mc->type]->read(mc, a, l, woff); + else + wl = devtab[mc->type]->write(mc, a, l, woff); + if (wl != l || l == 0) + error(Eio); + a = (char*)a + l; + n -= l; + blk++; + boff = 0; + wsz = Blksize; + } + return res; +} + +static long +mread(Chan *c, void *a, long n, vlong off) +{ + int i; + Fsdev *mp; + Chan *mc; + long l; + long res; + + if (c->qid.type & QTDIR) + return devdirread(c, a, n, 0, 0, mgen); + if (c->qid.path == Qctl) + return readstr((long)off, a, n, _confstr + strlen(Cfgstr)); + i = c->qid.path - Qfirst; + mp = path2dev(i, 1); + + if (off >= mp->size) + return 0; + if (off + n > mp->size) + n = mp->size - off; + if (n == 0) + return 0; + + res = -1; + switch(mp->type){ + case Fmirror: + for (i = 0; i < mp->ndevs; i++){ + mc = mp->idev[i]; + if (waserror()){ + // if a read fails we let the user know and try + // another device. + print("#k: mread: (%llx %d): %s\n", + c->qid.path, i, up->env->errstr); + continue; + } + l = devtab[mc->type]->read(mc, a, n, off); + poperror(); + if (l >=0){ + res = l; + break; + } + } + if (i == mp->ndevs) + error(Eio); + break; + case Fcat: + res = catio(mp, 1, a, n, off); + break; + case Finter: + res = interio(mp, 1, a, n, off); + break; + case Fpart: + off += mp->start; + mc = mp->idev[0]; + res = devtab[mc->type]->read(mc, a, n, off); + break; + } + return res; +} + +static long +mwrite(Chan *c, void *a, long n, vlong off) +{ + Fsdev *mp; + long l, res; + int i; + Chan *mc; + + if (c->qid.type & QTDIR) + error(Eperm); + if (c->qid.path == Qctl){ + mconfig(a, n); + return n; + } + mp = path2dev(c->qid.path - Qfirst, 1); + + if (off >= mp->size) + return 0; + if (off + n > mp->size) + n = mp->size - off; + if (n == 0) + return 0; + res = n; + switch(mp->type){ + case Fmirror: + for (i = mp->ndevs-1; i >=0; i--){ + mc = mp->idev[i]; + l = devtab[mc->type]->write(mc, a, n, off); + if (l < res) + res = l; + } + break; + case Fcat: + res = catio(mp, 0, a, n, off); + break; + case Finter: + res = interio(mp, 0, a, n, off); + break; + case Fpart: + mc = mp->idev[0]; + off += mp->start; + l = devtab[mc->type]->write(mc, a, n, off); + if (l < res) + res = l; + break; + } + return res; +} + +Dev dsdevtab = { + 'k', + "ds", + + devinit, + mattach, + mwalk, + mstat, + mopen, + devcreate, + mclose, + mread, + devbread, + mwrite, + devbwrite, + devremove, + devwstat, +}; -- cgit v1.2.3