]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
DEVEL15-windows-vnovnode-while-file-in-use-20070918
authorJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 18 Sep 2007 17:59:23 +0000 (17:59 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 18 Sep 2007 17:59:23 +0000 (17:59 +0000)
Discovered another case where VNOVNODE errors were not being handled.
If there are dirty buffers and a VNOVNODE error is received while
writing the buffer, the buffer would be left in the dirty buffers queue.
This caused a couple problems:
(1) any attempt to flush the file, volume, or cache would fail because
    there were unflushed dirty buffers that could not be flushed.
(2) shutdown of the service would hang because the buffers could not
    be flushed.

In addition, while a VNOVNODE error would result in the cm_scache_t
being marked CM_SCACHEFLAG_DELETED, this state was not being checked
at the SMB layer.  As a result, if a smb_fid_t was allocated and it
referenced the deleted cm_scache_t, the SMB operations would continue
to be processed and report success even if the actual file or directory
no longer existed.

We now clear the dirty state on buffers which cannot be written due to
VNOVNODE errors.  We also check the cm_scache_t for deletion prior to
use whenever a smb_fid_t is looked up.  If the cm_scache_t is deleted,
the smb_fid_t is closed and the error CM_ERROR_NOSUCHFILE is returned
for files or CM_ERROR_NOSUCHPATH for directories.

(cherry picked from commit b8abf04a45a82cc880d2ad59d3bbf2217fa08c11)

src/WINNT/afsd/cm_buf.c
src/WINNT/afsd/cm_dcache.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c

index d1d634885403e65b019f0a134656b5736517f88f..84c216c0cdd6ecde2678b920869325a9dca7f097 100644 (file)
@@ -622,12 +622,12 @@ long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
         * because we aren't going to be able to write this data to the file
         * server.
         */
-       if (code == CM_ERROR_NOSUCHFILE){
+       if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BADFD){
            bp->flags &= ~CM_BUF_DIRTY;
            bp->flags |= CM_BUF_ERROR;
             bp->dirty_offset = 0;
             bp->dirty_length = 0;
-           bp->error = CM_ERROR_NOSUCHFILE;
+           bp->error = code;
            bp->dataVersion = -1; /* bad */
            bp->dirtyCounter++;
        }
@@ -1490,9 +1490,23 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
             lock_ReleaseMutex(&bp->mx);
 
             code = (*cm_buf_opsp->Stabilizep)(scp, userp, reqp);
-            if (code) 
+            if (code && code != CM_ERROR_BADFD
                 goto skip;
 
+           /* if the scp's FID is bad its because we received VNOVNODE 
+            * when attempting to FetchStatus before the write.  This
+            * page therefore contains data that can no longer be stored.
+            */
+           lock_ObtainMutex(&bp->mx);
+           bp->flags &= ~CM_BUF_DIRTY;
+           bp->flags |= CM_BUF_ERROR;
+           bp->error = code;
+            bp->dirty_offset = 0;
+            bp->dirty_length = 0;
+            bp->dataVersion = -1;      /* known bad */
+            bp->dirtyCounter++;
+           lock_ReleaseMutex(&bp->mx);
+
             lock_ObtainWrite(&buf_globalLock);
             /* actually, we only know that buffer is clean if ref
              * count is 1, since we don't have buffer itself locked.
@@ -1509,7 +1523,8 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
             }
             lock_ReleaseWrite(&buf_globalLock);
 
-            (*cm_buf_opsp->Unstabilizep)(scp, userp);
+           if (code != CM_ERROR_BADFD)
+               (*cm_buf_opsp->Unstabilizep)(scp, userp);
         }
 
       skip:
index 0d9bbc65da042ac6d91f1c2550c39c001f04332f..d551bd557b2600446568b03ffb9ed222a8917478 100644 (file)
@@ -84,13 +84,13 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
      */
 
     lock_ObtainMutex(&scp->mx);
-    cm_AFSFidFromFid(&tfid, &scp->fid);
-
     if (scp->flags & CM_SCACHEFLAG_DELETED) {
        lock_ReleaseMutex(&scp->mx);
        return CM_ERROR_NOSUCHFILE;
     }
 
+    cm_AFSFidFromFid(&tfid, &scp->fid);
+
     code = cm_SetupStoreBIOD(scp, offsetp, length, &biod, userp, reqp);
     if (code) {
         osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code);
index c529a72d56a702eafbf5e3f3693c53cba2f6d259..77f40de55b038c38338d3dbaf34c3b29ed3837e6 100644 (file)
@@ -2636,7 +2636,10 @@ void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op
         outp->res[1] = inSmbp->res[1];
         op->inCom = inSmbp->com;
     }
-    outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+    outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+    outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
 
     /* copy fields in generic packet area */
@@ -3140,6 +3143,13 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     if (!fidp)
         goto send1;
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        code = CM_ERROR_NOSUCHFILE;
+        goto send1a;
+    }
+
+
     pid = ((smb_t *) inp)->pid;
     {
         LARGE_INTEGER LOffset, LLength;
@@ -5947,6 +5957,12 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6705,6 +6721,12 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
         
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6828,6 +6850,12 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
     fd = smb_GetSMBParm(inp, 0);
     fidp = smb_FindFID(vcp, fd, 0);
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return;
+    }
+
     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
 
@@ -6947,6 +6975,12 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return CM_ERROR_BADFD;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     {
         unsigned pid;
         cm_key_t key;
@@ -7090,6 +7124,12 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
         return CM_ERROR_BADFD;
         
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -7497,10 +7537,15 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* try to find the file descriptor */
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
index fac34cf64779283f0e2c398264cb7565677b4fe3..0cdd503943cc9a443deebce6a3ab23773a5edbdd 100644 (file)
@@ -3206,6 +3206,13 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return 0;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
     infoLevel = p->parmsp[1];
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
         responseSize = sizeof(qfi.u.QFbasicInfo);
@@ -3334,6 +3341,13 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         return 0;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
     infoLevel = p->parmsp[1];
     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
@@ -5777,6 +5791,12 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
@@ -6034,6 +6054,12 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6111,6 +6137,12 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6197,6 +6229,12 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
         return CM_ERROR_BADFD;
         
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6334,6 +6372,12 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     pid = ((smb_t *) inp)->pid;
     key = cm_GenerateKey(vcp->vcID, pid, fd);
     {
@@ -6627,6 +6671,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             cm_ReleaseUser(userp);
             return CM_ERROR_INVAL;
         }       
+
+        if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+            free(realPathp);
+            cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, baseFidp, NULL, 0);
+            smb_ReleaseFID(baseFidp);
+            return CM_ERROR_NOSUCHPATH;
+        }
+
         baseDirp = baseFidp->scp;
         tidPathp = NULL;
     }
@@ -7419,8 +7472,17 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
            osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
             free(realPathp);
             cm_ReleaseUser(userp);
-            return CM_ERROR_INVAL;
+            return CM_ERROR_BADFD;
         }       
+
+        if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+            free(realPathp);
+            cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, baseFidp, NULL, 0);
+            smb_ReleaseFID(baseFidp);
+            return CM_ERROR_NOSUCHPATH;
+        }
+
         baseDirp = baseFidp->scp;
         tidPathp = NULL;
     }
@@ -8004,6 +8066,12 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
         return CM_ERROR_BADFD;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     /* Create a copy of the Directory Watch Packet to use when sending the
      * notification if in the future a matching change is detected.
      */
@@ -8245,10 +8313,13 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch = watch;
             watch = watch->nextp;
             continue;
-        }       
-        if (fidp->scp != dscp
-             || (filter & notifyFilter) == 0
-             || (!isDirectParent && !wtree)) {
+        }      
+
+        if (fidp->scp != dscp ||
+            fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
+            (filter & notifyFilter) == 0 ||
+            (!isDirectParent && !wtree)) 
+        {
             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
             smb_ReleaseFID(fidp);
             lastWatch = watch;
@@ -8301,7 +8372,10 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         lock_ReleaseMutex(&dscp->mx);
 
         /* Convert to response packet */
-        ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+        ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+        ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
         ((smb_t *) watch)->wct = 0;
 
         /* out parms */