Allocate p->writechan during getdblock of a potentially-written block, to cut off race between dirtydblock and flush proc. Reference: /n/sources/patch/applied/venti-writechan Date: Tue Sep 18 03:04:17 CES 2007 Signed-off-by: rsc@swtch.com --- /sys/src/cmd/venti/srv/dcache.c Tue Sep 18 03:03:46 2007 +++ /sys/src/cmd/venti/srv/dcache.c Tue Sep 18 03:03:45 2007 @@ -377,6 +377,11 @@ if(b->heap != TWID32) fixheap(b->heap, b); + if((mode == ORDWR || mode == OWRITE) && part->writechan == nil){ + trace(TraceBlock, "getdblock allocwriteproc %s", part->name); + part->writechan = chancreate(sizeof(DBlock*), dcache.nblocks); + vtproc(writeproc, part); + } qunlock(&dcache.lock); trace(TraceBlock, "getdblock lock"); @@ -450,8 +455,6 @@ dirtydblock(DBlock *b, int dirty) { int odirty; - Part *p; - static int bitched; trace(TraceBlock, "dirtydblock enter %s 0x%llux %d from 0x%lux", b->part->name, b->addr, dirty, getcallerpc(&b)); @@ -464,16 +467,6 @@ else b->dirty = dirty; - p = b->part; - if(p->writechan == nil){ - trace(TraceBlock, "dirtydblock allocwriteproc %s", p->name); - /* XXX hope this doesn't fail! */ - p->writechan = chancreate(sizeof(DBlock*), dcache.nblocks); - if (p->writechan == nil && bitched++ == 0) - fprint(2, "%s: dirtydblock: couldn't create writechan\n", - argv0); - vtproc(writeproc, p); - } qlock(&dcache.lock); if(!odirty){ dcache.ndirty++; @@ -783,13 +776,13 @@ waitforkick(&dcache.round); trace(TraceWork, "start"); + t0 = nsec()/1000; + trace(TraceProc, "build t=%lud", (ulong)(nsec()/1000)-t0); + qlock(&dcache.lock); as = dcache.state; qunlock(&dcache.lock); - t0 = nsec()/1000; - - trace(TraceProc, "build t=%lud", (ulong)(nsec()/1000)-t0); write = dcache.write; n = 0; for(i=0; idirty is protected by b->lock while ndirty is protected + * by dcache.lock, so the --ndirty below is the delayed one + * from clearing b->dirty in the write proc. It may happen + * that some other proc has come along and redirtied b since + * the write. That's okay, it just means that ndirty may be + * one too high until we catch up and do the decrement. + */ trace(TraceProc, "undirty.%d t=%lud", j, (ulong)(nsec()/1000)-t0); qlock(&dcache.lock); dcache.diskstate = as;