hjfs: dentry qid checking, prevent newentry() from allocating already in use slot

always check if the directory entry qid from the loc still
matches the one on disk before doing anything. helps
catching bugs and is basically equivalent to what cwfs does
with its checktag.

make a haveloc() check in newentry() to make sure we dont
allocate a file slot thats still in use, but deleted.
this seems to fix the NPROC>1 build problems.
This commit is contained in:
cinap_lenrek 2012-11-16 13:42:45 +01:00
parent ffa6f9c6ea
commit b9bf9f1d54
5 changed files with 136 additions and 47 deletions

View file

@ -269,7 +269,8 @@ getbuf(Dev *d, uvlong off, int type, int nodata)
if(nodata) if(nodata)
b->type = type; b->type = type;
if(b->type != type && type != -1){ if(b->type != type && type != -1){
dprint("hjfs: type mismatch, dev %s, block %lld, got %T, want %T, caller %#p\n", d->name, off, b->type, type, getcallerpc(&d)); dprint("hjfs: type mismatch, dev %s, block %lld, got %T, want %T, caller %#p\n",
d->name, off, b->type, type, getcallerpc(&d));
werrstr("phase error -- type mismatch"); werrstr("phase error -- type mismatch");
putbuf(b); putbuf(b);
return nil; return nil;

View file

@ -143,8 +143,8 @@ again:
p = getbuf(fs->d, l->next->blk, TDENTRY, 0); p = getbuf(fs->d, l->next->blk, TDENTRY, 0);
if(p == nil) if(p == nil)
goto err; goto err;
d = &p->de[l->next->deind]; d = getdent(l->next, p);
for(i = 0; i < d->size; i++){ if(d != nil) for(i = 0; i < d->size; i++){
rc = getblk(fs, l->next, p, i, &r, GBREAD); rc = getblk(fs, l->next, p, i, &r, GBREAD);
if(rc <= 0) if(rc <= 0)
continue; continue;

View file

@ -8,6 +8,7 @@ void unpack(Buf *, uchar *);
Dev* newdev(char *); Dev* newdev(char *);
ThrData* getthrdata(void); ThrData* getthrdata(void);
Fs* initfs(Dev *, int, int); Fs* initfs(Dev *, int, int);
Dentry* getdent(FLoc *, Buf *);
int getfree(Fs *, uvlong *); int getfree(Fs *, uvlong *);
int putfree(Fs *, uvlong); int putfree(Fs *, uvlong);
Chan* chanattach(Fs *, int); Chan* chanattach(Fs *, int);

View file

@ -29,6 +29,35 @@ chref(Fs *fs, uvlong r, int stat)
return rc; return rc;
} }
static int
qidcmp(Qid *a, Qid *b)
{
if(a->type != b->type)
return 1;
if(a->path != b->path)
return 1;
return 0;
}
Dentry*
getdent(FLoc *l, Buf *b)
{
Dentry *d;
d = &b->de[l->deind];
if((d->mode & (DGONE | DALLOC)) == 0){
dprint("hjfs: getdent: file gone, callerpc %#p\n", getcallerpc(&l));
werrstr("phase error -- getdent");
return nil;
}
if(qidcmp(d, l) != 0){
dprint("hjfs: getdent: wrong qid, callerpc %#p\n", getcallerpc(&l));
werrstr("phase error -- getdent");
return nil;
}
return d;
}
int int
getfree(Fs *fs, uvlong *r) getfree(Fs *fs, uvlong *r)
{ {
@ -364,13 +393,13 @@ haveloc(Fs *fs, uvlong blk, int deind, Loc *next)
qlock(&fs->loctree); qlock(&fs->loctree);
l = next->child; l = next->child;
do{ if(l != nil) do{
if(l->blk == blk && l->deind == deind){ if(l->blk == blk && l->deind == deind){
qunlock(&fs->loctree); qunlock(&fs->loctree);
return 1; return 1;
} }
l = l->cnext; l = l->cnext;
}while(l != next->child); } while(l != next->child);
qunlock(&fs->loctree); qunlock(&fs->loctree);
return 0; return 0;
} }
@ -511,7 +540,11 @@ getblk(Fs *fs, FLoc *L, Buf *bd, uvlong blk, uvlong *r, int mode)
Dentry *d; Dentry *d;
b = bd; b = bd;
d = &bd->de[L->deind]; d = getdent(L, b);
if(d == nil){
dprint("hjfs: getblk: dirent gone\n");
return -1;
}
if(blk < NDIRECT){ if(blk < NDIRECT){
loc = &d->db[blk]; loc = &d->db[blk];
goto found; goto found;
@ -696,7 +729,9 @@ trunc(Fs *fs, FLoc *ll, Buf *bd, uvlong size)
uvlong l; uvlong l;
int i, j; int i, j;
d = &bd->de[ll->deind]; d = getdent(ll, bd);
if(d == nil)
return -1;
if(size >= d->size) if(size >= d->size)
goto done; goto done;
blk = HOWMANY(size, RBLOCK); blk = HOWMANY(size, RBLOCK);
@ -758,7 +793,9 @@ findentry(Fs *fs, FLoc *l, Buf *b, char *name, FLoc *rl, int dump)
uvlong r; uvlong r;
Buf *c; Buf *c;
d = &b->de[l->deind]; d = getdent(l, b);
if(d == nil)
return -1;
for(i = 0; i < d->size; i++){ for(i = 0; i < d->size; i++){
if(getblk(fs, l, b, i, &r, GBREAD) <= 0) if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
continue; continue;
@ -816,7 +853,10 @@ deltraverse(Fs *fs, Del *p, Buf *b, Del **last)
if(b == nil) if(b == nil)
return -1; return -1;
} }
s = b->de[p->deind].size; d = getdent(p, b);
if(d == nil)
return -1;
s = d->size;
for(i = 0; i < s; i++){ for(i = 0; i < s; i++){
rc = getblk(fs, p, b, i, &r, GBREAD); rc = getblk(fs, p, b, i, &r, GBREAD);
if(rc <= 0) if(rc <= 0)
@ -835,6 +875,7 @@ deltraverse(Fs *fs, Del *p, Buf *b, Del **last)
dd = emalloc(sizeof(Del)); dd = emalloc(sizeof(Del));
dd->blk = i; dd->blk = i;
dd->deind = j; dd->deind = j;
dd->Qid = d->Qid;
dd->prev = *last; dd->prev = *last;
(*last)->next = dd; (*last)->next = dd;
*last = dd; *last = dd;
@ -855,7 +896,9 @@ delete(Fs *fs, FLoc *l, Buf *b)
Buf *c; Buf *c;
Del *first, *last, *p, *q; Del *first, *last, *p, *q;
d = &b->de[l->deind]; d = getdent(l, b);
if(d == nil)
return -1;
if((d->type & QTDIR) == 0){ if((d->type & QTDIR) == 0){
trunc(fs, l, b, 0); trunc(fs, l, b, 0);
memset(d, 0, sizeof(*d)); memset(d, 0, sizeof(*d));
@ -873,9 +916,12 @@ delete(Fs *fs, FLoc *l, Buf *b)
c = getbuf(fs->d, p->blk, TDENTRY, 0); c = getbuf(fs->d, p->blk, TDENTRY, 0);
if(c == nil) if(c == nil)
continue; continue;
trunc(fs, p, c, 0); d = getdent(p, c);
memset(&c->de[p->deind], 0, sizeof(Dentry)); if(d != nil){
c->op |= BDELWRI; trunc(fs, p, c, 0);
memset(d, 0, sizeof(*d));
c->op |= BDELWRI;
}
if(p != first) if(p != first)
putbuf(c); putbuf(c);
} }
@ -885,16 +931,16 @@ delete(Fs *fs, FLoc *l, Buf *b)
int int
newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res) newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
{ {
Dentry *d; Dentry *d, *dd;
uvlong i, si, r; uvlong i, si, r;
int j, sj, rc; int j, sj, rc;
Buf *c; Buf *c;
FLoc f; FLoc f;
si = sj = -1; si = sj = -1;
d = &b->de[l->deind]; d = getdent(l, b);
for(i = 0; i <= d->size; i++){ if(d != nil) for(i = 0; i <= d->size; i++){
if(i == d->size && si != -1) if(i >= d->size && si != -1)
break; break;
rc = getblk(fs, l, b, i, &r, si == -1 ? GBCREATE : GBREAD); rc = getblk(fs, l, b, i, &r, si == -1 ? GBCREATE : GBREAD);
if(rc < 0) if(rc < 0)
@ -906,32 +952,34 @@ newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
continue; continue;
if(rc == 0){ if(rc == 0){
memset(c->de, 0, sizeof(c->de)); memset(c->de, 0, sizeof(c->de));
if(i == d->size){ if(i >= d->size){
d->size++; d->size = i+1;
b->op |= BDELWRI; b->op |= BDELWRI;
} }
c->op |= BDELWRI; c->op |= BDELWRI;
} }
for(j = 0; j < DEPERBLK; j++){ for(j = 0; j < DEPERBLK; j++){
if(si == -1 && (c->de[j].mode & DALLOC) == 0){ dd = &c->de[j];
si = i; if((dd->mode & DALLOC) != 0){
sj = j; if(strcmp(dd->name, name) == 0){
werrstr(Eexists);
putbuf(c);
return 0;
}
continue;
} }
if(si == -1 && (c->de[j].mode & DGONE) != 0 && !haveloc(fs, r, j, l)){ if(si != -1 || haveloc(fs, r, j, l))
continue;
if((dd->mode & DGONE) != 0){
memset(&f, 0, sizeof(f)); memset(&f, 0, sizeof(f));
f.blk = r; f.blk = r;
f.deind = j; f.deind = j;
if(delete(fs, &f, c) >= 0){ f.Qid = dd->Qid;
si = i; if(delete(fs, &f, c) < 0)
sj = j; continue;
}
}
if((c->de[j].mode & DALLOC) != 0 &&
strcmp(c->de[j].name, name) == 0){
werrstr(Eexists);
putbuf(c);
return 0;
} }
si = i;
sj = j;
} }
putbuf(c); putbuf(c);
} }
@ -942,5 +990,6 @@ newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
if(getblk(fs, l, b, si, &res->blk, GBWRITE) <= 0) if(getblk(fs, l, b, si, &res->blk, GBWRITE) <= 0)
return -1; return -1;
res->deind = sj; res->deind = sj;
res->Qid = (Qid){0, 0, 0};
return 1; return 1;
} }

View file

@ -53,7 +53,9 @@ chanwalk(Chan *ch, char *name)
chend(ch); chend(ch);
return -1; return -1;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil)
goto error;
if((d->type & QTDIR) == 0){ if((d->type & QTDIR) == 0){
werrstr(Enotadir); werrstr(Enotadir);
goto error; goto error;
@ -132,7 +134,9 @@ chancreat(Chan *ch, char *name, int perm, int mode)
chend(ch); chend(ch);
return -1; return -1;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil)
goto error;
if((d->type & QTDIR) == 0){ if((d->type & QTDIR) == 0){
werrstr(Enotadir); werrstr(Enotadir);
goto error; goto error;
@ -146,9 +150,9 @@ chancreat(Chan *ch, char *name, int perm, int mode)
c = getbuf(ch->fs->d, f.blk, TDENTRY, 0); c = getbuf(ch->fs->d, f.blk, TDENTRY, 0);
if(c == nil) if(c == nil)
goto error; goto error;
c->op |= BDELWRI;
b->op |= BDELWRI;
modified(ch, d); modified(ch, d);
b->op |= BDELWRI;
c->op |= BDELWRI;
if(isdir) if(isdir)
perm &= ~0777 | d->mode & 0777; perm &= ~0777 | d->mode & 0777;
else else
@ -213,7 +217,9 @@ chanopen(Chan *ch, int mode)
chend(ch); chend(ch);
return -1; return -1;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil)
goto err;
if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC)){ if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC)){
permerr: permerr:
werrstr(Eperm); werrstr(Eperm);
@ -325,7 +331,12 @@ chanwrite(Chan *ch, void *buf, ulong n, uvlong off)
chend(ch); chend(ch);
return -1; return -1;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil){
putbuf(b);
chend(ch);
return -1;
}
if((d->type & QTAPPEND) != 0) if((d->type & QTAPPEND) != 0)
off = d->size; off = d->size;
e = off + n; e = off + n;
@ -392,7 +403,12 @@ chanread(Chan *ch, void *buf, ulong n, uvlong off)
chend(ch); chend(ch);
return -1; return -1;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil){
putbuf(b);
chend(ch);
return -1;
}
if(off >= d->size) if(off >= d->size)
n = 0; n = 0;
else if(off + n > d->size) else if(off + n > d->size)
@ -465,6 +481,7 @@ int
chanstat(Chan *ch, Dir *di) chanstat(Chan *ch, Dir *di)
{ {
Buf *b; Buf *b;
Dentry *d;
chbegin(ch); chbegin(ch);
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0); b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
@ -472,7 +489,13 @@ chanstat(Chan *ch, Dir *di)
chend(ch); chend(ch);
return -1; return -1;
} }
statbuf(ch->fs, &b->de[ch->loc->deind], di, nil); d = getdent(ch->loc, b);
if(d == nil){
putbuf(b);
chend(ch);
return -1;
}
statbuf(ch->fs, d, di, nil);
putbuf(b); putbuf(b);
chend(ch); chend(ch);
return 0; return 0;
@ -504,7 +527,12 @@ chandirread(Chan *ch, void *buf, ulong n, uvlong off)
chend(ch); chend(ch);
return -1; return -1;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil){
putbuf(b);
chend(ch);
return -1;
}
if(ch->dwblk >= d->size){ if(ch->dwblk >= d->size){
putbuf(b); putbuf(b);
chend(ch); chend(ch);
@ -590,11 +618,16 @@ chanclunk(Chan *ch)
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0); b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
if(b == nil) if(b == nil)
goto err; goto err;
if(!permcheck(ch->fs, &p->de[ch->loc->next->deind], ch->uid, OWRITE)){ d = getdent(ch->loc->next, p);
if(d == nil)
goto err;
if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
werrstr(Eperm); werrstr(Eperm);
goto err; goto err;
} }
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil)
goto err;
if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0) if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0)
goto inval; goto inval;
if((d->mode & DGONE) != 0) if((d->mode & DGONE) != 0)
@ -653,7 +686,10 @@ chanwstat(Chan *ch, Dir *di)
pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0); pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
if(pb == nil) if(pb == nil)
goto error; goto error;
if(!permcheck(ch->fs, &pb->de[ch->loc->next->deind], ch->uid, OWRITE)) d = getdent(ch->loc->next, pb);
if(d == nil)
goto error;
if(!permcheck(ch->fs, d, ch->uid, OWRITE))
goto perm; goto perm;
rc = findentry(ch->fs, ch->loc->next, pb, di->name, nil, ch->flags & CHFDUMP); rc = findentry(ch->fs, ch->loc->next, pb, di->name, nil, ch->flags & CHFDUMP);
if(rc > 0) if(rc > 0)
@ -664,7 +700,9 @@ chanwstat(Chan *ch, Dir *di)
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0); b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
if(b == nil) if(b == nil)
goto error; goto error;
d = &b->de[ch->loc->deind]; d = getdent(ch->loc, b);
if(d == nil)
goto error;
isdir = (d->type & QTDIR) != 0; isdir = (d->type & QTDIR) != 0;
owner = ch->uid == d->uid || ingroup(ch->fs, ch->uid, d->gid, 1) || (ch->fs->flags & FSNOPERM) != 0; owner = ch->uid == d->uid || ingroup(ch->fs, ch->uid, d->gid, 1) || (ch->fs->flags & FSNOPERM) != 0;
if((uvlong)~di->length){ if((uvlong)~di->length){