afs: Set DWriting when truncating a dcache entry
authorAndrew Deason <adeason@sinenomine.net>
Thu, 22 Mar 2012 15:42:38 +0000 (10:42 -0500)
committerDerrick Brashear <shadow@dementix.org>
Mon, 26 Mar 2012 18:20:30 +0000 (11:20 -0700)
When we truncate a file, we truncate the contents of the relevant
dcache entry chunks, and prevent future FetchData operations from
fetching data beyond the truncation offset. If we never write anything
to that chunk, we never set DWriting, and so on disk it looks like
that dcache entry has valid data for the specified DV. However, since
the data is truncated, this is not true.

If a process holds a file open, truncates it without writing to it,
and then the client crashes (or we have trouble contacting the
fileserver when we close the file), the dcache entry will appear valid
on disk. So the next time we read the dcache entry, we will use the
incorrect cache contents as if they were accurate for the specified
DV.

To avoid this, set DWriting when we truncate a chunk. Normally we only
clear DWriting when we actually send data to the fileserver, so to
clear DWriting in this case, add an additional line to clear it in
afs_StoreAllSegments, after the StoreMini has completed.

Change-Id: Ifc3bfc21712ab37b1f2865ce59fa45bf03811dd8
Reviewed-on: http://gerrit.openafs.org/6937
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementix.org>

src/afs/afs_segments.c

index 47058f9..192a3d4 100644 (file)
@@ -418,6 +418,9 @@ afs_StoreAllSegments(struct vcache *avc, struct vrequest *areq,
                        UpgradeSToWLock(&tdc->lock, 678);
                        hset(tdc->f.versionNo, avc->f.m.DataVersion);
                        tdc->dflags |= DFEntryMod;
+                       /* DWriting may not have gotten cleared above, if all
+                        * we did was a StoreMini */
+                       tdc->f.states &= ~DWriting;
                        ConvertWToSLock(&tdc->lock);
                    }
                }
@@ -775,6 +778,7 @@ afs_TruncateAllSegments(struct vcache *avc, afs_size_t alen,
        ObtainSharedLock(&tdc->lock, 672);
        if (newSize < tdc->f.chunkBytes && newSize < MAX_AFS_UINT32) {
            UpgradeSToWLock(&tdc->lock, 673);
+           tdc->f.states |= DWriting;
            tfile = afs_CFileOpen(&tdc->f.inode);
            afs_CFileTruncate(tfile, (afs_int32)newSize);
            afs_CFileClose(tfile);