From 5745d6e260998288c2411057b661e3ff33ece78e Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Sat, 30 Oct 2004 00:38:53 +0000 Subject: [PATCH] windows-invalid-dir-handles-20041029 * 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 | 9 ++-- src/WINNT/afsd/cm_conn.c | 42 +++++++-------- src/WINNT/afsd/cm_freelance.c | 2 +- src/WINNT/afsd/cm_vnodeops.c | 19 ++++--- src/WINNT/afsd/cm_vnodeops.h | 1 + src/WINNT/afsd/smb.c | 99 +++++++++++++++++++++++------------ src/WINNT/afsd/smb3.c | 40 ++++++++++---- 7 files changed, 134 insertions(+), 78 deletions(-) diff --git a/src/WINNT/afsd/cm.h b/src/WINNT/afsd/cm.h index b0cef02e8..423bdd30f 100644 --- a/src/WINNT/afsd/cm.h +++ b/src/WINNT/afsd/cm.h @@ -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__ */ diff --git a/src/WINNT/afsd/cm_conn.c b/src/WINNT/afsd/cm_conn.c index 32e748ad1..4dbfb2cfd 100644 --- a/src/WINNT/afsd/cm_conn.c +++ b/src/WINNT/afsd/cm_conn.c @@ -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; } diff --git a/src/WINNT/afsd/cm_freelance.c b/src/WINNT/afsd/cm_freelance.c index e6b0a859e..0894791a1 100644 --- a/src/WINNT/afsd/cm_freelance.c +++ b/src/WINNT/afsd/cm_freelance.c @@ -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) { diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 17511447f..dcb48f00c 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -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; diff --git a/src/WINNT/afsd/cm_vnodeops.h b/src/WINNT/afsd/cm_vnodeops.h index 9f2a7a641..fc5a5e57c 100644 --- a/src/WINNT/afsd/cm_vnodeops.h +++ b/src/WINNT/afsd/cm_vnodeops.h @@ -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__ */ diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index fb3e1aefd..feb941ead 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -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 */ diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 9c8691f64..ea89009f8 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -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 */ -- 2.39.5