ref: 9a3942718357a83c534ee5a37ae9bd3bc85a2f50
parent: 08cd0ea8d4cb921004e8f06caf0f99c944057bdf
author: cinap_lenrek <[email protected]>
date: Sat Nov 17 19:06:54 EST 2012
hjfs: fix dump / create getdent() introduced a bug as the qid check fails in the case when we walk to DUMPROOTQID, but get ROOTQID in the directory instead. newentry() getblk(..., GBCREATE) caused the whole directory to get dumped until it hit a free slot. we cannot do this because this changes the addresses of Dentries of files but doesnt update the loctree. this caused the bogus walks when we hit a different directory than we expected. what we do now is the following: newentry() was changed to never dump anything. it will just read the directory and return a the address of a free slot or create a new block having space for one. chancreat() then makes a loc in the loctree for the free slot, drops the dirent buffer and calls willmodify() on the new slot. this will dump the block containing the slot (and possible other slots) and updates the loctree to the new version. after that, chancreate() modifies the slot filling the Dentry. there should be no race, as newentry() skips slots that have a loc in the loctree. theres one case where newentry() can dump the block immidiately when it is called from dump. added new parameter for that and documented in the comment. createuserdir() was simplified by just calling chancreat(). to get arround the permission check, a new per channel flag CHFNOPERM was added.
--- a/sys/src/cmd/hjfs/auth.c
+++ b/sys/src/cmd/hjfs/auth.c
@@ -366,54 +366,14 @@
createuserdir(Fs *fs, char *name, short uid)
{
Chan *ch;
- Buf *b, *c;
- Dentry *d;
- FLoc f;
- ch = chanattach(fs, 0);
+ ch = chanattach(fs, CHFNOPERM);
if(ch == nil)
return;
- ch->uid = -1;
- if(chanwalk(ch, "usr") <= 0 || (ch->loc->type & QTDIR) == 0){
- direrr:
- chanclunk(ch);
- return;
- }
- chbegin(ch);
- if(willmodify(ch->fs, ch->loc, 0) < 0){
- direrr1:
- chend(ch);
- goto direrr;
- }
- b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
- if(b == nil)
- goto direrr1;
- if(newentry(ch->fs, ch->loc, b, name, &f) <= 0){
- direrr2:
- putbuf(b);
- goto direrr1;
- }
- modified(ch, &b->de[ch->loc->deind]);
- c = getbuf(ch->fs->d, f.blk, TDENTRY, 0);
- if(c == nil)
- goto direrr2;
- c->op |= BDELWRI;
- d = &c->de[f.deind];
- memset(d, 0, sizeof(*d));
- if(newqid(fs, &d->path) < 0){
- direrr3:
- putbuf(c);
- goto direrr2;
- }
- strncpy(d->name, name, NAMELEN - 1);
- d->uid = uid;
- d->muid = uid;
- d->gid = uid;
- d->mode = DALLOC | 0775;
- d->type = QTDIR;
- d->atime = time(0);
- d->mtime = d->atime;
- goto direrr3;
+ ch->uid = uid;
+ if(chanwalk(ch, "usr") > 0)
+ chancreat(ch, name, DMDIR | 0775, OREAD);
+ chanclunk(ch);
}
int
--- a/sys/src/cmd/hjfs/buf.c
+++ b/sys/src/cmd/hjfs/buf.c
@@ -266,6 +266,11 @@
req.nodata = nodata;
send(getb, &req);
recv(th->resp, &b);
+ if(b->error != nil){
+ werrstr("%s", b->error);
+ putbuf(b);
+ return nil;
+ }
if(nodata)
b->type = type;
if(b->type != type && type != -1){
@@ -272,11 +277,6 @@
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");
- putbuf(b);
- return nil;
- }
- if(b->error != nil){
- werrstr("%s", b->error);
putbuf(b);
return nil;
}
--- a/sys/src/cmd/hjfs/conv.c
+++ b/sys/src/cmd/hjfs/conv.c
@@ -53,7 +53,7 @@
GET64(b->sb.qidpath);
break;
case TDENTRY:
- for(d = b->de; d < b->de + nelem(b->de); d++){
+ for(d = b->de; d < &b->de[DEPERBLK]; d++){
GETS(d->name, NAMELEN);
GET16(d->uid);
GET16(d->muid);
--- a/sys/src/cmd/hjfs/dat.h
+++ b/sys/src/cmd/hjfs/dat.h
@@ -185,8 +185,10 @@
CHWRITE = 2,
CHRCLOSE = 4,
CHFDUMP = 1,
+
CHFNOLOCK = 2,
CHFRO = 4,
+ CHFNOPERM = 8,
CHWBUSY = 1,
CHWCLUNK = 2,
--- a/sys/src/cmd/hjfs/dump.c
+++ b/sys/src/cmd/hjfs/dump.c
@@ -24,7 +24,7 @@
putbuf(ba);
return -1;
}
- rc = newentry(fs, b, bb, nname, &c);
+ rc = newentry(fs, b, bb, nname, &c, 1);
if(rc < 0){
err1:
putbuf(bb);
@@ -35,7 +35,7 @@
if(bc == nil)
goto err1;
d = &bc->de[c.deind];
- memcpy(d, &ba->de[a->deind], sizeof(Dentry));
+ memcpy(d, &ba->de[a->deind], sizeof(*d));
strcpy(d->name, nname);
for(i = 0; i < NDIRECT; i++)
if(d->db[i] != 0)
@@ -116,6 +116,7 @@
willmodify(Fs *fs, Loc *l, int nolock)
{
Buf *p;
+ Loc *m;
uvlong i, r;
Dentry *d;
int rc;
@@ -150,7 +151,7 @@
continue;
if(r == l->blk)
goto found;
- }
+ }
phase:
werrstr("willmodify -- phase error");
putbuf(p);
@@ -164,7 +165,19 @@
if(rc == 0)
goto phase;
putbuf(p);
- l->blk = r;
+
+ if(r != l->blk){
+ /*
+ * block got dumped, update the loctree so locs
+ * point to the new block.
+ */
+ qlock(&fs->loctree);
+ for(m = l->cnext; m != l; m = m->cnext)
+ if(m->blk == l->blk)
+ m->blk = r;
+ l->blk = r;
+ qunlock(&fs->loctree);
+ }
done:
l->flags |= LDUMPED;
if(!nolock){
--- a/sys/src/cmd/hjfs/fns.h
+++ b/sys/src/cmd/hjfs/fns.h
@@ -44,7 +44,7 @@
int dprint(char *fmt, ...);
int delete(Fs *, FLoc *, Buf *);
int chref(Fs *, uvlong, int);
-int newentry(Fs *, Loc *, Buf *, char *, FLoc *);
+int newentry(Fs *, Loc *, Buf *, char *, FLoc *, int);
int namevalid(char *);
int usersload(Fs *, Chan *);
int userssave(Fs *, Chan *);
--- a/sys/src/cmd/hjfs/fs1.c
+++ b/sys/src/cmd/hjfs/fs1.c
@@ -34,8 +34,12 @@
{
if(a->type != b->type)
return 1;
- if(a->path != b->path)
+ if(a->path != b->path){
+ /* special case for dump, this is ok */
+ if(a->path==ROOTQID && b->path==DUMPROOTQID)
+ return 0;
return 1;
+ }
return 0;
}
@@ -46,12 +50,14 @@
d = &b->de[l->deind];
if((d->mode & (DGONE | DALLOC)) == 0){
- dprint("hjfs: getdent: file gone, callerpc %#p\n", getcallerpc(&l));
+ dprint("hjfs: getdent: file gone, d=%llux, l=%llud/%d %llux, callerpc %#p\n",
+ d->path, l->blk, l->deind, l->path, getcallerpc(&l));
werrstr("phase error -- getdent");
return nil;
}
if(qidcmp(d, l) != 0){
- dprint("hjfs: getdent: wrong qid, callerpc %#p\n", getcallerpc(&l));
+ dprint("hjfs: getdent: wrong qid d=%llux != l=%llud/%d %llux, callerpc %#p\n",
+ d->path, l->blk, l->deind, l->path, getcallerpc(&l));
werrstr("phase error -- getdent");
return nil;
}
@@ -950,66 +956,70 @@
return 0;
}
+/*
+ * newentry() looks for a free slot in the directory
+ * and returns FLoc pointing to the slot. if no free
+ * slot is available a new block is allocated. if
+ * dump == 0, then the resulting blk from the FLoc
+ * *is not* dumped, so to finally allocate the Dentry,
+ * one has to call willmodify() on res before modyfing it.
+ */
int
-newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
+newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res, int dump)
{
Dentry *d, *dd;
uvlong i, si, r;
- int j, sj, rc;
+ int j, sj;
Buf *c;
- FLoc f;
si = sj = -1;
d = getdent(l, b);
- if(d != nil) for(i = 0; i <= d->size; i++){
- if(i >= d->size && si != -1)
- break;
- rc = getblk(fs, l, b, i, &r, si == -1 ? GBCREATE : GBREAD);
- if(rc < 0)
- continue;
- if(rc == 0 && si != -1)
- continue;
- c = getbuf(fs->d, r, TDENTRY, rc == 0);
- if(c == nil)
- continue;
- if(rc == 0){
- memset(c->de, 0, sizeof(c->de));
- if(i >= d->size){
- d->size = i+1;
- b->op |= BDELWRI;
+ if(d != nil){
+ for(i = 0; i < d->size; i++){
+ if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
+ continue;
+ c = getbuf(fs->d, r, TDENTRY, 0);
+ if(c == nil)
+ continue;
+ for(j = 0; j < DEPERBLK; j++){
+ dd = &c->de[j];
+ if((dd->mode & DGONE) != 0)
+ continue;
+ if((dd->mode & DALLOC) != 0){
+ if(strcmp(dd->name, name) == 0){
+ werrstr(Eexists);
+ putbuf(c);
+ return 0;
+ }
+ continue;
+ }
+ if(si != -1 || haveloc(fs, r, j, l))
+ continue;
+ si = i;
+ sj = j;
}
- c->op |= BDELWRI;
+ putbuf(c);
}
- for(j = 0; j < DEPERBLK; j++){
- dd = &c->de[j];
- if((dd->mode & DALLOC) != 0){
- if(strcmp(dd->name, name) == 0){
- werrstr(Eexists);
+ if(si == -1 && i == d->size){
+ if(getblk(fs, l, b, i, &r, GBCREATE) >= 0){
+ c = getbuf(fs->d, r, TDENTRY, 1);
+ if(c != nil){
+ si = i;
+ sj = 0;
+ d->size = i+1;
+ b->op |= BDELWRI;
+ memset(c->de, 0, sizeof(c->de));
+ c->op |= BDELWRI;
putbuf(c);
- return 0;
}
- continue;
}
- if(si != -1 || haveloc(fs, r, j, l))
- continue;
- if((dd->mode & DGONE) != 0){
- memset(&f, 0, sizeof(f));
- f.blk = r;
- f.deind = j;
- f.Qid = dd->Qid;
- if(delete(fs, &f, c) < 0)
- continue;
- }
- si = i;
- sj = j;
}
- putbuf(c);
}
if(si == -1 || sj == -1){
werrstr("phase error -- create");
return -1;
}
- if(getblk(fs, l, b, si, &res->blk, GBWRITE) <= 0)
+ if(getblk(fs, l, b, si, &res->blk, dump != 0 ? GBWRITE : GBREAD) <= 0)
return -1;
res->deind = sj;
res->Qid = (Qid){0, 0, 0};
--- a/sys/src/cmd/hjfs/fs2.c
+++ b/sys/src/cmd/hjfs/fs2.c
@@ -104,11 +104,12 @@
int
chancreat(Chan *ch, char *name, int perm, int mode)
{
- Buf *b, *c;
+ Buf *b;
Dentry *d;
int isdir;
+ Loc *l;
FLoc f;
-
+
if((ch->flags & CHFRO) != 0){
werrstr(Einval);
return -1;
@@ -134,6 +135,7 @@
chend(ch);
return -1;
}
+ l = nil;
d = getdent(ch->loc, b);
if(d == nil)
goto error;
@@ -141,36 +143,40 @@
werrstr(Enotadir);
goto error;
}
- if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
- werrstr(Eperm);
+ if((ch->flags & CHFNOPERM) == 0) /* for console */
+ if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
+ werrstr(Eperm);
+ goto error;
+ }
+ if(newentry(ch->fs, ch->loc, b, name, &f, 0) <= 0)
goto error;
- }
- if(newentry(ch->fs, ch->loc, b, name, &f) <= 0)
- goto error;
- c = getbuf(ch->fs->d, f.blk, TDENTRY, 0);
- if(c == nil)
- goto error;
- modified(ch, d);
- b->op |= BDELWRI;
- c->op |= BDELWRI;
if(isdir)
perm &= ~0777 | d->mode & 0777;
else
perm &= ~0666 | d->mode & 0666;
- d = &c->de[f.deind];
- memset(d, 0, sizeof(*d));
- if(newqid(ch->fs, &d->path) < 0){
- putbuf(c);
+ f.type = perm >> 24;
+ if(newqid(ch->fs, &f.path) < 0)
goto error;
- }
- d->type = perm >> 24;
+ l = getloc(ch->fs, f, ch->loc);
+ modified(ch, d);
+ b->op |= BDELWRI;
+ putbuf(b);
+ b = nil;
+
+ if(willmodify(ch->fs, l, ch->flags & CHFNOLOCK) < 0)
+ goto error;
+ b = getbuf(ch->fs->d, l->blk, TDENTRY, 0);
+ if(b == nil)
+ goto error;
+ ch->loc = l;
+ d = &b->de[l->deind];
+ memset(d, 0, sizeof(*d));
+ d->Qid = l->Qid;
strcpy(d->name, name);
d->mtime = time(0);
d->atime = d->mtime;
d->gid = d->uid = d->muid = ch->uid;
d->mode = DALLOC | perm & 0777;
- f.Qid = d->Qid;
- ch->loc = getloc(ch->fs, f, ch->loc);
if((d->type & QTEXCL) != 0){
qlock(&ch->loc->ex);
ch->loc->exlock = ch;
@@ -177,8 +183,9 @@
ch->loc->lwrite = d->atime;
qunlock(&ch->loc->ex);
}
- putbuf(c);
+ b->op |= BDELWRI;
putbuf(b);
+
switch(mode & OEXEC){
case ORDWR:
ch->open |= CHREAD;
@@ -194,7 +201,10 @@
return 1;
error:
- putbuf(b);
+ if(l != nil)
+ putloc(ch->fs, l, 0);
+ if(b != nil)
+ putbuf(b);
chend(ch);
return -1;
}
@@ -212,6 +222,11 @@
chend(ch);
return -1;
}
+ if((mode & OTRUNC) != 0)
+ if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0){
+ chend(ch);
+ return -1;
+ }
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
if(b == nil){
chend(ch);