From db717c69dad1518043cb317aedb6d082476386f0 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 20 Aug 2009 17:22:08 -0400 Subject: [PATCH] Windows: Correct buf_Write data loss errors 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 Reviewed-by: Asanka Herath Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- src/WINNT/afsd/cm_dcache.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/WINNT/afsd/cm_dcache.c b/src/WINNT/afsd/cm_dcache.c index 680008fc9..fd82c6ca4 100644 --- a/src/WINNT/afsd/cm_dcache.c +++ b/src/WINNT/afsd/cm_dcache.c @@ -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 -- 2.39.5