Source code of Windows XP (NT5)
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.

1270 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. PIO_STACK_LOCATION irpSp;
  351. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  352. irp->Tail.Overlay.OriginalFileObject = NULL;
  353. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  354. DEBUG irp->RequestorMode = KernelMode;
  355. //
  356. // Get a pointer to the next stack location. This one is used to
  357. // hold the parameters for the device I/O control request.
  358. //
  359. irpSp = IoGetNextIrpStackLocation( irp );
  360. //
  361. // Set up the completion routine.
  362. //
  363. IoSetCompletionRoutine(
  364. irp,
  365. SrvFsdIoCompletionRoutine,
  366. rawWorkContext,
  367. TRUE,
  368. TRUE,
  369. TRUE
  370. );
  371. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  372. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE;
  373. irpSp->FileObject = NULL;
  374. irpSp->DeviceObject = NULL;
  375. //
  376. // Copy the caller's parameters to the service-specific portion of the
  377. // IRP for those parameters that are the same for all three methods.
  378. //
  379. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  380. parameters->ReceiveLength = writeLength;
  381. parameters->ReceiveFlags = 0;
  382. irp->MdlAddress = mdl;
  383. irp->AssociatedIrp.SystemBuffer = NULL;
  384. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  385. }
  386. IF_SMB_DEBUG(RAW2) {
  387. KdPrint(( "Issuing receive with MDL %p\n", rawWorkContext->Irp->MdlAddress ));
  388. }
  389. irpSp = IoGetNextIrpStackLocation( rawWorkContext->Irp );
  390. //
  391. // If this is a writebehind write, tell the transport that we don't
  392. // plan to reply to the received message.
  393. //
  394. if ( finalResponseBuffer == NULL ) {
  395. ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveFlags |=
  396. TDI_RECEIVE_NO_RESPONSE_EXP;
  397. }
  398. //
  399. // Post the receive.
  400. //
  401. irpSp->Flags = 0;
  402. irpSp->DeviceObject = rawWorkContext->Connection->DeviceObject;
  403. irpSp->FileObject = rawWorkContext->Connection->FileObject;
  404. ASSERT( rawWorkContext->Irp->StackCount >=
  405. irpSp->DeviceObject->StackSize );
  406. (VOID)IoCallDriver( irpSp->DeviceObject, rawWorkContext->Irp );
  407. //
  408. // Send the interim (go-ahead) response.
  409. //
  410. response = (PRESP_WRITE_RAW_INTERIM)WorkContext->ResponseParameters;
  411. response->WordCount = 1;
  412. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  413. SmbPutUshort( &response->ByteCount, 0 );
  414. WorkContext->ResponseParameters = NEXT_LOCATION(
  415. response,
  416. RESP_WRITE_RAW_INTERIM,
  417. 0
  418. );
  419. SrvFsdSendResponse( WorkContext );
  420. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartPrepareRawMdlWrite complete\n" );
  421. Cleanup:
  422. if (bNeedTrace) {
  423. SrvWmiEndContext(WorkContext);
  424. }
  425. return;
  426. } // SrvFsdRestartPrepareRawMdlWrite
  427. VOID SRVFASTCALL
  428. SrvFsdRestartReadRaw (
  429. IN OUT PWORK_CONTEXT WorkContext
  430. )
  431. /*++
  432. Routine Description:
  433. Processes file read completion for the Read Block Raw SMB.
  434. This routine is called in both the FSP and the FSD.
  435. Arguments:
  436. WorkContext - Supplies a pointer to the work context block
  437. describing server-specific context for the request.
  438. Return Value:
  439. None.
  440. --*/
  441. {
  442. PRFCB rfcb;
  443. KIRQL oldIrql;
  444. USHORT readLength;
  445. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  446. if (bNeedTrace) {
  447. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  448. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_RAW;
  449. SrvWmiStartContext(WorkContext);
  450. }
  451. else
  452. WorkContext->bAlreadyTrace = FALSE;
  453. IF_DEBUG(FSD1) SrvPrint0( " - SrvFsdRestartReadRaw\n" );
  454. //
  455. // Get the file pointer.
  456. //
  457. rfcb = WorkContext->Rfcb;
  458. IF_DEBUG(TRACE2) {
  459. SrvPrint2( " connection 0x%p, RFCB 0x%p\n",
  460. WorkContext->Connection, rfcb );
  461. }
  462. //
  463. // Calculate the amount of data read.
  464. //
  465. if ( WorkContext->Irp->IoStatus.Status == STATUS_END_OF_FILE ) {
  466. readLength = 0;
  467. IF_SMB_DEBUG(RAW2) {
  468. SrvPrint0( "SrvFsdRestartReadRaw: 0 bytes read, at end-of-file\n" );
  469. }
  470. } else if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  471. readLength = 0;
  472. IF_SMB_DEBUG(ERRORS) {
  473. SrvPrint1( "SrvFsdRestartReadRaw: read request failed: %X\n",
  474. WorkContext->Irp->IoStatus.Status );
  475. }
  476. } else if ( WorkContext->Parameters.ReadRaw.MdlRead ) {
  477. //
  478. // For an MDL read, we have to walk the MDL chain in order to
  479. // determine how much data was read. This is because the
  480. // operation may have happened in multiple step, with the MDLs
  481. // being chained together. For example, part of the read may
  482. // have been satisfied by the fast path, while the rest was
  483. // satisfied using an IRP.
  484. //
  485. #if DBG
  486. ULONG mdlCount = 0;
  487. #endif
  488. PMDL mdl = WorkContext->Irp->MdlAddress;
  489. readLength = 0;
  490. while ( mdl != NULL ) {
  491. IF_SMB_DEBUG(RAW2) {
  492. #if DBG
  493. SrvPrint3( " mdl %ld at 0x%p, %ld bytes\n",
  494. mdlCount,
  495. mdl, MmGetMdlByteCount(mdl) );
  496. #else
  497. SrvPrint3( " mdl 0x%p, %ld bytes\n",
  498. mdl, MmGetMdlByteCount(mdl) );
  499. #endif
  500. }
  501. readLength += (USHORT)MmGetMdlByteCount(mdl);
  502. #if DBG
  503. mdlCount++;
  504. #endif
  505. mdl = mdl->Next;
  506. }
  507. IF_SMB_DEBUG(RAW2) {
  508. #if DBG
  509. SrvPrint2( "SrvFsdRestartReadRaw: %ld bytes in %ld MDLs\n",
  510. readLength, mdlCount );
  511. #else
  512. SrvPrint2( "SrvFsdRestartReadRaw: %ld bytes\n",
  513. readLength );
  514. #endif
  515. SrvPrint1( " info = 0x%p\n",
  516. (PVOID)WorkContext->Irp->IoStatus.Information );
  517. }
  518. } else {
  519. //
  520. // Copy read. The I/O status block has the length.
  521. //
  522. readLength = (USHORT)WorkContext->Irp->IoStatus.Information;
  523. IF_SMB_DEBUG(RAW2) {
  524. SrvPrint1( "SrvFsdRestartReadRaw: %ld bytes read\n", readLength );
  525. }
  526. }
  527. #ifdef SLMDBG
  528. {
  529. PRFCB_TRACE entry;
  530. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  531. rfcb->OperationCount++;
  532. entry = &rfcb->Trace[rfcb->NextTrace];
  533. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  534. rfcb->NextTrace = 0;
  535. rfcb->TraceWrapped = TRUE;
  536. }
  537. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  538. entry->Command = WorkContext->NextCommand;
  539. entry->Flags =
  540. (UCHAR)(WorkContext->Parameters.ReadRaw.MdlRead ? 1 : 0);
  541. KeQuerySystemTime( &entry->Time );
  542. entry->Data.ReadWrite.Offset =
  543. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset.LowPart;
  544. entry->Data.ReadWrite.Length = readLength;
  545. }
  546. #endif
  547. //
  548. // Update the file position.
  549. //
  550. // *** Note that we ignore the status of the operation, except to
  551. // check for end-of-file, since we can't tell the client what
  552. // the status was. We simply return as many bytes as the file
  553. // system says were read.
  554. //
  555. // !!! Should we save the error and return it when the client
  556. // retries?
  557. //
  558. // !!! Need to worry about wraparound?
  559. //
  560. if ( rfcb->ShareType == ShareTypeDisk ) {
  561. rfcb->CurrentPosition =
  562. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset.LowPart +
  563. readLength;
  564. }
  565. //
  566. // Save the count of bytes read, to be used to update the server
  567. // statistics database.
  568. //
  569. UPDATE_READ_STATS( WorkContext, readLength );
  570. //
  571. // Send the raw read data as the response.
  572. //
  573. WorkContext->ResponseBuffer->DataLength = readLength;
  574. //
  575. // There is no header on this SMB, do not generate a security signature
  576. //
  577. WorkContext->NoResponseSmbSecuritySignature = TRUE;
  578. if ( WorkContext->Parameters.ReadRaw.MdlRead ) {
  579. //
  580. // MDL read. The data is described by the MDL returned by the
  581. // file system (in irp->MdlAddress).
  582. //
  583. // *** Note that if the read failed completely (which happens if
  584. // the read starts beyond EOF), there is no MDL.
  585. // SrvStartSend handles this appropriately. So must
  586. // RestartMdlReadRawResponse.
  587. //
  588. //
  589. // Send the response.
  590. //
  591. SRV_START_SEND(
  592. WorkContext,
  593. WorkContext->Irp->MdlAddress,
  594. 0,
  595. SrvQueueWorkToFspAtSendCompletion,
  596. NULL,
  597. RestartMdlReadRawResponse
  598. );
  599. } else {
  600. //
  601. // Copy read. The data is described by the MDL allocated in
  602. // SrvFsdSmbReadRaw.
  603. //
  604. // *** Changing Mdl->ByteCount like this would be a problem if
  605. // we had to unlock the pages in RestartCopyReadRawResponse,
  606. // because we might end up unlocking fewer pages than we
  607. // locked. But we don't actually lock the pages to build
  608. // the MDL -- the buffer is allocated from nonpaged pool, so
  609. // we use MmBuildMdlForNonPagedPool rather than
  610. // MmProbeAndLockPages. So the pages haven't been
  611. // referenced to account for the MDL, so there's no need to
  612. // unlock them, so changing ByteCount isn't a problem.
  613. //
  614. //
  615. // Send the response.
  616. //
  617. SRV_START_SEND_2(
  618. WorkContext,
  619. RestartCopyReadRawResponse,
  620. NULL,
  621. NULL
  622. );
  623. }
  624. //
  625. // The response send has been started.
  626. //
  627. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartReadRaw complete\n" );
  628. if (bNeedTrace) {
  629. SrvWmiEndContext(WorkContext);
  630. }
  631. return;
  632. } // SrvFsdRestartReadRaw
  633. VOID SRVFASTCALL
  634. RestartWriteCompleteResponse (
  635. IN OUT PWORK_CONTEXT WorkContext
  636. )
  637. /*++
  638. Routine Description:
  639. This routine attempts, at DPC level, to clean up after a Write Raw
  640. completes. It tries to dereference control blocks referenced by the
  641. raw mode work item. If this cannot be done at DPC level (e.g., a
  642. reference count goes to zero), this routine queues the work item to
  643. the FSP for processing.
  644. This routine is called in the FSD. Its FSP counterpart is
  645. SrvRestartWriteCompleteResponse.
  646. Arguments:
  647. WorkContext - Supplies a pointer to the work context block
  648. describing server-specific context for the request.
  649. Return Value:
  650. None.
  651. --*/
  652. {
  653. PCONNECTION connection;
  654. KIRQL oldIrql;
  655. PRFCB rfcb;
  656. PWORK_QUEUE queue;
  657. UNLOCKABLE_CODE( 8FIL );
  658. IF_DEBUG(FSD1) SrvPrint0( " - RestartWriteCompleteResponse\n" );
  659. connection = WorkContext->Connection;
  660. queue = connection->CurrentWorkQueue;
  661. //
  662. // If a final response was sent, check the status and deallocate the
  663. // buffer.
  664. //
  665. if ( WorkContext->ResponseBuffer->Buffer != NULL ) {
  666. //
  667. // If the I/O request failed or was canceled, print an error
  668. // message.
  669. //
  670. // !!! If I/O failure, should we drop the connection?
  671. //
  672. if ( WorkContext->Irp->Cancel ||
  673. !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  674. IF_DEBUG(FSD1) {
  675. if ( WorkContext->Irp->Cancel ) {
  676. SrvPrint0( " I/O canceled\n" );
  677. } else {
  678. SrvPrint1( " I/O failed: %X\n",
  679. WorkContext->Irp->IoStatus.Status );
  680. }
  681. }
  682. }
  683. //
  684. // Deallocate the final response buffer.
  685. //
  686. // *** Note that we don't need to unlock it, because it was
  687. // allocated from nonpaged pool.
  688. //
  689. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer->Buffer );
  690. }
  691. //
  692. // If the work context block has references to a share, a session,
  693. // or a tree connect, queue it to the FSP immediately. These blocks
  694. // are not in nonpaged pool, so they can't be touched at DPC level.
  695. //
  696. if ( (WorkContext->Share != NULL) ||
  697. (WorkContext->Session != NULL) ||
  698. (WorkContext->TreeConnect != NULL) ) {
  699. goto queueToFsp;
  700. }
  701. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  702. //
  703. // See if we can dereference the RawWriteCount here. If the raw
  704. // write count goes to 0, and the RFCB is closing, or if there are
  705. // work items queued waiting for the raw write to complete, we need
  706. // to do this in the FSP.
  707. //
  708. // NOTE: The FSP decrements the count if WorkContext->Rfcb != NULL.
  709. //
  710. rfcb = WorkContext->Rfcb;
  711. --rfcb->RawWriteCount;
  712. if ( (rfcb->RawWriteCount == 0) &&
  713. ( (GET_BLOCK_STATE(rfcb) == BlockStateClosing) ||
  714. !IsListEmpty(&rfcb->RawWriteSerializationList) ) ) {
  715. rfcb->RawWriteCount++;
  716. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  717. goto queueToFsp;
  718. }
  719. //
  720. // Dereference the file block. It is safe to decrement the count here
  721. // because either the rfcb is not closed or RawWriteCount is not zero
  722. // which means that the active reference is still there.
  723. //
  724. UPDATE_REFERENCE_HISTORY( rfcb, TRUE );
  725. --rfcb->BlockHeader.ReferenceCount;
  726. ASSERT( rfcb->BlockHeader.ReferenceCount > 0 );
  727. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  728. WorkContext->Rfcb = NULL;
  729. //
  730. // Attempt to dereference the connection.
  731. //
  732. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  733. if ( connection->BlockHeader.ReferenceCount == 1 ) {
  734. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  735. goto queueToFsp;
  736. }
  737. --connection->BlockHeader.ReferenceCount;
  738. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  739. UPDATE_REFERENCE_HISTORY( connection, TRUE );
  740. WorkContext->Connection = NULL;
  741. WorkContext->Endpoint = NULL; // not a referenced pointer
  742. //
  743. // Put the work item back on the raw mode work item list.
  744. //
  745. InterlockedIncrement( &queue->FreeRawModeWorkItems );
  746. ExInterlockedPushEntrySList( &queue->RawModeWorkItemList,
  747. &WorkContext->SingleListEntry,
  748. &queue->SpinLock );
  749. IF_DEBUG(FSD2) SrvPrint0( "RestartWriteCompleteResponse complete\n" );
  750. return;
  751. queueToFsp:
  752. //
  753. // We were unable to do all the necessary cleanup at DPC level.
  754. // Queue the work item to the FSP.
  755. //
  756. WorkContext->FspRestartRoutine = SrvRestartWriteCompleteResponse;
  757. SrvQueueWorkToFsp( WorkContext );
  758. IF_DEBUG(FSD2) SrvPrint0( "RestartWriteCompleteResponse complete\n" );
  759. return;
  760. } // RestartWriteCompleteResponse
  761. VOID SRVFASTCALL
  762. SrvFsdRestartWriteRaw (
  763. IN OUT PWORK_CONTEXT WorkContext
  764. )
  765. /*++
  766. Routine Description:
  767. Processes file write completion for the Write Block Raw SMB.
  768. This routine is called in both the FSP and the FSD.
  769. Arguments:
  770. WorkContext - Supplies a pointer to the work context block
  771. describing server-specific context for the request.
  772. Return Value:
  773. None.
  774. --*/
  775. {
  776. KIRQL oldIrql;
  777. ULONG writeLength;
  778. ULONG immediateLength;
  779. BOOLEAN immediateWriteDone;
  780. SHARE_TYPE shareType;
  781. PMDL mdl;
  782. ULONG sendLength;
  783. PVOID finalResponseBuffer;
  784. NTSTATUS status = STATUS_SUCCESS;
  785. PRFCB rfcb = WorkContext->Rfcb;
  786. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  787. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_RAW;
  788. SrvWmiStartContext(WorkContext);
  789. IF_DEBUG(FSD1) SrvPrint0( " - SrvFsdRestartWriteRaw\n" );
  790. //
  791. // Find out the file type that we are dealing with. If it is a pipe
  792. // then we have not prewritten the immediate data.
  793. //
  794. // immediateLength is the length of the data sent with the write
  795. // block raw request.
  796. //
  797. shareType = rfcb->ShareType;
  798. immediateLength = WorkContext->Parameters.WriteRaw.ImmediateLength;
  799. immediateWriteDone = WorkContext->Parameters.WriteRaw.ImmediateWriteDone;
  800. //
  801. // Deallocate the raw receive buffer. Note that we do not need to
  802. // unlock the raw buffer, because it was allocated out of nonpaged
  803. // pool and locked using MmBuildMdlForNonPagedPool, which doesn't
  804. // increment reference counts and therefore has no inverse.
  805. //
  806. if ( !WorkContext->Parameters.WriteRaw.MdlWrite ) {
  807. //
  808. // If this is a named pipe the request buffer actually points
  809. // "immediateLength" bytes into the write buffer.
  810. //
  811. if ( immediateWriteDone ) {
  812. DEALLOCATE_NONPAGED_POOL( WorkContext->RequestBuffer->Buffer );
  813. IF_SMB_DEBUG(RAW2) {
  814. SrvPrint1( "raw buffer 0x%p deallocated\n",
  815. WorkContext->RequestBuffer->Buffer );
  816. }
  817. } else {
  818. DEALLOCATE_NONPAGED_POOL(
  819. (PCHAR)WorkContext->RequestBuffer->Buffer - immediateLength );
  820. IF_SMB_DEBUG(RAW2) {
  821. SrvPrint1( "raw buffer 0x%p deallocated\n",
  822. (PCHAR)WorkContext->RequestBuffer->Buffer - immediateLength );
  823. }
  824. }
  825. }
  826. status = WorkContext->Irp->IoStatus.Status;
  827. //
  828. // If this is not a pipe we have already successfully written the
  829. // immediate pipe data, so return the total bytes written by the two
  830. // write operations.
  831. //
  832. writeLength = (ULONG)WorkContext->Irp->IoStatus.Information;
  833. if( NT_SUCCESS( status ) && writeLength == 0 ) {
  834. writeLength = WorkContext->Parameters.WriteRaw.Length;
  835. } else {
  836. if ( immediateWriteDone ) {
  837. writeLength += immediateLength;
  838. }
  839. }
  840. UPDATE_WRITE_STATS( WorkContext, writeLength );
  841. finalResponseBuffer = WorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  842. //
  843. // Update the file position.
  844. //
  845. // !!! Need to worry about wraparound?
  846. //
  847. if ( shareType == ShareTypeDisk || shareType == ShareTypePrint ) {
  848. rfcb->CurrentPosition =
  849. WorkContext->Parameters.WriteRaw.Offset.LowPart + writeLength;
  850. }
  851. if ( finalResponseBuffer == NULL ) {
  852. //
  853. // Update server statistics.
  854. //
  855. UPDATE_STATISTICS( WorkContext, 0, SMB_COM_WRITE_RAW );
  856. //
  857. // Save the write behind error, if any.
  858. //
  859. if ( !NT_SUCCESS( status ) ) {
  860. //
  861. // because of our assumption that the cached rfcb does
  862. // not have a write behind error stored. This saves us
  863. // a compare on our critical path.
  864. //
  865. if ( WorkContext->Connection->CachedFid == (ULONG)rfcb->Fid ) {
  866. WorkContext->Connection->CachedFid = (ULONG)-1;
  867. }
  868. rfcb->SavedError = status;
  869. }
  870. //
  871. // Dereference control blocks, etc.
  872. //
  873. WorkContext->ResponseBuffer->Buffer = NULL;
  874. RestartWriteCompleteResponse( WorkContext );
  875. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartWriteRaw complete\n" );
  876. goto Cleanup;
  877. }
  878. //
  879. // Writethrough mode. Send a response to the client. We have to
  880. // get a little tricky here, to make the raw mode work item look
  881. // enough like a normal one to be able to send using it. Note that
  882. // the header from the original request SMB was copied into the
  883. // final response buffer.
  884. //
  885. WorkContext->ResponseHeader = (PSMB_HEADER)finalResponseBuffer;
  886. WorkContext->ResponseParameters = WorkContext->ResponseHeader + 1;
  887. ASSERT( WorkContext->RequestBuffer == WorkContext->ResponseBuffer );
  888. WorkContext->ResponseBuffer->Buffer = finalResponseBuffer;
  889. sendLength = (ULONG)( (PCHAR)NEXT_LOCATION(
  890. WorkContext->ResponseParameters,
  891. RESP_WRITE_COMPLETE,
  892. 0
  893. ) - (PCHAR)finalResponseBuffer );
  894. WorkContext->ResponseBuffer->DataLength = sendLength;
  895. //
  896. // Remap the MDL to describe the final response buffer.
  897. //
  898. mdl = WorkContext->ResponseBuffer->Mdl;
  899. MmInitializeMdl( mdl, finalResponseBuffer, sendLength );
  900. MmBuildMdlForNonPagedPool( mdl );
  901. //
  902. // Set the bit in the SMB that indicates this is a response from the
  903. // server.
  904. //
  905. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  906. //
  907. // Send the response. When the send completes, the restart routine
  908. // RestartWriteCompleteResponse is called. We then dereference
  909. // control blocks and put the raw mode work item back on the free
  910. // list.
  911. //
  912. if ( (status != STATUS_SUCCESS) &&
  913. (KeGetCurrentIrql() >= DISPATCH_LEVEL) ) {
  914. WorkContext->Irp->IoStatus.Status = status;
  915. WorkContext->Irp->IoStatus.Information = writeLength;
  916. WorkContext->FspRestartRoutine = SrvBuildAndSendWriteCompleteResponse;
  917. WorkContext->FsdRestartRoutine = RestartWriteCompleteResponse; // after response
  918. QUEUE_WORK_TO_FSP( WorkContext );
  919. } else {
  920. SrvFsdBuildWriteCompleteResponse(
  921. WorkContext,
  922. status,
  923. writeLength
  924. );
  925. SRV_START_SEND_2(
  926. WorkContext,
  927. SrvFsdSendCompletionRoutine,
  928. RestartWriteCompleteResponse,
  929. NULL
  930. );
  931. }
  932. Cleanup:
  933. SrvWmiEndContext(WorkContext);
  934. return;
  935. } // SrvFsdRestartWriteRaw