1 #include <u.h> 2 #include <libc.h> 3 #include "cformat.h" 4 #include "lru.h" 5 #include "bcache.h" 6 #include "disk.h" 7 #include "inode.h" 8 9 /* 10 * read the inode blocks and make sure they 11 * haven't been trashed. 12 * 13 * make the in-core table of qid to inode mappings. 14 * N.B. this is just an array. we need a linear search to find 15 * a particular inode. this could be done faster. 16 * 17 * nab is the first inode block. 18 */ 19 int 20 iinit(Icache *ic, int f, int psize) 21 { 22 Ibuf *b; 23 Imap *m; 24 ulong ino; 25 Bbuf *bb; 26 Dinode *bi; 27 28 /* 29 * get basic sizes and allocation info from disk 30 */ 31 if(dinit(ic, f, psize) < 0) 32 return -1; 33 34 /* 35 * read first inode block to get number of inodes 36 */ 37 bb = bcread(ic, ic->nab); 38 if(bb == 0){ 39 fprint(2, "iinit: can't read disk\n"); 40 return -1; 41 } 42 bi = (Dinode*)bb->data; 43 if(bi->nino==0 || bi->nino>2048){ 44 fprint(2, "iinit: bad nino\n"); 45 return -1; 46 } 47 ic->nino = bi->nino; 48 49 /* 50 * set up sizing constants 51 */ 52 ic->i2b = (ic->bsize - sizeof(Dihdr))/sizeof(Inode); 53 ic->nib = (ic->nino + ic->i2b - 1)/ic->i2b; 54 55 /* 56 * allocate the in-core qid/inode map, build it's lru 57 */ 58 if(ic->map) 59 free(ic->map); 60 ic->map = malloc(sizeof(Imap)*ic->nino); 61 if(ic->map == 0){ 62 fprint(2, "iinit: can't alloc map\n"); 63 return -1; 64 } 65 lruinit(&ic->mlru); 66 for(m = ic->map; m < &ic->map[ic->nino]; m++){ 67 m->inuse = 0; 68 m->b = 0; 69 lruadd(&ic->mlru, m); 70 } 71 72 /* 73 * mark all cache buffers as empty, put them on the lru list 74 */ 75 lruinit(&ic->blru); 76 for(b = ic->ib; b < &ic->ib[Nicache]; b++){ 77 b->inuse = 0; 78 lruadd(&ic->blru, b); 79 } 80 81 /* 82 * Read all inodes and 83 * build the in-core qid/inode map 84 */ 85 for(ino = 0; ino < ic->nino; ino++){ 86 b = iread(ic, ino); 87 if(b == 0){ 88 fprint(2, "iinit: can't read inode %ld\n", ino); 89 return -1; 90 } 91 if(b->inode.inuse){ 92 m = &ic->map[ino]; 93 m->inuse = 1; 94 m->qid = b->inode.qid; 95 lruref(&ic->mlru, m); 96 } 97 } 98 return 0; 99 } 100 101 /* 102 * format the inode blocks 103 */ 104 int 105 iformat(Icache *ic, int f, ulong nino, char *name, int bsize, int psize) 106 { 107 Bbuf *bb; 108 Dinode *bi; 109 ulong bno; 110 ulong i; 111 ulong i2b; 112 int nib; 113 114 /* 115 * first format disk allocation 116 */ 117 if(dformat(ic, f, name, bsize, psize) < 0) 118 return -1; 119 120 fprint(2, "formatting inodes\n"); 121 122 i2b = (bsize - sizeof(Dihdr))/sizeof(Inode); 123 nib = (nino + i2b - 1)/i2b; 124 125 for(bno = ic->nab; bno < ic->nab + nib; bno++){ 126 if(dalloc(ic, 0) == Notabno){ 127 fprint(2, "iformat: balloc failed\n"); 128 return -1; 129 } 130 bb = bcalloc(ic, bno); 131 if(bb == 0){ 132 fprint(2, "iformat: bcalloc failed\n"); 133 return -1; 134 } 135 bi = (Dinode*)bb->data; 136 bi->magic = Imagic; 137 bi->nino = nino; 138 for(i = 0; i < i2b; i++) 139 bi->inode[i].inuse = 0; 140 bcmark(ic, bb); 141 } 142 143 bcsync(ic); 144 145 return iinit(ic, f, psize); 146 } 147 148 /* 149 * allocate a cache buffer, use least recently used 150 */ 151 Ibuf* 152 ialloc(Icache *ic, ulong ino) 153 { 154 Imap *m; 155 Ibuf *b; 156 157 b = (Ibuf*)ic->blru.lnext; 158 if(b->inuse) 159 ic->map[b->ino].b = 0; 160 b->ino = ino; 161 b->inuse = 1; 162 m = &ic->map[ino]; 163 m->b = b; 164 return b; 165 } 166 167 /* 168 * free a cache buffer 169 */ 170 void 171 ifree(Icache *ic, Ibuf *b) 172 { 173 b->inuse = 0; 174 if(b->inuse) 175 ic->map[b->ino].b = 0; 176 lruderef(&ic->blru, b); 177 } 178 179 /* 180 * get an inode into the cache. if no inode exists for this qid, create one 181 * from an unused qid/inode map. 182 */ 183 Ibuf * 184 iget(Icache *ic, Qid qid) 185 { 186 Imap *m, *me; 187 Ibuf *b; 188 189 /* 190 * find map entry with same qid.path 191 */ 192 for(m = ic->map, me = &ic->map[ic->nino]; m < me; m++){ 193 if(m->inuse && m->qid.path==qid.path){ 194 if(m->qid.vers != qid.vers){ 195 /* 196 * our info is old, forget it 197 */ 198 DPRINT(2, "updating old file %lud.%lud\n", 199 qid.path, qid.vers); 200 m->qid = qid; 201 iupdate(ic, m - ic->map, qid); 202 } 203 break; 204 } 205 } 206 207 /* 208 * if an already existing inode, just get it 209 */ 210 if(m != me) 211 return iread(ic, m - ic->map); 212 213 /* 214 * create a new inode, throw out the least recently used inode 215 * if necessary 216 */ 217 m = (Imap*)ic->mlru.lnext; 218 if(m->inuse){ 219 DPRINT(2, "superceding file %ld.%ld by %ld.%ld\n", m->qid.path, 220 m->qid.vers, qid.path, qid.vers); 221 if(iremove(ic, m - ic->map) < 0) 222 return 0; 223 } 224 225 /* 226 * init inode and write to disk 227 */ 228 DPRINT(2, "new file %ld.%ld ino %ld\n", qid.path, qid.vers, m - ic->map); 229 b = ialloc(ic, m - ic->map); 230 b->inode.inuse = m->inuse = 1; 231 b->inode.qid = qid; 232 m->qid = qid; 233 b->inode.ptr.bno = Notabno; 234 iwrite(ic, b); 235 return b; 236 } 237 238 /* 239 * read an inode into the cache 240 * 241 * ASSUMPTION: the inode is valid 242 */ 243 Ibuf* 244 iread(Icache *ic, ulong ino) 245 { 246 Ibuf *b; 247 Imap *m; 248 ulong bno; 249 Bbuf *bb; 250 Dinode *bi; 251 252 /* 253 * first see if we already have it in a cache entry 254 */ 255 m = &ic->map[ino]; 256 if(m->inuse && m->b){ 257 b = m->b; 258 goto out; 259 } 260 261 /* 262 * read it 263 */ 264 b = ialloc(ic, ino); 265 bno = ic->nab + ino/ic->i2b; 266 bb = bcread(ic, bno); 267 if(bb == 0){ 268 ifree(ic, b); 269 return 0; 270 } 271 bi = (Dinode*)bb->data; 272 b->inode = bi->inode[ino % ic->i2b]; 273 274 /* 275 * consistency check 276 */ 277 if(bi->nino!=ic->nino || bi->magic!=Imagic){ 278 fprint(2, "iread: inconsistent inode block\n"); 279 ifree(ic, b); 280 return 0; 281 } 282 out: 283 b->inuse = 1; 284 m->b = b; 285 if(b->inode.inuse) 286 lruref(&ic->mlru, m); 287 lruref(&ic->blru, b); 288 return b; 289 } 290 291 /* 292 * write an inode back to disk 293 */ 294 int 295 iwrite(Icache *ic, Ibuf *b) 296 { 297 ulong bno; 298 Bbuf *bb; 299 Dinode *bi; 300 301 bno = ic->nab + b->ino/ic->i2b; 302 bb = bcread(ic, bno); 303 if(bb == 0) 304 return 0; 305 bi = (Dinode*)bb->data; 306 bi->inode[b->ino % ic->i2b] = b->inode; 307 bcmark(ic, bb); 308 lruref(&ic->mlru, &ic->map[b->ino]); 309 lruref(&ic->blru, b); 310 return 0; 311 } 312 313 /* 314 * Forget what we know about an inode without removing it 315 * 316 * N.B: ordering of iwrite and dfree is important 317 */ 318 int 319 iupdate(Icache *ic, ulong ino, Qid qid) 320 { 321 Ibuf *b; 322 Imap *m; 323 Dptr d; 324 325 b = iread(ic, ino); 326 if(b == 0) 327 return -1; 328 329 /* 330 * update inode and map 331 */ 332 b->inode.qid = qid; 333 m = &ic->map[ino]; 334 m->qid = qid; 335 336 /* 337 * the free is not done if the write fails! 338 * this is important 339 */ 340 d = b->inode.ptr; 341 b->inode.ptr.bno = Notabno; 342 if(iwrite(ic, b) < 0) 343 return -1; 344 dfree(ic, &d); 345 return 0; 346 } 347 348 /* 349 * remove an inode 350 * 351 * N.B: ordering of iwrite and dfree is important 352 */ 353 int 354 iremove(Icache *ic, ulong ino) 355 { 356 Ibuf *b; 357 Imap *m; 358 359 m = &ic->map[ino]; 360 361 /* 362 * read in inode 363 */ 364 b = iread(ic, ino); 365 if(b == 0) 366 return -1; 367 368 /* 369 * mark it unused on disk 370 */ 371 b->inode.inuse = 0; 372 if(iwrite(ic, b) < 0) 373 return -1; 374 375 /* 376 * throw out it's data pages 377 */ 378 dfree(ic, &b->inode.ptr); 379 380 /* 381 * free the inode buffer 382 */ 383 ifree(ic, b); 384 385 /* 386 * make map entry least recently used 387 */ 388 lruderef(&ic->mlru, m); 389 return 0; 390 } 391 392 /* 393 * increment our version number 394 */ 395 void 396 iinc(Icache *ic, Ibuf *b) 397 { 398 b->inode.qid.vers++; 399 ic->map[b->ino].qid = b->inode.qid; 400 iwrite(ic, b); 401 } 402