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