Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
21 KiB

  1. /*++ BUILD Version: 0009 // Increment this if a change has global effects
  2. Copyright (c) 1987-1993 Microsoft Corporation
  3. Module Name:
  4. smbcemid.c
  5. Abstract:
  6. This module defines the routines for manipulating MIDs associated with SMB's
  7. Author:
  8. Balan Sethu Raman (SethuR) 26-Aug-95 Created
  9. Notes:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifdef ALLOC_PRAGMA
  14. #endif
  15. RXDT_DefineCategory(SMBCEMID);
  16. #define Dbg (DEBUG_TRACE_SMBCEMID)
  17. INLINE
  18. BOOLEAN
  19. SmbCeVerifyMid(
  20. PSMBCEDB_SERVER_ENTRY pServerEntry,
  21. PSMB_EXCHANGE pExchange,
  22. SMB_MPX_ID Mid)
  23. {
  24. BOOLEAN MidIsValid = TRUE;
  25. USHORT ServerVersion;
  26. ASSERT(pServerEntry != NULL);
  27. ASSERT(pServerEntry->pMidAtlas != NULL);
  28. if (pServerEntry->pMidAtlas->MaximumMidFieldWidth < 16) {
  29. USHORT MidMask;
  30. MidMask = 0x1 << pServerEntry->pMidAtlas->MaximumMidFieldWidth;
  31. MidMask = MidMask -1;
  32. MidIsValid = ((Mid & ~MidMask) == pExchange->MidCookie);
  33. }
  34. return MidIsValid;
  35. }
  36. INLINE
  37. SMB_MPX_ID
  38. SmbCeEncodeMid(
  39. PSMBCEDB_SERVER_ENTRY pServerEntry,
  40. PSMB_EXCHANGE pExchange,
  41. SMB_MPX_ID Mid)
  42. {
  43. USHORT VersionNumber;
  44. SMB_MPX_ID EncodedMid;
  45. EncodedMid = Mid;
  46. if (pServerEntry->pMidAtlas->MaximumMidFieldWidth < 16) {
  47. LONG MidCookie = InterlockedIncrement(&pServerEntry->Server.MidCounter);
  48. pExchange->MidCookie= ((USHORT)MidCookie <<
  49. pServerEntry->pMidAtlas->MaximumMidFieldWidth);
  50. EncodedMid |= pExchange->MidCookie;
  51. }
  52. return EncodedMid;
  53. }
  54. INLINE
  55. SMB_MPX_ID
  56. SmbCeExtractMid(
  57. PSMBCEDB_SERVER_ENTRY pServerEntry,
  58. SMB_MPX_ID EncodedMid)
  59. {
  60. SMB_MPX_ID Mid = EncodedMid;
  61. if (pServerEntry->pMidAtlas->MaximumMidFieldWidth < 16) {
  62. USHORT MidMask;
  63. MidMask = 0x1 << pServerEntry->pMidAtlas->MaximumMidFieldWidth;
  64. MidMask = MidMask -1;
  65. Mid &= MidMask;
  66. }
  67. return Mid;
  68. }
  69. NTSTATUS
  70. SmbCeAssociateExchangeWithMid(
  71. PSMBCEDB_SERVER_ENTRY pServerEntry,
  72. struct _SMB_EXCHANGE *pExchange)
  73. /*++
  74. Routine Description:
  75. This routine associates an exchange with a MID
  76. Arguments:
  77. pServerEntry - the servere entry
  78. pExchange - the Exchange instance.
  79. Return Value:
  80. STATUS_SUCCESS if successful, otherwise one of the following errors
  81. Notes:
  82. If an asynchronous mechanism to acquire MID's is to be introduced this routine
  83. needs to be modified. Currently this routine does not return control till a
  84. MID is acquired or the exchange is aborted/terminated.
  85. --*/
  86. {
  87. NTSTATUS Status = STATUS_SUCCESS;
  88. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  89. SMBCE_RESUMPTION_CONTEXT ResumptionContext;
  90. SMBCEDB_SERVER_TYPE ServerType;
  91. BOOLEAN ResetServerEntry = FALSE;
  92. ServerType = SmbCeGetServerType(pServerEntry);
  93. // Acquire the resource
  94. SmbCeAcquireSpinLock();
  95. // Attempt to allocate a MID only for FILE Servers. Mailslot servers do
  96. // not require a valid MID.
  97. if (ServerType != SMBCEDB_MAILSLOT_SERVER) {
  98. if (pServerEntry->pMidAtlas != NULL) {
  99. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_INDEFINITE_DELAY_IN_RESPONSE) {
  100. // This exchange response can be arbitrarily delayed. Ensure that
  101. // all the available MIDS are not tied up in such exchanges.
  102. if ((pServerEntry->pMidAtlas->NumberOfMidsInUse + 1) >=
  103. pServerEntry->pMidAtlas->MaximumNumberOfMids) {
  104. Status = STATUS_TOO_MANY_COMMANDS;
  105. }
  106. }
  107. if (Status == STATUS_SUCCESS) {
  108. if (pServerEntry->pMidAtlas->NumberOfMidsDiscarded ==
  109. pServerEntry->pMidAtlas->MaximumNumberOfMids) {
  110. Status = STATUS_TOO_MANY_COMMANDS;
  111. ResetServerEntry = TRUE;
  112. }
  113. }
  114. if (Status == STATUS_SUCCESS) {
  115. SMB_MPX_ID Mid;
  116. Status = FsRtlAssociateContextWithMid(
  117. pServerEntry->pMidAtlas,
  118. pExchange,
  119. &Mid);
  120. if (Status == STATUS_SUCCESS) {
  121. pExchange->Mid = SmbCeEncodeMid(pServerEntry,pExchange,Mid);
  122. }
  123. }
  124. } else {
  125. if (pServerEntry->Header.State == SMBCEDB_ACTIVE) {
  126. Status = STATUS_INVALID_PARAMETER;
  127. } else {
  128. Status = STATUS_CONNECTION_DISCONNECTED;
  129. }
  130. }
  131. }
  132. if (Status == STATUS_UNSUCCESSFUL) {
  133. // Allocate a new entry and add it to the list.
  134. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  135. if (pRequestEntry != NULL) {
  136. // Enqueue the request entry.
  137. SmbCeInitializeResumptionContext(&ResumptionContext);
  138. pRequestEntry->MidRequest.Type = ACQUIRE_MID_REQUEST;
  139. pRequestEntry->MidRequest.pExchange = pExchange;
  140. pRequestEntry->MidRequest.pResumptionContext = &ResumptionContext;
  141. SmbCeAddRequestEntryLite(&pServerEntry->MidAssignmentRequests,pRequestEntry);
  142. } else {
  143. Status = STATUS_INSUFFICIENT_RESOURCES;
  144. }
  145. } else if (Status == STATUS_SUCCESS) {
  146. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_MID_VALID;
  147. }
  148. // Release the resource
  149. SmbCeReleaseSpinLock();
  150. if (Status == STATUS_UNSUCCESSFUL) {
  151. //DbgPrint("***** Thread %lx Waiting for MID Resumption Context %lx*****\n",PsGetCurrentThread(),&ResumptionContext);
  152. SmbCeSuspend(&ResumptionContext);
  153. Status = ResumptionContext.Status;
  154. //DbgPrint("***** Thread %lx MID Wait Satisfied %lx *****\n",PsGetCurrentThread(),&ResumptionContext);
  155. }
  156. if (ResetServerEntry) {
  157. // If all the mids have been discarded we rest the transport connection
  158. // to start afresh.
  159. SmbCeTransportDisconnectIndicated(pServerEntry);
  160. }
  161. return Status;
  162. }
  163. struct _SMB_EXCHANGE *
  164. SmbCeMapMidToExchange(
  165. PSMBCEDB_SERVER_ENTRY pServerEntry,
  166. SMB_MPX_ID Mid)
  167. /*++
  168. Routine Description:
  169. This routine maps a given MID to the exchange associated with it
  170. Arguments:
  171. pServerEntry - the servere entry
  172. Mid - the mid to be mapped to an Exchange.
  173. Return Value:
  174. a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
  175. --*/
  176. {
  177. PSMB_EXCHANGE pExchange;
  178. // Acquire the resource
  179. SmbCeAcquireSpinLock();
  180. if (pServerEntry->pMidAtlas != NULL) {
  181. pExchange = FsRtlMapMidToContext(
  182. pServerEntry->pMidAtlas,
  183. Mid);
  184. if (pExchange != NULL) {
  185. if (!SmbCeVerifyMid(pServerEntry,pExchange,Mid)) {
  186. pExchange = NULL;
  187. }
  188. }
  189. } else {
  190. pExchange = NULL;
  191. }
  192. // Release the resource
  193. SmbCeReleaseSpinLock();
  194. return pExchange;
  195. }
  196. NTSTATUS
  197. SmbCeDissociateMidFromExchange(
  198. PSMBCEDB_SERVER_ENTRY pServerEntry,
  199. struct _SMB_EXCHANGE *pExchange)
  200. /*++
  201. Routine Description:
  202. This routine disassociates an exchange from the MID
  203. Arguments:
  204. pServerEntry - the servere entry
  205. pExchange - the exchange instance.
  206. Return Value:
  207. a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
  208. Notes:
  209. If an asynchronous mechanism to acquire MID's is to be introduced this routine
  210. needs to be modified. This modification will also include posting requests
  211. for resumption of exchanges when invoked at DPC level.
  212. --*/
  213. {
  214. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  215. SMBCEDB_SERVER_TYPE ServerType;
  216. ServerType = SmbCeGetServerType(pServerEntry);
  217. if ((ServerType != SMBCEDB_MAILSLOT_SERVER) &&
  218. (pExchange->Mid != SMBCE_OPLOCK_RESPONSE_MID) &&
  219. (pExchange->Mid != SMBCE_MAILSLOT_OPERATION_MID)) {
  220. PVOID pContext;
  221. PSMBCEDB_REQUEST_ENTRY pRequestEntry = NULL;
  222. // Acquire the resource
  223. SmbCeAcquireSpinLock();
  224. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
  225. // Check if there are any pending MID assignment requests and transfer the MID
  226. // if one exists.
  227. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->MidAssignmentRequests);
  228. if (pRequestEntry != NULL) {
  229. SmbCeRemoveRequestEntryLite(&pServerEntry->MidAssignmentRequests,pRequestEntry);
  230. }
  231. if (pServerEntry->pMidAtlas != NULL) {
  232. SMB_MPX_ID Mid;
  233. Mid = SmbCeExtractMid(pServerEntry,pExchange->Mid);
  234. if (pRequestEntry != NULL) {
  235. Status = FsRtlReassociateMid(
  236. pServerEntry->pMidAtlas,
  237. Mid,
  238. pRequestEntry->MidRequest.pExchange);
  239. ASSERT(Status == STATUS_SUCCESS);
  240. pRequestEntry->MidRequest.pExchange->SmbCeFlags |= SMBCE_EXCHANGE_MID_VALID;
  241. pRequestEntry->MidRequest.pExchange->Mid = SmbCeEncodeMid(
  242. pServerEntry,
  243. pRequestEntry->MidRequest.pExchange,
  244. Mid);
  245. pRequestEntry->MidRequest.pResumptionContext->Status = STATUS_SUCCESS;
  246. } else {
  247. Status = FsRtlMapAndDissociateMidFromContext(
  248. pServerEntry->pMidAtlas,
  249. Mid,
  250. &pContext);
  251. ASSERT(pContext == pExchange);
  252. }
  253. } else {
  254. Status = STATUS_INVALID_PARAMETER;
  255. }
  256. }
  257. // Release the resource
  258. SmbCeReleaseSpinLock();
  259. if (pRequestEntry != NULL) {
  260. // Signal the waiter for resumption
  261. SmbCeResume(pRequestEntry->MidRequest.pResumptionContext);
  262. SmbCeTearDownRequestEntry(pRequestEntry);
  263. }
  264. }
  265. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_MID_VALID;
  266. return Status;
  267. }
  268. VOID
  269. SmbCeDiscardMidAssignmentRequests(
  270. PSMBCEDB_SERVER_ENTRY pServerEntry)
  271. /*++
  272. Routine Description:
  273. This routine discards all mid assignment requests for a given server entry
  274. Arguments:
  275. pServerEntry - the servere entry
  276. Notes:
  277. This typically happens when the mids in use are being cancelled against a
  278. down level server. In such cases there is no cancel command that can be
  279. sent to the server. Typically we throw away the MID and not use it any
  280. further. this will lead to a graceful degradation in performance when
  281. the connection is reestablished
  282. --*/
  283. {
  284. SMBCEDB_REQUESTS MidRequests;
  285. InitializeListHead(&MidRequests.ListHead);
  286. SmbCeAcquireSpinLock();
  287. if (pServerEntry->pMidAtlas != NULL) {
  288. if (pServerEntry->pMidAtlas->NumberOfMidsDiscarded ==
  289. pServerEntry->pMidAtlas->MaximumNumberOfMids) {
  290. SmbCeTransferRequests(
  291. &MidRequests,
  292. &pServerEntry->MidAssignmentRequests);
  293. }
  294. }
  295. SmbCeReleaseSpinLock();
  296. SmbCeResumeDiscardedMidAssignmentRequests(
  297. &MidRequests,
  298. STATUS_TOO_MANY_COMMANDS);
  299. SmbCeDereferenceServerEntry(pServerEntry);
  300. }
  301. NTSTATUS
  302. SmbCepDiscardMidAssociatedWithExchange(
  303. PSMB_EXCHANGE pExchange)
  304. /*++
  305. Routine Description:
  306. This routine discards the mid associated with an exchange
  307. Arguments:
  308. pExchange - the exchange
  309. Notes:
  310. We use the hypercritical thread to ensure that this request does not block
  311. behind other requests.
  312. This routine also assumes that it is invoked with the SmbCeSpinLock held
  313. --*/
  314. {
  315. NTSTATUS Status = STATUS_SUCCESS;
  316. if ((pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) &&
  317. (pExchange->Mid != SMBCE_OPLOCK_RESPONSE_MID) &&
  318. (pExchange->Mid != SMBCE_MAILSLOT_OPERATION_MID) &&
  319. (pExchange->Mid != SMBCE_ECHO_PROBE_MID)) {
  320. PSMBCEDB_SERVER_ENTRY pServerEntry;
  321. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  322. if ((pServerEntry != NULL) &&
  323. (pServerEntry->pMidAtlas != NULL)) {
  324. SMB_MPX_ID Mid;
  325. Mid = SmbCeExtractMid(pServerEntry,pExchange->Mid);
  326. Status = FsRtlReassociateMid(
  327. pServerEntry->pMidAtlas,
  328. Mid,
  329. NULL);
  330. if (Status == STATUS_SUCCESS) {
  331. pServerEntry->pMidAtlas->NumberOfMidsDiscarded++;
  332. if (pServerEntry->pMidAtlas->NumberOfMidsDiscarded ==
  333. pServerEntry->pMidAtlas->MaximumNumberOfMids) {
  334. // All the mids have been discarded. Any pending
  335. // mid assignment requests needs to be completed
  336. // with the appropriate error code.
  337. SmbCeReferenceServerEntry(pServerEntry);
  338. Status = RxDispatchToWorkerThread(
  339. MRxSmbDeviceObject,
  340. HyperCriticalWorkQueue,
  341. SmbCeDiscardMidAssignmentRequests,
  342. pServerEntry);
  343. }
  344. }
  345. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_MID_VALID;
  346. } else {
  347. Status = STATUS_INVALID_PARAMETER;
  348. }
  349. }
  350. return Status;
  351. }
  352. VOID
  353. SmbCeResumeDiscardedMidAssignmentRequests(
  354. PSMBCEDB_REQUESTS pMidRequests,
  355. NTSTATUS ResumptionStatus)
  356. /*++
  357. Routine Description:
  358. This routine resumes discarded mid assignment requests with the appropriate error
  359. Arguments:
  360. pMidRequests - the discarded requests
  361. ResumptionStatus - the resumption status
  362. Return Value:
  363. a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
  364. Notes:
  365. This routine and the routines that follow enable a pipelined reuse of MID's
  366. If a large buffer is to be copied then this can be done without hodling onto
  367. a MID. This improves the throughput between the client and the server. At the
  368. very least this mechanism ensures that the connection engine will not be the
  369. constraining factor in MID reuse.
  370. --*/
  371. {
  372. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  373. pRequestEntry = SmbCeGetFirstRequestEntry(pMidRequests);
  374. while (pRequestEntry != NULL) {
  375. // Remove the request entry from the list
  376. SmbCeRemoveRequestEntryLite(pMidRequests,pRequestEntry);
  377. ASSERT(pRequestEntry->GenericRequest.Type == ACQUIRE_MID_REQUEST);
  378. // Signal the waiter for resumption
  379. pRequestEntry->MidRequest.pResumptionContext->Status = ResumptionStatus;
  380. SmbCeResume(pRequestEntry->MidRequest.pResumptionContext);
  381. SmbCeTearDownRequestEntry(pRequestEntry);
  382. pRequestEntry = SmbCeGetFirstRequestEntry(pMidRequests);
  383. }
  384. }
  385. struct _SMB_EXCHANGE *
  386. SmbCeGetExchangeAssociatedWithBuffer(
  387. PSMBCEDB_SERVER_ENTRY pServerEntry,
  388. PVOID pBuffer)
  389. /*++
  390. Routine Description:
  391. This routine gets the exchange associated with a buffer
  392. Arguments:
  393. pServerEntry - the servere entry
  394. pBuffer - the buffer instance.
  395. Return Value:
  396. a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
  397. Notes:
  398. This routine and the routines that follow enable a pipelined reuse of MID's
  399. If a large buffer is to be copied then this can be done without hodling onto
  400. a MID. This improves the throughput between the client and the server. At the
  401. very least this mechanism ensures that the connection engine will not be the
  402. constraining factor in MID reuse.
  403. --*/
  404. {
  405. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  406. PSMB_EXCHANGE pExchange = NULL;
  407. // Acquire the resource
  408. SmbCeAcquireSpinLock();
  409. // Walk through the list of requests maintained on this and remove the one
  410. // matching the cached buffer ptr with the ptr indicated
  411. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  412. while (pRequestEntry != NULL) {
  413. if ((pRequestEntry->GenericRequest.Type == COPY_DATA_REQUEST) &&
  414. (pRequestEntry->CopyDataRequest.pBuffer == pBuffer)) {
  415. pExchange = pRequestEntry->CopyDataRequest.pExchange;
  416. pRequestEntry->CopyDataRequest.pBuffer = NULL;
  417. break;
  418. }
  419. pRequestEntry = SmbCeGetNextRequestEntry(
  420. &pServerEntry->OutstandingRequests,
  421. pRequestEntry);
  422. }
  423. // Release the resource
  424. SmbCeReleaseSpinLock();
  425. return pExchange;
  426. }
  427. NTSTATUS
  428. SmbCeAssociateBufferWithExchange(
  429. PSMBCEDB_SERVER_ENTRY pServerEntry,
  430. struct _SMB_EXCHANGE * pExchange,
  431. PVOID pBuffer)
  432. /*++
  433. Routine Description:
  434. This routine establishes an association between an exchange and a copy data request
  435. buffer
  436. Arguments:
  437. pServerEntry - the servere entry
  438. pBuffer - the buffer instance.
  439. Return Value:
  440. STATUS_SUCCESS if succesful
  441. --*/
  442. {
  443. NTSTATUS Status = STATUS_SUCCESS;
  444. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  445. // Acquire the resource
  446. SmbCeAcquireSpinLock();
  447. Status = pServerEntry->ServerStatus;
  448. if (Status == RX_MAP_STATUS(SUCCESS)) {
  449. // Walk through the list of requests maintained on this and remove the one
  450. // matching the cached buffer ptr with the ptr indicated
  451. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  452. while (pRequestEntry != NULL) {
  453. if ((pRequestEntry->GenericRequest.Type == COPY_DATA_REQUEST) &&
  454. (pRequestEntry->CopyDataRequest.pBuffer == NULL)) {
  455. pRequestEntry->CopyDataRequest.pExchange = pExchange;
  456. pRequestEntry->CopyDataRequest.pBuffer = pBuffer;
  457. break;
  458. }
  459. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  460. }
  461. }
  462. // Release the resource
  463. SmbCeReleaseSpinLock();
  464. if ((Status == RX_MAP_STATUS(SUCCESS)) &&
  465. (pRequestEntry == NULL)) {
  466. // Allocate a new entry and add it to the list.
  467. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  468. if (pRequestEntry != NULL) {
  469. // Enqueue the request entry.
  470. pRequestEntry->CopyDataRequest.Type = COPY_DATA_REQUEST;
  471. pRequestEntry->CopyDataRequest.pExchange = pExchange;
  472. pRequestEntry->CopyDataRequest.pBuffer = pBuffer;
  473. // Acquire the resource
  474. SmbCeAcquireSpinLock();
  475. if ((Status = pServerEntry->ServerStatus) == RX_MAP_STATUS(SUCCESS)) {
  476. SmbCeAddRequestEntryLite(&pServerEntry->OutstandingRequests,pRequestEntry);
  477. }
  478. // Release the resource
  479. SmbCeReleaseSpinLock();
  480. if (Status != RX_MAP_STATUS(SUCCESS)) {
  481. SmbCeTearDownRequestEntry(pRequestEntry);
  482. }
  483. } else {
  484. Status = STATUS_INSUFFICIENT_RESOURCES;
  485. }
  486. }
  487. return Status;
  488. }
  489. VOID
  490. SmbCePurgeBuffersAssociatedWithExchange(
  491. PSMBCEDB_SERVER_ENTRY pServerEntry,
  492. struct _SMB_EXCHANGE * pExchange)
  493. /*++
  494. Routine Description:
  495. This routine purges all the copy data requests associated with an exchange.
  496. Arguments:
  497. pServerEntry - the servere entry
  498. pExchange - the exchange instance.
  499. Notes:
  500. This mechanism of delaying the purging of requests associated with an exchange
  501. till it is discared is intended to solve the problem of repeated allocation/freeing
  502. of request entries. This rests on the assumption that there will not be too many
  503. copy data requests outstanding for any exchange. If evidence to the contrary is
  504. noticed this technique has to be modified.
  505. --*/
  506. {
  507. SMBCEDB_REQUESTS ExchangeRequests;
  508. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  509. PSMBCEDB_REQUEST_ENTRY pNextRequestEntry;
  510. SmbCeInitializeRequests(&ExchangeRequests);
  511. // Acquire the resource
  512. SmbCeAcquireSpinLock();
  513. // Walk through the list of requests maintained on this and remove the one
  514. // matching the given exchange
  515. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  516. while (pRequestEntry != NULL) {
  517. pNextRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  518. if (pRequestEntry->GenericRequest.pExchange == pExchange) {
  519. SmbCeRemoveRequestEntryLite(&pServerEntry->OutStandingRequests,pRequestEntry);
  520. SmbCeAddRequestEntryLite(&ExchangeRequests,pRequestEntry);
  521. }
  522. pRequestEntry = pNextRequestEntry;
  523. }
  524. // Release the resource
  525. SmbCeReleaseSpinLock();
  526. pRequestEntry = SmbCeGetFirstRequestEntry(&ExchangeRequests);
  527. while (pRequestEntry != NULL) {
  528. SmbCeRemoveRequestEntryLite(&ExchangeRequests,pRequestEntry);
  529. SmbCeTearDownRequestEntry(pRequestEntry);
  530. pRequestEntry = SmbCeGetFirstRequestEntry(&ExchangeRequests);
  531. }
  532. }
  533.