/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * cached-worm device */#include "all.h" #define CDEV(d) ((d)->cw.c)#define WDEV(d) ((d)->cw.w)#define RDEV(d) ((d)->cw.ro) enum { DEBUG = 0, FIRST = SUPER_ADDR, ADDFREE = 100, CACHE_ADDR = SUPER_ADDR, MAXAGE = 10000,}; /* cache state */enum{ /* states -- beware these are recorded on the cache */ /* cache worm */ Cnone = 0, /* 0 ? */ Cdirty, /* 1 0 */ Cdump, /* 1 0->1 */ Cread, /* 1 1 */ Cwrite, /* 2 1 */ Cdump1, /* inactive form of dump */ Cerror, /* opcodes -- these are not recorded */ Onone, Oread, Owrite, Ogrow, Odump, Orele, Ofree,}; typedef struct Cw Cw;struct Cw{ Device* dev; Device* cdev; Device* wdev; Device* rodev; Cw* link; int dbucket; /* last bucket dumped */ Off daddr; /* last block dumped */ Off ncopy; int nodump;/* * following are cached variables for dumps */ Off fsize; Off ndump; int depth; int all; /* local flag to recur on modified dirs */ int allflag; /* global flag to recur on modified dirs */ Off falsehits; /* times recur found modified blocks */ struct { char name[500]; char namepad[NAMELEN+10]; };}; static char* cwnames[] ={ [Cnone] "none", [Cdirty] "dirty", [Cdump] "dump", [Cread] "read", [Cwrite] "write", [Cdump1] "dump1", [Cerror] "error", [Onone] "none", [Oread] "read", [Owrite] "write", [Ogrow] "grow", [Odump] "dump", [Orele] "rele",}; int oldcachefmt = 1; Centry* getcentry(Bucket*, Off);int cwio(Device*, Off, void*, int);void cmd_cwcmd(int, char*[]); /* * console command * initiate a dump */voidcmd_dump(int argc, char *argv[]){ Filsys *fs; fs = cons.curfs; if(argc > 1) fs = fsstr(argv[1]); if(fs == 0) { print("%s: unknown file system\n", argv[1]); return; } cfsdump(fs);} /* * console command * worm stats */static voidcmd_statw(int, char*[]){ Filsys *fs; Iobuf *p; Superb *sb; Cache *h; Bucket *b; Centry *c, *ce; Off m, nw, bw, state[Onone]; Off sbfsize, sbcwraddr, sbroraddr, sblast, sbnext; Off hmsize, hmaddr, dsize, dsizepct; Device *dev; Cw *cw; int s; fs = cons.curfs; dev = fs->dev; if(dev->type != Devcw) { print("curfs not type cw\n"); return; } cw = dev->private; if(cw == 0) { print("curfs not inited\n"); return; } print("cwstats %s\n", fs->name); sbfsize = 0; sbcwraddr = 0; sbroraddr = 0; sblast = 0; sbnext = 0; print("\tfilesys %s\n", fs->name);// print("\tnio =%7W%7W%7W\n", cw->ncwio+0, cw->ncwio+1, cw->ncwio+2); p = getbuf(dev, cwsaddr(dev), Brd); if(!p || checktag(p, Tsuper, QPSUPER)) { print("cwstats: checktag super\n"); if(p) { putbuf(p); p = 0; } } if(p) { sb = (Superb*)p->iobuf; sbfsize = sb->fsize; sbcwraddr = sb->cwraddr; sbroraddr = sb->roraddr; sblast = sb->last; sbnext = sb->next; putbuf(p); } p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); if(!p || checktag(p, Tcache, QPSUPER)) { print("cwstats: checktag c bucket\n"); if(p) putbuf(p); return; } h = (Cache*)p->iobuf; hmaddr = h->maddr; hmsize = h->msize; print("\t\tmaddr = %8lld\n", (Wideoff)hmaddr); print("\t\tmsize = %8lld\n", (Wideoff)hmsize); print("\t\tcaddr = %8lld\n", (Wideoff)h->caddr); print("\t\tcsize = %8lld\n", (Wideoff)h->csize); print("\t\tsbaddr = %8lld\n", (Wideoff)h->sbaddr); print("\t\tcraddr = %8lld %8lld\n", (Wideoff)h->cwraddr, (Wideoff)sbcwraddr); print("\t\troaddr = %8lld %8lld\n", (Wideoff)h->roraddr, (Wideoff)sbroraddr); /* print stats in terms of (first-)disc sides */ dsize = wormsizeside(dev, 0); if (dsize < 1) { if (DEBUG) print("wormsizeside returned size %lld for %Z side 0\n", (Wideoff)dsize, dev); dsize = h->wsize; /* it's probably a fake worm */ if (dsize < 1) dsize = 1000; /* don't divide by zero */ } dsizepct = dsize/100; print("\t\tfsize = %8lld %8lld %2lld+%2lld%%\n", (Wideoff)h->fsize, (Wideoff)sbfsize, (Wideoff)h->fsize/dsize, (Wideoff)(h->fsize%dsize)/dsizepct); print("\t\tslast = %8lld\n", (Wideoff)sblast); print("\t\tsnext = %8lld\n", (Wideoff)sbnext); print("\t\twmax = %8lld %2lld+%2lld%%\n", (Wideoff)h->wmax, (Wideoff)h->wmax/dsize, (Wideoff)(h->wmax%dsize)/dsizepct); print("\t\twsize = %8lld %2lld+%2lld%%\n", (Wideoff)h->wsize, (Wideoff)h->wsize/dsize, (Wideoff)(h->wsize%dsize)/dsizepct); putbuf(p); bw = 0; /* max filled bucket */ memset(state, 0, sizeof(state)); for(m = 0; m < hmsize; m++) { p = getbuf(cw->cdev, hmaddr + m/BKPERBLK, Brd); if(!p || checktag(p, Tbuck, hmaddr + m/BKPERBLK)) { print("cwstats: checktag c bucket\n"); if(p) putbuf(p); return; } b = (Bucket*)p->iobuf + m%BKPERBLK; ce = b->entry + CEPERBK; nw = 0; for(c = b->entry; c < ce; c++) { s = c->state; state[s]++; if(s != Cnone && s != Cread) nw++; } putbuf(p); if(nw > bw) bw = nw; } for(s = Cnone; s < Cerror; s++) print("\t\t%6lld %s\n", (Wideoff)state[s], cwnames[s]); print("\t\tcache %2lld%% full\n", ((Wideoff)bw*100)/CEPERBK);} intdumpblock(Device *dev){ Iobuf *p, *cb, *p1, *p2; Cache *h; Centry *c, *ce, *bc; Bucket *b; Off m, a, msize, maddr, wmax, caddr; int s1, s2, count; Cw *cw; cw = dev->private; if(cw == 0 || cw->nodump) return 0; cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); h = (Cache*)cb->iobuf; msize = h->msize; maddr = h->maddr; wmax = h->wmax; caddr = h->caddr; putbuf(cb); for(m=msize; m>=0; m--) { a = cw->dbucket + 1; if(a < 0 || a >= msize) a = 0; cw->dbucket = a; p = getbuf(cw->cdev, maddr + a/BKPERBLK, Brd); b = (Bucket*)p->iobuf + a%BKPERBLK; ce = b->entry + CEPERBK; bc = 0; for(c = b->entry; c < ce; c++) if(c->state == Cdump) { if(bc == 0) { bc = c; continue; } if(c->waddr < cw->daddr) { if(bc->waddr < cw->daddr && bc->waddr > c->waddr) bc = c; continue; } if(bc->waddr < cw->daddr || bc->waddr > c->waddr) bc = c; } if(bc) { c = bc; goto found; } putbuf(p); } if(cw->ncopy) { print("%lld blocks copied to worm\n", (Wideoff)cw->ncopy); cw->ncopy = 0; } cw->nodump = 1; return 0; found: if (oldcachefmt) a = a*CEPERBK + (c - b->entry) + caddr; else a += (c - b->entry)*msize + caddr; p1 = getbuf(devnone, Cwdump1, 0); count = 0; retry: count++; if(count > 10 || devread(cw->cdev, a, p1->iobuf)) goto stop; m = c->waddr; cw->daddr = m; s1 = devwrite(cw->wdev, m, p1->iobuf); if(s1) { p2 = getbuf(devnone, Cwdump2, 0); s2 = devread(cw->wdev, m, p2->iobuf); if(s2) { if(s1 == 0x61 && s2 == 0x60) { putbuf(p2); goto retry; } goto stop1; } if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) goto stop1; putbuf(p2); } /* * reread and compare */ if(conf.dumpreread) { p2 = getbuf(devnone, Cwdump2, 0); s1 = devread(cw->wdev, m, p2->iobuf); if(s1) goto stop1; if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) { print("reread C%lld W%lld didnt compare\n", (Wideoff)a, (Wideoff)m); goto stop1; } putbuf(p2); } putbuf(p1); c->state = Cread; p->flags |= Bmod; putbuf(p); if(m > wmax) { cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); h = (Cache*)cb->iobuf; if(m > h->wmax) h->wmax = m; putbuf(cb); } cw->ncopy++; return 1; stop1: putbuf(p2); putbuf(p1); c->state = Cdump1; p->flags |= Bmod; putbuf(p); return 1; stop: putbuf(p1); putbuf(p); print("stopping dump!!\n"); cw->nodump = 1; return 0;} voidcwinit1(Device *dev){ Cw *cw; static int first; cw = dev->private; if(cw) return; if(first == 0) { cmd_install("dump", "-- make dump backup to worm", cmd_dump); cmd_install("statw", "-- cache/worm stats", cmd_statw); cmd_install("cwcmd", "subcommand -- cache/worm errata", cmd_cwcmd); roflag = flag_install("ro", "-- ro reads and writes"); first = 1; } cw = malloc(sizeof(Cw)); dev->private = cw; cw->allflag = 0; cw->dev = dev; cw->cdev = CDEV(dev); cw->wdev = WDEV(dev); cw->rodev = RDEV(dev); devinit(cw->cdev); devinit(cw->wdev);} voidcwinit(Device *dev){ Cw *cw; Cache *h; Iobuf *cb, *p; Off l, m; cwinit1(dev); cw = dev->private; l = devsize(cw->wdev); cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); h = (Cache*)cb->iobuf; h->toytime = toytime() + SECOND(30); h->time = time(nil); m = h->wsize; if(l != m) { print("wdev changed size %lld to %lld\n", (Wideoff)m, (Wideoff)l); h->wsize = l; cb->flags |= Bmod; } for(m=0; m<h->msize; m++) { p = getbuf(cw->cdev, h->maddr + m/BKPERBLK, Brd); if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK)) panic("cwinit: checktag c bucket"); putbuf(p); } putbuf(cb);} Offcwsaddr(Device *dev){ Iobuf *cb; Off sa; cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); sa = ((Cache*)cb->iobuf)->sbaddr; putbuf(cb); return sa;} Offcwraddr(Device *dev){ Iobuf *cb; Off ra; switch(dev->type) { default: print("unknown dev in cwraddr %Z\n", dev); return 1; case Devcw: cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); ra = ((Cache*)cb->iobuf)->cwraddr; break; case Devro: cb = getbuf(CDEV(dev->ro.parent), CACHE_ADDR, Brd|Bres); ra = ((Cache*)cb->iobuf)->roraddr; break; } putbuf(cb); return ra;} Devsizecwsize(Device *dev){ Iobuf *cb; Devsize fs; cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); fs = ((Cache*)cb->iobuf)->fsize;Lines 1–500 of 2277. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * cached-worm device */ #include "all.h" #define CDEV(d) ((d)->cw.c) #define WDEV(d) ((d)->cw.w) #define RDEV(d) ((d)->cw.ro) enum { DEBUG = 0, FIRST = SUPER_ADDR, ADDFREE = 100, CACHE_ADDR = SUPER_ADDR, MAXAGE = 10000, }; /* cache state */ enum { /* states -- beware these are recorded on the cache */ /* cache worm */ Cnone = 0, /* 0 ? */ Cdirty, /* 1 0 */ Cdump, /* 1 0->1 */ Cread, /* 1 1 */ Cwrite, /* 2 1 */ Cdump1, /* inactive form of dump */ Cerror, /* opcodes -- these are not recorded */ Onone, Oread, Owrite, Ogrow, Odump, Orele, Ofree, }; typedef struct Cw Cw; struct Cw { Device* dev; Device* cdev; Device* wdev; Device* rodev; Cw* link; int dbucket; /* last bucket dumped */ Off daddr; /* last block dumped */ Off ncopy; int nodump; /* * following are cached variables for dumps */ Off fsize; Off ndump; int depth; int all; /* local flag to recur on modified dirs */ int allflag; /* global flag to recur on modified dirs */ Off falsehits; /* times recur found modified blocks */ struct { char name[500]; char namepad[NAMELEN+10]; }; }; static char* cwnames[] = { [Cnone] "none", [Cdirty] "dirty", [Cdump] "dump", [Cread] "read", [Cwrite] "write", [Cdump1] "dump1", [Cerror] "error", [Onone] "none", [Oread] "read", [Owrite] "write", [Ogrow] "grow", [Odump] "dump", [Orele] "rele", }; int oldcachefmt = 1; Centry* getcentry(Bucket*, Off); int cwio(Device*, Off, void*, int); void cmd_cwcmd(int, char*[]); /* * console command * initiate a dump */ void cmd_dump(int argc, char *argv[]) { Filsys *fs; fs = cons.curfs; if(argc > 1) fs = fsstr(argv[1]); if(fs == 0) { print("%s: unknown file system\n", argv[1]); return; } cfsdump(fs); } /* * console command * worm stats */ static void cmd_statw(int, char*[]) { Filsys *fs; Iobuf *p; Superb *sb; Cache *h; Bucket *b; Centry *c, *ce; Off m, nw, bw, state[Onone]; Off sbfsize, sbcwraddr, sbroraddr, sblast, sbnext; Off hmsize, hmaddr, dsize, dsizepct; Device *dev; Cw *cw; int s; fs = cons.curfs; dev = fs->dev; if(dev->type != Devcw) { print("curfs not type cw\n"); return; } cw = dev->private; if(cw == 0) { print("curfs not inited\n"); return; } print("cwstats %s\n", fs->name); sbfsize = 0; sbcwraddr = 0; sbroraddr = 0; sblast = 0; sbnext = 0; print("\tfilesys %s\n", fs->name); // print("\tnio =%7W%7W%7W\n", cw->ncwio+0, cw->ncwio+1, cw->ncwio+2); p = getbuf(dev, cwsaddr(dev), Brd); if(!p || checktag(p, Tsuper, QPSUPER)) { print("cwstats: checktag super\n"); if(p) { putbuf(p); p = 0; } } if(p) { sb = (Superb*)p->iobuf; sbfsize = sb->fsize; sbcwraddr = sb->cwraddr; sbroraddr = sb->roraddr; sblast = sb->last; sbnext = sb->next; putbuf(p); } p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); if(!p || checktag(p, Tcache, QPSUPER)) { print("cwstats: checktag c bucket\n"); if(p) putbuf(p); return; } h = (Cache*)p->iobuf; hmaddr = h->maddr; hmsize = h->msize; print("\t\tmaddr = %8lld\n", (Wideoff)hmaddr); print("\t\tmsize = %8lld\n", (Wideoff)hmsize); print("\t\tcaddr = %8lld\n", (Wideoff)h->caddr); print("\t\tcsize = %8lld\n", (Wideoff)h->csize); print("\t\tsbaddr = %8lld\n", (Wideoff)h->sbaddr); print("\t\tcraddr = %8lld %8lld\n", (Wideoff)h->cwraddr, (Wideoff)sbcwraddr); print("\t\troaddr = %8lld %8lld\n", (Wideoff)h->roraddr, (Wideoff)sbroraddr); /* print stats in terms of (first-)disc sides */ dsize = wormsizeside(dev, 0); if (dsize < 1) { if (DEBUG) print("wormsizeside returned size %lld for %Z side 0\n", (Wideoff)dsize, dev); dsize = h->wsize; /* it's probably a fake worm */ if (dsize < 1) dsize = 1000; /* don't divide by zero */ } dsizepct = dsize/100; print("\t\tfsize = %8lld %8lld %2lld+%2lld%%\n", (Wideoff)h->fsize, (Wideoff)sbfsize, (Wideoff)h->fsize/dsize, (Wideoff)(h->fsize%dsize)/dsizepct); print("\t\tslast = %8lld\n", (Wideoff)sblast); print("\t\tsnext = %8lld\n", (Wideoff)sbnext); print("\t\twmax = %8lld %2lld+%2lld%%\n", (Wideoff)h->wmax, (Wideoff)h->wmax/dsize, (Wideoff)(h->wmax%dsize)/dsizepct); print("\t\twsize = %8lld %2lld+%2lld%%\n", (Wideoff)h->wsize, (Wideoff)h->wsize/dsize, (Wideoff)(h->wsize%dsize)/dsizepct); putbuf(p); bw = 0; /* max filled bucket */ memset(state, 0, sizeof(state)); for(m = 0; m < hmsize; m++) { p = getbuf(cw->cdev, hmaddr + m/BKPERBLK, Brd); if(!p || checktag(p, Tbuck, hmaddr + m/BKPERBLK)) { print("cwstats: checktag c bucket\n"); if(p) putbuf(p); return; } b = (Bucket*)p->iobuf + m%BKPERBLK; ce = b->entry + CEPERBK; nw = 0; for(c = b->entry; c < ce; c++) { s = c->state; state[s]++; if(s != Cnone && s != Cread) nw++; } putbuf(p); if(nw > bw) bw = nw; } for(s = Cnone; s < Cerror; s++) print("\t\t%6lld %s\n", (Wideoff)state[s], cwnames[s]); print("\t\tcache %2lld%% full\n", ((Wideoff)bw*100)/CEPERBK); } int dumpblock(Device *dev) { Iobuf *p, *cb, *p1, *p2; Cache *h; Centry *c, *ce, *bc; Bucket *b; Off m, a, msize, maddr, wmax, caddr; int s1, s2, count; Cw *cw; cw = dev->private; if(cw == 0 || cw->nodump) return 0; cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); h = (Cache*)cb->iobuf; msize = h->msize; maddr = h->maddr; wmax = h->wmax; caddr = h->caddr; putbuf(cb); for(m=msize; m>=0; m--) { a = cw->dbucket + 1; if(a < 0 || a >= msize) a = 0; cw->dbucket = a; p = getbuf(cw->cdev, maddr + a/BKPERBLK, Brd); b = (Bucket*)p->iobuf + a%BKPERBLK; ce = b->entry + CEPERBK; bc = 0; for(c = b->entry; c < ce; c++) if(c->state == Cdump) { if(bc == 0) { bc = c; continue; } if(c->waddr < cw->daddr) { if(bc->waddr < cw->daddr && bc->waddr > c->waddr) bc = c; continue; } if(bc->waddr < cw->daddr || bc->waddr > c->waddr) bc = c; } if(bc) { c = bc; goto found; } putbuf(p); } if(cw->ncopy) { print("%lld blocks copied to worm\n", (Wideoff)cw->ncopy); cw->ncopy = 0; } cw->nodump = 1; return 0; found: if (oldcachefmt) a = a*CEPERBK + (c - b->entry) + caddr; else a += (c - b->entry)*msize + caddr; p1 = getbuf(devnone, Cwdump1, 0); count = 0; retry: count++; if(count > 10 || devread(cw->cdev, a, p1->iobuf)) goto stop; m = c->waddr; cw->daddr = m; s1 = devwrite(cw->wdev, m, p1->iobuf); if(s1) { p2 = getbuf(devnone, Cwdump2, 0); s2 = devread(cw->wdev, m, p2->iobuf); if(s2) { if(s1 == 0x61 && s2 == 0x60) { putbuf(p2); goto retry; } goto stop1; } if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) goto stop1; putbuf(p2); } /* * reread and compare */ if(conf.dumpreread) { p2 = getbuf(devnone, Cwdump2, 0); s1 = devread(cw->wdev, m, p2->iobuf); if(s1) goto stop1; if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) { print("reread C%lld W%lld didnt compare\n", (Wideoff)a, (Wideoff)m); goto stop1; } putbuf(p2); } putbuf(p1); c->state = Cread; p->flags |= Bmod; putbuf(p); if(m > wmax) { cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); h = (Cache*)cb->iobuf; if(m > h->wmax) h->wmax = m; putbuf(cb); } cw->ncopy++; return 1; stop1: putbuf(p2); putbuf(p1); c->state = Cdump1; p->flags |= Bmod; putbuf(p); return 1; stop: putbuf(p1); putbuf(p); print("stopping dump!!\n"); cw->nodump = 1; return 0; } void cwinit1(Device *dev) { Cw *cw; static int first; cw = dev->private; if(cw) return; if(first == 0) { cmd_install("dump", "-- make dump backup to worm", cmd_dump); cmd_install("statw", "-- cache/worm stats", cmd_statw); cmd_install("cwcmd", "subcommand -- cache/worm errata", cmd_cwcmd); roflag = flag_install("ro", "-- ro reads and writes"); first = 1; } cw = malloc(sizeof(Cw)); dev->private = cw; cw->allflag = 0; cw->dev = dev; cw->cdev = CDEV(dev); cw->wdev = WDEV(dev); cw->rodev = RDEV(dev); devinit(cw->cdev); devinit(cw->wdev); } void cwinit(Device *dev) { Cw *cw; Cache *h; Iobuf *cb, *p; Off l, m; cwinit1(dev); cw = dev->private; l = devsize(cw->wdev); cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); h = (Cache*)cb->iobuf; h->toytime = toytime() + SECOND(30); h->time = time(nil); m = h->wsize; if(l != m) { print("wdev changed size %lld to %lld\n", (Wideoff)m, (Wideoff)l); h->wsize = l; cb->flags |= Bmod; } for(m=0; m<h->msize; m++) { p = getbuf(cw->cdev, h->maddr + m/BKPERBLK, Brd); if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK)) panic("cwinit: checktag c bucket"); putbuf(p); } putbuf(cb); } Off cwsaddr(Device *dev) { Iobuf *cb; Off sa; cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); sa = ((Cache*)cb->iobuf)->sbaddr; putbuf(cb); return sa; } Off cwraddr(Device *dev) { Iobuf *cb; Off ra; switch(dev->type) { default: print("unknown dev in cwraddr %Z\n", dev); return 1; case Devcw: cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); ra = ((Cache*)cb->iobuf)->cwraddr; break; case Devro: cb = getbuf(CDEV(dev->ro.parent), CACHE_ADDR, Brd|Bres); ra = ((Cache*)cb->iobuf)->roraddr; break; } putbuf(cb); return ra; } Devsize cwsize(Device *dev) { Iobuf *cb; Devsize fs; cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); fs = ((Cache*)cb->iobuf)->fsize;