* NAME: getbucket() * DESCRIPTION: fetch a bucket from the cache, or an empty one to be filled */
| 482 | * DESCRIPTION: fetch a bucket from the cache, or an empty one to be filled |
| 483 | */ |
| 484 | static |
| 485 | bucket *getbucket(bcache *cache, unsigned long bnum, int fill) |
| 486 | { |
| 487 | bucket **hslot, *b, *p, *bptr, |
| 488 | *chain[HFS_BLOCKBUFSZ], **slots[HFS_BLOCKBUFSZ]; |
| 489 | |
| 490 | b = findbucket(cache, bnum, &hslot); |
| 491 | |
| 492 | if (b) |
| 493 | { |
| 494 | /* cache hit; move towards head of cache chain */ |
| 495 | |
| 496 | ++cache->hits; |
| 497 | |
| 498 | if (++b->count > b->cprev->count && |
| 499 | b != cache->tail->cnext) |
| 500 | { |
| 501 | p = b->cprev; |
| 502 | |
| 503 | p->cprev->cnext = b; |
| 504 | b->cnext->cprev = p; |
| 505 | |
| 506 | p->cnext = b->cnext; |
| 507 | b->cprev = p->cprev; |
| 508 | |
| 509 | p->cprev = b; |
| 510 | b->cnext = p; |
| 511 | |
| 512 | if (cache->tail == b) |
| 513 | cache->tail = p; |
| 514 | } |
| 515 | } |
| 516 | else |
| 517 | { |
| 518 | /* cache miss; reuse least-used cache bucket */ |
| 519 | |
| 520 | ++cache->misses; |
| 521 | |
| 522 | b = cache->tail; |
| 523 | |
| 524 | if (reuse(cache, b, bnum) == -1) |
| 525 | goto fail; |
| 526 | |
| 527 | if (fill) |
| 528 | { |
| 529 | unsigned int len = 0; |
| 530 | |
| 531 | chain[len] = b; |
| 532 | slots[len++] = hslot; |
| 533 | |
| 534 | for (bptr = b->cprev; |
| 535 | len < (HFS_BLOCKBUFSZ >> 1) && ++bnum < cache->vol->vlen; |
| 536 | bptr = bptr->cprev) |
| 537 | { |
| 538 | if (findbucket(cache, bnum, &hslot)) |
| 539 | break; |
| 540 | |
| 541 | if (reuse(cache, bptr, bnum) == -1) |