windows-invalid-dir-handles-20041029
authorJeffrey Altman <jaltman@mit.edu>
Sat, 30 Oct 2004 00:38:53 +0000 (00:38 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Sat, 30 Oct 2004 00:38:53 +0000 (00:38 +0000)
 * Define new error CM_ERROR_TOO_MANY_SYMLINKS

 * Fix storage location for Freelance Mount Points broken in
   previous patch

 * Correct locking throughout the Directory Search code
   which was resulting in invalid handle errors being
   generated when objects were freed while they were still
   in use by the CIFS client

src/WINNT/afsd/cm.h
src/WINNT/afsd/cm_conn.c
src/WINNT/afsd/cm_freelance.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c

index b0cef02..423bdd3 100644 (file)
@@ -245,8 +245,9 @@ int RXAFS_Lookup (struct rx_connection *,
 #define CM_ERROR_BUFFERTOOSMALL                (CM_ERROR_BASE+38)
 #define CM_ERROR_RENAME_IDENTICAL      (CM_ERROR_BASE+39)
 #define CM_ERROR_ALLOFFLINE             (CM_ERROR_BASE+40)
-#define CM_ERROR_AMBIGUOUS_FILENAME (CM_ERROR_BASE+41)
-#define CM_ERROR_BADLOGONTYPE  (CM_ERROR_BASE+42)
-#define CM_ERROR_GSSCONTINUE    (CM_ERROR_BASE+43)
-#define CM_ERROR_TIDIPC         (CM_ERROR_BASE+44)
+#define CM_ERROR_AMBIGUOUS_FILENAME     (CM_ERROR_BASE+41)
+#define CM_ERROR_BADLOGONTYPE          (CM_ERROR_BASE+42)
+#define CM_ERROR_GSSCONTINUE            (CM_ERROR_BASE+43)
+#define CM_ERROR_TIDIPC                 (CM_ERROR_BASE+44)
+#define CM_ERROR_TOO_MANY_SYMLINKS      (CM_ERROR_BASE+45)
 #endif /*  __CM_H_ENV__ */
index 32e748a..4dbfb2c 100644 (file)
@@ -384,12 +384,12 @@ out:
 long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
        cm_req_t *reqp, cm_conn_t **connpp)
 {
-       long code;
-       cm_serverRef_t *tsrp;
+    long code;
+    cm_serverRef_t *tsrp;
     cm_server_t *tsp;
     long firstError = 0;
-       int someBusy = 0, someOffline = 0, allBusy = 1, allDown = 1;
-       long timeUsed, timeLeft, hardTimeLeft;
+    int someBusy = 0, someOffline = 0, allBusy = 1, allDown = 1;
+    long timeUsed, timeLeft, hardTimeLeft;
 #ifdef DJGPP
     struct timeval now;
 #endif /* DJGPP */        
@@ -397,17 +397,17 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
     *connpp = NULL;
 
 #ifndef DJGPP
-       timeUsed = (GetCurrentTime() - reqp->startTime) / 1000;
+    timeUsed = (GetCurrentTime() - reqp->startTime) / 1000;
 #else
     gettimeofday(&now, NULL);
     timeUsed = sub_time(now, reqp->startTime) / 1000;
 #endif
         
-       /* leave 5 seconds margin of safety */
-       timeLeft =  ConnDeadtimeout - timeUsed - 5;
-       hardTimeLeft = HardDeadtimeout - timeUsed - 5;
+    /* leave 5 seconds margin of safety */
+    timeLeft =  ConnDeadtimeout - timeUsed - 5;
+    hardTimeLeft = HardDeadtimeout - timeUsed - 5;
 
-       lock_ObtainWrite(&cm_serverLock);
+    lock_ObtainWrite(&cm_serverLock);
     for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
         tsp = tsrp->server;
         cm_GetServerNoLock(tsp);
@@ -419,7 +419,7 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
             else if (tsrp->status == offline)
                 someOffline = 1;
             else {
-                               allBusy = 0;
+                allBusy = 0;
                 code = cm_ConnByServer(tsp, usersp, connpp);
                 if (code == 0) {
                     cm_PutServer(tsp);
@@ -439,24 +439,24 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
                 if (firstError == 0) 
                     firstError = code;
             }
-               } 
+        } 
         lock_ObtainWrite(&cm_serverLock);
         cm_PutServerNoLock(tsp);
     }   
 
-       lock_ReleaseWrite(&cm_serverLock);
-       if (firstError == 0) {
+    lock_ReleaseWrite(&cm_serverLock);
+    if (firstError == 0) {
         if (serversp == NULL)
-                       firstError = CM_ERROR_NOSUCHVOLUME;
+            firstError = CM_ERROR_NOSUCHVOLUME;
         else if (allDown) 
-                       firstError = CM_ERROR_ALLOFFLINE;
-               else if (allBusy) 
-                       firstError = CM_ERROR_ALLBUSY;
-               else
-                       firstError = CM_ERROR_TIMEDOUT;
-       }
+            firstError = CM_ERROR_ALLOFFLINE;
+        else if (allBusy) 
+            firstError = CM_ERROR_ALLBUSY;
+        else
+            firstError = CM_ERROR_TIMEDOUT;
+    }
 
-       osi_Log1(afsd_logp, "cm_ConnByMServers returning %x", firstError);
+    osi_Log1(afsd_logp, "cm_ConnByMServers returning %x", firstError);
     return firstError;
 }
 
index e6b0a85..0894791 100644 (file)
@@ -776,7 +776,7 @@ long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw,
 
 #if !defined(DJGPP)
     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
-                      "SOFTWARE\\OpenAFS\\Client\\Freelance\\Symlinks",
+                      "SOFTWARE\\OpenAFS\\Client\\Freelance",
                       0,
                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
                       &hkFreelance) == ERROR_SUCCESS) {
index 1751144..dcb48f0 100644 (file)
@@ -787,7 +787,8 @@ long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
         }
     }
     /* locked, has callback, has valid data in buffer */
-    if ((tlen = scp->length.LowPart) > 1000) return CM_ERROR_TOOBIG;
+    if ((tlen = scp->length.LowPart) > 1000) 
+        return CM_ERROR_TOOBIG;
     if (tlen <= 0) {
         code = CM_ERROR_INVAL;
         goto done;
@@ -1104,10 +1105,10 @@ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
                 *outpScpp = scp;
                 return 0;
             }
-                       if (scp) {
-                               cm_ReleaseSCache(scp);
-                               scp = 0;
-                       }
+            if (scp) {
+                cm_ReleaseSCache(scp);
+                scp = 0;
+            }
         } else {
             return cm_LookupInternal(dscp, namep, flags, userp, reqp, outpScpp);
         }
@@ -1405,12 +1406,12 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                 if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
                     /* this is a symlink; assemble a new buffer */
                     lock_ReleaseMutex(&tscp->mx);
-                    if (symlinkCount++ >= 16) {
+                    if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
                         cm_ReleaseSCache(tscp);
                         cm_ReleaseSCache(dirScp);
                         if (psp) 
                             cm_FreeSpace(psp);
-                        return CM_ERROR_TOOBIG;
+                        return CM_ERROR_TOO_MANY_SYMLINKS;
                     }
                     if (tc == 0) 
                         restp = "";
@@ -1659,9 +1660,11 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
     bb.counter = 0;
     bb.bufOffset = *offsetp;
 
+       lock_ReleaseMutex(&dscp->mx);
     /* first, assemble the file IDs we need to stat */
     code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &bb, offsetp, userp,
                         reqp, NULL);
+       lock_ObtainMutex(&dscp->mx);
 
     /* if we failed, bail out early */
     if (code && code != CM_ERROR_STOPNOW) return;
@@ -1671,7 +1674,7 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
      * time.
      */
     filex = 0;
-    while(filex < bb.counter) {
+    while (filex < bb.counter) {
         filesThisCall = bb.counter - filex;
         if (filesThisCall > AFSCBMAX) filesThisCall = AFSCBMAX;
 
index 9f2a7a6..fc5a5e5 100644 (file)
@@ -154,4 +154,5 @@ extern void cm_CheckLocks();
 
 extern long cm_RetryLock(cm_file_lock_t *oldFileLock, int vcp_is_dead);
 
+#define MAX_SYMLINK_COUNT 16
 #endif /*  __CM_VNODEOPS_H_ENV__ */
index fb3e1ae..feb941e 100644 (file)
@@ -387,10 +387,21 @@ unsigned int smb_Attributes(cm_scache_t *scp)
 {
     unsigned int attrs;
 
-    if (scp->fileType == CM_SCACHETYPE_DIRECTORY
-         || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
+    if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+         scp->fileType == CM_SCACHETYPE_MOUNTPOINT) 
+    {
         attrs = SMB_ATTR_DIRECTORY;
-    else
+#ifdef SPECIAL_FOLDERS
+#ifdef AFS_FREELANCE_CLIENT
+        if ( cm_freelanceEnabled &&
+             scp->fid.cell==AFS_FAKE_ROOT_CELL_ID && 
+             scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
+             scp->fid.vnode==0x1 && scp->fid.unique==0x1) {
+            attrs |= SMB_ATTR_SYSTEM;          /* FILE_ATTRIBUTE_SYSTEM */
+        }
+#endif /* AFS_FREELANCE_CLIENT */
+#endif /* SPECIAL_FOLDERS */
+    } else
         attrs = 0;
 
     /*
@@ -1546,11 +1557,11 @@ int smb_FindShareCSCPolicy(char *shareName)
 /* find a dir search structure by cookie value, and return it held.
  * Must be called with smb_globalLock held.
  */
-smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
+smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
 {
     smb_dirSearch_t *dsp;
         
-    for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
+    for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
         if (dsp->cookie == cookie) {
             if (dsp != smb_firstDirSearchp) {
                 /* move to head of LRU queue, too, if we're not already there */
@@ -1562,7 +1573,9 @@ smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
                 if (!smb_lastDirSearchp)
                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
             }
+            lock_ObtainMutex(&dsp->mx);
             dsp->refCount++;
+            lock_ReleaseMutex(&dsp->mx);
             break;
         }
     }
@@ -1572,10 +1585,9 @@ smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
 {
     lock_ObtainWrite(&smb_globalLock);
-    dsp->flags |= SMB_DIRSEARCH_DELETE;
-    lock_ReleaseWrite(&smb_globalLock);
     lock_ObtainMutex(&dsp->mx);
-    if(dsp->scp != NULL) {
+    dsp->flags |= SMB_DIRSEARCH_DELETE;
+    if (dsp->scp != NULL) {
         lock_ObtainMutex(&dsp->scp->mx);
         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
@@ -1585,37 +1597,47 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
         lock_ReleaseMutex(&dsp->scp->mx);
     }  
     lock_ReleaseMutex(&dsp->mx);
+    lock_ReleaseWrite(&smb_globalLock);
 }               
 
-void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
+/* Must be called with the smb_globalLock held */
+void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
 {
     cm_scache_t *scp;
         
     scp = NULL;
 
-    lock_ObtainWrite(&smb_globalLock);
+    lock_ObtainMutex(&dsp->mx);
     osi_assert(dsp->refCount-- > 0);
     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
+        lock_ReleaseMutex(&dsp->mx);
         lock_FinalizeMutex(&dsp->mx);
         scp = dsp->scp;
         free(dsp);
+    } else {
+        lock_ReleaseMutex(&dsp->mx);
     }
-    lock_ReleaseWrite(&smb_globalLock);
-
     /* do this now to avoid spurious locking hierarchy creation */
     if (scp) cm_ReleaseSCache(scp);
 }       
 
+void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
+{
+    lock_ObtainWrite(&smb_globalLock);
+    smb_ReleaseDirSearchNoLock(dsp);
+    lock_ReleaseWrite(&smb_globalLock);
+}       
+
 /* find a dir search structure by cookie value, and return it held */
 smb_dirSearch_t *smb_FindDirSearch(long cookie)
 {
     smb_dirSearch_t *dsp;
 
     lock_ObtainWrite(&smb_globalLock);
-    dsp = smb_FindDirSearchNL(cookie);
+    dsp = smb_FindDirSearchNoLock(cookie);
     lock_ReleaseWrite(&smb_globalLock);
     return dsp;
 }
@@ -1650,15 +1672,14 @@ void smb_GCDirSearches(int isV3)
         }
 
         /* don't do more than this */
-        if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
+        if (victimCount >= SMB_DIRSEARCH_GCMAX) 
+            break;
     }
        
     /* now release them */
-    lock_ReleaseWrite(&smb_globalLock);
-    for(i = 0; i < victimCount; i++) {
-        smb_ReleaseDirSearch(victimsp[i]);
+    for (i = 0; i < victimCount; i++) {
+        smb_ReleaseDirSearchNoLock(victimsp[i]);
     }
-    lock_ObtainWrite(&smb_globalLock);
 }
 
 /* function for allocating a dir search entry.  We need these to remember enough context
@@ -1677,25 +1698,27 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
     counter = 0;
 
     /* what's the biggest ID allowed in this version of the protocol */
-    if (isV3) maxAllowed = 65535;
-    else maxAllowed = 255;
+    maxAllowed = isV3 ? 65535 : 255;
 
-    while(1) {
+    while (1) {
         /* twice so we have enough tries to find guys we GC after one pass;
          * 10 extra is just in case I mis-counted.
          */
-        if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
-                                                    __FILE__, __LINE__);
+        if (++counter > 2*maxAllowed+10) 
+            osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
+
         if (smb_dirSearchCounter > maxAllowed) {       
             smb_dirSearchCounter = 1;
-            smb_GCDirSearches(isV3);   /* GC some (drops global lock) */
+            smb_GCDirSearches(isV3);   /* GC some */
         }      
-        dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
+        dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
         if (dsp) {
             /* don't need to watch for refcount zero and deleted, since
             * we haven't dropped the global lock.
             */
+            lock_ObtainMutex(&dsp->mx);
             dsp->refCount--;
+            lock_ReleaseMutex(&dsp->mx);
             ++smb_dirSearchCounter;
             continue;
         }      
@@ -1703,7 +1726,8 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         dsp = malloc(sizeof(*dsp));
         memset(dsp, 0, sizeof(*dsp));
         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
-        if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
+        if (!smb_lastDirSearchp) 
+            smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
         dsp->cookie = smb_dirSearchCounter;
         ++smb_dirSearchCounter;
         dsp->refCount = 1;
@@ -2275,6 +2299,13 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_GSSCONTINUE) {
         NTStatus = 0xC0000016L; /* more processing required */
     }
+    else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
+#ifdef COMMENT
+        NTStatus = 0xC0000280L; /* reparse point not resolved */
+#else
+        NTStatus = 0xC0000022L; /* Access Denied */
+#endif
+    }
     else {
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
@@ -3402,7 +3433,6 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     else {
         spacep = inp->spacep;
         smb_StripLastComponent(spacep->data, NULL, pathp);
-        lock_ReleaseMutex(&dsp->mx);
         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
         if (code) {
             lock_ReleaseMutex(&dsp->mx);
@@ -3413,9 +3443,9 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         }
         code = cm_NameI(cm_rootSCachep, spacep->data,
                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
-        lock_ObtainMutex(&dsp->mx);
         if (code == 0) {
-            if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
+            if (dsp->scp != 0) 
+                cm_ReleaseSCache(dsp->scp);
             dsp->scp = scp;
             /* we need one hold for the entry we just stored into,
              * and one for our own processing.  When we're done with this
@@ -3520,13 +3550,14 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             lock_ObtainRead(&scp->bufCreateLock);
             code = buf_Get(scp, &thyper, &bufferp);
             lock_ReleaseRead(&scp->bufCreateLock);
+            lock_ObtainMutex(&dsp->mx);
 
             /* now, if we're doing a star match, do bulk fetching of all of 
              * the status info for files in the dir.
              */
             if (starPattern) {
-                smb_ApplyDirListPatches(&dirListPatchesp, userp,
-                                         &req);
+                smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
+                lock_ObtainMutex(&scp->mx);
                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
                      LargeIntegerGreaterThanOrEqualTo(thyper, 
                                                       scp->bulkStatProgress)) {
@@ -3539,11 +3570,13 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                     } else
                         cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
+            } else {
+                lock_ObtainMutex(&scp->mx);
             }
-
-            lock_ObtainMutex(&scp->mx);
+            lock_ReleaseMutex(&dsp->mx);
             if (code) 
                 break;
+
             bufferOffset = thyper;
 
             /* now get the data in the cache */
index 9c8691f..ea89009 100644 (file)
@@ -72,9 +72,20 @@ unsigned long smb_ExtAttributes(cm_scache_t *scp)
     unsigned long attrs;
 
     if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
-        scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
+        scp->fileType == CM_SCACHETYPE_MOUNTPOINT) 
+    {
         attrs = SMB_ATTR_DIRECTORY;
-    else
+#ifdef SPECIAL_FOLDERS
+#ifdef AFS_FREELANCE_CLIENT
+        if ( cm_freelanceEnabled &&
+             scp->fid.cell==AFS_FAKE_ROOT_CELL_ID && 
+             scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
+             scp->fid.vnode==0x1 && scp->fid.unique==0x1) {
+            attrs |= SMB_ATTR_SYSTEM;          /* FILE_ATTRIBUTE_SYSTEM */
+        }
+#endif /* AFS_FREELANCE_CLIENT */
+#endif /* SPECIAL_FOLDERS */
+    } else
         attrs = 0;
     /*
      * We used to mark a file RO if it was in an RO volume, but that
@@ -3575,8 +3586,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         pathp = ((char *) p->parmsp) + 12;     /* points to path */
         nextCookie = 0;
         maskp = strrchr(pathp, '\\');
-        if (maskp == NULL) maskp = pathp;
-        else maskp++;  /* skip over backslash */
+        if (maskp == NULL) 
+            maskp = pathp;
+        else 
+            maskp++;   /* skip over backslash */
         strcpy(dsp->mask, maskp);      /* and save mask */
         /* track if this is likely to match a lot of entries */
         starPattern = smb_V3IsStarMask(maskp);
@@ -3585,7 +3598,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         osi_assert(p->opcode == 2);
         /* find next; obtain basic parameters from request or open dir file */
         dsp = smb_FindDirSearch(p->parmsp[0]);
-        if (!dsp) return CM_ERROR_BADFD;
+        if (!dsp) 
+            return CM_ERROR_BADFD;
         attribute = dsp->attribute;
         maxCount = p->parmsp[1];
         infoLevel = p->parmsp[2];
@@ -3653,10 +3667,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     else {
         spacep = cm_GetSpace();
         smb_StripLastComponent(spacep->data, NULL, pathp);
-        lock_ReleaseMutex(&dsp->mx);
-
         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
         if (code) {
+            lock_ReleaseMutex(&dsp->mx);
             cm_ReleaseUser(userp);
             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
             smb_FreeTran2Packet(outp);
@@ -3669,9 +3682,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         userp, tidPathp, &req, &scp);
         cm_FreeSpace(spacep);
 
-        lock_ObtainMutex(&dsp->mx);
         if (code == 0) {
-            if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
+            if (dsp->scp != 0) 
+                cm_ReleaseSCache(dsp->scp);
             dsp->scp = scp;
             /* we need one hold for the entry we just stored into,
              * and one for our own processing.  When we're done
@@ -3784,6 +3797,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             lock_ObtainRead(&scp->bufCreateLock);
             code = buf_Get(scp, &thyper, &bufferp);
             lock_ReleaseRead(&scp->bufCreateLock);
+            lock_ObtainMutex(&dsp->mx);
 
             /* now, if we're doing a star match, do bulk fetching
              * of all of the status info for files in the dir.
@@ -3792,6 +3806,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
                                            infoLevel, userp,
                                            &req);
+                lock_ObtainMutex(&scp->mx);
                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
                     /* Don't bulk stat if risking timeout */
@@ -3803,10 +3818,13 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     } else
                         cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
+            } else {
+                lock_ObtainMutex(&scp->mx);
             }
+            lock_ReleaseMutex(&dsp->mx);
+            if (code) 
+                break;
 
-            lock_ObtainMutex(&scp->mx);
-            if (code) break;
             bufferOffset = thyper;
 
             /* now get the data in the cache */