1 #include <u.h> 2 #include <libc.h> 3 #include "cformat.h" 4 #include "lru.h" 5 #include "bcache.h" 6 7 int 8 bcinit(Bcache *bc, int f, int bsize) 9 { 10 Bbuf *b; 11 12 /* 13 * allocate space for all buffers 14 * point all buffers into outer space 15 */ 16 bc->dfirst = 0; 17 bc->bsize = bsize; 18 bc->f = f; 19 lruinit(bc); 20 for(b = bc->bb; b < &bc->bb[Nbcache]; b++){ 21 b->inuse = 0; 22 b->next = 0; 23 b->dirty = 0; 24 if(b->data == 0) 25 b->data = (char *)malloc(bc->bsize); 26 if(b->data == 0) 27 return -1; 28 lruadd(bc, b); 29 } 30 31 return 0; 32 } 33 34 /* 35 * Find a buffer for block b. If it's dirty, write it out. 36 */ 37 Bbuf * 38 bcfind(Bcache *bc, ulong bno) 39 { 40 Bbuf *b; 41 42 if(bno == Notabno) 43 error("bcfind: Notabno"); 44 bno &= ~Indbno; 45 46 /* 47 * if we already have a buffer for this bno, use it 48 */ 49 for(b = bc->bb; b < &bc->bb[Nbcache]; b++) 50 if(b->inuse && b->bno==bno) 51 goto out; 52 53 /* 54 * get least recently used block 55 */ 56 b = (Bbuf*)bc->lnext; 57 out: 58 /* 59 * if dirty, write it out 60 */ 61 if(b->dirty) 62 if(bcwrite(bc, b) < 0) 63 warning("writing dirty page"); 64 lruref(bc, b); 65 return b; 66 } 67 68 /* 69 * allocate a buffer block for a block. it's guaranteed to be there till 70 * the next Nbcache bcread's. 71 */ 72 Bbuf * 73 bcalloc(Bcache *bc, ulong bno) 74 { 75 Bbuf *b; 76 77 b = bcfind(bc, bno); 78 bno &= ~Indbno; 79 b->bno = bno; 80 b->inuse = 1; 81 return b; 82 } 83 84 /* 85 * read a block into a buffer cache. it's guaranteed to be there till 86 * the next Nbcache bcread's. 87 */ 88 Bbuf * 89 bcread(Bcache *bc, ulong bno) 90 { 91 Bbuf *b; 92 93 b = bcfind(bc, bno); 94 bno &= ~Indbno; 95 if(b->bno!=bno || !b->inuse) 96 /* 97 * read in the one we really want 98 */ 99 if(bread(bc, bno, b->data) < 0){ 100 b->inuse = 0; 101 return 0; 102 } 103 b->bno = bno; 104 b->inuse = 1; 105 return b; 106 } 107 108 /* 109 * mark a page dirty, if it's already dirty force a write 110 * 111 * N.B: ordering is important. 112 */ 113 void 114 bcmark(Bcache *bc, Bbuf *b) 115 { 116 lruref(bc, b); 117 118 if(b->dirty){ 119 bcwrite(bc, b); 120 return; 121 } 122 123 b->dirty = 1; 124 if(bc->dfirst) 125 bc->dlast->next = b; 126 else 127 bc->dfirst = b; 128 bc->dlast = b; 129 } 130 131 /* 132 * write out a page (and all preceding dirty ones) 133 */ 134 int 135 bcwrite(Bcache *bc, Bbuf *b) 136 { 137 Bbuf *nb; 138 139 /* 140 * write out all preceding pages 141 */ 142 while(nb = bc->dfirst){ 143 if(bwrite(bc, nb->bno, nb->data) < 0) 144 return -1; 145 nb->dirty = 0; 146 bc->dfirst = nb->next; 147 nb->next = 0; 148 if(nb == b) 149 return 0; 150 } 151 152 /* 153 * write out this page 154 */ 155 if(bwrite(bc, b->bno, b->data) < 0) 156 return -1; 157 b->dirty = 0; 158 b->next = 0; 159 return 0; 160 } 161 162 /* 163 * write out all dirty pages (in order) 164 */ 165 int 166 bcsync(Bcache *bc) 167 { 168 if(bc->dfirst) 169 return bcwrite(bc, bc->dlast); 170 return 0; 171 } 172 173 /* 174 * read a block from disk 175 */ 176 int 177 bread(Bcache *bc, ulong bno, void *buf) 178 { 179 uvlong x = (uvlong)bno * bc->bsize; 180 181 if(pread(bc->f, buf, bc->bsize, x) != bc->bsize) 182 return -1; 183 return 0; 184 } 185 186 /* 187 * write a block to disk 188 */ 189 int 190 bwrite(Bcache *bc, ulong bno, void *buf) 191 { 192 uvlong x = (uvlong)bno * bc->bsize; 193 194 if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize) 195 return -1; 196 return 0; 197 } 198