summaryrefslogtreecommitdiff
path: root/os/port/devsrv.c
diff options
context:
space:
mode:
authorforsyth <forsyth@vitanuova.com>2010-12-20 16:41:32 +0000
committerforsyth <forsyth@vitanuova.com>2010-12-20 16:41:32 +0000
commit6452fd51371162995ee47fb7c151a9a7d2538b5f (patch)
tree241a75126e4eadc831a0c241a6158449d03c9a36 /os/port/devsrv.c
parentfb671874c11f6599b277adcd6d909f4f622c7043 (diff)
20101220-1640
Diffstat (limited to 'os/port/devsrv.c')
-rw-r--r--os/port/devsrv.c204
1 files changed, 151 insertions, 53 deletions
diff --git a/os/port/devsrv.c b/os/port/devsrv.c
index 724e007e..707c690d 100644
--- a/os/port/devsrv.c
+++ b/os/port/devsrv.c
@@ -9,22 +9,39 @@
#include "runt.h"
typedef struct SrvFile SrvFile;
+typedef struct Pending Pending;
+
+/* request pending to a server, in case a server vanishes */
+struct Pending
+{
+ Pending* next;
+ Pending* prev;
+ int fid;
+ Channel* rc;
+ Channel* wc;
+};
+
struct SrvFile
{
- char* spec;
char* name;
char* user;
ulong perm;
- vlong length;
Qid qid;
int ref;
+
+ /* root directory */
+ char* spec;
+ SrvFile* devlist;
+ SrvFile* entry;
+
+ /* file */
int opens;
int flags;
+ vlong length;
Channel* read;
Channel* write;
- SrvFile* entry;
- SrvFile* dir;
- SrvFile* devlist;
+ SrvFile* dir; /* parent directory */
+ Pending waitlist; /* pending requests from client opens */
};
enum
@@ -50,15 +67,20 @@ static SrvDev dev;
void freechan(Heap*, int);
static void freerdchan(Heap*, int);
static void freewrchan(Heap*, int);
+static void delwaiting(Pending*);
Type *Trdchan;
Type *Twrchan;
static int
-srvgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
+srvgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
{
SrvFile *f;
+ USED(name);
+ USED(tab);
+ USED(ntab);
+
if(s == DEVDOTDOT){
devdir(c, c->qid, "#s", 0, eve, 0555, dp);
return 1;
@@ -97,7 +119,7 @@ srvinit(void)
}
static int
-srvchkattach(SrvFile *d)
+srvcanattach(SrvFile *d)
{
if(strcmp(d->user, up->env->user) == 0)
return 1;
@@ -118,47 +140,47 @@ srvattach(char *spec)
Chan *c;
SrvFile *d;
+ qlock(&dev.l);
+ if(waserror()){
+ qunlock(&dev.l);
+ nexterror();
+ }
+
if(spec[0] != '\0'){
- qlock(&dev.l);
for(d = dev.devices; d != nil; d = d->devlist){
if(strcmp(spec, d->spec) == 0){
- if(srvchkattach(d) == 0){
- qunlock(&dev.l);
+ if(!srvcanattach(d))
error(Eperm);
- }
+ c = devattach('s', spec);
+ c->aux = d;
+ c->qid = d->qid;
d->ref++;
- break;
+ poperror();
+ qunlock(&dev.l);
+ return c;
}
}
- qunlock(&dev.l);
-
- if(d != nil){
- c = devattach('s', spec);
- c->aux = d;
- c->qid = d->qid;
- return c;
- }
}
d = malloc(sizeof(SrvFile));
if(d == nil)
error(Enomem);
- c = devattach('s', spec);
-
d->ref = 1;
kstrdup(&d->spec, spec);
kstrdup(&d->user, up->env->user);
snprint(up->genbuf, sizeof(up->genbuf), "srv%ld", up->env->pgrp->pgrpid);
kstrdup(&d->name, up->genbuf);
d->perm = DMDIR|0770;
-
- qlock(&dev.l);
mkqid(&d->qid, dev.pathgen++, 0, QTDIR);
+
d->devlist = dev.devices;
dev.devices = d;
+
+ poperror();
qunlock(&dev.l);
+ c = devattach('s', spec);
c->aux = d;
c->qid = d->qid;
@@ -193,6 +215,7 @@ srvwalk(Chan *c, Chan *nc, char **name, int nname)
w->clone->aux = d;
d->ref++;
}
+
poperror();
qunlock(&dev.l);
return w;
@@ -293,23 +316,23 @@ srvwstat(Chan *c, uchar *dp, int n)
}
static void
-srvputdir(SrvFile *sf)
+srvputdir(SrvFile *dir)
{
SrvFile **l, *d;
- sf->ref--;
- if(sf->ref != 0)
+ dir->ref--;
+ if(dir->ref != 0)
return;
for(l = &dev.devices; (d = *l) != nil; l = &d->devlist)
- if(d == sf){
+ if(d == dir){
*l = d->devlist;
break;
}
- free(sf->spec);
- free(sf->user);
- free(sf->name);
- free(sf);
+ free(dir->spec);
+ free(dir->user);
+ free(dir->name);
+ free(dir);
}
static void
@@ -346,30 +369,59 @@ srvunblock(SrvFile *sf, int fid)
}
static void
-srvdecr(SrvFile *sf, int remove)
+srvcancelreqs(SrvFile *sf)
+{
+ Pending *w, *ws;
+ Sys_Rread rreply;
+ Sys_Rwrite wreply;
+
+ acquire();
+ ws = &sf->waitlist;
+ while((w = ws->next) != ws){
+ delwaiting(w);
+ if(waserror() == 0){
+ if(w->rc != nil){
+ rreply.t0 = H;
+ rreply.t1 = c2string(Ehungup, strlen(Ehungup));
+ csend(w->rc, &rreply);
+ }
+ if(w->wc != nil){
+ wreply.t0 = 0;
+ wreply.t1 = c2string(Ehungup, strlen(Ehungup));
+ csend(w->wc, &wreply);
+ }
+ poperror();
+ }
+ }
+ release();
+}
+
+static void
+srvdelete(SrvFile *sf)
{
SrvFile *f, **l;
- if(remove){
- l = &sf->dir->entry;
- for(f = *l; f != nil; f = f->entry){
+ if((sf->flags & SREMOVED) == 0){
+ for(l = &sf->dir->entry; (f = *l) != nil; l = &f->entry){
if(sf == f){
*l = f->entry;
break;
}
- l = &f->entry;
}
sf->ref--;
sf->flags |= SREMOVED;
}
+}
+static void
+srvchkref(SrvFile *sf)
+{
if(sf->ref != 0)
return;
if(sf->dir != nil)
srvputdir(sf->dir);
- free(sf->spec);
free(sf->user);
free(sf->name);
free(sf);
@@ -381,7 +433,10 @@ srvfree(SrvFile *sf, int flag)
sf->flags |= flag;
if((sf->flags & (SRDCLOSE | SWRCLOSE)) == (SRDCLOSE | SWRCLOSE)){
sf->ref--;
- srvdecr(sf, (sf->flags & SREMOVED) == 0);
+ srvdelete(sf);
+ /* no further requests can arrive; return error to pending requests */
+ srvcancelreqs(sf);
+ srvchkref(sf);
}
}
@@ -397,6 +452,7 @@ freerdchan(Heap *h, int swept)
srvfree(sf, SRDCLOSE);
qunlock(&dev.l);
acquire();
+
freechan(h, swept);
}
@@ -412,6 +468,7 @@ freewrchan(Heap *h, int swept)
srvfree(sf, SWRCLOSE);
qunlock(&dev.l);
acquire();
+
freechan(h, swept);
}
@@ -430,17 +487,16 @@ srvclunk(Chan *c, int remove)
error(Eperm);
return;
}
-
opens = 0;
if(c->flag & COPEN){
opens = sf->opens--;
- if (sf->read != H || sf->write != H)
+ if(sf->read != H || sf->write != H)
srvunblock(sf, c->fid);
}
sf->ref--;
if(opens == 1){
- if((sf->flags & (SORCLOSE | SREMOVED)) == SORCLOSE)
+ if(sf->flags & SORCLOSE)
remove = 1;
}
@@ -449,8 +505,9 @@ srvclunk(Chan *c, int remove)
noperm = 1;
remove = 0;
}
-
- srvdecr(sf, remove);
+ if(remove)
+ srvdelete(sf);
+ srvchkref(sf);
qunlock(&dev.l);
if(noperm)
@@ -469,6 +526,25 @@ srvremove(Chan *c)
srvclunk(c, 1);
}
+static void
+addwaiting(SrvFile *sp, Pending *w)
+{
+ Pending *sw;
+
+ sw = &sp->waitlist;
+ w->next = sw;
+ w->prev = sw->prev;
+ sw->prev->next = w;
+ sw->prev = w;
+}
+
+static void
+delwaiting(Pending *w)
+{
+ w->next->prev = w->prev;
+ w->prev->next = w->next;
+}
+
static long
srvread(Chan *c, void *va, long count, vlong offset)
{
@@ -478,6 +554,7 @@ srvread(Chan *c, void *va, long count, vlong offset)
SrvFile *sp;
Channel *rc;
Channel *rd;
+ Pending wait;
Sys_Rread * volatile r;
Sys_FileIO_read req;
@@ -503,7 +580,7 @@ srvread(Chan *c, void *va, long count, vlong offset)
rd = sp->read;
if(rd == H)
- error(Eshutdown);
+ error(Ehungup);
rc = cnewc(dev.Rread, movtmp, 1);
ptradd(D2H(rc));
@@ -519,16 +596,23 @@ srvread(Chan *c, void *va, long count, vlong offset)
req.t3 = rc;
csend(rd, &req);
+ wait.fid = c->fid;
+ wait.rc = rc;
+ wait.wc = nil;
+ addwaiting(sp, &wait);
+
h = heap(dev.Rread);
r = H2D(Sys_Rread *, h);
ptradd(h);
if(waserror()){
ptrdel(h);
destroy(r);
+ delwaiting(&wait);
nexterror();
}
crecv(rc, r);
+ delwaiting(&wait);
if(r->t1 != H)
error(string2c(r->t1));
@@ -563,6 +647,7 @@ srvwrite(Chan *c, void *va, long count, vlong offset)
SrvFile *sp;
Channel *wc;
Channel *wr;
+ Pending wait;
Sys_Rwrite * volatile w;
Sys_FileIO_write req;
@@ -578,7 +663,7 @@ srvwrite(Chan *c, void *va, long count, vlong offset)
sp = c->aux;
wr = sp->write;
if(wr == H)
- error(Eshutdown);
+ error(Ehungup);
wc = cnewc(dev.Rwrite, movtmp, 1);
ptradd(D2H(wc));
@@ -594,6 +679,7 @@ srvwrite(Chan *c, void *va, long count, vlong offset)
req.t3 = wc;
ptradd(D2H(req.t1));
+
if(waserror()){
ptrdel(D2H(req.t1));
destroy(req.t1);
@@ -609,12 +695,20 @@ srvwrite(Chan *c, void *va, long count, vlong offset)
h = heap(dev.Rwrite);
w = H2D(Sys_Rwrite *, h);
ptradd(h);
+
+ wait.fid = c->fid;
+ wait.rc = nil;
+ wait.wc = wc;
+ addwaiting(sp, &wait);
+
if(waserror()){
+ delwaiting(&wait);
ptrdel(h);
destroy(w);
nexterror();
}
crecv(wc, w);
+ delwaiting(&wait);
if(w->t1 != H)
error(string2c(w->t1));
poperror();
@@ -639,7 +733,7 @@ srvretype(Channel *c, SrvFile *f, Type *t)
Heap *h;
h = D2H(c);
- h->t->ref--;
+ freetype(h->t);
h->t = t;
t->ref++;
c->aux = f;
@@ -667,23 +761,26 @@ srvf2c(char *dir, char *file, Sys_FileIO *io)
s = c.c->aux;
qlock(&dev.l);
+ if(waserror()){
+ qunlock(&dev.l);
+ nexterror();
+ }
for(f = s->entry; f != nil; f = f->entry){
- if(strcmp(f->name, file) == 0){
- qunlock(&dev.l);
+ if(strcmp(f->name, file) == 0)
error(Eexist);
- }
}
f = malloc(sizeof(SrvFile));
- if(f == nil){
- qunlock(&dev.l);
+ if(f == nil)
error(Enomem);
- }
srvretype(io->read, f, Trdchan);
srvretype(io->write, f, Twrchan);
f->read = io->read;
f->write = io->write;
+
+ f->waitlist.next = &f->waitlist;
+ f->waitlist.prev = &f->waitlist;
kstrdup(&f->name, file);
kstrdup(&f->user, up->env->user);
@@ -696,6 +793,7 @@ srvf2c(char *dir, char *file, Sys_FileIO *io)
s->entry = f;
s->ref++;
f->dir = s;
+ poperror();
qunlock(&dev.l);
cclose(c.c);