dir: Explicitly state buffer locations for data
authorSimon Wilkinson <sxw@your-file-system.com>
Wed, 27 Apr 2011 18:24:56 +0000 (14:24 -0400)
committerDerrick Brashear <shadow@dementia.org>
Thu, 2 Jun 2011 14:37:59 +0000 (07:37 -0700)
DNew and DRead always returned directory page aligned pointers,
however the directory code further manipulates those pointers,
requiring the DRelease be able to fill a page when passed a pointer
to any address within that page. This is relatively straightforward
in the userspace implementation, but much more complex in the kernel,
where all of the directory pages are not necessarily contiguous.

Resolve this issue by making DNew, DRead and DRelease all return a
new structure, struct DirBuffer. This structure contains both a
pointer to the data, and an implementation specific private
pointer to data describing the page containing the address. The
directory code is free to play with the data pointer as it wishes,
as long as the private pointer to the page is passed through intact.

DRelease (and DVOffset) can then simply use the private pointer for
their operations, without having to walk page lists.

This new behaviour also requires changes to the directory functions
GetBlob, FindItem and FindFid which all return pointers to directory
data.

Change-Id: I8b8b003b789976b593a7c752969f47d55f4ee707
Reviewed-on: http://gerrit.openafs.org/4744
Tested-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/afs/LINUX/osi_vnodeops.c
src/afs/LINUX24/osi_vnodeops.c
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/VNOPS/afs_vnop_readdir.c
src/afs/afs_buffer.c
src/afs/afs_prototypes.h
src/dir/Makefile.in
src/dir/buffer.c
src/dir/dir.c
src/dir/dir.h
src/dir/salvage.c

index 17a1b62..0106099 100644 (file)
@@ -263,6 +263,7 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
     int offset;
     int dirpos;
     struct DirEntry *de;
+    struct DirBuffer entry;
     ino_t ino;
     int len;
     afs_size_t origOffset, tlen;
@@ -339,9 +340,10 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
        if (!dirpos)
            break;
 
-       de = afs_dir_GetBlob(tdc, dirpos);
-       if (!de)
+       code = afs_dir_GetBlob(tdc, dirpos, &entry);
+       if (code)
            break;
+       de = (struct DirEntry *)entry.data;
 
        ino = afs_calc_inum (avc->f.fid.Fid.Volume, ntohl(de->fid.vnode));
 
@@ -350,7 +352,7 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
        else {
            printf("afs_linux_readdir: afs_dir_GetBlob failed, null name (inode %lx, dirpos %d)\n", 
                   (unsigned long)&tdc->f.inode, dirpos);
-           DRelease(de, 0);
+           DRelease(&entry, 0);
            ReleaseSharedLock(&avc->lock);
            afs_PutDCache(tdc);
            code = -ENOENT;
@@ -397,7 +399,7 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
            code = (*filldir) (dirbuf, de->name, len, offset, ino, type);
            AFS_GLOCK();
        }
-       DRelease(de, 0);
+       DRelease(&entry, 0);
        if (code)
            break;
        offset = dirpos + 1 + ((len + 16) >> 5);
index b0956e5..df01f85 100644 (file)
@@ -300,9 +300,10 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
        if (!dirpos)
            break;
 
-       de = afs_dir_GetBlob(tdc, dirpos);
-       if (!de)
+       code = afs_dir_GetBlob(tdc, dirpos, &entry);
+       if (code)
            break;
+       de = (struct DirEntry *)entry.data;
 
        ino = afs_calc_inum (avc->f.fid.Fid.Volume, ntohl(de->fid.vnode));
 
index 103a586..c2ac9bc 100644 (file)
@@ -674,6 +674,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     afs_size_t statSeqNo = 0;  /* Valued of file size to detect races */
     int code;                  /* error code */
     long newIndex;             /* new index in the dir */
+    struct DirBuffer entry;    /* Buffer for dir manipulation */
     struct DirEntry *dirEntryp;        /* dir entry we are examining */
     int i;
     struct VenusFid afid;      /* file ID we are using now */
@@ -792,14 +793,14 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        dirCookie = newIndex << 5;
 
        /* get a ptr to the dir entry */
-       dirEntryp =
-           (struct DirEntry *)afs_dir_GetBlob(dcp, newIndex);
-       if (!dirEntryp)
+       code = afs_dir_GetBlob(dcp, newIndex, &entry);
+       if (code)
            break;
+       dirEntryp = (struct DirEntry *)entry.data;
 
        /* dont copy more than we have room for */
        if (fidIndex >= nentries) {
-           DRelease(dirEntryp, 0);
+           DRelease(&entry, 0);
            break;
        }
 
@@ -852,7 +853,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
            }
            if (!tvcp)
            {
-               DRelease(dirEntryp, 0);
+               DRelease(&entry, 0);
                ReleaseReadLock(&dcp->lock);
                ReleaseReadLock(&adp->lock);
                afs_PutDCache(dcp);
@@ -911,7 +912,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
         * used by this dir entry.
         */
        temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
-       DRelease(dirEntryp, 0);
+       DRelease(&entry, 0);
        if (temp <= 0)
            break;
        dirCookie += temp;
index 12a049d..b7ecbb1 100644 (file)
@@ -66,15 +66,19 @@ BlobScan(struct dcache * afile, afs_int32 ablob)
     afs_int32 relativeBlob;
     afs_int32 pageBlob;
     struct PageHeader *tpe;
+    struct DirBuffer headerbuf;
     afs_int32 i;
+    int code;
 
     AFS_STATCNT(BlobScan);
     /* advance ablob over free and header blobs */
     while (1) {
        pageBlob = ablob & ~(EPP - 1);  /* base blob in same page */
-       tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
-       if (!tpe)
-           return 0;           /* we've past the end */
+       code = afs_dir_GetBlob(afile, pageBlob, &headerbuf);
+       if (code)
+           return 0;
+       tpe = (struct PageHeader *)headerbuf.data;
+
        relativeBlob = ablob - pageBlob;        /* relative to page's first blob */
        /* first watch for headers */
        if (pageBlob == 0) {    /* first dir page has extra-big header */
@@ -92,7 +96,7 @@ BlobScan(struct dcache * afile, afs_int32 ablob)
        }
        /* now relativeBlob is the page-relative first allocated blob,
         * or EPP (if there are none in this page). */
-       DRelease(tpe, 0);
+       DRelease(&headerbuf, 0);
        if (i != EPP)
            return i + pageBlob;
        ablob = pageBlob + EPP; /* go around again */
@@ -597,6 +601,7 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
     afs_size_t origOffset, tlen;
     afs_int32 len;
     int code = 0;
+    struct DirBuffer oldEntry, nextEntry;
     struct DirEntry *ode = 0, *nde = 0;
     int o_slen = 0, n_slen = 0;
     afs_uint32 us;
@@ -625,6 +630,9 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
      */
     AFS_STATCNT(afs_readdir);
 
+    memset(&oldEntry, 0, sizeof(struct DirBuffer));
+    memset(&nextEntry, 0, sizeof(struct DirBuffer));
+
 #if defined(AFS_SGI53_ENV)
 #ifdef AFS_SGI61_ENV
 #ifdef AFS_SGI62_ENV
@@ -743,7 +751,7 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
        /* scan for the next interesting entry scan for in-use blob otherwise up point at
         * this blob note that ode, if non-zero, also represents a held dir page */
        if (!(us = BlobScan(tdc, (origOffset >> 5)))
-           || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
+           || (afs_dir_GetBlob(tdc, us, &nextEntry) != 0)) {
            /* failed to setup nde, return what we've got, and release ode */
            if (len) {
                /* something to hand over. */
@@ -794,11 +802,11 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
            if (eofp)
                *eofp = 1;      /* Set it properly */
 #endif
-           if (ode)
-               DRelease(ode, 0);
+           DRelease(&oldEntry, 0);
            goto dirend;
        }
-       /* by here nde is set */
+       nde = (struct DirEntry *)nextEntry.data;
+       
        /* Do we have enough user space to carry out our mission? */
 #if defined(AFS_SGI_ENV)
        n_slen = strlen(nde->name) + 1; /* NULL terminate */
@@ -813,7 +821,7 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
        if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
 #endif /* AFS_SGI53_ENV */
            /* No can do no more now; ya know... at this time */
-           DRelease(nde, 0);   /* can't use this one. */
+           DRelease(&nextEntry, 0);    /* can't use this one. */
            if (len) {
 #ifdef AFS_HPUX_ENV
                sdirEntry->d_fileno =
@@ -862,8 +870,7 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
                 */
                code = EINVAL;
            }
-           if (ode)
-               DRelease(ode, 0);
+           DRelease(&oldEntry, 0);
            goto dirend;
        }
 
@@ -912,13 +919,13 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
 #else
        len = DIRSIZ_LEN(o_slen = n_slen);
 #endif /* AFS_SGI53_ENV */
-       if (ode)
-           DRelease(ode, 0);
+       
+       DRelease(&oldEntry, 0);
        ode = nde;
        AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
     }
-    if (ode)
-       DRelease(ode, 0);
+    
+    DRelease(&oldEntry, 0);
 
   dirend:
     ReleaseReadLock(&tdc->lock);
@@ -935,233 +942,4 @@ afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
     return code;
 }
 
-#if defined(AFS_HPUX_ENV)
-int
-afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred)
-{
-    struct vrequest treq;
-    struct dcache *tdc;
-    afs_size_t origOffset, len;
-    int code = 0;
-    struct DirEntry *ode = 0, *nde = 0;
-    int o_slen = 0, n_slen = 0;
-    afs_uint32 us;
-    /*
-     * XXX All the hacks for alloced sdirEntry and inlining of
-     * afs_readdir_move instead of calling it is necessary for hpux due to
-     * stack problems that seem to occur when coming thru the nfs
-     * translator side XXX
-     */
-    struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
-       osi_AllocSmallSpace(sizeof(struct min_direct));
-    afs_int32 rlen;
-
-    struct afs_fakestat_state fakestate;
-
-    AFS_STATCNT(afs_readdir);
-    if (code = afs_InitReq(&treq, acred)) {
-       osi_FreeSmallSpace((char *)sdirEntry);
-       return code;
-    }
-    afs_InitFakeStat(&fakestate);
-    AFS_DISCON_LOCK();
-    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
-    if (code) {
-       osi_FreeSmallSpace((char *)sdirEntry);
-       AFS_DISCON_UNLOCK();
-       afs_PutFakeStat(&fakestate);
-       return code;
-    }
-    /* update the cache entry */
-  tagain:
-    code = afs_VerifyVCache(avc, &treq);
-    if (code)
-       goto done;
-    /* get a reference to the entire directory */
-    tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
-    if (!tdc) {
-       code = ENOENT;
-       goto done;
-    }
-    ObtainReadLock(&avc->lock);
-    ObtainReadLock(&tdc->lock);
-
-    /*
-     * Make sure that the data in the cache is current. There are two
-     * cases we need to worry about:
-     * 1. The cache data is being fetched by another process.
-     * 2. The cache data is no longer valid
-     */
-    while ((avc->f.states & CStatd)
-          && (tdc->dflags & DFFetching)
-          && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
-       afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
-                  __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
-                  ICL_TYPE_INT32, tdc->dflags);
-       ReleaseReadLock(&tdc->lock);
-       ReleaseReadLock(&avc->lock);
-       afs_osi_Sleep(&tdc->validPos);
-       ObtainReadLock(&avc->lock);
-       ObtainReadLock(&tdc->lock);
-    }
-    if (!(avc->f.states & CStatd)
-       || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
-       ReleaseReadLock(&tdc->lock);
-       ReleaseReadLock(&avc->lock);
-       afs_PutDCache(tdc);
-       goto tagain;
-    }
-
-    len = 0;
-    auio->uio_fpflags = 0;
-    while (code == 0) {
-       origOffset = AFS_UIO_OFFSET(auio);
-
-       /* scan for the next interesting entry scan for in-use blob
-        * otherwise up point at this blob note that ode, if non-zero,
-        * also represents a held dir page */
-       if (!(us = BlobScan(tdc, (origOffset >> 5)))
-           || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
-           /* failed to setup nde, return what we've got, and release ode */
-           if (len) {
-               /* something to hand over. */
-               sdirEntry->d_fileno =
-                   (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-               FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-               sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
-               sdirEntry->d_namlen = o_slen;
-               sdirEntry->d_off = origOffset;
-               AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
-                           auio, code);
-               if (code == 0) {
-                   AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
-               }
-               /* pad out the remaining characters with zeros */
-               if (code == 0) {
-                   AFS_UIOMOVE(bufofzeros,
-                               ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
-                               UIO_READ, auio, code);
-               }
-               /* pad out the difference between rlen and slen... */
-               if (NDIRSIZ_LEN(o_slen) < rlen) {
-                   while (NDIRSIZ_LEN(o_slen) < rlen) {
-                       int minLen = rlen - NDIRSIZ_LEN(o_slen);
-                       if (minLen > sizeof(bufofzeros))
-                           minLen = sizeof(bufofzeros);
-                       AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
-                       rlen -= minLen;
-                   }
-               }
-               AFS_UIO_SETRESID(auio, 0);
-           } else {
-               /* nothin to hand over */
-           }
-           if (ode)
-               DRelease(ode, 0);
-           goto dirend;
-       }
-       /* by here nde is set */
-
-       /* Do we have enough user space to carry out our mission? */
-       n_slen = strlen(nde->name);
-       if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
-           /* No can do no more now; ya know... at this time */
-           DRelease(nde, 0);   /* can't use this one. */
-           if (len) {
-               sdirEntry->d_fileno =
-                   (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-               FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-               sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
-               sdirEntry->d_namlen = o_slen;
-               sdirEntry->d_off = origOffset;
-               AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
-                           auio, code);
-               if (code == 0)
-                   AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
-               /* pad out the remaining characters with zeros */
-               if (code == 0) {
-                   AFS_UIOMOVE(bufofzeros,
-                               ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
-                               UIO_READ, auio, code);
-               }
-               /* pad out the difference between rlen and slen... */
-               if (NDIRSIZ_LEN(o_slen) < rlen) {
-                   while (NDIRSIZ_LEN(o_slen) < rlen) {
-                       int minLen = rlen - NDIRSIZ_LEN(o_slen);
-                       if (minLen > sizeof(bufofzeros))
-                           minLen = sizeof(bufofzeros);
-                       AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
-                       rlen -= minLen;
-                   }
-               }
-               /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
-               AFS_UIO_SETOFFSET(auio, origOffset);
-               AFS_UIO_SETRESID(auio, 0);
-           } else {            /* trouble, can't give anything to the user! */
-               /* even though he has given us a buffer, 
-                * even though we have something to give us,
-                * Looks like we lost something somewhere.
-                */
-               code = EINVAL;
-           }
-           if (ode)
-               DRelease(ode, 0);
-           goto dirend;
-       }
-
-       /*
-        * In any event, we move out the LAST de entry, getting ready
-        * to set up for the next one.
-        */
-       if (len) {
-           sdirEntry->d_fileno =
-               (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-           FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-           sdirEntry->d_reclen = rlen = len;
-           sdirEntry->d_namlen = o_slen;
-           sdirEntry->d_off = origOffset;
-           AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
-                       code);
-           if (code == 0)
-               AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
-           /* pad out the remaining characters with zeros */
-           if (code == 0) {
-               AFS_UIOMOVE(bufofzeros,
-                           ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
-                           UIO_READ, auio, code);
-           }
-           /* pad out the difference between rlen and slen... */
-           if (NDIRSIZ_LEN(o_slen) < rlen) {
-               while (NDIRSIZ_LEN(o_slen) < rlen) {
-                   int minLen = rlen - NDIRSIZ_LEN(o_slen);
-                   if (minLen > sizeof(bufofzeros))
-                       minLen = sizeof(bufofzeros);
-                   AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
-                   rlen -= minLen;
-               }
-           }
-       }
-       len = NDIRSIZ_LEN(o_slen = n_slen);
-       if (ode)
-           DRelease(ode, 0);
-       ode = nde;
-       AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
-    }
-    if (ode)
-       DRelease(ode, 0);
-
-  dirend:
-    ReleaseReadLock(&tdc->lock);
-    afs_PutDCache(tdc);
-    ReleaseReadLock(&avc->lock);
-
-  done:
-    osi_FreeSmallSpace((char *)sdirEntry);
-    AFS_DISCON_UNLOCK();
-    afs_PutFakeStat(&fakestate);
-    code = afs_CheckCode(code, &treq, 29);
-    return code;
-}
-
-#endif
 #endif /* !AFS_LINUX20_ENV */
index 6563656..68cd146 100644 (file)
@@ -145,8 +145,8 @@ DInit(int abuffers)
     return;
 }
 
-void *
-DRead(struct dcache *adc, int page)
+int
+DRead(struct dcache *adc, int page, struct DirBuffer *entry)
 {
     /* Read a page from the disk. */
     struct buffer *tb, *tb2;
@@ -154,6 +154,9 @@ DRead(struct dcache *adc, int page)
     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)
@@ -173,7 +176,9 @@ DRead(struct dcache *adc, int page)
            tb->accesstime = timecounter++;
            AFS_STATS(afs_stats_cmperf.bufHits++);
            ReleaseWriteLock(&tb->lock);
-           return tb->data;
+           entry->buffer = tb;
+           entry->data = tb->data;
+           return 0;
        } else {
            struct buffer **bufhead;
            bufhead = &(phTable[pHash(adc->index, page)]);
@@ -186,7 +191,9 @@ DRead(struct dcache *adc, int page)
                    tb2->accesstime = timecounter++;
                    AFS_STATS(afs_stats_cmperf.bufHits++);
                    ReleaseWriteLock(&tb2->lock);
-                   return tb2->data;
+                   entry->buffer = tb2;
+                   entry->data = tb2->data;
+                   return 0;
                }
                if ((tb = tb2->hashNext)) {
                    if (bufmatch(tb)) {
@@ -197,7 +204,8 @@ DRead(struct dcache *adc, int page)
                        tb->accesstime = timecounter++;
                        AFS_STATS(afs_stats_cmperf.bufHits++);
                        ReleaseWriteLock(&tb->lock);
-                       return tb->data;
+                       entry->buffer = tb;
+                       entry->data = tb->data;
                    }
                } else
                    break;
@@ -215,7 +223,7 @@ DRead(struct dcache *adc, int page)
     tb = afs_newslot(adc, page, (tb ? tb : tb2));
     if (!tb) {
        ReleaseWriteLock(&afs_bufferLock);
-       return NULL;
+       return EIO;
     }
     ObtainWriteLock(&tb->lock, 260);
     tb->lockers++;
@@ -225,7 +233,7 @@ DRead(struct dcache *adc, int page)
        afs_reset_inode(&tb->inode);
        tb->lockers--;
        ReleaseWriteLock(&tb->lock);
-       return NULL;
+       return EIO;
     }
     tfile = afs_CFileOpen(&adc->f.inode);
     code =
@@ -237,12 +245,14 @@ DRead(struct dcache *adc, int page)
        afs_reset_inode(&tb->inode);
        tb->lockers--;
        ReleaseWriteLock(&tb->lock);
-       return NULL;
+       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 void
@@ -377,30 +387,17 @@ afs_newslot(struct dcache *adc, afs_int32 apage, struct buffer *lp)
 }
 
 void
-DRelease(void *loc, int flag)
+DRelease(struct DirBuffer *entry, int flag)
 {
-    /* Release a buffer, specifying whether or not the buffer has been
-     * modified by the locker. */
-    struct buffer *bp = (struct buffer *)loc;
-    int index;
     struct buffer *tp;
 
     AFS_STATCNT(DRelease);
-    if (!bp)
+
+    tp = entry->buffer;
+    if (tp == NULL)
        return;
-    /* look for buffer by scanning Unix buffers for appropriate address */
-    /* careful: despite the declaration above at this point bp is still simply
-     * an address inside the buffer, not a pointer to the buffer header */
-    tp = Buffers;
-    for (index = 0; index < nbuffers; index += NPB, tp += NPB) {
-       if ( (char *) bp >= (char *) tp->data &&
-            (char *) bp < (char *) tp->data + AFS_BUFFER_PAGESIZE * NPB) {
-           /* we found the right range */
-           index += ((char *) bp - (char *) tp->data) >> LOGPS;
-           break;
-       }
-    }
-    tp = &(Buffers[index]);
+
+    tp = entry->buffer;
     ObtainWriteLock(&tp->lock, 261);
     tp->lockers--;
     if (flag)
@@ -409,27 +406,15 @@ DRelease(void *loc, int flag)
 }
 
 int
-DVOffset(void *ap)
+DVOffset(struct DirBuffer *entry)
 {
-    /* Return the byte within a file represented by a buffer pointer. */
-    int index;
-    struct buffer *tp;
+    struct buffer *bp;
+
     AFS_STATCNT(DVOffset);
-    /* look for buffer by scanning Unix buffers for appropriate address */
-    /* see comment in DRelease about the meaning of ap/bp */
-    tp = Buffers;
-    for (index = 0; index < nbuffers; index += NPB, tp += NPB) {
-       if ( (char *) ap >= (char *) tp->data &&
-            (char *) ap < (char *) tp->data + AFS_BUFFER_PAGESIZE * NPB) {
-           /* we found the right range */
-           index += ((char *) ap - (char *) tp->data) >> LOGPS;
-           break;
-       }
-    }
-    if (index < 0 || index >= nbuffers)
-       return -1;
-    tp = &(Buffers[index]);
-    return AFS_BUFFER_PAGESIZE * tp->page + (int)(((char *)ap) - tp->data);
+
+    bp = entry->buffer;
+    return AFS_BUFFER_PAGESIZE * bp->page 
+           + (char *)entry->data - (char *)bp->data;
 }
 
 /*!
@@ -539,16 +524,18 @@ DFlush(void)
     ReleaseReadLock(&afs_bufferLock);
 }
 
-void *
-DNew(struct dcache *adc, int page)
+int
+DNew(struct dcache *adc, int page, struct DirBuffer *entry)
 {
-    /* Same as read, only do *not* even try to read the page, since it probably doesn't exist. */
+    /* Same as read, only do *not* even try to read the page, since it
+     * probably doesn't exist. */
     struct buffer *tb;
     AFS_STATCNT(DNew);
+
     ObtainWriteLock(&afs_bufferLock, 264);
     if ((tb = afs_newslot(adc, page, NULL)) == 0) {
        ReleaseWriteLock(&afs_bufferLock);
-       return 0;
+       return EIO;
     }
     /* extend the chunk, if needed */
     /* Do it now, not in DFlush or afs_newslot when the data is written out,
@@ -563,7 +550,10 @@ DNew(struct dcache *adc, int page)
     tb->lockers++;
     ReleaseWriteLock(&afs_bufferLock);
     ReleaseWriteLock(&tb->lock);
-    return tb->data;
+    entry->buffer = tb;
+    entry->data = tb->data;
+
+    return 0;
 }
 
 void
index f7a8f93..a02b393 100644 (file)
@@ -26,13 +26,14 @@ extern void afs_FreeAllAxs(struct axscache **headp);
 extern void shutdown_xscache(void);
 
 /* afs_buffer.c */
+struct DirBuffer;
 extern void DInit(int abuffers);
-extern void *DRead(struct dcache * fid, int page);
-extern int DVOffset(void *ap);
+extern int DRead(struct dcache * fid, int page, struct DirBuffer *);
+extern int DVOffset(struct DirBuffer *);
 extern void DZap(struct dcache * fid);
 extern void DFlush(void);
 extern void DFlushDCache(struct dcache *);
-extern void *DNew(struct dcache * fid, int page);
+extern int DNew(struct dcache * fid, int page, struct DirBuffer *);
 extern void shutdown_bufferpackage(void);
 
 /* afs_call.c */
index 8eb0f96..077a1f6 100644 (file)
@@ -35,7 +35,7 @@ libdir.a: buffer.o dir.o salvage.o AFS_component_version_number.o
 test: 
        cd test; $(MAKE)
 
-buffer.o: buffer.c
+buffer.o: buffer.c dir.h
 
 dir.o: dir.c dir.h
 
index f25bb1c..459e9db 100644 (file)
@@ -148,12 +148,14 @@ DInit(int abuffers)
  * @return pointer to requested page in directory cache
  *    @retval NULL read failed
  */
-void *
-DRead(afs_int32 *fid, int page)
+int
+DRead(afs_int32 *fid, int page, struct DirBuffer *entry)
 {
     /* Read a page from the disk. */
     struct buffer *tb, *tb2, **bufhead;
 
+    memset(entry, 0, sizeof(struct DirBuffer));
+
     ObtainWriteLock(&afs_bufferLock);
     calls++;
 
@@ -174,7 +176,9 @@ DRead(afs_int32 *fid, int page)
            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)) {
@@ -185,7 +189,9 @@ DRead(afs_int32 *fid, int page)
                    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)) {
@@ -195,7 +201,8 @@ DRead(afs_int32 *fid, int page)
                        ReleaseWriteLock(&afs_bufferLock);
                        tb->accesstime = ++timecounter;
                        ReleaseWriteLock(&tb->lock);
-                       return tb->data;
+                       entry->buffer = tb;
+                       entry->data = tb->data;
                    }
                } else
                    break;
@@ -218,15 +225,18 @@ DRead(afs_int32 *fid, int page)
        tb->lockers--;
        FidZap(tb->fid);        /* 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(struct buffer *ap)
 {
@@ -307,15 +317,13 @@ newslot(afs_int32 *afid, afs_int32 apage, struct buffer *lp)
 /* Release a buffer, specifying whether or not the buffer has been modified
  * by the locker. */
 void
-DRelease(void *loc, int flag)
+DRelease(struct DirBuffer *entry, int flag)
 {
-    struct buffer *bp = (struct buffer *)loc;
-    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)
@@ -323,18 +331,14 @@ DRelease(void *loc, int flag)
     ReleaseWriteLock(&bp->lock);
 }
 
+/* Return the byte within a file represented by a buffer pointer. */
 int
-DVOffset(void *ap)
+DVOffset(struct DirBuffer *entry)
 {
-    /* Return the byte within a file represented by a buffer pointer. */
-    struct buffer *bp = ap;
-    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
@@ -435,21 +439,28 @@ DFlush(void)
     return rcode;
 }
 
-void *
-DNew(afs_int32 *fid, int page)
+/* Same as read, only do *not* even try to read the page,
+ * since it probably doesn't exist.
+ */
+int
+DNew(afs_int32 *fid, int page, struct DirBuffer *entry)
 {
-    /* Same as read, only do *not* even try to read the page,
-     * since it probably doesn't exist.
-     */
     struct buffer *tb;
+
+    memset(entry,0, sizeof(struct DirBuffer));
+
     ObtainWriteLock(&afs_bufferLock);
     if ((tb = newslot(fid, 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;
 }
index 4ba73b9..bcc2ed6 100644 (file)
 #  ifndef AFS_LINUX20_ENV
 #   include "netinet/in.h"
 #  endif
-
-/* afs_buffer.c */
-/* These are needed because afs_prototypes.h is not included here */
-struct dcache;
-extern void *DRead(struct dcache *adc, int page);
-extern void *DNew(struct dcache *adc, int page);
-
 # else /* !defined(UKERNEL) */
 #  include "afs/stds.h"
 #  include "afs/sysincludes.h"
+# endif /* !defined(UKERNEL) */
 
 /* afs_buffer.c */
 /* These are needed because afs_prototypes.h is not included here */
-extern void *DRead(afs_int32 *fid, int page);
-extern void *DNew(afs_int32 *fid, int page);
+struct dcache;
+struct DirBuffer;
+extern int DRead(struct dcache *adc, int page, struct DirBuffer *);
+extern int DNew(struct dcache *adc, int page, struct DirBuffer *);
 
-# endif /* !defined(UKERNEL) */
 # include "afs/afs_osi.h"
 
 # include "afs/dir.h"
@@ -95,9 +90,8 @@ extern void *DNew(afs_int32 *fid, int page);
 afs_int32 DErrno;
 
 /* Local static prototypes */
-static struct DirEntry *FindItem(void *dir, char *ename,
-                                unsigned short **previtem);
-
+static int FindItem(void *dir, char *ename, struct DirBuffer *,
+                   struct DirBuffer *);
 
 /* Find out how many entries are required to store a name. */
 int
@@ -116,43 +110,49 @@ Create(void *dir, char *entry, void *voidfid)
     afs_int32 *vfid = (afs_int32 *) voidfid;
     int blobs, firstelt;
     int i;
+    struct DirBuffer entrybuf, prevbuf, headerbuf;
     struct DirEntry *ep;
-    unsigned short *pp = NULL;
     struct DirHeader *dhp;
 
     /* check name quality */
     if (*entry == 0)
        return EINVAL;
+
     /* First check if file already exists. */
-    ep = FindItem(dir, entry, &pp);
-    if (ep) {
-       DRelease(ep, 0);
-       DRelease(pp, 0);
+    if (FindItem(dir, entry, &prevbuf, &entrybuf) == 0) {
+       DRelease(&entrybuf, 0);
+       DRelease(&prevbuf, 0);
+       printf("Exists ...\n");
        return EEXIST;
     }
+
     blobs = NameBlobs(entry);  /* number of entries required */
     firstelt = FindBlobs(dir, blobs);
     if (firstelt < 0)
        return EFBIG;           /* directory is full */
+
     /* First, we fill in the directory entry. */
-    ep = GetBlob(dir, firstelt);
-    if (ep == 0)
+    if (GetBlob(dir, firstelt, &entrybuf) != 0)
        return EIO;
+    ep = (struct DirEntry *)entrybuf.data;
+
     ep->flag = FFIRST;
     ep->fid.vnode = htonl(vfid[1]);
     ep->fid.vunique = htonl(vfid[2]);
     strcpy(ep->name, entry);
+
     /* Now we just have to thread it on the hash table list. */
-    dhp = (struct DirHeader *)DRead(dir, 0);
-    if (!dhp) {
-       DRelease(ep, 1);
+    if (DRead(dir, 0, &headerbuf) != 0) {
+       DRelease(&entrybuf, 1);
        return EIO;
     }
+    dhp = (struct DirHeader *)headerbuf.data;
+
     i = DirHash(entry);
     ep->next = dhp->hashTable[i];
     dhp->hashTable[i] = htons(firstelt);
-    DRelease(dhp, 1);
-    DRelease(ep, 1);
+    DRelease(&headerbuf, 1);
+    DRelease(&entrybuf, 1);
     return 0;
 }
 
@@ -160,10 +160,13 @@ int
 Length(void *dir)
 {
     int i, ctr;
+    struct DirBuffer headerbuf;
     struct DirHeader *dhp;
-    dhp = (struct DirHeader *)DRead(dir, 0);
-    if (!dhp)
+
+    if (DRead(dir, 0, &headerbuf) != 0)
        return 0;
+    dhp = (struct DirHeader *)headerbuf.data;
+
     if (dhp->header.pgcount != 0)
        ctr = ntohs(dhp->header.pgcount);
     else {
@@ -173,25 +176,31 @@ Length(void *dir)
            if (dhp->alloMap[i] != EPP)
                ctr++;
     }
-    DRelease(dhp, 0);
+    DRelease(&headerbuf, 0);
     return ctr * AFS_PAGESIZE;
 }
 
 int
 Delete(void *dir, char *entry)
 {
-    /* Delete an entry from a directory, including update of all free entry descriptors. */
+    /* Delete an entry from a directory, including update of all free entry
+     * descriptors. */
     int nitems, index;
+    struct DirBuffer entrybuf, prevbuf;
     struct DirEntry *firstitem;
     unsigned short *previtem;
-    firstitem = FindItem(dir, entry, &previtem);
-    if (firstitem == 0)
+
+    if (FindItem(dir, entry, &prevbuf, &entrybuf) != 0)
        return ENOENT;
+
+    firstitem = (struct DirEntry *)entrybuf.data;
+    previtem = (unsigned short *)prevbuf.data;
+
     *previtem = firstitem->next;
-    DRelease(previtem, 1);
-    index = DVOffset(firstitem) / 32;
+    DRelease(&prevbuf, 1);
+    index = DVOffset(&entrybuf) / 32;
     nitems = NameBlobs(firstitem->name);
-    DRelease(firstitem, 0);
+    DRelease(&entrybuf, 0);
     FreeBlobs(dir, index, nitems);
     return 0;
 }
@@ -202,13 +211,16 @@ FindBlobs(void *dir, int nblobs)
     /* Find a bunch of contiguous entries; at least nblobs in a row. */
     int i, j, k;
     int failed = 0;
+    struct DirBuffer headerbuf, pagebuf;
     struct DirHeader *dhp;
     struct PageHeader *pp;
     int pgcount;
 
-    dhp = (struct DirHeader *)DRead(dir, 0);   /* read the dir header in first. */
-    if (!dhp)
+    /* read the dir header in first. */
+    if (DRead(dir, 0, &headerbuf) != 0)
        return -1;
+    dhp = (struct DirHeader *)headerbuf.data;
+
     for (i = 0; i < BIGMAXPAGES; i++) {
        if (i >= MAXPAGES || dhp->alloMap[i] >= nblobs) {
            /* if page could contain enough entries */
@@ -231,11 +243,13 @@ FindBlobs(void *dir, int nblobs)
                dhp->alloMap[i] = EPP - 1;
                dhp->header.pgcount = htons(i + 1);
            }
-           pp = (struct PageHeader *)DRead(dir, i);    /* read the page in. */
-           if (!pp) {
-               DRelease(dhp, 1);
+
+           /* read the page in. */
+           if (DRead(dir, i, &pagebuf) != 0) {
+               DRelease(&headerbuf, 1);
                break;
            }
+           pp = (struct PageHeader *)pagebuf.data;
            for (j = 0; j <= EPP - nblobs; j++) {
                failed = 0;
                for (k = 0; k < nblobs; k++)
@@ -252,17 +266,17 @@ FindBlobs(void *dir, int nblobs)
                 * and free up any resources we've got allocated. */
                if (i < MAXPAGES)
                    dhp->alloMap[i] -= nblobs;
-               DRelease(dhp, 1);
+               DRelease(&headerbuf, 1);
                for (k = 0; k < nblobs; k++)
                    pp->freebitmap[(j + k) >> 3] |= 1 << ((j + k) & 7);
-               DRelease(pp, 1);
+               DRelease(&pagebuf, 1);
                return j + i * EPP;
            }
-           DRelease(pp, 0);    /* This dir page is unchanged. */
+           DRelease(&pagebuf, 0);      /* This dir page is unchanged. */
        }
     }
     /* If we make it here, the directory is full. */
-    DRelease(dhp, 1);
+    DRelease(&headerbuf, 1);
     return -1;
 }
 
@@ -271,8 +285,12 @@ AddPage(void *dir, int pageno)
 {                              /* Add a page to a directory. */
     int i;
     struct PageHeader *pp;
+    struct DirBuffer pagebuf;
+
+    /* Get a new buffer labelled dir,pageno */
+    DNew(dir, pageno, &pagebuf);
+    pp = (struct PageHeader *)pagebuf.data;
 
-    pp = (struct PageHeader *)DNew(dir, pageno);       /* Get a new buffer labelled dir,pageno */
     pp->tag = htons(1234);
     if (pageno > 0)
        pp->pgcount = 0;
@@ -280,7 +298,7 @@ AddPage(void *dir, int pageno)
     pp->freebitmap[0] = 0x01;
     for (i = 1; i < EPP / 8; i++)      /* It's a constant */
        pp->freebitmap[i] = 0;
-    DRelease(pp, 1);
+    DRelease(&pagebuf, 1);
 }
 
 /* Free a whole bunch of directory entries. */
@@ -290,22 +308,29 @@ FreeBlobs(void *dir, int firstblob, int nblobs)
 {
     int i;
     int page;
+    struct DirBuffer headerbuf, pagehdbuf;
     struct DirHeader *dhp;
     struct PageHeader *pp;
     page = firstblob / EPP;
     firstblob -= EPP * page;   /* convert to page-relative entry */
-    dhp = (struct DirHeader *)DRead(dir, 0);
-    if (!dhp)
+
+    if (DRead(dir, 0, &headerbuf) != 0)
        return;
+    dhp = (struct DirHeader *)headerbuf.data;
+
     if (page < MAXPAGES)
        dhp->alloMap[page] += nblobs;
-    DRelease(dhp, 1);
-    pp = (struct PageHeader *)DRead(dir, page);
-    if (pp)
-       for (i = 0; i < nblobs; i++)
-           pp->freebitmap[(firstblob + i) >> 3] &=
-               ~(1 << ((firstblob + i) & 7));
-    DRelease(pp, 1);
+
+    DRelease(&headerbuf, 1);
+
+    if (DRead(dir, page, &pagehdbuf) != 0)
+       return;
+    pp = (struct PageHeader *)pagehdbuf.data;
+
+    for (i = 0; i < nblobs; i++)
+       pp->freebitmap[(firstblob + i) >> 3] &= ~(1 << ((firstblob + i) & 7));
+
+    DRelease(&pagehdbuf, 1);
 }
 
 /*
@@ -317,8 +342,12 @@ int
 MakeDir(void *dir, afs_int32 * me, afs_int32 * parent)
 {
     int i;
+    struct DirBuffer buffer;
     struct DirHeader *dhp;
-    dhp = (struct DirHeader *)DNew(dir, 0);
+
+    DNew(dir, 0, &buffer);
+    dhp = (struct DirHeader *)buffer.data;
+
     dhp->header.pgcount = htons(1);
     dhp->header.tag = htons(1234);
     dhp->header.freecount = (EPP - DHE - 1);
@@ -331,7 +360,7 @@ MakeDir(void *dir, afs_int32 * me, afs_int32 * parent)
        dhp->alloMap[i] = EPP;
     for (i = 0; i < NHASHENT; i++)
        dhp->hashTable[i] = 0;
-    DRelease(dhp, 1);
+    DRelease(&buffer, 1);
     Create(dir, ".", me);
     Create(dir, "..", parent); /* Virtue is its own .. */
     return 0;
@@ -343,16 +372,17 @@ int
 Lookup(void *dir, char *entry, void *voidfid)
 {
     afs_int32 *fid = (afs_int32 *) voidfid;
+    struct DirBuffer firstbuf, prevbuf;
     struct DirEntry *firstitem;
-    unsigned short *previtem;
 
-    firstitem = FindItem(dir, entry, &previtem);
-    if (firstitem == 0)
+    if (FindItem(dir, entry, &prevbuf, &firstbuf) != 0)
        return ENOENT;
-    DRelease(previtem, 0);
+    DRelease(&prevbuf, 0);
+    firstitem = (struct DirEntry *)firstbuf.data;
+
     fid[1] = ntohl(firstitem->fid.vnode);
     fid[2] = ntohl(firstitem->fid.vunique);
-    DRelease(firstitem, 0);
+    DRelease(&firstbuf, 0);
     return 0;
 }
 
@@ -362,38 +392,42 @@ int
 LookupOffset(void *dir, char *entry, void *voidfid, long *offsetp)
 {
     afs_int32 *fid = (afs_int32 *) voidfid;
+    struct DirBuffer firstbuf, prevbuf;
     struct DirEntry *firstitem;
-    unsigned short *previtem;
 
-    firstitem = FindItem(dir, entry, &previtem);
-    if (firstitem == 0)
+    if (FindItem(dir, entry, &prevbuf, &firstbuf) != 0)
        return ENOENT;
-    DRelease(previtem, 0);
+    DRelease(&prevbuf, 0);
+    firstitem = (struct DirEntry *)firstbuf.data;
+
     fid[1] = ntohl(firstitem->fid.vnode);
     fid[2] = ntohl(firstitem->fid.vunique);
     if (offsetp)
-       *offsetp = DVOffset(firstitem);
-    DRelease(firstitem, 0);
+       *offsetp = DVOffset(&firstbuf);
+    DRelease(&firstbuf, 0);
     return 0;
 }
 
+/*
+ * Enumerate the contents of a directory. Break when hook function
+ * returns non 0.
+ */
+
 int
 EnumerateDir(void *dir, int (*hookproc) (void *dir, char *name,
                                         afs_int32 vnode, afs_int32 unique),
             void *hook)
 {
-    /* Enumerate the contents of a directory.
-     * Break when hook function returns non 0.
-     */
     int i;
     int num;
+    struct DirBuffer headerbuf, entrybuf;
     struct DirHeader *dhp;
     struct DirEntry *ep;
     int code = 0;
 
-    dhp = (struct DirHeader *)DRead(dir, 0);
-    if (!dhp)
-       return EIO;             /* first page should be there */
+    if (DRead(dir, 0, &headerbuf) != 0)
+       return EIO;
+    dhp = (struct DirHeader *)headerbuf.data;
 
     for (i = 0; i < NHASHENT; i++) {
        /* For each hash chain, enumerate everyone on the list. */
@@ -401,25 +435,25 @@ EnumerateDir(void *dir, int (*hookproc) (void *dir, char *name,
        while (num != 0) {
            /* Walk down the hash table list. */
            DErrno = 0;
-           ep = GetBlob(dir, num);
-           if (!ep) {
+           if (GetBlob(dir, num, &entrybuf) != 0) {
                if (DErrno) {
                    /* we failed, return why */
-                   DRelease(dhp, 0);
+                   DRelease(&headerbuf, 0);
                    return DErrno;
                }
                break;
            }
+           ep = (struct DirEntry *)entrybuf.data;
 
            num = ntohs(ep->next);
            code = (*hookproc) (hook, ep->name, ntohl(ep->fid.vnode),
                         ntohl(ep->fid.vunique));
-           DRelease(ep, 0);
+           DRelease(&entrybuf, 0);
            if (code)
                break;
        }
     }
-    DRelease(dhp, 0);
+    DRelease(&headerbuf, 0);
     return 0;
 }
 
@@ -429,41 +463,49 @@ IsEmpty(void *dir)
     /* Enumerate the contents of a directory. */
     int i;
     int num;
+    struct DirBuffer headerbuf, entrybuf;
     struct DirHeader *dhp;
     struct DirEntry *ep;
-    dhp = (struct DirHeader *)DRead(dir, 0);
-    if (!dhp)
+
+    if (DRead(dir, 0, &headerbuf) != 0)
        return 0;
+    dhp = (struct DirHeader *)headerbuf.data;
+
     for (i = 0; i < NHASHENT; i++) {
        /* For each hash chain, enumerate everyone on the list. */
        num = ntohs(dhp->hashTable[i]);
        while (num != 0) {
            /* Walk down the hash table list. */
-           ep = GetBlob(dir, num);
-           if (!ep)
-               break;
+           if (GetBlob(dir, num, &entrybuf) != 0);
+               break;
+           ep = (struct DirEntry *)entrybuf.data;
            if (strcmp(ep->name, "..") && strcmp(ep->name, ".")) {
-               DRelease(ep, 0);
-               DRelease(dhp, 0);
+               DRelease(&entrybuf, 0);
+               DRelease(&headerbuf, 0);
                return 1;
            }
            num = ntohs(ep->next);
-           DRelease(ep, 0);
+           DRelease(&entrybuf, 0);
        }
     }
-    DRelease(dhp, 0);
+    DRelease(&headerbuf, 0);
     return 0;
 }
 
-struct DirEntry *
-GetBlob(void *dir, afs_int32 blobno)
+int
+GetBlob(void *dir, afs_int32 blobno, struct DirBuffer *buffer)
 {
-    /* Return a pointer to an entry, given its number. */
-    struct DirEntry *ep;
-    ep = DRead(dir, blobno >> LEPP);
-    if (!ep)
-       return 0;
-    return (struct DirEntry *)(((long)ep) + 32 * (blobno & (EPP - 1)));
+    int code;
+
+    memset(buffer, 0, sizeof(struct DirBuffer));
+
+    code = DRead(dir, blobno >> LEPP, buffer);
+    if (code)
+       return code;
+
+    buffer->data = (void *)(((long)buffer->data) + 32 * (blobno & (EPP - 1)));
+
+    return 0;
 }
 
 int
@@ -493,88 +535,123 @@ DirHash(char *string)
  * found, however, no items are left locked, and a null pointer is
  * returned instead. */
 
-static struct DirEntry *
-FindItem(void *dir, char *ename, unsigned short **previtem)
+static int
+FindItem(void *dir, char *ename, struct DirBuffer *prevbuf,
+         struct DirBuffer *itembuf )
 {
-    int i;
+    int i, code;
+    struct DirBuffer curr, prev;
     struct DirHeader *dhp;
-    unsigned short *lp;
     struct DirEntry *tp;
+
+    memset(prevbuf, 0, sizeof(struct DirBuffer));
+    memset(itembuf, 0, sizeof(struct DirBuffer));
+
+    code = DRead(dir, 0, &prev);
+    if (code)
+       return code;
+    dhp = (struct DirHeader *)prev.data;
+
     i = DirHash(ename);
-    dhp = (struct DirHeader *)DRead(dir, 0);
-    if (!dhp)
-       return 0;
     if (dhp->hashTable[i] == 0) {
        /* no such entry */
-       DRelease(dhp, 0);
-       return 0;
+       DRelease(&prev, 0);
+       return ENOENT;
     }
-    tp = GetBlob(dir, (u_short) ntohs(dhp->hashTable[i]));
-    if (!tp) {
-       DRelease(dhp, 0);
-       return 0;
+
+    code = GetBlob(dir, (u_short) ntohs(dhp->hashTable[i]), &curr);
+    if (code) {
+       DRelease(&prev, 0);
+       return code;
     }
-    lp = &(dhp->hashTable[i]);
+
+    prev.data = &(dhp->hashTable[i]);
+
     while (1) {
-       /* Look at each hash conflict entry. */
+       /* Look at each entry on the hash chain */
+       tp = (struct DirEntry *)curr.data;
        if (!strcmp(ename, tp->name)) {
-           /* Found our entry. */
-           *previtem = lp;
-           return tp;
+           /* Found it! */
+           *prevbuf = prev;
+           *itembuf = curr;
+           return 0;
        }
-       DRelease(lp, 0);
-       lp = &(tp->next);
+       DRelease(&prev, 0);
        if (tp->next == 0) {
            /* The end of the line */
-           DRelease(lp, 0);    /* Release all locks. */
-           return 0;
+           DRelease(&curr, 0);
+           return ENOENT;
        }
-       tp = GetBlob(dir, (u_short) ntohs(tp->next));
-       if (!tp) {
-           DRelease(lp, 0);
-           return 0;
+
+       prev = curr;
+       prev.data = &(tp->next);
+
+       code = GetBlob(dir, (u_short) ntohs(tp->next), &curr);
+       if (code) {
+           DRelease(&prev, 0);
+           return code;
        }
     }
+    /* Never reached */
 }
 
-static struct DirEntry *
-FindFid (void *dir, afs_uint32 vnode, afs_uint32 unique)
+static int
+FindFid (void *dir, afs_uint32 vnode, afs_uint32 unique,
+        struct DirBuffer *itembuf)
 {
     /* Find a directory entry, given the vnode and uniquifier of a object.
      * This entry returns a pointer to a locked buffer.  If no entry is found,
      * however, no items are left locked, and a null pointer is returned
      * instead.
      */
-    int i;
+    int i, code;
+    unsigned short next;
+    struct DirBuffer curr, header;
     struct DirHeader *dhp;
-    unsigned short *lp;
     struct DirEntry *tp;
-    dhp = (struct DirHeader *) DRead(dir,0);
-    if (!dhp) return 0;
+
+    memset(itembuf, 0, sizeof(struct DirBuffer));
+
+    code = DRead(dir, 0, &header);
+    if (code)
+       return code;
+    dhp = (struct DirHeader *)header.data;
+
     for (i=0; i<NHASHENT; i++) {
        if (dhp->hashTable[i] != 0) {
-           tp = GetBlob(dir,(u_short)ntohs(dhp->hashTable[i]));
-           if (!tp) { /* should not happen */
-               DRelease(dhp, 0);
-               return 0;
+           code = GetBlob(dir, (u_short)ntohs(dhp->hashTable[i]),
+                          &curr);
+           if (code) {
+               DRelease(&header, 0);
+               return code;
            }
-           while(tp) {
+
+           while (curr.data != NULL) {
+               tp = (struct DirEntry *)curr.data;
+
                if (vnode == ntohl(tp->fid.vnode)
                    && unique == ntohl(tp->fid.vunique)) {
-                   DRelease(dhp, 0);
-                   return tp;
+                   DRelease(&header, 0);
+                   *itembuf = curr;
+                   return 0;
                }
-               lp = &(tp->next);
-               if (tp->next == 0)
+
+               next = tp->next;
+               DRelease(&curr, 0);
+
+               if (next == 0)
                    break;
-               tp = GetBlob(dir,(u_short)ntohs(tp->next));
-               DRelease(lp, 0);
+
+               code = GetBlob(dir, (u_short)ntohs(next), &curr);
+               if (code) {
+                   DRelease(&header, 0);
+                   return code;
+               }
            }
-           DRelease(lp, 0);
        }
     }
-    DRelease(dhp, 0);
-    return NULL;
+    DRelease(&header, 0);
+    return ENOENT;
 }
 
 int
@@ -582,17 +659,19 @@ InverseLookup (void *dir, afs_uint32 vnode, afs_uint32 unique, char *name,
               afs_uint32 length)
 {
     /* Look for the name pointing to given vnode and unique in a directory */
+    struct DirBuffer entrybuf;
     struct DirEntry *entry;
     int code = 0;
 
-    entry = FindFid(dir, vnode, unique);
-    if (!entry)
+    if (FindFid(dir, vnode, unique, &entrybuf) != 0)
        return ENOENT;
+    entry = (struct DirEntry *)entrybuf.data;
+
     if (strlen(entry->name) >= length)
        code = E2BIG;
     else
        strcpy(name, entry->name);
-    DRelease(entry, 0);
+    DRelease(&entrybuf, 0);
     return code;
 }
 
@@ -610,17 +689,17 @@ int ChangeFid(void *dir,
                afs_uint32 *old_fid,
                afs_uint32 *new_fid)
 {
+    struct DirBuffer prevbuf, entrybuf;
     struct DirEntry *firstitem;
-    unsigned short *previtem;
     struct MKFid *fid_old = (struct MKFid *) old_fid;
     struct MKFid *fid_new = (struct MKFid *) new_fid;
 
     /* Find entry. */
-    firstitem = FindItem(dir, entry, &previtem);
-    if (firstitem == 0) {
+    if (FindItem(dir, entry, &prevbuf, &entrybuf) != 0)
        return ENOENT;
-    }
-    DRelease(previtem, 1);
+    firstitem = (struct DirEntry *)entrybuf.data;
+    DRelease(&prevbuf, 1);
+
     /* Replace fid. */
     if (!old_fid ||
        ((htonl(fid_old->vnode) == firstitem->fid.vnode) &&
@@ -630,7 +709,7 @@ int ChangeFid(void *dir,
        firstitem->fid.vunique = htonl(fid_new->vunique);
     }
 
-    DRelease(firstitem, 1);
+    DRelease(&entrybuf, 1);
 
     return 0;
 }
index d558e1d..3861853 100644 (file)
@@ -39,6 +39,11 @@ struct PageHeader {
     char padding[32 - (5 + EPP / 8)];
 };
 
+struct DirBuffer {
+    void *buffer;
+    void *data;
+};
+
 struct DirHeader {
     /* A directory header object. */
     struct PageHeader header;
@@ -77,7 +82,7 @@ struct DirPage1 {
  * user space code.  One implementation is in afs/afs_buffer.c; the
  * other is in dir/buffer.c.
  */
-extern int DVOffset(void *ap);
+extern int DVOffset(struct DirBuffer *);
 
 
 /* This is private to buffer.c */
@@ -99,12 +104,11 @@ extern int EnumerateDir(void *dir,
                                         afs_int32 vnode, afs_int32 unique),
                        void *hook);
 extern int IsEmpty(void *dir);
-extern struct DirEntry *GetBlob(void *dir, afs_int32 blobno);
+extern int GetBlob(void *dir, afs_int32 blobno, struct DirBuffer *);
 extern int DirHash(char *string);
 
 extern int DStat(int *abuffers, int *acalls, int *aios);
-extern void DRelease(void *loc, int flag);
-extern int DVOffset(void *ap);
+extern void DRelease(struct DirBuffer *loc, int flag);
 extern int DFlushVolume(afs_int32 vid);
 extern int DFlushEntry(afs_int32 *fid);
 extern int InverseLookup (void *dir, afs_uint32 vnode, afs_uint32 unique,
@@ -114,9 +118,9 @@ extern int InverseLookup (void *dir, afs_uint32 vnode, afs_uint32 unique,
    in afs_prototypes.h */
 #ifndef KERNEL
 extern int DInit(int abuffers);
-extern void *DRead(afs_int32 *fid, int page);
+extern int DRead(afs_int32 *fid, int page, struct DirBuffer *);
 extern int DFlush(void);
-extern void *DNew(afs_int32 *fid, int page);
+extern int DNew(afs_int32 *fid, int page, struct DirBuffer *);
 extern void DZap(afs_int32 *fid);
 
 /* salvage.c */
@@ -144,7 +148,7 @@ extern int afs_dir_EnumerateDir(void *dir,
 extern int afs_dir_IsEmpty(void *dir);
 extern int afs_dir_ChangeFid(void *dir, char *entry, afs_uint32 *old_fid,
                                     afs_uint32 *new_fid);
-extern struct DirEntry *afs_dir_GetBlob(void *dir, afs_int32 blobno);
+extern int afs_dir_GetBlob(void *dir, afs_int32 blobno, struct DirBuffer *);
 #endif
 
 #endif /*       !defined(__AFS_DIR_H) */
index 900b92f..d3716c7 100644 (file)
@@ -75,6 +75,7 @@ DirOK(void *file)
     struct DirHeader *dhp;
     struct PageHeader *pp;
     struct DirEntry *ep;
+    struct DirBuffer headerbuf, pagebuf, entrybuf;
     int i, j, k, up;
     int havedot = 0, havedotdot = 0;
     int usedPages, count, entry;
@@ -82,12 +83,13 @@ DirOK(void *file)
     int eaSize;
     afs_int32 entcount, maxents;
     unsigned short ne;
+    int code;
 
     eaSize = BIGMAXPAGES * EPP / 8;
 
     /* Read the directory header */
-    dhp = (struct DirHeader *)DRead(file, 0);
-    if (!dhp) {
+    code = DRead(file,0, &headerbuf);
+    if (code) {
        /* if DErrno is 0, then we know that the read worked, but was short,
         * and the damage is permanent.  Otherwise, we got an I/O or programming
         * error.  Claim the dir is OK, but log something.
@@ -100,11 +102,12 @@ DirOK(void *file)
        printf("First page in directory does not exist.\n");
        return 0;
     }
+    dhp = (struct DirHeader *)headerbuf.data;
 
     /* Check magic number for first page */
     if (dhp->header.tag != htons(1234)) {
        printf("Bad first pageheader magic number.\n");
-       DRelease(dhp, 0);
+       DRelease(&headerbuf, 0);
        return 0;
     }
 
@@ -125,13 +128,13 @@ DirOK(void *file)
                 * two must exist for "." and ".."
                 */
                printf("The dir header alloc map for page %d is bad.\n", i);
-               DRelease(dhp, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
        } else {
            if ((j < 0) || (j > EPP)) {
                printf("The dir header alloc map for page %d is bad.\n", i);
-               DRelease(dhp, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
        }
@@ -142,7 +145,7 @@ DirOK(void *file)
                printf
                    ("A partially-full page occurs in slot %d, after the dir end.\n",
                     i);
-               DRelease(dhp, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
        } else if (j == EPP) {  /* is this the last page */
@@ -160,7 +163,7 @@ DirOK(void *file)
     if (usedPages < up) {
        printf
            ("Count of used directory pages does not match count in directory header\n");
-       DRelease(dhp, 0);
+       DRelease(&headerbuf, 0);
        return 0;
     }
 
@@ -170,9 +173,9 @@ DirOK(void *file)
      */
     for (i = 0; i < usedPages; i++) {
        /* Read the page header */
-       pp = (struct PageHeader *)DRead(file, i);
-       if (!pp) {
-           DRelease(dhp, 0);
+       code = DRead(file, i, &pagebuf);
+       if (code) {
+           DRelease(&headerbuf, 0);
            if (DErrno != 0) {
                /* couldn't read page, but not because it wasn't there permanently */
                printf("Failed to read dir page %d (errno %d)\n", i, DErrno);
@@ -182,12 +185,13 @@ DirOK(void *file)
            printf("Directory shorter than alloMap indicates (page %d)\n", i);
            return 0;
        }
+       pp = (struct PageHeader *)pagebuf.data;
 
        /* check the tag field */
        if (pp->tag != htons(1234)) {
            printf("Directory page %d has a bad magic number.\n", i);
-           DRelease(pp, 0);
-           DRelease(dhp, 0);
+           DRelease(&pagebuf, 0);
+           DRelease(&headerbuf, 0);
            return 0;
        }
 
@@ -221,12 +225,12 @@ DirOK(void *file)
            printf
                ("Header alloMap count doesn't match count in freebitmap for page %d.\n",
                 i);
-           DRelease(pp, 0);
-           DRelease(dhp, 0);
+           DRelease(&pagebuf, 0);
+           DRelease(&headerbuf, 0);
            return 0;
        }
 
-       DRelease(pp, 0);
+       DRelease(&pagebuf, 0);
     }
 
     /* Initialize the in-memory freebit map for all pages. */
@@ -254,34 +258,36 @@ DirOK(void *file)
            /* Verify that the entry is within range */
            if (entry < 0 || entry >= maxents) {
                printf("Out-of-range hash id %d in chain %d.\n", entry, i);
-               DRelease(dhp, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
 
            /* Read the directory entry */
            DErrno = 0;
-           ep = GetBlob(file, entry);
-           if (!ep) {
+           code = GetBlob(file, entry, &entrybuf);
+           if (code) {
                if (DErrno != 0) {
                    /* something went wrong reading the page, but it wasn't
                     * really something wrong with the dir that we can fix.
                     */
                    printf("Could not get dir blob %d (errno %d)\n", entry,
                           DErrno);
-                   DRelease(dhp, 0);
+                   DRelease(&headerbuf, 0);
                    Die("dirok3");
                }
                printf("Invalid hash id %d in chain %d.\n", entry, i);
-               DRelease(dhp, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
+           ep = (struct DirEntry *)entrybuf.data;
+
            ne = ntohs(ep->next);
 
            /* There can't be more than maxents entries */
            if (++entcount >= maxents) {
                printf("Directory's hash chain %d is circular.\n", i);
-               DRelease(ep, 0);
-               DRelease(dhp, 0);
+               DRelease(&entrybuf, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
 
@@ -289,8 +295,8 @@ DirOK(void *file)
            if (ep->name[0] == '\000') {
                printf("Dir entry %"AFS_PTR_FMT
                       " in chain %d has bogus (null) name.\n", ep, i);
-               DRelease(ep, 0);
-               DRelease(dhp, 0);
+               DRelease(&entrybuf, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
 
@@ -298,8 +304,8 @@ DirOK(void *file)
            if (ep->flag != FFIRST) {
                printf("Dir entry %"AFS_PTR_FMT
                       " in chain %d has bogus flag field.\n", ep, i);
-               DRelease(ep, 0);
-               DRelease(dhp, 0);
+               DRelease(&entrybuf, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
 
@@ -308,8 +314,8 @@ DirOK(void *file)
            if (j >= MAXENAME) {        /* MAXENAME counts the null */
                printf("Dir entry %"AFS_PTR_FMT
                       " in chain %d has too-long name.\n", ep, i);
-               DRelease(ep, 0);
-               DRelease(dhp, 0);
+               DRelease(&entrybuf, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
 
@@ -326,8 +332,8 @@ DirOK(void *file)
                printf("Dir entry %"AFS_PTR_FMT
                       " should be in hash bucket %d but IS in %d.\n",
                       ep, j, i);
-               DRelease(ep, 0);
-               DRelease(dhp, 0);
+               DRelease(&entrybuf, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
 
@@ -340,8 +346,8 @@ DirOK(void *file)
                        ("Dir entry %"AFS_PTR_FMT
                         ", index 13 has name '%s' should be '.'\n",
                         ep, ep->name);
-                   DRelease(ep, 0);
-                   DRelease(dhp, 0);
+                   DRelease(&entrybuf, 0);
+                   DRelease(&headerbuf, 0);
                    return 0;
                }
            }
@@ -355,15 +361,15 @@ DirOK(void *file)
                        ("Dir entry %"AFS_PTR_FMT
                         ", index 14 has name '%s' should be '..'\n",
                         ep, ep->name);
-                   DRelease(ep, 0);
-                   DRelease(dhp, 0);
+                   DRelease(&entrybuf, 0);
+                   DRelease(&headerbuf, 0);
                    return 0;
                }
            }
 
            /* CHECK FOR DUPLICATE NAMES? */
 
-           DRelease(ep, 0);
+           DRelease(&entrybuf, 0);
        }
     }
 
@@ -371,7 +377,7 @@ DirOK(void *file)
     if (!havedot || !havedotdot) {
        printf
            ("Directory entry '.' or '..' does not exist or is in the wrong index.\n");
-       DRelease(dhp, 0);
+       DRelease(&headerbuf, 0);
        return 0;
     }
 
@@ -380,12 +386,12 @@ DirOK(void *file)
      * Note that if this matches, alloMap has already been checked against it.
      */
     for (i = 0; i < usedPages; i++) {
-       pp = DRead(file, i);
-       if (!pp) {
+       code = DRead(file, i, &pagebuf);
+       if (code) {
            printf
                ("Failed on second attempt to read dir page %d (errno %d)\n",
                 i, DErrno);
-           DRelease(dhp, 0);
+           DRelease(&headerbuf, 0);
            /* if DErrno is 0, then the dir is really bad, and we return dir *not* OK.
             * otherwise, we want to return true (1), meaning the dir isn't known
             * to be bad (we can't tell, since I/Os are failing.
@@ -395,6 +401,7 @@ DirOK(void *file)
            else
                return 0;       /* dir is really shorter */
        }
+       pp = (struct PageHeader *)pagebuf.data;
 
        count = i * (EPP / 8);
        for (j = 0; j < EPP / 8; j++) {
@@ -402,17 +409,17 @@ DirOK(void *file)
                printf
                    ("Entry freebitmap error, page %d, map offset %d, %x should be %x.\n",
                     i, j, pp->freebitmap[j], eaMap[count + j]);
-               DRelease(pp, 0);
-               DRelease(dhp, 0);
+               DRelease(&pagebuf, 0);
+               DRelease(&headerbuf, 0);
                return 0;
            }
        }
 
-       DRelease(pp, 0);
+       DRelease(&pagebuf, 0);
     }
 
     /* Finally cleanup and return. */
-    DRelease(dhp, 0);
+    DRelease(&headerbuf, 0);
     return 1;
 }
 
@@ -438,6 +445,7 @@ DirSalvage(void *fromFile, void *toFile, afs_int32 vn, afs_int32 vu,
     char tname[256];
     int i;
     char *tp;
+    struct DirBuffer headerbuf, entrybuf;
     struct DirHeader *dhp;
     struct DirEntry *ep;
     int entry;
@@ -454,8 +462,8 @@ DirSalvage(void *fromFile, void *toFile, afs_int32 vn, afs_int32 vu,
     /* Find out how many pages are valid, using stupid heuristic since DRead
      * never returns null.
      */
-    dhp = (struct DirHeader *)DRead(fromFile, 0);
-    if (!dhp) {
+    code = DRead(fromFile, 0, &headerbuf);
+    if (code) {
        printf("Failed to read first page of fromDir!\n");
        /* if DErrno != 0, then our call failed and we should let our
         * caller know that there's something wrong with the new dir.  If not,
@@ -463,6 +471,7 @@ DirSalvage(void *fromFile, void *toFile, afs_int32 vn, afs_int32 vu,
         */
        return DErrno;
     }
+    dhp = (struct DirHeader *)headerbuf.data;
 
     usedPages = ComputeUsedPages(dhp);
 
@@ -477,20 +486,23 @@ DirSalvage(void *fromFile, void *toFile, afs_int32 vn, afs_int32 vu,
                    ("Warning: bogus hash table entry encountered, ignoring.\n");
                break;
            }
+
            DErrno = 0;
-           ep = GetBlob(fromFile, entry);
-           if (!ep) {
+           code = GetBlob(fromFile, entry, &entrybuf);
+           if (code) {
                if (DErrno) {
                    printf
                        ("can't continue down hash chain (entry %d, errno %d)\n",
                         entry, DErrno);
-                   DRelease(dhp, 0);
+                   DRelease(&headerbuf, 0);
                    return DErrno;
                }
                printf
                    ("Warning: bogus hash chain encountered, switching to next.\n");
                break;
            }
+           ep = (struct DirEntry *)entrybuf.data;
+
            strncpy(tname, ep->name, MAXENAME);
            tname[MAXENAME - 1] = '\000';       /* just in case */
            tp = tname;
@@ -505,15 +517,15 @@ DirSalvage(void *fromFile, void *toFile, afs_int32 vn, afs_int32 vu,
                    printf
                        ("Create of %s returned code %d, skipping to next hash chain.\n",
                         tname, code);
-                   DRelease(ep, 0);
+                   DRelease(&entrybuf, 0);
                    break;
                }
            }
-           DRelease(ep, 0);
+           DRelease(&entrybuf, 0);
        }
     }
 
     /* Clean up things. */
-    DRelease(dhp, 0);
+    DRelease(&headerbuf, 0);
     return 0;
 }