venti.c (3242B)
1 #include <u.h> 2 #include <libc.h> 3 #include <diskfs.h> 4 #include <venti.h> 5 6 extern void vtlibthread(void); 7 8 typedef struct DiskVenti DiskVenti; 9 struct DiskVenti 10 { 11 Disk disk; 12 VtEntry e; 13 VtCache *c; 14 }; 15 16 extern int nfilereads; 17 extern void _nfilereads_darwin_sucks(void); 18 19 /* 20 * This part is like file.c but doesn't require storing the root block 21 * in the cache permanently and doesn't care about locking since 22 * all the blocks are read-only. Perhaps at some point this functionality 23 * should go into libvac in some form. 24 */ 25 static int 26 vtfileindices(VtEntry *e, u32int bn, int *index) 27 { 28 int i, np; 29 30 memset(index, 0, VtPointerDepth*sizeof(int)); 31 32 np = e->psize/VtScoreSize; 33 for(i=0; bn > 0; i++){ 34 if(i >= VtPointerDepth){ 35 werrstr("bad block number %lud", (ulong)bn); 36 return -1; 37 } 38 index[i] = bn % np; 39 bn /= np; 40 } 41 return i; 42 } 43 44 VtBlock *_vtfileblock(VtCache*, VtEntry*, u32int); /* avoid auto-inline by putting later in file */ 45 static void 46 diskventiblockput(Block *b) 47 { 48 vtblockput(b->priv); 49 free(b); 50 } 51 52 static Block* 53 diskventiread(Disk *dd, u32int len, u64int offset) 54 { 55 DiskVenti *d = (DiskVenti*)dd; 56 VtBlock *vb; 57 Block *b; 58 int frag; 59 60 nfilereads++; 61 vb = _vtfileblock(d->c, &d->e, offset/d->e.dsize); 62 if(vb == nil) 63 return nil; 64 65 b = mallocz(sizeof(Block), 1); 66 if(b == nil){ 67 vtblockput(vb); 68 return nil; 69 } 70 71 b->priv = vb; 72 b->_close = diskventiblockput; 73 frag = offset%d->e.dsize; 74 b->data = (uchar*)vb->data + frag; 75 b->len = d->e.dsize - frag; 76 if(b->len > len) 77 b->len = len; 78 return b; 79 } 80 81 VtBlock* 82 _vtfileblock(VtCache *c, VtEntry *e, u32int bn) 83 { 84 VtBlock *b; 85 int i, d, index[VtPointerDepth+1], t; 86 uchar score[VtScoreSize]; 87 88 i = vtfileindices(e, bn, index); 89 if(i < 0) 90 return nil; 91 d = (e->type&VtTypeDepthMask); 92 if(i > d){ 93 werrstr("bad address %d > %d (%x %x)", i, d, e->type, e->flags); 94 return nil; 95 } 96 97 /*fprint(2, "vtread %V\n", e->score); */ 98 b = vtcacheglobal(c, e->score, e->type, d == 0 ? e->dsize : e->psize); 99 for(i=d-1; i>=0 && b; i--){ 100 t = VtDataType+i; 101 /*fprint(2, "vtread %V\n", b->data+index[i]*VtScoreSize); */ 102 memmove(score, b->data+index[i]*VtScoreSize, VtScoreSize); 103 vtblockput(b); 104 b = vtcacheglobal(c, score, t, i == 0 ? e->dsize : e->psize); 105 } 106 return b; 107 } 108 109 static void 110 diskventiclose(Disk *dd) 111 { 112 DiskVenti *d = (DiskVenti*)dd; 113 free(d); 114 } 115 116 Disk* 117 diskopenventi(VtCache *c, uchar score[VtScoreSize]) 118 { 119 DiskVenti *d; 120 VtEntry e; 121 VtRoot root; 122 VtBlock *b; 123 124 if((b = vtcacheglobal(c, score, VtRootType, VtRootSize)) == nil) 125 goto Err; 126 if(vtrootunpack(&root, b->data) < 0) 127 goto Err; 128 if(root.blocksize < 512 || (root.blocksize&(root.blocksize-1))){ 129 werrstr("bad blocksize %d", root.blocksize); 130 goto Err; 131 } 132 vtblockput(b); 133 134 if((b = vtcacheglobal(c, root.score, VtDirType, VtEntrySize)) == nil) 135 goto Err; 136 if(vtentryunpack(&e, b->data, 0) < 0) 137 goto Err; 138 vtblockput(b); 139 b = nil; 140 if((e.type&VtTypeBaseMask) != VtDataType){ 141 werrstr("not a single file"); 142 goto Err; 143 } 144 145 d = mallocz(sizeof(DiskVenti), 1); 146 if(d == nil) 147 goto Err; 148 149 d->disk._read = diskventiread; 150 d->disk._close = diskventiclose; 151 d->e = e; 152 d->c = c; 153 return &d->disk; 154 155 Err: 156 if(b) 157 vtblockput(b); 158 159 _nfilereads_darwin_sucks(); /* force Darwin ld to pull in file.o */ 160 return nil; 161 }