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.

1248 lines
34 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. fsdraw.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs in
  7. the server FSD:
  8. Read Block Raw
  9. Write Block Raw
  10. The routines in this module generally work closely with the routines
  11. in smbraw.c.
  12. *** There is no support here for raw writes from MS-NET 1.03 clients.
  13. There are very few of these machines in existence, and raw mode
  14. is only a performance issue, so it is not worth the trouble to
  15. add the necessary hacks for MS-NET 1.03, which sends raw write
  16. requests in a different format.
  17. Author:
  18. Chuck Lenzmeier (chuckl) 8-Sep-1990
  19. Manny Weiser (mannyw)
  20. David Treadwell (davidtr)
  21. Revision History:
  22. --*/
  23. #include "precomp.h"
  24. #include "fsdraw.tmh"
  25. #pragma hdrstop
  26. //
  27. // Forward declarations.
  28. //
  29. STATIC
  30. VOID SRVFASTCALL
  31. RestartWriteCompleteResponse (
  32. IN OUT PWORK_CONTEXT WorkContext
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text( PAGE8FIL, SrvFsdBuildWriteCompleteResponse )
  36. #pragma alloc_text( PAGE8FIL, RestartWriteCompleteResponse )
  37. #endif
  38. #if 0
  39. NOT PAGEABLE -- RestartCopyReadRawResponse
  40. NOT PAGEABLE -- SrvFsdRestartPrepareRawMdlWrite
  41. NOT PAGEABLE -- SrvFsdRestartReadRaw
  42. NOT PAGEABLE -- SrvFsdRestartWriteRaw
  43. #endif
  44. #if DBG
  45. VOID
  46. DumpMdlChain(
  47. IN PMDL mdl
  48. );
  49. #endif
  50. VOID
  51. SrvFsdBuildWriteCompleteResponse (
  52. IN OUT PWORK_CONTEXT WorkContext,
  53. IN NTSTATUS Status,
  54. IN ULONG BytesWritten
  55. )
  56. /*++
  57. Routine Description:
  58. Sets up a final response to a Write Block Raw/Mpx request.
  59. This routine is called in both the FSP and the FSD. It can be called
  60. in the FSD only if Status == STATUS_SUCCESS.
  61. Arguments:
  62. WorkContext - Supplies a pointer to the work context block
  63. describing server-specific context for the request.
  64. Status - Supplies a status value to be returned to the client.
  65. BytesWritten - Supplies the number of bytes actually written.
  66. Return Value:
  67. SMB_PROCESSOR_RETURN_TYPE - Returns SmbStatusSendResponse.
  68. --*/
  69. {
  70. PSMB_HEADER header;
  71. PRESP_WRITE_COMPLETE response;
  72. if ( WorkContext->Rfcb != NULL ) {
  73. UNLOCKABLE_CODE( 8FIL );
  74. } else {
  75. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  76. }
  77. //
  78. // Get pointers to the header and the response parameters area.
  79. // Note that Write Block Raw/Mpx can't be chained to an AndX SMB.
  80. //
  81. header = WorkContext->ResponseHeader;
  82. response = (PRESP_WRITE_COMPLETE)WorkContext->ResponseParameters;
  83. //
  84. // Change the SMB command code to Write Complete.
  85. //
  86. header->Command = SMB_COM_WRITE_COMPLETE;
  87. //
  88. // Put the error code in the header. Note that SrvSetSmbError
  89. // writes a null parameter area to the end of the SMB; we overwrite
  90. // that with our own parameter area.
  91. //
  92. if ( Status != STATUS_SUCCESS ) {
  93. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  94. SrvSetSmbError2( WorkContext, Status, TRUE );
  95. }
  96. //
  97. // Build the response SMB.
  98. //
  99. response->WordCount = 1;
  100. SmbPutUshort( &response->Count, (USHORT)BytesWritten );
  101. SmbPutUshort( &response->ByteCount, 0 );
  102. WorkContext->ResponseParameters = NEXT_LOCATION(
  103. response,
  104. RESP_WRITE_COMPLETE,
  105. 0
  106. );
  107. return;
  108. } // SrvFsdBuildWriteCompleteResponse
  109. NTSTATUS
  110. RestartCopyReadRawResponse (
  111. IN PDEVICE_OBJECT DeviceObject,
  112. IN PIRP Irp,
  113. IN OUT PWORK_CONTEXT WorkContext
  114. )
  115. /*++
  116. Routine Description:
  117. This is the restart routine that is invoked when the send of a
  118. Read Block Raw response completes.
  119. This routine is called in the FSD.
  120. Arguments:
  121. DeviceObject - Pointer to target device object for the request.
  122. Irp - Pointer to I/O request packet
  123. WorkContext - Caller-specified context parameter associated with IRP.
  124. This is actually a pointer to a Work Context block.
  125. Return Value:
  126. STATUS_MORE_PROCESSING_REQUIRED.
  127. --*/
  128. {
  129. KIRQL oldIrql;
  130. PCONNECTION connection;
  131. IF_DEBUG(FSD1) SrvPrint0( " - RestartCopyReadRawResponse\n" );
  132. //
  133. // Check the status of the send completion.
  134. //
  135. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  136. //
  137. // Reset the IRP cancelled bit.
  138. //
  139. Irp->Cancel = FALSE;
  140. //
  141. // Deallocate the raw buffer, if the original SMB buffer was not
  142. // used. Note that we do not need to unlock the raw buffer, because
  143. // it was allocated out of nonpaged pool and locked using
  144. // MmBuildMdlForNonPagedPool, which doesn't increment reference
  145. // counts and therefore has no inverse.
  146. //
  147. if ( WorkContext->Parameters.ReadRaw.SavedResponseBuffer != NULL ) {
  148. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer->Buffer );
  149. IoFreeMdl( WorkContext->ResponseBuffer->Mdl );
  150. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  151. WorkContext->ResponseBuffer =
  152. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  153. }
  154. //
  155. // If there is an oplock break request pending, then we must go to the
  156. // FSP to initiate the break, otherwise complete processing in the FSD.
  157. //
  158. connection = WorkContext->Connection;
  159. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  160. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  161. if ( IsListEmpty( &connection->OplockWorkList ) ) {
  162. //
  163. // Dereference control blocks and put the work item back on the
  164. // receive queue.
  165. //
  166. WorkContext->Connection->RawReadsInProgress--;
  167. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  168. SrvFsdRestartSmbComplete( WorkContext );
  169. } else {
  170. //
  171. // Send this work context to the FSP for completion.
  172. //
  173. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  174. WorkContext->FspRestartRoutine = SrvRestartReadRawComplete;
  175. QUEUE_WORK_TO_FSP( WorkContext );
  176. }
  177. IF_DEBUG(TRACE2) SrvPrint0( "RestartCopyReadRawResponse complete\n" );
  178. KeLowerIrql( oldIrql );
  179. return STATUS_MORE_PROCESSING_REQUIRED;
  180. } // RestartCopyReadRawResponse
  181. VOID SRVFASTCALL
  182. SrvFsdRestartPrepareRawMdlWrite(
  183. IN OUT PWORK_CONTEXT WorkContext
  184. )
  185. /*++
  186. Routine Description:
  187. Restart routine for completion of a "prepare MDL write" I/O request.
  188. Prepares a work context block and an IRP describing the raw receive,
  189. posts the receive, and sends a "go-ahead" response.
  190. This routine is called in both the FSP and the FSD.
  191. Arguments:
  192. WorkContext - Supplies a pointer to the work context block
  193. describing server-specific context for the request.
  194. Return Value:
  195. None.
  196. --*/
  197. {
  198. PREQ_WRITE_RAW request;
  199. PRESP_WRITE_RAW_INTERIM response;
  200. PVOID finalResponseBuffer;
  201. PWORK_CONTEXT rawWorkContext;
  202. ULONG writeLength;
  203. ULONG immediateLength;
  204. BOOLEAN immediateWriteDone;
  205. PMDL mdl;
  206. PCHAR src;
  207. PCHAR dest;
  208. ULONG lengthToCopy;
  209. PIO_STACK_LOCATION irpSp;
  210. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  211. if (bNeedTrace) {
  212. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  213. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_RAW;
  214. SrvWmiStartContext(WorkContext);
  215. }
  216. else
  217. WorkContext->bAlreadyTrace = FALSE;
  218. IF_DEBUG(FSD1) SrvPrint0( " - SrvFsdRestartPrepareRawMdlWrite\n" );
  219. //
  220. // Get request parameters and saved context.
  221. //
  222. request = (PREQ_WRITE_RAW)WorkContext->RequestParameters;
  223. rawWorkContext = WorkContext->Parameters.WriteRawPhase1.RawWorkContext;
  224. writeLength = SmbGetUshort( &request->Count );
  225. immediateLength = SmbGetUshort( &request->DataLength );
  226. immediateWriteDone = rawWorkContext->Parameters.WriteRaw.ImmediateWriteDone;
  227. if ( immediateWriteDone ) {
  228. writeLength -= immediateLength;
  229. }
  230. finalResponseBuffer =
  231. rawWorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  232. //
  233. // If the prepare MDL write I/O failed, send an error response.
  234. //
  235. if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  236. IF_DEBUG(ERRORS) {
  237. SrvPrint1( "SrvFsdRestartPrepareRawMdlWrite: Write failed: %X\n",
  238. WorkContext->Irp->IoStatus.Status );
  239. }
  240. //
  241. // We won't be needing the final response buffer or the raw mode
  242. // work item.
  243. //
  244. if ( finalResponseBuffer != NULL ) {
  245. DEALLOCATE_NONPAGED_POOL( finalResponseBuffer );
  246. }
  247. rawWorkContext->ResponseBuffer->Buffer = NULL;
  248. RestartWriteCompleteResponse( rawWorkContext );
  249. //
  250. // Build and send the response.
  251. //
  252. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  253. WorkContext->Irp->IoStatus.Information =
  254. immediateWriteDone ? immediateLength : 0;
  255. WorkContext->FspRestartRoutine = SrvBuildAndSendWriteCompleteResponse;
  256. WorkContext->FsdRestartRoutine = SrvFsdRestartSmbComplete; // after response
  257. QUEUE_WORK_TO_FSP( WorkContext );
  258. } else {
  259. SrvFsdBuildWriteCompleteResponse(
  260. WorkContext,
  261. WorkContext->Irp->IoStatus.Status,
  262. immediateWriteDone ? immediateLength : 0
  263. );
  264. SrvFsdSendResponse( WorkContext );
  265. }
  266. IF_DEBUG(TRACE2) {
  267. SrvPrint0( "SrvFsdRestartPrepareRawMdlWrite complete\n" );
  268. }
  269. goto Cleanup;
  270. }
  271. //
  272. // If a final response is going to be sent, save information from
  273. // the request in the final response buffer.
  274. //
  275. if ( finalResponseBuffer != NULL ) {
  276. RtlCopyMemory(
  277. (PSMB_HEADER)finalResponseBuffer,
  278. WorkContext->RequestHeader,
  279. sizeof(SMB_HEADER)
  280. );
  281. }
  282. //
  283. // If the immediate data has not yet been written, copy it now.
  284. //
  285. mdl = WorkContext->Irp->MdlAddress;
  286. #if DBG
  287. IF_SMB_DEBUG(RAW2) {
  288. KdPrint(( "SrvFsdRestartPrepareRawMdlWrite: input chain:\n" ));
  289. DumpMdlChain( mdl );
  290. }
  291. #endif
  292. rawWorkContext->Parameters.WriteRaw.FirstMdl = mdl;
  293. if ( !immediateWriteDone ) {
  294. src = (PCHAR)WorkContext->RequestHeader +
  295. SmbGetUshort( &request->DataOffset );
  296. while ( immediateLength ) {
  297. lengthToCopy = MIN( immediateLength, mdl->ByteCount );
  298. dest = MmGetSystemAddressForMdlSafe( mdl,NormalPoolPriority );
  299. if (dest == NULL) {
  300. WorkContext->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  301. WorkContext->Irp->IoStatus.Information = 0;
  302. WorkContext->FspRestartRoutine = SrvBuildAndSendWriteCompleteResponse;
  303. WorkContext->FsdRestartRoutine = SrvFsdRestartSmbComplete; // after response
  304. QUEUE_WORK_TO_FSP( WorkContext );
  305. goto Cleanup;
  306. }
  307. RtlCopyMemory( dest, src, lengthToCopy );
  308. src += lengthToCopy;
  309. immediateLength -= lengthToCopy;
  310. writeLength -= lengthToCopy;
  311. if ( lengthToCopy == mdl->ByteCount ) {
  312. mdl = mdl->Next;
  313. } else {
  314. PCHAR baseVa;
  315. ULONG lengthOfMdl;
  316. PMDL rawMdl;
  317. ASSERT( immediateLength == 0 );
  318. baseVa = (PCHAR)MmGetMdlVirtualAddress(mdl) + lengthToCopy;
  319. lengthOfMdl = mdl->ByteCount - lengthToCopy;
  320. ASSERT( lengthOfMdl <= 65535 );
  321. rawMdl = rawWorkContext->RequestBuffer->Mdl;
  322. rawMdl->Size = (CSHORT)(sizeof(MDL) + (sizeof(ULONG_PTR) *
  323. ADDRESS_AND_SIZE_TO_SPAN_PAGES( baseVa, lengthOfMdl )));
  324. IoBuildPartialMdl( mdl, rawMdl, baseVa, lengthOfMdl );
  325. rawMdl->Next = mdl->Next;
  326. #if DBG
  327. IF_SMB_DEBUG(RAW2) {
  328. KdPrint(( "SrvFsdRestartPrepareRawMdlWrite: built partial MDL at 0x%p\n", rawMdl ));
  329. DumpMdlChain( rawMdl );
  330. }
  331. #endif
  332. mdl = rawMdl;
  333. }
  334. }
  335. }
  336. //
  337. // Save the length of the raw write.
  338. //
  339. rawWorkContext->RequestBuffer->BufferLength = writeLength;
  340. //
  341. // Set up the restart routines in the work context.
  342. //
  343. rawWorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  344. rawWorkContext->FspRestartRoutine = SrvRestartRawReceive;
  345. //
  346. // Build the TdiReceive request packet.
  347. //
  348. {
  349. PIRP irp = rawWorkContext->Irp;
  350. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  351. irp->Tail.Overlay.OriginalFileObject = NULL;
  352. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  353. DEBUG irp->RequestorMode = KernelMode;
  354. //
  355. // Get a pointer to the next stack location. This one is used to
  356. // hold the parameters for the device I/O control request.
  357. //
  358. irpSp = IoGetNextIrpStackLocation( irp );
  359. //
  360. // Set up the completion routine.
  361. //
  362. IoSetCompletionRoutine(
  363. irp,
  364. SrvFsdIoCompletionRoutine,
  365. rawWorkContext,
  366. TRUE,
  367. TRUE,
  368. TRUE
  369. );
  370. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  371. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE;
  372. irpSp->FileObject = NULL;
  373. irpSp->DeviceObject = NULL;
  374. //
  375. // Copy the caller's parameters to the service-specific portion of the
  376. // IRP for those parameters that are the same for all three methods.
  377. //
  378. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  379. parameters->ReceiveLength = writeLength;
  380. parameters->ReceiveFlags = 0;
  381. irp->MdlAddress = mdl;
  382. irp->AssociatedIrp.SystemBuffer = NULL;
  383. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  384. }
  385. IF_SMB_DEBUG(RAW2) {
  386. KdPrint(( "Issuing receive with MDL %p\n", rawWorkContext->Irp->MdlAddress ));
  387. }
  388. irpSp = IoGetNextIrpStackLocation( rawWorkContext->Irp );
  389. //
  390. // If this is a writebehind write, tell the transport that we don't
  391. // plan to reply to the received message.
  392. //
  393. if ( finalResponseBuffer == NULL ) {
  394. ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveFlags |=
  395. TDI_RECEIVE_NO_RESPONSE_EXP;
  396. }
  397. //
  398. // Post the receive.
  399. //
  400. irpSp->Flags = 0;
  401. irpSp->DeviceObject = rawWorkContext->Connection->DeviceObject;
  402. irpSp->FileObject = rawWorkContext->Connection->FileObject;
  403. ASSERT( rawWorkContext->Irp->StackCount >=
  404. irpSp->DeviceObject->StackSize );
  405. (VOID)IoCallDriver( irpSp->DeviceObject, rawWorkContext->Irp );
  406. //
  407. // Send the interim (go-ahead) response.
  408. //
  409. response = (PRESP_WRITE_RAW_INTERIM)WorkContext->ResponseParameters;
  410. response->WordCount = 1;
  411. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  412. SmbPutUshort( &response->ByteCount, 0 );
  413. WorkContext->ResponseParameters = NEXT_LOCATION(
  414. response,
  415. RESP_WRITE_RAW_INTERIM,
  416. 0
  417. );
  418. SrvFsdSendResponse( WorkContext );
  419. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartPrepareRawMdlWrite complete\n" );
  420. Cleanup:
  421. if (bNeedTrace) {
  422. SrvWmiEndContext(WorkContext);
  423. }
  424. return;
  425. } // SrvFsdRestartPrepareRawMdlWrite
  426. VOID SRVFASTCALL
  427. SrvFsdRestartReadRaw (
  428. IN OUT PWORK_CONTEXT WorkContext
  429. )
  430. /*++
  431. Routine Description:
  432. Processes file read completion for the Read Block Raw SMB.
  433. This routine is called in both the FSP and the FSD.
  434. Arguments:
  435. WorkContext - Supplies a pointer to the work context block
  436. describing server-specific context for the request.
  437. Return Value:
  438. None.
  439. --*/
  440. {
  441. PRFCB rfcb;
  442. KIRQL oldIrql;
  443. USHORT readLength;
  444. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  445. if (bNeedTrace) {
  446. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  447. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_RAW;
  448. SrvWmiStartContext(WorkContext);
  449. }
  450. else
  451. WorkContext->bAlreadyTrace = FALSE;
  452. IF_DEBUG(FSD1) SrvPrint0( " - SrvFsdRestartReadRaw\n" );
  453. //
  454. // Get the file pointer.
  455. //
  456. rfcb = WorkContext->Rfcb;
  457. IF_DEBUG(TRACE2) {
  458. SrvPrint2( " connection 0x%p, RFCB 0x%p\n",
  459. WorkContext->Connection, rfcb );
  460. }
  461. //
  462. // Calculate the amount of data read.
  463. //
  464. if ( WorkContext->Irp->IoStatus.Status == STATUS_END_OF_FILE ) {
  465. readLength = 0;
  466. IF_SMB_DEBUG(RAW2) {
  467. SrvPrint0( "SrvFsdRestartReadRaw: 0 bytes read, at end-of-file\n" );
  468. }
  469. } else if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  470. readLength = 0;
  471. IF_SMB_DEBUG(ERRORS) {
  472. SrvPrint1( "SrvFsdRestartReadRaw: read request failed: %X\n",
  473. WorkContext->Irp->IoStatus.Status );
  474. }
  475. } else if ( WorkContext->Parameters.ReadRaw.MdlRead ) {
  476. //
  477. // For an MDL read, we have to walk the MDL chain in order to
  478. // determine how much data was read. This is because the
  479. // operation may have happened in multiple step, with the MDLs
  480. // being chained together. For example, part of the read may
  481. // have been satisfied by the fast path, while the rest was
  482. // satisfied using an IRP.
  483. //
  484. #if DBG
  485. ULONG mdlCount = 0;
  486. #endif
  487. PMDL mdl = WorkContext->Irp->MdlAddress;
  488. readLength = 0;
  489. while ( mdl != NULL ) {
  490. IF_SMB_DEBUG(RAW2) {
  491. #if DBG
  492. SrvPrint3( " mdl %ld at 0x%p, %ld bytes\n",
  493. mdlCount,
  494. mdl, MmGetMdlByteCount(mdl) );
  495. #else
  496. SrvPrint3( " mdl 0x%p, %ld bytes\n",
  497. mdl, MmGetMdlByteCount(mdl) );
  498. #endif
  499. }
  500. readLength += (USHORT)MmGetMdlByteCount(mdl);
  501. #if DBG
  502. mdlCount++;
  503. #endif
  504. mdl = mdl->Next;
  505. }
  506. IF_SMB_DEBUG(RAW2) {
  507. #if DBG
  508. SrvPrint2( "SrvFsdRestartReadRaw: %ld bytes in %ld MDLs\n",
  509. readLength, mdlCount );
  510. #else
  511. SrvPrint2( "SrvFsdRestartReadRaw: %ld bytes\n",
  512. readLength );
  513. #endif
  514. SrvPrint1( " info = 0x%p\n",
  515. (PVOID)WorkContext->Irp->IoStatus.Information );
  516. }
  517. } else {
  518. //
  519. // Copy read. The I/O status block has the length.
  520. //
  521. readLength = (USHORT)WorkContext->Irp->IoStatus.Information;
  522. IF_SMB_DEBUG(RAW2) {
  523. SrvPrint1( "SrvFsdRestartReadRaw: %ld bytes read\n", readLength );
  524. }
  525. }
  526. //
  527. // Update the file position.
  528. //
  529. // *** Note that we ignore the status of the operation, except to
  530. // check for end-of-file, since we can't tell the client what
  531. // the status was. We simply return as many bytes as the file
  532. // system says were read.
  533. //
  534. // !!! Should we save the error and return it when the client
  535. // retries?
  536. //
  537. // !!! Need to worry about wraparound?
  538. //
  539. if ( rfcb->ShareType == ShareTypeDisk ) {
  540. rfcb->CurrentPosition =
  541. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset.LowPart +
  542. readLength;
  543. }
  544. //
  545. // Save the count of bytes read, to be used to update the server
  546. // statistics database.
  547. //
  548. UPDATE_READ_STATS( WorkContext, readLength );
  549. //
  550. // Send the raw read data as the response.
  551. //
  552. WorkContext->ResponseBuffer->DataLength = readLength;
  553. //
  554. // There is no header on this SMB, do not generate a security signature
  555. //
  556. WorkContext->NoResponseSmbSecuritySignature = TRUE;
  557. if ( WorkContext->Parameters.ReadRaw.MdlRead ) {
  558. //
  559. // MDL read. The data is described by the MDL returned by the
  560. // file system (in irp->MdlAddress).
  561. //
  562. // *** Note that if the read failed completely (which happens if
  563. // the read starts beyond EOF), there is no MDL.
  564. // SrvStartSend handles this appropriately. So must
  565. // RestartMdlReadRawResponse.
  566. //
  567. //
  568. // Send the response.
  569. //
  570. SRV_START_SEND(
  571. WorkContext,
  572. WorkContext->Irp->MdlAddress,
  573. 0,
  574. SrvQueueWorkToFspAtSendCompletion,
  575. NULL,
  576. RestartMdlReadRawResponse
  577. );
  578. } else {
  579. //
  580. // Copy read. The data is described by the MDL allocated in
  581. // SrvFsdSmbReadRaw.
  582. //
  583. // *** Changing Mdl->ByteCount like this would be a problem if
  584. // we had to unlock the pages in RestartCopyReadRawResponse,
  585. // because we might end up unlocking fewer pages than we
  586. // locked. But we don't actually lock the pages to build
  587. // the MDL -- the buffer is allocated from nonpaged pool, so
  588. // we use MmBuildMdlForNonPagedPool rather than
  589. // MmProbeAndLockPages. So the pages haven't been
  590. // referenced to account for the MDL, so there's no need to
  591. // unlock them, so changing ByteCount isn't a problem.
  592. //
  593. //
  594. // Send the response.
  595. //
  596. SRV_START_SEND_2(
  597. WorkContext,
  598. RestartCopyReadRawResponse,
  599. NULL,
  600. NULL
  601. );
  602. }
  603. //
  604. // The response send has been started.
  605. //
  606. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartReadRaw complete\n" );
  607. if (bNeedTrace) {
  608. SrvWmiEndContext(WorkContext);
  609. }
  610. return;
  611. } // SrvFsdRestartReadRaw
  612. VOID SRVFASTCALL
  613. RestartWriteCompleteResponse (
  614. IN OUT PWORK_CONTEXT WorkContext
  615. )
  616. /*++
  617. Routine Description:
  618. This routine attempts, at DPC level, to clean up after a Write Raw
  619. completes. It tries to dereference control blocks referenced by the
  620. raw mode work item. If this cannot be done at DPC level (e.g., a
  621. reference count goes to zero), this routine queues the work item to
  622. the FSP for processing.
  623. This routine is called in the FSD. Its FSP counterpart is
  624. SrvRestartWriteCompleteResponse.
  625. Arguments:
  626. WorkContext - Supplies a pointer to the work context block
  627. describing server-specific context for the request.
  628. Return Value:
  629. None.
  630. --*/
  631. {
  632. PCONNECTION connection;
  633. KIRQL oldIrql;
  634. PRFCB rfcb;
  635. PWORK_QUEUE queue;
  636. UNLOCKABLE_CODE( 8FIL );
  637. IF_DEBUG(FSD1) SrvPrint0( " - RestartWriteCompleteResponse\n" );
  638. connection = WorkContext->Connection;
  639. queue = connection->CurrentWorkQueue;
  640. //
  641. // If a final response was sent, check the status and deallocate the
  642. // buffer.
  643. //
  644. if ( WorkContext->ResponseBuffer->Buffer != NULL ) {
  645. //
  646. // If the I/O request failed or was canceled, print an error
  647. // message.
  648. //
  649. // !!! If I/O failure, should we drop the connection?
  650. //
  651. if ( WorkContext->Irp->Cancel ||
  652. !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  653. IF_DEBUG(FSD1) {
  654. if ( WorkContext->Irp->Cancel ) {
  655. SrvPrint0( " I/O canceled\n" );
  656. } else {
  657. SrvPrint1( " I/O failed: %X\n",
  658. WorkContext->Irp->IoStatus.Status );
  659. }
  660. }
  661. }
  662. //
  663. // Deallocate the final response buffer.
  664. //
  665. // *** Note that we don't need to unlock it, because it was
  666. // allocated from nonpaged pool.
  667. //
  668. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer->Buffer );
  669. }
  670. //
  671. // If the work context block has references to a share, a session,
  672. // or a tree connect, queue it to the FSP immediately. These blocks
  673. // are not in nonpaged pool, so they can't be touched at DPC level.
  674. //
  675. if ( (WorkContext->Share != NULL) ||
  676. (WorkContext->Session != NULL) ||
  677. (WorkContext->TreeConnect != NULL) ) {
  678. goto queueToFsp;
  679. }
  680. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  681. //
  682. // See if we can dereference the RawWriteCount here. If the raw
  683. // write count goes to 0, and the RFCB is closing, or if there are
  684. // work items queued waiting for the raw write to complete, we need
  685. // to do this in the FSP.
  686. //
  687. // NOTE: The FSP decrements the count if WorkContext->Rfcb != NULL.
  688. //
  689. rfcb = WorkContext->Rfcb;
  690. --rfcb->RawWriteCount;
  691. if ( (rfcb->RawWriteCount == 0) &&
  692. ( (GET_BLOCK_STATE(rfcb) == BlockStateClosing) ||
  693. !IsListEmpty(&rfcb->RawWriteSerializationList) ) ) {
  694. rfcb->RawWriteCount++;
  695. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  696. goto queueToFsp;
  697. }
  698. //
  699. // Dereference the file block. It is safe to decrement the count here
  700. // because either the rfcb is not closed or RawWriteCount is not zero
  701. // which means that the active reference is still there.
  702. //
  703. UPDATE_REFERENCE_HISTORY( rfcb, TRUE );
  704. --rfcb->BlockHeader.ReferenceCount;
  705. ASSERT( rfcb->BlockHeader.ReferenceCount > 0 );
  706. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  707. WorkContext->Rfcb = NULL;
  708. //
  709. // Attempt to dereference the connection.
  710. //
  711. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  712. if ( connection->BlockHeader.ReferenceCount == 1 ) {
  713. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  714. goto queueToFsp;
  715. }
  716. --connection->BlockHeader.ReferenceCount;
  717. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  718. UPDATE_REFERENCE_HISTORY( connection, TRUE );
  719. WorkContext->Connection = NULL;
  720. WorkContext->Endpoint = NULL; // not a referenced pointer
  721. //
  722. // Put the work item back on the raw mode work item list.
  723. //
  724. InterlockedIncrement( &queue->FreeRawModeWorkItems );
  725. ExInterlockedPushEntrySList( &queue->RawModeWorkItemList,
  726. &WorkContext->SingleListEntry,
  727. &queue->SpinLock );
  728. IF_DEBUG(FSD2) SrvPrint0( "RestartWriteCompleteResponse complete\n" );
  729. return;
  730. queueToFsp:
  731. //
  732. // We were unable to do all the necessary cleanup at DPC level.
  733. // Queue the work item to the FSP.
  734. //
  735. WorkContext->FspRestartRoutine = SrvRestartWriteCompleteResponse;
  736. SrvQueueWorkToFsp( WorkContext );
  737. IF_DEBUG(FSD2) SrvPrint0( "RestartWriteCompleteResponse complete\n" );
  738. return;
  739. } // RestartWriteCompleteResponse
  740. VOID SRVFASTCALL
  741. SrvFsdRestartWriteRaw (
  742. IN OUT PWORK_CONTEXT WorkContext
  743. )
  744. /*++
  745. Routine Description:
  746. Processes file write completion for the Write Block Raw SMB.
  747. This routine is called in both the FSP and the FSD.
  748. Arguments:
  749. WorkContext - Supplies a pointer to the work context block
  750. describing server-specific context for the request.
  751. Return Value:
  752. None.
  753. --*/
  754. {
  755. KIRQL oldIrql;
  756. ULONG writeLength;
  757. ULONG immediateLength;
  758. BOOLEAN immediateWriteDone;
  759. SHARE_TYPE shareType;
  760. PMDL mdl;
  761. ULONG sendLength;
  762. PVOID finalResponseBuffer;
  763. NTSTATUS status = STATUS_SUCCESS;
  764. PRFCB rfcb = WorkContext->Rfcb;
  765. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  766. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_RAW;
  767. SrvWmiStartContext(WorkContext);
  768. IF_DEBUG(FSD1) SrvPrint0( " - SrvFsdRestartWriteRaw\n" );
  769. //
  770. // Find out the file type that we are dealing with. If it is a pipe
  771. // then we have not prewritten the immediate data.
  772. //
  773. // immediateLength is the length of the data sent with the write
  774. // block raw request.
  775. //
  776. shareType = rfcb->ShareType;
  777. immediateLength = WorkContext->Parameters.WriteRaw.ImmediateLength;
  778. immediateWriteDone = WorkContext->Parameters.WriteRaw.ImmediateWriteDone;
  779. //
  780. // Deallocate the raw receive buffer. Note that we do not need to
  781. // unlock the raw buffer, because it was allocated out of nonpaged
  782. // pool and locked using MmBuildMdlForNonPagedPool, which doesn't
  783. // increment reference counts and therefore has no inverse.
  784. //
  785. if ( !WorkContext->Parameters.WriteRaw.MdlWrite ) {
  786. //
  787. // If this is a named pipe the request buffer actually points
  788. // "immediateLength" bytes into the write buffer.
  789. //
  790. if ( immediateWriteDone ) {
  791. DEALLOCATE_NONPAGED_POOL( WorkContext->RequestBuffer->Buffer );
  792. IF_SMB_DEBUG(RAW2) {
  793. SrvPrint1( "raw buffer 0x%p deallocated\n",
  794. WorkContext->RequestBuffer->Buffer );
  795. }
  796. } else {
  797. DEALLOCATE_NONPAGED_POOL(
  798. (PCHAR)WorkContext->RequestBuffer->Buffer - immediateLength );
  799. IF_SMB_DEBUG(RAW2) {
  800. SrvPrint1( "raw buffer 0x%p deallocated\n",
  801. (PCHAR)WorkContext->RequestBuffer->Buffer - immediateLength );
  802. }
  803. }
  804. }
  805. status = WorkContext->Irp->IoStatus.Status;
  806. //
  807. // If this is not a pipe we have already successfully written the
  808. // immediate pipe data, so return the total bytes written by the two
  809. // write operations.
  810. //
  811. writeLength = (ULONG)WorkContext->Irp->IoStatus.Information;
  812. if( NT_SUCCESS( status ) && writeLength == 0 ) {
  813. writeLength = WorkContext->Parameters.WriteRaw.Length;
  814. } else {
  815. if ( immediateWriteDone ) {
  816. writeLength += immediateLength;
  817. }
  818. }
  819. UPDATE_WRITE_STATS( WorkContext, writeLength );
  820. finalResponseBuffer = WorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  821. //
  822. // Update the file position.
  823. //
  824. // !!! Need to worry about wraparound?
  825. //
  826. if ( shareType == ShareTypeDisk || shareType == ShareTypePrint ) {
  827. rfcb->CurrentPosition =
  828. WorkContext->Parameters.WriteRaw.Offset.LowPart + writeLength;
  829. }
  830. if ( finalResponseBuffer == NULL ) {
  831. //
  832. // Update server statistics.
  833. //
  834. UPDATE_STATISTICS( WorkContext, 0, SMB_COM_WRITE_RAW );
  835. //
  836. // Save the write behind error, if any.
  837. //
  838. if ( !NT_SUCCESS( status ) ) {
  839. //
  840. // because of our assumption that the cached rfcb does
  841. // not have a write behind error stored. This saves us
  842. // a compare on our critical path.
  843. //
  844. if ( WorkContext->Connection->CachedFid == (ULONG)rfcb->Fid ) {
  845. WorkContext->Connection->CachedFid = (ULONG)-1;
  846. }
  847. rfcb->SavedError = status;
  848. }
  849. //
  850. // Dereference control blocks, etc.
  851. //
  852. WorkContext->ResponseBuffer->Buffer = NULL;
  853. RestartWriteCompleteResponse( WorkContext );
  854. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartWriteRaw complete\n" );
  855. goto Cleanup;
  856. }
  857. //
  858. // Writethrough mode. Send a response to the client. We have to
  859. // get a little tricky here, to make the raw mode work item look
  860. // enough like a normal one to be able to send using it. Note that
  861. // the header from the original request SMB was copied into the
  862. // final response buffer.
  863. //
  864. WorkContext->ResponseHeader = (PSMB_HEADER)finalResponseBuffer;
  865. WorkContext->ResponseParameters = WorkContext->ResponseHeader + 1;
  866. ASSERT( WorkContext->RequestBuffer == WorkContext->ResponseBuffer );
  867. WorkContext->ResponseBuffer->Buffer = finalResponseBuffer;
  868. sendLength = (ULONG)( (PCHAR)NEXT_LOCATION(
  869. WorkContext->ResponseParameters,
  870. RESP_WRITE_COMPLETE,
  871. 0
  872. ) - (PCHAR)finalResponseBuffer );
  873. WorkContext->ResponseBuffer->DataLength = sendLength;
  874. //
  875. // Remap the MDL to describe the final response buffer.
  876. //
  877. mdl = WorkContext->ResponseBuffer->Mdl;
  878. MmInitializeMdl( mdl, finalResponseBuffer, sendLength );
  879. MmBuildMdlForNonPagedPool( mdl );
  880. //
  881. // Set the bit in the SMB that indicates this is a response from the
  882. // server.
  883. //
  884. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  885. //
  886. // Send the response. When the send completes, the restart routine
  887. // RestartWriteCompleteResponse is called. We then dereference
  888. // control blocks and put the raw mode work item back on the free
  889. // list.
  890. //
  891. if ( (status != STATUS_SUCCESS) &&
  892. (KeGetCurrentIrql() >= DISPATCH_LEVEL) ) {
  893. WorkContext->Irp->IoStatus.Status = status;
  894. WorkContext->Irp->IoStatus.Information = writeLength;
  895. WorkContext->FspRestartRoutine = SrvBuildAndSendWriteCompleteResponse;
  896. WorkContext->FsdRestartRoutine = RestartWriteCompleteResponse; // after response
  897. QUEUE_WORK_TO_FSP( WorkContext );
  898. } else {
  899. SrvFsdBuildWriteCompleteResponse(
  900. WorkContext,
  901. status,
  902. writeLength
  903. );
  904. SRV_START_SEND_2(
  905. WorkContext,
  906. SrvFsdSendCompletionRoutine,
  907. RestartWriteCompleteResponse,
  908. NULL
  909. );
  910. }
  911. Cleanup:
  912. SrvWmiEndContext(WorkContext);
  913. return;
  914. } // SrvFsdRestartWriteRaw