/* look buffer up from buffer cache; dev is buffer-device ID, not system */ struct bufblk * buffindblk(long dev, off_t num, long rel) { #if (BUFNEWHASH) bufval_t val = bufmkhashkey(dev, num); bufval_t key = bufhash(val); struct bufblk *blk; struct bufchain *chain = &bufhash[key]; #else bufval_t key = bufhash(num); long dkey = dev & BUFDEVMASK; struct bufblk *blk = NULL; #endif #if (BUFNEWHASH) fmtxlk(&chain->lk); blk = chain->list; while ((blk) && blk->num != num) { blk = blk->tabnext; } if ((blk) && (rel)) { /* remove block from buffer hash chain */ if (blk->tabprev) { blk->tabprev->tabnext = blk->tabnext; } else { chain->list = blk->tabnext; } if (blk->tabnext) { blk->tabnext->tabprev = blk->tabprev; } } return blk; #else fmtxlk(&buflktab[dkey]); blk = bufhash[dkey][key]; while ((blk) && blk->num != num) { blk = blk->tabnext; } if ((blk) && (rel)) { /* remove block from buffer hash chain */ if (blk->tabprev) { blk->tabprev->tabnext = blk->tabnext; } else { bufhash[dkey][key] = blk->tabnext; } if (blk->tabnext) { blk->tabnext->tabprev = blk->tabprev; } } fmtxunlk(&buflktab[dkey]); return blk; #endif }
static void insert_into_hashtable(struct bufpool *pool, struct buf *buf) { int slot; slot = bufhash(buf->blkno) % BUFPOOL_HASHSIZE; if (pool->hashtable[slot]) pool->hashtable[slot]->bucket.prev = buf; buf->bucket.next = pool->hashtable[slot]; buf->bucket.prev = NULL; pool->hashtable[slot] = buf; }
static void remove_from_hashtable(struct bufpool *pool, struct buf *buf) { int slot; slot = bufhash(buf->blkno) % BUFPOOL_HASHSIZE; if (buf->bucket.next) buf->bucket.next->bucket.prev = buf->bucket.prev; if (buf->bucket.prev) buf->bucket.prev->bucket.next = buf->bucket.next; if (pool->hashtable[slot] == buf) pool->hashtable[slot] = buf->bucket.next; buf->bucket.next = NULL; buf->bucket.prev = NULL; }
void bufaddblk(struct bufblk *blk) { #if (BUFNEWHASH) bufval_t val = bufmkhashkey(blk->dev, blk->num); bufval_t key = bufhash(val); struct bufblk *buf; struct bufchain *chain = &bufhash[key]; #else buval_t key = bufhash(blk->num); long dkey = blk->dev & BUFDEVMASK; struct bufblk *buf; #endif #if (BUFNEWHASH) fmtxlk(&chain->lk); buf = chain->list; buf->tabprev = NULL; if (buf) { buf->tabprev = blk; } blk->tabnext = buf; chain->list = buf; fmtxunlk(&chain->lk); #else fmtxlk(&buflktab[dkey]); buf = bufhash[dkey][key]; if (buf) { buf->tabprev = blk; } bufhash[dkey][key] = blk; fmtxunlk(&buflktab[dkey]); #endif return; }
static struct buf *lookup_buffer(struct bufpool *pool, vfs_blkno_t blkno) { struct buf *buf; buf = pool->hashtable[bufhash(blkno) % BUFPOOL_HASHSIZE]; while (buf && buf->blkno != blkno) buf = buf->bucket.next; if (!buf) return NULL; switch (buf->state) { case BUF_STATE_FREE: panic("free buffer in cache"); break; case BUF_STATE_CLEAN: // Remove from clean list if (buf->chain.next) buf->chain.next->chain.prev = buf->chain.prev; if (buf->chain.prev) buf->chain.prev->chain.next = buf->chain.next; if (pool->clean.head == buf) pool->clean.head = buf->chain.next; if (pool->clean.tail == buf) pool->clean.tail = buf->chain.prev; // Set state to locked and add lock buf->chain.next = NULL; buf->chain.prev = NULL; buf->state = BUF_STATE_LOCKED; buf->locks++; break; case BUF_STATE_DIRTY: // Remove from dirty list if (buf->chain.next) buf->chain.next->chain.prev = buf->chain.prev; if (buf->chain.prev) buf->chain.prev->chain.next = buf->chain.next; if (pool->dirty.head == buf) pool->dirty.head = buf->chain.next; if (pool->dirty.tail == buf) pool->dirty.tail = buf->chain.prev; // Set state to updated and add lock buf->chain.next = NULL; buf->chain.prev = NULL; buf->state = BUF_STATE_UPDATED; buf->locks++; break; case BUF_STATE_READING: case BUF_STATE_WRITING: // Wait for buffer to become ready. Buffer is locked by reader/writer wait_for_buffer(buf); break; case BUF_STATE_LOCKED: case BUF_STATE_UPDATED: // Add lock buf->locks++; break; case BUF_STATE_INVALID: // Set state to locked, add lock and clear buffer buf->state = BUF_STATE_LOCKED; buf->locks++; memset(buf->data, 0, pool->bufsize); break; default: panic("invalid buffer state"); } return buf; }