From c3e1346bbcc2f737ff69fdc353125714ec937ddb Mon Sep 17 00:00:00 2001 From: Jacob Moody Date: Sun, 12 Jun 2022 00:44:10 +0000 Subject: [PATCH] kernel: add /srv/clone /srv/clone allows a namespace to get their own private /srv session. --- sys/man/3/srv | 11 ++ sys/src/9/port/devsrv.c | 265 ++++++++++++++++++++++++++++++++-------- 2 files changed, 225 insertions(+), 51 deletions(-) diff --git a/sys/man/3/srv b/sys/man/3/srv index 820c849db..00497c79d 100644 --- a/sys/man/3/srv +++ b/sys/man/3/srv @@ -5,6 +5,7 @@ srv \- server registry .nf .B bind #s /srv +.BI #s/ clone/ .BI #s/ service1 .BI #s/ service2 ... @@ -40,6 +41,16 @@ releases that reference. .PP It is an error to write more than one number into a server file, or to create a file with a name that is already being used. +.PP +A walk to +.I clone +creates a blank private bulletin board. Private boards are +recursable but disjoint; walks may only descend. A process +may get a private +.B /srv +by doing: +.IP +bind -c /srv/clone /srv .SH EXAMPLE To drop one end of a pipe into .BR /srv , diff --git a/sys/src/9/port/devsrv.c b/sys/src/9/port/devsrv.c index 8128569a1..9cece906b 100644 --- a/sys/src/9/port/devsrv.c +++ b/sys/src/9/port/devsrv.c @@ -5,6 +5,7 @@ #include "fns.h" #include "../port/error.h" +#include "netif.h" typedef struct Srv Srv; struct Srv @@ -17,16 +18,34 @@ struct Srv ulong path; }; -static QLock srvlk; -static Srv *srv; -static int qidpath; +typedef struct Fid Fid; +struct Fid +{ + int ref; + QLock lk; + Srv *tail; + ulong nextpath; +}; + +enum{ + Qroot, + Qclone, + + Qend +}; + +static Fid global; + +struct { + QLock; + ulong path; +} sessions; static Srv* -srvlookup(char *name, ulong qidpath) +srvlookup(Srv *sp, char *name, ulong qidpath) { - Srv *sp; - - for(sp = srv; sp != nil; sp = sp->link) { + qidpath = NETTYPE(qidpath); + for(; sp != nil; sp = sp->link) { if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0)) return sp; } @@ -38,47 +57,139 @@ srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) { Srv *sp; Qid q; + Fid *f; + ulong id; if(s == DEVDOTDOT){ - devdir(c, c->qid, "#s", 0, eve, 0555, dp); + switch(NETTYPE(c->qid.path)){ + case Qroot: + mkqid(&q, Qroot, 0, QTDIR); + devdir(c, q, "#s", 0, eve, 0555|DMDIR, dp); + break; + case Qclone: + default: + /* + * Someone has walked down /srv/clone/clone/.... and + * would like back up. We do not allow revisiting + * previous sessions. Dead end + */ + error(Enonexist); + break; + } return 1; } - qlock(&srvlk); + id = NETID(c->qid.path); + if(name != nil && strcmp(name, "clone") == 0){ + /* walk; new session */ + qlock(&sessions); + id = ++sessions.path; + qunlock(&sessions); + + f = smalloc(sizeof *f); + f->ref = 1; + f->nextpath = Qend; + + mkqid(&q, NETQID(id, Qclone), id, QTDIR); + devdir(c, q, "clone", 0, eve, 0555|DMDIR, dp); + c->aux = f; + return 1; + } else if(name == nil && s == 0) { + /* stat, dirread; current session */ + mkqid(&q, NETQID(id, Qclone), id, QTDIR); + devdir(c, q, "clone", 0, eve, 0555|DMDIR, dp); + return 1; + } + + f = c->aux; + qlock(&f->lk); if(name != nil) - sp = srvlookup(name, -1); + sp = srvlookup(f->tail, name, -1); else { - for(sp = srv; sp != nil && s > 0; sp = sp->link) + s -= 1; + for(sp = f->tail; sp != nil && s > 0; sp = sp->link) s--; } if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) { - qunlock(&srvlk); + qunlock(&f->lk); return -1; } - mkqid(&q, sp->path, 0, QTFILE); + mkqid(&q, NETQID(id, 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); + qunlock(&f->lk); return 1; } static void srvinit(void) { - qidpath = 1; + global.nextpath = Qend; } static Chan* srvattach(char *spec) { - return devattach('s', spec); + Chan *c; + + c = devattach('s', spec); + c->aux = &global; + return c; } static Walkqid* srvwalk(Chan *c, Chan *nc, char **name, int nname) { - return devwalk(c, nc, name, nname, 0, 0, srvgen); + Walkqid *wq; + Fid *f; + int tripped; + + /* + * We need to allow for infinite recursions through clone but we + * don't need to permit passing multiple clones in a single walk. + * This allows us to ensure that only a single clone is alloted + * per walk. + */ + tripped = 0; + if(nname > 1){ + nname = 1; + tripped = 1; + } + wq = devwalk(c, nc, name, nname, 0, 0, srvgen); + if(wq == nil || wq->clone == nil || wq->clone == c) + return wq; + + if(tripped){ + /* + * Our partial walk returned a newly alloc'd clone. + * We wll never see a clunk for that partially walked + * fid, so just clean it up now. + */ + if(NETTYPE(wq->clone->qid.path) == Qclone){ + f = wq->clone->aux; + assert(f->tail == nil); + assert(f->ref == 1); + free(f); + } + /* Correct state to indicate failure to walk all names */ + wq->clone->type = 0; + cclose(wq->clone); + wq->clone = nil; + return wq; + } + if(wq->clone->aux == &global) + return wq; + + if(NETID(c->qid.path) != NETID(wq->clone->qid.path)) + return wq; + + assert(c->aux == wq->clone->aux); + f = c->aux; + qlock(&f->lk); + f->ref++; + qunlock(&f->lk); + return wq; } static int @@ -91,11 +202,13 @@ char* srvname(Chan *c) { Srv *sp; + Fid *f; char *s; s = nil; - qlock(&srvlk); - for(sp = srv; sp != nil; sp = sp->link) { + f = &global; + qlock(&f->lk); + for(sp = f->tail; sp != nil; sp = sp->link) { if(sp->chan == c){ s = malloc(3+strlen(sp->name)+1); if(s != nil) @@ -103,7 +216,7 @@ srvname(Chan *c) break; } } - qunlock(&srvlk); + qunlock(&f->lk); return s; } @@ -111,6 +224,7 @@ static Chan* srvopen(Chan *c, int omode) { Srv *sp; + Fid *f; Chan *nc; if(c->qid.type == QTDIR){ @@ -123,13 +237,14 @@ srvopen(Chan *c, int omode) c->offset = 0; return c; } - qlock(&srvlk); + f = c->aux; + qlock(&f->lk); if(waserror()){ - qunlock(&srvlk); + qunlock(&f->lk); nexterror(); } - sp = srvlookup(nil, c->qid.path); + sp = srvlookup(f->tail, nil, c->qid.path); if(sp == nil || sp->chan == nil) error(Eshutdown); @@ -144,7 +259,7 @@ srvopen(Chan *c, int omode) nc = sp->chan; incref(nc); - qunlock(&srvlk); + qunlock(&f->lk); poperror(); cclose(c); @@ -155,6 +270,7 @@ static Chan* srvcreate(Chan *c, char *name, int omode, ulong perm) { Srv *sp; + Fid *f; if(openmode(omode) != OWRITE) error(Eperm); @@ -162,31 +278,32 @@ srvcreate(Chan *c, char *name, int omode, ulong perm) if(strlen(name) >= sizeof(up->genbuf)) error(Etoolong); + f = c->aux; sp = smalloc(sizeof *sp); kstrdup(&sp->name, name); kstrdup(&sp->owner, up->user); - qlock(&srvlk); + qlock(&f->lk); if(waserror()){ - qunlock(&srvlk); + qunlock(&f->lk); free(sp->owner); free(sp->name); free(sp); nexterror(); } - if(srvlookup(name, -1) != nil) + if(srvlookup(f->tail, name, -1) != nil) error(Eexist); sp->perm = perm&0777; - sp->path = qidpath++; + sp->path = f->nextpath++; - c->qid.path = sp->path; + c->qid.path = NETQID(NETID(c->qid.path), sp->path); c->qid.type = QTFILE; - sp->link = srv; - srv = sp; + sp->link = f->tail; + f->tail = sp; - qunlock(&srvlk); + qunlock(&f->lk); poperror(); c->flag |= COPEN; @@ -199,18 +316,22 @@ static void srvremove(Chan *c) { Srv *sp, **l; + Fid *f; + ulong id; if(c->qid.type == QTDIR) error(Eperm); - qlock(&srvlk); + f = c->aux; + + qlock(&f->lk); if(waserror()){ - qunlock(&srvlk); + qunlock(&f->lk); nexterror(); } - l = &srv; + l = &f->tail; for(sp = *l; sp != nil; sp = *l) { - if(sp->path == c->qid.path) + if(sp->path == NETTYPE(c->qid.path)) break; l = &sp->link; } @@ -231,15 +352,29 @@ srvremove(Chan *c) *l = sp->link; sp->link = nil; + id = NETID(c->qid.path); - qunlock(&srvlk); poperror(); - if(sp->chan != nil) cclose(sp->chan); free(sp->owner); free(sp->name); free(sp); + + if(f == &global){ + qunlock(&f->lk); + return; + } + + f->ref--; + if(f->ref == 0){ + assert(f->tail == nil); + qunlock(&f->lk); + free(f); + } else if(f->ref < 0) + panic("srv ref rm %d id %uld", f->ref, id); + else + qunlock(&f->lk); } static int @@ -247,6 +382,7 @@ srvwstat(Chan *c, uchar *dp, int n) { char *strs; Srv *sp; + Fid *f; Dir d; if(c->qid.type & QTDIR) @@ -261,13 +397,15 @@ srvwstat(Chan *c, uchar *dp, int n) if(n == 0) error(Eshortstat); - qlock(&srvlk); + f = c->aux; + + qlock(&f->lk); if(waserror()){ - qunlock(&srvlk); + qunlock(&f->lk); nexterror(); } - sp = srvlookup(nil, c->qid.path); + sp = srvlookup(f->tail, nil, c->qid.path); if(sp == nil) error(Enonexist); @@ -286,7 +424,7 @@ srvwstat(Chan *c, uchar *dp, int n) if(d.mode != ~0UL) sp->perm = d.mode & 0777; - qunlock(&srvlk); + qunlock(&f->lk); poperror(); free(strs); @@ -298,16 +436,36 @@ srvwstat(Chan *c, uchar *dp, int n) static void srvclose(Chan *c) { + Fid *f; + /* * 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((c->flag & COPEN) && (c->flag & CRCLOSE)){ if(waserror()) - return; + goto ref; + srvremove(c); poperror(); + } else { + +ref: + f = c->aux; + if(f == &global) + return; + + qlock(&f->lk); + f->ref--; + if(f->ref == 0){ + assert(f->tail == nil); + qunlock(&f->lk); + free(f); + } else if(f->ref < 0) + panic("srvref close %d %uld", f->ref, NETID(c->qid.path)); + else + qunlock(&f->lk); } } @@ -322,6 +480,7 @@ static long srvwrite(Chan *c, void *va, long n, vlong) { Srv *sp; + Fid *f; Chan *c1; int fd; char buf[32]; @@ -334,15 +493,17 @@ srvwrite(Chan *c, void *va, long n, vlong) c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ - qlock(&srvlk); + f = c->aux; + + qlock(&f->lk); if(waserror()) { - qunlock(&srvlk); + qunlock(&f->lk); cclose(c1); nexterror(); } if(c1->qid.type & QTAUTH) error("cannot post auth file in srv"); - sp = srvlookup(nil, c->qid.path); + sp = srvlookup(f->tail, nil, c->qid.path); if(sp == nil) error(Enonexist); @@ -351,7 +512,7 @@ srvwrite(Chan *c, void *va, long n, vlong) sp->chan = c1; - qunlock(&srvlk); + qunlock(&f->lk); poperror(); return n; } @@ -381,11 +542,13 @@ void srvrenameuser(char *old, char *new) { Srv *sp; + Fid *f; - qlock(&srvlk); - for(sp = srv; sp != nil; sp = sp->link) { + f = &global; + qlock(&f->lk); + for(sp = f->tail; sp != nil; sp = sp->link) { if(sp->owner != nil && strcmp(old, sp->owner) == 0) kstrdup(&sp->owner, new); } - qunlock(&srvlk); + qunlock(&f->lk); }