From 5172dc4629e85e7c32dca5e2a8b4fc95754e1ebf Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 20 Feb 1996 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1996-02-20 --- port/devtinyfs.c | 330 ++++++++++++++++++++++++++++++----------------- 1 file changed, 215 insertions(+), 115 deletions(-) diff --git a/port/devtinyfs.c b/port/devtinyfs.c index 770f2e4903765814994eece3a98fb68012030dd5..0df77273621a6dac4d07bc0b0ba36b72eb1d40ad 100644 --- a/port/devtinyfs.c +++ b/port/devtinyfs.c @@ -49,7 +49,7 @@ typedef struct Mdata Mdata; struct Mdata { uchar type; uchar bno[2]; - char data[Dlen]; + uchar data[Dlen]; uchar sum; }; @@ -63,6 +63,10 @@ struct Tfile { ushort pin; uchar flag; ulong length; + + /* hint to avoid egregious reading */ + ushort fbno; + ulong finger; }; typedef struct Tfs Tfs; @@ -80,7 +84,6 @@ struct Tfs { struct { QLock; Tfs fs[Maxfs]; - short nfs; } tinyfs; #define GETS(x) ((x)[0]|((x)[1]<<8)) @@ -125,7 +128,6 @@ mapalloc(Tfs *fs) int i, j, lim; uchar x; - qlock(fs); lim = (fs->nblocks + 8 - 1)/8; for(i = 0; i < lim; i++){ x = fs->map[i]; @@ -134,12 +136,11 @@ mapalloc(Tfs *fs) for(j = 0; j < 8; j++) if((x & (1<map[i] = x|(1<dbno; + if(waserror()) + return; + while(bno != bend && bno != Notabno){ mapclr(fs, bno); - n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); - if(n != Blen) + if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) break; md = validdata(fs, buf, 0); if(md == 0) @@ -267,13 +266,24 @@ freefile(Tfs *fs, Tfile *f, ulong bend) bno = GETS(md->bno); } + poperror(); +} + +static void +freefile(Tfs *fs, Tfile *f, ulong bend) +{ + uchar buf[Blen]; + + /* remove blocks from map */ + freeblocks(fs, f->dbno, bend); + /* change file type to free on medium */ if(f->bno != Notabno){ - n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno); - if(n != Blen) + if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno) != Blen) return; buf[0] = Tagfree; devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); + mapclr(fs, f->bno); } /* forget we ever knew about it */ @@ -288,8 +298,10 @@ expand(Tfs *fs) fs->fsize += 8; f = smalloc(fs->fsize*sizeof(*f)); - memmove(f, fs->f, fs->nf*sizeof(f)); - free(fs->f); + if(fs->f){ + memmove(f, fs->f, fs->nf*sizeof(*f)); + free(fs->f); + } fs->f = f; } @@ -310,8 +322,11 @@ newfile(Tfs *fs, char *name) } } - if(i < fs->fsize) + if(i < fs->fsize){ + if(i >= fs->nf) + fs->nf = i+1; break; + } expand(fs); } @@ -319,6 +334,8 @@ newfile(Tfs *fs, char *name) f->flag = Fcreating; f->dbno = Notabno; f->bno = mapalloc(fs); + f->fbno = Notabno; + f->r = 1; /* write directory block */ if(waserror()){ @@ -437,6 +454,8 @@ tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) if(i >= fs->nf) return -1; f = &fs->f[i]; + if(f->name[0] == 0) + return 0; qid.path = i; qid.vers = 0; devdir(c, qid, f->name, f->length, eve, 0664, dp); @@ -461,37 +480,49 @@ tinyfsattach(char *spec) Tfs *fs; Chan *c, *cc; int i; + char *p; - cc = namec(spec, Aopen, ORDWR, 0); + p = 0; + if(strcmp(spec, "hd0") == 0) + p = "#H/hd0nvram"; + else + error("bad spec"); + + cc = namec(p, Aopen, ORDWR, 0); if(waserror()){ close(cc); - qunlock(&tinyfs); nexterror(); } - qlock(&tinyfs); fs = 0; - for(i = 0; i < tinyfs.nfs; i++){ + for(i = 0; i < Maxfs; i++){ fs = &tinyfs.fs[i]; - if(fs && eqchan(cc, fs->c, 0)) + qlock(fs); + if(fs->r && eqchan(cc, fs->c, 0)) break; + qunlock(fs); } - if(i < tinyfs.nfs){ - qlock(fs); + if(i < Maxfs){ fs->r++; qunlock(fs); close(cc); } else { - if(tinyfs.nfs >= Maxfs) + for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ + qlock(fs); + if(fs->r == 0) + break; + qunlock(fs); + } + if(fs == &tinyfs.fs[Maxfs]) error("too many tinyfs's"); - fs = &tinyfs.fs[tinyfs.nfs]; - memset(fs, 0, sizeof(*fs)); fs->c = cc; fs->r = 1; + fs->f = 0; + fs->nf = 0; + fs->fsize = 0; fsinit(fs); - tinyfs.nfs++; + qunlock(fs); } - qunlock(&tinyfs); poperror(); c = devattach('U', spec); @@ -553,14 +584,24 @@ tinyfsopen(Chan *c, int omode) error(Eperm); } else { qlock(fs); - if(omode == (OTRUNC|ORDWR)){ + if(waserror()){ + qunlock(fs); + nexterror(); + } + switch(omode){ + case OTRUNC|ORDWR: + case OTRUNC|OWRITE: f = newfile(fs, fs->f[c->qid.path].name); + fs->f[c->qid.path].r--; c->qid.path = f - fs->f; - } else if(omode != OREAD){ - qunlock(fs); + break; + case OREAD: + break; + default: error(Eperm); } qunlock(fs); + poperror(); } return devopen(c, omode, 0, 0, tinyfsgen); @@ -572,14 +613,18 @@ tinyfscreate(Chan *c, char *name, int omode, ulong perm) Tfs *fs; Tfile *f; - if(perm & CHDIR) - error("directory creation illegal"); + USED(perm); fs = &tinyfs.fs[c->dev]; qlock(fs); + if(waserror()){ + qunlock(fs); + nexterror(); + } f = newfile(fs, name); qunlock(fs); + poperror(); c->qid.path = f - fs->f; c->qid.vers = 0; @@ -589,8 +634,16 @@ tinyfscreate(Chan *c, char *name, int omode, ulong perm) void tinyfsremove(Chan *c) { - USED(c); - error(Eperm); + Tfs *fs; + Tfile *f; + + if(c->qid.path == CHDIR) + error(Eperm); + fs = &tinyfs.fs[c->dev]; + f = &fs->f[c->qid.path]; + qlock(fs); + freefile(fs, f, Notabno); + qunlock(fs); } void @@ -603,7 +656,7 @@ tinyfswstat(Chan *c, char *dp) void tinyfsclose(Chan *c) { - Tfs *fs, **l; + Tfs *fs; Tfile *f, *nf; int i; @@ -612,48 +665,48 @@ tinyfsclose(Chan *c) qlock(fs); /* dereference file and remove old versions */ - if(c->qid.path != CHDIR){ - f = &fs->f[c->qid.path]; - f->r--; - if(f->r == 0){ - if(f->flag & Fcreating){ - /* remove all other files with this name */ - for(i = 0; i < fs->fsize; i++){ - nf = &fs->f[i]; - if(f == nf) - continue; - if(strcmp(nf->name, f->name) == 0){ - if(nf->r) - nf->flag |= Frmonclose; - else - freefile(fs, nf, Notabno); + if(!waserror()){ + if(c->qid.path != CHDIR){ + f = &fs->f[c->qid.path]; + f->r--; + if(f->r == 0){ + if(f->flag & Frmonclose) + freefile(fs, f, Notabno); + else if(f->flag & Fcreating){ + /* remove all other files with this name */ + for(i = 0; i < fs->fsize; i++){ + nf = &fs->f[i]; + if(f == nf) + continue; + if(strcmp(nf->name, f->name) == 0){ + if(nf->r) + nf->flag |= Frmonclose; + else + freefile(fs, nf, Notabno); + } } + f->flag &= ~Fcreating; } - f->flag &= ~(Frmonclose|Fcreating); } - if(f->flag & Frmonclose) - freefile(fs, f, Notabno); } + poperror(); } /* dereference fs and remove on zero refs */ fs->r--; - qunlock(fs); - qlock(&tinyfs); if(fs->r == 0){ - for(l = &fs->l; *l;){ - if(*l == fs){ - *l = fs->next; - break; - } - l = &(*l)->next; - } - free(fs->f); - free(fs->map); + if(fs->f) + free(fs->f); + fs->f = 0; + fs->nf = 0; + fs->fsize = 0; + if(fs->map) + free(fs->map); + fs->map = 0; close(fs->c); - memset(fs, 0, sizeof(*fs)); + fs->c = 0; } - qunlock(&tinyfs); + qunlock(fs); } long @@ -661,7 +714,7 @@ tinyfsread(Chan *c, void *a, long n, ulong offset) { Tfs *fs; Tfile *f; - int sofar, i; + int sofar, i, off; ulong bno; Mdata *md; uchar buf[Blen]; @@ -670,34 +723,56 @@ tinyfsread(Chan *c, void *a, long n, ulong offset) if(c->qid.path & CHDIR) return devdirread(c, a, n, 0, 0, tinyfsgen); - fs = tinyfs.fs[c->dev]; + fs = &tinyfs.fs[c->dev]; f = &fs->f[c->qid.path]; if(offset >= f->length) return 0; + + qlock(fs); + if(waserror()){ + qunlock(fs); + nexterror(); + } if(n + offset >= f->length) n = f->length - offset; /* walk to starting data block */ - bno = f->dbno; - for(sofar = 0; sofar + Blen < offset; sofar += Blen){ + if(f->finger < offset && f->fbno != Notabno){ + sofar = f->finger; + bno = f->fbno; + } else { + sofar = 0; + bno = f->dbno; + } + for(; sofar + Dlen < offset; sofar += Dlen){ md = readdata(fs, bno, buf, 0); + if(md == 0) + error(Eio); bno = GETS(md->bno); } /* read data */ - offset = offset%Blen; + off = offset%Dlen; + offset -= off; for(sofar = 0; sofar < n; sofar += i){ md = readdata(fs, bno, buf, &i); - i -= offset; + if(md == 0) + error(Eio); + + /* update finger for successful read */ + f->finger = offset + sofar; + f->fbno = bno; + + i -= off; if(i > n) i = n; - if(i < 0) - break; memmove(p, md->data, i); p += i; bno = GETS(md->bno); - offset = 0; + off = 0; } + qunlock(fs); + poperror(); return sofar; } @@ -708,13 +783,17 @@ tinyfsbread(Chan *c, long n, ulong offset) return devbread(c, n, offset); } +/* + * if we get a write error in this routine, blocks will + * be lost. They should be recovered next fsinit. + */ long -tinyfswrite(Chan *c, char *a, long n, ulong offset) +tinyfswrite(Chan *c, void *a, long n, ulong offset) { Tfs *fs; Tfile *f; - int sofar, i, x; - ulong bno, tbno; + int last, next, i, off, finger; + ulong bno, dbno, fbno; Mdata *md; uchar buf[Blen]; uchar *p = a; @@ -725,7 +804,7 @@ tinyfswrite(Chan *c, char *a, long n, ulong offset) if(n == 0) return 0; - fs = tinyfs.fs[c->dev]; + fs = &tinyfs.fs[c->dev]; f = &fs->f[c->qid.path]; /* files are append only, anything else is illegal */ @@ -733,57 +812,78 @@ tinyfswrite(Chan *c, char *a, long n, ulong offset) error("append only"); qlock(fs); + dbno = Notabno; if(waserror()){ - f->flag |= Frmonclose; + freeblocks(fs, dbno, Notabno); qunlock(fs); nexterror(); } + /* write blocks backwards */ + p += n; + last = offset + n; + off = offset; + fbno = Notabno; + finger = 0; + for(next = (last/Dlen)*Dlen; next >= off; next -= Dlen){ + bno = mapalloc(fs); + if(bno == Notabno){ + error("out of space"); + } + i = last - next; + p -= i; + if(last == n+offset){ + writedata(fs, bno, dbno, p, i, 1); + finger = next; /* remember for later */ + fbno = bno; + } else + writedata(fs, bno, dbno, p, i, 0); + dbno = bno; + last = next; + } + /* walk to last data block */ - bno = f->dbno; - for(sofar = 0; sofar + Blen < offset; sofar += Blen){ + md = (Mdata*)buf; + if(f->finger < offset && f->fbno != Notabno){ + next = f->finger; + bno = f->fbno; + } else { + next = 0; + bno = f->dbno; + } + for(; next < offset; next += Dlen){ md = readdata(fs, bno, buf, 0); + if(md == 0) + error(Eio); if(md->type == Tagend) break; bno = GETS(md->bno); } - sofar = 0; - i = offset%Dlen; - if(i){ - x = n; - if(i + x > Dlen) - x = Dlen - i; - memmove(md->data + i, p, sofar); - f->length += x; - sofar += x; - } - - while(x = n - sofar) { - tbno = mapalloc(fs); - if(f->length == 0){ - f->dbno = tbno; - writedir(fs, f); - } else { - writedata(fs, bno, tbno, md->data, Dlen, 0); + /* point to new blocks */ + if(offset == 0){ + f->dbno = dbno; + writedir(fs, f); + } else { + i = last - offset; + next = offset%Dlen; + if(i > 0){ + p -= i; + memmove(md->data + next, p, i); } - if(x > Dlen) - x = Dlen; - memmove(md->data, p + sofar, x); - sofar += x; - f->length += x; - bno = tbno; + writedata(fs, bno, dbno, md->data, i+next, last == n+offset); } + f->length += n; - i = f->length%Dlen; - if(i == 0) - i = Dlen; - writedata(fs, bno, tbno, md->data, i, 1); - + /* update finger */ + if(fbno != Notabno){ + f->finger = finger; + f->fbno = fbno; + } poperror(); qunlock(fs); - return sofar; + return n; } long