#include <afsconfig.h>
#include <afs/param.h>
-RCSID
- ("$Header$");
+#include <roken.h>
+#include <afs/opr.h>
-#include <stdlib.h>
#include <lock.h>
#include "dir.h"
+#ifdef AFS_64BIT_IOPS_ENV
+#define BUFFER_FID_SIZE (9*sizeof(int) + 2*sizeof(char*))
+#else
+#define BUFFER_FID_SIZE (6*sizeof(int) + 2*sizeof(char*))
+#endif
+
+struct buffer {
+ /* fid is used for Unique cache key + i/o addressing.
+ * fid size is based on 4 + size of inode and size of pointer
+ */
+ char fid[BUFFER_FID_SIZE];
+ afs_int32 page;
+ afs_int32 accesstime;
+ struct buffer *hashNext;
+ void *data;
+ char lockers;
+ char dirty;
+ char hashIndex;
+ struct Lock lock;
+};
+
+static_inline dir_file_t
+bufferDir(struct buffer *b)
+{
+ return (dir_file_t) &b->fid;
+}
+
struct Lock afs_bufferLock;
/* page size */
* based on the volume id. This means this macro is dependent upon the
* layout of DirHandle in viced/viced.h, vol/salvage.h and volser/salvage.h.
*/
-#define pHash(fid) ((fid)[0] & (PHSIZE-1))
+#define pHash(fid) (((afs_int32 *)fid)[0] & (PHSIZE-1))
#define vHash(vid) (vid & (PHSIZE-1))
/* admittedly system dependent, this is the maximum signed 32-bit value */
#define NULL 0
#endif
-#ifdef AFS_64BIT_IOPS_ENV
-#define BUFFER_FID_SIZE (9 + 2*sizeof(char*)/sizeof(int))
-#else
-#define BUFFER_FID_SIZE (6 + 2*sizeof(char*)/sizeof(int))
-#endif
-
-static struct buffer {
- /* fid is used for Unique cache key + i/o addressing.
- * fid size is based on 4 + size of inode and size of pointer
- */
- afs_int32 fid[BUFFER_FID_SIZE];
- afs_int32 page;
- afs_int32 accesstime;
- struct buffer *hashNext;
- void *data;
- char lockers;
- char dirty;
- char hashIndex;
- struct Lock lock;
-} **Buffers;
+static struct buffer **Buffers;
char *BufferData;
int timecounter;
static int calls = 0, ios = 0;
-struct buffer *newslot();
+struct buffer *newslot(dir_file_t dir, afs_int32 apage,
+ struct buffer *lp);
+
+/* XXX - This sucks. The correct prototypes for these functions are ...
+ *
+ * extern void FidZero(DirHandle *);
+ * extern int FidEq(DirHandle *a, DirHandle *b);
+ * extern int ReallyRead(DirHandle *a, int block, char *data);
+ */
+
+extern void FidZero(dir_file_t);
+extern int FidEq(dir_file_t, dir_file_t);
+extern int ReallyRead(dir_file_t, int block, char *data);
+extern int ReallyWrite(dir_file_t, int block, char *data);
+extern void FidZap(dir_file_t);
+extern int FidVolEq(dir_file_t, afs_int32 vid);
+extern void FidCpy(dir_file_t, dir_file_t fromfile);
int
-DStat(abuffers, acalls, aios)
- int *abuffers, *acalls, *aios;
+DStat(int *abuffers, int *acalls, int *aios)
{
*abuffers = nbuffers;
*acalls = calls;
return 0;
}
-int
-DInit(abuffers)
- int abuffers;
+/**
+ * initialize the directory package.
+ *
+ * @param[in] abuffers size of directory buffer cache
+ *
+ * @return operation status
+ * @retval 0 success
+ */
+void
+DInit(int abuffers)
{
/* Initialize the venus buffer system. */
- register int i, tsize;
- register struct buffer *tb;
- register char *tp;
+ int i, tsize;
+ struct buffer *tb;
+ char *tp;
Lock_Init(&afs_bufferLock);
/* Align each element of Buffers on a doubleword boundary */
tsize = (sizeof(struct buffer) + 7) & ~7;
- tp = (char *)malloc(abuffers * tsize);
- Buffers = (struct buffer **)malloc(abuffers * sizeof(struct buffer *));
- BufferData = (char *)malloc(abuffers * BUFFER_PAGE_SIZE);
+ tp = malloc(abuffers * tsize);
+ Buffers = malloc(abuffers * sizeof(struct buffer *));
+ BufferData = malloc(abuffers * BUFFER_PAGE_SIZE);
timecounter = 0;
LastBuffer = (struct buffer *)tp;
nbuffers = abuffers;
tb = (struct buffer *)tp;
Buffers[i] = tb;
tp += tsize;
- FidZero(tb->fid);
+ FidZero(bufferDir(tb));
tb->accesstime = tb->lockers = 0;
tb->data = &BufferData[BUFFER_PAGE_SIZE * i];
tb->hashIndex = 0;
tb->dirty = 0;
Lock_Init(&tb->lock);
}
- return 0;
+ return;
}
-void *
-DRead(fid, page)
- register afs_int32 *fid;
- register int page;
+/**
+ * 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
+ */
+int
+DRead(dir_file_t fid, int page, struct DirBuffer *entry)
{
/* Read a page from the disk. */
- register struct buffer *tb, *tb2, **bufhead;
+ struct buffer *tb, *tb2, **bufhead;
+
+ memset(entry, 0, sizeof(struct DirBuffer));
ObtainWriteLock(&afs_bufferLock);
calls++;
-#define bufmatch(tb) (tb->page == page && FidEq(tb->fid, fid))
+#define bufmatch(tb,fid) (tb->page == page && FidEq(bufferDir(tb), 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
* 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)) {
+ if ((tb = phTable[pHash(fid)])) { /* ASSMT HERE */
+ if (bufmatch(tb, fid)) {
ObtainWriteLock(&tb->lock);
tb->lockers++;
ReleaseWriteLock(&afs_bufferLock);
tb->accesstime = ++timecounter;
ReleaseWriteLock(&tb->lock);
- return tb->data;
+ entry->buffer = tb;
+ entry->data = tb->data;
+ return 0;
} else {
bufhead = &(phTable[pHash(fid)]);
- while (tb2 = tb->hashNext) {
- if (bufmatch(tb2)) {
+ while ((tb2 = tb->hashNext)) {
+ if (bufmatch(tb2, fid)) {
buf_Front(bufhead, tb, tb2);
ObtainWriteLock(&tb2->lock);
tb2->lockers++;
ReleaseWriteLock(&afs_bufferLock);
tb2->accesstime = ++timecounter;
ReleaseWriteLock(&tb2->lock);
- return tb2->data;
+ entry->buffer = tb2;
+ entry->data = tb2->data;
+ return 0;
}
- if (tb = tb2->hashNext) { /* ASSIGNMENT HERE! */
- if (bufmatch(tb)) {
+ if ((tb = tb2->hashNext)) { /* ASSIGNMENT HERE! */
+ if (bufmatch(tb, fid)) {
buf_Front(bufhead, tb2, tb);
ObtainWriteLock(&tb->lock);
tb->lockers++;
ReleaseWriteLock(&afs_bufferLock);
tb->accesstime = ++timecounter;
ReleaseWriteLock(&tb->lock);
- return tb->data;
+ entry->buffer = tb;
+ entry->data = tb->data;
+ return 0;
}
} else
break;
ObtainWriteLock(&tb->lock);
tb->lockers++;
ReleaseWriteLock(&afs_bufferLock);
- if (ReallyRead(tb->fid, tb->page, tb->data)) {
+ if (ReallyRead(bufferDir(tb), tb->page, tb->data)) {
tb->lockers--;
- FidZap(tb->fid); /* disaster */
+ FidZap(bufferDir(tb)); /* disaster */
ReleaseWriteLock(&tb->lock);
- return 0;
+ return EIO;
}
/* Note that findslot sets the page field in the buffer equal to
* what it is searching for.
*/
ReleaseWriteLock(&tb->lock);
- return tb->data;
+ entry->buffer = tb;
+ entry->data = tb->data;
+ return 0;
}
+
static int
-FixupBucket(ap)
- register struct buffer *ap;
+FixupBucket(struct buffer *ap)
{
- register struct buffer **lp, *tp;
- register int i;
+ struct buffer **lp, *tp;
+ int i;
/* first try to get it out of its current hash bucket, in which it might not be */
i = ap->hashIndex;
lp = &tp->hashNext;
}
/* now figure the new hash bucket */
- i = pHash(ap->fid);
+ i = pHash(ap);
ap->hashIndex = i; /* remember where we are for deletion */
ap->hashNext = phTable[i]; /* add us to the list */
phTable[i] = ap; /* at the front, since it's LRU */
}
struct buffer *
-newslot(afid, apage, lp)
- afs_int32 *afid, apage;
- register struct buffer *lp; /* pointer to a fairly-old buffer */
+newslot(dir_file_t dir, afs_int32 apage, struct buffer *lp)
{
/* Find a usable buffer slot */
- register afs_int32 i;
+ afs_int32 i;
afs_int32 lt;
- register struct buffer **tbp;
+ struct buffer **tbp;
if (lp && (lp->lockers == 0)) {
lt = lp->accesstime;
* 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))
+ if (ReallyWrite(bufferDir(lp), 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 */
+ FidZap(bufferDir(lp));
+ FidCpy(bufferDir(lp), dir); /* set this */
+ memset(lp->data, 0, BUFFER_PAGE_SIZE); /* Don't leak stale data. */
lp->page = apage;
lp->accesstime = ++timecounter;
return lp;
}
+/* Release a buffer, specifying whether or not the buffer has been modified
+ * by the locker. */
void
-DRelease(bp, flag)
- register struct buffer *bp;
- int flag;
+DRelease(struct DirBuffer *entry, int flag)
{
- /* Release a buffer, specifying whether or not the buffer has been modified by the locker. */
- register int index;
+ struct buffer *bp;
- if (!bp)
+ bp = (struct buffer *) entry->buffer;
+ if (bp == NULL)
return;
- index = ((char *)bp - BufferData) >> LOGPS;
- bp = Buffers[index];
ObtainWriteLock(&bp->lock);
bp->lockers--;
if (flag)
ReleaseWriteLock(&bp->lock);
}
+/* Return the byte within a file represented by a buffer pointer. */
int
-DVOffset(ap)
- register void *ap;
+DVOffset(struct DirBuffer *entry)
{
- /* Return the byte within a file represented by a buffer pointer. */
- register struct buffer *bp = ap;
- register int index;
-
- index = ((char *)bp - BufferData) >> LOGPS;
- if (index < 0 || index >= nbuffers)
- return -1;
- bp = Buffers[index];
- return BUFFER_PAGE_SIZE * bp->page + (char *)ap - (char *)bp->data;
+ struct buffer *bp;
+
+ bp = entry->buffer;
+ return BUFFER_PAGE_SIZE * bp->page + (char *)entry->data - (char *)bp->data;
}
void
-DZap(fid)
- register afs_int32 *fid;
+DZap(dir_file_t dir)
{
/* Destroy all buffers pertaining to a particular fid. */
- register struct buffer *tb;
+ struct buffer *tb;
ObtainReadLock(&afs_bufferLock);
- for (tb = phTable[pHash(fid)]; tb; tb = tb->hashNext)
- if (FidEq(tb->fid, fid)) {
+ for (tb = phTable[pHash(dir)]; tb; tb = tb->hashNext)
+ if (FidEq(bufferDir(tb), dir)) {
ObtainWriteLock(&tb->lock);
- FidZap(tb->fid);
+ FidZap(bufferDir(tb));
tb->dirty = 0;
ReleaseWriteLock(&tb->lock);
}
}
int
-DFlushVolume(vid)
- register afs_int32 vid;
+DFlushVolume(afs_int32 vid)
{
/* Flush all data and release all inode handles for a particular volume */
- register struct buffer *tb;
- register int code, rcode = 0;
+ struct buffer *tb;
+ int code, rcode = 0;
ObtainReadLock(&afs_bufferLock);
for (tb = phTable[vHash(vid)]; tb; tb = tb->hashNext)
- if (FidVolEq(tb->fid, vid)) {
+ if (FidVolEq(bufferDir(tb), vid)) {
ObtainWriteLock(&tb->lock);
if (tb->dirty) {
- code = ReallyWrite(tb->fid, tb->page, tb->data);
+ code = ReallyWrite(bufferDir(tb), tb->page, tb->data);
if (code && !rcode)
rcode = code;
tb->dirty = 0;
}
- FidZap(tb->fid);
+ FidZap(bufferDir(tb));
ReleaseWriteLock(&tb->lock);
}
ReleaseReadLock(&afs_bufferLock);
}
int
-DFlushEntry(fid)
- register afs_int32 *fid;
+DFlushEntry(dir_file_t fid)
{
/* Flush pages modified by one entry. */
- register struct buffer *tb;
+ struct buffer *tb;
int code;
ObtainReadLock(&afs_bufferLock);
for (tb = phTable[pHash(fid)]; tb; tb = tb->hashNext)
- if (FidEq(tb->fid, fid) && tb->dirty) {
+ if (FidEq(bufferDir(tb), fid) && tb->dirty) {
ObtainWriteLock(&tb->lock);
if (tb->dirty) {
- code = ReallyWrite(tb->fid, tb->page, tb->data);
+ code = ReallyWrite(bufferDir(tb), tb->page, tb->data);
if (code) {
ReleaseWriteLock(&tb->lock);
ReleaseReadLock(&afs_bufferLock);
}
int
-DFlush()
+DFlush(void)
{
/* Flush all the modified buffers. */
- register int i;
- register struct buffer **tbp;
+ int i;
+ struct buffer **tbp;
afs_int32 code, rcode;
rcode = 0;
(*tbp)->lockers++;
ReleaseReadLock(&afs_bufferLock);
if ((*tbp)->dirty) {
- code = ReallyWrite((*tbp)->fid, (*tbp)->page, (*tbp)->data);
+ code = ReallyWrite(bufferDir(*tbp), (*tbp)->page, (*tbp)->data);
if (!code)
(*tbp)->dirty = 0; /* Clear the dirty flag */
if (code && !rcode) {
return rcode;
}
-void *
-DNew(fid, page)
- register int page;
- register afs_int32 *fid;
+/* Same as read, only do *not* even try to read the page,
+ * since it probably doesn't exist.
+ */
+int
+DNew(dir_file_t dir, int page, struct DirBuffer *entry)
{
- /* Same as read, only do *not* even try to read the page,
- * since it probably doesn't exist.
- */
- register struct buffer *tb;
+ struct buffer *tb;
+
+ memset(entry,0, sizeof(struct DirBuffer));
+
ObtainWriteLock(&afs_bufferLock);
- if ((tb = newslot(fid, page, 0)) == 0) {
+ if ((tb = newslot(dir, page, 0)) == 0) {
ReleaseWriteLock(&afs_bufferLock);
- return 0;
+ return EIO;
}
ObtainWriteLock(&tb->lock);
tb->lockers++;
ReleaseWriteLock(&afs_bufferLock);
ReleaseWriteLock(&tb->lock);
- return tb->data;
+
+ entry->buffer = tb;
+ entry->data = tb->data;
+
+ return 0;
}