15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier #include "dat.h"
35e96a66cSDavid du Colombier #include "fns.h"
45e96a66cSDavid du Colombier #include "error.h"
55e96a66cSDavid du Colombier
65e96a66cSDavid du Colombier static void diskThread(void *a);
75e96a66cSDavid du Colombier
85e96a66cSDavid du Colombier enum {
9*c39c2eb3SDavid du Colombier /*
10*c39c2eb3SDavid du Colombier * disable measurement since it gets alignment faults on BG
11*c39c2eb3SDavid du Colombier * and the guts used to be commented out.
12*c39c2eb3SDavid du Colombier */
13*c39c2eb3SDavid du Colombier Timing = 0, /* flag */
145e96a66cSDavid du Colombier QueueSize = 100, /* maximum block to queue */
155e96a66cSDavid du Colombier };
165e96a66cSDavid du Colombier
175e96a66cSDavid du Colombier struct Disk {
185e96a66cSDavid du Colombier VtLock *lk;
195e96a66cSDavid du Colombier int ref;
205e96a66cSDavid du Colombier
215e96a66cSDavid du Colombier int fd;
225e96a66cSDavid du Colombier Header h;
235e96a66cSDavid du Colombier
245e96a66cSDavid du Colombier VtRendez *flow;
255e96a66cSDavid du Colombier VtRendez *starve;
265e96a66cSDavid du Colombier VtRendez *flush;
275e96a66cSDavid du Colombier VtRendez *die;
285e96a66cSDavid du Colombier
295e96a66cSDavid du Colombier int nqueue;
305e96a66cSDavid du Colombier
315e96a66cSDavid du Colombier Block *cur; /* block to do on current scan */
325e96a66cSDavid du Colombier Block *next; /* blocks to do next scan */
335e96a66cSDavid du Colombier };
345e96a66cSDavid du Colombier
35f6333ca0SDavid du Colombier /* keep in sync with Part* enum in dat.h */
36f6333ca0SDavid du Colombier static char *partname[] = {
37f6333ca0SDavid du Colombier [PartError] "error",
38f6333ca0SDavid du Colombier [PartSuper] "super",
39f6333ca0SDavid du Colombier [PartLabel] "label",
40f6333ca0SDavid du Colombier [PartData] "data",
41f6333ca0SDavid du Colombier [PartVenti] "venti",
42f6333ca0SDavid du Colombier };
435e96a66cSDavid du Colombier
445e96a66cSDavid du Colombier Disk *
diskAlloc(int fd)455e96a66cSDavid du Colombier diskAlloc(int fd)
465e96a66cSDavid du Colombier {
475e96a66cSDavid du Colombier u8int buf[HeaderSize];
485e96a66cSDavid du Colombier Header h;
495e96a66cSDavid du Colombier Disk *disk;
505e96a66cSDavid du Colombier
515e96a66cSDavid du Colombier if(pread(fd, buf, HeaderSize, HeaderOffset) < HeaderSize){
52dc5a79c1SDavid du Colombier vtSetError("short read: %r");
535e96a66cSDavid du Colombier vtOSError();
545e96a66cSDavid du Colombier return nil;
555e96a66cSDavid du Colombier }
565e96a66cSDavid du Colombier
57dc5a79c1SDavid du Colombier if(!headerUnpack(&h, buf)){
58dc5a79c1SDavid du Colombier vtSetError("bad disk header");
595e96a66cSDavid du Colombier return nil;
60dc5a79c1SDavid du Colombier }
615e96a66cSDavid du Colombier disk = vtMemAllocZ(sizeof(Disk));
625e96a66cSDavid du Colombier disk->lk = vtLockAlloc();
635e96a66cSDavid du Colombier disk->starve = vtRendezAlloc(disk->lk);
645e96a66cSDavid du Colombier disk->flow = vtRendezAlloc(disk->lk);
655e96a66cSDavid du Colombier disk->flush = vtRendezAlloc(disk->lk);
665e96a66cSDavid du Colombier disk->fd = fd;
675e96a66cSDavid du Colombier disk->h = h;
685e96a66cSDavid du Colombier
695e96a66cSDavid du Colombier disk->ref = 2;
705e96a66cSDavid du Colombier vtThread(diskThread, disk);
715e96a66cSDavid du Colombier
725e96a66cSDavid du Colombier return disk;
735e96a66cSDavid du Colombier }
745e96a66cSDavid du Colombier
755e96a66cSDavid du Colombier void
diskFree(Disk * disk)765e96a66cSDavid du Colombier diskFree(Disk *disk)
775e96a66cSDavid du Colombier {
785e96a66cSDavid du Colombier diskFlush(disk);
795e96a66cSDavid du Colombier
805e96a66cSDavid du Colombier /* kill slave */
815e96a66cSDavid du Colombier vtLock(disk->lk);
825e96a66cSDavid du Colombier disk->die = vtRendezAlloc(disk->lk);
835e96a66cSDavid du Colombier vtWakeup(disk->starve);
845e96a66cSDavid du Colombier while(disk->ref > 1)
855e96a66cSDavid du Colombier vtSleep(disk->die);
865e96a66cSDavid du Colombier vtUnlock(disk->lk);
875e96a66cSDavid du Colombier vtRendezFree(disk->flow);
885e96a66cSDavid du Colombier vtRendezFree(disk->starve);
895e96a66cSDavid du Colombier vtRendezFree(disk->die);
905e96a66cSDavid du Colombier vtLockFree(disk->lk);
915e96a66cSDavid du Colombier close(disk->fd);
925e96a66cSDavid du Colombier vtMemFree(disk);
935e96a66cSDavid du Colombier }
945e96a66cSDavid du Colombier
955e96a66cSDavid du Colombier static u32int
partStart(Disk * disk,int part)965e96a66cSDavid du Colombier partStart(Disk *disk, int part)
975e96a66cSDavid du Colombier {
985e96a66cSDavid du Colombier switch(part){
995e96a66cSDavid du Colombier default:
1005e96a66cSDavid du Colombier assert(0);
1015e96a66cSDavid du Colombier case PartSuper:
1025e96a66cSDavid du Colombier return disk->h.super;
1035e96a66cSDavid du Colombier case PartLabel:
1045e96a66cSDavid du Colombier return disk->h.label;
1055e96a66cSDavid du Colombier case PartData:
1065e96a66cSDavid du Colombier return disk->h.data;
1075e96a66cSDavid du Colombier }
1085e96a66cSDavid du Colombier }
1095e96a66cSDavid du Colombier
1105e96a66cSDavid du Colombier
1115e96a66cSDavid du Colombier static u32int
partEnd(Disk * disk,int part)1125e96a66cSDavid du Colombier partEnd(Disk *disk, int part)
1135e96a66cSDavid du Colombier {
1145e96a66cSDavid du Colombier switch(part){
1155e96a66cSDavid du Colombier default:
1165e96a66cSDavid du Colombier assert(0);
1175e96a66cSDavid du Colombier case PartSuper:
1185e96a66cSDavid du Colombier return disk->h.super+1;
1195e96a66cSDavid du Colombier case PartLabel:
1205e96a66cSDavid du Colombier return disk->h.data;
1215e96a66cSDavid du Colombier case PartData:
1225e96a66cSDavid du Colombier return disk->h.end;
1235e96a66cSDavid du Colombier }
1245e96a66cSDavid du Colombier }
1255e96a66cSDavid du Colombier
1265e96a66cSDavid du Colombier int
diskReadRaw(Disk * disk,int part,u32int addr,uchar * buf)1275e96a66cSDavid du Colombier diskReadRaw(Disk *disk, int part, u32int addr, uchar *buf)
1285e96a66cSDavid du Colombier {
1295e96a66cSDavid du Colombier ulong start, end;
1305e96a66cSDavid du Colombier u64int offset;
1315e96a66cSDavid du Colombier int n, nn;
1325e96a66cSDavid du Colombier
1335e96a66cSDavid du Colombier start = partStart(disk, part);
1345e96a66cSDavid du Colombier end = partEnd(disk, part);
1355e96a66cSDavid du Colombier
1365e96a66cSDavid du Colombier if(addr >= end-start){
1375e96a66cSDavid du Colombier vtSetError(EBadAddr);
1385e96a66cSDavid du Colombier return 0;
1395e96a66cSDavid du Colombier }
1405e96a66cSDavid du Colombier
1415e96a66cSDavid du Colombier offset = ((u64int)(addr + start))*disk->h.blockSize;
1425e96a66cSDavid du Colombier n = disk->h.blockSize;
1435e96a66cSDavid du Colombier while(n > 0){
1445e96a66cSDavid du Colombier nn = pread(disk->fd, buf, n, offset);
1455e96a66cSDavid du Colombier if(nn < 0){
1465e96a66cSDavid du Colombier vtOSError();
1475e96a66cSDavid du Colombier return 0;
1485e96a66cSDavid du Colombier }
1495e96a66cSDavid du Colombier if(nn == 0){
150e569ccb5SDavid du Colombier vtSetError("eof reading disk");
1515e96a66cSDavid du Colombier return 0;
1525e96a66cSDavid du Colombier }
1535e96a66cSDavid du Colombier n -= nn;
1545e96a66cSDavid du Colombier offset += nn;
1555e96a66cSDavid du Colombier buf += nn;
1565e96a66cSDavid du Colombier }
1575e96a66cSDavid du Colombier return 1;
1585e96a66cSDavid du Colombier }
1595e96a66cSDavid du Colombier
1605e96a66cSDavid du Colombier int
diskWriteRaw(Disk * disk,int part,u32int addr,uchar * buf)1615e96a66cSDavid du Colombier diskWriteRaw(Disk *disk, int part, u32int addr, uchar *buf)
1625e96a66cSDavid du Colombier {
1635e96a66cSDavid du Colombier ulong start, end;
1645e96a66cSDavid du Colombier u64int offset;
1655e96a66cSDavid du Colombier int n;
1665e96a66cSDavid du Colombier
1675e96a66cSDavid du Colombier start = partStart(disk, part);
1685e96a66cSDavid du Colombier end = partEnd(disk, part);
1695e96a66cSDavid du Colombier
1705e96a66cSDavid du Colombier if(addr >= end - start){
1715e96a66cSDavid du Colombier vtSetError(EBadAddr);
1725e96a66cSDavid du Colombier return 0;
1735e96a66cSDavid du Colombier }
1745e96a66cSDavid du Colombier
1755e96a66cSDavid du Colombier offset = ((u64int)(addr + start))*disk->h.blockSize;
1766de6ce84SDavid du Colombier n = pwrite(disk->fd, buf, disk->h.blockSize, offset);
1776de6ce84SDavid du Colombier if(n < 0){
1785e96a66cSDavid du Colombier vtOSError();
1795e96a66cSDavid du Colombier return 0;
1805e96a66cSDavid du Colombier }
1816de6ce84SDavid du Colombier if(n < disk->h.blockSize) {
1826de6ce84SDavid du Colombier vtSetError("short write");
1836de6ce84SDavid du Colombier return 0;
1846de6ce84SDavid du Colombier }
1855e96a66cSDavid du Colombier
1865e96a66cSDavid du Colombier return 1;
1875e96a66cSDavid du Colombier }
1885e96a66cSDavid du Colombier
1895e96a66cSDavid du Colombier static void
diskQueue(Disk * disk,Block * b)1905e96a66cSDavid du Colombier diskQueue(Disk *disk, Block *b)
1915e96a66cSDavid du Colombier {
1925e96a66cSDavid du Colombier Block **bp, *bb;
1935e96a66cSDavid du Colombier
1945e96a66cSDavid du Colombier vtLock(disk->lk);
1955e96a66cSDavid du Colombier while(disk->nqueue >= QueueSize)
1965e96a66cSDavid du Colombier vtSleep(disk->flow);
1975e96a66cSDavid du Colombier if(disk->cur == nil || b->addr > disk->cur->addr)
1985e96a66cSDavid du Colombier bp = &disk->cur;
1995e96a66cSDavid du Colombier else
2005e96a66cSDavid du Colombier bp = &disk->next;
2015e96a66cSDavid du Colombier
2025e96a66cSDavid du Colombier for(bb=*bp; bb; bb=*bp){
2035e96a66cSDavid du Colombier if(b->addr < bb->addr)
2045e96a66cSDavid du Colombier break;
2055e96a66cSDavid du Colombier bp = &bb->ionext;
2065e96a66cSDavid du Colombier }
2075e96a66cSDavid du Colombier b->ionext = bb;
2085e96a66cSDavid du Colombier *bp = b;
2095e96a66cSDavid du Colombier if(disk->nqueue == 0)
2105e96a66cSDavid du Colombier vtWakeup(disk->starve);
2115e96a66cSDavid du Colombier disk->nqueue++;
2125e96a66cSDavid du Colombier vtUnlock(disk->lk);
2135e96a66cSDavid du Colombier }
2145e96a66cSDavid du Colombier
2155e96a66cSDavid du Colombier
2165e96a66cSDavid du Colombier void
diskRead(Disk * disk,Block * b)2175e96a66cSDavid du Colombier diskRead(Disk *disk, Block *b)
2185e96a66cSDavid du Colombier {
2195e96a66cSDavid du Colombier assert(b->iostate == BioEmpty || b->iostate == BioLabel);
2205e96a66cSDavid du Colombier blockSetIOState(b, BioReading);
2215e96a66cSDavid du Colombier diskQueue(disk, b);
2225e96a66cSDavid du Colombier }
2235e96a66cSDavid du Colombier
2245e96a66cSDavid du Colombier void
diskWrite(Disk * disk,Block * b)2255e96a66cSDavid du Colombier diskWrite(Disk *disk, Block *b)
2265e96a66cSDavid du Colombier {
227867bfcc6SDavid du Colombier assert(b->nlock == 1);
2285e96a66cSDavid du Colombier assert(b->iostate == BioDirty);
2295e96a66cSDavid du Colombier blockSetIOState(b, BioWriting);
2305e96a66cSDavid du Colombier diskQueue(disk, b);
2315e96a66cSDavid du Colombier }
2325e96a66cSDavid du Colombier
233867bfcc6SDavid du Colombier void
diskWriteAndWait(Disk * disk,Block * b)234867bfcc6SDavid du Colombier diskWriteAndWait(Disk *disk, Block *b)
235867bfcc6SDavid du Colombier {
236867bfcc6SDavid du Colombier int nlock;
237867bfcc6SDavid du Colombier
238867bfcc6SDavid du Colombier /*
239867bfcc6SDavid du Colombier * If b->nlock > 1, the block is aliased within
240867bfcc6SDavid du Colombier * a single thread. That thread is us.
241867bfcc6SDavid du Colombier * DiskWrite does some funny stuff with VtLock
242867bfcc6SDavid du Colombier * and blockPut that basically assumes b->nlock==1.
243867bfcc6SDavid du Colombier * We humor diskWrite by temporarily setting
244867bfcc6SDavid du Colombier * nlock to 1. This needs to be revisited.
245867bfcc6SDavid du Colombier */
246867bfcc6SDavid du Colombier nlock = b->nlock;
247867bfcc6SDavid du Colombier if(nlock > 1)
248867bfcc6SDavid du Colombier b->nlock = 1;
249867bfcc6SDavid du Colombier diskWrite(disk, b);
250867bfcc6SDavid du Colombier while(b->iostate != BioClean)
251867bfcc6SDavid du Colombier vtSleep(b->ioready);
252867bfcc6SDavid du Colombier b->nlock = nlock;
253867bfcc6SDavid du Colombier }
254867bfcc6SDavid du Colombier
2555e96a66cSDavid du Colombier int
diskBlockSize(Disk * disk)2565e96a66cSDavid du Colombier diskBlockSize(Disk *disk)
2575e96a66cSDavid du Colombier {
2585e96a66cSDavid du Colombier return disk->h.blockSize; /* immuttable */
2595e96a66cSDavid du Colombier }
2605e96a66cSDavid du Colombier
2615e96a66cSDavid du Colombier int
diskFlush(Disk * disk)2625e96a66cSDavid du Colombier diskFlush(Disk *disk)
2635e96a66cSDavid du Colombier {
2645e96a66cSDavid du Colombier Dir dir;
2655e96a66cSDavid du Colombier
2665e96a66cSDavid du Colombier vtLock(disk->lk);
2675e96a66cSDavid du Colombier while(disk->nqueue > 0)
2685e96a66cSDavid du Colombier vtSleep(disk->flush);
2695e96a66cSDavid du Colombier vtUnlock(disk->lk);
2705e96a66cSDavid du Colombier
2715e96a66cSDavid du Colombier /* there really should be a cleaner interface to flush an fd */
2725e96a66cSDavid du Colombier nulldir(&dir);
2735e96a66cSDavid du Colombier if(dirfwstat(disk->fd, &dir) < 0){
2745e96a66cSDavid du Colombier vtOSError();
2755e96a66cSDavid du Colombier return 0;
2765e96a66cSDavid du Colombier }
2775e96a66cSDavid du Colombier return 1;
2785e96a66cSDavid du Colombier }
2795e96a66cSDavid du Colombier
2805e96a66cSDavid du Colombier u32int
diskSize(Disk * disk,int part)2815e96a66cSDavid du Colombier diskSize(Disk *disk, int part)
2825e96a66cSDavid du Colombier {
2835e96a66cSDavid du Colombier return partEnd(disk, part) - partStart(disk, part);
2845e96a66cSDavid du Colombier }
2855e96a66cSDavid du Colombier
28674f16c81SDavid du Colombier static uintptr
mypc(int x)287fe853e23SDavid du Colombier mypc(int x)
288fe853e23SDavid du Colombier {
289fe853e23SDavid du Colombier return getcallerpc(&x);
290fe853e23SDavid du Colombier }
291fe853e23SDavid du Colombier
292f6333ca0SDavid du Colombier static char *
disk2file(Disk * disk)293f6333ca0SDavid du Colombier disk2file(Disk *disk)
294f6333ca0SDavid du Colombier {
295f6333ca0SDavid du Colombier static char buf[256];
296f6333ca0SDavid du Colombier
297f6333ca0SDavid du Colombier if (fd2path(disk->fd, buf, sizeof buf) < 0)
298f6333ca0SDavid du Colombier strncpy(buf, "GOK", sizeof buf);
299f6333ca0SDavid du Colombier return buf;
300f6333ca0SDavid du Colombier }
301f6333ca0SDavid du Colombier
3025e96a66cSDavid du Colombier static void
diskThread(void * a)3035e96a66cSDavid du Colombier diskThread(void *a)
3045e96a66cSDavid du Colombier {
3055e96a66cSDavid du Colombier Disk *disk = a;
3065e96a66cSDavid du Colombier Block *b;
3075e96a66cSDavid du Colombier uchar *buf, *p;
3085e96a66cSDavid du Colombier double t;
3095e96a66cSDavid du Colombier int nio;
3105e96a66cSDavid du Colombier
3115e96a66cSDavid du Colombier vtThreadSetName("disk");
3125e96a66cSDavid du Colombier
313dc5a79c1SDavid du Colombier //fprint(2, "diskThread %d\n", getpid());
3145e96a66cSDavid du Colombier
3155e96a66cSDavid du Colombier buf = vtMemAlloc(disk->h.blockSize);
3165e96a66cSDavid du Colombier
3175e96a66cSDavid du Colombier vtLock(disk->lk);
318*c39c2eb3SDavid du Colombier if (Timing) {
3195e96a66cSDavid du Colombier nio = 0;
3205e96a66cSDavid du Colombier t = -nsec();
321*c39c2eb3SDavid du Colombier }
3225e96a66cSDavid du Colombier for(;;){
3235e96a66cSDavid du Colombier while(disk->nqueue == 0){
324*c39c2eb3SDavid du Colombier if (Timing) {
3255e96a66cSDavid du Colombier t += nsec();
326*c39c2eb3SDavid du Colombier if(nio >= 10000){
327*c39c2eb3SDavid du Colombier fprint(2, "disk: io=%d at %.3fms\n",
328*c39c2eb3SDavid du Colombier nio, t*1e-6/nio);
329*c39c2eb3SDavid du Colombier nio = 0;
330*c39c2eb3SDavid du Colombier t = 0;
331*c39c2eb3SDavid du Colombier }
332*c39c2eb3SDavid du Colombier }
3335e96a66cSDavid du Colombier if(disk->die != nil)
3345e96a66cSDavid du Colombier goto Done;
3355e96a66cSDavid du Colombier vtSleep(disk->starve);
336*c39c2eb3SDavid du Colombier if (Timing)
3375e96a66cSDavid du Colombier t -= nsec();
3385e96a66cSDavid du Colombier }
3395e96a66cSDavid du Colombier assert(disk->cur != nil || disk->next != nil);
3405e96a66cSDavid du Colombier
3415e96a66cSDavid du Colombier if(disk->cur == nil){
3425e96a66cSDavid du Colombier disk->cur = disk->next;
3435e96a66cSDavid du Colombier disk->next = nil;
3445e96a66cSDavid du Colombier }
3455e96a66cSDavid du Colombier b = disk->cur;
3465e96a66cSDavid du Colombier disk->cur = b->ionext;
3475e96a66cSDavid du Colombier vtUnlock(disk->lk);
3485e96a66cSDavid du Colombier
3495e96a66cSDavid du Colombier /*
3505e96a66cSDavid du Colombier * no one should hold onto blocking in the
3515e96a66cSDavid du Colombier * reading or writing state, so this lock should
3525e96a66cSDavid du Colombier * not cause deadlock.
3535e96a66cSDavid du Colombier */
354f6333ca0SDavid du Colombier if(0)fprint(2, "fossil: diskThread: %d:%d %x\n", getpid(), b->part, b->addr);
3555e96a66cSDavid du Colombier bwatchLock(b);
3565e96a66cSDavid du Colombier vtLock(b->lk);
357fe853e23SDavid du Colombier b->pc = mypc(0);
3585e96a66cSDavid du Colombier assert(b->nlock == 1);
3595e96a66cSDavid du Colombier switch(b->iostate){
3605e96a66cSDavid du Colombier default:
3615e96a66cSDavid du Colombier abort();
3625e96a66cSDavid du Colombier case BioReading:
3635e96a66cSDavid du Colombier if(!diskReadRaw(disk, b->part, b->addr, b->data)){
364f366f900SDavid du Colombier fprint(2, "fossil: diskReadRaw failed: %s: "
365f366f900SDavid du Colombier "score %V: part=%s block %ud: %r\n",
366f366f900SDavid du Colombier disk2file(disk), b->score,
367f366f900SDavid du Colombier partname[b->part], b->addr);
3685e96a66cSDavid du Colombier blockSetIOState(b, BioReadError);
3695e96a66cSDavid du Colombier }else
3705e96a66cSDavid du Colombier blockSetIOState(b, BioClean);
3715e96a66cSDavid du Colombier break;
3725e96a66cSDavid du Colombier case BioWriting:
3735e96a66cSDavid du Colombier p = blockRollback(b, buf);
374f366f900SDavid du Colombier /* NB: ctime result ends with a newline */
3755e96a66cSDavid du Colombier if(!diskWriteRaw(disk, b->part, b->addr, p)){
376f366f900SDavid du Colombier fprint(2, "fossil: diskWriteRaw failed: %s: "
377f366f900SDavid du Colombier "score %V: date %s part=%s block %ud: %r\n",
378f366f900SDavid du Colombier disk2file(disk), b->score,
379f366f900SDavid du Colombier ctime(time(0)),
380f366f900SDavid du Colombier partname[b->part], b->addr);
3815e96a66cSDavid du Colombier break;
3825e96a66cSDavid du Colombier }
3835e96a66cSDavid du Colombier if(p != buf)
3845e96a66cSDavid du Colombier blockSetIOState(b, BioClean);
3855e96a66cSDavid du Colombier else
3865e96a66cSDavid du Colombier blockSetIOState(b, BioDirty);
3875e96a66cSDavid du Colombier break;
3885e96a66cSDavid du Colombier }
3895e96a66cSDavid du Colombier
3905e96a66cSDavid du Colombier blockPut(b); /* remove extra reference, unlock */
3915e96a66cSDavid du Colombier vtLock(disk->lk);
3925e96a66cSDavid du Colombier disk->nqueue--;
3935e96a66cSDavid du Colombier if(disk->nqueue == QueueSize-1)
3945e96a66cSDavid du Colombier vtWakeup(disk->flow);
3955e96a66cSDavid du Colombier if(disk->nqueue == 0)
3965e96a66cSDavid du Colombier vtWakeup(disk->flush);
397*c39c2eb3SDavid du Colombier if(Timing)
3985e96a66cSDavid du Colombier nio++;
3995e96a66cSDavid du Colombier }
4005e96a66cSDavid du Colombier Done:
401dc5a79c1SDavid du Colombier //fprint(2, "diskThread done\n");
4025e96a66cSDavid du Colombier disk->ref--;
4035e96a66cSDavid du Colombier vtWakeup(disk->die);
4045e96a66cSDavid du Colombier vtUnlock(disk->lk);
4055e96a66cSDavid du Colombier vtMemFree(buf);
4065e96a66cSDavid du Colombier }
407