afs: Throw EIO in DRead on empty dir blob 29/13429/2
authorAndrew Deason <adeason@sinenomine.net>
Thu, 17 Jan 2019 05:46:34 +0000 (23:46 -0600)
committerBenjamin Kaduk <kaduk@mit.edu>
Mon, 4 Feb 2019 04:46:33 +0000 (23:46 -0500)
DRead currently returns ENOENT if we try to read a page beyond the end
of the given dir blob. We do this to indicate we've hit EOF, but we do
this even if the dir blob is completely empty (which is not a valid
dir blob).

If a dir blob in the cache is truncated due to cache corruption
issues, that means we'll indicate a normal EOF condition in that
directory for most code paths. If someone is trying to list the
directory's entries, for instance, we'll just return that there are no
entries in the dir, even though the dir itself is just invalid.

To avoid this for at least some cases, return an EIO error instead if
the dir blob is completely empty.

Change-Id: I8544e125ad12632523d7c514fe63ff9d87e1cd8f
Reviewed-on: https://gerrit.openafs.org/13429
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/afs/afs_buffer.c

index 8a1141d..cb99d07 100644 (file)
@@ -231,12 +231,20 @@ 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) {
+    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;
+    } else if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
+        code = ENOENT; /* past the end */
+    }
+    if (code) {
        tb->fid = NULLIDX;
        afs_reset_inode(&tb->inode);
        tb->lockers--;
        ReleaseWriteLock(&tb->lock);
-       return ENOENT; /* past the end */
+       return code;
     }
     tfile = afs_CFileOpen(&adc->f.inode);
     osi_Assert(tfile);