afs: remove redundant assignment
[openafs.git] / src / afs / afs_buffer.c
index 58d9fce..76c2b7c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include "afs/sysincludes.h"
 #include "afsincludes.h"
 #if !defined(UKERNEL)
-#include "h/param.h"
+#if !defined(AFS_LINUX26_ENV)
+# include "h/param.h"
+#endif
 #include "h/types.h"
 #include "h/time.h"
-#if    defined(AFS_AIX31_ENV) 
+#if    defined(AFS_AIX31_ENV)
 #include "h/limits.h"
 #endif
 #if    !defined(AFS_AIX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV)
@@ -46,8 +48,9 @@
 #ifndef        BUF_TIME_MAX
 #define        BUF_TIME_MAX    0x7fffffff
 #endif
-/* number of pages per Unix buffer, when we're using Unix buffer pool */
-#define        NPB 4
+#define NPB 8                  /* must be a pwer of 2 */
+static int afs_max_buffers;    /* should be an integral multiple of NPB */
+
 /* page size */
 #define AFS_BUFFER_PAGESIZE 2048
 /* log page size */
@@ -76,9 +79,23 @@ extern struct buf *geteblk();
 #ifdef AFS_FBSD_ENV
 #define timecounter afs_timecounter
 #endif
-/* The locks for individual buffer entries are now sometimes obtained while holding the
- * afs_bufferLock. Thus we now have a locking hierarchy: afs_bufferLock -> Buffers[].lock.
+
+/* A note on locking in 'struct buffer'
+ *
+ * afs_bufferLock protects the hash chain, and the 'lockers' field where that
+ * has a zero value. It must be held whenever lockers is incremented from zero.
+ *
+ * The individual buffer lock protects the contents of the structure, including
+ * the lockers field.
+ *
+ * For safety: afs_bufferLock and the individual buffer lock must be held
+ * when obtaining a reference on a structure. Only the individual buffer lock
+ * need be held when releasing a reference.
+ *
+ * The locking hierarchy is afs_bufferLock-> buffer.lock
+ *
  */
+
 static afs_lock_t afs_bufferLock;
 static struct buffer *phTable[PHSIZE]; /* page hash table */
 static int nbuffers;
@@ -86,60 +103,43 @@ static afs_int32 timecounter;
 
 /* Prototypes for static routines */
 static struct buffer *afs_newslot(struct dcache *adc, afs_int32 apage,
-                                 register struct buffer *lp);
+                                 struct buffer *lp);
 
 static int dinit_flag = 0;
 void
 DInit(int abuffers)
 {
     /* Initialize the venus buffer system. */
-    register int i;
-    register struct buffer *tb;
-#if defined(AFS_USEBUFFERS)
-    struct buf *tub;           /* unix buffer for allocation */
-#endif
+    int i;
+    struct buffer *tb;
 
     AFS_STATCNT(DInit);
     if (dinit_flag)
        return;
     dinit_flag = 1;
-#if defined(AFS_USEBUFFERS)
     /* round up to next multiple of NPB, since we allocate multiple pages per chunk */
     abuffers = ((abuffers - 1) | (NPB - 1)) + 1;
-#endif
+    afs_max_buffers = abuffers << 2;           /* possibly grow up to 4 times as big */
     LOCK_INIT(&afs_bufferLock, "afs_bufferLock");
-    Buffers =
-       (struct buffer *)afs_osi_Alloc(abuffers * sizeof(struct buffer));
-#if !defined(AFS_USEBUFFERS)
-    BufferData = (char *)afs_osi_Alloc(abuffers * AFS_BUFFER_PAGESIZE);
-#endif
+    Buffers = afs_osi_Alloc(afs_max_buffers * sizeof(struct buffer));
+    osi_Assert(Buffers != NULL);
     timecounter = 1;
     afs_stats_cmperf.bufAlloced = nbuffers = abuffers;
     for (i = 0; i < PHSIZE; i++)
        phTable[i] = 0;
     for (i = 0; i < abuffers; i++) {
-#if defined(AFS_USEBUFFERS)
        if ((i & (NPB - 1)) == 0) {
            /* time to allocate a fresh buffer */
-           tub = geteblk(AFS_BUFFER_PAGESIZE * NPB);
-           BufferData = (char *)tub->b_un.b_addr;
+           BufferData = afs_osi_Alloc(AFS_BUFFER_PAGESIZE * NPB);
+           osi_Assert(BufferData != NULL);
        }
-#endif
        /* Fill in each buffer with an empty indication. */
        tb = &Buffers[i];
        tb->fid = NULLIDX;
        afs_reset_inode(&tb->inode);
        tb->accesstime = 0;
        tb->lockers = 0;
-#if defined(AFS_USEBUFFERS)
-       if ((i & (NPB - 1)) == 0)
-           tb->bufp = tub;
-       else
-           tb->bufp = 0;
        tb->data = &BufferData[AFS_BUFFER_PAGESIZE * (i & (NPB - 1))];
-#else
-       tb->data = &BufferData[AFS_BUFFER_PAGESIZE * i];
-#endif
        tb->hashIndex = 0;
        tb->dirty = 0;
        AFS_RWLOCK_INIT(&tb->lock, "buffer lock");
@@ -147,59 +147,94 @@ DInit(int abuffers)
     return;
 }
 
-void *
-DRead(register struct dcache *adc, register int page)
+/*!
+ * Read and return the requested directory page.
+ *
+ * \param[in]   adc    pointer to directory dcache
+ * \param[in]  page    number of the desired directory page
+ * \param[out] entry   buffer to return requested page
+ * \param[out] physerr (optional) pointer to return errno, if any
+ *
+ * \retval 0       success
+ * \retval non-zero invalid directory or internal IO error;
+ *                 if physerr is supplied by caller, it will be set:
+ *                     0       logical error
+ *                     errno   physical error
+ */
+int
+DReadWithErrno(struct dcache *adc, int page, struct DirBuffer *entry, int *physerr)
 {
     /* Read a page from the disk. */
-    register struct buffer *tb, *tb2;
+    struct buffer *tb, *tb2;
     struct osi_file *tfile;
     int code;
 
     AFS_STATCNT(DRead);
-    MObtainWriteLock(&afs_bufferLock, 256);
+
+    if (physerr != NULL)
+       *physerr = 0;
+
+    memset(entry, 0, sizeof(struct DirBuffer));
+
+    if (adc->f.chunk == 0 && adc->f.chunkBytes == 0) {
+        /* The directory blob is empty, apparently. This is not a valid dir
+         * blob, so throw an error. */
+        return EIO;
+    }
+    if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
+        return ENOENT; /* past the end */
+    }
+
+    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 
+     * 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. 
+     * macros.
      */
     if ((tb = phTable[pHash(adc->index, page)])) {
        if (bufmatch(tb)) {
-           MObtainWriteLock(&tb->lock, 257);
-           ReleaseWriteLock(&afs_bufferLock);
+           ObtainWriteLock(&tb->lock, 257);
            tb->lockers++;
+           ReleaseWriteLock(&afs_bufferLock);
            tb->accesstime = timecounter++;
            AFS_STATS(afs_stats_cmperf.bufHits++);
-           MReleaseWriteLock(&tb->lock);
-           return tb->data;
+           ReleaseWriteLock(&tb->lock);
+           entry->buffer = tb;
+           entry->data = tb->data;
+           return 0;
        } else {
-           register struct buffer **bufhead;
+           struct buffer **bufhead;
            bufhead = &(phTable[pHash(adc->index, page)]);
            while ((tb2 = tb->hashNext)) {
                if (bufmatch(tb2)) {
                    buf_Front(bufhead, tb, tb2);
-                   MObtainWriteLock(&tb2->lock, 258);
-                   ReleaseWriteLock(&afs_bufferLock);
+                   ObtainWriteLock(&tb2->lock, 258);
                    tb2->lockers++;
+                   ReleaseWriteLock(&afs_bufferLock);
                    tb2->accesstime = timecounter++;
                    AFS_STATS(afs_stats_cmperf.bufHits++);
-                   MReleaseWriteLock(&tb2->lock);
-                   return tb2->data;
+                   ReleaseWriteLock(&tb2->lock);
+                   entry->buffer = tb2;
+                   entry->data = tb2->data;
+                   return 0;
                }
                if ((tb = tb2->hashNext)) {
                    if (bufmatch(tb)) {
                        buf_Front(bufhead, tb2, tb);
-                       MObtainWriteLock(&tb->lock, 259);
-                       ReleaseWriteLock(&afs_bufferLock);
+                       ObtainWriteLock(&tb->lock, 259);
                        tb->lockers++;
+                       ReleaseWriteLock(&afs_bufferLock);
                        tb->accesstime = timecounter++;
                        AFS_STATS(afs_stats_cmperf.bufHits++);
-                       MReleaseWriteLock(&tb->lock);
-                       return tb->data;
+                       ReleaseWriteLock(&tb->lock);
+                       entry->buffer = tb;
+                       entry->data = tb->data;
+                       return 0;
                    }
                } else
                    break;
@@ -211,47 +246,68 @@ DRead(register struct dcache *adc, register int page)
     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 
+     * 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) {
-       MReleaseWriteLock(&afs_bufferLock);
-       return NULL;
+       ReleaseWriteLock(&afs_bufferLock);
+       return EIO;
     }
-    MObtainWriteLock(&tb->lock, 260);
-    MReleaseWriteLock(&afs_bufferLock);
+    ObtainWriteLock(&tb->lock, 260);
     tb->lockers++;
-    if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
-       tb->fid = NULLIDX;
-       afs_reset_inode(&tb->inode);
-       tb->lockers--;
-       MReleaseWriteLock(&tb->lock);
-       return NULL;
-    }
+    ReleaseWriteLock(&afs_bufferLock);
     tfile = afs_CFileOpen(&adc->f.inode);
+    if (!tfile) {
+       code = EIO;
+       goto error;
+    }
     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--;
-       MReleaseWriteLock(&tb->lock);
-       return NULL;
+       if (code < 0 && physerr != NULL)
+          *physerr = -code;
+       code = EIO;
+       goto error;
     }
     /* Note that findslot sets the page field in the buffer equal to
      * what it is searching for. */
-    MReleaseWriteLock(&tb->lock);
-    return tb->data;
+    ReleaseWriteLock(&tb->lock);
+    entry->buffer = tb;
+    entry->data = tb->data;
+    return 0;
+
+ error:
+    tb->fid = NULLIDX;
+    afs_reset_inode(&tb->inode);
+    tb->lockers--;
+    ReleaseWriteLock(&tb->lock);
+    return code;
+}
+
+/*!
+ * Read and return the requested directory page.
+ *
+ * \param[in]   adc    pointer to directory dcache
+ * \param[in]  page    number of the desired directory page
+ * \param[out] entry   buffer to return requested page
+ *
+ * \retval 0       success
+ * \retval non-zero invalid directory or internal IO error;
+ */
+int
+DRead(struct dcache *adc, int page, struct DirBuffer *entry)
+{
+    return DReadWithErrno(adc, page, entry, NULL);
 }
 
 static void
-FixupBucket(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 */
     AFS_STATCNT(FixupBucket);
@@ -273,12 +329,12 @@ FixupBucket(register struct buffer *ap)
 
 /* lp is pointer to a fairly-old buffer */
 static struct buffer *
-afs_newslot(struct dcache *adc, afs_int32 apage, register struct buffer *lp)
+afs_newslot(struct dcache *adc, afs_int32 apage, struct buffer *lp)
 {
     /* Find a usable buffer slot */
-    register afs_int32 i;
-    afs_int32 lt;
-    register struct buffer *tp;
+    afs_int32 i;
+    afs_int32 lt = 0;
+    struct buffer *tp;
     struct osi_file *tfile;
 
     AFS_STATCNT(afs_newslot);
@@ -291,8 +347,7 @@ afs_newslot(struct dcache *adc, afs_int32 apage, register struct buffer *lp)
     if (lp && (lp->lockers == 0)) {
        lt = lp->accesstime;
     } else {
-       lp = 0;
-       lt = BUF_TIME_MAX;
+       lp = NULL;
     }
 
     /* timecounter might have wrapped, if machine is very very busy
@@ -322,7 +377,7 @@ afs_newslot(struct dcache *adc, afs_int32 apage, register struct buffer *lp)
        tp = Buffers;
        for (i = 0; i < nbuffers; i++, tp++) {
            if (tp->lockers == 0) {
-               if (tp->accesstime < lt) {
+               if (!lp || tp->accesstime < lt) {
                    lp = tp;
                    lt = tp->accesstime;
                }
@@ -331,17 +386,40 @@ afs_newslot(struct dcache *adc, afs_int32 apage, register struct buffer *lp)
     }
 
     if (lp == 0) {
-       /* There are no unlocked buffers -- this used to panic, but that
-        * seems extreme.  To the best of my knowledge, all the callers
-        * of DRead are prepared to handle a zero return.  Some of them
-        * just panic directly, but not all of them. */
-       afs_warn("all buffers locked");
-       return 0;
+       /* No unlocked buffers. If still possible, allocate a new increment */
+       if (nbuffers + NPB > afs_max_buffers) {
+           /* There are no unlocked buffers -- this used to panic, but that
+            * seems extreme.  To the best of my knowledge, all the callers
+            * of DRead are prepared to handle a zero return.  Some of them
+            * just panic directly, but not all of them. */
+           afs_warn("afs: all buffers locked\n");
+           return 0;
+       }
+
+       BufferData = afs_osi_Alloc(AFS_BUFFER_PAGESIZE * NPB);
+       osi_Assert(BufferData != NULL);
+       for (i = 0; i< NPB; i++) {
+           /* Fill in each buffer with an empty indication. */
+           tp = &Buffers[i + nbuffers];
+           tp->fid = NULLIDX;
+           afs_reset_inode(&tp->inode);
+           tp->accesstime = 0;
+           tp->lockers = 0;
+           tp->data = &BufferData[AFS_BUFFER_PAGESIZE * i];
+           tp->hashIndex = 0;
+           tp->dirty = 0;
+           AFS_RWLOCK_INIT(&tp->lock, "buffer lock");
+       }
+       lp = &Buffers[nbuffers];
+       nbuffers += NPB;
     }
 
     if (lp->dirty) {
        /* see DFlush for rationale for not getting and locking the dcache */
         tfile = afs_CFileOpen(&lp->inode);
+       if (!tfile)
+           return NULL;    /* Callers will flag as EIO */
+
        afs_CFileWrite(tfile, lp->page * AFS_BUFFER_PAGESIZE, lp->data,
                       AFS_BUFFER_PAGESIZE);
        lp->dirty = 0;
@@ -349,6 +427,8 @@ afs_newslot(struct dcache *adc, afs_int32 apage, register struct buffer *lp)
        AFS_STATS(afs_stats_cmperf.bufFlushDirty++);
     }
 
+    /* Zero out the data so we don't leak something we shouldn't. */
+    memset(lp->data, 0, AFS_BUFFER_PAGESIZE);
     /* Now fill in the header. */
     lp->fid = adc->index;
     afs_copy_inode(&lp->inode, &adc->f.inode);
@@ -360,81 +440,42 @@ afs_newslot(struct dcache *adc, afs_int32 apage, register 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. */
-    register struct buffer *bp = (struct buffer *)loc;
-    register int index;
-#if defined(AFS_USEBUFFERS)
-    register struct buffer *tp;
-#endif
+    struct buffer *tp;
 
     AFS_STATCNT(DRelease);
-    if (!bp)
+
+    tp = entry->buffer;
+    if (tp == NULL)
        return;
-#if defined(AFS_USEBUFFERS)
-    /* look for buffer by scanning Unix buffers for appropriate address */
-    tp = Buffers;
-    for (index = 0; index < nbuffers; index += NPB, tp += NPB) {
-       if ((afs_int32) bp >= (afs_int32) tp->data
-           && (afs_int32) bp <
-           (afs_int32) tp->data + AFS_BUFFER_PAGESIZE * NPB) {
-           /* we found the right range */
-           index += ((afs_int32) bp - (afs_int32) tp->data) >> LOGPS;
-           break;
-       }
-    }
-#else
-    index = (((char *)bp) - ((char *)BufferData)) >> LOGPS;
-#endif
-    bp = &(Buffers[index]);
-    MObtainWriteLock(&bp->lock, 261);
-    bp->lockers--;
+
+    ObtainWriteLock(&tp->lock, 261);
+    tp->lockers--;
     if (flag)
-       bp->dirty = 1;
-    MReleaseWriteLock(&bp->lock);
+       tp->dirty = 1;
+    ReleaseWriteLock(&tp->lock);
 }
 
 int
-DVOffset(register void *ap)
+DVOffset(struct DirBuffer *entry)
 {
-    /* Return the byte within a file represented by a buffer pointer. */
-    register struct buffer *bp;
-    register int index;
-#if defined(AFS_USEBUFFERS)
-    register struct buffer *tp;
-#endif
+    struct buffer *bp;
+
     AFS_STATCNT(DVOffset);
-    bp = ap;
-#if defined(AFS_USEBUFFERS)
-    /* look for buffer by scanning Unix buffers for appropriate address */
-    tp = Buffers;
-    for (index = 0; index < nbuffers; index += NPB, tp += NPB) {
-       if ((afs_int32) bp >= (afs_int32) tp->data
-           && (afs_int32) bp <
-           (afs_int32) tp->data + AFS_BUFFER_PAGESIZE * NPB) {
-           /* we found the right range */
-           index += ((afs_int32) bp - (afs_int32) tp->data) >> LOGPS;
-           break;
-       }
-    }
-#else
-    index = (((char *)bp) - ((char *)BufferData)) >> LOGPS;
-#endif
-    if (index < 0 || index >= nbuffers)
-       return -1;
-    bp = &(Buffers[index]);
-    return AFS_BUFFER_PAGESIZE * bp->page + (int)(((char *)ap) - bp->data);
+
+    bp = entry->buffer;
+    return AFS_BUFFER_PAGESIZE * bp->page 
+           + (char *)entry->data - (char *)bp->data;
 }
 
-/*! 
+/*!
  * Zap one dcache entry: destroy one FID's buffers.
  *
  * 1/1/91 - I've modified the hash function to take the page as well
  * as the *fid, so that lookup will be a bit faster.  That presents some
  * difficulties for Zap, which now has to have some knowledge of the nature
- * of the hash function.  Oh well.  This should use the list traversal 
+ * of the hash function.  Oh well.  This should use the list traversal
  * method of DRead...
  *
  * \param adc The dcache entry to be zapped.
@@ -442,30 +483,32 @@ DVOffset(register void *ap)
 void
 DZap(struct dcache *adc)
 {
-    register int i;
+    int i;
     /* Destroy all buffers pertaining to a particular fid. */
-    register struct buffer *tb;
+    struct buffer *tb;
 
     AFS_STATCNT(DZap);
-    MObtainReadLock(&afs_bufferLock);
+    ObtainReadLock(&afs_bufferLock);
 
     for (i = 0; i <= PHPAGEMASK; i++)
        for (tb = phTable[pHash(adc->index, i)]; tb; tb = tb->hashNext)
            if (tb->fid == adc->index) {
-               MObtainWriteLock(&tb->lock, 262);
+               ObtainWriteLock(&tb->lock, 262);
                tb->fid = NULLIDX;
                afs_reset_inode(&tb->inode);
                tb->dirty = 0;
-               MReleaseWriteLock(&tb->lock);
+               ReleaseWriteLock(&tb->lock);
            }
-    MReleaseReadLock(&afs_bufferLock);
+    ReleaseReadLock(&afs_bufferLock);
 }
 
 static void
-DFlushBuffer(struct buffer *ab) {
+DFlushBuffer(struct buffer *ab)
+{
     struct osi_file *tfile;
-    
+
     tfile = afs_CFileOpen(&ab->inode);
+    osi_Assert(tfile);
     afs_CFileWrite(tfile, ab->page * AFS_BUFFER_PAGESIZE,
                   ab->data, AFS_BUFFER_PAGESIZE);
     ab->dirty = 0;     /* Clear the dirty flag */
@@ -473,7 +516,7 @@ DFlushBuffer(struct buffer *ab) {
 }
 
 void
-DFlushDCache(struct dcache *adc) 
+DFlushDCache(struct dcache *adc)
 {
     int i;
     struct buffer *tb;
@@ -497,26 +540,26 @@ DFlushDCache(struct dcache *adc)
     ReleaseReadLock(&afs_bufferLock);
 }
 
-void
+int
 DFlush(void)
 {
     /* Flush all the modified buffers. */
-    register int i;
-    register struct buffer *tb;
+    int i;
+    struct buffer *tb;
 
     AFS_STATCNT(DFlush);
     tb = Buffers;
-    MObtainReadLock(&afs_bufferLock);
+    ObtainReadLock(&afs_bufferLock);
     for (i = 0; i < nbuffers; i++, tb++) {
        if (tb->dirty) {
-           MObtainWriteLock(&tb->lock, 263);
+           ObtainWriteLock(&tb->lock, 263);
            tb->lockers++;
-           MReleaseReadLock(&afs_bufferLock);
+           ReleaseReadLock(&afs_bufferLock);
            if (tb->dirty) {
                /* it seems safe to do this I/O without having the dcache
                 * locked, since the only things that will update the data in
                 * a directory are the buffer package, which holds the relevant
-                * tb->lock while doing the write, or afs_GetDCache, which 
+                * tb->lock while doing the write, or afs_GetDCache, which
                 * DZap's the directory while holding the dcache lock.
                 * It is not possible to lock the dcache or even call
                 * afs_GetDSlot to map the index to the dcache since the dir
@@ -527,23 +570,27 @@ DFlush(void)
                DFlushBuffer(tb);
            }
            tb->lockers--;
-           MReleaseWriteLock(&tb->lock);
-           MObtainReadLock(&afs_bufferLock);
+           ReleaseWriteLock(&tb->lock);
+           ObtainReadLock(&afs_bufferLock);
        }
     }
-    MReleaseReadLock(&afs_bufferLock);
+    ReleaseReadLock(&afs_bufferLock);
+
+    return 0;
 }
 
-void *
-DNew(register struct dcache *adc, register 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. */
-    register struct buffer *tb;
+    /* Same as read, only do *not* even try to read the page, since it
+     * probably doesn't exist. */
+    struct buffer *tb;
     AFS_STATCNT(DNew);
-    MObtainWriteLock(&afs_bufferLock, 264);
+
+    ObtainWriteLock(&afs_bufferLock, 264);
     if ((tb = afs_newslot(adc, page, NULL)) == 0) {
-       MReleaseWriteLock(&afs_bufferLock);
-       return 0;
+       ReleaseWriteLock(&afs_bufferLock);
+       return EIO;
     }
     /* extend the chunk, if needed */
     /* Do it now, not in DFlush or afs_newslot when the data is written out,
@@ -552,48 +599,41 @@ DNew(register struct dcache *adc, register int page)
      * DFlush due to lock hierarchy issues */
     if ((page + 1) * AFS_BUFFER_PAGESIZE > adc->f.chunkBytes) {
        afs_AdjustSize(adc, (page + 1) * AFS_BUFFER_PAGESIZE);
-       afs_WriteDCache(adc, 1);
+       osi_Assert(afs_WriteDCache(adc, 1) == 0);
     }
-    MObtainWriteLock(&tb->lock, 265);
-    MReleaseWriteLock(&afs_bufferLock);
+    ObtainWriteLock(&tb->lock, 265);
     tb->lockers++;
-    MReleaseWriteLock(&tb->lock);
-    return tb->data;
+    ReleaseWriteLock(&afs_bufferLock);
+    ReleaseWriteLock(&tb->lock);
+    entry->buffer = tb;
+    entry->data = tb->data;
+
+    return 0;
 }
 
 void
 shutdown_bufferpackage(void)
 {
-#if defined(AFS_USEBUFFERS)
-    register struct buffer *tp;
-#endif
+    struct buffer *tp;
     int i;
 
     AFS_STATCNT(shutdown_bufferpackage);
     /* Free all allocated Buffers and associated buffer pages */
     DFlush();
+
+    dinit_flag = 0;
+    tp = Buffers;
+    for (i = 0; i < nbuffers; i += NPB, tp += NPB) {
+       afs_osi_Free(tp->data, NPB * AFS_BUFFER_PAGESIZE);
+    }
+    afs_osi_Free(Buffers, nbuffers * sizeof(struct buffer));
+    Buffers = NULL;
+    nbuffers = 0;
+    timecounter = 1;
+    for (i = 0; i < PHSIZE; i++)
+       phTable[i] = NULL;
+
     if (afs_cold_shutdown) {
-       dinit_flag = 0;
-#if !defined(AFS_USEBUFFERS)
-       afs_osi_Free(BufferData, nbuffers * AFS_BUFFER_PAGESIZE);
-#else
-       tp = Buffers;
-       for (i = 0; i < nbuffers; i += NPB, tp += NPB) {
-           /* The following check shouldn't be necessary and it will be removed soon */
-           if (!tp->bufp)
-               afs_warn
-                   ("shutdown_bufferpackage: bufp == 0!! Shouldn't happen\n");
-           else {
-               brelse(tp->bufp);
-               tp->bufp = 0;
-           }
-       }
-#endif
-       afs_osi_Free(Buffers, nbuffers * sizeof(struct buffer));
-       nbuffers = 0;
-       timecounter = 1;
-       for (i = 0; i < PHSIZE; i++)
-           phTable[i] = 0;
-       memset((char *)&afs_bufferLock, 0, sizeof(afs_lock_t));
+       memset(&afs_bufferLock, 0, sizeof(afs_lock_t));
     }
 }