struct buffer * newslot(afs_int32 *afid, afs_int32 apage, struct buffer *lp) { /* Find a usable buffer slot */ afs_int32 i; afs_int32 lt; struct buffer **tbp; if (lp && (lp->lockers == 0)) { lt = lp->accesstime; } else { lp = 0; lt = BUFFER_LONG_MAX; } tbp = Buffers; for (i = 0; i < nbuffers; i++, tbp++) { if ((*tbp)->lockers == 0) { if ((*tbp)->accesstime < lt) { lp = (*tbp); lt = (*tbp)->accesstime; } } } /* There are no unlocked buffers */ if (lp == 0) { if (lt < 0) Die("accesstime counter wrapped"); else Die("all buffers locked"); } /* We do not need to lock the buffer here because it has no lockers * and the afs_bufferLock prevents other threads from zapping this * buffer while we are writing it out */ if (lp->dirty) { if (ReallyWrite(lp->fid, lp->page, lp->data)) Die("writing bogus buffer"); lp->dirty = 0; } /* Now fill in the header. */ FidZap(lp->fid); FidCpy(lp->fid, afid); /* set this */ lp->page = apage; lp->accesstime = ++timecounter; FixupBucket(lp); /* move to the right hash bucket */ return lp; }
void DZap(afs_int32 *fid) { /* Destroy all buffers pertaining to a particular fid. */ struct buffer *tb; ObtainReadLock(&afs_bufferLock); for (tb = phTable[pHash(fid)]; tb; tb = tb->hashNext) if (FidEq(tb->fid, fid)) { ObtainWriteLock(&tb->lock); FidZap(tb->fid); tb->dirty = 0; ReleaseWriteLock(&tb->lock); } ReleaseReadLock(&afs_bufferLock); }
void DZap(dir_file_t dir) { /* Destroy all buffers pertaining to a particular fid. */ struct buffer *tb; ObtainReadLock(&afs_bufferLock); for (tb = phTable[pHash(dir)]; tb; tb = tb->hashNext) if (FidEq(bufferDir(tb), dir)) { ObtainWriteLock(&tb->lock); FidZap(bufferDir(tb)); tb->dirty = 0; ReleaseWriteLock(&tb->lock); } ReleaseReadLock(&afs_bufferLock); }
int DFlushVolume(afs_int32 vid) { /* Flush all data and release all inode handles for a particular volume */ struct buffer *tb; int code, rcode = 0; ObtainReadLock(&afs_bufferLock); for (tb = phTable[vHash(vid)]; tb; tb = tb->hashNext) if (FidVolEq(tb->fid, vid)) { ObtainWriteLock(&tb->lock); if (tb->dirty) { code = ReallyWrite(tb->fid, tb->page, tb->data); if (code && !rcode) rcode = code; tb->dirty = 0; } FidZap(tb->fid); ReleaseWriteLock(&tb->lock); } ReleaseReadLock(&afs_bufferLock); return rcode; }
/** * read a page out of a directory object. * * @param[in] fid directory object fid * @param[in] page page in hash table to be read * * @return pointer to requested page in directory cache * @retval NULL read failed */ void * DRead(afs_int32 *fid, int page) { /* Read a page from the disk. */ struct buffer *tb, *tb2, **bufhead; ObtainWriteLock(&afs_bufferLock); calls++; #define bufmatch(tb) (tb->page == page && FidEq(tb->fid, fid)) #define buf_Front(head,parent,p) {(parent)->hashNext = (p)->hashNext; (p)->hashNext= *(head);*(head)=(p);} /* this apparently-complicated-looking code is simply an example of * a little bit of loop unrolling, and is a standard linked-list * traversal trick. It saves a few assignments at the the expense * of larger code size. This could be simplified by better use of * macros. With the use of these LRU queues, the old one-cache is * probably obsolete. */ if ((tb = phTable[pHash(fid)])) { /* ASSMT HERE */ if (bufmatch(tb)) { ObtainWriteLock(&tb->lock); tb->lockers++; ReleaseWriteLock(&afs_bufferLock); tb->accesstime = ++timecounter; ReleaseWriteLock(&tb->lock); return tb->data; } else { bufhead = &(phTable[pHash(fid)]); while ((tb2 = tb->hashNext)) { if (bufmatch(tb2)) { buf_Front(bufhead, tb, tb2); ObtainWriteLock(&tb2->lock); tb2->lockers++; ReleaseWriteLock(&afs_bufferLock); tb2->accesstime = ++timecounter; ReleaseWriteLock(&tb2->lock); return tb2->data; } if ((tb = tb2->hashNext)) { /* ASSIGNMENT HERE! */ if (bufmatch(tb)) { buf_Front(bufhead, tb2, tb); ObtainWriteLock(&tb->lock); tb->lockers++; ReleaseWriteLock(&afs_bufferLock); tb->accesstime = ++timecounter; ReleaseWriteLock(&tb->lock); return tb->data; } } else break; } } } else tb2 = NULL; /* can't find it */ /* The last thing we looked at was either tb or tb2 (or nothing). That * is at least the oldest buffer on one particular hash chain, so it's * a pretty good place to start looking for the truly oldest buffer. */ tb = newslot(fid, page, (tb ? tb : tb2)); ios++; ObtainWriteLock(&tb->lock); tb->lockers++; ReleaseWriteLock(&afs_bufferLock); if (ReallyRead(tb->fid, tb->page, tb->data)) { tb->lockers--; FidZap(tb->fid); /* disaster */ ReleaseWriteLock(&tb->lock); return 0; } /* Note that findslot sets the page field in the buffer equal to * what it is searching for. */ ReleaseWriteLock(&tb->lock); return tb->data; }