ref: 8e50556f14d6fc1271c606dce05f1229bed7ae93
parent: 7a8e875668d92020548d07b5ad30f7b83b61d1fc
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Nov 20 19:37:35 EST 2018
upas/fs: rework the refcounting, use 64bit qid path, add checks add function to check the refcounts for Mailbox and Message on a fid use the full 64 bit of the qid.path, so we can use the full 32 bit for the id instead of only maintaining refcount for the top message, msgincref() now adds a reference to all its parent messages including self and top message. then we can check in recursive delmessage() that all the parts have a zero refcount. remove the Fid.mtop field, it was never used. make sure deletion and flag changes only affect the top message. cachefree(): only look for top message in lru. sub-parts are never added to the cache. use the nparts field when reading sub-part of existing message, so that we parse the index right in case the number of parts somehow changed. messages marked as Deleted but still in inbox should be written to the index.
--- a/sys/src/cmd/upas/fs/cache.c
+++ b/sys/src/cmd/upas/fs/cache.c
@@ -31,17 +31,29 @@
addlru(mb, m);
}
-static void
-cachefree0(Mailbox *mb, Message *m, int force)
+void
+cachefree(Mailbox *mb, Message *m, int force)
{
- long sz, i;
- Message *s;
+ long i;
+ Message *s, **ll;
if(!force && mb->fetch == nil)
return;
+ if(Topmsg(mb, m)){
+ for(ll = &mb->lru; *ll != nil; ll = &((*ll)->lru)){
+ if(*ll == m){
+ mb->nlru--;
+ *ll = m->lru;
+ m->lru = nil;
+ break;
+ }
+ }
+ if(mb->decache)
+ mb->decache(mb, m);
+ mb->cached -= m->csize;
+ }
for(s = m->part; s; s = s->next)
cachefree(mb, s, force);
- dprint("cachefree: %D %p, %p\n", m->fileid, m, m->start);
if(m->mallocd){
free(m->start);
m->mallocd = 0;
@@ -58,7 +70,6 @@
free(m->references[i]);
m->references[i] = 0;
}
- sz = m->csize;
m->csize = 0;
m->start = 0;
m->end = 0;
@@ -69,33 +80,13 @@
m->bend = 0;
m->mheader = 0;
m->mhend = 0;
- if(mb->decache)
- mb->decache(mb, m);
m->decoded = 0;
m->converted = 0;
m->badchars = 0;
m->cstate &= ~(Cheader|Cbody);
- if(Topmsg(mb, m))
- mb->cached -= sz;
}
void
-cachefree(Mailbox *mb, Message *m, int force)
-{
- Message **ll;
-
- for(ll = &mb->lru; *ll != nil; ll = &((*ll)->lru)){
- if(*ll == m){
- mb->nlru--;
- *ll = m->lru;
- m->lru = nil;
- break;
- }
- }
- cachefree0(mb, m, force);
-}
-
-void
putcache(Mailbox *mb, Message *m)
{
int n;
@@ -277,7 +268,8 @@
}
if(y == 0)
return 0;
- dprint("middlecache %d [%D] %lud %lud\n", m->id, m->fileid, (ulong)(m->end - m->start), m->size);
+ dprint("middlecache %lud [%D] %lud %lud\n",
+ m->id, m->fileid, (ulong)(m->end - m->start), m->size);
return cachebody(mb, m);
}
@@ -292,7 +284,7 @@
return 0;
if(!Topmsg(mb, m))
return middlecache(mb, m);
- dprint("cacheheaders %d %D\n", m->id, m->fileid);
+ dprint("cacheheaders %lud %D\n", m->id, m->fileid);
if(m->size < 10000)
r = fetch(mb, m, 0, m->size);
else for(r = 0; (o = m->end - m->start) < m->size; ){
@@ -327,7 +319,7 @@
m->deleted = Dup; /* no dups allowed */
}else
mtreeadd(mb, m);
- dprint("%d %#A\n", m->id, m->digest);
+ dprint("%lud %#A\n", m->id, m->digest);
}
int
@@ -337,10 +329,10 @@
while(!Topmsg(mb, m))
m = m->whole;
- if(!mb->fetch || m->cstate&Cbody)
+ if(mb->fetch == nil || m->cstate&Cbody)
return 0;
o = m->end - m->start;
- dprint("cachebody %d [%D] %lud %lud %s", m->id, m->fileid, o, m->size, cstate(m));
+ dprint("cachebody %lud [%D] %lud %lud %s", m->id, m->fileid, o, m->size, cstate(m));
if(o < m->size)
if(fetch(mb, m, o, m->size - o) < 0)
return -1;
@@ -389,7 +381,7 @@
{
if(m->deleted || !m->inmbox)
return -1;
- msgincref(m);
+ msgincref(mb, m);
cacheidx(mb, m);
if((m->cstate & Cidx) == 0){
logmsg(m, "%s: can't cache: %s: %r", mb->path, m->name);
--- a/sys/src/cmd/upas/fs/dat.h
+++ b/sys/src/cmd/upas/fs/dat.h
@@ -74,7 +74,7 @@
typedef struct Message Message;
struct Message {
- int id;
+ ulong id;
int refs;
int subname;
char name[12];
@@ -152,7 +152,7 @@
struct Mailbox {
int refs;
Mailbox *next;
- int id;
+ ulong id;
int flags;
char rmflags;
char dolock; /* lock when syncing? */
@@ -209,7 +209,6 @@
void putcache(Mailbox*, Message*); /* asymmetricial */
void cachefree(Mailbox*, Message*, int);
-Message* gettopmsg(Mailbox*, Message*);
char* syncmbox(Mailbox*, int);
void* emalloc(ulong);
void* erealloc(void*, ulong);
@@ -223,13 +222,12 @@
void eprint(char*, ...);
void iprint(char *, ...);
-int newid(void);
char* newmbox(char*, char*, int, Mailbox**);
void freembox(char*);
char* removembox(char*, int);
void syncallmboxes(void);
void logmsg(Message*, char*, ...);
-void msgincref(Message*);
+void msgincref(Mailbox*, Message*);
void msgdecref(Mailbox*, Message*);
void mboxincref(Mailbox*);
void mboxdecref(Mailbox*);
@@ -306,7 +304,7 @@
Qmboxctl,
};
-#define PATH(id, f) ((((id) & 0xfffff)<<10) | (f))
+#define PATH(id, f) (((uvlong)(id)<<10) | (f))
#define FILE(p) ((p) & 0x3ff)
/* hash table to aid in name lookup, all files have an entry */
@@ -314,16 +312,16 @@
struct Hash {
Hash *next;
char *name;
- ulong ppath;
+ uvlong ppath;
Qid qid;
Mailbox *mb;
Message *m;
};
-uint hash(char*);
-Hash *hlook(ulong, char*);
-void henter(ulong, char*, Qid, Message*, Mailbox*);
-void hfree(ulong, char*);
+ulong hash(char*);
+Hash *hlook(uvlong, char*);
+void henter(uvlong, char*, Qid, Message*, Mailbox*);
+void hfree(uvlong, char*);
char *intern(char*);
void idxfree(Idx*);
--- a/sys/src/cmd/upas/fs/fs.c
+++ b/sys/src/cmd/upas/fs/fs.c
@@ -14,7 +14,6 @@
Fid *next;
Mailbox *mb;
Message *m;
- Message *mtop; /* top level message */
long foff; /* offset/DIRLEN of finger */
Message *fptr; /* pointer to message at off */
@@ -132,8 +131,6 @@
void
sanemsg(Message *m)
{
- assert(m->refs < 100);
- assert(m->next != m);
if(m->end < m->start)
abort();
if(m->ballocd && (m->start <= m->body && m->end >= m->body))
@@ -769,13 +766,10 @@
return nil;
nf->busy = 1;
nf->open = 0;
- nf->mb = f->mb;
- if(nf->mb)
+ if(nf->mb = f->mb)
mboxincref(nf->mb);
if(nf->m = f->m)
- msgincref(gettopmsg(nf->mb, nf->m));
- if(nf->mtop = f->mtop)
- msgincref(nf->mtop);
+ msgincref(nf->mb, nf->m);
nf->qid = f->qid;
return nf;
}
@@ -798,9 +792,10 @@
{
char *rv, *p;
int t, t1;
- Mailbox *mb;
Hash *h;
+ if(f->qid.type != QTDIR)
+ return Enotdir;
t = FILE(f->qid.path);
rv = Enotexist;
@@ -815,26 +810,16 @@
}else
h = hlook(f->qid.path, name);
if(h != nil){
+ if(h->mb)
+ mboxincref(h->mb);
+ if(h->m)
+ msgincref(h->mb, h->m);
if(f->m)
- msgdecref(f->mb, gettopmsg(f->mb, f->m));
- if(f->mb && f->mb != h->mb)
+ msgdecref(f->mb, f->m);
+ if(f->mb)
mboxdecref(f->mb);
- f->mb = h->mb;
f->m = h->m;
- if(f->m)
- msgincref(gettopmsg(f->mb, f->m));
- switch(t){
- case Qtop:
- if(f->mb)
- mboxincref(f->mb);
- break;
- case Qmbox:
- if(f->m){
- msgincref(f->m);
- f->mtop = f->m;
- }
- break;
- }
+ f->mb = h->mb;
f->qid = h->qid;
if(t1 < Qmax)
f->qid.path = PATH(f->m->id, t1); /* sleezy speedup */
@@ -842,18 +827,9 @@
}else if((p = strchr(name, '.')) != nil && *name != '.'){
*p = 0;
goto retry;
- }
-
- if(rv == nil)
- return rv;
-
- if(strcmp(name, ".") == 0)
- return nil;
-
- if(f->qid.type != QTDIR)
- return Enotdir;
-
- if(strcmp(name, "..") == 0){
+ } else if(strcmp(name, ".") == 0){
+ rv = nil;
+ } else if(strcmp(name, "..") == 0){
switch(t){
case Qtop:
f->qid.path = PATH(0, Qtop);
@@ -864,9 +840,8 @@
f->qid.path = PATH(0, Qtop);
f->qid.type = QTDIR;
f->qid.vers = 0;
- mb = f->mb;
+ mboxdecref(f->mb);
f->mb = nil;
- mboxdecref(mb);
break;
case Qdir:
if(Topmsg(f->mb, f->m)){
@@ -873,11 +848,11 @@
f->qid.path = PATH(f->mb->id, Qmbox);
f->qid.type = QTDIR;
f->qid.vers = f->mb->vers;
- msgdecref(f->mb, f->mtop);
msgdecref(f->mb, f->m);
- f->m = f->mtop = nil;
+ f->m = nil;
} else {
- /* refs don't change; still the same message */
+ msgincref(f->mb, f->m->whole);
+ msgdecref(f->mb, f->m);
f->m = f->m->whole;
f->qid.path = PATH(f->m->id, Qdir);
f->qid.type = QTDIR;
@@ -987,6 +962,8 @@
pos += m;
for(mb = mbl; mb != nil; mb = mb->next){
+ assert(mb->refs > 0);
+
mkstat(&d, mb, nil, Qmbox);
m = convD2M(&d, &buf[n], blen - n);
if(off <= pos){
@@ -1008,6 +985,8 @@
long pos;
Message *msg;
+ assert(f->mb->refs > 0);
+
if(off == 0)
syncmbox(f->mb, 1);
@@ -1198,7 +1177,6 @@
{
char *argvbuf[1024], **argv, file[Pathlen], *err, *v0;
int i, t, argc, flags;
- Message *m;
t = FILE(f->qid.path);
rhdr.count = thdr.count;
@@ -1288,21 +1266,19 @@
}
return Ebadctl;
case Qmboxctl:
- if(f->mb && f->mb->ctl){
- argc = tokenize(thdr.data, argv, nelem(argvbuf));
- if(argc == 0)
- return Ebadctl;
- return f->mb->ctl(f->mb, argc, argv);
- }
- break;
+ if(f->mb->ctl == nil)
+ break;
+ argc = tokenize(thdr.data, argv, nelem(argvbuf));
+ if(argc == 0)
+ return Ebadctl;
+ return f->mb->ctl(f->mb, argc, argv);
case Qflags:
/*
* modifying flags on subparts is a little strange.
*/
- if(!f->mb || !f->m)
+ if(!Topmsg(f->mb, f->m))
break;
- m = gettopmsg(f->mb, f->m);
- return modflags(f->mb, m, thdr.data);
+ return modflags(f->mb, f->m, thdr.data);
}
return Eperm;
}
@@ -1310,21 +1286,17 @@
char*
rclunk(Fid *f)
{
- Mailbox *mb;
-
f->busy = 1;
/* coherence(); */
f->fid = -1;
f->open = 0;
- mb = f->mb;
- if(f->mtop)
- msgdecref(mb, f->mtop);
- if(f->m)
- msgdecref(mb, gettopmsg(mb, f->m));
- f->m = f->mtop = nil;
- if(mb){
+ if(f->m != nil){
+ msgdecref(f->mb, f->m);
+ f->m = nil;
+ }
+ if(f->mb != nil){
+ mboxdecref(f->mb);
f->mb = nil;
- mboxdecref(mb);
}
f->busy = 0;
return 0;
@@ -1333,7 +1305,7 @@
char *
rremove(Fid *f)
{
- if(f->m != nil && f->m->deleted == 0)
+ if(f->mb != nil && f->m != nil && Topmsg(f->mb, f->m) && f->m->deleted == 0)
f->m->deleted = Deleted;
return rclunk(f);
}
@@ -1357,6 +1329,28 @@
return Eperm;
}
+static Fid*
+checkfid(Fid *f)
+{
+ switch(FILE(f->qid.path)){
+ case Qtop:
+ case Qctl:
+ assert(f->mb == nil);
+ assert(f->m == nil);
+ break;
+ case Qmbox:
+ case Qmboxctl:
+ assert(f->mb != nil && f->mb->refs > 0);
+ assert(f->m == nil);
+ break;
+ default:
+ assert(f->mb != nil && f->mb->refs > 0);
+ assert(f->m != nil && f->m->refs > 0);
+ break;
+ }
+ return f;
+}
+
Fid*
newfid(int fid)
{
@@ -1365,7 +1359,7 @@
ff = 0;
for(f = fids; f; f = f->next)
if(f->fid == fid)
- return f;
+ return checkfid(f);
else if(!ff && !f->busy)
ff = f;
if(ff){
@@ -1475,20 +1469,6 @@
}
}
-int
-newid(void)
-{
- int rv;
- static int id;
- static Lock idlock;
-
- lock(&idlock);
- rv = ++id;
- unlock(&idlock);
-
- return rv;
-}
-
void
error(char *s)
{
@@ -1600,10 +1580,10 @@
return to - buf;
}
-uint
+ulong
hash(char *s)
{
- uint c, h;
+ ulong c, h;
h = 0;
while(c = *s++)
@@ -1613,9 +1593,9 @@
}
Hash*
-hlook(ulong ppath, char *name)
+hlook(uvlong ppath, char *name)
{
- int h;
+ ulong h;
Hash *hp;
h = (hash(name)+ppath) % nelem(htab);
@@ -1626,9 +1606,9 @@
}
void
-henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
+henter(uvlong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
{
- int h;
+ ulong h;
Hash *hp, **l;
h = (hash(name)+ppath) % nelem(htab);
@@ -1650,9 +1630,9 @@
}
void
-hfree(ulong ppath, char *name)
+hfree(uvlong ppath, char *name)
{
- int h;
+ ulong h;
Hash *hp, **l;
h = (hash(name)+ppath) % nelem(htab);
--- a/sys/src/cmd/upas/fs/idx.c
+++ b/sys/src/cmd/upas/fs/idx.c
@@ -366,18 +366,20 @@
/*
* read in mutable information.
* currently this is only flags
+ * and nparts.
*/
redux++;
if(level == 0)
m->deleted &= ~Dmark;
- if(m->nparts)
+ n = m->nparts;
+ m->nparts = strtoul(f[21], 0, 0);
if(rdidx(b, mb, m, m->nparts, level + 1) == -1)
goto dead;
ll = &m->next;
- idprint("%d seen before %d... %.2ux", level, m->id, m->cstate);
+ idprint("%d seen before %lud... %.2ux", level, m->id, m->cstate);
flags = m->flags;
m->flags |= strtoul(f[1], 0, 16);
- if(flags != m->flags)
+ if(flags != m->flags || n != m->nparts)
m->cstate |= Cidxstale;
m->cstate |= Cidx;
idprint("→%.2ux\n", m->cstate);
@@ -385,7 +387,7 @@
continue;
}
m = newmessage(parent);
- idprint("%d new %d %#A\n", level, m->id, digest);
+ idprint("%d new %lud %#A\n", level, m->id, digest);
m->digest = digest;
m->flags = strtoul(f[1], 0, 16);
m->fileid = rdfileid(f[2], level);
--- a/sys/src/cmd/upas/fs/mbox.c
+++ b/sys/src/cmd/upas/fs/mbox.c
@@ -191,6 +191,20 @@
head[i].len = strlen(head[i].type);
}
+static ulong
+newid(void)
+{
+ ulong rv;
+ static ulong id;
+ static Lock idlock;
+
+ lock(&idlock);
+ rv = ++id;
+ unlock(&idlock);
+
+ return rv;
+}
+
char*
newmbox(char *path, char *name, int flags, Mailbox **r)
{
@@ -271,50 +285,42 @@
{
Mailbox **l, *mb;
- for(l=&mbl; *l != nil; l=&(*l)->next)
- if(strcmp(name, (*l)->name) == 0){
- mb = *l;
+ for(l = &mbl; (mb = *l) != nil; l = &mb->next)
+ if(strcmp(name, mb->name) == 0){
*l = mb->next;
+ mb->next = nil;
+ hfree(PATH(0, Qtop), mb->name);
+ if(mb->ctl)
+ hfree(PATH(mb->id, Qmbox), "ctl");
mboxdecref(mb);
break;
}
- hfree(PATH(0, Qtop), name);
}
-void
-syncallmboxes(void)
-{
- char *err;
- Mailbox *m;
-
- for(m = mbl; m != nil; m = m->next)
- if(err = syncmbox(m, 0))
- eprint("syncmbox: %s\n", err);
-}
-
-
char*
removembox(char *name, int flags)
{
- int found;
- Mailbox **l, *mb;
+ Mailbox *mb;
- found = 0;
- for(l=&mbl; *l != nil; l=&(*l)->next)
- if(strcmp(name, (*l)->path) == 0){
- mb = *l;
- *l = mb->next;
+ for(mb = mbl; mb != nil; mb = mb->next)
+ if(strcmp(name, mb->path) == 0){
mb->flags |= ORCLOSE;
mb->rmflags = flags;
- mboxdecref(mb);
- found = 1;
- break;
+ freembox(mb->name);
+ return 0;
}
- hfree(PATH(0, Qtop), name);
+ return "maibox not found";
+}
- if(found == 0)
- return "maibox not found";
- return 0;
+void
+syncallmboxes(void)
+{
+ Mailbox *mb;
+ char *err;
+
+ for(mb = mbl; mb != nil; mb = mb->next)
+ if(err = syncmbox(mb, 0))
+ eprint("syncmbox: %s\n", err);
}
/*
@@ -347,7 +353,7 @@
return r;
}
-Message*
+static Message*
gettopmsg(Mailbox *mb, Message *m)
{
while(!Topmsg(mb, m))
@@ -355,7 +361,7 @@
return m;
}
-void
+static void
datesec(Mailbox *mb, Message *m)
{
vlong v;
@@ -1011,16 +1017,20 @@
{
Message **l;
+ assert(m->refs == 0);
+ while(m->part)
+ delmessage(mb, m->part);
+
mb->vers++;
msgfreed++;
- if(m->whole != m){
+ if(m != m->whole){
/* unchain from parent */
for(l = &m->whole->part; *l && *l != m; l = &(*l)->next)
;
if(*l != nil)
*l = m->next;
-
+ m->next = nil;
/* clear out of name lookup hash table */
if(m->whole->whole == m->whole)
hfree(PATH(mb->id, Qmbox), m->name);
@@ -1027,15 +1037,12 @@
else
hfree(PATH(m->whole->id, Qdir), m->name);
hfree(PATH(m->id, Qdir), "xxx"); /* sleezy speedup */
- }
- if(Topmsg(mb, m)){
- if(m != mb->root)
+
+ if(Topmsg(mb, m))
mtreedelete(mb, m);
cachefree(mb, m, 1);
+ idxfree(m);
}
- idxfree(m);
- while(m->part)
- delmessage(mb, m->part);
free(m->unixfrom);
free(m->unixheader);
free(m->date822);
@@ -1093,7 +1100,7 @@
if(argc%2)
return "bad flags";
- for(mb = mbl; mb; mb = mb->next)
+ for(mb = mbl; mb != nil; mb = mb->next)
if(strcmp(*argv, mb->name) == 0)
break;
if(mb == nil)
@@ -1114,21 +1121,33 @@
}
void
-msgincref(Message *m)
+msgincref(Mailbox *mb, Message *m)
{
- m->refs++;
+ assert(mb->refs > 0);
+ for(;; m = m->whole){
+ assert(m->refs >= 0);
+ m->refs++;
+ if(Topmsg(mb, m))
+ break;
+ }
}
void
msgdecref(Mailbox *mb, Message *m)
{
- assert(m->refs > 0);
- m->refs--;
- if(m->refs == 0){
- if(m->deleted)
- syncmbox(mb, 1);
- else
- putcache(mb, m);
+ assert(mb->refs >= 0);
+ for(;; m = m->whole){
+ assert(m->refs > 0);
+ m->refs--;
+ if(Topmsg(mb, m)){
+ if(m->refs == 0){
+ if(m->deleted)
+ syncmbox(mb, 1);
+ else
+ putcache(mb, m);
+ }
+ break;
+ }
}
}
@@ -1156,21 +1175,18 @@
mboxdecref(Mailbox *mb)
{
assert(mb->refs > 0);
- mb->refs--;
- if(mb->refs == 0){
- syncmbox(mb, 1);
- delmessage(mb, mb->root);
- if(mb->ctl)
- hfree(PATH(mb->id, Qmbox), "ctl");
- if(mb->close)
- mb->close(mb);
- if(mb->flags & ORCLOSE && mb->remove)
- if(mb->remove(mb, mb->rmflags))
- rmidx(mb->path, mb->rmflags);
- free(mb->mtree);
- free(mb->d);
- free(mb);
- }
+ if(--mb->refs)
+ return;
+ syncmbox(mb, 1);
+ delmessage(mb, mb->root);
+ if(mb->close)
+ mb->close(mb);
+ if(mb->flags & ORCLOSE && mb->remove)
+ if(mb->remove(mb, mb->rmflags))
+ rmidx(mb->path, mb->rmflags);
+ free(mb->mtree);
+ free(mb->d);
+ free(mb);
}
--- a/sys/src/cmd/upas/fs/mkfile
+++ b/sys/src/cmd/upas/fs/mkfile
@@ -1,7 +1,7 @@
</$objtype/mkfile
<../mkupas
-TARG= fs\
+TARG=fs
OFILES=\
cache.$O\