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, char* name) 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, name) < 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 int nib; 109 ulong bno, i2b, i; 110 Bbuf *bb; 111 Dinode *bi; 112 113 /* 114 * first format disk allocation 115 */ 116 if(dformat(ic, f, name, bsize, psize) < 0) 117 return -1; 118 119 fprint(2, "formatting inodes\n"); 120 121 i2b = (bsize - sizeof(Dihdr))/sizeof(Inode); 122 nib = (nino + i2b - 1)/i2b; 123 124 for(bno = ic->nab; bno < ic->nab + nib; bno++){ 125 if(dalloc(ic, 0) == Notabno){ 126 fprint(2, "iformat: balloc failed\n"); 127 return -1; 128 } 129 bb = bcalloc(ic, bno); 130 if(bb == 0){ 131 fprint(2, "iformat: bcalloc failed\n"); 132 return -1; 133 } 134 bi = (Dinode*)bb->data; 135 bi->magic = Imagic; 136 bi->nino = nino; 137 for(i = 0; i < i2b; i++) 138 bi->inode[i].inuse = 0; 139 bcmark(ic, bb); 140 } 141 142 bcsync(ic); 143 144 return iinit(ic, f, psize, name); 145 } 146 147 /* 148 * allocate a cache buffer, use least recently used 149 */ 150 Ibuf* 151 ialloc(Icache *ic, ulong ino) 152 { 153 Imap *m; 154 Ibuf *b; 155 156 b = (Ibuf*)ic->blru.lnext; 157 if(b->inuse) 158 ic->map[b->ino].b = 0; 159 b->ino = ino; 160 b->inuse = 1; 161 m = &ic->map[ino]; 162 m->b = b; 163 return b; 164 } 165 166 /* 167 * free a cache buffer 168 */ 169 void 170 ifree(Icache *ic, Ibuf *b) 171 { 172 b->inuse = 0; 173 if(b->inuse) 174 ic->map[b->ino].b = 0; 175 lruderef(&ic->blru, b); 176 } 177 178 /* 179 * get an inode into the cache. if no inode exists for this qid, create one 180 * from an unused qid/inode map. 181 */ 182 Ibuf * 183 iget(Icache *ic, Qid qid) 184 { 185 Imap *m, *me; 186 Ibuf *b; 187 188 /* 189 * find map entry with same qid.path 190 */ 191 for(m = ic->map, me = &ic->map[ic->nino]; m < me; m++) 192 if(m->inuse && m->qid.path==qid.path){ 193 if(m->qid.vers != qid.vers){ 194 /* 195 * our info is old, forget it 196 */ 197 DPRINT(2, "updating old file %llud.%lud\n", 198 qid.path, qid.vers); 199 m->qid = qid; 200 iupdate(ic, m - ic->map, qid); 201 } 202 break; 203 } 204 205 /* 206 * if an already existing inode, just get it 207 */ 208 if(m != me) 209 return iread(ic, m - ic->map); 210 211 /* 212 * create a new inode, throw out the least recently used inode 213 * if necessary 214 */ 215 m = (Imap*)ic->mlru.lnext; 216 if(m->inuse){ 217 DPRINT(2, "superceding file %llud.%ld by %llud.%ld\n", 218 m->qid.path, m->qid.vers, qid.path, qid.vers); 219 if(iremove(ic, m - ic->map) < 0) 220 return 0; 221 } 222 223 if(statson) 224 cfsstat.ninsert++; 225 /* 226 * init inode and write to disk 227 */ 228 DPRINT(2, "new file %llud.%ld ino %ld\n", 229 qid.path, qid.vers, m - ic->map); 230 b = ialloc(ic, m - ic->map); 231 b->inode.inuse = m->inuse = 1; 232 b->inode.qid = qid; 233 b->inode.length = 0x7fffffffffffffffLL; 234 m->qid = qid; 235 b->inode.ptr.bno = Notabno; 236 iwrite(ic, b); 237 return b; 238 } 239 240 /* 241 * read an inode into the cache 242 * 243 * ASSUMPTION: the inode is valid 244 */ 245 Ibuf* 246 iread(Icache *ic, ulong ino) 247 { 248 Ibuf *b; 249 Imap *m; 250 ulong bno; 251 Bbuf *bb; 252 Dinode *bi; 253 254 /* 255 * first see if we already have it in a cache entry 256 */ 257 m = &ic->map[ino]; 258 if(m->inuse && m->b){ 259 b = m->b; 260 goto out; 261 } 262 263 /* 264 * read it 265 */ 266 b = ialloc(ic, ino); 267 bno = ic->nab + ino/ic->i2b; 268 bb = bcread(ic, bno); 269 if(bb == 0){ 270 ifree(ic, b); 271 return 0; 272 } 273 bi = (Dinode*)bb->data; 274 b->inode = bi->inode[ino % ic->i2b]; 275 276 /* 277 * consistency check 278 */ 279 if(bi->nino!=ic->nino || bi->magic!=Imagic){ 280 fprint(2, "iread: inconsistent inode block\n"); 281 ifree(ic, b); 282 return 0; 283 } 284 out: 285 b->inuse = 1; 286 m->b = b; 287 if(b->inode.inuse) 288 lruref(&ic->mlru, m); 289 lruref(&ic->blru, b); 290 return b; 291 } 292 293 /* 294 * write an inode back to disk 295 */ 296 int 297 iwrite(Icache *ic, Ibuf *b) 298 { 299 ulong bno; 300 Bbuf *bb; 301 Dinode *bi; 302 303 bno = ic->nab + b->ino/ic->i2b; 304 bb = bcread(ic, bno); 305 if(bb == 0) 306 return 0; 307 bi = (Dinode*)bb->data; 308 bi->inode[b->ino % ic->i2b] = b->inode; 309 bcmark(ic, bb); 310 lruref(&ic->mlru, &ic->map[b->ino]); 311 lruref(&ic->blru, b); 312 return 0; 313 } 314 315 /* 316 * Forget what we know about an inode without removing it 317 * 318 * N.B: ordering of iwrite and dfree is important 319 */ 320 int 321 iupdate(Icache *ic, ulong ino, Qid qid) 322 { 323 Ibuf *b; 324 Imap *m; 325 Dptr d; 326 327 if(statson) 328 cfsstat.nupdate++; 329 b = iread(ic, ino); 330 if(b == 0) 331 return -1; 332 333 /* 334 * update inode and map 335 */ 336 b->inode.qid = qid; 337 b->inode.length = 0x7fffffffffffffffLL; /* Set to maximum */ 338 m = &ic->map[ino]; 339 m->qid = qid; 340 341 /* 342 * the free is not done if the write fails! 343 * this is important 344 */ 345 d = b->inode.ptr; 346 b->inode.ptr.bno = Notabno; 347 if(iwrite(ic, b) < 0) 348 return -1; 349 dfree(ic, &d); 350 return 0; 351 } 352 353 /* 354 * remove an inode 355 * 356 * N.B: ordering of iwrite and dfree is important 357 */ 358 int 359 iremove(Icache *ic, ulong ino) 360 { 361 Ibuf *b; 362 Imap *m; 363 364 if(statson) 365 cfsstat.ndelete++; 366 m = &ic->map[ino]; 367 368 /* 369 * read in inode 370 */ 371 b = iread(ic, ino); 372 if(b == 0) 373 return -1; 374 375 /* 376 * mark it unused on disk 377 */ 378 b->inode.inuse = 0; 379 if(iwrite(ic, b) < 0) 380 return -1; 381 382 /* 383 * throw out it's data pages 384 */ 385 dfree(ic, &b->inode.ptr); 386 387 /* 388 * free the inode buffer 389 */ 390 ifree(ic, b); 391 392 /* 393 * make map entry least recently used 394 */ 395 lruderef(&ic->mlru, m); 396 return 0; 397 } 398 399 /* 400 * increment our version number 401 */ 402 void 403 iinc(Icache *ic, Ibuf *b) 404 { 405 b->inode.qid.vers++; 406 ic->map[b->ino].qid = b->inode.qid; 407 iwrite(ic, b); 408 } 409