PATHMSLOP = 20,
};
-struct
+static struct Chanalloc
{
Lock;
int fid;
unlock(r);
if(x < 0)
panic("decref pc=%#p", getcallerpc(&r));
-
return x;
}
int nt;
nt = strlen(t);
- if(nt+1 <= ns){
- memmove(s, t, nt+1);
- return;
- }
- /* too long */
- if(ns < 4){
- /* but very short! */
- strncpy(s, t, ns);
+ if(nt < ns){
+ memmove(s, t, nt);
+ s[nt] = '\0';
return;
}
- /* truncate with ... at character boundary (very rare case) */
- memmove(s, t, ns-4);
+ /* too long, truncate */
+ nt = ns-1;
+ memmove(s, t, nt);
+ s[nt] = '\0';
+ /* append ... if there is space */
ns -= 4;
- s[ns] = '\0';
+ if(ns < 0)
+ return;
/* look for first byte of UTF-8 sequence by skipping continuation bytes */
while(ns>0 && (s[--ns]&0xC0)==0x80)
;
int n;
char *t, *prev;
- n = strlen(s)+1;
+ n = strlen(s);
/* if it's a user, we can wait for memory; if not, something's very wrong */
- if(up){
- t = smalloc(n);
- setmalloctag(t, getcallerpc(&p));
- }else{
- t = malloc(n);
+ if(up != nil)
+ t = smalloc(n+1);
+ else{
+ t = malloc(n+1);
if(t == nil)
panic("kstrdup: no memory");
}
+ setmalloctag(t, getcallerpc(&p));
memmove(t, s, n);
+ t[n] = '\0';
prev = *p;
*p = t;
free(prev);
devtab[i]->reset();
}
+static void closeproc(void*);
+
void
chandevinit(void)
{
for(i=0; devtab[i] != nil; i++)
devtab[i]->init();
+ kproc("closeproc", closeproc, nil);
}
void
lock(&chanalloc);
c = chanalloc.free;
- if(c != 0)
+ if(c != 0){
chanalloc.free = c->next;
+ c->next = 0;
+ }
unlock(&chanalloc);
if(c == nil){
unlock(&chanalloc);
}
-void
-cclose(Chan *c)
-{
- if(c == nil || c->ref < 1 || c->flag&CFREE)
- panic("cclose %#p", getcallerpc(&c));
-
- DBG("cclose %p name=%s ref=%ld\n", c, chanpath(c), c->ref);
- if(decref(c))
- return;
-
- if(!waserror()){
- devtab[c->type]->close(c);
- poperror();
- }
- chanfree(c);
-}
-
/*
* Queue a chan to be closed by one of the clunk procs.
*/
struct {
Chan *head;
Chan *tail;
- int nqueued;
- int nclosed;
+ ulong nqueued;
+ ulong nclosed;
Lock l;
QLock q;
Rendez r;
} clunkq;
-void closeproc(void*);
-void
-ccloseq(Chan *c)
+static int
+clunkwork(void*)
{
- if(c == nil || c->ref < 1 || c->flag&CFREE)
- panic("ccloseq %#p", getcallerpc(&c));
-
- DBG("ccloseq %p name=%s ref=%ld\n", c, chanpath(c), c->ref);
-
- if(decref(c))
- return;
+ return clunkq.head != nil;
+}
+static void
+closechanq(Chan *c)
+{
lock(&clunkq.l);
clunkq.nqueued++;
c->next = nil;
clunkq.head = c;
clunkq.tail = c;
unlock(&clunkq.l);
-
- if(!wakeup(&clunkq.r))
- kproc("closeproc", closeproc, nil);
+ wakeup(&clunkq.r);
}
-static int
-clunkwork(void*)
+static Chan*
+closechandeq(void)
{
- return clunkq.head != nil;
+ Chan *c;
+
+ lock(&clunkq.l);
+ c = clunkq.head;
+ if(c != nil) {
+ clunkq.head = c->next;
+ clunkq.nclosed++;
+ }
+ unlock(&clunkq.l);
+ return c;
}
-void
-closeproc(void*)
+static void
+closeproc(void *)
{
Chan *c;
for(;;){
- qlock(&clunkq.q);
- if(clunkq.head == nil){
- if(!waserror()){
- tsleep(&clunkq.r, clunkwork, nil, 5000);
+ c = closechandeq();
+ if(c == nil) {
+ qlock(&clunkq.q);
+ if(!waserror()) {
+ tsleep(&clunkq.r, clunkwork, nil, 500);
poperror();
}
- if(clunkq.head == nil){
+ c = closechandeq();
+ if(c == nil) {
+ if(clunkq.q.head != nil) {
+ qunlock(&clunkq.q);
+ pexit("no work", 1);
+ }
qunlock(&clunkq.q);
- pexit("no work", 1);
+ continue;
}
+ if(clunkq.q.head == nil) {
+ if(!waserror()) {
+ kproc("closeproc", closeproc, nil);
+ poperror();
+ }
+ }
+ qunlock(&clunkq.q);
}
- lock(&clunkq.l);
- c = clunkq.head;
- clunkq.head = c->next;
- clunkq.nclosed++;
- unlock(&clunkq.l);
- qunlock(&clunkq.q);
if(!waserror()){
devtab[c->type]->close(c);
poperror();
}
}
+void
+cclose(Chan *c)
+{
+ if(c == nil || c->ref < 1 || c->flag&CFREE)
+ panic("cclose %#p", getcallerpc(&c));
+
+ DBG("cclose %p name=%s ref=%ld\n", c, chanpath(c), c->ref);
+
+ if(decref(c))
+ return;
+
+ if(devtab[c->type]->dc == L'M')
+ if((c->flag&(CRCLOSE|CCACHE)) == CCACHE)
+ if((c->qid.type&(QTEXCL|QTMOUNT|QTAUTH)) == 0)
+ if((clunkq.nqueued - clunkq.nclosed) < 64){
+ closechanq(c);
+ return;
+ }
+
+ if(!waserror()){
+ devtab[c->type]->close(c);
+ poperror();
+ }
+ chanfree(c);
+}
+
+void
+ccloseq(Chan *c)
+{
+ if(c == nil || c->ref < 1 || c->flag&CFREE)
+ panic("ccloseq %#p", getcallerpc(&c));
+
+ DBG("ccloseq %p name=%s ref=%ld\n", c, chanpath(c), c->ref);
+
+ if(decref(c))
+ return;
+
+ closechanq(c);
+}
+
/*
* Make sure we have the only copy of c. (Copy on write.)
*/
*nerror = nhave;
pathclose(path);
cclose(c);
- strcpy(up->errstr, Enotdir);
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
if(mh != nil)
putmhead(mh);
return -1;
* mh->mount->to == c, so start at mh->mount->next
*/
rlock(&mh->lock);
- f = mh->mount;
- for(f = (f? f->next: f); f; f = f->next)
- if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil)
+ if((f = mh->mount) != nil)
+ f = f->next;
+ for(; f != nil; f = f->next)
+ if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil){
+ type = f->to->type;
+ dev = f->to->dev;
break;
+ }
runlock(&mh->lock);
- if(f != nil){
- type = f->to->type;
- dev = f->to->dev;
- }
}
if(wq == nil){
cclose(c);
if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
if(nerror)
*nerror = nhave+wq->nqid+1;
- strcpy(up->errstr, Edoesnotexist);
+ kstrcpy(up->errstr, Edoesnotexist, ERRMAX);
}else{
if(nerror)
*nerror = nhave+wq->nqid;
- strcpy(up->errstr, Enotdir);
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
}
free(wq);
if(mh != nil)
nexterror();
}
for(f = m->mount; f; f = f->next){
- if(f->mflag&MCREATE){
+ if(f->to != nil && (f->mflag&MCREATE) != 0){
nc = cclone(f->to);
runlock(&m->lock);
poperror();
/* save&update the name; domount might change c */
path = c->path;
incref(path);
+ if(waserror()){
+ pathclose(path);
+ nexterror();
+ }
m = nil;
if(!nomount)
domount(&c, &m, &path);
/* now it's our copy anyway, we can put the name back */
pathclose(c->path);
c->path = path;
+ poperror();
/* record whether c is on a mount point */
c->ismtpt = m!=nil;
goto Open;
default:
- panic("unknown namec access %d\n", amode);
+ panic("unknown namec access %d", amode);
}
/* place final element in genbuf for e.g. exec */