plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }