[-- Attachment #1: Type: text/plain, Size: 547 bytes --] Hello all, since some people asked mycroftiv about rfork V (and zrv) here's a patch for current (yesterday) 9front. Some things changed since the last official ants diffs, so manual adjustments were needed. Also don't forget backups! The patch should apply cleanly. Rebuilding libc, rc and kernel is needed (libc before rc!). This patch does _not_ include the changes to postmountsrv, which make it possible to srv directly to /zrv (`application -s name` vs `application -s /zrv/name`). All credits go to mycroftiv for this. sirjofri . [-- Attachment #2: Type: text/plain, Size: 7461 bytes --] diff -r d1a5cac82bd7 sys/include/libc.h --- a/sys/include/libc.h Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/include/libc.h Tue Jan 05 17:22:13 2021 +0100 @@ -624,6 +624,7 @@ RFPROC = (1<<4), RFMEM = (1<<5), RFNOWAIT = (1<<6), + RFCSRVG = (1<<9), RFCNAMEG = (1<<10), RFCENVG = (1<<11), RFCFDG = (1<<12), diff -r d1a5cac82bd7 sys/lib/dist/cfg/plan9.ini --- a/sys/lib/dist/cfg/plan9.ini Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/lib/dist/cfg/plan9.ini Tue Jan 05 17:22:13 2021 +0100 @@ -3,3 +3,4 @@ mouseport=ask monitor=ask vgasize=ask +bootfile=/amd64/9pc64 diff -r d1a5cac82bd7 sys/src/9/pc64/pc64 --- a/sys/src/9/pc64/pc64 Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/pc64/pc64 Tue Jan 05 17:22:13 2021 +0100 @@ -10,6 +10,7 @@ proc mnt srv + zrv shr dup rtc diff -r d1a5cac82bd7 sys/src/9/port/auth.c --- a/sys/src/9/port/auth.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/auth.c Tue Jan 05 17:22:13 2021 +0100 @@ -141,6 +141,7 @@ renameuser(eve, buf); srvrenameuser(eve, buf); + zrvrenameuser(eve, buf); shrrenameuser(eve, buf); kstrdup(&eve, buf); procsetuser(buf); diff -r d1a5cac82bd7 sys/src/9/port/devroot.c --- a/sys/src/9/port/devroot.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/devroot.c Tue Jan 05 17:22:13 2021 +0100 @@ -108,6 +108,7 @@ addrootdir("root"); addrootdir("srv"); addrootdir("shr"); + addrootdir("zrv"); } static Chan* diff -r d1a5cac82bd7 sys/src/9/port/devsrv.c --- a/sys/src/9/port/devsrv.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/devsrv.c Tue Jan 05 17:22:13 2021 +0100 @@ -6,19 +6,7 @@ #include "../port/error.h" -typedef struct Srv Srv; -struct Srv -{ - char *name; - char *owner; - ulong perm; - Chan *chan; - Srv *link; - ulong path; -}; - static QLock srvlk; -static Srv *srv; static int qidpath; static Srv* @@ -26,7 +14,7 @@ { Srv *sp; - for(sp = srv; sp != nil; sp = sp->link) { + for(sp = up->sgrp->srvgrp; sp != nil; sp = sp->link) { if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0)) return sp; } @@ -48,7 +36,7 @@ if(name != nil) sp = srvlookup(name, -1); else { - for(sp = srv; sp != nil && s > 0; sp = sp->link) + for(sp = up->sgrp->srvgrp; sp != nil && s > 0; sp = sp->link) s--; } if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) { @@ -95,7 +83,7 @@ s = nil; qlock(&srvlk); - for(sp = srv; sp != nil; sp = sp->link) { + for(sp = up->sgrp->srvgrp; sp != nil; sp = sp->link) { if(sp->chan == c){ s = malloc(3+strlen(sp->name)+1); if(s != nil) @@ -183,8 +171,8 @@ c->qid.path = sp->path; c->qid.type = QTFILE; - sp->link = srv; - srv = sp; + sp->link = up->sgrp->srvgrp; + up->sgrp->srvgrp = sp; qunlock(&srvlk); poperror(); @@ -208,7 +196,7 @@ qunlock(&srvlk); nexterror(); } - l = &srv; + l = &up->sgrp->srvgrp; for(sp = *l; sp != nil; sp = *l) { if(sp->path == c->qid.path) break; @@ -378,12 +366,30 @@ }; void +closesgrp(Sgrp *sg) +{ + Srv *sp; + Srv *tsp; + + if(decref(sg) == 0){ + sp = sg->srvgrp; + while(sp!=nil){ + tsp=sp; + sp=sp->link; + free(tsp); + } + free(sg); + } + return; +} + +void srvrenameuser(char *old, char *new) { Srv *sp; qlock(&srvlk); - for(sp = srv; sp != nil; sp = sp->link) { + for(sp = up->sgrp->srvgrp; sp != nil; sp = sp->link) { if(sp->owner != nil && strcmp(old, sp->owner) == 0) kstrdup(&sp->owner, new); } diff -r d1a5cac82bd7 sys/src/9/port/portdat.h --- a/sys/src/9/port/portdat.h Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/portdat.h Tue Jan 05 17:22:13 2021 +0100 @@ -44,6 +44,8 @@ typedef struct Segment Segment; typedef struct Segio Segio; typedef struct Sema Sema; +typedef struct Sgrp Sgrp; +typedef struct Srv Srv; typedef struct Timer Timer; typedef struct Timers Timers; typedef struct Uart Uart; @@ -468,6 +470,21 @@ Page *pghash[PGHSIZE]; /* page cache */ }; +struct Srv +{ + char *name; + char *owner; + ulong perm; + Chan *chan; + Srv *link; + ulong path; +}; + +struct Sgrp +{ + Ref; + Srv *srvgrp; +}; struct Pgrp { @@ -576,6 +593,7 @@ RFPROC = (1<<4), RFMEM = (1<<5), RFNOWAIT = (1<<6), + RFCSRVG = (1<<9), RFCNAMEG = (1<<10), RFCENVG = (1<<11), RFCFDG = (1<<12), @@ -678,6 +696,7 @@ Egrp *egrp; /* Environment group */ Fgrp *fgrp; /* File descriptor group */ Rgrp *rgrp; /* Rendez group */ + Sgrp *sgrp; /* Srv group */ Fgrp *closingfgrp; /* used during teardown */ diff -r d1a5cac82bd7 sys/src/9/port/portfns.h --- a/sys/src/9/port/portfns.h Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/portfns.h Tue Jan 05 17:22:13 2021 +0100 @@ -34,6 +34,7 @@ void closefgrp(Fgrp*); void closepgrp(Pgrp*); void closergrp(Rgrp*); +void closesgrp(Sgrp*); long clrfpintr(void); void cmderror(Cmdbuf*, char*); int cmount(Chan**, Chan*, int, char*); @@ -340,6 +341,8 @@ void splxpc(int); char* srvname(Chan*); void srvrenameuser(char*, char*); +char* zrvname(Chan*); +void zrvrenameuser(char*, char*); void shrrenameuser(char*, char*); int swapcount(uintptr); int swapfull(void); diff -r d1a5cac82bd7 sys/src/9/port/proc.c --- a/sys/src/9/port/proc.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/proc.c Tue Jan 05 17:22:13 2021 +0100 @@ -1092,6 +1092,7 @@ Egrp *egrp; Rgrp *rgrp; Pgrp *pgrp; + Sgrp *sgrp; Chan *dot; void (*pt)(Proc*, int, vlong); @@ -1122,6 +1123,13 @@ closeegrp(egrp); if(rgrp != nil) closergrp(rgrp); + /* sgrp is nilled out here because closefgrp may need srvclose */ + qlock(&up->debug); + sgrp = up->sgrp; + up->sgrp = nil; + qunlock(&up->debug); + if(sgrp != nil) + closesgrp(sgrp); if(dot != nil) cclose(dot); if(pgrp != nil) diff -r d1a5cac82bd7 sys/src/9/port/sysproc.c --- a/sys/src/9/port/sysproc.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/sysproc.c Tue Jan 05 17:22:13 2021 +0100 @@ -32,6 +32,7 @@ Pgrp *opg; Rgrp *org; Egrp *oeg; + Sgrp *osg; ulong pid, flag; Mach *wm; @@ -71,6 +72,12 @@ up->rgrp = newrgrp(); closergrp(org); } + if(flag & RFCSRVG) { + osg = up->sgrp; + up->sgrp = smalloc(sizeof(Sgrp)); + up->sgrp->ref = 1; + closesgrp(osg); + } if(flag & (RFENVG|RFCENVG)) { oeg = up->egrp; up->egrp = smalloc(sizeof(Egrp)); @@ -187,6 +194,15 @@ p->rgrp = up->rgrp; } + /* Srv group */ + if(flag & RFCSRVG) { + p->sgrp = smalloc(sizeof(Sgrp)); + p->sgrp->ref = 1; + } else { + p->sgrp = up->sgrp; + incref(p->sgrp); + } + /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); diff -r d1a5cac82bd7 sys/src/9/port/userinit.c --- a/sys/src/9/port/userinit.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/9/port/userinit.c Tue Jan 05 17:22:13 2021 +0100 @@ -31,6 +31,8 @@ up->pgrp = newpgrp(); up->egrp = smalloc(sizeof(Egrp)); up->egrp->ref = 1; + up->sgrp = smalloc(sizeof(Sgrp)); + up->sgrp->ref = 1; up->fgrp = dupfgrp(nil); up->rgrp = newrgrp(); diff -r d1a5cac82bd7 sys/src/cmd/rc/plan9.c --- a/sys/src/cmd/rc/plan9.c Tue Jan 05 22:36:03 2021 +1030 +++ b/sys/src/cmd/rc/plan9.c Tue Jan 05 17:22:13 2021 +0100 @@ -81,11 +81,13 @@ arg|=RFFDG; break; case 'F': arg|=RFCFDG; break; + case 'V': + arg|=RFCSRVG; break; } break; default: Usage: - pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word); + pfmt(err, "Usage: %s [fnesFNEmV]\n", runq->argv->words->word); setstatus("rfork usage"); poplist(); return;
this implementation seemes flawed to me. closesgrp() appears only to free the memory of the Srv* nodes, but doesnt actually free srv->chan, srv->owner and srv->name. also the locking seems suspicious. as the global Srv* list was just replaced with per process one, but we'r still only have a single srvlock to serialize concurrent access to it. so far, the srvgrp can only be reset or shared depending of the RFCSRVG flag. once you implement copying you'd need a lock per Sgrp. i'd prefer to have a lock per Sgrp right now and remove the global srvlock. pexit() should move the sgrp = up->sgrp; up->sgrp = nil in the exiting qlock(&up->debug);... block instead of making its own. why do we need /zrv? is there a new devzrv.c device that was missing in the diff? -- cinap
Quoth cinap_lenrek@felloff.net:
> this implementation seemes flawed to me.
>
> closesgrp() appears only to free the memory of the Srv*
> nodes, but doesnt actually free srv->chan, srv->owner
> and srv->name.
>
> also the locking seems suspicious. as the global Srv*
> list was just replaced with per process one, but we'r
> still only have a single srvlock to serialize
> concurrent access to it.
>
> so far, the srvgrp can only be reset or shared depending
> of the RFCSRVG flag. once you implement copying you'd
> need a lock per Sgrp. i'd prefer to have a lock per
> Sgrp right now and remove the global srvlock.
>
> pexit() should move the sgrp = up->sgrp; up->sgrp = nil
> in the exiting qlock(&up->debug);... block instead of
> making its own.
>
> why do we need /zrv? is there a new devzrv.c device that
> was missing in the diff?
>
> --
> cinap
>
On top of that, I think rfork flags aren't a very
nice semantic. What about reworking to
bind '#s/clone' /srv
to create a new fork of a srv, without adding new
special namespace cases?
That also eliminates the need for zrv, since you
can just keep the old /srv bound somewhere else.
Hello again, the included patch is indeed mycroftiv's work without many adjustments. We just made it work in current 9front code. Also I did forget to attach the devzrv.c. devzrv btw is the same as srv but doesn't fork. It is possible to srvfs the forked srvs in zrv. Sure, there are much cleaner solutions. Using #s/clone as ori suggested would be a nice kernel-based solution (instead of a fully userspace implementation I can also imagine). Another idea I can think of would be similar to #σ. Imagine mkdir '#s/newsrv' && bind -c '#/newsrv' /srv or even like some mntgen without the mkdir. This would break compatibility! More compatible would be something like echo newsrv > '#sc' && bind '#s' /srv. This would be more compatible to current implementation. In both ideas the newsrv is just an arbitrary name. sirjofri
or you could use the mntspec when binding #s. having srvspace like fork also has the disadvantage that you have the previous namespace now all bullshit. all the mount channels become inaccessible as you RFCSRV. at some point, i'd really like to have dedicated 9p opertation and syscall to "post" a file descriptor to a fileserver, instead of having more process specific magic wormholes which doesnt transcent across exportfs. no code yet unfortunately :( there are a bunch of other fileservers that need it. like when you want to add another channel to a devbridge. also think about stuff like dossrv. you can pass it a filename to the dos partition on mount, but it needs to be in its namespace. or stuff like devtls. grabbing into the calling process filedescriptor table or namespace should be avoided at all cost. -- cinap
hope you are all right! -- cinap
[-- Attachment #1: Type: text/plain, Size: 216 bytes --] > Also I did forget to attach the devzrv.c. devzrv btw is the same as srv > but doesn't fork. It is possible to srvfs the forked srvs in zrv. Attached is the missing devzrv.c that's missing in the patch. sirjofri [-- Attachment #2: devzrv.c --] [-- Type: text/plain, Size: 6049 bytes --] #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" static QLock srvlk; static Srv *srv; static int qidpath; static Srv* srvlookup(char *name, ulong qidpath) { Srv *sp; for(sp = srv; sp != nil; sp = sp->link) { if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0)) return sp; } return nil; } static int srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) { Srv *sp; Qid q; if(s == DEVDOTDOT){ devdir(c, c->qid, "#z", 0, eve, 0555, dp); return 1; } qlock(&srvlk); if(name != nil) sp = srvlookup(name, -1); else { for(sp = srv; sp != nil && s > 0; sp = sp->link) s--; } if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) { qunlock(&srvlk); return -1; } mkqid(&q, sp->path, 0, QTFILE); /* make sure name string continues to exist after we release lock */ kstrcpy(up->genbuf, sp->name, sizeof up->genbuf); devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp); qunlock(&srvlk); return 1; } static void srvinit(void) { qidpath = 1; } static Chan* srvattach(char *spec) { return devattach('z', spec); } static Walkqid* srvwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, srvgen); } static int srvstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, 0, 0, srvgen); } char* zrvname(Chan *c) { Srv *sp; char *s; s = nil; qlock(&srvlk); for(sp = srv; sp != nil; sp = sp->link) { if(sp->chan == c){ s = malloc(3+strlen(sp->name)+1); if(s != nil) sprint(s, "#z/%s", sp->name); break; } } qunlock(&srvlk); return s; } static Chan* srvopen(Chan *c, int omode) { Srv *sp; Chan *nc; if(c->qid.type == QTDIR){ if(omode & ORCLOSE) error(Eperm); if(omode != OREAD) error(Eisdir); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } qlock(&srvlk); if(waserror()){ qunlock(&srvlk); nexterror(); } sp = srvlookup(nil, c->qid.path); if(sp == nil || sp->chan == nil) error(Eshutdown); if(omode&OTRUNC) error(Eexist); if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR) error(Eperm); devpermcheck(sp->owner, sp->perm, omode); nc = sp->chan; incref(nc); qunlock(&srvlk); poperror(); cclose(c); return nc; } static Chan* srvcreate(Chan *c, char *name, int omode, ulong perm) { Srv *sp; if(openmode(omode) != OWRITE) error(Eperm); if(strlen(name) >= sizeof(up->genbuf)) error(Etoolong); sp = smalloc(sizeof *sp); kstrdup(&sp->name, name); kstrdup(&sp->owner, up->user); qlock(&srvlk); if(waserror()){ qunlock(&srvlk); free(sp->owner); free(sp->name); free(sp); nexterror(); } if(srvlookup(name, -1) != nil) error(Eexist); sp->perm = perm&0777; sp->path = qidpath++; c->qid.path = sp->path; c->qid.type = QTFILE; sp->link = srv; srv = sp; qunlock(&srvlk); poperror(); c->flag |= COPEN; c->mode = OWRITE; return c; } static void srvremove(Chan *c) { Srv *sp, **l; if(c->qid.type == QTDIR) error(Eperm); qlock(&srvlk); if(waserror()){ qunlock(&srvlk); nexterror(); } l = &srv; for(sp = *l; sp != nil; sp = *l) { if(sp->path == c->qid.path) break; l = &sp->link; } if(sp == nil) error(Enonexist); /* * Only eve can remove system services. */ if(strcmp(sp->owner, eve) == 0 && !iseve()) error(Eperm); /* * No removing personal services. */ if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve()) error(Eperm); *l = sp->link; sp->link = nil; qunlock(&srvlk); poperror(); if(sp->chan != nil) cclose(sp->chan); free(sp->owner); free(sp->name); free(sp); } static int srvwstat(Chan *c, uchar *dp, int n) { char *strs; Srv *sp; Dir d; if(c->qid.type & QTDIR) error(Eperm); strs = smalloc(n); if(waserror()){ free(strs); nexterror(); } n = convM2D(dp, n, &d, strs); if(n == 0) error(Eshortstat); qlock(&srvlk); if(waserror()){ qunlock(&srvlk); nexterror(); } sp = srvlookup(nil, c->qid.path); if(sp == nil) error(Enonexist); if(strcmp(sp->owner, up->user) != 0 && !iseve()) error(Eperm); if(d.name != nil && *d.name && strcmp(sp->name, d.name) != 0) { if(strchr(d.name, '/') != nil) error(Ebadchar); if(strlen(d.name) >= sizeof(up->genbuf)) error(Etoolong); kstrdup(&sp->name, d.name); } if(d.uid != nil && *d.uid) kstrdup(&sp->owner, d.uid); if(d.mode != ~0UL) sp->perm = d.mode & 0777; qunlock(&srvlk); poperror(); free(strs); poperror(); return n; } static void srvclose(Chan *c) { /* * in theory we need to override any changes in removability * since open, but since all that's checked is the owner, * which is immutable, all is well. */ if(c->flag & CRCLOSE){ if(waserror()) return; srvremove(c); poperror(); } } static long srvread(Chan *c, void *va, long n, vlong) { isdir(c); return devdirread(c, va, n, 0, 0, srvgen); } static long srvwrite(Chan *c, void *va, long n, vlong) { Srv *sp; Chan *c1; int fd; char buf[32]; if(n >= sizeof buf) error(Etoobig); memmove(buf, va, n); /* so we can NUL-terminate */ buf[n] = 0; fd = strtoul(buf, 0, 0); c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ qlock(&srvlk); if(waserror()) { qunlock(&srvlk); cclose(c1); nexterror(); } if(c1->flag & (CCEXEC|CRCLOSE)) error("posted fd has remove-on-close or close-on-exec"); if(c1->qid.type & QTAUTH) error("cannot post auth file in zrv"); sp = srvlookup(nil, c->qid.path); if(sp == nil) error(Enonexist); if(sp->chan != nil) error(Ebadusefd); sp->chan = c1; qunlock(&srvlk); poperror(); return n; } Dev zrvdevtab = { 'z', "zrv", devreset, srvinit, devshutdown, srvattach, srvwalk, srvstat, srvopen, srvcreate, srvclose, srvread, devbread, srvwrite, devbwrite, srvremove, srvwstat, }; void zrvrenameuser(char *old, char *new) { Srv *sp; qlock(&srvlk); for(sp = srv; sp != nil; sp = sp->link) { if(sp->owner != nil && strcmp(old, sp->owner) == 0) kstrdup(&sp->owner, new); } qunlock(&srvlk); }
> i'd really like to have dedicated 9p opertation and
> syscall to "post" a file descriptor to a fileserver, ...
> think about stuff like dossrv.
Would make the *srv fs's (run once, stays resident and handles all
mounts of that type) feel more like loadable kernel modules. In terms
of usage, I mean.
Sorry it's late… http://runjimmyrunrunyoufuckerrun.com/demo/glenda.c Warning: lots of draw. For the weak-willed or underpowered: http://runjimmyrunrunyoufuckerrun.com/demo/glenda.mp4 Have fun at the mini-hackathon! umbraticus