ref: 693f5ff94696f7386d9adb6310b5cebb954bd64f
parent: b1eca83bfc6cb960855d9e5b6457e710e335284e
author: 9ferno <[email protected]>
date: Mon Nov 8 19:15:32 EST 2021
import 9front devmnt.c
--- a/include/kernel.h
+++ b/include/kernel.h
@@ -31,14 +31,14 @@
extern int kmount(int, int, char*, int, char*);
extern int kopen(char*, int);
extern int kpipe(int[2]);
-extern long kpread(int, void*, long, vlong);
-extern long kread(int, void*, long);
+extern s32 kpread(int, void*, s32, s64);
+extern s32 kread(int, void*, s32);
extern int kremove(char*);
extern vlong kseek(int, vlong, int);
extern int kstat(char*, uchar*, int);
extern int kunmount(char*, char*);
-extern long kpwrite(int, void*, long, vlong);
-extern long kwrite(int, void*, long);
+extern s32 kpwrite(int, void*, s32, s64);
+extern s32 kwrite(int, void*, s32);
extern int kwstat(char*, uchar*, int);
extern int klisten(char*, char*);
extern int kannounce(char*, char*);
--- a/os/pc64/errstr.h
+++ b/os/pc64/errstr.h
@@ -1,6 +1,7 @@
char Enoerror[] = "no error";
char Emount[] = "inconsistent mount";
char Eunmount[] = "not mounted";
+char Eismtpt[] = "is a mount point";
char Eunion[] = "not in union";
char Emountrpc[] = "mount rpc error";
char Eshutdown[] = "mounted device shut down";
--- a/os/pc64/ff.s
+++ b/os/pc64/ff.s
@@ -6,6 +6,7 @@
ff outputs to screen now.
But, the input needs to be fixed.
make this into a devff like device that reads commands and outputs the result.
+replace variable with value (as in open firmware), to avoid exposing addresses
ff kernel, amd64 9front variant
--- a/os/port/chan.c
+++ b/os/port/chan.c
@@ -5,6 +5,8 @@
#include "fns.h"
#include "../port/error.h"
+#define DBG if(0)print
+
enum
{
PATHSLOP = 20,
@@ -54,30 +56,35 @@
return p[0]=='.' && p[1]=='.' && p[2]=='\0';
}
+/*
+ * sticking with inferno's definition of Ref
+ * as it keeps the incref() and decref() simple
+ * and also puts the proc on the fast path by the
+ * scheduler's priorities (PriLock)
+ */
int
incref(Ref *r)
{
- long old, new;
+ int x;
- do {
- old = r->ref;
- new = old+1;
- } while(!cmpswap(&r->ref, old, new));
- return new;
+ lock(&r->l);
+ x = ++r->ref;
+ unlock(&r->l);
+ return x;
}
int
decref(Ref *r)
{
- long old, new;
+ int x;
- do {
- old = r->ref;
- if(old <= 0)
- panic("decref pc=%#p", getcallerpc(&r));
- new = old-1;
- } while(!cmpswap(&r->ref, old, new));
- return new;
+ lock(&r->l);
+ x = --r->ref;
+ unlock(&r->l);
+ if(x < 0)
+ panic("decref, pc=0x%zux", getcallerpc(&r));
+
+ return x;
}
/*
@@ -159,7 +166,7 @@
/*
* closeproc() kproc is used by 9front not inferno
- * TODO not sure if closeproc() is needed for 9ferno
+ * used to close clunked chan's
*/
static void closeproc(void*);
@@ -185,6 +192,12 @@
devtab[i]->shutdown();
}
+void
+dumpchan(char *s, Chan *c)
+{
+ print("%s chanpath %s\n", s, chanpath(c));
+}
+
Chan*
newchan(void)
{
@@ -192,18 +205,19 @@
lock(&chanalloc);
c = chanalloc.free;
- if(c != 0)
+ if(c != nil){
chanalloc.free = c->next;
- unlock(&chanalloc);
-
- if(c == nil) {
+ c->next = nil;
+ } else {
+ unlock(&chanalloc);
c = smalloc(sizeof(Chan));
lock(&chanalloc);
- c->fid = ++chanalloc.fid;
c->link = chanalloc.list;
chanalloc.list = c;
- unlock(&chanalloc);
}
+ if(c->fid == 0)
+ c->fid = ++chanalloc.fid;
+ unlock(&chanalloc);
/* if you get an error before associating with a dev,
close calls rootclose, a nop */
@@ -212,18 +226,23 @@
c->ref = 1;
c->dev = 0;
c->offset = 0;
+ c->devoffset = 0;
c->iounit = 0;
- c->umh = 0;
+ c->umh = nil;
+ c->umc = nil;
c->uri = 0;
c->dri = 0;
- c->aux = 0;
- c->mchan = 0;
- c->mcp = 0;
- c->mux = 0;
- c->mqid.path = 0;
- c->mqid.vers = 0;
- c->mqid.type = 0;
+ c->dirrock = nil;
+ c->nrock = 0;
+ c->mrock = 0;
+ c->ismtpt = 0;
+ c->mcp = nil;
+ c->mux = nil;
+ c->aux = nil;
+ c->mchan = nil;
+ memset(&c->mqid, 0, sizeof(c->mqid));
c->path = nil;
+
return c;
}
@@ -288,9 +307,13 @@
if(p == nil || decref(p))
return;
+ DBG("pathclose path %s mlen %d malen %d\n", p->s, p->mlen, p->malen);
for(i=0; i<p->mlen; i++)
- if(p->mtpt[i] != nil)
+ if(p->mtpt[i] != nil){
+ DBG("pathclose i %d p->mtpt[i] path %s p->mtpt[i]->ref %d\n",
+ i, chanpath(p->mtpt[i]), p->mtpt[i]->ref);
cclose(p->mtpt[i]);
+ }
free(p->mtpt);
free(p->s);
free(p);
@@ -515,7 +538,8 @@
if(c == nil)
return;
if(c->ref < 1 || c->flag&CFREE)
- panic("cclose %#p", getcallerpc(&c));
+ panic("cclose %#p c->path %s c->ref %d c->flag 0x%ux",
+ getcallerpc(&c), chanpath(c), c->ref, c->flag);
if(decref(c))
return;
@@ -529,7 +553,7 @@
}
if(!waserror()){
- devtab[c->type]->close(c);
+ devtab[c->type]->close(c);
poperror();
}
chanfree(c);
--- a/os/port/devmnt.c
+++ b/os/port/devmnt.c
@@ -25,71 +25,63 @@
Fcall request; /* Outgoing file system protocol message */
Fcall reply; /* Incoming reply */
Mnt* m; /* Mount device during rpc */
- Rendez r; /* Place to hang out */
- uchar* rpc; /* I/O Data buffer */
- uint rpclen; /* len of buffer */
- Block *b; /* reply blocks */
- char done; /* Rpc completed */
- u64 stime; /* start time for mnt statistics */
- u32 reqlen; /* request length for mnt statistics */
- u32 replen; /* reply length for mnt statistics */
+ Rendez* z; /* Place to hang out */
+ Block* w; /* copy of write rpc for cache */
+ Block* b; /* reply blocks */
Mntrpc* flushed; /* message this one flushes */
+ char done; /* Rpc completed */
};
enum
{
- TAGSHIFT = 5, /* ulong has to be 32 bits */
+ TAGSHIFT = 5,
TAGMASK = (1<<TAGSHIFT)-1,
NMASK = (64*1024)>>TAGSHIFT,
};
-struct Mntalloc
+static struct Mntalloc
{
Lock;
Mnt* list; /* Mount devices in use */
Mnt* mntfree; /* Free list */
Mntrpc* rpcfree;
- int nrpcfree;
- int nrpcused;
- u32 id;
- u32 tagmask[NMASK];
-}mntalloc;
+ ulong nrpcfree;
+ ulong nrpcused;
+ ulong id;
+ u32int tagmask[NMASK];
+} mntalloc;
-void mattach(Mnt*, Chan*, char*);
-Mnt* mntchk(Chan*);
-void mntdirfix(uchar*, Chan*);
-Mntrpc* mntflushalloc(Mntrpc*, ulong);
-void mntflushfree(Mnt*, Mntrpc*);
-void mntfree(Mntrpc*);
-void mntgate(Mnt*);
-void mntpntfree(Mnt*);
-void mntqrm(Mnt*, Mntrpc*);
-Mntrpc* mntralloc(Chan*, ulong);
-s32 mntrdwr(int, Chan*, void*, s32, s64);
-s32 mntrpcread(Mnt*, Mntrpc*);
-void mountio(Mnt*, Mntrpc*);
-void mountmux(Mnt*, Mntrpc*);
-void mountrpc(Mnt*, Mntrpc*);
-int rpcattn(void*);
-Chan* mntchan(void);
+static Chan* mntchan(void);
+static Mnt* mntchk(Chan*);
+static void mntdirfix(uchar*, Chan*);
+static Mntrpc* mntflushalloc(Mntrpc*);
+static Mntrpc* mntflushfree(Mnt*, Mntrpc*);
+static void mntfree(Mntrpc*);
+static void mntgate(Mnt*);
+static void mntqrm(Mnt*, Mntrpc*);
+static Mntrpc* mntralloc(Chan*);
+static long mntrdwr(int, Chan*, void*, long, vlong);
+static int mntrpcread(Mnt*, Mntrpc*);
+static void mountio(Mnt*, Mntrpc*);
+static void mountmux(Mnt*, Mntrpc*);
+static void mountrpc(Mnt*, Mntrpc*);
+static int rpcattn(void*);
#define cachedchan(c) (((c)->flag & CCACHE) != 0 && (c)->mcp != nil)
char Esbadstat[] = "invalid directory entry received from server";
-char Enoversion[] = "version not established for mount channel";
+char Enoversion[] = "version not established for mount channel";
-void (*mntstats)(int, Chan*, uvlong, ulong);
-
static void
mntreset(void)
{
mntalloc.id = 1;
mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
- mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
+ mntalloc.tagmask[NMASK-1] = 0x80000000; /* don't allow NOTAG */
fmtinstall('F', fcallfmt);
-/* fmtinstall('D', dirfmt); */
-/* fmtinstall('M', dirmodefmt); */
+ fmtinstall('D', dirfmt);
+/* We can't install %M since eipfmt does and is used in the kernel [sape] */
cinit();
}
@@ -104,11 +96,12 @@
uchar *msg;
Mnt *m;
char *v;
+ Queue *q;
long k, l;
uvlong oo;
char buf[128];
- qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
+ eqlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
if(waserror()){
qunlock(&c->umqlock);
nexterror();
@@ -170,7 +163,6 @@
unlock(c);
l = devtab[c->type]->write(c, msg, k, oo);
-
if(l < k){
lock(c);
c->offset -= k - l;
@@ -179,14 +171,15 @@
}
/* message sent; receive and decode reply */
- k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
- if(k <= 0)
- error("EOF receiving fversion reply");
+ for(k = 0; k < BIT32SZ || (k < GBIT32(msg) && k < 8192+IOHDRSZ); k += l){
+ l = devtab[c->type]->read(c, msg+k, 8192+IOHDRSZ-k, c->offset);
+ if(l <= 0)
+ error("EOF receiving fversion reply");
+ lock(c);
+ c->offset += l;
+ unlock(c);
+ }
- lock(c);
- c->offset += k;
- unlock(c);
-
l = convM2S(msg, k, &f);
if(l != k)
error("bad fversion conversion on reply");
@@ -199,36 +192,52 @@
error("server tries to increase msize in fversion");
if(f.msize<256 || f.msize>1024*1024)
error("nonsense value of msize in fversion");
- if(strncmp(f.version, v, strlen(f.version)) != 0)
+ k = strlen(f.version);
+ if(strncmp(f.version, v, k) != 0)
error("bad 9P version returned from server");
+ if(returnlen > 0 && returnlen < k)
+ error(Eshort);
+ v = nil;
+ kstrdup(&v, f.version);
+ q = qopen(10*MAXRPC, 0, nil, nil);
+ if(q == nil){
+ free(v);
+ exhausted("mount queues");
+ }
+
/* now build Mnt associated with this connection */
lock(&mntalloc);
m = mntalloc.mntfree;
- if(m != 0)
+ if(m != nil)
mntalloc.mntfree = m->list;
else {
+ unlock(&mntalloc);
m = malloc(sizeof(Mnt));
- if(m == 0) {
- unlock(&mntalloc);
+ if(m == nil) {
+ qfree(q);
+ free(v);
exhausted("mount devices");
}
+ lock(&mntalloc);
}
m->list = mntalloc.list;
mntalloc.list = m;
- m->version = nil;
- kstrdup(&m->version, f.version);
+ m->version = v;
m->id = mntalloc.id++;
- m->q = qopen(10*MAXRPC, 0, nil, nil);
+ m->q = q;
m->msize = f.msize;
unlock(&mntalloc);
+ if(returnlen > 0)
+ memmove(version, f.version, k); /* length was checked above */
+
poperror(); /* msg */
free(msg);
lock(m);
- m->queue = 0;
- m->rip = 0;
+ m->queue = nil;
+ m->rip = nil;
c->flag |= CMSG;
c->mux = m;
@@ -238,13 +247,6 @@
poperror(); /* c */
qunlock(&c->umqlock);
- k = strlen(f.version);
- if(returnlen > 0){
- if(returnlen < k)
- error(Eshort);
- memmove(version, f.version, k);
- }
-
return k;
}
@@ -255,9 +257,8 @@
Mntrpc *r;
m = c->mux;
-
if(m == nil){
- mntversion(c, VERSION9P, MAXRPC, 0);
+ mntversion(c, nil, 0, 0);
m = c->mux;
if(m == nil)
error(Enoversion);
@@ -272,8 +273,7 @@
nexterror();
}
- r = mntralloc(0, m->msize);
-
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -290,6 +290,7 @@
incref(m->c);
c->mqid = c->qid;
c->mode = ORDWR;
+ c->iounit = m->msize-IOHDRSZ;
poperror(); /* r */
mntfree(r);
@@ -300,24 +301,16 @@
}
-static Chan*
-mntattach(char *muxattach)
+Chan*
+mntattach(Chan *c, Chan *ac, char *spec, int flags)
{
Mnt *m;
- Chan *c;
Mntrpc *r;
- struct bogus{
- Chan *chan;
- Chan *authchan;
- char *spec;
- int flags;
- }bogus;
- bogus = *((struct bogus *)muxattach);
- c = bogus.chan;
+ if(ac != nil && ac->mchan != c)
+ error(Ebadusefd);
m = c->mux;
-
if(m == nil){
mntversion(c, nil, 0, 0);
m = c->mux;
@@ -334,21 +327,19 @@
nexterror();
}
- r = mntralloc(0, m->msize);
-
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
}
-
r->request.type = Tattach;
r->request.fid = c->fid;
- if(bogus.authchan == nil)
+ if(ac == nil)
r->request.afid = NOFID;
else
- r->request.afid = bogus.authchan->fid;
+ r->request.afid = ac->fid;
r->request.uname = up->env->user;
- r->request.aname = bogus.spec;
+ r->request.aname = spec;
mountrpc(m, r);
c->qid = r->reply.qid;
@@ -361,12 +352,19 @@
poperror(); /* c */
- if(bogus.flags&MCACHE)
+ if(flags&MCACHE)
c->flag |= CCACHE;
return c;
}
-Chan*
+static Chan*
+noattach(char *)
+{
+ error(Enoattach);
+ return nil;
+}
+
+static Chan*
mntchan(void)
{
Chan *c;
@@ -376,13 +374,13 @@
c->dev = mntalloc.id++;
unlock(&mntalloc);
- if(c->mchan)
+ if(c->mchan != nil)
panic("mntchan non-zero %p", c->mchan);
return c;
}
static Walkqid*
-mntwalk(Chan *c, Chan *nc, char **name, s32 nname)
+mntwalk(Chan *c, Chan *nc, char **name, int nname)
{
int i, alloc;
Mnt *m;
@@ -404,7 +402,7 @@
alloc = 0;
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(nc == nil){
nc = devclone(c);
/*
@@ -412,6 +410,7 @@
* Therefore set type to 0 for now; rootclose is known to be safe.
*/
nc->type = 0;
+ nc->flag |= (c->flag & CCACHE);
alloc = 1;
}
wq->clone = nc;
@@ -471,7 +470,7 @@
if(n < BIT16SZ)
error(Eshortstat);
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -481,9 +480,8 @@
mountrpc(m, r);
if(r->reply.nstat > n){
- /* doesn't fit; just patch the count and return */
- PBIT16((uchar*)dp, r->reply.nstat);
n = BIT16SZ;
+ PBIT16((uchar*)dp, r->reply.nstat-2);
}else{
n = r->reply.nstat;
memmove(dp, r->reply.stat, n);
@@ -496,13 +494,13 @@
}
static Chan*
-mntopencreate(int type, Chan *c, char *name, s32 omode, u32 perm)
+mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
{
Mnt *m;
Mntrpc *r;
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -526,8 +524,11 @@
poperror();
mntfree(r);
- if(c->flag & CCACHE)
- copen(c);
+ if(c->flag & CCACHE){
+ if(copen(c))
+ if(type == Tcreate || (omode&OTRUNC) != 0)
+ ctrunc(c);
+ }
return c;
}
@@ -550,13 +551,13 @@
Mnt *m;
Mntrpc *r;
+ cclunk(c);
m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(waserror()){
+ r = mntralloc(c);
+ if(waserror()) {
mntfree(r);
nexterror();
}
-
r->request.type = t;
r->request.fid = c->fid;
mountrpc(m, r);
@@ -567,27 +568,22 @@
void
muxclose(Mnt *m)
{
- Mntrpc *q, *r;
+ Mnt *f, **l;
+ Mntrpc *r;
- for(q = m->queue; q; q = r) {
- r = q->list;
- mntfree(q);
+ while((r = m->queue) != nil){
+ m->queue = r->list;
+ mntfree(r);
}
m->id = 0;
free(m->version);
m->version = nil;
- mntpntfree(m);
-}
+ qfree(m->q);
+ m->q = nil;
-void
-mntpntfree(Mnt *m)
-{
- Mnt *f, **l;
- Queue *q;
-
lock(&mntalloc);
l = &mntalloc.list;
- for(f = *l; f; f = f->list) {
+ for(f = *l; f != nil; f = f->list) {
if(f == m) {
*l = m->list;
break;
@@ -596,10 +592,7 @@
}
m->list = mntalloc.mntfree;
mntalloc.mntfree = m;
- q = m->q;
unlock(&mntalloc);
-
- qfree(q);
}
static void
@@ -614,14 +607,14 @@
mntclunk(c, Tremove);
}
-static s32
-mntwstat(Chan *c, uchar *dp, s32 n)
+static int
+mntwstat(Chan *c, uchar *dp, int n)
{
Mnt *m;
Mntrpc *r;
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -633,6 +626,11 @@
mountrpc(m, r);
poperror();
mntfree(r);
+
+ if(c->flag & CCACHE)
+ if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL)
+ ctrunc(c);
+
return n;
}
@@ -640,32 +638,11 @@
mntread(Chan *c, void *buf, s32 n, s64 off)
{
uchar *p, *e;
- int nc, cache, isdir, dirlen;
+ int dirlen;
- isdir = 0;
- cache = c->flag & CCACHE;
- if(c->qid.type & QTDIR) {
- cache = 0;
- isdir = 1;
- }
-
p = buf;
- if(cache) {
- nc = cread(c, buf, n, off);
- if(nc > 0) {
- n -= nc;
- if(n == 0)
- return nc;
- p += nc;
- off += nc;
- }
- n = mntrdwr(Tread, c, p, n, off);
- cupdate(c, p, n, off);
- return n + nc;
- }
-
- n = mntrdwr(Tread, c, buf, n, off);
- if(isdir) {
+ n = mntrdwr(Tread, c, p, n, off);
+ if(c->qid.type & QTDIR) {
for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
dirlen = BIT16SZ+GBIT16(p);
if(p+dirlen > e)
@@ -685,23 +662,69 @@
return mntrdwr(Twrite, c, buf, n, off);
}
-s32
-mntrdwr(int type, Chan *c, void *buf, s32 n, s64 off)
+static void
+mntcache(Mntrpc *r)
{
+ ulong n, m;
+ vlong off;
+ Block *b;
+ Chan *c;
+
+ c = r->c;
+ if(!cachedchan(c))
+ return;
+ off = r->request.offset;
+ switch(r->reply.type){
+ case Rread:
+ m = r->reply.count;
+ if(m > r->request.count)
+ m = r->request.count;
+ for(b = r->b; m > 0 && b != nil; m -= n, b = b->next) {
+ n = BLEN(b);
+ if(m < n)
+ n = m;
+ cupdate(c, b->rp, n, off);
+ off += n;
+ }
+ break;
+ case Rwrite:
+ b = r->w;
+ if(convM2S(b->rp, BLEN(b), &r->request) == 0)
+ panic("convM2S");
+ m = r->reply.count;
+ if(m > r->request.count)
+ m = r->request.count;
+ cwrite(c, (uchar*)r->request.data, m, off);
+ break;
+ }
+}
+
+static long
+mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
+{
Mnt *m;
Mntrpc *r;
char *uba;
- int cache;
ulong cnt, nr, nreq;
m = mntchk(c);
uba = buf;
cnt = 0;
- cache = c->flag & CCACHE;
- if(c->qid.type & QTDIR)
- cache = 0;
+
for(;;) {
- r = mntralloc(c, m->msize);
+ nreq = n;
+ if(nreq > c->iounit)
+ nreq = c->iounit;
+
+ if(type == Tread && cachedchan(c)) {
+ nr = cread(c, (uchar*)uba, nreq, off);
+ if(nr > 0) {
+ nreq = nr;
+ goto Next;
+ }
+ }
+
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -710,34 +733,252 @@
r->request.fid = c->fid;
r->request.offset = off;
r->request.data = uba;
- nr = n;
- if(nr > m->msize-IOHDRSZ)
- nr = m->msize-IOHDRSZ;
- r->request.count = nr;
+ r->request.count = nreq;
mountrpc(m, r);
- nreq = r->request.count;
+ mntcache(r);
nr = r->reply.count;
if(nr > nreq)
nr = nreq;
-
if(type == Tread)
nr = readblist(r->b, (uchar*)uba, nr, 0);
- else if(cache)
- cwrite(c, (uchar*)uba, nr, off);
-
- poperror();
mntfree(r);
+ poperror();
+
+ Next:
off += nr;
uba += nr;
cnt += nr;
n -= nr;
- if(nr != nreq || n == 0 || up->killed)
+ if(nr != nreq || n == 0 || up->nnote)
break;
}
return cnt;
}
+static int
+mntprocwork(void *a)
+{
+ Mntproc *p = a;
+ return p->f != nil;
+}
+
+static void
+mntproc(void *a)
+{
+ Mntproc *p = a;
+ Chan *c;
+ Mnt *m;
+
+ while(waserror())
+ ;
+
+ m = p->m;
+ for(;;){
+ tsleep(p, mntprocwork, p, 500);
+
+ lock(m);
+ if(p->f == nil){
+ p->m = nil;
+ unlock(m);
+ pexit("no work", 1);
+ }
+ c = p->r->c;
+ unlock(m);
+
+ (*p->f)(p->r, p->a);
+
+ lock(m);
+ p->r = nil;
+ p->a = nil;
+ p->f = nil;
+ unlock(m);
+
+ cclose(c);
+ }
+}
+
+static int
+mntdefer(void (*f)(Mntrpc*, void*), Mntrpc *r, void *a)
+{
+ Mntproc *p;
+ Mnt *m;
+ int i;
+
+ m = mntchk(r->c);
+ lock(m);
+ for(i = 0; i < nelem(m->defered); i++){
+ p = &m->defered[i];
+ if(p->f != nil)
+ continue;
+
+ incref(r->c);
+ r->m = m;
+ p->r = r;
+ p->a = a;
+ p->f = f;
+
+ if(p->m == nil){
+ p->m = m;
+ unlock(m);
+ kproc("mntproc", mntproc, p, 0);
+ } else {
+ unlock(m);
+ wakeup(p);
+ }
+ return 1;
+ }
+ unlock(m);
+ return 0;
+}
+
+static void
+rahproc(Mntrpc *r, void *a)
+{
+ Mntrah *rah = a;
+
+ if(!waserror()){
+ mountrpc(r->m, r);
+ poperror();
+ }
+ r->done = 2;
+ wakeup(rah);
+}
+
+static int
+rahdone(void *v)
+{
+ Mntrpc *r = v;
+ return r->done == 2;
+}
+
+static Mntrpc*
+rahfindrpc(Mntrah *rah, vlong off)
+{
+ Mntrpc *r;
+ int i, n;
+ vlong o;
+
+ for(i=0; i<nelem(rah->r); i++){
+ if((r = rah->r[i]) == nil)
+ continue;
+ n = r->request.count;
+ o = r->request.offset;
+ if(off >= o && off < o+n)
+ return r;
+ }
+ return nil;
+}
+
void
+mntrahinit(Mntrah *rah)
+{
+ Mntrpc *r;
+ int i;
+
+ while(waserror())
+ ;
+
+ for(i=0; i<nelem(rah->r); i++){
+ if((r = rah->r[i]) != nil){
+ while(!rahdone(r))
+ sleep(rah, rahdone, r);
+ rah->r[i] = nil;
+ mntfree(r);
+ }
+ }
+ rah->i = 0;
+
+ rah->off = 0;
+ rah->seq = 0;
+
+ poperror();
+}
+
+long
+mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off)
+{
+ Mntrpc *r, **rr;
+ vlong o, w, e;
+ long n, tot;
+
+ if(len <= 0)
+ return 0;
+ if(off != rah->off){
+ rah->off = off;
+ if(rahfindrpc(rah, off) == nil)
+ rah->seq = 0;
+ }
+ rah->off += len;
+ rah->seq += len;
+ if(rah->seq >= 2*c->iounit){
+ w = (off / c->iounit) * c->iounit;
+ e = w + rah->seq;
+ for(o = w; o < e; o += c->iounit){
+ if(rahfindrpc(rah, o) != nil)
+ continue;
+
+ rr = &rah->r[rah->i % nelem(rah->r)];
+ if((r = *rr) != nil){
+ if(!rahdone(r) || (r->request.offset >= w && r->request.offset < e))
+ break;
+ *rr = nil;
+ mntfree(r);
+ }
+
+ r = mntralloc(c);
+ r->request.type = Tread;
+ r->request.fid = c->fid;
+ r->request.offset = o;
+ r->request.count = c->iounit;
+ if(!mntdefer(rahproc, r, rah)){
+ mntfree(r);
+ break;
+ }
+ *rr = r;
+ rah->i++;
+ }
+ }
+
+ tot = 0;
+ while(len > 0 && (r = rahfindrpc(rah, off)) != nil){
+ while(!rahdone(r))
+ sleep(rah, rahdone, r);
+
+ switch(r->reply.type){
+ default:
+ error(Emountrpc);
+ case Rflush:
+ error(Eintr);
+ case Rerror:
+ error(r->reply.ename);
+ case Rread:
+ break;
+ }
+ mntcache(r);
+ n = r->request.count;
+ o = r->request.offset;
+ if(r->reply.count < n)
+ n = r->reply.count;
+ n -= (off - o);
+ if(n <= 0)
+ break;
+ if(len < n)
+ n = len;
+ n = readblist(r->b, buf, n, off - o);
+ buf += n;
+ off += n;
+ tot += n;
+ len -= n;
+ }
+ if(tot > 0){
+ rah->off -= len;
+ rah->seq -= len;
+ }
+
+ return tot;
+}
+
+static void
mountrpc(Mnt *m, Mntrpc *r)
{
int t;
@@ -764,22 +1005,32 @@
}
}
-void
+static void
mountio(Mnt *m, Mntrpc *r)
{
+ Block *b;
int n;
while(waserror()) {
if(m->rip == up)
mntgate(m);
- if(strcmp(up->env->errstr, Eintr) != 0){
- mntflushfree(m, r);
+ if(strcmp(up->env->errstr, Eintr) != 0 || waserror()){
+ r = mntflushfree(m, r);
+ switch(r->request.type){
+ case Tremove:
+ case Tclunk:
+ /* botch, abandon fid */
+ if(strcmp(up->env->errstr, Ehungup) != 0)
+ r->c->fid = 0;
+ }
nexterror();
}
- r = mntflushalloc(r, m->msize);
+ r = mntflushalloc(r);
+ poperror();
}
lock(m);
+ r->z = &up->sleep;
r->m = m;
r->list = m->queue;
m->queue = r;
@@ -786,24 +1037,32 @@
unlock(m);
/* Transmit a file system rpc */
- if(m->msize == 0)
- panic("msize");
- n = convS2M(&r->request, r->rpc, m->msize);
- if(n < 0)
- panic("bad message type in mountio");
- if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
+ n = sizeS2M(&r->request);
+ b = allocb(n);
+ if(waserror()){
+ freeb(b);
+ nexterror();
+ }
+ n = convS2M(&r->request, b->wp, n);
+ if(n <= 0 || n > m->msize) {
+ print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
+ up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
error(Emountrpc);
-/* r->stime = fastticks(nil); */
- r->reqlen = n;
+ }
+ b->wp += n;
+ if(r->request.type == Twrite && cachedchan(r->c))
+ r->w = copyblock(b, n);
+ poperror();
+ devtab[m->c->type]->bwrite(m->c, b, 0);
/* Gate readers onto the mount point one at a time */
for(;;) {
lock(m);
- if(m->rip == 0)
+ if(m->rip == nil)
break;
unlock(m);
- sleep(&r->r, rpcattn, r);
- if(r->done){
+ sleep(r->z, rpcattn, r);
+ if(r->done) {
poperror();
mntflushfree(m, r);
return;
@@ -828,18 +1087,13 @@
while(qlen(m->q) < len){
b = devtab[m->c->type]->bread(m->c, m->msize, 0);
- if(b == nil)
+ if(b == nil || qaddlist(m->q, b) == 0)
return -1;
- if(blocklen(b) == 0){
- freeblist(b);
- return -1;
- }
- qaddlist(m->q, b);
}
return 0;
}
-int
+static int
mntrpcread(Mnt *m, Mntrpc *r)
{
int i, t, len, hlen;
@@ -911,55 +1165,57 @@
return 0;
}
-void
+static void
mntgate(Mnt *m)
{
Mntrpc *q;
lock(m);
- m->rip = 0;
- for(q = m->queue; q; q = q->list) {
+ m->rip = nil;
+ for(q = m->queue; q != nil; q = q->list) {
if(q->done == 0)
- if(wakeup(&q->r))
+ if(wakeup(q->z))
break;
}
unlock(m);
}
-void
+static void
mountmux(Mnt *m, Mntrpc *r)
{
Mntrpc **l, *q;
+ Rendez *z;
lock(m);
l = &m->queue;
- for(q = *l; q; q = q->list) {
+ for(q = *l; q != nil; q = q->list) {
/* look for a reply to a message */
if(q->request.tag == r->reply.tag) {
*l = q->list;
- if(q != r) {
- /*
- * Completed someone else.
- * Trade pointers to receive buffer.
- */
- q->reply = r->reply;
- q->b = r->b;
- r->b = nil;
+ if(q == r) {
+ q->done = 1;
+ unlock(m);
+ return;
}
+ /*
+ * Completed someone else.
+ * Trade pointers to receive buffer.
+ */
+ q->reply = r->reply;
+ q->b = r->b;
+ r->b = nil;
+ z = q->z;
+ coherence();
q->done = 1;
+ wakeup(z);
unlock(m);
- if(mntstats != nil)
- (*mntstats)(q->request.type,
- m->c, q->stime,
- q->reqlen + r->replen);
- if(q != r)
- wakeup(&q->r);
return;
}
l = &q->list;
}
unlock(m);
- print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
+ print("mnt: unexpected reply from %s tag %ud; type %d\n",
+ chanpath(m->c), r->reply.tag, r->reply.type);
}
/*
@@ -966,13 +1222,12 @@
* Create a new flush request and chain the previous
* requests from it
*/
-Mntrpc*
-mntflushalloc(Mntrpc *r, ulong iounit)
+static Mntrpc*
+mntflushalloc(Mntrpc *r)
{
Mntrpc *fr;
- fr = mntralloc(0, iounit);
-
+ fr = mntralloc(r->c);
fr->request.type = Tflush;
if(r->request.type == Tflush)
fr->request.oldtag = r->request.oldtag;
@@ -988,23 +1243,25 @@
* flush and the original message from the unanswered
* request queue. Mark the original message as done
* and if it hasn't been answered set the reply to to
- * Rflush.
+ * Rflush. Return the original rpc.
*/
-void
+static Mntrpc*
mntflushfree(Mnt *m, Mntrpc *r)
{
Mntrpc *fr;
- while(r){
+ while(r != nil){
fr = r->flushed;
if(!r->done){
r->reply.type = Rflush;
mntqrm(m, r);
}
- if(fr)
- mntfree(r);
+ if(fr == nil)
+ break;
+ mntfree(r);
r = fr;
}
+ return r;
}
static int
@@ -1011,19 +1268,18 @@
alloctag(void)
{
int i, j;
- ulong v;
+ u32int v;
for(i = 0; i < NMASK; i++){
v = mntalloc.tagmask[i];
- if(v == ~0UL)
+ if(v == -1)
continue;
- for(j = 0; j < 1<<TAGSHIFT; j++)
- if((v & (1<<j)) == 0){
- mntalloc.tagmask[i] |= 1<<j;
- return (i<<TAGSHIFT) + j;
- }
+ for(j = 0; (v & 1) != 0; j++)
+ v >>= 1;
+ mntalloc.tagmask[i] |= 1<<j;
+ return i<<TAGSHIFT | j;
}
- /* panic("no devmnt tags left"); */
+ panic("no friggin tags left");
return NOTAG;
}
@@ -1033,51 +1289,27 @@
mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
}
-Mntrpc*
-mntralloc(Chan *c, ulong msize)
+static Mntrpc*
+mntralloc(Chan *c)
{
Mntrpc *new;
- lock(&mntalloc);
- new = mntalloc.rpcfree;
- if(new == nil){
+ if(mntalloc.nrpcfree == 0) {
+ Alloc:
new = malloc(sizeof(Mntrpc));
- if(new == nil) {
- unlock(&mntalloc);
+ if(new == nil)
exhausted("mount rpc header");
- }
- /*
- * The header is split from the data buffer as
- * mountmux may swap the buffer with another header.
- */
- new->rpc = mallocz(msize, 0);
- if(new->rpc == nil){
- free(new);
- unlock(&mntalloc);
- exhausted("mount rpc buffer");
- }
- new->rpclen = msize;
+ lock(&mntalloc);
new->request.tag = alloctag();
- if(new->request.tag == NOTAG){
- free(new);
+ } else {
+ lock(&mntalloc);
+ new = mntalloc.rpcfree;
+ if(new == nil) {
unlock(&mntalloc);
- exhausted("rpc tags");
+ goto Alloc;
}
- }
- else {
mntalloc.rpcfree = new->list;
mntalloc.nrpcfree--;
- if(new->rpclen < msize){
- free(new->rpc);
- new->rpc = mallocz(msize, 0);
- if(new->rpc == nil){
- free(new);
- mntalloc.nrpcused--;
- unlock(&mntalloc);
- exhausted("mount rpc buffer");
- }
- new->rpclen = msize;
- }
}
mntalloc.nrpcused++;
unlock(&mntalloc);
@@ -1085,30 +1317,30 @@
new->done = 0;
new->flushed = nil;
new->b = nil;
+ new->w = nil;
return new;
}
-void
+static void
mntfree(Mntrpc *r)
{
- if(r->b != nil)
- freeblist(r->b);
+ freeb(r->w);
+ freeblist(r->b);
lock(&mntalloc);
- if(mntalloc.nrpcfree >= 10){
- free(r->rpc);
- freetag(r->request.tag);
- free(r);
- }
- else{
+ mntalloc.nrpcused--;
+ if(mntalloc.nrpcfree < 32) {
r->list = mntalloc.rpcfree;
mntalloc.rpcfree = r;
mntalloc.nrpcfree++;
+ unlock(&mntalloc);
+ return;
}
- mntalloc.nrpcused--;
+ freetag(r->request.tag);
unlock(&mntalloc);
+ free(r);
}
-void
+static void
mntqrm(Mnt *m, Mntrpc *r)
{
Mntrpc **l, *f;
@@ -1117,7 +1349,7 @@
r->done = 1;
l = &m->queue;
- for(f = *l; f; f = f->list) {
+ for(f = *l; f != nil; f = f->list) {
if(f == r) {
*l = r->list;
break;
@@ -1127,23 +1359,21 @@
unlock(m);
}
-Mnt*
+static Mnt*
mntchk(Chan *c)
{
Mnt *m;
/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
-
if(c->mchan == nil)
- panic("mntchk 1: nil mchan c %s\n", chanpath(c));
+ panic("mntchk 1: nil mchan c %s", chanpath(c));
m = c->mchan->mux;
-
if(m == nil)
print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
/*
- * Was it closed and reused (was error(Eshutdown); now, it can't happen)
+ * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
*/
if(m->id == 0 || m->id >= c->dev)
panic("mntchk 3: can't happen");
@@ -1156,7 +1386,7 @@
* reflect local values. These entries are known to be
* the first two in the Dir encoding after the count.
*/
-void
+static void
mntdirfix(uchar *dirbuf, Chan *c)
{
uint r;
@@ -1168,13 +1398,13 @@
PBIT32(dirbuf, c->dev);
}
-int
+static int
rpcattn(void *v)
{
Mntrpc *r;
r = v;
- return r->done || r->m->rip == 0;
+ return r->done || r->m->rip == nil;
}
Dev mntdevtab = {
@@ -1184,7 +1414,7 @@
mntreset,
devinit,
devshutdown,
- mntattach,
+ noattach,
mntwalk,
mntstat,
mntopen,
--- a/os/port/devprog.c
+++ b/os/port/devprog.c
@@ -487,7 +487,7 @@
&"r w rw"[(c->mode&3)<<1],
devtab[c->type]->dc, c->dev,
c->qid.path, w, c->qid.vers, c->qid.type,
- c->iounit, c->offset, c->path->s);
+ c->iounit, c->offset, chanpath(c));
return n;
}
@@ -499,7 +499,7 @@
int n, i, w, ww;
f = o->fgrp; /* f is not locked because we've acquired */
- n = readstr(0, va, count, o->pgrp->dot->path->s);
+ n = readstr(0, va, count, chanpath(o->pgrp->dot));
n += snprint(va+n, count-n, "\n");
offset = progoffset(offset, va, &n);
/* compute width of qid.path */
@@ -887,19 +887,19 @@
mntscan(mw, o->pgrp);
if(mw->mh == 0) {
mw->cddone = 1;
- i = snprint(a, n, "cd %s\n", o->pgrp->dot->path->s);
+ i = snprint(a, n, "cd %s\n", chanpath(o->pgrp->dot));
poperror();
release();
return i;
}
int2flag(mw->cm->mflag, flag);
- if(strcmp(mw->cm->to->path->s, "#M") == 0){
+ if(strcmp(chanpath(mw->cm->to), "#M") == 0){
i = snprint(a, n, "mount %s %s %s %s\n", flag,
- mw->cm->to->mchan->path->s,
- mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
+ chanpath(mw->cm->to->mchan),
+ chanpath(mw->mh->from), mw->cm->spec? mw->cm->spec : "");
}else
i = snprint(a, n, "bind %s %s %s\n", flag,
- mw->cm->to->path->s, mw->mh->from->path->s);
+ chanpath(mw->cm->to), chanpath(mw->mh->from));
poperror();
release();
return i;
--- a/os/port/error.h
+++ b/os/port/error.h
@@ -1,6 +1,7 @@
extern char Enoerror[]; /* no error */
extern char Emount[]; /* inconsistent mount */
extern char Eunmount[]; /* not mounted */
+extern char Eismtpt[]; /* is a mount point */
extern char Eunion[]; /* not in union */
extern char Emountrpc[]; /* mount rpc error */
extern char Eshutdown[]; /* mounted device shut down */
--- a/os/port/inferno.c
+++ b/os/port/inferno.c
@@ -265,7 +265,7 @@
n = f->n;
if(f->buf == (Array*)H || n < 0) {
*f->ret = 0;
- return;
+ return;
}
if(n > f->buf->len)
n = f->buf->len;
--- a/os/port/pgrp.c
+++ b/os/port/pgrp.c
@@ -12,10 +12,60 @@
Whinesecs = 10, /* frequency of out-of-resources printing */
};
-/* TODO code here is different from 9front. Need to understand why. */
-
static Ref mountid;
+void
+dumpmount(char *s, Mount *m)
+{
+ if(m == nil)
+ return;
+
+ print("%smountid %d spec %s",
+ s, m->mountid, m->spec);
+ dumpchan("to", m->to);
+}
+
+void
+dumpmhead(char *s, Mhead *mh)
+{
+ Mount *m;
+
+ if(mh == nil)
+ return;
+
+ dumpchan(" from ", mh->from);
+ print(" to\n");
+ m = mh->mount;
+ dumpmount(" ", m);
+ print(" next\n");
+ for(m = m->next; m != nil; m = m->next) {
+ dumpmount(" ", m);
+ }
+}
+
+void
+dumppgrp(char *s, Pgrp *p)
+{
+ int i;
+ Mhead *mh;
+
+ if(p == nil)
+ return;
+
+ rlock(&p->ns);
+ print("%s%p:%3ud slash %s dot %s\n mnthash\n",
+ s, p, p->pgrpid, chanpath(p->slash), chanpath(p->dot));
+ for(i = 0; i<MNTHASH; i++){
+ print(" i %d\n", i);
+ for(mh = p->mnthash[i]; mh != nil; mh = mh->hash){
+ rlock(&mh->lock);
+ dumpmhead(" ", mh);
+ runlock(&mh->lock);
+ }
+ }
+ runlock(&p->ns);
+}
+
Pgrp*
newpgrp(void)
{
@@ -48,43 +98,36 @@
void
closepgrp(Pgrp *p)
{
- Mhead **h, **e, *f, *next;
+ Mhead **h, **e, *f;
+ Mount *m;
- if(p == nil || decref(p) != 0)
+ if(p == nil || decref(p))
return;
- wlock(&p->ns);
- p->pgrpid = -1;
-
e = &p->mnthash[MNTHASH];
for(h = p->mnthash; h < e; h++) {
- for(f = *h; f; f = next) {
+ while((f = *h) != nil){
+ *h = f->hash;
wlock(&f->lock);
- cclose(f->from);
- mountfree(f->mount);
+ m = f->mount;
f->mount = nil;
- next = f->hash;
wunlock(&f->lock);
+ mountfree(m);
putmhead(f);
}
}
- wunlock(&p->ns);
cclose(p->dot);
cclose(p->slash);
free(p);
}
-void
+static void
pgrpinsert(Mount **order, Mount *m)
{
Mount *f;
- m->order = 0;
- if(*order == 0) {
- *order = m;
- return;
- }
- for(f = *order; f; f = f->order) {
+ m->order = nil;
+ for(f = *order; f != nil; f = f->order) {
if(m->mountid < f->mountid) {
m->order = f;
*order = m;
@@ -97,6 +140,8 @@
/*
* pgrpcpy MUST preserve the mountid allocation order of the parent group
+ * Hence, uses Mount.order to build a sorted linked list of mounts while
+ * copying the mounts.
*/
void
pgrpcpy(Pgrp *to, Pgrp *from)
@@ -105,6 +150,8 @@
Mount *n, *m, **link, *order;
Mhead *f, **l, *mh;
+/* print("pgrpcpy to->pgrpid %d from->pgrpid %d\n", to->pgrpid, from->pgrpid);
+ dumppgrp(" from \n ", from); */
wlock(&to->ns);
rlock(&from->ns);
order = nil;
@@ -144,6 +191,7 @@
runlock(&from->ns);
wunlock(&to->ns);
+/* dumppgrp(" to \n ", to); */
}
/* not used by 9front. why? */
@@ -224,7 +272,7 @@
int i;
Chan *c;
- if(f == nil || decref(f))
+ if(f == nil || decref(f) != 0)
return;
/*
--- a/os/port/portdat.h
+++ b/os/port/portdat.h
@@ -20,7 +20,9 @@
typedef struct Mntcache Mntcache;
typedef struct Mntparam Mntparam;
typedef struct Mount Mount;
+typedef struct Mntrah Mntrah;
typedef struct Mntrpc Mntrpc;
+typedef struct Mntproc Mntproc;
typedef struct Mntwalk Mntwalk;
typedef struct Mnt Mnt;
typedef struct Mhead Mhead;
@@ -62,6 +64,12 @@
#include "fcall.h"
#include <pool.h>
+/*
+ * sticking with inferno's definition of Ref
+ * as it keeps the incref() and decref() simple
+ * and also puts the proc on the fast path by the
+ * scheduler's priorities (PriLock)
+ */
struct Ref
{
Lock l;
@@ -116,10 +124,10 @@
struct QLock
{
- Lock use; /* to access Qlock structure */
- Proc *head; /* next process waiting for object */
- Proc *tail; /* last process waiting for object */
- s32 locked; /* flag */
+ Lock use; /* to access Qlock structure */
+ Proc *head; /* next process waiting for object */
+ Proc *tail; /* last process waiting for object */
+ s32 locked; /* flag */
};
struct RWlock
@@ -203,8 +211,8 @@
{
Ref;
Lock;
- Chan* next; /* allocation */
- Chan* link;
+ Chan *next; /* allocation */
+ Chan *link;
s64 offset; /* in fd */
s64 devoffset; /* in underlying device; see read */
u16 type;
@@ -214,25 +222,25 @@
Qid qid;
s32 fid; /* for devmnt */
u32 iounit; /* chunk size for i/o; 0==default */
- Mhead* umh; /* mount point that derived Chan; used in unionread */
- Chan* umc; /* channel in union; held for union read */
- QLock umqlock; /* serialize unionreads */
+ Mhead *umh; /* mount point that derived Chan; used in unionread */
+ Chan *umc; /* channel in union; held for union read */
+ QLock umqlock; /* serialize unionreads */
s32 uri; /* union read index */
s32 dri; /* devdirread index */
- uchar* dirrock; /* directory entry rock for translations */
+ uchar *dirrock; /* directory entry rock for translations */
int nrock;
int mrock;
QLock rockqlock;
int ismtpt;
- Mntcache*mcp; /* Mount cache pointer */
- Mnt* mux; /* Mnt for clients using me for messages */
+ Mntcache *mcp; /* Mount cache pointer */
+ Mnt *mux; /* Mnt for clients using me for messages */
union {
- void* aux;
+ void *aux;
u32 mid; /* for ns in devproc */
};
- Chan* mchan; /* channel to mounted server */
+ Chan *mchan; /* channel to mounted server */
Qid mqid; /* qid of root of mount point */
- Path* path;
+ Path *path;
};
struct Path
@@ -239,7 +247,7 @@
{
Ref;
char *s;
- Chan **mtpt; /* mtpt history */
+ Chan **mtpt; /* mtpt history */
int len; /* strlen(s) */
int alen; /* allocated length of s */
int mlen; /* number of path elements */
@@ -249,7 +257,7 @@
struct Dev
{
s32 dc;
- char* name;
+ char *name;
void (*reset)(void);
void (*init)(void);
@@ -296,16 +304,23 @@
{
s32 cddone;
u32 id;
- Mhead* mh;
- Mount* cm;
+ Mhead *mh;
+ Mount *cm;
};
+/*
+ * *order is used to build a temporary mountid sorted linked
+ * list by pgrpcpy() to preserve the mountid allocation order
+ * of the source pgrp.
+ * Alternative would be to build an array of copied mounts and
+ * qsort() it at the end before allocating mountid's.
+ */
struct Mount
{
u32 mountid;
- Mount* next;
- Mount* order;
- Chan* to; /* channel replacing channel */
+ Mount *next;
+ Mount *order;
+ Chan *to; /* channel replacing channel */
s32 mflag;
char *spec;
};
@@ -314,11 +329,34 @@
{
Ref;
RWlock lock;
- Chan* from; /* channel mounted upon */
- Mount* mount; /* what's mounted upon it */
- Mhead* hash; /* Hash chain */
+ Chan *from; /* channel mounted upon */
+ Mount *mount; /* what's mounted upon it */
+ Mhead *hash; /* Hash chain */
};
+struct Mntrah
+{
+ Rendez;
+
+ ulong vers;
+
+ vlong off;
+ vlong seq;
+
+ uint i;
+ Mntrpc *r[8];
+};
+
+struct Mntproc
+{
+ Rendez;
+
+ Mnt *m;
+ Mntrpc *r;
+ void *a;
+ void (*f)(Mntrpc*, void*);
+};
+
struct Mnt
{
Lock;
@@ -326,6 +364,7 @@
Chan *c; /* Channel to file service */
Proc *rip; /* Reader in progress */
Mntrpc *queue; /* Queue of pending requests on this channel */
+ Mntproc defered[8]; /* Worker processes for defered RPCs (read ahead) */
u32 id; /* Multiplexer id for channel check */
Mnt *list; /* Free list */
s32 flags; /* cache */
@@ -367,6 +406,10 @@
s32 flags;
};
+/*
+ * All processes in a process group share the namespace.
+ * Hence, this can be called the namespace group too
+ */
struct Pgrp
{
Ref; /* also used as a lock when mounting */
@@ -383,6 +426,11 @@
s32 pin;
};
+/*
+ * Array of Chan* (Every file is a Chan* in the server).
+ * fd (file descriptor) is the file's index in that array.
+ * fdtochan(fd) => Chan*
+ */
struct Fgrp
{
Ref;
--- a/os/port/portfns.h
+++ b/os/port/portfns.h
@@ -78,11 +78,14 @@
void drawactive(int);
void drawcmap(void);
void dumpaproc(Proc*);
+void dumpchan(char*, Chan*);
+void dumppgrp(char *s, Pgrp *p);
void dumpstack(void);
Fgrp* dupfgrp(Fgrp*);
void egrpcpy(Egrp*, Egrp*);
int emptystr(char*);
int eqchan(Chan*, Chan*, int);
+int eqchantdqid(Chan*, int, int, Qid, int);
int eqqid(Qid, Qid);
void eqlock(QLock*);
void error(char*);
@@ -95,7 +98,7 @@
int export(int, char*, int);
uvlong fastticks(uvlong*);
uvlong fastticks2ns(uvlong);
-void fdclose(Fgrp*, int);
+void fdclose(Fgrp*, int, int);
Chan* fdtochan(Fgrp*, int, int, int, int);
int findmount(Chan**, Mhead**, int, int, Qid);
void forceclosefgrp(void);
@@ -171,6 +174,7 @@
uvlong mk64fract(uvlong, uvlong);
void mkqid(Qid*, vlong, ulong, int);
void modinit(void);
+Chan* mntattach(Chan*, Chan*, char*, int);
Chan* mntauth(Chan*, char*);
int mntversion(Chan*, char*, int, int);
void mountfree(Mount*);
@@ -181,6 +185,7 @@
void mul64fract(uvlong*, uvlong, uvlong);
void muxclose(Mnt*);
Chan* namec(char*, int, int, ulong);
+void nameerror(char*, char*);
Chan* newchan(void);
Egrp* newegrp(void);
Fgrp* newfgrp(Fgrp*);
--- a/os/port/proc.c
+++ b/os/port/proc.c
@@ -896,6 +896,7 @@
continue;
dumpaproc(p);
+ dumppgrp(" ", p->env->pgrp);
}
}
--- a/os/port/sysfile.c
+++ b/os/port/sysfile.c
@@ -5,6 +5,8 @@
#include "fns.h"
#include "../port/error.h"
+#define DBG if(1)print
+
static void
unlockfgrp(Fgrp *f)
{
@@ -138,10 +140,10 @@
{
Chan *c;
- c = 0;
+ c = nil;
lock(f);
- if(fd<0 || f->maxfd<fd || (c = f->fd[fd])==0) {
+ if(fd<0 || f->maxfd<fd || (c = f->fd[fd])==nil) {
unlock(f);
error(Ebadfd);
}
@@ -209,24 +211,21 @@
}
void
-fdclose(Fgrp *f, int fd)
+fdclose(Fgrp *f, int fd, int flag)
{
- int i;
Chan *c;
lock(f);
- c = f->fd[fd];
- if(c == 0){
- /* can happen for users with shared fd tables */
+ c = fd <= f->maxfd ? f->fd[fd] : nil;
+ if(c == nil || (flag != 0 && ((f->flag[fd]|c->flag)&flag) == 0)){
unlock(f);
return;
}
- f->fd[fd] = 0;
- if(fd == f->maxfd)
- for(i=fd; --i>=0 && f->fd[i]==0; )
- f->maxfd = i;
- if(fd < f->minfd)
- f->minfd = fd;
+ f->fd[fd] = nil;
+ if(fd == f->maxfd){
+ while(fd > 0 && f->fd[fd] == nil)
+ f->maxfd = --fd;
+ }
unlock(f);
cclose(c);
}
@@ -260,7 +259,7 @@
* fdclose takes care of processes racing through here.
*/
fdtochan(f, fd, -1, 0, 0);
- fdclose(f, fd);
+ fdclose(f, fd, 0);
poperror();
return 0;
}
@@ -448,84 +447,390 @@
}
int
-kpipe(int fd[2])
+kpipe(int ufd[2])
{
- Dev *d;
- Fgrp *f;
+ static char *datastr[] = {"data", "data1"};
+ int fd[2];
Chan *c[2];
- static char *names[] = {"data", "data1"};
- f = up->env->fgrp;
-
- d = devtab[devno('|', 0)];
+ ufd[0] = ufd[1] = fd[0] = fd[1] = -1;
c[0] = namec("#|", Atodir, 0, 0);
- c[1] = 0;
- fd[0] = -1;
- fd[1] = -1;
+ c[1] = nil;
if(waserror()) {
- if(c[0] != 0)
+ if(c[0] != nil)
cclose(c[0]);
- if(c[1] != 0)
+ if(c[1] != nil)
cclose(c[1]);
- if(fd[0] >= 0)
- f->fd[fd[0]]=0;
- if(fd[1] >= 0)
- f->fd[fd[1]]=0;
return -1;
}
c[1] = cclone(c[0]);
- if(walk(&c[0], &names[0], 1, 1, nil) < 0)
+ if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
error(Egreg);
- if(walk(&c[1], &names[1], 1, 1, nil) < 0)
+ if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
error(Egreg);
- c[0] = d->open(c[0], ORDWR);
- c[1] = d->open(c[1], ORDWR);
+ c[0] = devtab[c[0]->type]->open(c[0], ORDWR);
+ c[1] = devtab[c[1]->type]->open(c[1], ORDWR);
if(newfd2(fd, c) < 0)
- error(Enofd);
+ error(Enofd);
+ ufd[0] = fd[0];
+ ufd[1] = fd[1];
poperror();
return 0;
}
-int
-kfwstat(int fd, uchar *buf, int n)
+static int
+dirfixed(uchar *p, uchar *e, Dir *d)
{
- Chan *c;
+ int len;
- if(waserror())
+ len = GBIT16(p)+BIT16SZ;
+ if(p + len > e)
return -1;
- validstat(buf, n);
- c = fdtochan(up->env->fgrp, fd, -1, 1, 1);
- if(waserror()) {
+ p += BIT16SZ; /* ignore size */
+ d->type = devno(GBIT16(p), 1);
+ p += BIT16SZ;
+ d->dev = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.type = GBIT8(p);
+ p += BIT8SZ;
+ d->qid.vers = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.path = GBIT64(p);
+ p += BIT64SZ;
+ d->mode = GBIT32(p);
+ p += BIT32SZ;
+ d->atime = GBIT32(p);
+ p += BIT32SZ;
+ d->mtime = GBIT32(p);
+ p += BIT32SZ;
+ d->length = GBIT64(p);
+
+ return len;
+}
+
+static char*
+dirname(uchar *p, int *n)
+{
+ p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
+ + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
+ *n = GBIT16(p);
+ return (char*)p+BIT16SZ;
+}
+
+static long
+dirsetname(char *name, int len, uchar *p, long n, long maxn)
+{
+ char *oname;
+ int olen;
+ long nn;
+
+ if(n == BIT16SZ)
+ return BIT16SZ;
+
+ oname = dirname(p, &olen);
+
+ nn = n+len-olen;
+ PBIT16(p, nn-BIT16SZ);
+ if(nn > maxn)
+ return BIT16SZ;
+
+ if(len != olen)
+ memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
+ PBIT16((uchar*)(oname-2), len);
+ memmove(oname, name, len);
+ return nn;
+}
+
+/*
+ * Mountfix might have caused the fixed results of the directory read
+ * to overflow the buffer. Catch the overflow in c->dirrock.
+ */
+static void
+mountrock(Chan *c, uchar *p, uchar **pe)
+{
+ uchar *e, *r;
+ int len, n;
+
+ e = *pe;
+
+ /* find last directory entry */
+ for(;;){
+ len = BIT16SZ+GBIT16(p);
+ if(p+len >= e)
+ break;
+ p += len;
+ }
+
+ /* save it away */
+ qlock(&c->rockqlock);
+ if(c->nrock+len > c->mrock){
+ n = ROUND(c->nrock+len, 1024);
+ r = smalloc(n);
+ memmove(r, c->dirrock, c->nrock);
+ free(c->dirrock);
+ c->dirrock = r;
+ c->mrock = n;
+ }
+ memmove(c->dirrock+c->nrock, p, len);
+ c->nrock += len;
+ qunlock(&c->rockqlock);
+
+ /* drop it */
+ *pe = p;
+}
+
+/*
+ * Satisfy a directory read with the results saved in c->dirrock.
+ */
+static int
+mountrockread(Chan *c, uchar *op, s32 n, s32 *nn)
+{
+ long dirlen;
+ uchar *rp, *erp, *ep, *p;
+
+ /* common case */
+ if(c->nrock == 0)
+ return 0;
+
+ /* copy out what we can */
+ qlock(&c->rockqlock);
+ rp = c->dirrock;
+ erp = rp+c->nrock;
+ p = op;
+ ep = p+n;
+ while(rp+BIT16SZ <= erp){
+ dirlen = BIT16SZ+GBIT16(rp);
+ if(p+dirlen > ep)
+ break;
+ memmove(p, rp, dirlen);
+ p += dirlen;
+ rp += dirlen;
+ }
+
+ if(p == op){
+ qunlock(&c->rockqlock);
+ return 0;
+ }
+
+ /* shift the rest */
+ if(rp != erp)
+ memmove(c->dirrock, rp, erp-rp);
+ c->nrock = erp - rp;
+
+ *nn = p - op;
+ qunlock(&c->rockqlock);
+ return 1;
+}
+
+static void
+mountrewind(Chan *c)
+{
+ c->nrock = 0;
+}
+
+/*
+ * Rewrite the results of a directory read to reflect current
+ * name space bindings and mounts. Specifically, replace
+ * directory entries for bind and mount points with the results
+ * of statting what is mounted there. Except leave the old names.
+ */
+static long
+mountfix(Chan *c, uchar *op, s32 n, s32 maxn)
+{
+ char *name;
+ int nbuf, nname;
+ Chan *nc;
+ Mhead *mh;
+ Mount *m;
+ uchar *p;
+ int dirlen, rest;
+ long l;
+ uchar *buf, *e;
+ Dir d;
+
+ p = op;
+ buf = nil;
+ nbuf = 0;
+ for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
+ dirlen = dirfixed(p, e, &d);
+ if(dirlen < 0)
+ break;
+ nc = nil;
+ mh = nil;
+ if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
+ /*
+ * If it's a union directory and the original is
+ * in the union, don't rewrite anything.
+ */
+ rlock(&mh->lock);
+ for(m = mh->mount; m != nil; m = m->next){
+ if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1)){
+ runlock(&mh->lock);
+ goto Norewrite;
+ }
+ }
+ runlock(&mh->lock);
+
+ name = dirname(p, &nname);
+ /*
+ * Do the stat but fix the name. If it fails, leave old entry.
+ * BUG: If it fails because there isn't room for the entry,
+ * what can we do? Nothing, really. Might as well skip it.
+ */
+ if(buf == nil){
+ nbuf = 4096;
+ buf = smalloc(nbuf);
+ }
+ if(waserror())
+ goto Norewrite;
+ l = devtab[nc->type]->stat(nc, buf, nbuf);
+ l = dirsetname(name, nname, buf, l, nbuf);
+ if(l == BIT16SZ)
+ error("dirsetname");
+ poperror();
+
+ /*
+ * Shift data in buffer to accomodate new entry,
+ * possibly overflowing into rock.
+ */
+ rest = e - (p+dirlen);
+ if(l > dirlen){
+ while(p+l+rest > op+maxn){
+ mountrock(c, p, &e);
+ if(e == p){
+ dirlen = 0;
+ goto Norewrite;
+ }
+ rest = e - (p+dirlen);
+ }
+ }
+ if(l != dirlen){
+ memmove(p+l, p+dirlen, rest);
+ dirlen = l;
+ e = p+dirlen+rest;
+ }
+
+ /*
+ * Rewrite directory entry.
+ */
+ memmove(p, buf, l);
+
+ Norewrite:
+ cclose(nc);
+ putmhead(mh);
+ }
+ }
+ if(buf != nil)
+ free(buf);
+
+ if(p != e)
+ error("oops in rockfix");
+
+ return e-op;
+}
+
+static u32
+wstat(Chan *c, uchar *d, int nd)
+{
+ u32 l;
+ int namelen;
+
+ if(waserror()){
cclose(c);
nexterror();
}
- n = devtab[c->type]->wstat(c, buf, n);
+ if(c->ismtpt){
+ /*
+ * Renaming mount points is disallowed to avoid surprises
+ * (which should be renamed? the mount point or the mounted Chan?).
+ */
+ dirname(d, &namelen);
+ if(namelen)
+ nameerror(chanpath(c), Eismtpt);
+ }
+ l = devtab[c->type]->wstat(c, d, nd);
poperror();
cclose(c);
+ return l;
+}
- poperror();
- return n;
+int
+kfwstat(int fd, uchar *buf, int n)
+{
+ Chan *c;
+
+ if(waserror())
+ return -1;
+
+ validstat(buf, n);
+ c = fdtochan(up->env->fgrp, fd, -1, 1, 1);
+ return (wstat(c, buf, n));
}
-long
-bindmount(Chan *c, char *old, int flag, char *spec)
+static int
+bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, int flag, char* spec)
{
int ret;
- Chan *c1;
+ Chan *c0, *c1, *ac, *bc;
- if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
+ if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
error(Ebadarg);
- c1 = namec(old, Amount, 0, 0);
+ if(ismount){
+ spec = validnamedup(spec, 1);
+ if(waserror()){
+ free(spec);
+ nexterror();
+ }
+
+ if(up->env->pgrp->noattach)
+ error(Enoattach);
+
+ ac = nil;
+ bc = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
+ if(waserror()) {
+ if(ac != nil)
+ cclose(ac);
+ cclose(bc);
+ nexterror();
+ }
+
+ if(afd >= 0)
+ ac = fdtochan(up->env->fgrp, afd, ORDWR, 0, 1);
+
+ c0 = mntattach(bc, ac, spec, flag&MCACHE);
+ poperror(); /* ac bc */
+ if(ac != nil)
+ cclose(ac);
+ cclose(bc);
+ }else{
+ spec = nil;
+ c0 = namec(arg0, Abind, 0, 0);
+ }
+
if(waserror()){
+ cclose(c0);
+ nexterror();
+ }
+
+ c1 = namec(arg1, Amount, 0, 0);
+ if(waserror()){
cclose(c1);
nexterror();
}
- ret = cmount(c, c1, flag, spec);
+ ret = cmount(c0, c1, flag, spec);
+
poperror();
cclose(c1);
+ poperror();
+ cclose(c0);
+ if(ismount){
+ fdclose(up->env->fgrp, fd, 0);
+ poperror();
+ free(spec);
+ }
return ret;
}
@@ -532,77 +837,29 @@
int
kbind(char *new, char *old, int flags)
{
- long r;
- Chan *c0;
-
- if(waserror())
- return -1;
-
- c0 = namec(new, Abind, 0, 0);
- if(waserror()) {
- cclose(c0);
- nexterror();
- }
- r = bindmount(c0, old, flags, "");
- poperror();
- cclose(c0);
-
- poperror();
- return r;
+ return bindmount(0, -1, -1, new, old, flags, nil);
}
int
kmount(int fd, int afd, char *old, int flags, char *spec)
{
- long r;
- volatile struct { Chan *c; } c0;
- volatile struct { Chan *c; } bc;
- volatile struct { Chan *c; } ac;
- Mntparam mntparam;
-
- ac.c = nil;
- bc.c = nil;
- c0.c = nil;
- if(waserror()) {
- cclose(ac.c);
- cclose(bc.c);
- cclose(c0.c);
- return -1;
- }
- bc.c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
- if(afd >= 0)
- ac.c = fdtochan(up->env->fgrp, afd, ORDWR, 0, 1);
- mntparam.chan = bc.c;
- mntparam.authchan = ac.c;
- mntparam.spec = spec;
- mntparam.flags = flags;
- c0.c = devtab[devno('M', 0)]->attach((char*)&mntparam);
-
- r = bindmount(c0.c, old, flags, spec);
- poperror();
- cclose(ac.c);
- cclose(bc.c);
- cclose(c0.c);
-
- return r;
+ return bindmount(1, fd, afd, nil, old, flags, spec);
}
int
-kunmount(char *old, char *new)
+kunmount(char *name, char *old)
{
- volatile struct { Chan *c; } cmount;
- volatile struct { Chan *c; } cmounted;
+ Chan *cmount, *cmounted;
- cmount.c = nil;
- cmounted.c = nil;
+ cmounted = nil;
+ cmount = namec(old, Amount, 0, 0);
if(waserror()) {
- cclose(cmount.c);
- cclose(cmounted.c);
- return -1;
+ cclose(cmount);
+ if(cmounted != nil)
+ cclose(cmounted);
+ nexterror();
}
-
- cmount.c = namec(new, Amount, 0, 0);
- if(old != nil && old[0] != '\0') {
+ if(name != nil) {
/*
* This has to be namec(..., Aopen, ...) because
* if arg[0] is something like /srv/cs or /fd/0,
@@ -609,13 +866,13 @@
* opening it is the only way to get at the real
* Chan underneath.
*/
- cmounted.c = namec(old, Aopen, OREAD, 0);
+ cmounted = namec(name, Aopen, OREAD, 0);
}
-
- cunmount(cmount.c, cmounted.c);
+ cunmount(cmount, cmounted);
poperror();
- cclose(cmount.c);
- cclose(cmounted.c);
+ cclose(cmount);
+ if(cmounted != nil)
+ cclose(cmounted);
return 0;
}
@@ -679,7 +936,7 @@
/* Advance to next element */
c->uri++;
- if(c->umc) {
+ if(c->umc != nil) {
cclose(c->umc);
c->umc = nil;
}
@@ -695,7 +952,7 @@
{
qlock(&c->umqlock);
c->uri = 0;
- if(c->umc){
+ if(c->umc != nil){
cclose(c->umc);
c->umc = nil;
}
@@ -702,69 +959,87 @@
qunlock(&c->umqlock);
}
-static long
-rread(int fd, void *va, long n, vlong *offp)
+static s32
+rread(int fd, void *p, s32 n, s64 *offp)
{
- int dir;
+ s32 nn, nnn;
Chan *c;
- vlong off;
+ s64 off;
- if(waserror())
- return -1;
-
c = fdtochan(up->env->fgrp, fd, OREAD, 1, 1);
- if(waserror()) {
+
+ if(waserror()){
cclose(c);
nexterror();
}
- if(n < 0)
- error(Etoosmall);
+ /*
+ * The offset is passed through on directories, normally.
+ * Sysseek complains, but pread is used by servers like exportfs,
+ * that shouldn't need to worry about this issue.
+ *
+ * Notice that c->devoffset is the offset that c's dev is seeing.
+ * The number of bytes read on this fd (c->offset) may be different
+ * due to rewritings in rockfix.
+ */
+ if(offp == nil) /* use and maintain channel's offset */
+ off = c->offset;
+ else
+ off = *offp;
+ if(off < 0)
+ error(Enegoff);
- dir = c->qid.type & QTDIR;
- if(dir && c->umh)
- n = unionread(c, va, n);
- else{
- if(offp == nil){
- lock(c); /* lock for vlong assignment */
- off = c->offset;
- unlock(c);
- }else
- off = *offp;
- if(off < 0)
- error(Enegoff);
- if(off == 0){
- if(offp == nil){
- lock(c);
- c->offset = 0;
- c->dri = 0;
- unlock(c);
- }
- unionrewind(c);
+ if(off == 0){ /* rewind to the beginning of the directory */
+ if(offp == nil || (c->qid.type & QTDIR)){
+ c->offset = 0;
+ c->devoffset = 0;
}
- n = devtab[c->type]->read(c, va, n, off);
+ mountrewind(c);
+ unionrewind(c);
+ }
+
+ if(c->qid.type & QTDIR){
+ if(mountrockread(c, p, n, &nn)){
+ /* do nothing: mountrockread filled buffer */
+ }else if(c->umh != nil)
+ nn = unionread(c, p, n);
+ else{
+ if(off != c->offset)
+ error(Edirseek);
+ nn = devtab[c->type]->read(c, p, n, c->devoffset);
+ }
+ nnn = mountfix(c, p, nn, n);
+ }else
+ nnn = nn = devtab[c->type]->read(c, p, n, off);
+
+ if(offp == nil || (c->qid.type & QTDIR)){
lock(c);
- c->offset += n;
+ c->devoffset += nn;
+ c->offset += nnn;
unlock(c);
}
poperror();
cclose(c);
-
- poperror();
- return n;
+ return nnn;
}
-long
-kread(int fd, void *va, long n)
+s32
+kread(int fd, void *va, s32 n)
{
return rread(fd, va, n, nil);
}
-long
-kpread(int fd, void *va, long n, vlong off)
+s32
+kpread(int fd, void *va, s32 n, s64 off)
{
- return rread(fd, va, n, &off);
+ s64 *offp;
+
+ if(off != ~0ULL)
+ offp = &off;
+ else
+ offp = nil;
+ return rread(fd, va, n, offp);
}
int
@@ -772,11 +1047,16 @@
{
Chan *c;
- if(waserror())
- return -1;
-
c = namec(path, Aremove, 0, 0);
- if(waserror()) {
+ /*
+ * Removing mount points is disallowed to avoid surprises
+ * (which should be removed: the mount point or the mounted Chan?).
+ */
+ if(c->ismtpt){
+ cclose(c);
+ error(Eismtpt);
+ }
+ if(waserror()){
c->type = 0; /* see below */
cclose(c);
nexterror();
@@ -789,40 +1069,35 @@
c->type = 0;
poperror();
cclose(c);
-
- poperror();
return 0;
}
-vlong
-kseek(int fd, vlong off, int whence)
+s64
+kseek(int fd, s64 o, int type)
{
- Dir *dir;
Chan *c;
+ uchar buf[sizeof(Dir)+100];
+ Dir dir;
+ int n;
+ s64 off;
- if(waserror())
- return -1;
-
c = fdtochan(up->env->fgrp, fd, -1, 1, 1);
- if(waserror()) {
+ if(waserror()){
cclose(c);
nexterror();
}
-
- if(devtab[c->type]->dc == '|')
+ if(devtab[c->type]->dc == L'|')
error(Eisstream);
- switch(whence) {
+ off = 0;
+ switch(type){
case 0:
- if(c->qid.type & QTDIR){
- if(off != 0)
- error(Eisdir);
- unionrewind(c);
- }else if(off < 0)
+ off = o;
+ if((c->qid.type & QTDIR) && off != 0)
+ error(Eisdir);
+ if(off < 0)
error(Enegoff);
- lock(c); /* lock for vlong assignment */
c->offset = off;
- unlock(c);
break;
case 1:
@@ -829,7 +1104,7 @@
if(c->qid.type & QTDIR)
error(Eisdir);
lock(c); /* lock for read/write update */
- off += c->offset;
+ off = o + c->offset;
if(off < 0){
unlock(c);
error(Enegoff);
@@ -841,23 +1116,19 @@
case 2:
if(c->qid.type & QTDIR)
error(Eisdir);
- dir = chandirstat(c);
- if(dir == nil)
+ n = devtab[c->type]->stat(c, buf, sizeof buf);
+ if(convM2D(buf, n, &dir, nil) == 0)
error("internal error: stat error in seek");
- off += dir->length;
- free(dir);
+ off = dir.length + o;
if(off < 0)
error(Enegoff);
- lock(c); /* lock for read/write update */
c->offset = off;
- unlock(c);
break;
default:
error(Ebadarg);
- break;
}
- poperror();
+ c->uri = 0;
c->dri = 0;
cclose(c);
poperror();
@@ -891,10 +1162,26 @@
validname(buf, 0);
}
+static char*
+pathlast(Path *p)
+{
+ char *s;
+
+ if(p == nil)
+ return nil;
+ if(p->len == 0)
+ return nil;
+ s = strrchr(p->s, '/');
+ if(s != nil)
+ return s+1;
+ return p->s;
+}
+
int
kstat(char *path, uchar *buf, int n)
{
Chan *c;
+ uint r;
if(waserror())
return -1;
@@ -904,35 +1191,42 @@
cclose(c);
nexterror();
}
- devtab[c->type]->stat(c, buf, n);
+ r = devtab[c->type]->stat(c, buf, n);
+ path = pathlast(c->path);
+ if(path != nil)
+ r = dirsetname(path, strlen(path), buf, r, n);
poperror();
cclose(c);
poperror();
- return 0;
+ return r;
}
-static long
-rwrite(int fd, void *va, long n, vlong *offp)
+static s32
+rwrite(int fd, void *buf, s32 len, s64 *offp)
{
Chan *c;
- vlong off;
- long m;
+ s32 m, n;
+ s64 off;
- if(waserror())
- return -1;
+ n = 0;
c = fdtochan(up->env->fgrp, fd, OWRITE, 1, 1);
if(waserror()) {
+ if(offp == nil){
+ lock(c);
+ c->offset -= n;
+ unlock(c);
+ }
cclose(c);
nexterror();
}
+
if(c->qid.type & QTDIR)
error(Eisdir);
- if(n < 0)
- error(Etoosmall);
+ n = len;
- if(offp == nil){
+ if(offp == nil){ /* use and maintain channel's offset */
lock(c);
off = c->offset;
c->offset += n;
@@ -940,19 +1234,10 @@
}else
off = *offp;
- if(waserror()){
- if(offp == nil){
- lock(c);
- c->offset -= n;
- unlock(c);
- }
- nexterror();
- }
if(off < 0)
error(Enegoff);
- m = devtab[c->type]->write(c, va, n, off);
- poperror();
+ m = devtab[c->type]->write(c, buf, n, off);
if(offp == nil && m < n){
lock(c);
c->offset -= n - m;
@@ -961,21 +1246,25 @@
poperror();
cclose(c);
-
- poperror();
- return n;
+ return m;
}
-long
-kwrite(int fd, void *va, long n)
+s32
+kwrite(int fd, void *va, s32 n)
{
return rwrite(fd, va, n, nil);
}
-long
-kpwrite(int fd, void *va, long n, vlong off)
+s32
+kpwrite(int fd, void *va, s32 n, s64 off)
{
- return rwrite(fd, va, n, &off);
+ s64 *offp;
+
+ if(off != ~0ULL)
+ offp = &off;
+ else
+ offp = nil;
+ return rwrite(fd, va, n, offp);
}
int
@@ -982,6 +1271,8 @@
kwstat(char *path, uchar *buf, int n)
{
Chan *c;
+ long l;
+ int namelen;
if(waserror())
return -1;
@@ -992,12 +1283,19 @@
cclose(c);
nexterror();
}
- n = devtab[c->type]->wstat(c, buf, n);
+ if(c->ismtpt){
+ /*
+ * Renaming mount points is disallowed to avoid surprises
+ * (which should be renamed? the mount point or the mounted Chan?).
+ */
+ dirname(buf, &namelen);
+ if(namelen)
+ nameerror(chanpath(c), Eismtpt);
+ }
+ l = devtab[c->type]->wstat(c, buf, n);
poperror();
cclose(c);
-
- poperror();
- return n;
+ return l;
}
enum