ref: 568a0b246c42d79eaa1b70cbc4442723a2efb489
parent: 62253b9d1720fb3ce962a5a6b2bdf5588267be8a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Dec 25 12:34:29 EST 2022
devsrv: Various fixes. Make global variables static to avoid symbol clashes. Order Link fields more compactly for 64-bit archs. Add a common freelink() function for freeing Boards and Srvs. Chain all Boards in a circular doubly-linked list, so srvrename() can actually change the owners of *all* the boards instead of just the root. We cannot use recursion here as that could potentially blow the kernel stack. srvname() was also only processing the root. Instead, we add a srvname field to Chan and set it to the original path of the srv file that was used to post the channel. Call openmode() at the beginning of srvopen(). The reason is if omode has invalid bits it can error and leave stuff in a inconsistent state. Prevent srvwstat() to rename a file to "clone", it is reserved. Get rid of "lease expired" error message, just use Eshutdown.
--- a/sys/src/9/port/chan.c
+++ b/sys/src/9/port/chan.c
@@ -222,6 +222,7 @@
c->mchan = nil;
memset(&c->mqid, 0, sizeof(c->mqid));
c->path = nil;
+ c->srvname = nil;
return c;
}
@@ -410,6 +411,10 @@
if(c->mchan != nil){
cclose(c->mchan);
c->mchan = nil;
+ }
+ if(c->srvname != nil){
+ free(c->srvname);
+ c->srvname = nil;
}
pathclose(c->path);
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -671,11 +671,12 @@
int2flag(cm->mflag, flag);
if(strcmp(cm->to->path->s, "#M") == 0){
- srv = srvname(cm->to->mchan);
+ srv = cm->to->mchan->srvname;
+ if(srv == nil)
+ srv = cm->to->mchan->path->s;
i = snprint(buf, nbuf, (cm->spec && *cm->spec)?
"mount %s %q %q %q\n": "mount %s %q %q\n", flag,
- srv? srv: cm->to->mchan->path->s, mh->from->path->s, cm->spec);
- free(srv);
+ srv, mh->from->path->s, cm->spec);
}else{
i = snprint(buf, nbuf, "bind %s %q %q\n", flag,
cm->to->path->s, mh->from->path->s);
--- a/sys/src/9/port/devsrv.c
+++ b/sys/src/9/port/devsrv.c
@@ -14,9 +14,9 @@
{
void *link;
char *name;
- ulong path;
char *owner;
ulong perm;
+ ulong path;
};
typedef struct Srv Srv;
@@ -32,10 +32,16 @@
Link;
Ref;
+ int closed;
+ Srv *srv;
+
+ /* tree linkage */
Board *parent;
Board *child;
- Srv *srv;
- int closed;
+
+ /* all boards list */
+ Board *prev;
+ Board *next;
};
enum{
@@ -44,11 +50,11 @@
Qlease,
};
-Board root;
-RWlock srvlk;
-ulong srvpath;
+static char clone[] = "clone";
-static char Eexpired[] = "expired lease";
+static RWlock srvlk;
+static ulong srvpath;
+static Board srvroot;
static void*
lookup(Link *l, char *name, ulong qidpath)
@@ -95,14 +101,24 @@
}
static void
+freelink(Link *l)
+{
+ free(l->name);
+ free(l->owner);
+ free(l);
+}
+
+/* always called with srvlock wlock'ed */
+static void
boardclunk(Board *b)
{
Board *ch;
- if(b == &root)
+ /* srvroot is not ref-counted nor clunkable */
+ if(b == &srvroot)
return;
- if(decref(b) != 0)
+ if(decref(b))
return;
/*
@@ -113,16 +129,18 @@
*/
while(b->closed && b->child == nil){
assert(b->srv == nil);
-
- //Root should never be closed
assert(b->parent != nil);
+
+ /* unlink from parent board */
ch = remove((Link**)&b->parent->child, b->name, ~0UL);
assert(ch == b);
+ /* unlink from all boards list */
+ ch->prev->next = ch->next;
+ ch->next->prev = ch->prev;
+
b = ch->parent;
- free(ch->name);
- free(ch->owner);
- free(ch);
+ freelink(ch);
}
}
@@ -151,11 +169,11 @@
case DEVDOTDOT:
ch = b->parent;
if(ch == nil)
- ch = &root;
+ ch = &srvroot;
goto Child;
}
if(name != nil){
- if(strcmp("clone", name) == 0)
+ if(strcmp(name, clone) == 0)
goto Clone;
sp = lookup(b->srv, name, ~0UL);
@@ -187,7 +205,7 @@
} else if(0){
Clone:
q.path = SRVQID(SRVPATH(c->qid.path), Qclone);
- devdir(c, q, "clone", 0, eve, 0444, dp);
+ devdir(c, q, clone, 0, eve, 0444, dp);
} else {
runlock(&srvlk);
poperror();
@@ -202,11 +220,12 @@
static void
srvinit(void)
{
- srvpath = 0;
- root.path = srvpath++;
- root.name = "#s";
- root.perm = 0777;
- kstrdup(&root.owner, eve);
+ srvroot.next = &srvroot;
+ srvroot.prev = &srvroot;
+ srvroot.path = srvpath++;
+ srvroot.name = "#s";
+ srvroot.perm = 0777;
+ kstrdup(&srvroot.owner, eve);
}
static Chan*
@@ -215,7 +234,7 @@
Chan *c;
c = devattach('s', spec);
- c->aux = &root;
+ c->aux = &srvroot;
return c;
}
@@ -230,7 +249,7 @@
return wq;
b = wq->clone->aux;
- if(b == &root)
+ if(b == &srvroot)
return wq;
incref(b);
@@ -254,28 +273,6 @@
return devstat(c, db, n, 0, 0, srvgen);
}
-char*
-srvname(Chan *c)
-{
- Board *b;
- Srv *sp;
- char *s;
-
- s = nil;
- b = &root;
- rlock(&srvlk);
- for(sp = b->srv; sp != nil; sp = sp->link) {
- if(sp->chan == c){
- s = malloc(3+strlen(sp->name)+1);
- if(s != nil)
- sprint(s, "#s/%s", sp->name);
- break;
- }
- }
- runlock(&srvlk);
- return s;
-}
-
static Chan*
srvopen(Chan *c, int omode)
{
@@ -283,14 +280,16 @@
Srv *sp;
Chan *nc;
char buf[64];
+ int mode;
if(omode&OTRUNC)
error(Eexist);
if(omode&ORCLOSE)
error(Eperm);
+ mode = openmode(omode);
b = c->aux;
- if(SRVTYPE(c->qid.path) == Qclone){;
+ if(SRVTYPE(c->qid.path) == Qclone){
wlock(&srvlk);
if(waserror()){
wunlock(&srvlk);
@@ -297,25 +296,31 @@
nexterror();
}
if(b->closed)
- error(Eexpired);
-
+ error(Eshutdown);
ch = smalloc(sizeof *ch);
ch->ref = 1;
ch->perm = 0770;
- kstrdup(&ch->owner, up->user);
do {
ch->path = srvpath++;
snprint(buf, sizeof buf, "%ld", ch->path);
} while(lookup(b->srv, buf, ~0UL) != nil);
-
- ch->parent = b;
kstrdup(&ch->name, buf);
+ kstrdup(&ch->owner, up->user);
+ /* link to all boards list */
+ ch->next = &srvroot;
+ ch->prev = srvroot.prev;
+ ch->next->prev = ch;
+ ch->prev->next = ch;
+
+ /* link to parent board */
+ ch->parent = b;
ch->link = b->child;
b->child = ch;
+
c->aux = ch;
c->qid.path = SRVQID(ch->path, Qlease);
- c->mode = openmode(omode);
+ c->mode = mode;
boardclunk(b);
wunlock(&srvlk);
poperror();
@@ -328,12 +333,10 @@
nexterror();
}
if(c->qid.type == QTDIR){
- if(omode & ORCLOSE)
- error(Eperm);
if(omode != OREAD)
error(Eisdir);
devpermcheck(b->owner, b->perm, omode);
- c->mode = openmode(omode);
+ c->mode = mode;
c->flag |= COPEN;
c->offset = 0;
runlock(&srvlk);
@@ -341,17 +344,18 @@
return c;
}
if(b->closed)
- error(Eexpired);
+ error(Eshutdown);
sp = lookup(b->srv, nil, c->qid.path);
- if(sp == nil || sp->chan == nil)
+ if(sp == nil)
error(Eshutdown);
-
- if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
+ nc = sp->chan;
+ if(nc == nil)
+ error(Eshutdown);
+ if(mode != nc->mode && nc->mode != ORDWR)
error(Eperm);
devpermcheck(sp->owner, sp->perm, omode);
- nc = sp->chan;
incref(nc);
runlock(&srvlk);
@@ -373,8 +377,8 @@
if(strlen(name) >= sizeof(up->genbuf))
error(Etoolong);
- if(strcmp("clone", name) == 0)
- error("reserved name");
+ if(strcmp(name, clone) == 0)
+ error(Eexist);
sp = smalloc(sizeof *sp);
kstrdup(&sp->name, name);
@@ -384,13 +388,11 @@
wlock(&srvlk);
if(waserror()){
wunlock(&srvlk);
- free(sp->owner);
- free(sp->name);
- free(sp);
+ freelink(sp);
nexterror();
}
if(b->closed)
- error(Eexpired);
+ error(Eshutdown);
devpermcheck(b->owner, b->perm, OWRITE);
if(lookup(b->srv, name, ~0UL) != nil)
error(Eexist);
@@ -451,9 +453,7 @@
if(sp->chan != nil)
cclose(sp->chan);
- free(sp->owner);
- free(sp->name);
- free(sp);
+ freelink(sp);
}
static int
@@ -469,7 +469,7 @@
case Qclone:
error(Eperm);
}
- if(c->qid.type == QTDIR && c->aux == &root)
+ if(c->qid.type == QTDIR && c->aux == &srvroot)
error(Eperm);
strs = smalloc(n);
@@ -488,7 +488,7 @@
nexterror();
}
if(b->closed)
- error(Eexpired);
+ error(Eshutdown);
if(c->qid.type == QTDIR)
lp = b;
@@ -506,7 +506,9 @@
if(strlen(d.name) >= sizeof(up->genbuf))
error(Etoolong);
- //Ensure new name doesn't conflict with old names
+ /* Ensure new name doesn't conflict with old names */
+ if(strcmp(d.name, clone) == 0)
+ error(Eexist);
if(c->qid.type == QTDIR)
s = b->parent;
else
@@ -537,7 +539,7 @@
Srv *sp, *link;
Board *b;
- if(c->flag & CRCLOSE && SRVTYPE(c->qid.path) != Qlease){
+ if((c->flag & CRCLOSE) != 0 && SRVTYPE(c->qid.path) != Qlease){
/*
* in theory we need to override any changes in removability
* since open, but since all that's checked is the owner,
@@ -551,7 +553,7 @@
}
b = c->aux;
- if(b == &root)
+ if(b == &srvroot)
return;
wlock(&srvlk);
@@ -572,9 +574,7 @@
link = sp->link;
if(sp->chan != nil)
ccloseq(sp->chan);
- free(sp->owner);
- free(sp->name);
- free(sp);
+ freelink(sp);
}
}
@@ -627,7 +627,7 @@
nexterror();
}
if(b->closed)
- error(Eexpired);
+ error(Eshutdown);
if(c1->qid.type & QTAUTH)
error("cannot post auth file in srv");
sp = lookup(b->srv, nil, c->qid.path);
@@ -639,6 +639,9 @@
sp->chan = c1;
+ if(c1->srvname == nil)
+ kstrdup(&c1->srvname, c->path->s);
+
wunlock(&srvlk);
poperror();
return n;
@@ -671,12 +674,15 @@
Board *b;
Srv *sp;
- b = &root;
wlock(&srvlk);
- kstrdup(&b->owner, new);
- for(sp = b->srv; sp != nil; sp = sp->link) {
- if(sp->owner != nil && strcmp(old, sp->owner) == 0)
- kstrdup(&sp->owner, new);
- }
+ b = &srvroot;
+ do {
+ if(strcmp(b->owner, old) == 0)
+ kstrdup(&b->owner, new);
+ for(sp = b->srv; sp != nil; sp = sp->link)
+ if(strcmp(sp->owner, old) == 0)
+ kstrdup(&sp->owner, new);
+ b = b->next;
+ } while(b != &srvroot);
wunlock(&srvlk);
}
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -193,6 +193,7 @@
Chan* mchan; /* channel to mounted server */
Qid mqid; /* qid of root of mount point */
Path* path;
+ char* srvname; /* /srv/name when posted */
};
struct Path