#include "all.h" enum{ MAXWREN = 7, }; static char WMAGIC[] = "kfs wren device\n"; static char MMAGIC[] = "kfs multi-wren device %4d/%4d\n"; typedef struct Wren Wren; struct Wren { QLock; Device dev; ulong nblocks; int fd; }; static char *wmagic = WMAGIC; static Wren *wrens; static int maxwren; char *wrenfile; int nwren; int badmagic; static Wren * wren(Device dev) { int i; for(i = 0; i < maxwren; i++) { if(devcmp(dev, wrens[i].dev) == 0) return &wrens[i]; } panic("can't find wren for %D", dev); return 0; } /* * find out the length of a file * given the mesg version of a stat buffer * we call this because fsconvM2D is different * for the file system than in the os */ ulong statlen(char *ap) { uchar *p; p = (uchar*)ap; p += 3*NAMELEN+5*4; return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); } static void wrenpartinit(Device dev, int k) { char buf[8*1024], d[DIRREC]; char file[128], magic[64]; Wren *w; int fd, i, nmagic; if(wrens == 0) wrens = fsalloc(MAXWREN * sizeof *wrens); w = &wrens[maxwren]; if(nwren > 0) sprint(file, "%s%d", wrenfile, k); else strcpy(file, wrenfile); fd = kopen(file, ORDWR); if(fd < 0) panic("can't open %s", file); if(kfstat(fd, d) < 0) panic("can't stat %s\n", file); kseek(fd, 0, 0); i = kread(fd, buf, sizeof buf); if(i < sizeof buf) panic("can't read %s", file); badmagic = 0; RBUFSIZE = 1024; sprint(magic, wmagic, k, nwren); nmagic = strlen(magic); if(strncmp(buf+256, magic, nmagic) == 0){ RBUFSIZE = atol(buf+256+nmagic); if(RBUFSIZE % 512){ fprint(2, "kfs: bad buffersize(%d) set 1K\n", RBUFSIZE); RBUFSIZE = 1024; } }else badmagic = 1; w->dev = dev; w->nblocks = statlen(d)/RBUFSIZE; if(k > 0) w->nblocks -= 1; /* don't count magic */ w->fd = fd; maxwren++; } void wreninit(Device dev) { int i; if(nwren > 0) wmagic = MMAGIC; i = 0; do{ wrenpartinit(dev, i); }while(++i < nwren); } static void wrenpartream(Device dev, int k) { Wren *w; char buf[8*1024], magic[64]; int fd, i; if(RBUFSIZE % 512) panic("kfs: bad buffersize(%d): use a multiple of 512\n", RBUFSIZE); print("kfs: reaming the file system using %d byte blocks\n", RBUFSIZE); w = wren(dev)+k; fd = w->fd; memset(buf, 0, sizeof buf); sprint(magic, wmagic, k, nwren); sprint(buf+256, "%s%d\n", magic, RBUFSIZE); qlock(w); i = kseek(fd, 0, 0) < 0 || kwrite(fd, buf, RBUFSIZE) != RBUFSIZE; qunlock(w); if(i < 0) panic("can't ream disk"); } void wrenream(Device dev) { int i; i = 0; do{ wrenpartream(dev, i); }while(++i < nwren); } static int wrentag(char *p, int tag, long qpath) { Tag *t; t = (Tag*)(p+BUFSIZE); return t->tag != tag || (qpath&~QPDIR) != t->path; } int wrencheck(Device dev) { char buf[8*1024]; if(badmagic) return 1; if(RBUFSIZE > sizeof buf) panic("bufsize too big"); if(wrenread(dev, wrensuper(dev), buf) || wrentag(buf, Tsuper, QPSUPER) || wrenread(dev, wrenroot(dev), buf) || wrentag(buf, Tdir, QPROOT)) return 1; if(((Dentry *)buf)[0].mode & DALLOC) return 0; return 1; } long wrensize(Device dev) { Wren *w; int i, nb; w = wren(dev); nb = 0; i = 0; do{ nb += w[i].nblocks; }while(++i < nwren); return nb; } long wrensuper(Device dev) { USED(dev); return 1; } long wrenroot(Device dev) { USED(dev); return 2; } int wrenread(Device dev, long addr, void *b) { Wren *w; int fd, i; w = wren(dev); for(i=0; inblocks) break; addr -= w->nblocks; ++w; } if(i > 0) addr++; fd = w->fd; qlock(w); i = seek(fd, addr*RBUFSIZE, 0) == -1 || read(fd, b, RBUFSIZE) != RBUFSIZE; qunlock(w); return i; } int wrenwrite(Device dev, long addr, void *b) { Wren *w; int fd, i; w = wren(dev); for(i=0; inblocks) break; addr -= w->nblocks; ++w; } if(i > 0) addr++; fd = w->fd; qlock(w); i = seek(fd, addr*RBUFSIZE, 0) == -1 || write(fd, b, RBUFSIZE) != RBUFSIZE; qunlock(w); return i; }