Windows: Correct buf_Write data loss errors
authorJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 20 Aug 2009 21:22:08 +0000 (17:22 -0400)
committerJeffrey Altman <jaltman@openafs.org>
Thu, 20 Aug 2009 22:40:29 +0000 (15:40 -0700)
buf_Write has two errors in it.  First, if offset at which the
write is supposed to begin does not align with the cm_data.blockSize,
then (offset %blockSize) octets at the end of the write will fail
to be written to the file server.   Second, if there is no knowledge
of the file server's ability to handle RXAFS_StoreData64 calls
and the file server does not support StoreData64 calls, then the
first chunkSize of data will be written to the file server before
the RXGEN_OPCODE error is detected.  In this case a retry using
RXAFS_StoreData is performed but the values of 'nbytes' and 'qdp'
were not reset before the retry.  As a result, the first chunkSize
of data would fail to be written to the file server.

The second problem can reliably occur when connectivity between the
cache manager and the file server is interrupted due to firewall
port mapping closures.  Upon establishing a new rx connection, a
SRXAFSCB_InitCallBackState3 RPC will be issued by the file server
erasing any prior knowledge of the file server's ability to process
64-bit data operations.  If the first 64-bit operation is a
StoreData64, then data loss will occur.

LICENSE MIT

FIXES 125220
FIXES 108199

Reviewed-on: http://gerrit.openafs.org/332
Tested-by: Asanka Herath <asanka@secure-endpoints.com>
Reviewed-by: Asanka Herath <asanka@secure-endpoints.com>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>

src/WINNT/afsd/cm_dcache.c

index 680008f..fd82c6c 100644 (file)
@@ -55,6 +55,9 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
     long code, code1;
     cm_scache_t *scp = vscp;
     afs_int32 nbytes;
+#ifdef AFS_LARGEFILES
+    afs_int32 save_nbytes;
+#endif
     long temp;
     AFSFetchStatus outStatus;
     AFSStoreStatus inStatus;
@@ -148,6 +151,9 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
     lock_ReleaseWrite(&scp->rw);
 
     /* now we're ready to do the store operation */
+#ifdef AFS_LARGEFILES
+    save_nbytes = nbytes;
+#endif
     do {
         code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
         if (code) 
@@ -207,16 +213,20 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
             /* write the data from the the list of buffers */
             qdp = NULL;
             while(nbytes > 0) {
-                if (qdp == NULL)
+                afs_uint32 buf_offset;
+                if (qdp == NULL) {
                     qdp = biod.bufListEndp;
-                else
+                    buf_offset = offsetp->LowPart % cm_data.buf_blockSize;
+                } else {
                     qdp = (osi_queueData_t *) osi_QPrev(&qdp->q);
+                    buf_offset = 0;
+                }
                 osi_assertx(qdp != NULL, "null osi_queueData_t");
                 bufp = osi_GetQData(qdp);
-                bufferp = bufp->datap;
+                bufferp = bufp->datap + buf_offset;
                 wbytes = nbytes;
-                if (wbytes > cm_data.buf_blockSize) 
-                    wbytes = cm_data.buf_blockSize;
+                if (wbytes > cm_data.buf_blockSize - buf_offset)
+                    wbytes = cm_data.buf_blockSize - buf_offset;
 
                 /* write out wbytes of data from bufferp */
                 temp = rx_Write(rxcallp, bufferp, wbytes);
@@ -252,6 +262,8 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
 #ifdef AFS_LARGEFILES
         if ((code == RXGEN_OPCODE || code1 == RXGEN_OPCODE) && SERVERHAS64BIT(connp)) {
             SET_SERVERHASNO64BIT(connp);
+            qdp = NULL;
+            nbytes = save_nbytes;
             goto retry;
         }
 #endif