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 /* 55 * get least recently used block 56 */ 57 b = (Bbuf*)bc->lnext; 58 out: 59 /* 60 * if dirty, write it out 61 */ 62 if(b->dirty){ 63 if(bcwrite(bc, b) < 0) 64 warning("writing dirty page"); 65 } 66 lruref(bc, b); 67 return b; 68 } 69 70 /* 71 * allocate a buffer block for a block. it's guaranteed to be there till 72 * the next Nbcache bcread's. 73 */ 74 Bbuf * 75 bcalloc(Bcache *bc, ulong bno) 76 { 77 Bbuf *b; 78 79 b = bcfind(bc, bno); 80 bno &= ~Indbno; 81 b->bno = bno; 82 b->inuse = 1; 83 return b; 84 } 85 86 /* 87 * read a block into a buffer cache. it's guaranteed to be there till 88 * the next Nbcache bcread's. 89 */ 90 Bbuf * 91 bcread(Bcache *bc, ulong bno) 92 { 93 Bbuf *b; 94 95 b = bcfind(bc, bno); 96 bno &= ~Indbno; 97 if(b->bno!=bno || !b->inuse){ 98 /* 99 * read in the one we really want 100 */ 101 if(bread(bc, bno, b->data) < 0){ 102 b->inuse = 0; 103 return 0; 104 } 105 } 106 b->bno = bno; 107 b->inuse = 1; 108 return b; 109 } 110 111 /* 112 * mark a page dirty, if it's already dirty force a write 113 * 114 * N.B: ordering is important. 115 */ 116 void 117 bcmark(Bcache *bc, Bbuf *b) 118 { 119 lruref(bc, b); 120 121 if(b->dirty){ 122 bcwrite(bc, b); 123 return; 124 } 125 126 b->dirty = 1; 127 if(bc->dfirst) 128 bc->dlast->next = b; 129 else 130 bc->dfirst = b; 131 bc->dlast = b; 132 } 133 134 /* 135 * write out a page (and all preceeding dirty ones) 136 */ 137 int 138 bcwrite(Bcache *bc, Bbuf *b) 139 { 140 Bbuf *nb; 141 142 /* 143 * write out all preceeding pages 144 */ 145 while(nb = bc->dfirst){ 146 if(bwrite(bc, nb->bno, nb->data) < 0) 147 return -1; 148 nb->dirty = 0; 149 bc->dfirst = nb->next; 150 nb->next = 0; 151 if(nb == b) 152 return 0; 153 } 154 155 /* 156 * write out this page 157 */ 158 if(bwrite(bc, b->bno, b->data) < 0) 159 return -1; 160 b->dirty = 0; 161 b->next = 0; 162 return 0; 163 } 164 165 /* 166 * write out all dirty pages (in order) 167 */ 168 int 169 bcsync(Bcache *bc) 170 { 171 if(bc->dfirst) 172 return bcwrite(bc, bc->dlast); 173 return 0; 174 } 175 176 /* 177 * read a block from disk 178 */ 179 int 180 bread(Bcache *bc, ulong bno, void *buf) 181 { 182 ulong x = bno*bc->bsize; 183 184 if(seek(bc->f, x, 0) != x) 185 return -1; 186 if(read(bc->f, buf, bc->bsize) != bc->bsize) 187 return -1; 188 return 0; 189 } 190 191 /* 192 * write a block to disk 193 */ 194 int 195 bwrite(Bcache *bc, ulong bno, void *buf) 196 { 197 ulong x = bno*bc->bsize; 198 199 if(seek(bc->f, x, 0) != x) 200 return -1; 201 if(write(bc->f, buf, bc->bsize) != bc->bsize) 202 return -1; 203 return 0; 204 } 205