tlen = avc->f.truncPos;
avc->f.truncPos = AFS_NOTRUNC;
avc->f.states &= ~CExtendedFile;
+ memset(&InStatus, 0, sizeof(InStatus));
do {
tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
AFS_STATCNT(afs_StoreAllSegments);
- hset(oldDV, avc->f.m.DataVersion);
- hset(newDV, avc->f.m.DataVersion);
hash = DVHash(&avc->f.fid);
foreign = (avc->f.states & CForeign);
dcList = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
/*printf("Net down in afs_StoreSegments\n");*/
return ENETDOWN;
}
+
+ /*
+ * Can't do this earlier because osi_VM_StoreAllSegments drops locks
+ * and can indirectly do some stores that increase the DV.
+ */
+ hset(oldDV, avc->f.m.DataVersion);
+ hset(newDV, avc->f.m.DataVersion);
+
ConvertWToSLock(&avc->lock);
/*
ObtainWriteLock(&afs_xdcache, 285);
for (j = 0, safety = 0, index = afs_dvhashTbl[hash];
- index != NULLIDX && safety < afs_cacheFiles + 2;) {
+ index != NULLIDX && safety < afs_cacheFiles + 2;
+ index = afs_dvnextTbl[index]) {
if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
tdc = afs_GetValidDSlot(index);
- if (!tdc) osi_Panic("afs_StoreAllSegments tdc dv");
+ if (!tdc) {
+ /* This is okay; since manipulating the dcaches at this
+ * point is best-effort. We only get a dcache here to
+ * increment the dv and turn off DWriting. If we were
+ * supposed to do that for a dcache, but could not
+ * due to an I/O error, it just means the dv won't
+ * be updated so we don't be able to use that cached
+ * chunk in the future. That's inefficient, but not
+ * an error. */
+ continue;
+ }
ReleaseReadLock(&tdc->tlock);
if (!FidCmp(&tdc->f.fid, &avc->f.fid)
afs_PutDCache(tdc);
}
}
-
- index = afs_dvnextTbl[index];
}
ReleaseWriteLock(&afs_xdcache);
for (index = afs_dvhashTbl[hash]; index != NULLIDX;) {
if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
tdc = afs_GetValidDSlot(index);
- if (!tdc) osi_Panic("afs_InvalidateAllSegments tdc count");
+ if (!tdc) {
+ /* In the case of fatal errors during stores, we MUST
+ * invalidate all of the relevant chunks. Otherwise, the chunks
+ * will be left with the 'new' data that was never successfully
+ * written to the server, but the DV in the dcache is still the
+ * old DV. So, we may indefinitely serve data to applications
+ * that is not actually in the file on the fileserver. If we
+ * cannot afs_GetValidDSlot the appropriate entries, currently
+ * there is no way to ensure the dcache is invalidated. So for
+ * now, to avoid risking serving bad data from the cache, panic
+ * instead. */
+ osi_Panic("afs_InvalidateAllSegments tdc count");
+ }
ReleaseReadLock(&tdc->tlock);
if (!FidCmp(&tdc->f.fid, &avc->f.fid))
dcListMax++;
for (index = afs_dvhashTbl[hash]; index != NULLIDX;) {
if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
tdc = afs_GetValidDSlot(index);
- if (!tdc) osi_Panic("afs_InvalidateAllSegments tdc store");
+ if (!tdc) {
+ /* We cannot proceed after getting this error; we risk serving
+ * incorrect data to applications. So panic instead. See the
+ * above comment next to the previous afs_GetValidDSlot call
+ * for details. */
+ osi_Panic("afs_InvalidateAllSegments tdc store");
+ }
ReleaseReadLock(&tdc->tlock);
if (!FidCmp(&tdc->f.fid, &avc->f.fid)) {
/* same file? we'll zap it */
afs_size_t newSize;
int dcCount, dcPos;
- struct dcache **tdcArray;
+ struct dcache **tdcArray = NULL;
AFS_STATCNT(afs_TruncateAllSegments);
avc->f.m.Date = osi_Time();
tdcArray = osi_Alloc(dcCount * sizeof(struct dcache *));
dcPos = 0;
- for (index = afs_dvhashTbl[code]; index != NULLIDX;) {
+ for (index = afs_dvhashTbl[code]; index != NULLIDX; index = afs_dvnextTbl[index]) {
if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
tdc = afs_GetValidDSlot(index);
- if (!tdc) osi_Panic("afs_TruncateAllSegments tdc");
+ if (!tdc) {
+ /* make sure we put back all of the tdcArray members before
+ * bailing out */
+ /* remember, the last valid tdc is at dcPos-1, so start at
+ * dcPos-1, not at dcPos itself. */
+ for (dcPos = dcPos - 1; dcPos >= 0; dcPos--) {
+ tdc = tdcArray[dcPos];
+ afs_PutDCache(tdc);
+ }
+ code = EIO;
+ goto done;
+ }
ReleaseReadLock(&tdc->tlock);
if (!FidCmp(&tdc->f.fid, &avc->f.fid)) {
/* same file, and modified, we'll store it back */
afs_PutDCache(tdc);
}
}
- index = afs_dvnextTbl[index];
}
ReleaseWriteLock(&afs_xdcache);
afs_PutDCache(tdc);
}
- osi_Free(tdcArray, dcCount * sizeof(struct dcache *));
-
code = 0;
done:
+ if (tdcArray) {
+ osi_Free(tdcArray, dcCount * sizeof(struct dcache *));
+ }
#if (defined(AFS_SUN5_ENV))
ObtainWriteLock(&avc->vlock, 547);
if (--avc->activeV == 0 && (avc->vstates & VRevokeWait)) {