afs: Avoid panics on failed return from afs_CFileOpen
[openafs.git] / src / afs / afs_buffer.c
index 52243d6..1f2a470 100644 (file)
@@ -14,7 +14,9 @@
 #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)
@@ -229,24 +231,29 @@ DRead(struct dcache *adc, int page, struct DirBuffer *entry)
     ObtainWriteLock(&tb->lock, 260);
     tb->lockers++;
     ReleaseWriteLock(&afs_bufferLock);
-    if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
-       tb->fid = NULLIDX;
-       afs_reset_inode(&tb->inode);
-       tb->lockers--;
-       ReleaseWriteLock(&tb->lock);
-       return EIO;
+    code = 0;
+    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. */
+        code = EIO;
+       goto error;
+    } else if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
+        code = ENOENT; /* past the end */
+       goto error;
     }
+
     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--;
-       ReleaseWriteLock(&tb->lock);
-       return EIO;
+       code = EIO;
+       goto error;
     }
     /* Note that findslot sets the page field in the buffer equal to
      * what it is searching for. */
@@ -254,6 +261,13 @@ DRead(struct dcache *adc, int page, struct DirBuffer *entry)
     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;
 }
 
 static void
@@ -370,6 +384,9 @@ afs_newslot(struct dcache *adc, afs_int32 apage, struct buffer *lp)
     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;
@@ -377,6 +394,8 @@ afs_newslot(struct dcache *adc, afs_int32 apage, 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);
@@ -457,6 +476,7 @@ 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 */
@@ -547,7 +567,7 @@ DNew(struct dcache *adc, int page, struct DirBuffer *entry)
      * 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);
     }
     ObtainWriteLock(&tb->lock, 265);
     tb->lockers++;
@@ -568,17 +588,20 @@ shutdown_bufferpackage(void)
     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;
-       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));
-       nbuffers = 0;
-       timecounter = 1;
-       for (i = 0; i < PHSIZE; i++)
-           phTable[i] = 0;
        memset(&afs_bufferLock, 0, sizeof(afs_lock_t));
     }
 }