Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
/**
 * 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;
}