Пример #1
0
int
DRead(struct dcache *adc, int page, struct DirBuffer *entry)
{
    /* Read a page from the disk. */
    struct buffer *tb, *tb2;
    struct osi_file *tfile;
    int code;

    AFS_STATCNT(DRead);

    memset(entry, 0, sizeof(struct DirBuffer));

    ObtainWriteLock(&afs_bufferLock, 256);

#define bufmatch(tb) (tb->page == page && tb->fid == adc->index)
#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.
     */
    if ((tb = phTable[pHash(adc->index, page)])) {
	if (bufmatch(tb)) {
	    ObtainWriteLock(&tb->lock, 257);
	    tb->lockers++;
	    ReleaseWriteLock(&afs_bufferLock);
	    tb->accesstime = timecounter++;
	    AFS_STATS(afs_stats_cmperf.bufHits++);
	    ReleaseWriteLock(&tb->lock);
	    entry->buffer = tb;
	    entry->data = tb->data;
	    return 0;
	} else {
	    struct buffer **bufhead;
	    bufhead = &(phTable[pHash(adc->index, page)]);
	    while ((tb2 = tb->hashNext)) {
		if (bufmatch(tb2)) {
		    buf_Front(bufhead, tb, tb2);
		    ObtainWriteLock(&tb2->lock, 258);
		    tb2->lockers++;
		    ReleaseWriteLock(&afs_bufferLock);
		    tb2->accesstime = timecounter++;
		    AFS_STATS(afs_stats_cmperf.bufHits++);
		    ReleaseWriteLock(&tb2->lock);
		    entry->buffer = tb2;
		    entry->data = tb2->data;
		    return 0;
		}
		if ((tb = tb2->hashNext)) {
		    if (bufmatch(tb)) {
			buf_Front(bufhead, tb2, tb);
			ObtainWriteLock(&tb->lock, 259);
			tb->lockers++;
			ReleaseWriteLock(&afs_bufferLock);
			tb->accesstime = timecounter++;
			AFS_STATS(afs_stats_cmperf.bufHits++);
			ReleaseWriteLock(&tb->lock);
			entry->buffer = tb;
			entry->data = tb->data;
			return 0;
		    }
		} else
		    break;
	    }
	}
    } else
	tb2 = NULL;

    AFS_STATS(afs_stats_cmperf.bufMisses++);
    /* 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 = afs_newslot(adc, page, (tb ? tb : tb2));
    if (!tb) {
	ReleaseWriteLock(&afs_bufferLock);
	return EIO;
    }
    ObtainWriteLock(&tb->lock, 260);
    tb->lockers++;
    ReleaseWriteLock(&afs_bufferLock);
    if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
	tb->fid = NULLIDX;
	afs_reset_inode(&tb->inode);
	tb->lockers--;
	ReleaseWriteLock(&tb->lock);
	return EIO;
    }
    tfile = afs_CFileOpen(&adc->f.inode);
    code =
	afs_CFileRead(tfile, tb->page * AFS_BUFFER_PAGESIZE, tb->data,
		      AFS_BUFFER_PAGESIZE);
    afs_CFileClose(tfile);
    if (code < AFS_BUFFER_PAGESIZE) {
	tb->fid = NULLIDX;
	afs_reset_inode(&tb->inode);
	tb->lockers--;
	ReleaseWriteLock(&tb->lock);
	return EIO;
    }
    /* Note that findslot sets the page field in the buffer equal to
     * what it is searching for. */
    ReleaseWriteLock(&tb->lock);
    entry->buffer = tb;
    entry->data = tb->data;
    return 0;
}
Пример #2
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;
}