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.

4004 lines
111 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. smbmpx.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs:
  7. Read Block Multiplexed
  8. Write Block Multiplexed
  9. Note that core and raw mode SMB processors are not contained in this
  10. module. Check smbrdwrt.c and smbraw.c instead. SMB commands that
  11. pertain exclusively to locking (LockByteRange, UnlockByteRange, and
  12. LockingAndX) are processed in smblock.c.
  13. Author:
  14. Chuck Lenzmeier (chuckl) 4-Nov-1993
  15. Revision History:
  16. --*/
  17. #include "precomp.h"
  18. #include "smbmpx.tmh"
  19. #pragma hdrstop
  20. #define BugCheckFileId SRV_FILE_SMBMPX
  21. #if 0
  22. BOOLEAN MpxDelay = TRUE;
  23. #endif
  24. //
  25. // Stack overflow threshold. This is used to determine when we are
  26. // getting close to the end of our stack and need to stop recursing
  27. // in SendCopy/MdlReadMpxFragment.
  28. //
  29. #define STACK_THRESHOLD 0xE00
  30. //
  31. // Forward declarations
  32. //
  33. VOID SRVFASTCALL
  34. RestartReadMpx (
  35. IN OUT PWORK_CONTEXT WorkContext
  36. );
  37. NTSTATUS
  38. SendCopyReadMpxFragment (
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp,
  41. IN OUT PWORK_CONTEXT WorkContext
  42. );
  43. VOID SRVFASTCALL
  44. SendCopyReadMpxFragment2 (
  45. IN OUT PWORK_CONTEXT
  46. );
  47. NTSTATUS
  48. SendMdlReadMpxFragment (
  49. IN PDEVICE_OBJECT DeviceObject,
  50. IN PIRP Irp,
  51. IN OUT PWORK_CONTEXT WorkContext
  52. );
  53. VOID SRVFASTCALL
  54. SendMdlReadMpxFragment2 (
  55. IN OUT PWORK_CONTEXT WorkContext
  56. );
  57. VOID SRVFASTCALL
  58. RestartMdlReadMpxComplete (
  59. IN OUT PWORK_CONTEXT WorkContext
  60. );
  61. VOID SRVFASTCALL
  62. RestartWriteMpx (
  63. IN OUT PWORK_CONTEXT WorkContext
  64. );
  65. BOOLEAN
  66. CheckForWriteMpxComplete (
  67. IN OUT PWORK_CONTEXT WorkContext
  68. );
  69. VOID SRVFASTCALL
  70. RestartPrepareMpxMdlWrite (
  71. IN OUT PWORK_CONTEXT WorkContext
  72. );
  73. VOID SRVFASTCALL
  74. AddPacketToGlom (
  75. IN OUT PWORK_CONTEXT WorkContext
  76. );
  77. VOID SRVFASTCALL
  78. RestartAfterGlomDelay (
  79. IN OUT PWORK_CONTEXT WorkContext
  80. );
  81. VOID SRVFASTCALL
  82. RestartCompleteGlommingInIndication(
  83. IN OUT PWORK_CONTEXT WorkContext
  84. );
  85. VOID SRVFASTCALL
  86. RestartWriteMpxCompleteRfcbClose (
  87. IN OUT PWORK_CONTEXT WorkContext
  88. );
  89. VOID SRVFASTCALL
  90. WriteMpxMdlWriteComplete (
  91. IN OUT PWORK_CONTEXT WorkContext
  92. );
  93. #ifdef ALLOC_PRAGMA
  94. #pragma alloc_text( PAGE, SrvSmbReadMpx )
  95. #pragma alloc_text( PAGE, RestartMdlReadMpxComplete )
  96. #pragma alloc_text( PAGE, SrvRestartReceiveWriteMpx )
  97. #pragma alloc_text( PAGE, SrvSmbWriteMpxSecondary )
  98. #pragma alloc_text( PAGE, SendCopyReadMpxFragment2 )
  99. #pragma alloc_text( PAGE, SendMdlReadMpxFragment2 )
  100. #pragma alloc_text( PAGE8FIL, RestartReadMpx )
  101. #pragma alloc_text( PAGE8FIL, SendCopyReadMpxFragment )
  102. #pragma alloc_text( PAGE8FIL, RestartCopyReadMpxComplete )
  103. #pragma alloc_text( PAGE8FIL, SendMdlReadMpxFragment )
  104. #endif
  105. #if 0
  106. NOT PAGEABLE -- SrvSmbWriteMpx
  107. NOT PAGEABLE -- RestartWriteMpx
  108. NOT PAGEABLE -- CheckForWriteMpxComplete
  109. NOT PAGEABLE -- RestartCompleteGlommingInIndication
  110. NOT PAGEABLE -- RestartWriteMpxCompleteRfcbClose
  111. NOT PAGEABLE -- WriteMpxMdlWriteComplete
  112. #endif
  113. #if DBG
  114. VOID
  115. DumpMdlChain(
  116. IN PMDL mdl
  117. );
  118. #endif
  119. SMB_PROCESSOR_RETURN_TYPE
  120. SrvSmbReadMpx (
  121. SMB_PROCESSOR_PARAMETERS
  122. )
  123. /*++
  124. Routine Description:
  125. Processes the Read Mpx SMB.
  126. Arguments:
  127. WorkContext - Supplies a pointer to the work context block
  128. representing the work item
  129. Return Value:
  130. None.
  131. --*/
  132. {
  133. PSMB_HEADER header;
  134. PREQ_READ_MPX request;
  135. NTSTATUS status = STATUS_SUCCESS;
  136. SMB_STATUS SmbStatus = SmbStatusInProgress;
  137. USHORT fid;
  138. PRFCB rfcb;
  139. PLFCB lfcb;
  140. ULONG bufferOffset;
  141. PCHAR readAddress;
  142. CLONG readLength;
  143. ULONG key;
  144. LARGE_INTEGER offset;
  145. PMDL mdl;
  146. PVOID mpxBuffer;
  147. UCHAR minorFunction;
  148. PAGED_CODE( );
  149. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  150. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_MPX;
  151. SrvWmiStartContext(WorkContext);
  152. header = WorkContext->RequestHeader;
  153. request = (PREQ_READ_MPX)WorkContext->RequestParameters;
  154. fid = SmbGetUshort( &request->Fid );
  155. IF_SMB_DEBUG(MPX1) {
  156. KdPrint(( "Read Block Multiplexed request; FID 0x%lx, "
  157. "count %ld, offset %ld\n",
  158. fid, SmbGetUshort( &request->MaxCount ),
  159. SmbGetUlong( &request->Offset ) ));
  160. }
  161. //
  162. // Verify the FID. If verified, the RFCB is referenced and its
  163. // address is stored in the WorkContext block, and the RFCB address
  164. // is returned.
  165. //
  166. rfcb = SrvVerifyFid(
  167. WorkContext,
  168. fid,
  169. TRUE,
  170. SrvRestartSmbReceived, // serialize with raw write
  171. &status
  172. );
  173. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  174. if ( !NT_SUCCESS( status )) {
  175. //
  176. // Invalid file ID or write behind error. Reject the request.
  177. //
  178. IF_DEBUG(ERRORS) {
  179. KdPrint((
  180. "SrvSmbReadMpx: Status %X on FID: 0x%lx\n",
  181. status,
  182. fid
  183. ));
  184. }
  185. SrvSetSmbError( WorkContext, status );
  186. SmbStatus = SmbStatusSendResponse;
  187. goto Cleanup;
  188. }
  189. //
  190. // The work item has been queued because a raw write is in
  191. // progress.
  192. //
  193. SmbStatus = SmbStatusInProgress;
  194. goto Cleanup;
  195. }
  196. lfcb = rfcb->Lfcb;
  197. if( lfcb->Session->IsSessionExpired )
  198. {
  199. status = SESSION_EXPIRED_STATUS_CODE;
  200. SrvSetSmbError( WorkContext, status );
  201. SmbStatus = SmbStatusSendResponse;
  202. goto Cleanup;
  203. }
  204. //
  205. // Verify that the client has read access to the file via the
  206. // specified handle.
  207. //
  208. if( rfcb->MpxReadsOk == FALSE ) {
  209. if ( !rfcb->ReadAccessGranted ) {
  210. CHECK_PAGING_IO_ACCESS(
  211. WorkContext,
  212. rfcb->GrantedAccess,
  213. &status );
  214. if ( !NT_SUCCESS( status ) ) {
  215. SrvStatistics.GrantedAccessErrors++;
  216. IF_DEBUG(ERRORS) {
  217. KdPrint(( "SrvSmbReadMpx: Read access not granted.\n"));
  218. }
  219. SrvSetSmbError( WorkContext, status );
  220. SmbStatus = SmbStatusSendResponse;
  221. goto Cleanup;
  222. }
  223. }
  224. //
  225. // If this is not a disk file, tell the client to use core read.
  226. //
  227. if ( rfcb->ShareType != ShareTypeDisk ) {
  228. SrvSetSmbError( WorkContext, STATUS_SMB_USE_STANDARD );
  229. status = STATUS_SMB_USE_STANDARD;
  230. SmbStatus = SmbStatusSendResponse;
  231. goto Cleanup;
  232. }
  233. rfcb->MpxReadsOk = TRUE;
  234. }
  235. //
  236. // Form the lock key using the FID and the PID.
  237. //
  238. // *** The FID must be included in the key in order to account for
  239. // the folding of multiple remote compatibility mode opens into
  240. // a single local open.
  241. //
  242. key = rfcb->ShiftedFid | SmbGetAlignedUshort( &header->Pid );
  243. //
  244. // See if the direct host IPX smart card can handle this read. If so,
  245. // return immediately, and the card will call our restart routine at
  246. // SrvIpxSmartCardReadComplete
  247. //
  248. if( rfcb->PagedRfcb->IpxSmartCardContext ) {
  249. IF_DEBUG( SIPX ) {
  250. KdPrint(( "SrvSmbReadMpx: calling SmartCard Read for context %p\n",
  251. WorkContext ));
  252. }
  253. WorkContext->Parameters.SmartCardRead.MdlReadComplete = lfcb->MdlReadComplete;
  254. WorkContext->Parameters.SmartCardRead.DeviceObject = lfcb->DeviceObject;
  255. if( SrvIpxSmartCard.Read( WorkContext->RequestBuffer->Buffer,
  256. rfcb->PagedRfcb->IpxSmartCardContext,
  257. key,
  258. WorkContext ) == TRUE ) {
  259. IF_DEBUG( SIPX ) {
  260. KdPrint(( " SrvSmbReadMpx: SmartCard Read returns TRUE\n" ));
  261. }
  262. SmbStatus = SmbStatusInProgress;
  263. goto Cleanup;
  264. }
  265. IF_DEBUG( SIPX ) {
  266. KdPrint(( " SrvSmbReadMpx: SmartCard Read returns FALSE\n" ));
  267. }
  268. }
  269. //
  270. // Get the file offset.
  271. //
  272. WorkContext->Parameters.ReadMpx.Offset = SmbGetUlong( &request->Offset );
  273. offset.QuadPart = WorkContext->Parameters.ReadMpx.Offset;
  274. //
  275. // Calculate the address in the buffer at which to put the data.
  276. // This must be rounded up to a dword boundary. (The -1 below is
  277. // because sizeof(RESP_READ_MPX) includes one byte of Buffer.)
  278. //
  279. bufferOffset = (sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX, Buffer) + 3) & ~3;
  280. //
  281. // Calculate how much data we can send back in each fragment. This
  282. // is the size of the client's buffer, rounded down to a dword multiple.
  283. //
  284. // *** Because we use the SMB buffer's partial MDL to describe the
  285. // data fragments that we return, we need to limit the fragment
  286. // size to the SMB buffer size. Normally the client's buffer
  287. // size is <= ours, so this shouldn't be a factor.
  288. //
  289. WorkContext->Parameters.ReadMpx.FragmentSize =
  290. (USHORT)((MIN( lfcb->Session->MaxBufferSize,
  291. SrvReceiveBufferLength ) - bufferOffset) & ~3);
  292. //
  293. // If the SMB buffer is large enough, use it to do the local read.
  294. //
  295. readLength = SmbGetUshort( &request->MaxCount );
  296. if ( //0 &&
  297. (readLength <= SrvMpxMdlReadSwitchover) ) {
  298. do_copy_read:
  299. WorkContext->Parameters.ReadMpx.MdlRead = FALSE;
  300. WorkContext->Parameters.ReadMpx.MpxBuffer = NULL;
  301. WorkContext->Parameters.ReadMpx.MpxBufferMdl =
  302. WorkContext->ResponseBuffer->Mdl;
  303. readAddress = (PCHAR)WorkContext->ResponseHeader + bufferOffset;
  304. WorkContext->Parameters.ReadMpx.NextFragmentAddress = readAddress;
  305. //
  306. // Try the fast I/O path first.
  307. //
  308. if ( lfcb->FastIoRead != NULL ) {
  309. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  310. try {
  311. if ( lfcb->FastIoRead(
  312. lfcb->FileObject,
  313. &offset,
  314. readLength,
  315. TRUE,
  316. key,
  317. readAddress,
  318. &WorkContext->Irp->IoStatus,
  319. lfcb->DeviceObject
  320. ) ) {
  321. //
  322. // The fast I/O path worked. Send the data.
  323. //
  324. WorkContext->bAlreadyTrace = TRUE;
  325. RestartReadMpx( WorkContext );
  326. SmbStatus = SmbStatusInProgress;
  327. goto Cleanup;
  328. }
  329. }
  330. except( EXCEPTION_EXECUTE_HANDLER ) {
  331. // Fall through to the slow path on an exception
  332. status = GetExceptionCode();
  333. IF_DEBUG(ERRORS) {
  334. KdPrint(("FastIoRead threw exception %x\n", status ));
  335. }
  336. }
  337. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  338. }
  339. //
  340. // The fast I/O path failed, so we need to use a regular copy
  341. // I/O request. Build an MDL describing the read buffer.
  342. //
  343. // *** Note the assumption that the response buffer already has
  344. // a valid full MDL from which a partial MDL can be built.
  345. //
  346. IoBuildPartialMdl(
  347. WorkContext->ResponseBuffer->Mdl,
  348. WorkContext->ResponseBuffer->PartialMdl,
  349. readAddress,
  350. readLength
  351. );
  352. mdl = WorkContext->ResponseBuffer->PartialMdl;
  353. minorFunction = 0;
  354. } else {
  355. //
  356. // The SMB buffer isn't big enough. Does the target file system
  357. // support the cache manager routines?
  358. //
  359. if ( //0 &&
  360. (lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) ) {
  361. WorkContext->Parameters.ReadMpx.MdlRead = TRUE;
  362. //
  363. // We can use an MDL read. Try the fast I/O path first.
  364. //
  365. WorkContext->Irp->MdlAddress = NULL;
  366. WorkContext->Irp->IoStatus.Information = 0;
  367. WorkContext->Parameters.ReadMpx.ReadLength = readLength;
  368. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  369. if ( lfcb->MdlRead &&
  370. lfcb->MdlRead(
  371. lfcb->FileObject,
  372. &offset,
  373. readLength,
  374. key,
  375. &WorkContext->Irp->MdlAddress,
  376. &WorkContext->Irp->IoStatus,
  377. lfcb->DeviceObject
  378. ) && WorkContext->Irp->MdlAddress != NULL ) {
  379. //
  380. // The fast I/O path worked. Send the data.
  381. //
  382. WorkContext->bAlreadyTrace = TRUE;
  383. RestartReadMpx( WorkContext );
  384. SmbStatus = SmbStatusInProgress;
  385. goto Cleanup;
  386. }
  387. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  388. //
  389. // The fast I/O path failed. We need to issue a regular MDL
  390. // read request.
  391. //
  392. // The fast path may have partially succeeded, returning a
  393. // partial MDL chain. We need to adjust our read request
  394. // to account for that.
  395. //
  396. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  397. readLength -= (ULONG)WorkContext->Irp->IoStatus.Information;
  398. mdl = WorkContext->Irp->MdlAddress;
  399. minorFunction = IRP_MN_MDL;
  400. readAddress = NULL; // Not used for MDL read
  401. } else if (readLength > (WorkContext->ResponseBuffer->BufferLength -
  402. bufferOffset)) {
  403. //
  404. // We have to use a normal "copy" read. We need to allocate
  405. // a separate buffer.
  406. //
  407. WorkContext->Parameters.ReadMpx.MdlRead = FALSE;
  408. mpxBuffer = ALLOCATE_NONPAGED_POOL(
  409. readLength,
  410. BlockTypeDataBuffer
  411. );
  412. if ( mpxBuffer == NULL ) {
  413. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  414. status = STATUS_INSUFF_SERVER_RESOURCES;
  415. SmbStatus = SmbStatusSendResponse;
  416. goto Cleanup;
  417. }
  418. WorkContext->Parameters.ReadMpx.MpxBuffer = mpxBuffer;
  419. WorkContext->Parameters.ReadMpx.NextFragmentAddress = mpxBuffer;
  420. readAddress = mpxBuffer;
  421. //
  422. // We also need an MDL to describe the buffer.
  423. //
  424. mdl = IoAllocateMdl( mpxBuffer, readLength, FALSE, FALSE, NULL );
  425. if ( mdl == NULL ) {
  426. DEALLOCATE_NONPAGED_POOL( mpxBuffer );
  427. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  428. status = STATUS_INSUFF_SERVER_RESOURCES;
  429. SmbStatus = SmbStatusSendResponse;
  430. goto Cleanup;
  431. }
  432. WorkContext->Parameters.ReadMpx.MpxBufferMdl = mdl;
  433. //
  434. // Build the mdl.
  435. //
  436. MmBuildMdlForNonPagedPool( mdl );
  437. //
  438. // Try the fast I/O path first.
  439. //
  440. if ( lfcb->FastIoRead != NULL ) {
  441. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  442. try {
  443. if ( lfcb->FastIoRead(
  444. lfcb->FileObject,
  445. &offset,
  446. readLength,
  447. TRUE,
  448. key,
  449. mpxBuffer,
  450. &WorkContext->Irp->IoStatus,
  451. lfcb->DeviceObject
  452. ) ) {
  453. //
  454. // The fast I/O path worked. Send the data.
  455. //
  456. WorkContext->bAlreadyTrace = TRUE;
  457. RestartReadMpx( WorkContext );
  458. SmbStatus = SmbStatusInProgress;
  459. goto Cleanup;
  460. }
  461. }
  462. except( EXCEPTION_EXECUTE_HANDLER ) {
  463. // Fall through to the slow path on an exception
  464. status = GetExceptionCode();
  465. IF_DEBUG(ERRORS) {
  466. KdPrint(("FastIoRead threw exception %x\n", status ));
  467. }
  468. }
  469. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  470. }
  471. //
  472. // The fast I/O path failed, so we need to use a regular copy
  473. // I/O request.
  474. //
  475. minorFunction = 0;
  476. } else {
  477. goto do_copy_read;
  478. }
  479. } // read fits in SMB buffer?
  480. //
  481. // Build the read request, reusing the receive IRP.
  482. //
  483. SrvBuildReadOrWriteRequest(
  484. WorkContext->Irp, // input IRP address
  485. lfcb->FileObject, // target file object address
  486. WorkContext, // context
  487. IRP_MJ_READ, // major function code
  488. minorFunction, // minor function code
  489. readAddress, // buffer address
  490. readLength, // buffer length
  491. mdl, // MDL address
  492. offset, // byte offset
  493. key // lock key
  494. );
  495. //
  496. // Pass the request to the file system.
  497. //
  498. WorkContext->bAlreadyTrace = TRUE;
  499. WorkContext->FsdRestartRoutine = RestartReadMpx;
  500. DEBUG WorkContext->FspRestartRoutine = NULL;
  501. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  502. //
  503. // The read has been started. Control will return to the restart
  504. // routine when the read completes.
  505. //
  506. SmbStatus = SmbStatusInProgress;
  507. Cleanup:
  508. SrvWmiEndContext(WorkContext);
  509. return SmbStatus;
  510. } // SrvSmbReadMpx
  511. VOID SRVFASTCALL
  512. RestartReadMpx (
  513. IN OUT PWORK_CONTEXT WorkContext
  514. )
  515. /*++
  516. Routine Description:
  517. Processes file read completion for a Read MPX SMB.
  518. Arguments:
  519. WorkContext - Supplies a pointer to the work context block
  520. describing server-specific context for the request.
  521. Return Value:
  522. None.
  523. --*/
  524. {
  525. PRESP_READ_MPX response;
  526. NTSTATUS status = STATUS_SUCCESS;
  527. SMB_STATUS SmbStatus = SmbStatusInProgress;
  528. LARGE_INTEGER position;
  529. KIRQL oldIrql;
  530. USHORT readLength;
  531. ULONG offset;
  532. PMDL mdl;
  533. BOOLEAN mdlRead;
  534. PIRP irp = WorkContext->Irp;
  535. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  536. UNLOCKABLE_CODE( 8FIL );
  537. if (bNeedTrace) {
  538. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  539. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_MPX;
  540. SrvWmiStartContext(WorkContext);
  541. }
  542. else
  543. WorkContext->bAlreadyTrace = FALSE;
  544. IF_DEBUG(FSD2) KdPrint(( " - RestartReadMpx\n" ));
  545. //
  546. // If we just completed an MDL read, we need to remember the address
  547. // of the first MDL in the returned chain, so that we can give it
  548. // back to the cache manager when we're done.
  549. //
  550. mdlRead = WorkContext->Parameters.ReadMpx.MdlRead;
  551. if ( mdlRead ) {
  552. mdl = irp->MdlAddress;
  553. //KdPrint(( "Read MDL chain:\n" ));
  554. //DumpMdlChain( mdl );
  555. WorkContext->Parameters.ReadMpx.FirstMdl = mdl;
  556. }
  557. //
  558. // If the read failed, set an error status in the response header.
  559. // (If we tried to read entirely beyond the end of file, we return a
  560. // normal response indicating that nothing was read.)
  561. //
  562. status = irp->IoStatus.Status;
  563. if ( !NT_SUCCESS(status) && (status != STATUS_END_OF_FILE) ) {
  564. IF_DEBUG(ERRORS) KdPrint(( "Read failed: %X\n", status ));
  565. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  566. WorkContext->FspRestartRoutine = RestartReadMpx;
  567. SrvQueueWorkToFsp( WorkContext );
  568. goto Cleanup;
  569. }
  570. SrvSetSmbError( WorkContext, status );
  571. respond:
  572. if ( mdlRead ) {
  573. SrvFsdSendResponse2( WorkContext, RestartMdlReadMpxComplete );
  574. } else {
  575. WorkContext->ResponseBuffer->DataLength =
  576. (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  577. (PCHAR)WorkContext->ResponseHeader );
  578. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  579. SRV_START_SEND_2(
  580. WorkContext,
  581. RestartCopyReadMpxComplete,
  582. NULL,
  583. NULL );
  584. }
  585. goto Cleanup;
  586. }
  587. //
  588. // Get the amount of data actually read.
  589. //
  590. if ( status == STATUS_END_OF_FILE ) {
  591. //
  592. // The read started beyond the end of the file.
  593. //
  594. readLength = 0;
  595. } else if ( mdlRead ) {
  596. //
  597. // For an MDL read, we have to walk the MDL chain in order to
  598. // determine how much data was read. This is because the
  599. // operation may have happened in multiple steps, with the MDLs
  600. // being chained together. For example, part of the read may
  601. // have been satisfied by the fast path, while the rest was
  602. // satisfied using an IRP.
  603. //
  604. readLength = 0;
  605. while ( mdl != NULL ) {
  606. readLength += (USHORT)MmGetMdlByteCount(mdl);
  607. mdl = mdl->Next;
  608. }
  609. } else {
  610. //
  611. // Copy read. The I/O status block has the length.
  612. //
  613. readLength = (USHORT)irp->IoStatus.Information;
  614. }
  615. //
  616. // Update the file position.
  617. //
  618. offset = WorkContext->Parameters.ReadMpx.Offset;
  619. WorkContext->Rfcb->CurrentPosition = offset + readLength;
  620. //
  621. // Update statistics.
  622. //
  623. UPDATE_READ_STATS( WorkContext, readLength );
  624. //
  625. // Special-case 0 bytes read.
  626. //
  627. response = (PRESP_READ_MPX)WorkContext->ResponseParameters;
  628. response->WordCount = 8;
  629. SmbPutUshort( &response->DataCompactionMode, 0 );
  630. SmbPutUshort( &response->Reserved, 0 );
  631. if ( readLength == 0 ) {
  632. SmbPutUlong( &response->Offset, offset );
  633. SmbPutUshort( &response->Count, 0 );
  634. SmbPutUshort( &response->Remaining, 0 );
  635. SmbPutUshort( &response->DataLength, 0 );
  636. SmbPutUshort( &response->DataOffset, 0 );
  637. SmbPutUshort( &response->ByteCount, 0 );
  638. WorkContext->ResponseParameters = NEXT_LOCATION(
  639. response,
  640. RESP_READ_MPX,
  641. 0
  642. );
  643. goto respond;
  644. }
  645. //
  646. // Build the static response header/parameters.
  647. //
  648. SmbPutUshort( &response->Count, readLength );
  649. SmbPutUshort(
  650. &response->DataOffset,
  651. (sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX, Buffer) + 3) & ~3
  652. );
  653. //
  654. // We will use two MDLs to describe the packet we're sending -- one
  655. // for the header and parameters, and another for the data. So we
  656. // set the "response length" to not include the data. This is what
  657. // SrvStartSend uses to set the first MDL's length.
  658. //
  659. // Handling of the second MDL varies depending on whether we did a
  660. // copy read or an MDL read.
  661. //
  662. ASSERT( ((sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX,Buffer)) & 3) == 3 );
  663. WorkContext->ResponseParameters = NEXT_LOCATION(
  664. response,
  665. RESP_READ_MPX,
  666. 1 // pad byte
  667. );
  668. WorkContext->ResponseBuffer->Mdl->ByteCount =
  669. (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  670. (PCHAR)WorkContext->ResponseHeader );
  671. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  672. //
  673. // Start sending fragments.
  674. //
  675. WorkContext->Parameters.ReadMpx.RemainingLength = readLength;
  676. ASSERT( WorkContext->ResponseBuffer->Mdl->Next == NULL );
  677. WorkContext->ResponseBuffer->Mdl->Next =
  678. WorkContext->ResponseBuffer->PartialMdl;
  679. WorkContext->ResponseBuffer->PartialMdl->Next = NULL;
  680. if ( mdlRead ) {
  681. WorkContext->Parameters.ReadMpx.CurrentMdl =
  682. WorkContext->Parameters.ReadMpx.FirstMdl;
  683. WorkContext->Parameters.ReadMpx.CurrentMdlOffset = 0;
  684. (VOID)SendMdlReadMpxFragment( NULL, irp, WorkContext );
  685. } else {
  686. (VOID)SendCopyReadMpxFragment( NULL, irp, WorkContext );
  687. }
  688. Cleanup:
  689. if (bNeedTrace) {
  690. SrvWmiEndContext(WorkContext);
  691. }
  692. return;
  693. } // RestartReadMpx
  694. VOID SRVFASTCALL
  695. SendCopyReadMpxFragment2 (
  696. IN OUT PWORK_CONTEXT WorkContext
  697. )
  698. /*++
  699. Routine Description:
  700. Stub to call actual routine.
  701. Arguments:
  702. WorkContext - Supplies a pointer to the work context block
  703. representing the work item
  704. Return Value:
  705. None.
  706. --*/
  707. {
  708. PAGED_CODE( );
  709. (VOID) SendCopyReadMpxFragment( NULL, WorkContext->Irp, WorkContext );
  710. } // SendCopyReadMpxFragment2
  711. NTSTATUS
  712. SendCopyReadMpxFragment (
  713. IN PDEVICE_OBJECT DeviceObject,
  714. IN PIRP Irp,
  715. IN OUT PWORK_CONTEXT WorkContext
  716. )
  717. /*++
  718. Routine Description:
  719. Sends a Read Mpx response fragment when copy read was used.
  720. Arguments:
  721. WorkContext - Supplies a pointer to the work context block
  722. describing server-specific context for the request.
  723. Return Value:
  724. None.
  725. --*/
  726. {
  727. PRESP_READ_MPX response;
  728. USHORT fragmentSize;
  729. USHORT remainingLength;
  730. ULONG offset;
  731. PCHAR fragmentAddress;
  732. PIO_COMPLETION_ROUTINE sendCompletionRoutine;
  733. UNLOCKABLE_CODE( 8FIL );
  734. //
  735. // Check the status of the send completion.
  736. //
  737. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  738. //
  739. // Turn off cancel boolean
  740. //
  741. Irp->Cancel = FALSE;
  742. //
  743. // Get context.
  744. //
  745. fragmentSize = WorkContext->Parameters.ReadMpx.FragmentSize;
  746. remainingLength = WorkContext->Parameters.ReadMpx.RemainingLength;
  747. offset = WorkContext->Parameters.ReadMpx.Offset;
  748. fragmentAddress = WorkContext->Parameters.ReadMpx.NextFragmentAddress;
  749. //
  750. // If the amount left to send is less than the fragment size, only
  751. // send the remaining amount. Update the remaining amount.
  752. //
  753. if ( remainingLength < fragmentSize ) {
  754. fragmentSize = remainingLength;
  755. }
  756. ASSERT( fragmentSize != 0 );
  757. remainingLength -= fragmentSize;
  758. //
  759. // Build the response parameters.
  760. //
  761. response = (PRESP_READ_MPX)(WorkContext->ResponseHeader + 1);
  762. SmbPutUshort( &response->Remaining, remainingLength );
  763. SmbPutUlong( &response->Offset, offset );
  764. SmbPutUshort( &response->DataLength, fragmentSize );
  765. ASSERT( ((sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX, Buffer)) & 3) == 3 );
  766. SmbPutUshort( &response->ByteCount, fragmentSize + 1 ); // account for padding
  767. //
  768. // Build a partial MDL describing the data.
  769. //
  770. IoBuildPartialMdl(
  771. WorkContext->Parameters.ReadMpx.MpxBufferMdl,
  772. WorkContext->ResponseBuffer->PartialMdl,
  773. fragmentAddress,
  774. fragmentSize
  775. );
  776. //
  777. // Final preparation for the send depends on whether this is the
  778. // last fragment.
  779. //
  780. if ( remainingLength != 0 ) {
  781. //
  782. // Not done. Update context. Set up to restart after the send
  783. // in this routine. We want do this as an FSD restart routine.
  784. // But this may recurse, if the send doesn't pend, so we may use
  785. // up the stack. If we are running out of stack, restart here
  786. // in the FSP.
  787. //
  788. WorkContext->Parameters.ReadMpx.RemainingLength = remainingLength;
  789. WorkContext->Parameters.ReadMpx.Offset += fragmentSize;
  790. WorkContext->Parameters.ReadMpx.NextFragmentAddress += fragmentSize;
  791. if ( IoGetRemainingStackSize() >= STACK_THRESHOLD ) {
  792. DEBUG WorkContext->FsdRestartRoutine = NULL;
  793. sendCompletionRoutine = SendCopyReadMpxFragment;
  794. } else {
  795. DEBUG WorkContext->FsdRestartRoutine = NULL;
  796. WorkContext->FspRestartRoutine = SendCopyReadMpxFragment2;
  797. sendCompletionRoutine = SrvQueueWorkToFspAtSendCompletion;
  798. }
  799. } else {
  800. //
  801. // This is the last fragment. Restart in the cleanup routine.
  802. //
  803. DEBUG WorkContext->FsdRestartRoutine = NULL;
  804. DEBUG WorkContext->FspRestartRoutine = NULL;
  805. sendCompletionRoutine = RestartCopyReadMpxComplete;
  806. }
  807. //
  808. // Send the fragment.
  809. //
  810. WorkContext->ResponseBuffer->DataLength = // +1 for pad
  811. sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX,Buffer) + 1 + fragmentSize;
  812. if ( WorkContext->Endpoint->IsConnectionless ) {
  813. SrvIpxStartSend( WorkContext, sendCompletionRoutine );
  814. } else {
  815. SrvStartSend2( WorkContext, sendCompletionRoutine );
  816. }
  817. return(STATUS_MORE_PROCESSING_REQUIRED);
  818. } // SendCopyReadMpxFragment
  819. VOID SRVFASTCALL
  820. SendMdlReadMpxFragment2 (
  821. IN OUT PWORK_CONTEXT WorkContext
  822. )
  823. /*++
  824. Routine Description:
  825. Stub to call actual routine.
  826. Arguments:
  827. WorkContext - Supplies a pointer to the work context block
  828. representing the work item
  829. Return Value:
  830. None.
  831. --*/
  832. {
  833. PAGED_CODE( );
  834. (VOID) SendMdlReadMpxFragment( NULL, WorkContext->Irp, WorkContext );
  835. } // SendMdlReadMpxFragment2
  836. NTSTATUS
  837. SendMdlReadMpxFragment (
  838. IN PDEVICE_OBJECT DeviceObject,
  839. IN PIRP Irp,
  840. IN OUT PWORK_CONTEXT WorkContext
  841. )
  842. /*++
  843. Routine Description:
  844. Sends a Read Mpx response fragment when MDL read was used.
  845. Arguments:
  846. WorkContext - Supplies a pointer to the work context block
  847. describing server-specific context for the request.
  848. Return Value:
  849. None.
  850. --*/
  851. {
  852. PRESP_READ_MPX response;
  853. PIO_COMPLETION_ROUTINE sendCompletionRoutine;
  854. USHORT fragmentSize;
  855. USHORT remainingLength;
  856. ULONG offset;
  857. PCHAR fragmentAddress;
  858. PMDL mdl;
  859. ULONG mdlOffset;
  860. ULONG partialLength;
  861. ULONG lengthNeeded;
  862. PCHAR startVa;
  863. PCHAR systemVa;
  864. UNLOCKABLE_CODE( 8FIL );
  865. //
  866. // Check the status of the send completion.
  867. //
  868. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  869. //
  870. // Turn off cancel boolean
  871. //
  872. Irp->Cancel = FALSE;
  873. //
  874. // Get context.
  875. //
  876. fragmentSize = WorkContext->Parameters.ReadMpx.FragmentSize,
  877. remainingLength = WorkContext->Parameters.ReadMpx.RemainingLength;
  878. offset = WorkContext->Parameters.ReadMpx.Offset;
  879. //
  880. // If the amount left to send is less than the fragment size, only
  881. // send the remaining amount. Update the remaining amount.
  882. //
  883. if ( remainingLength < fragmentSize ) {
  884. fragmentSize = remainingLength;
  885. }
  886. ASSERT( fragmentSize != 0 );
  887. remainingLength -= fragmentSize;
  888. //
  889. // Build the response parameters.
  890. //
  891. response = (PRESP_READ_MPX)(WorkContext->ResponseHeader + 1);
  892. SmbPutUshort( &response->Remaining, remainingLength );
  893. SmbPutUlong( &response->Offset, offset );
  894. SmbPutUshort( &response->DataLength, fragmentSize );
  895. ASSERT( ((sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX,Buffer)) & 3) == 3 );
  896. SmbPutUshort( &response->ByteCount, fragmentSize + 1 ); // account for padding
  897. //
  898. // If the current MDL doesn't describe all of the data we need to
  899. // send, we need to play some games.
  900. //
  901. MmPrepareMdlForReuse( WorkContext->ResponseBuffer->PartialMdl );
  902. mdl = WorkContext->Parameters.ReadMpx.CurrentMdl;
  903. startVa = MmGetMdlVirtualAddress( mdl );
  904. mdlOffset = WorkContext->Parameters.ReadMpx.CurrentMdlOffset;
  905. partialLength = MmGetMdlByteCount(mdl) - mdlOffset;
  906. if ( partialLength >= fragmentSize ) {
  907. //
  908. // The current MDL has all of the data we need to send. Build
  909. // a partial MDL describing that data.
  910. //
  911. IoBuildPartialMdl(
  912. mdl,
  913. WorkContext->ResponseBuffer->PartialMdl,
  914. startVa + mdlOffset,
  915. fragmentSize
  916. );
  917. //
  918. // Indicate how much data we're taking out of the current MDL.
  919. //
  920. partialLength = fragmentSize;
  921. } else {
  922. //
  923. // The data we need is spread across more than one MDL. Painful
  924. // as this seems, we need to copy the data into the standard
  925. // response buffer. It's possible that we could play some games
  926. // with the MDLs and avoid the copy, but it doesn't seem worth it.
  927. // There is, after all, additional cost in the NDIS driver for
  928. // chaining MDLs together.
  929. //
  930. // *** Note that we still send a second MDL, even though the data
  931. // for this send will abut the response parameters.
  932. //
  933. // Calculate the address of the buffer. Build a partial MDL
  934. // describing it.
  935. //
  936. fragmentAddress = (PCHAR)WorkContext->ResponseBuffer->Buffer +
  937. sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX,Buffer) + 1;
  938. IoBuildPartialMdl(
  939. WorkContext->ResponseBuffer->Mdl,
  940. WorkContext->ResponseBuffer->PartialMdl,
  941. fragmentAddress,
  942. fragmentSize
  943. );
  944. ASSERT( WorkContext->ResponseBuffer->PartialMdl->Next == NULL );
  945. //
  946. // Copy from the current MDL into the buffer.
  947. //
  948. systemVa = MmGetSystemAddressForMdl( mdl );
  949. RtlCopyMemory( fragmentAddress, systemVa + mdlOffset, partialLength );
  950. //
  951. // Update the destination address and set the remaining copy
  952. // amount.
  953. //
  954. fragmentAddress += partialLength;
  955. lengthNeeded = fragmentSize - partialLength;
  956. ASSERT( lengthNeeded != 0 );
  957. do {
  958. //
  959. // Move to the next MDL.
  960. //
  961. mdl = mdl->Next;
  962. ASSERT( mdl != NULL );
  963. //
  964. // Calculate how much we can (and need to) copy out of this
  965. // MDL, and do the copy.
  966. //
  967. startVa = MmGetMdlVirtualAddress( mdl );
  968. partialLength = MIN( MmGetMdlByteCount(mdl), lengthNeeded );
  969. systemVa = MmGetSystemAddressForMdl( mdl );
  970. RtlCopyMemory( fragmentAddress, systemVa, partialLength );
  971. //
  972. // Update the destination address and the remaining copy
  973. // amount. We may be done.
  974. //
  975. fragmentAddress += partialLength;
  976. lengthNeeded -= partialLength;
  977. } while ( lengthNeeded != 0 );
  978. //
  979. // We just copied from the beginning of the current MDL.
  980. //
  981. mdlOffset = 0;
  982. }
  983. //
  984. // Final preparation for the send depends on whether this is the
  985. // last fragment.
  986. //
  987. if ( remainingLength != 0 ) {
  988. //
  989. // Not done. Update the current MDL position. If we have
  990. // finished off the current MDL, move to the next one.
  991. //
  992. mdlOffset += partialLength;
  993. if ( mdlOffset >= MmGetMdlByteCount(mdl) ) {
  994. mdl = mdl->Next;
  995. ASSERT( mdl != NULL );
  996. mdlOffset = 0;
  997. }
  998. //
  999. // Update context. Set up to restart after the send in this
  1000. // routine. We want do this as an FSD restart routine. But
  1001. // this may recurse, if the send doesn't pend, so we may use up
  1002. // the stack. If we are running out of stack, restart here in
  1003. // the FSP.
  1004. //
  1005. WorkContext->Parameters.ReadMpx.CurrentMdl = mdl;
  1006. WorkContext->Parameters.ReadMpx.CurrentMdlOffset = (USHORT)mdlOffset;
  1007. WorkContext->Parameters.ReadMpx.RemainingLength = remainingLength;
  1008. WorkContext->Parameters.ReadMpx.Offset += fragmentSize;
  1009. if ( IoGetRemainingStackSize() >= STACK_THRESHOLD ) {
  1010. DEBUG WorkContext->FsdRestartRoutine = NULL;
  1011. sendCompletionRoutine = SendMdlReadMpxFragment;
  1012. } else {
  1013. DEBUG WorkContext->FsdRestartRoutine = NULL;
  1014. WorkContext->FspRestartRoutine = SendMdlReadMpxFragment2;
  1015. sendCompletionRoutine = SrvQueueWorkToFspAtSendCompletion;
  1016. }
  1017. } else {
  1018. //
  1019. // This is the last fragment. Restart in the cleanup routine.
  1020. //
  1021. DEBUG WorkContext->FsdRestartRoutine = NULL;
  1022. WorkContext->FspRestartRoutine = RestartMdlReadMpxComplete;
  1023. sendCompletionRoutine = SrvQueueWorkToFspAtSendCompletion;
  1024. }
  1025. //
  1026. // Send the fragment.
  1027. //
  1028. WorkContext->ResponseBuffer->DataLength = // +1 for pad
  1029. sizeof(SMB_HEADER) + FIELD_OFFSET(RESP_READ_MPX,Buffer) + 1 + fragmentSize;
  1030. if ( WorkContext->Endpoint->IsConnectionless ) {
  1031. SrvIpxStartSend( WorkContext, sendCompletionRoutine );
  1032. } else {
  1033. SrvStartSend2( WorkContext, sendCompletionRoutine );
  1034. }
  1035. return(STATUS_MORE_PROCESSING_REQUIRED);
  1036. } // SendMdlReadMpxFragment
  1037. NTSTATUS
  1038. RestartCopyReadMpxComplete (
  1039. IN PDEVICE_OBJECT DeviceObject,
  1040. IN PIRP Irp,
  1041. IN OUT PWORK_CONTEXT WorkContext
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. This is the final completion routine for Read Mpx when copy read is
  1046. used. It is called after the send of the last fragment completes.
  1047. Arguments:
  1048. DeviceObject - Pointer to target device object for the request.
  1049. Irp - Pointer to I/O request packet
  1050. WorkContext - Caller-specified context parameter associated with IRP.
  1051. This is actually a pointer to a Work Context block.
  1052. Return Value:
  1053. STATUS_MORE_PROCESSING_REQUIRED.
  1054. --*/
  1055. {
  1056. KIRQL oldIrql;
  1057. UNLOCKABLE_CODE( 8FIL );
  1058. //
  1059. // Check the status of the send completion.
  1060. //
  1061. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  1062. //
  1063. // Reset the IRP cancelled bit.
  1064. //
  1065. Irp->Cancel = FALSE;
  1066. ASSERT( !WorkContext->Parameters.ReadMpx.MdlRead );
  1067. //
  1068. // If we allocated a separate buffer to do the read, free it and its
  1069. // MDL now.
  1070. //
  1071. if ( WorkContext->Parameters.ReadMpx.MpxBuffer != NULL ) {
  1072. DEALLOCATE_NONPAGED_POOL( WorkContext->Parameters.ReadMpx.MpxBuffer );
  1073. IoFreeMdl( WorkContext->Parameters.ReadMpx.MpxBufferMdl );
  1074. }
  1075. WorkContext->ResponseBuffer->Mdl->Next = NULL;
  1076. //
  1077. // Complete and requeue the work item.
  1078. //
  1079. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1080. SrvFsdRestartSmbComplete( WorkContext );
  1081. KeLowerIrql( oldIrql );
  1082. return STATUS_MORE_PROCESSING_REQUIRED;
  1083. } // RestartCopyReadMpxComplete
  1084. VOID SRVFASTCALL
  1085. RestartMdlReadMpxComplete (
  1086. IN OUT PWORK_CONTEXT WorkContext
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This is the final completion routine for Read Mpx when MDL read is
  1091. used. It is called after the send of the last fragment completes.
  1092. Arguments:
  1093. WorkContext - Supplies a pointer to the work context block
  1094. describing server-specific context for the request.
  1095. Return Value:
  1096. None.
  1097. --*/
  1098. {
  1099. NTSTATUS status;
  1100. LARGE_INTEGER offset;
  1101. PAGED_CODE( );
  1102. ASSERT( WorkContext->Parameters.ReadMpx.MdlRead );
  1103. //
  1104. // Give the MDL back to the cache manager. (If the read failed or
  1105. // returned no data, there will be no MDL.)
  1106. //
  1107. MmPrepareMdlForReuse( WorkContext->ResponseBuffer->PartialMdl );
  1108. if ( WorkContext->Parameters.ReadMpx.FirstMdl != NULL ) {
  1109. //KdPrint(( "Freeing MDL chain:\n" ));
  1110. //DumpMdlChain( WorkContext->Parameters.ReadMpx.FirstMdl );
  1111. if( WorkContext->Rfcb->Lfcb->MdlReadComplete == NULL ||
  1112. WorkContext->Rfcb->Lfcb->MdlReadComplete(
  1113. WorkContext->Rfcb->Lfcb->FileObject,
  1114. WorkContext->Parameters.ReadMpx.FirstMdl,
  1115. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  1116. offset.QuadPart = WorkContext->Parameters.ReadMpx.Offset;
  1117. //
  1118. // Fast path didn't work, try an IRP...
  1119. //
  1120. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  1121. WorkContext->Parameters.ReadMpx.FirstMdl,
  1122. IRP_MJ_READ,
  1123. &offset,
  1124. WorkContext->Parameters.ReadMpx.ReadLength
  1125. );
  1126. if( !NT_SUCCESS( status ) ) {
  1127. //
  1128. // All we can do is complain now!
  1129. //
  1130. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  1131. }
  1132. }
  1133. }
  1134. WorkContext->ResponseBuffer->Mdl->Next = NULL;
  1135. //
  1136. // Free the work item by dereferencing it.
  1137. //
  1138. SrvDereferenceWorkItem( WorkContext );
  1139. return;
  1140. } // RestartMdlReadMpxComplete
  1141. VOID SRVFASTCALL
  1142. SrvRestartReceiveWriteMpx (
  1143. IN OUT PWORK_CONTEXT WorkContext
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. This routine replaces the normal restart routine for TDI Receive
  1148. completion when a Write Mpx SMB is received over IPX. If a receive
  1149. error occurs, or if the SMB is invalid, it cleans up the active
  1150. write mpx state that was set up in SrvIpxServerDatagramHandler.
  1151. Arguments:
  1152. WorkContext - Supplies a pointer to the work context block
  1153. describing server-specific context for the request.
  1154. Return Value:
  1155. None.
  1156. --*/
  1157. {
  1158. NTSTATUS status;
  1159. SMB_STATUS smbStatus;
  1160. PCONNECTION connection;
  1161. PIRP irp;
  1162. PSMB_HEADER header;
  1163. ULONG length;
  1164. PAGED_CODE( );
  1165. connection = WorkContext->Connection;
  1166. irp = WorkContext->Irp;
  1167. //
  1168. // Save the length of the received message. Store the length
  1169. // in the work context block for statistics gathering.
  1170. //
  1171. length = (ULONG)irp->IoStatus.Information;
  1172. WorkContext->RequestBuffer->DataLength = length;
  1173. WorkContext->CurrentWorkQueue->stats.BytesReceived += length;
  1174. //
  1175. // Store in the work context block the time at which processing
  1176. // of the request began. Use the time that the work item was
  1177. // queued to the FSP for this purpose.
  1178. //
  1179. WorkContext->StartTime = WorkContext->Timestamp;
  1180. //
  1181. // Update the server network error count. If the TDI receive
  1182. // failed or was canceled, don't try to process an SMB.
  1183. //
  1184. status = irp->IoStatus.Status;
  1185. if ( irp->Cancel || !NT_SUCCESS(status) ) {
  1186. IF_DEBUG(NETWORK_ERRORS) {
  1187. KdPrint(( "SrvRestartReceiveWriteMpx: status = %X for IRP %p\n",
  1188. irp->IoStatus.Status, irp ));
  1189. }
  1190. SrvUpdateErrorCount( &SrvNetworkErrorRecord, TRUE );
  1191. if ( NT_SUCCESS(status) ) status = STATUS_CANCELLED;
  1192. goto cleanup;
  1193. }
  1194. SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE );
  1195. //
  1196. // Initialize the error class and code fields in the header to
  1197. // indicate success.
  1198. //
  1199. header = WorkContext->ResponseHeader;
  1200. SmbPutUlong( &header->ErrorClass, STATUS_SUCCESS );
  1201. //
  1202. // If the connection is closing or the server is shutting down,
  1203. // ignore this SMB.
  1204. //
  1205. if ( (GET_BLOCK_STATE(connection) != BlockStateActive) ||
  1206. SrvFspTransitioning ) {
  1207. goto cleanup;
  1208. }
  1209. //
  1210. // Verify the SMB to make sure that it has a valid header, and that
  1211. // the word count and byte count are within range.
  1212. //
  1213. WorkContext->NextCommand = header->Command;
  1214. if ( !SrvValidateSmb( WorkContext ) ) {
  1215. IF_DEBUG(SMB_ERRORS) {
  1216. KdPrint(( "SrvRestartReceiveWriteMpx: Invalid SMB.\n" ));
  1217. KdPrint(( " SMB received from %z\n",
  1218. (PCSTRING)&WorkContext->Connection->OemClientMachineNameString ));
  1219. }
  1220. //
  1221. // The SMB is invalid. We send back an INVALID_SMB status.
  1222. //
  1223. status = STATUS_INVALID_SMB;
  1224. goto cleanup;
  1225. }
  1226. //
  1227. // Clear the flag that indicates the we just sent an oplock break II
  1228. // to none. This allows subsequent raw reads to be processed.
  1229. //
  1230. //not needed on IPX//connection->BreakIIToNoneJustSent = FALSE;
  1231. //
  1232. // Process the received SMB. The called routine is responsible
  1233. // for sending any response(s) that are needed and for getting
  1234. // the receive buffer back onto the receive queue as soon as
  1235. // possible.
  1236. //
  1237. smbStatus = SrvSmbWriteMpx( WorkContext );
  1238. ASSERT( smbStatus != SmbStatusMoreCommands );
  1239. if ( smbStatus != SmbStatusInProgress ) {
  1240. //
  1241. // Return the TransportContext
  1242. //
  1243. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  1244. TdiReturnChainedReceives( &WorkContext->Parameters.WriteMpx.TransportContext,
  1245. 1
  1246. );
  1247. }
  1248. SrvEndSmbProcessing( WorkContext, smbStatus );
  1249. }
  1250. return;
  1251. cleanup:
  1252. //
  1253. // We will not be processing this write. We still need to check
  1254. // for whether this is the last Write Mpx active on the RFCB, and
  1255. // if so, send the response to the write.
  1256. //
  1257. // *** Note that if we are here because we received an invalid
  1258. // SMB, the completion of the Write Mpx overrides the sending
  1259. // of an error response.
  1260. //
  1261. //
  1262. // Return the TransportContext
  1263. //
  1264. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  1265. TdiReturnChainedReceives( &WorkContext->Parameters.WriteMpx.TransportContext,
  1266. 1
  1267. );
  1268. }
  1269. if ( CheckForWriteMpxComplete( WorkContext ) ) {
  1270. SrvFsdSendResponse( WorkContext );
  1271. } else if ( status == STATUS_INVALID_SMB ) {
  1272. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1273. SrvFsdSendResponse( WorkContext );
  1274. } else {
  1275. SrvDereferenceWorkItem( WorkContext );
  1276. }
  1277. return;
  1278. } // SrvRestartReceiveWriteMpx
  1279. SMB_PROCESSOR_RETURN_TYPE
  1280. SrvSmbWriteMpx (
  1281. SMB_PROCESSOR_PARAMETERS
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. Processes the Write Mpx SMB.
  1286. *** The server currently does not support multiplexed mode reads and
  1287. writes on connection-based transports. When such requests are
  1288. received, the error "use standard mode" is returned.
  1289. Multiplexed mode turns out not to be the performance win it was
  1290. thought to be (on local nets), so we haven't implemented it,
  1291. except over IPX.
  1292. Arguments:
  1293. WorkContext - Supplies a pointer to the work context block
  1294. representing the work item
  1295. Return Value:
  1296. None.
  1297. --*/
  1298. {
  1299. PSMB_HEADER header;
  1300. PREQ_WRITE_MPX request;
  1301. PRESP_WRITE_MPX_DATAGRAM response;
  1302. NTSTATUS status = STATUS_SUCCESS;
  1303. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1304. USHORT fid;
  1305. USHORT mid;
  1306. PRFCB rfcb;
  1307. PLFCB lfcb;
  1308. PWRITE_MPX_CONTEXT writeMpx;
  1309. CLONG bufferOffset;
  1310. PCHAR writeAddress;
  1311. USHORT writeLength;
  1312. ULONG key;
  1313. LARGE_INTEGER offset;
  1314. USHORT writeMode;
  1315. BOOLEAN writeThrough;
  1316. KIRQL oldIrql;
  1317. PMDL mdl;
  1318. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1319. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_MPX;
  1320. SrvWmiStartContext(WorkContext);
  1321. header = WorkContext->RequestHeader;
  1322. request = (PREQ_WRITE_MPX)WorkContext->RequestParameters;
  1323. fid = SmbGetUshort( &request->Fid );
  1324. IF_SMB_DEBUG(MPX1) {
  1325. KdPrint(( "Write Block Multipliexed request; FID 0x%lx, "
  1326. "count %ld, offset %ld\n",
  1327. fid, SmbGetUshort( &request->Count ),
  1328. SmbGetUlong( &request->Offset ) ));
  1329. }
  1330. //
  1331. // Verify the FID. If verified, the RFCB is referenced and its
  1332. // address is stored in the WorkContext block, and the RFCB
  1333. // address is returned.
  1334. //
  1335. writeMode = SmbGetUshort( &request->WriteMode );
  1336. if( (writeMode & SMB_WMODE_DATAGRAM) == 0 ||
  1337. !WorkContext->Endpoint->IsConnectionless ) {
  1338. SrvFsdBuildWriteCompleteResponse( WorkContext, STATUS_SMB_USE_STANDARD, 0 );
  1339. SmbStatus = SmbStatusSendResponse;
  1340. goto Cleanup;
  1341. }
  1342. rfcb = SrvVerifyFid(
  1343. WorkContext,
  1344. fid,
  1345. TRUE,
  1346. SrvRestartSmbReceived, // serialize with raw write
  1347. &status
  1348. );
  1349. if ( rfcb == SRV_INVALID_RFCB_POINTER) {
  1350. if ( !NT_SUCCESS(status) ) {
  1351. //
  1352. // Invalid file ID or write behind error. Reject the request.
  1353. //
  1354. IF_DEBUG(ERRORS) {
  1355. KdPrint((
  1356. "SrvSmbWriteMpx: Status %X on FID: 0x%lx\n",
  1357. status,
  1358. fid
  1359. ));
  1360. }
  1361. goto error;
  1362. }
  1363. //
  1364. // The work item has been queued because a raw write is in
  1365. // progress.
  1366. //
  1367. SmbStatus = SmbStatusInProgress;
  1368. goto Cleanup;
  1369. }
  1370. if( rfcb->Lfcb->Session->IsSessionExpired )
  1371. {
  1372. status = SESSION_EXPIRED_STATUS_CODE;
  1373. SrvFsdBuildWriteCompleteResponse( WorkContext, status, 0 );
  1374. SmbStatus = SmbStatusSendResponse;
  1375. goto Cleanup;
  1376. }
  1377. //
  1378. // Verify that the client has write access to the file via the
  1379. // specified handle.
  1380. //
  1381. if( !rfcb->MpxWritesOk ) {
  1382. if ( !rfcb->WriteAccessGranted && !rfcb->AppendAccessGranted ) {
  1383. SrvStatistics.GrantedAccessErrors++;
  1384. IF_DEBUG(ERRORS) {
  1385. KdPrint(( "SrvSmbWriteMpx: Write access not granted.\n"));
  1386. }
  1387. status = STATUS_ACCESS_DENIED;
  1388. goto error;
  1389. }
  1390. //
  1391. // If this is not a disk or a print file tell the client to use core write.
  1392. //
  1393. if ( rfcb->ShareType != ShareTypeDisk &&
  1394. rfcb->ShareType != ShareTypePrint ) {
  1395. status = STATUS_SMB_USE_STANDARD;
  1396. goto error;
  1397. }
  1398. rfcb->MpxWritesOk = TRUE;
  1399. }
  1400. rfcb->WrittenTo = TRUE;
  1401. //
  1402. // If this a stale packet, ignore it. Stale here means that the MID
  1403. // of the packet is not equal to the MID of the current write mux.
  1404. // Such a packet can be received if a duplicate packet from a
  1405. // previous write mux is delivered after a new write mux starts.
  1406. //
  1407. writeMpx = &rfcb->WriteMpx;
  1408. mid = SmbGetAlignedUshort( &header->Mid );
  1409. if ( mid != writeMpx->Mid ) {
  1410. //
  1411. // Set the sequence number to 0 so that we don't send a response
  1412. // unless we have to because the Write Mpx refcount drops to 0.
  1413. //
  1414. SmbPutAlignedUshort( &header->SequenceNumber, 0 );
  1415. goto error;
  1416. }
  1417. //
  1418. // Get the file offset.
  1419. //
  1420. offset.QuadPart = SmbGetUlong( &request->Offset );
  1421. //
  1422. // Determine the amount of data to write. This is the minimum of
  1423. // the amount requested by the client and the amount of data
  1424. // actually sent in the request buffer.
  1425. //
  1426. bufferOffset = SmbGetUshort( &request->DataOffset );
  1427. //
  1428. // If we have the transport context, then setup WriteAddress accordingly.
  1429. //
  1430. WorkContext->Parameters.WriteMpx.DataMdl = NULL;
  1431. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  1432. writeAddress = (PCHAR)WorkContext->Parameters.WriteMpx.Buffer + bufferOffset;
  1433. } else {
  1434. writeAddress = (PCHAR)header + bufferOffset;
  1435. }
  1436. writeLength =
  1437. (USHORT)(MIN( (CLONG)SmbGetUshort( &request->DataLength ),
  1438. WorkContext->ResponseBuffer->DataLength - bufferOffset ));
  1439. //
  1440. // Save context for the restart routine.
  1441. //
  1442. WorkContext->Parameters.WriteMpx.WriteLength = writeLength;
  1443. //
  1444. // Form the lock key using the FID and the PID.
  1445. //
  1446. // *** The FID must be included in the key in order to account for
  1447. // the folding of multiple remote compatibility mode opens into
  1448. // a single local open.
  1449. //
  1450. key = rfcb->ShiftedFid | SmbGetAlignedUshort( &header->Pid );
  1451. //
  1452. // If this is the first packet of a new MID, set up to glom the
  1453. // packets into one big write.
  1454. //
  1455. lfcb = rfcb->Lfcb;
  1456. if ( WorkContext->Parameters.WriteMpx.FirstPacketOfGlom ) {
  1457. //
  1458. // Try the fast path first.
  1459. //
  1460. WorkContext->Irp->MdlAddress = NULL;
  1461. WorkContext->Irp->IoStatus.Information = 0;
  1462. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1463. ASSERT( lfcb->FileObject->Flags & FO_CACHE_SUPPORTED );
  1464. writeLength = SmbGetUshort( &request->Count );
  1465. writeMpx->StartOffset = offset.LowPart;
  1466. writeMpx->Length = writeLength;
  1467. if ( lfcb->PrepareMdlWrite &&
  1468. lfcb->PrepareMdlWrite(
  1469. lfcb->FileObject,
  1470. &offset,
  1471. writeLength,
  1472. key,
  1473. &WorkContext->Irp->MdlAddress,
  1474. &WorkContext->Irp->IoStatus,
  1475. lfcb->DeviceObject
  1476. ) && WorkContext->Irp->MdlAddress != NULL ) {
  1477. //
  1478. // The fast I/O path worked.
  1479. //
  1480. WorkContext->bAlreadyTrace = TRUE;
  1481. RestartPrepareMpxMdlWrite( WorkContext );
  1482. SmbStatus = SmbStatusInProgress;
  1483. goto Cleanup;
  1484. }
  1485. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1486. //
  1487. // The fast I/O path failed. Build the write request, reusing the
  1488. // receive IRP.
  1489. //
  1490. // The fast path may have partially succeeded, returning a partial
  1491. // MDL chain. We need to adjust our write request to account for
  1492. // that.
  1493. //
  1494. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  1495. writeLength -= (USHORT)WorkContext->Irp->IoStatus.Information;
  1496. SrvBuildReadOrWriteRequest(
  1497. WorkContext->Irp, // input IRP address
  1498. lfcb->FileObject, // target file object address
  1499. WorkContext, // context
  1500. IRP_MJ_WRITE, // major function code
  1501. IRP_MN_MDL, // minor function code
  1502. NULL, // buffer address (ignored)
  1503. writeLength, // buffer length
  1504. WorkContext->Irp->MdlAddress, // MDL address
  1505. offset, // byte offset
  1506. key // lock key
  1507. );
  1508. //
  1509. // Pass the request to the file system.
  1510. //
  1511. WorkContext->bAlreadyTrace = TRUE;
  1512. WorkContext->FsdRestartRoutine = RestartPrepareMpxMdlWrite;
  1513. DEBUG WorkContext->FspRestartRoutine = NULL;
  1514. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1515. //
  1516. // The MDL write has been started. When it completes, processing
  1517. // resumes at RestartPrepareMpxMdlWrite.
  1518. //
  1519. SmbStatus = SmbStatusInProgress;
  1520. goto Cleanup;
  1521. }
  1522. //
  1523. // Save context for the restart routine.
  1524. //
  1525. WorkContext->Parameters.WriteMpx.Offset = offset.LowPart;
  1526. WorkContext->Parameters.WriteMpx.Mid = mid;
  1527. if ( writeMpx->GlomPending ) {
  1528. //
  1529. // A glom setup is pending. Wait for that to complete.
  1530. //
  1531. ACQUIRE_SPIN_LOCK( &rfcb->Connection->SpinLock, &oldIrql );
  1532. if ( writeMpx->GlomPending ) {
  1533. InsertTailList(
  1534. &writeMpx->GlomDelayList,
  1535. &WorkContext->ListEntry
  1536. );
  1537. RELEASE_SPIN_LOCK( &rfcb->Connection->SpinLock, oldIrql );
  1538. SmbStatus = SmbStatusInProgress;
  1539. goto Cleanup;
  1540. }
  1541. RELEASE_SPIN_LOCK( &rfcb->Connection->SpinLock, oldIrql );
  1542. }
  1543. if ( writeMpx->Glomming ) {
  1544. //
  1545. // We're glomming this into one big write. Add the data from
  1546. // this packet.
  1547. //
  1548. AddPacketToGlom( WorkContext );
  1549. SmbStatus = SmbStatusInProgress;
  1550. goto Cleanup;
  1551. }
  1552. //
  1553. // We are not glomming this write, because we missed the first
  1554. // packet of the write. So we write each block as it arrives.
  1555. //
  1556. // If the file's writethrough mode needs to be changed, do so now.
  1557. //
  1558. writeThrough = (BOOLEAN)((writeMode & SMB_WMODE_WRITE_THROUGH) != 0);
  1559. if ( writeThrough && (lfcb->FileMode & FILE_WRITE_THROUGH) == 0
  1560. || !writeThrough && (lfcb->FileMode & FILE_WRITE_THROUGH) != 0 ) {
  1561. SrvSetFileWritethroughMode( lfcb, writeThrough );
  1562. }
  1563. //
  1564. // Try the fast I/O path first. If that fails, fall through to the
  1565. // normal build-an-IRP path.
  1566. //
  1567. if ( lfcb->FastIoWrite != NULL ) {
  1568. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1569. try {
  1570. if ( lfcb->FastIoWrite(
  1571. lfcb->FileObject,
  1572. &offset,
  1573. writeLength,
  1574. TRUE,
  1575. key,
  1576. writeAddress,
  1577. &WorkContext->Irp->IoStatus,
  1578. lfcb->DeviceObject
  1579. ) ) {
  1580. //
  1581. // The fast I/O path worked. Call the restart routine directly
  1582. // to do postprocessing (including sending the response).
  1583. //
  1584. WorkContext->bAlreadyTrace = TRUE;
  1585. RestartWriteMpx( WorkContext );
  1586. SmbStatus = SmbStatusInProgress;
  1587. goto Cleanup;
  1588. }
  1589. }
  1590. except( EXCEPTION_EXECUTE_HANDLER ) {
  1591. // Fall through to the slow path on an exception
  1592. status = GetExceptionCode();
  1593. IF_DEBUG(ERRORS) {
  1594. KdPrint(("FastIoRead threw exception %x\n", status ));
  1595. }
  1596. }
  1597. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1598. }
  1599. //
  1600. // The turbo path failed. Build the write request, reusing the
  1601. // receive IRP.
  1602. //
  1603. // Build an MDL describing the write buffer. Note that if the file
  1604. // system can complete the write immediately, the MDL isn't really
  1605. // needed, but if the file system must send the request to its FSP,
  1606. // the MDL _is_ needed.
  1607. //
  1608. // *** Note the assumption that the request buffer already has a
  1609. // valid full MDL from which a partial MDL can be built.
  1610. //
  1611. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  1612. mdl = IoAllocateMdl(
  1613. writeAddress,
  1614. writeLength,
  1615. FALSE,
  1616. FALSE,
  1617. NULL
  1618. );
  1619. if ( mdl == NULL ) {
  1620. status = STATUS_INSUFF_SERVER_RESOURCES;
  1621. goto error;
  1622. }
  1623. //
  1624. // Build the mdl.
  1625. //
  1626. MmBuildMdlForNonPagedPool( mdl );
  1627. WorkContext->Parameters.WriteMpx.DataMdl = mdl;
  1628. } else {
  1629. mdl = WorkContext->RequestBuffer->PartialMdl;
  1630. IoBuildPartialMdl(
  1631. WorkContext->RequestBuffer->Mdl,
  1632. mdl,
  1633. writeAddress,
  1634. writeLength
  1635. );
  1636. }
  1637. //
  1638. // Build the IRP.
  1639. //
  1640. SrvBuildReadOrWriteRequest(
  1641. WorkContext->Irp, // input IRP address
  1642. lfcb->FileObject, // target file object address
  1643. WorkContext, // context
  1644. IRP_MJ_WRITE, // major function code
  1645. 0, // minor function code
  1646. writeAddress, // buffer address
  1647. writeLength, // buffer length
  1648. mdl, // MDL address
  1649. offset, // byte offset
  1650. key // lock key
  1651. );
  1652. //
  1653. // Pass the request to the file system.
  1654. //
  1655. WorkContext->bAlreadyTrace = TRUE;
  1656. WorkContext->FsdRestartRoutine = RestartWriteMpx;
  1657. DEBUG WorkContext->FspRestartRoutine = NULL;
  1658. IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1659. //
  1660. // The write has been started. Control will return to
  1661. // RestartWriteMpx when the write completes.
  1662. //
  1663. SmbStatus = SmbStatusInProgress;
  1664. goto Cleanup;
  1665. error:
  1666. //
  1667. // There is an error of some sort. We still need to check for
  1668. // whether this is the last Write Mpx active on the RFCB, and if so,
  1669. // send the response to the write instead of the error. If this is
  1670. // not the last active mux request, then we either send an error
  1671. // response (non-datagram write mux or sequenced write mux) or
  1672. // ignore this request (unsequenced datagram). Note that if this is
  1673. // a non-datagram write mux, then we didn't come in over IPX, and we
  1674. // didn't bump the Write Mpx refcount.
  1675. //
  1676. //
  1677. // Return the TransportContext
  1678. //
  1679. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  1680. TdiReturnChainedReceives( &WorkContext->Parameters.WriteMpx.TransportContext,
  1681. 1
  1682. );
  1683. }
  1684. if ( WorkContext->Rfcb && CheckForWriteMpxComplete( WorkContext ) ) {
  1685. SmbStatus = SmbStatusSendResponse;
  1686. goto Cleanup;
  1687. }
  1688. if ( SmbGetAlignedUshort(&header->SequenceNumber) != 0 ) {
  1689. SrvSetSmbError2( WorkContext, status, TRUE );
  1690. response = (PRESP_WRITE_MPX_DATAGRAM)WorkContext->ResponseParameters;
  1691. response->WordCount = 2;
  1692. SmbPutUlong( &response->Mask, 0 );
  1693. SmbPutUshort( &response->ByteCount, 0 );
  1694. WorkContext->ResponseParameters = NEXT_LOCATION(
  1695. response,
  1696. RESP_WRITE_MPX_DATAGRAM,
  1697. 0
  1698. );
  1699. SmbStatus = SmbStatusSendResponse;
  1700. goto Cleanup;
  1701. }
  1702. SmbStatus = SmbStatusNoResponse;
  1703. Cleanup:
  1704. SrvWmiEndContext(WorkContext);
  1705. return SmbStatus;
  1706. } // SrvSmbWriteMpx
  1707. VOID SRVFASTCALL
  1708. RestartWriteMpx (
  1709. IN OUT PWORK_CONTEXT WorkContext
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. Processes file write completion for a Write MPX SMB.
  1714. Arguments:
  1715. WorkContext - Supplies a pointer to the work context block
  1716. describing server-specific context for the request.
  1717. Return Value:
  1718. None.
  1719. --*/
  1720. {
  1721. PSMB_HEADER header;
  1722. PREQ_WRITE_MPX request;
  1723. BOOLEAN rfcbClosing;
  1724. PRESP_WRITE_MPX_DATAGRAM response;
  1725. NTSTATUS status = STATUS_SUCCESS;
  1726. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1727. PRFCB rfcb;
  1728. PWRITE_MPX_CONTEXT writeMpx;
  1729. PCONNECTION connection;
  1730. KIRQL oldIrql;
  1731. USHORT writeLength;
  1732. LARGE_INTEGER position;
  1733. USHORT sequenceNumber;
  1734. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  1735. IF_DEBUG(FSD2) KdPrint(( " - RestartWriteMpx\n" ));
  1736. if (bNeedTrace) {
  1737. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1738. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_MPX;
  1739. SrvWmiStartContext(WorkContext);
  1740. }
  1741. else
  1742. WorkContext->bAlreadyTrace = FALSE;
  1743. header = WorkContext->RequestHeader;
  1744. request = (PREQ_WRITE_MPX)WorkContext->RequestParameters;
  1745. response = (PRESP_WRITE_MPX_DATAGRAM)WorkContext->ResponseParameters;
  1746. rfcb = WorkContext->Rfcb;
  1747. connection = WorkContext->Connection;
  1748. status = WorkContext->Irp->IoStatus.Status;
  1749. //
  1750. // Return the TransportContext
  1751. //
  1752. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  1753. TdiReturnChainedReceives( &WorkContext->Parameters.WriteMpx.TransportContext,
  1754. 1
  1755. );
  1756. WorkContext->Parameters.WriteMpx.TransportContext = NULL;
  1757. }
  1758. //
  1759. // Free the data Mdl.
  1760. //
  1761. if ( WorkContext->Parameters.WriteMpx.DataMdl ) {
  1762. IoFreeMdl( WorkContext->Parameters.WriteMpx.DataMdl );
  1763. WorkContext->Parameters.WriteMpx.DataMdl = NULL;
  1764. }
  1765. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1766. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  1767. //
  1768. // If we're entered at dispatch level, and the write failed,
  1769. // or there is a saved error, or the rfcb is closing, then
  1770. // we need to have a worker thread call this routine.
  1771. //
  1772. if ( ((status != STATUS_SUCCESS) ||
  1773. (rfcb->SavedError != STATUS_SUCCESS) ||
  1774. (GET_BLOCK_STATE(rfcb) != BlockStateActive)) &&
  1775. (oldIrql >= DISPATCH_LEVEL) ) {
  1776. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1777. WorkContext->FspRestartRoutine = RestartWriteMpx;
  1778. QUEUE_WORK_TO_FSP( WorkContext );
  1779. KeLowerIrql( oldIrql );
  1780. goto Cleanup;
  1781. }
  1782. //
  1783. // If this write is from a previous mux (meaning that a new one was
  1784. // started while we were doing this write), toss this request.
  1785. //
  1786. writeMpx = &rfcb->WriteMpx;
  1787. if ( WorkContext->Parameters.WriteMpx.Mid != writeMpx->Mid ) {
  1788. goto check_for_mux_end;
  1789. }
  1790. if ( !NT_SUCCESS(status) ) {
  1791. //
  1792. // The write failed. Remember the failure in the RFCB.
  1793. //
  1794. IF_DEBUG(ERRORS) KdPrint(( "Write failed: %X\n", status ));
  1795. if ( rfcb->SavedError == STATUS_SUCCESS ) {
  1796. rfcb->SavedError = status;
  1797. }
  1798. } else {
  1799. //
  1800. // The write succeeded. Update the information in the write mpx
  1801. // context block.
  1802. //
  1803. // !!! Need to deal with mask shifting by the redir and delayed
  1804. // packets.
  1805. //
  1806. #if 0
  1807. MpxDelay = !MpxDelay;
  1808. if ( MpxDelay ) {
  1809. LARGE_INTEGER interval;
  1810. interval.QuadPart = -10*1000*100;
  1811. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  1812. }
  1813. #endif
  1814. writeMpx->Mask |= SmbGetUlong( &request->Mask );
  1815. }
  1816. //
  1817. // Save the count of bytes written, to be used to update the server
  1818. // statistics database.
  1819. //
  1820. writeLength = (USHORT)WorkContext->Irp->IoStatus.Information;
  1821. UPDATE_WRITE_STATS( WorkContext, writeLength );
  1822. IF_SMB_DEBUG(MPX1) {
  1823. KdPrint(( "RestartWriteMpx: Fid 0x%lx, wrote %ld bytes\n",
  1824. rfcb->Fid, writeLength ));
  1825. }
  1826. //
  1827. // If this is an unsequenced request, we're done. We don't respond
  1828. // until we get a sequenced request.
  1829. //
  1830. sequenceNumber = SmbGetAlignedUshort( &header->SequenceNumber );
  1831. if ( sequenceNumber == 0 ) {
  1832. goto check_for_mux_end;
  1833. }
  1834. //
  1835. // This is the last request in this mux sent by the client. Save
  1836. // the sequence number and update the file position.
  1837. //
  1838. writeMpx->SequenceNumber = sequenceNumber;
  1839. rfcb->CurrentPosition = WorkContext->Parameters.WriteMpx.Offset + writeLength;
  1840. check_for_mux_end:
  1841. //
  1842. // If we have received the sequenced command for this write mux,
  1843. // and this is the last active command, then it's time to send
  1844. // the response. Otherwise, we are done with this SMB.
  1845. //
  1846. if ( --writeMpx->ReferenceCount != 0 ) {
  1847. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1848. SrvFsdRestartSmbComplete( WorkContext );
  1849. KeLowerIrql( oldIrql );
  1850. goto Cleanup;
  1851. }
  1852. //
  1853. // WriteMpx refcount is 0.
  1854. //
  1855. rfcbClosing = (GET_BLOCK_STATE(rfcb) != BlockStateActive);
  1856. if ( writeMpx->SequenceNumber == 0 ) {
  1857. //
  1858. // If the rfcb is closing, complete the cleanup.
  1859. //
  1860. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1861. KeLowerIrql( oldIrql );
  1862. if ( rfcbClosing ) {
  1863. RestartWriteMpxCompleteRfcbClose( WorkContext );
  1864. }
  1865. if( oldIrql >= DISPATCH_LEVEL ) {
  1866. SrvFsdRestartSmbComplete( WorkContext );
  1867. } else {
  1868. SrvRestartFsdComplete( WorkContext );
  1869. }
  1870. goto Cleanup;
  1871. }
  1872. //
  1873. // We are done with this write mux. Save the accumulated mask, the
  1874. // sequence number, and the original MID, then clear the mask and
  1875. // sequence number to indicate that we no longer are in the middle
  1876. // of a write mux.
  1877. //
  1878. SmbPutUlong( &response->Mask, writeMpx->Mask );
  1879. writeMpx->Mask = 0;
  1880. SmbPutAlignedUshort( &header->SequenceNumber, writeMpx->SequenceNumber );
  1881. writeMpx->SequenceNumber = 0;
  1882. SmbPutAlignedUshort( &header->Mid, writeMpx->Mid );
  1883. //
  1884. // Save the status.
  1885. //
  1886. status = rfcb->SavedError;
  1887. rfcb->SavedError = STATUS_SUCCESS;
  1888. //
  1889. // Now we can release the lock.
  1890. //
  1891. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1892. KeLowerIrql( oldIrql );
  1893. //
  1894. // Complete the rfcb close.
  1895. //
  1896. if ( rfcbClosing ) {
  1897. RestartWriteMpxCompleteRfcbClose( WorkContext );
  1898. }
  1899. //
  1900. // Build the response message.
  1901. //
  1902. if ( !NT_SUCCESS(status) ) {
  1903. SrvSetSmbError2( WorkContext, status, TRUE );
  1904. }
  1905. response->WordCount = 2;
  1906. SmbPutUshort( &response->ByteCount, 0 );
  1907. WorkContext->ResponseParameters = NEXT_LOCATION(
  1908. response,
  1909. RESP_WRITE_MPX_DATAGRAM,
  1910. 0
  1911. );
  1912. //
  1913. // Send the response.
  1914. //
  1915. SrvFsdSendResponse( WorkContext );
  1916. Cleanup:
  1917. if (bNeedTrace) {
  1918. SrvWmiEndContext(WorkContext);
  1919. }
  1920. return;
  1921. } // RestartWriteMpx
  1922. BOOLEAN
  1923. CheckForWriteMpxComplete (
  1924. IN OUT PWORK_CONTEXT WorkContext
  1925. )
  1926. {
  1927. PSMB_HEADER header;
  1928. PRESP_WRITE_MPX_DATAGRAM response;
  1929. NTSTATUS status;
  1930. PRFCB rfcb = WorkContext->Rfcb;
  1931. PWRITE_MPX_CONTEXT writeMpx = &rfcb->WriteMpx;
  1932. PCONNECTION connection = WorkContext->Connection;
  1933. KIRQL oldIrql;
  1934. //
  1935. // If we have not received the sequenced command for this write mux,
  1936. // or this is not the last active command, then return FALSE.
  1937. // Otherwise, it's time to send the response, so build it and return
  1938. // TRUE.
  1939. //
  1940. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1941. if ( --writeMpx->ReferenceCount != 0 ) {
  1942. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1943. return(FALSE);
  1944. }
  1945. //
  1946. // WriteMpx refcount is 0.
  1947. //
  1948. if ( writeMpx->SequenceNumber == 0 ) {
  1949. //
  1950. // If the rfcb is closing, complete the cleanup.
  1951. //
  1952. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  1953. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1954. RestartWriteMpxCompleteRfcbClose( WorkContext );
  1955. } else {
  1956. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1957. }
  1958. return FALSE;
  1959. }
  1960. //
  1961. // We are done with this write mux. Save the accumulated mask, the
  1962. // sequence number, and the original MID, then clear the mask and
  1963. // sequence number to indicate that we no longer are in the middle
  1964. // of a write mux.
  1965. //
  1966. header = WorkContext->ResponseHeader;
  1967. response = (PRESP_WRITE_MPX_DATAGRAM)WorkContext->ResponseParameters;
  1968. SmbPutUlong( &response->Mask, writeMpx->Mask );
  1969. writeMpx->Mask = 0;
  1970. SmbPutAlignedUshort( &header->SequenceNumber, writeMpx->SequenceNumber );
  1971. writeMpx->SequenceNumber = 0;
  1972. SmbPutAlignedUshort( &header->Mid, writeMpx->Mid );
  1973. //
  1974. // Save the status.
  1975. //
  1976. status = rfcb->SavedError;
  1977. rfcb->SavedError = STATUS_SUCCESS;
  1978. //
  1979. // Now we can release the lock.
  1980. //
  1981. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  1982. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1983. RestartWriteMpxCompleteRfcbClose( WorkContext );
  1984. } else {
  1985. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1986. }
  1987. //
  1988. // Build the response message.
  1989. //
  1990. if ( !NT_SUCCESS(status) ) {
  1991. SrvSetSmbError2( WorkContext, status, TRUE );
  1992. }
  1993. response->WordCount = 2;
  1994. SmbPutUshort( &response->ByteCount, 0 );
  1995. WorkContext->ResponseParameters = NEXT_LOCATION(
  1996. response,
  1997. RESP_WRITE_MPX_DATAGRAM,
  1998. 0
  1999. );
  2000. return TRUE;
  2001. } // CheckForWriteMpxComplete
  2002. VOID SRVFASTCALL
  2003. RestartPrepareMpxMdlWrite (
  2004. IN OUT PWORK_CONTEXT WorkContext
  2005. )
  2006. {
  2007. PSMB_HEADER header;
  2008. PREQ_WRITE_MPX request;
  2009. PRFCB rfcb;
  2010. PWRITE_MPX_CONTEXT writeMpx;
  2011. PCONNECTION connection;
  2012. PLIST_ENTRY listEntry;
  2013. PWORK_CONTEXT workContext;
  2014. USHORT writeLength;
  2015. PCHAR writeAddress;
  2016. KIRQL oldIrql;
  2017. ULONG bytesCopied;
  2018. NTSTATUS status = STATUS_SUCCESS;
  2019. SMB_STATUS SmbStatus = SmbStatusInProgress;
  2020. PMDL mdl;
  2021. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  2022. if (bNeedTrace) {
  2023. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  2024. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_MPX;
  2025. SrvWmiStartContext(WorkContext);
  2026. }
  2027. else
  2028. WorkContext->bAlreadyTrace = FALSE;
  2029. header = WorkContext->RequestHeader;
  2030. request = (PREQ_WRITE_MPX)WorkContext->RequestParameters;
  2031. rfcb = WorkContext->Rfcb;
  2032. writeMpx = &rfcb->WriteMpx;
  2033. connection = WorkContext->Connection;
  2034. //
  2035. // If the MDL write preparation succeeded, copy the data from this
  2036. // packet into the cache. If it failed, toss this packet.
  2037. //
  2038. if( NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  2039. mdl = WorkContext->Irp->MdlAddress;
  2040. #if DBG
  2041. IF_SMB_DEBUG(MPX2) {
  2042. KdPrint(( "RestartPrepareMpxMdlWrite: rfcb %p, input chain:\n", rfcb ));
  2043. DumpMdlChain( mdl );
  2044. }
  2045. #endif
  2046. writeMpx->MdlChain = mdl;
  2047. writeMpx->NumberOfRuns = 1;
  2048. writeMpx->RunList[0].Offset = 0;
  2049. writeLength = WorkContext->Parameters.WriteMpx.WriteLength;
  2050. writeMpx->RunList[0].Length = writeLength;
  2051. //
  2052. // If we have the transport context, setup writeAddress accordingly.
  2053. //
  2054. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  2055. writeAddress = (PCHAR)WorkContext->Parameters.WriteMpx.Buffer +
  2056. SmbGetUshort( &request->DataOffset );
  2057. } else {
  2058. writeAddress = (PCHAR)WorkContext->ResponseHeader +
  2059. SmbGetUshort( &request->DataOffset );
  2060. }
  2061. status = TdiCopyBufferToMdl(
  2062. writeAddress,
  2063. 0,
  2064. writeLength,
  2065. mdl,
  2066. 0,
  2067. &bytesCopied
  2068. );
  2069. ASSERT( status == STATUS_SUCCESS );
  2070. ASSERT( bytesCopied == writeLength );
  2071. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  2072. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2073. writeMpx->Glomming = TRUE;
  2074. ASSERT( writeMpx->Mask == 0 );
  2075. writeMpx->Mask = SmbGetUlong( &request->Mask );
  2076. --writeMpx->ReferenceCount;
  2077. ASSERT( writeMpx->SequenceNumber == 0 );
  2078. } else {
  2079. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  2080. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2081. if ( rfcb->SavedError == STATUS_SUCCESS ) {
  2082. rfcb->SavedError = WorkContext->Irp->IoStatus.Status;
  2083. }
  2084. --writeMpx->ReferenceCount;
  2085. writeMpx->Glomming = FALSE;
  2086. }
  2087. //
  2088. // Return the TransportContext
  2089. //
  2090. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  2091. TdiReturnChainedReceives( &WorkContext->Parameters.WriteMpx.TransportContext,
  2092. 1
  2093. );
  2094. }
  2095. writeMpx->GlomPending = FALSE;
  2096. while ( !IsListEmpty( &writeMpx->GlomDelayList ) ) {
  2097. listEntry = RemoveHeadList( &writeMpx->GlomDelayList );
  2098. workContext = CONTAINING_RECORD( listEntry, WORK_CONTEXT, ListEntry );
  2099. workContext->FspRestartRoutine = AddPacketToGlom;
  2100. QUEUE_WORK_TO_FSP( workContext );
  2101. }
  2102. //
  2103. // If the rfcb is closing and the write mpx ref count == 0,
  2104. // then we must complete the close.
  2105. //
  2106. if ( (GET_BLOCK_STATE(rfcb) != BlockStateActive) &&
  2107. (writeMpx->ReferenceCount == 0) ) {
  2108. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2109. WorkContext->FspRestartRoutine = RestartWriteMpxCompleteRfcbClose;
  2110. QUEUE_WORK_TO_FSP( WorkContext );
  2111. KeLowerIrql( oldIrql );
  2112. goto Cleanup;
  2113. }
  2114. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2115. SrvFsdRestartSmbComplete( WorkContext );
  2116. KeLowerIrql( oldIrql );
  2117. Cleanup:
  2118. if (bNeedTrace) {
  2119. SrvWmiEndContext(WorkContext);
  2120. }
  2121. return;
  2122. } // RestartPrepareMpxMdlWrite
  2123. VOID SRVFASTCALL
  2124. AddPacketToGlom (
  2125. IN OUT PWORK_CONTEXT WorkContext
  2126. )
  2127. {
  2128. PSMB_HEADER header;
  2129. PREQ_WRITE_MPX request;
  2130. PRESP_WRITE_MPX_DATAGRAM response;
  2131. PRFCB rfcb;
  2132. PWRITE_MPX_CONTEXT writeMpx;
  2133. PCONNECTION connection;
  2134. ULONG fileOffset;
  2135. USHORT glomOffset;
  2136. CLONG bufferOffset;
  2137. PCHAR writeAddress;
  2138. USHORT writeLength;
  2139. ULONG bytesCopied;
  2140. KIRQL oldIrql;
  2141. NTSTATUS status = STATUS_UNSUCCESSFUL;
  2142. USHORT sequenceNumber;
  2143. BOOLEAN rfcbClosing;
  2144. PWRITE_MPX_RUN run, nextRun;
  2145. ULONG runIndex, runCount;
  2146. USHORT runOffset;
  2147. USHORT runLength;
  2148. PMDL cacheMdl;
  2149. LARGE_INTEGER cacheOffset;
  2150. header = WorkContext->RequestHeader;
  2151. request = (PREQ_WRITE_MPX)WorkContext->RequestParameters;
  2152. rfcb = WorkContext->Rfcb;
  2153. connection = WorkContext->Connection;
  2154. writeMpx = &rfcb->WriteMpx;
  2155. cacheMdl = writeMpx->MdlChain;
  2156. if( writeMpx->Glomming == FALSE ) {
  2157. //
  2158. // We must have encountered an error in RestartPrepareMpxMdlWrite(), but
  2159. // we call through this routine to ensure we send a response back to the
  2160. // client.
  2161. //
  2162. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  2163. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2164. goto check;
  2165. }
  2166. ASSERT( writeMpx->Glomming );
  2167. ASSERT( !writeMpx->GlomPending );
  2168. ASSERT( WorkContext->Parameters.WriteMpx.Mid == writeMpx->Mid );
  2169. //
  2170. // Get the file offset of this packet's data.
  2171. //
  2172. fileOffset = WorkContext->Parameters.WriteMpx.Offset;
  2173. //
  2174. // Determine the amount of data to write. This is the minimum of
  2175. // the amount requested by the client and the amount of data
  2176. // actually sent in the request buffer.
  2177. //
  2178. bufferOffset = SmbGetUshort( &request->DataOffset );
  2179. //
  2180. // If we have the transport context, setup writeAddress accordingly.
  2181. //
  2182. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  2183. writeAddress = (PCHAR)WorkContext->Parameters.WriteMpx.Buffer +
  2184. bufferOffset;
  2185. } else {
  2186. writeAddress = (PCHAR)header + bufferOffset;
  2187. }
  2188. writeLength = WorkContext->Parameters.WriteMpx.WriteLength;
  2189. ASSERT( writeLength <= 0xffff );
  2190. //
  2191. // If the data doesn't fall within the bounds of the glommed write,
  2192. // discard the packet.
  2193. //
  2194. // We always know that we've copied at least the first part of the
  2195. // glom.
  2196. //
  2197. ASSERT( writeMpx->NumberOfRuns > 0 );
  2198. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  2199. if ( fileOffset <= writeMpx->StartOffset ) {
  2200. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2201. goto discard;
  2202. }
  2203. fileOffset -= writeMpx->StartOffset;
  2204. if ( (fileOffset + writeLength) > writeMpx->Length ) {
  2205. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2206. goto discard;
  2207. }
  2208. ASSERT( fileOffset <= 0xffff );
  2209. ASSERT( fileOffset + writeLength <= 0xffff );
  2210. glomOffset = (USHORT)fileOffset;
  2211. //
  2212. // Copy the packet data into the glom.
  2213. //
  2214. status = TdiCopyBufferToMdl(
  2215. writeAddress,
  2216. 0,
  2217. writeLength,
  2218. cacheMdl,
  2219. glomOffset,
  2220. &bytesCopied
  2221. );
  2222. ASSERT( status == STATUS_SUCCESS );
  2223. ASSERT( bytesCopied == writeLength );
  2224. //
  2225. // Return the TransportContext
  2226. //
  2227. if ( WorkContext->Parameters.WriteMpx.TransportContext ) {
  2228. TdiReturnChainedReceives( &WorkContext->Parameters.WriteMpx.TransportContext,
  2229. 1
  2230. );
  2231. }
  2232. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2233. //
  2234. // Update the glom run information. Note that this packet may have
  2235. // been received multiple times, so it may already be marked in the
  2236. // run information.
  2237. //
  2238. if (0) IF_SMB_DEBUG(MPX2) {
  2239. KdPrint(( "rfcb %p, offset %lx, length %lx\n", rfcb, glomOffset, writeLength ));
  2240. }
  2241. runCount = writeMpx->NumberOfRuns;
  2242. for ( runIndex = 1, nextRun = &writeMpx->RunList[1];
  2243. runIndex < runCount;
  2244. runIndex++, nextRun++ ) {
  2245. if ( nextRun->Offset > glomOffset ) {
  2246. break;
  2247. }
  2248. }
  2249. run = nextRun - 1;
  2250. runOffset = run->Offset;
  2251. runLength = run->Length;
  2252. ASSERT( runOffset <= glomOffset );
  2253. if ( (runOffset + runLength) == glomOffset ) {
  2254. //
  2255. // This packet abuts the end of the previous run. Add the
  2256. // length of this packet to the run length and attempt to
  2257. // coalesce with the next run.
  2258. //
  2259. runLength += writeLength;
  2260. goto coalesce;
  2261. }
  2262. if ( (runOffset + runLength) > glomOffset ) {
  2263. //
  2264. // This packet overlaps the previous run. If it lies completely
  2265. // within the previous run, ignore it.
  2266. //
  2267. if ( (USHORT)(runOffset + runLength) >= (glomOffset + writeLength) ) {
  2268. goto discard;
  2269. }
  2270. //
  2271. // This packet overlaps and extends the previous run. Calculate
  2272. // the new run length and attempt to coalesce with the next run.
  2273. //
  2274. runLength = (glomOffset - runOffset + writeLength);
  2275. goto coalesce;
  2276. }
  2277. //
  2278. // This packet's data is disjoint from the previous run.
  2279. //
  2280. if ( runIndex < runCount ) {
  2281. //
  2282. // There is a next run. Does this packet overlap with that run?
  2283. //
  2284. runOffset = nextRun->Offset;
  2285. runLength = nextRun->Length;
  2286. if ( (glomOffset + writeLength) >= runOffset ) {
  2287. //
  2288. // This packet overlaps the next run. Calculate the new run
  2289. // length.
  2290. //
  2291. nextRun->Offset = glomOffset;
  2292. nextRun->Length = runOffset - glomOffset + runLength;
  2293. goto check;
  2294. }
  2295. }
  2296. //
  2297. // Either this packet is disjoint from the next run, or there is no
  2298. // next run. Is there room in the run array for another run? If
  2299. // not, discard this packet. (Note that we discard it even though
  2300. // we have already copied the packet data. That's OK -- it will
  2301. // just be resent.)
  2302. //
  2303. if ( runCount == MAX_GLOM_RUN_COUNT ) {
  2304. goto discard;
  2305. }
  2306. //
  2307. // Add a new run. Since we know the new run is disjoint from the
  2308. // previous run, we know that the glom is not complete.
  2309. //
  2310. RtlMoveMemory( // NOT RtlCopyMemory -- buffers overlap
  2311. nextRun + 1,
  2312. nextRun,
  2313. (runCount - runIndex) * sizeof(WRITE_MPX_RUN)
  2314. );
  2315. writeMpx->NumberOfRuns++;
  2316. nextRun->Offset = glomOffset;
  2317. nextRun->Length = writeLength;
  2318. goto check;
  2319. coalesce:
  2320. if ( runIndex == runCount ) {
  2321. run->Length = runLength;
  2322. } else if ( (runOffset + runLength) >= nextRun->Offset ) {
  2323. run->Length = nextRun->Length + nextRun->Offset - runOffset;
  2324. writeMpx->NumberOfRuns--;
  2325. RtlMoveMemory( // NOT RtlCopyMemory -- buffers overlap
  2326. nextRun,
  2327. nextRun + 1,
  2328. (runCount - runIndex) * sizeof(WRITE_MPX_RUN)
  2329. );
  2330. } else {
  2331. run->Length += writeLength;
  2332. ASSERT( (runOffset + run->Length) < nextRun->Offset );
  2333. }
  2334. if ( (writeMpx->NumberOfRuns == 1) &&
  2335. (writeMpx->RunList[0].Length == writeMpx->Length) ) {
  2336. //
  2337. // The glom is complete.
  2338. //
  2339. writeMpx->GlomComplete = TRUE;
  2340. }
  2341. check:
  2342. if (0) IF_SMB_DEBUG(MPX2) {
  2343. if( writeMpx->Glomming ) {
  2344. ULONG i;
  2345. PWRITE_MPX_RUN runi;
  2346. for ( i = 0, runi = &writeMpx->RunList[0];
  2347. i < writeMpx->NumberOfRuns;
  2348. i++, runi++ ) {
  2349. KdPrint(( " run %d: offset %lx, length %lx\n", i, runi->Offset, runi->Length ));
  2350. }
  2351. }
  2352. }
  2353. writeMpx->Mask |= SmbGetUlong( &request->Mask );
  2354. //
  2355. // If this is an unsequenced request, we're done. We don't respond
  2356. // until we get a sequenced request.
  2357. //
  2358. sequenceNumber = SmbGetAlignedUshort( &header->SequenceNumber );
  2359. if ( sequenceNumber == 0 ) {
  2360. goto discard;
  2361. }
  2362. //
  2363. // This is the last request in this mux sent by the client. Save
  2364. // the sequence number.
  2365. //
  2366. writeMpx->SequenceNumber = sequenceNumber;
  2367. discard:
  2368. //
  2369. // If we have received the sequenced command for this write mux,
  2370. // and this is the last active command, then it's time to send
  2371. // the response. Otherwise, we are done with this SMB.
  2372. //
  2373. if ( --writeMpx->ReferenceCount != 0 ) {
  2374. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2375. SrvFsdRestartSmbComplete( WorkContext );
  2376. KeLowerIrql( oldIrql );
  2377. return;
  2378. }
  2379. //
  2380. // WriteMpx refcount is 0.
  2381. //
  2382. rfcbClosing = (GET_BLOCK_STATE(rfcb) != BlockStateActive);
  2383. if ( writeMpx->SequenceNumber == 0 ) {
  2384. //
  2385. // If the rfcb is closing, complete the cleanup.
  2386. //
  2387. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2388. KeLowerIrql( oldIrql );
  2389. if ( rfcbClosing ) {
  2390. RestartWriteMpxCompleteRfcbClose( WorkContext );
  2391. }
  2392. SrvRestartFsdComplete( WorkContext );
  2393. return;
  2394. }
  2395. //
  2396. // We are done with this write mux. Save the accumulated mask, the
  2397. // sequence number, and the original MID, then clear the mask and
  2398. // sequence number to indicate that we no longer are in the middle
  2399. // of a write mux.
  2400. //
  2401. response = (PRESP_WRITE_MPX_DATAGRAM)WorkContext->ResponseParameters;
  2402. SmbPutUlong( &response->Mask, writeMpx->Mask );
  2403. writeMpx->Mask = 0;
  2404. SmbPutAlignedUshort( &header->SequenceNumber, writeMpx->SequenceNumber );
  2405. writeMpx->SequenceNumber = 0;
  2406. SmbPutAlignedUshort( &header->Mid, writeMpx->Mid );
  2407. //
  2408. // If the glom is complete, we need to complete the MDL write. But
  2409. // we can't do that with the lock held, so we need to clear out all
  2410. // information related to the glom first.
  2411. //
  2412. if ( writeMpx->Glomming && writeMpx->GlomComplete ) {
  2413. PWORK_CONTEXT newContext;
  2414. //
  2415. // Save and clear information about the active glom.
  2416. //
  2417. writeMpx->Glomming = FALSE;
  2418. writeMpx->GlomComplete = FALSE;
  2419. cacheOffset.QuadPart = writeMpx->StartOffset;
  2420. writeLength = writeMpx->Length;
  2421. DEBUG writeMpx->MdlChain = NULL;
  2422. DEBUG writeMpx->StartOffset = 0;
  2423. DEBUG writeMpx->Length = 0;
  2424. //
  2425. // Save the status.
  2426. //
  2427. status = rfcb->SavedError;
  2428. rfcb->SavedError = STATUS_SUCCESS;
  2429. //
  2430. // Now we can release the lock.
  2431. //
  2432. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2433. KeLowerIrql( oldIrql );
  2434. ALLOCATE_WORK_CONTEXT( WorkContext->CurrentWorkQueue, &newContext );
  2435. #if DBG
  2436. IF_SMB_DEBUG(MPX2) {
  2437. KdPrint(( "AddPacketToGlom: rfcb %p, completed chain:\n", rfcb ));
  2438. DumpMdlChain( cacheMdl );
  2439. }
  2440. #endif
  2441. if( newContext == NULL ) {
  2442. //
  2443. // Tell the cache manager that we're done with this MDL write.
  2444. //
  2445. if( rfcb->Lfcb->MdlWriteComplete == NULL ||
  2446. rfcb->Lfcb->MdlWriteComplete(
  2447. rfcb->Lfcb->FileObject,
  2448. &cacheOffset,
  2449. cacheMdl,
  2450. rfcb->Lfcb->DeviceObject ) == FALSE ) {
  2451. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  2452. cacheMdl,
  2453. IRP_MJ_WRITE,
  2454. &cacheOffset,
  2455. writeLength
  2456. );
  2457. if( !NT_SUCCESS( status ) ) {
  2458. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2459. }
  2460. }
  2461. } else {
  2462. //
  2463. // Send the FsRtlMdlWriteComplete off on its way, and go ahead and send
  2464. // the response to the client now.
  2465. //
  2466. newContext->Rfcb = WorkContext->Rfcb;
  2467. SrvReferenceRfcb( newContext->Rfcb );
  2468. newContext->Parameters.WriteMpxMdlWriteComplete.CacheOffset = cacheOffset;
  2469. newContext->Parameters.WriteMpxMdlWriteComplete.WriteLength = writeLength;
  2470. newContext->Parameters.WriteMpxMdlWriteComplete.CacheMdl = cacheMdl;
  2471. newContext->FspRestartRoutine = WriteMpxMdlWriteComplete;
  2472. SrvQueueWorkToFsp( newContext );
  2473. }
  2474. } else {
  2475. if( writeMpx->Glomming == FALSE ) {
  2476. status = rfcb->SavedError;
  2477. rfcb->SavedError = STATUS_SUCCESS;
  2478. }
  2479. //
  2480. // Now we can release the lock.
  2481. //
  2482. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2483. KeLowerIrql( oldIrql );
  2484. }
  2485. //
  2486. // Complete the rfcb close.
  2487. //
  2488. if ( rfcbClosing ) {
  2489. RestartWriteMpxCompleteRfcbClose( WorkContext );
  2490. }
  2491. //
  2492. // Build the response message.
  2493. //
  2494. if ( !NT_SUCCESS(status) ) {
  2495. SrvSetSmbError2( WorkContext, status, TRUE );
  2496. }
  2497. response->WordCount = 2;
  2498. SmbPutUshort( &response->ByteCount, 0 );
  2499. WorkContext->ResponseParameters = NEXT_LOCATION(
  2500. response,
  2501. RESP_WRITE_MPX_DATAGRAM,
  2502. 0
  2503. );
  2504. //
  2505. // Send the response.
  2506. //
  2507. SrvFsdSendResponse( WorkContext );
  2508. return;
  2509. } // AddPacketToGlom
  2510. BOOLEAN
  2511. AddPacketToGlomInIndication (
  2512. IN PWORK_CONTEXT WorkContext,
  2513. IN OUT PRFCB Rfcb,
  2514. IN PVOID Tsdu,
  2515. IN ULONG BytesAvailable,
  2516. IN ULONG ReceiveDatagramFlags,
  2517. IN PVOID SourceAddress,
  2518. IN PVOID Options
  2519. )
  2520. /*++
  2521. Routine Description:
  2522. Do Write glomming at indication.
  2523. *** connection spinlock assumed held. Released on exit ***
  2524. Arguments:
  2525. Return Value:
  2526. TRUE if the caller has to clean up the connection block.
  2527. --*/
  2528. {
  2529. PREQ_WRITE_MPX request;
  2530. PRESP_WRITE_MPX_DATAGRAM response;
  2531. PWRITE_MPX_CONTEXT writeMpx = &Rfcb->WriteMpx;
  2532. PCONNECTION connection = WorkContext->Connection;
  2533. ULONG fileOffset;
  2534. USHORT glomOffset;
  2535. CLONG bufferOffset;
  2536. PCHAR writeAddress;
  2537. USHORT writeLength;
  2538. ULONG bytesCopied;
  2539. NTSTATUS status = STATUS_SUCCESS;
  2540. USHORT sequenceNumber;
  2541. PSMB_HEADER header = (PSMB_HEADER)Tsdu;
  2542. PWRITE_MPX_RUN run, nextRun;
  2543. ULONG runIndex, runCount;
  2544. USHORT runOffset;
  2545. USHORT runLength;
  2546. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  2547. //
  2548. // copied from SrvRestartReceive.
  2549. //
  2550. WorkContext->CurrentWorkQueue->stats.BytesReceived += BytesAvailable;
  2551. connection->BreakIIToNoneJustSent = FALSE;
  2552. SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE );
  2553. //
  2554. // Set up locals.
  2555. //
  2556. request = (PREQ_WRITE_MPX)(header + 1);
  2557. ASSERT( writeMpx->Glomming );
  2558. ASSERT( !writeMpx->GlomPending );
  2559. ASSERT( header->Mid == writeMpx->Mid );
  2560. //
  2561. // Get the file offset of this packet's data.
  2562. //
  2563. fileOffset = SmbGetUlong( &request->Offset );
  2564. //
  2565. // Determine the amount of data to write. This is the minimum of
  2566. // the amount requested by the client and the amount of data
  2567. // actually sent in the request buffer.
  2568. //
  2569. bufferOffset = SmbGetUshort( &request->DataOffset );
  2570. writeAddress = (PCHAR)header + bufferOffset;
  2571. writeLength =
  2572. (USHORT)(MIN( (CLONG)SmbGetUshort( &request->DataLength ),
  2573. BytesAvailable - bufferOffset ));
  2574. ASSERT( writeLength <= 0xffff );
  2575. //
  2576. // If the data doesn't fall within the bounds of the glommed write,
  2577. // discard the packet.
  2578. //
  2579. // We always know that we've copied at least the first part of the
  2580. // glom.
  2581. //
  2582. ASSERT( writeMpx->NumberOfRuns > 0 );
  2583. if ( fileOffset <= writeMpx->StartOffset ) {
  2584. goto discard;
  2585. }
  2586. fileOffset -= writeMpx->StartOffset;
  2587. if ( (fileOffset + writeLength) > writeMpx->Length ) {
  2588. goto discard;
  2589. }
  2590. ASSERT( fileOffset <= 0xffff );
  2591. ASSERT( fileOffset + writeLength <= 0xffff );
  2592. glomOffset = (USHORT)fileOffset;
  2593. //
  2594. // Copy the packet data into the glom.
  2595. //
  2596. status = TdiCopyBufferToMdl(
  2597. writeAddress,
  2598. 0,
  2599. writeLength,
  2600. writeMpx->MdlChain,
  2601. glomOffset,
  2602. &bytesCopied
  2603. );
  2604. ASSERT( status == STATUS_SUCCESS );
  2605. ASSERT( bytesCopied == writeLength );
  2606. //
  2607. // Update the glom run information. Note that this packet may have
  2608. // been received multiple times, so it may already be marked in the
  2609. // run information.
  2610. //
  2611. if (0) IF_SMB_DEBUG(MPX2) {
  2612. KdPrint(( "rfcb %p, offset %lx, length %lx\n", Rfcb, glomOffset, writeLength ));
  2613. }
  2614. runCount = writeMpx->NumberOfRuns;
  2615. for ( runIndex = 1, nextRun = &writeMpx->RunList[1];
  2616. runIndex < runCount;
  2617. runIndex++, nextRun++ ) {
  2618. if ( nextRun->Offset > glomOffset ) {
  2619. break;
  2620. }
  2621. }
  2622. run = nextRun - 1;
  2623. runOffset = run->Offset;
  2624. runLength = run->Length;
  2625. ASSERT( runOffset <= glomOffset );
  2626. if ( (runOffset + runLength) == glomOffset ) {
  2627. //
  2628. // This packet abuts the end of the previous run. Add the
  2629. // length of this packet to the run length and attempt to
  2630. // coalesce with the next run.
  2631. //
  2632. runLength += writeLength;
  2633. goto coalesce;
  2634. }
  2635. if ( (runOffset + runLength) > glomOffset ) {
  2636. //
  2637. // This packet overlaps the previous run. If it lies completely
  2638. // within the previous run, ignore it.
  2639. //
  2640. if ( (USHORT)(runOffset + runLength) >= (glomOffset + writeLength) ) {
  2641. goto discard;
  2642. }
  2643. //
  2644. // This packet overlaps and extends the previous run. Calculate
  2645. // the new run length and attempt to coalesce with the next run.
  2646. //
  2647. runLength = (glomOffset - runOffset + writeLength);
  2648. goto coalesce;
  2649. }
  2650. //
  2651. // This packet's data is disjoint from the previous run.
  2652. //
  2653. if ( runIndex < runCount ) {
  2654. //
  2655. // There is a next run. Does this packet overlap with that run?
  2656. //
  2657. runOffset = nextRun->Offset;
  2658. runLength = nextRun->Length;
  2659. if ( (glomOffset + writeLength) >= runOffset ) {
  2660. //
  2661. // This packet overlaps the next run. Calculate the new run
  2662. // length.
  2663. //
  2664. nextRun->Offset = glomOffset;
  2665. nextRun->Length = runOffset - glomOffset + runLength;
  2666. goto check;
  2667. }
  2668. }
  2669. //
  2670. // Either this packet is disjoint from the next run, or there is no
  2671. // next run. Is there room in the run array for another run? If
  2672. // not, discard this packet. (Note that we discard it even though
  2673. // we have already copied the packet data. That's OK -- it will
  2674. // just be resent.)
  2675. //
  2676. if ( runCount == MAX_GLOM_RUN_COUNT ) {
  2677. goto discard;
  2678. }
  2679. //
  2680. // Add a new run. Since we know the new run is disjoint from the
  2681. // previous run, we know that the glom is not complete.
  2682. //
  2683. RtlMoveMemory( // NOT RtlCopyMemory -- buffers overlap
  2684. nextRun + 1,
  2685. nextRun,
  2686. (runCount - runIndex) * sizeof(WRITE_MPX_RUN)
  2687. );
  2688. writeMpx->NumberOfRuns++;
  2689. nextRun->Offset = glomOffset;
  2690. nextRun->Length = writeLength;
  2691. goto check;
  2692. coalesce:
  2693. if ( runIndex == runCount ) {
  2694. run->Length = runLength;
  2695. } else if ( (runOffset + runLength) >= nextRun->Offset ) {
  2696. run->Length = nextRun->Length + nextRun->Offset - runOffset;
  2697. writeMpx->NumberOfRuns--;
  2698. RtlMoveMemory( // NOT RtlCopyMemory -- buffers overlap
  2699. nextRun,
  2700. nextRun + 1,
  2701. (runCount - runIndex) * sizeof(WRITE_MPX_RUN)
  2702. );
  2703. } else {
  2704. run->Length += writeLength;
  2705. ASSERT( (runOffset + run->Length) < nextRun->Offset );
  2706. }
  2707. if ( (writeMpx->NumberOfRuns == 1) &&
  2708. (writeMpx->RunList[0].Length == writeMpx->Length) ) {
  2709. //
  2710. // The glom is complete.
  2711. //
  2712. writeMpx->GlomComplete = TRUE;
  2713. }
  2714. check:
  2715. if (0) IF_SMB_DEBUG(MPX2) {
  2716. ULONG i;
  2717. PWRITE_MPX_RUN runi;
  2718. for ( i = 0, runi = &writeMpx->RunList[0];
  2719. i < writeMpx->NumberOfRuns;
  2720. i++, runi++ ) {
  2721. KdPrint(( " run %d: offset %lx, length %lx\n", i, runi->Offset, runi->Length ));
  2722. }
  2723. }
  2724. writeMpx->Mask |= SmbGetUlong( &request->Mask );
  2725. //
  2726. // If this is an unsequenced request, we're done. We don't respond
  2727. // until we get a sequenced request.
  2728. //
  2729. sequenceNumber = SmbGetAlignedUshort( &header->SequenceNumber );
  2730. if ( sequenceNumber == 0 ) {
  2731. goto discard;
  2732. }
  2733. //
  2734. // This is the last request in this mux sent by the client. Save
  2735. // the sequence number.
  2736. //
  2737. writeMpx->SequenceNumber = sequenceNumber;
  2738. discard:
  2739. //
  2740. // If we have received the sequenced command for this write mux,
  2741. // and this is the last active command, then it's time to send
  2742. // the response. Otherwise, we are done with this SMB.
  2743. //
  2744. if ( (--writeMpx->ReferenceCount != 0) ||
  2745. (writeMpx->SequenceNumber == 0) ) {
  2746. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2747. return TRUE;
  2748. }
  2749. //
  2750. // Copy the header portion for the response.
  2751. //
  2752. TdiCopyLookaheadData(
  2753. WorkContext->RequestBuffer->Buffer,
  2754. Tsdu,
  2755. sizeof(SMB_HEADER),
  2756. ReceiveDatagramFlags
  2757. );
  2758. // WorkContext->RequestBuffer->DataLength = BytesAvailable;
  2759. //
  2760. // We are done with this write mux. Save the accumulated mask, the
  2761. // sequence number, and the original MID, then clear the mask and
  2762. // sequence number to indicate that we no longer are in the middle
  2763. // of a write mux.
  2764. //
  2765. response = (PRESP_WRITE_MPX_DATAGRAM)WorkContext->ResponseParameters;
  2766. SmbPutUlong( &response->Mask, writeMpx->Mask );
  2767. writeMpx->Mask = 0;
  2768. SmbPutAlignedUshort( &header->SequenceNumber, writeMpx->SequenceNumber );
  2769. writeMpx->SequenceNumber = 0;
  2770. SmbPutAlignedUshort( &header->Mid, writeMpx->Mid );
  2771. //
  2772. // If the glom is complete, we need to complete the MDL write. But
  2773. // we can't do that with the lock held, so we need to clear out all
  2774. // information related to the glom first.
  2775. //
  2776. if ( writeMpx->GlomComplete ) {
  2777. //
  2778. // The file is active and the TID is valid. Reference the
  2779. // RFCB.
  2780. //
  2781. Rfcb->BlockHeader.ReferenceCount++;
  2782. UPDATE_REFERENCE_HISTORY( Rfcb, FALSE );
  2783. //
  2784. // Now we can release the lock.
  2785. //
  2786. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2787. WorkContext->Rfcb = Rfcb;
  2788. //
  2789. // Build the response message.
  2790. //
  2791. response->WordCount = 2;
  2792. SmbPutUshort( &response->ByteCount, 0 );
  2793. WorkContext->ResponseParameters = NEXT_LOCATION(
  2794. response,
  2795. RESP_WRITE_MPX_DATAGRAM,
  2796. 0
  2797. );
  2798. //
  2799. // Send this off to the fsp for final processing. We need to do
  2800. // this since we cannot call the cache manager at dpc level.
  2801. //
  2802. WorkContext->FspRestartRoutine = RestartCompleteGlommingInIndication;
  2803. SrvQueueWorkToFsp( WorkContext );
  2804. return FALSE;
  2805. } else {
  2806. //
  2807. // Now we can release the lock.
  2808. //
  2809. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2810. }
  2811. //
  2812. // Build the response message.
  2813. //
  2814. ASSERT( status == STATUS_SUCCESS );
  2815. response->WordCount = 2;
  2816. SmbPutUshort( &response->ByteCount, 0 );
  2817. WorkContext->ResponseParameters = NEXT_LOCATION(
  2818. response,
  2819. RESP_WRITE_MPX_DATAGRAM,
  2820. 0
  2821. );
  2822. //
  2823. // Send the response.
  2824. //
  2825. SrvFsdSendResponse( WorkContext );
  2826. return FALSE;
  2827. } // AddPacketToGlomInIndication
  2828. SMB_PROCESSOR_RETURN_TYPE
  2829. SrvSmbWriteMpxSecondary (
  2830. SMB_PROCESSOR_PARAMETERS
  2831. )
  2832. /*++
  2833. Routine Description:
  2834. Processes the Write Mpx Secondary SMB.
  2835. *** The server should never see this SMB, since it returns the "use
  2836. standard read" error to the main Write Mpx SMB, except over IPX,
  2837. which doesn't use Write Mpx Secondary.
  2838. Arguments:
  2839. WorkContext - Supplies a pointer to the work context block
  2840. representing the work item
  2841. Return Value:
  2842. None.
  2843. --*/
  2844. {
  2845. PAGED_CODE( );
  2846. //
  2847. // Send a response that tells the client that this SMB is not
  2848. // valid.
  2849. //
  2850. INTERNAL_ERROR(
  2851. ERROR_LEVEL_UNEXPECTED,
  2852. "SrvSmbWriteMpxSecondary: unexpected SMB",
  2853. NULL,
  2854. NULL
  2855. );
  2856. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2857. return SmbStatusSendResponse;
  2858. } // SrvSmbWriteMpxSecondary
  2859. VOID SRVFASTCALL
  2860. RestartCompleteGlommingInIndication(
  2861. IN OUT PWORK_CONTEXT WorkContext
  2862. )
  2863. {
  2864. LARGE_INTEGER cacheOffset;
  2865. KIRQL oldIrql;
  2866. PMDL cacheMdl;
  2867. NTSTATUS status;
  2868. PRFCB rfcb = WorkContext->Rfcb;
  2869. PWRITE_MPX_CONTEXT writeMpx = &rfcb->WriteMpx;
  2870. PCONNECTION connection = WorkContext->Connection;
  2871. ULONG writeLength;
  2872. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  2873. //
  2874. // Save the status.
  2875. //
  2876. status = rfcb->SavedError;
  2877. rfcb->SavedError = STATUS_SUCCESS;
  2878. //
  2879. // If the rfcb has closed, then the mdl write was completed.
  2880. //
  2881. if ( GET_BLOCK_STATE(rfcb) == BlockStateActive ) {
  2882. PWORK_CONTEXT newContext;
  2883. writeMpx->GlomComplete = FALSE;
  2884. writeMpx->Glomming = FALSE;
  2885. cacheOffset.QuadPart = writeMpx->StartOffset;
  2886. cacheMdl = writeMpx->MdlChain;
  2887. writeLength = writeMpx->Length;
  2888. DEBUG writeMpx->MdlChain = NULL;
  2889. DEBUG writeMpx->StartOffset = 0;
  2890. DEBUG writeMpx->Length = 0;
  2891. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2892. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  2893. ALLOCATE_WORK_CONTEXT( WorkContext->CurrentWorkQueue, &newContext );
  2894. KeLowerIrql( oldIrql );
  2895. if( newContext == NULL ) {
  2896. //
  2897. // Tell the cache manager that we're done with this MDL write.
  2898. //
  2899. if( rfcb->Lfcb->MdlWriteComplete == NULL ||
  2900. rfcb->Lfcb->MdlWriteComplete(
  2901. rfcb->Lfcb->FileObject,
  2902. &cacheOffset,
  2903. cacheMdl,
  2904. rfcb->Lfcb->DeviceObject ) == FALSE ) {
  2905. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  2906. cacheMdl,
  2907. IRP_MJ_WRITE,
  2908. &cacheOffset,
  2909. writeLength
  2910. );
  2911. if( !NT_SUCCESS( status ) ) {
  2912. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2913. }
  2914. }
  2915. } else {
  2916. //
  2917. // Send the FsRtlMdlWriteComplete off on its way, and go ahead and send
  2918. // the response to the client now.
  2919. //
  2920. newContext->Rfcb = WorkContext->Rfcb;
  2921. WorkContext->Rfcb = NULL;
  2922. newContext->Parameters.WriteMpxMdlWriteComplete.CacheOffset = cacheOffset;
  2923. newContext->Parameters.WriteMpxMdlWriteComplete.WriteLength = writeLength;
  2924. newContext->Parameters.WriteMpxMdlWriteComplete.CacheMdl = cacheMdl;
  2925. newContext->FspRestartRoutine = WriteMpxMdlWriteComplete;
  2926. SrvQueueWorkToFsp( newContext );
  2927. }
  2928. } else {
  2929. ASSERT( !writeMpx->Glomming );
  2930. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2931. }
  2932. //
  2933. // Send the response.
  2934. //
  2935. if ( !NT_SUCCESS(status) ) {
  2936. SrvSetSmbError2( WorkContext, status, TRUE );
  2937. }
  2938. SrvFsdSendResponse( WorkContext );
  2939. return;
  2940. } // RestartCompleteGlommingInIndication
  2941. VOID SRVFASTCALL
  2942. WriteMpxMdlWriteComplete (
  2943. IN OUT PWORK_CONTEXT WorkContext
  2944. )
  2945. {
  2946. NTSTATUS status;
  2947. if( WorkContext->Rfcb->Lfcb->MdlWriteComplete == NULL ||
  2948. WorkContext->Rfcb->Lfcb->MdlWriteComplete(
  2949. WorkContext->Rfcb->Lfcb->FileObject,
  2950. &WorkContext->Parameters.WriteMpxMdlWriteComplete.CacheOffset,
  2951. WorkContext->Parameters.WriteMpxMdlWriteComplete.CacheMdl,
  2952. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  2953. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  2954. WorkContext->Parameters.WriteMpxMdlWriteComplete.CacheMdl,
  2955. IRP_MJ_WRITE,
  2956. &WorkContext->Parameters.WriteMpxMdlWriteComplete.CacheOffset,
  2957. WorkContext->Parameters.WriteMpxMdlWriteComplete.WriteLength );
  2958. if( !NT_SUCCESS( status ) ) {
  2959. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2960. }
  2961. }
  2962. SrvDereferenceRfcb( WorkContext->Rfcb );
  2963. WorkContext->Rfcb = NULL;
  2964. WorkContext->FspRestartRoutine = SrvRestartReceive;
  2965. ASSERT( WorkContext->BlockHeader.ReferenceCount == 1 );
  2966. #if DBG
  2967. WorkContext->BlockHeader.ReferenceCount = 0;
  2968. #endif
  2969. RETURN_FREE_WORKITEM( WorkContext );
  2970. }
  2971. VOID SRVFASTCALL
  2972. RestartWriteMpxCompleteRfcbClose (
  2973. IN OUT PWORK_CONTEXT WorkContext
  2974. )
  2975. /*++
  2976. Routine Description:
  2977. Completes the rfcb close after last active writempx is finished.
  2978. Arguments:
  2979. WorkContext - Supplies a pointer to the work context block
  2980. representing the work item
  2981. Return Value:
  2982. None.
  2983. --*/
  2984. {
  2985. PCONNECTION connection = WorkContext->Connection;
  2986. PRFCB rfcb = WorkContext->Rfcb;
  2987. PWRITE_MPX_CONTEXT writeMpx = &rfcb->WriteMpx;
  2988. LARGE_INTEGER cacheOffset;
  2989. PMDL mdlChain;
  2990. KIRQL oldIrql;
  2991. ULONG writeLength;
  2992. NTSTATUS status;
  2993. //
  2994. // This rfcb is closing.
  2995. //
  2996. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  2997. ASSERT ( GET_BLOCK_STATE(rfcb) != BlockStateActive );
  2998. writeMpx = &rfcb->WriteMpx;
  2999. if ( writeMpx->Glomming ) {
  3000. //
  3001. // We need to complete this write mdl
  3002. //
  3003. writeMpx->Glomming = FALSE;
  3004. writeMpx->GlomComplete = FALSE;
  3005. //
  3006. // Save the offset and MDL address.
  3007. //
  3008. cacheOffset.QuadPart = writeMpx->StartOffset;
  3009. mdlChain = writeMpx->MdlChain;
  3010. writeLength = writeMpx->Length;
  3011. DEBUG writeMpx->MdlChain = NULL;
  3012. DEBUG writeMpx->StartOffset = 0;
  3013. DEBUG writeMpx->Length = 0;
  3014. //
  3015. // Now we can release the lock.
  3016. //
  3017. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  3018. //
  3019. // Tell the cache manager that we're done with this MDL write.
  3020. //
  3021. if( rfcb->Lfcb->MdlWriteComplete == NULL ||
  3022. rfcb->Lfcb->MdlWriteComplete(
  3023. writeMpx->FileObject,
  3024. &cacheOffset,
  3025. mdlChain,
  3026. rfcb->Lfcb->DeviceObject ) == FALSE ) {
  3027. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  3028. mdlChain,
  3029. IRP_MJ_WRITE,
  3030. &cacheOffset,
  3031. writeLength );
  3032. if( !NT_SUCCESS( status ) ) {
  3033. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  3034. }
  3035. }
  3036. } else {
  3037. //
  3038. // Now we can release the lock.
  3039. //
  3040. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  3041. }
  3042. //
  3043. // Do the actual close
  3044. //
  3045. SrvCompleteRfcbClose( rfcb );
  3046. return;
  3047. } // RestartWriteMpxCompleteRfcbClose