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.

3291 lines
92 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbraw.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs in
  7. the server FSP:
  8. Read Block Raw
  9. Write Block Raw
  10. The routines in this module generally work closely with the routines
  11. in fsdraw.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 "smbraw.tmh"
  25. #pragma hdrstop
  26. #define BugCheckFileId SRV_FILE_SMBRAW
  27. //
  28. // Forward declarations
  29. //
  30. VOID SRVFASTCALL
  31. AbortRawWrite(
  32. IN OUT PWORK_CONTEXT WorkContext
  33. );
  34. VOID SRVFASTCALL
  35. PrepareRawCopyWrite (
  36. IN OUT PWORK_CONTEXT WorkContext
  37. );
  38. BOOLEAN SRVFASTCALL
  39. ReadRawPipe (
  40. IN PWORK_CONTEXT WorkContext
  41. );
  42. VOID SRVFASTCALL
  43. RestartMdlReadRawResponse (
  44. IN OUT PWORK_CONTEXT WorkContext
  45. );
  46. VOID SRVFASTCALL
  47. RestartPipeReadRawPeek (
  48. IN OUT PWORK_CONTEXT WorkContext
  49. );
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text( PAGE, SrvSmbWriteRaw )
  52. #pragma alloc_text( PAGE, AbortRawWrite )
  53. #pragma alloc_text( PAGE, PrepareRawCopyWrite )
  54. #pragma alloc_text( PAGE, ReadRawPipe )
  55. #pragma alloc_text( PAGE, RestartMdlReadRawResponse )
  56. #pragma alloc_text( PAGE, RestartPipeReadRawPeek )
  57. #pragma alloc_text( PAGE, SrvRestartRawReceive )
  58. #pragma alloc_text( PAGE, SrvRestartReadRawComplete )
  59. #pragma alloc_text( PAGE, SrvRestartWriteCompleteResponse )
  60. #pragma alloc_text( PAGE, SrvBuildAndSendWriteCompleteResponse )
  61. #endif
  62. #if 0
  63. NOT PAGEABLE -- DumpMdlChain
  64. NOT PAGEABLE -- SrvSmbReadRaw
  65. NOT PAGEABLE -- SrvDecrementRawWriteCount
  66. #endif
  67. #if DBG
  68. VOID
  69. DumpMdlChain(
  70. IN PMDL mdl
  71. )
  72. {
  73. ULONG mdlCount = 0;
  74. ULONG length = 0;
  75. if ( mdl == NULL ) {
  76. KdPrint(( " <empty MDL chain>\n" ));
  77. return;
  78. }
  79. do {
  80. KdPrint(( " mdl %p len %04x flags %04x sysva %p va %p offset %04x\n",
  81. mdl, mdl->ByteCount, mdl->MdlFlags,
  82. mdl->MappedSystemVa, mdl->StartVa, mdl->ByteOffset ));
  83. length += mdl->ByteCount;
  84. mdlCount++;
  85. mdl = mdl->Next;
  86. } while ( mdl != NULL );
  87. KdPrint(( " total of %ld bytes in %ld MDLs\n", length, mdlCount ));
  88. return;
  89. }
  90. #endif
  91. SMB_PROCESSOR_RETURN_TYPE
  92. SrvSmbReadRaw (
  93. SMB_PROCESSOR_PARAMETERS
  94. )
  95. /*++
  96. Routine Description:
  97. Processes the Read Block Raw SMB.
  98. Note that Read Block Raw cannot return an error response. When the
  99. server is unable to process the request, for whatever reason, it
  100. simply responds with a zero-length message. The client uses a
  101. normal Read SMB to determine what happened.
  102. Arguments:
  103. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description of the
  104. parameters to SMB processor routines.
  105. Return Value:
  106. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  107. --*/
  108. {
  109. PREQ_READ_RAW request;
  110. PREQ_NT_READ_RAW ntRequest;
  111. NTSTATUS status = STATUS_SUCCESS;
  112. SMB_STATUS SmbStatus = SmbStatusInProgress;
  113. USHORT fid;
  114. PRFCB rfcb;
  115. PLFCB lfcb;
  116. PCONNECTION connection;
  117. UCHAR minorFunction = 0;
  118. PVOID rawBuffer = NULL;
  119. CLONG readLength;
  120. PMDL mdl = NULL;
  121. ULONG key;
  122. LARGE_INTEGER offset;
  123. SHARE_TYPE shareType;
  124. KIRQL oldIrql;
  125. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  126. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_RAW;
  127. SrvWmiStartContext(WorkContext);
  128. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsAttempted );
  129. request = (PREQ_READ_RAW)WorkContext->RequestParameters;
  130. fid = SmbGetUshort( &request->Fid );
  131. IF_SMB_DEBUG(RAW1) {
  132. KdPrint(( "Read Block Raw request; FID 0x%lx, count %ld, "
  133. "offset %ld\n",
  134. fid, SmbGetUshort( &request->MaxCount ),
  135. SmbGetUlong( &request->Offset ) ));
  136. }
  137. //
  138. // If raw mode has been disabled or if the connection is unreliable,
  139. // reject the raw read. Ask the client to use standard read by
  140. // sending a zero-length response. The client will react by issuing
  141. // a normal Read SMB, which we will be able to process.
  142. //
  143. connection = WorkContext->Connection;
  144. if ( !SrvEnableRawMode || !connection->EnableRawIo ) {
  145. IF_SMB_DEBUG(RAW1) {
  146. KdPrint(( "SrvSmbReadRaw: Raw mode is disabled\n" ));
  147. }
  148. goto error_exit_no_cleanup;
  149. }
  150. //
  151. // Get the rfcb
  152. //
  153. //
  154. // Acquire the spin lock that guards the connection's file table.
  155. //
  156. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  157. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  158. if ( connection->CachedFid == fid ) {
  159. rfcb = connection->CachedRfcb;
  160. } else {
  161. PTABLE_HEADER tableHeader;
  162. USHORT index;
  163. USHORT sequence;
  164. //
  165. // Initialize local variables: obtain the connection block address
  166. // and crack the FID into its components.
  167. //
  168. index = FID_INDEX( fid );
  169. sequence = FID_SEQUENCE( fid );
  170. //
  171. // Verify that the FID is in range, is in use, and has the correct
  172. // sequence number.
  173. tableHeader = &connection->FileTable;
  174. if ( (index >= (USHORT)tableHeader->TableSize) ||
  175. (tableHeader->Table[index].Owner == NULL) ||
  176. (tableHeader->Table[index].SequenceNumber != sequence) ) {
  177. goto error_exit_no_cleanup_locked;
  178. }
  179. rfcb = tableHeader->Table[index].Owner;
  180. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  181. goto error_exit_no_cleanup_locked;
  182. }
  183. //
  184. // If there is a write behind error, reject the raw read.
  185. //
  186. if ( !NT_SUCCESS(rfcb->SavedError) ) {
  187. goto error_exit_no_cleanup_locked;
  188. }
  189. //
  190. // Cache this rfcb
  191. //
  192. connection->CachedRfcb = rfcb;
  193. connection->CachedFid = (ULONG)fid;
  194. }
  195. //
  196. // The FID is valid within the context of this connection. Verify
  197. // that the file is still active and that the owning tree connect's
  198. // TID is correct.
  199. //
  200. // Do not verify the UID for clients that do not understand it.
  201. //
  202. if ( (rfcb->Tid !=
  203. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid )) ||
  204. ((rfcb->Uid !=
  205. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )) &&
  206. DIALECT_HONORS_UID(connection->SmbDialect)) ) {
  207. goto error_exit_no_cleanup_locked;
  208. }
  209. //
  210. // Mark the rfcb as active
  211. //
  212. rfcb->IsActive = TRUE;
  213. //
  214. // If a raw write is active, queue this work item in the RFCB
  215. // pending completion of the raw write.
  216. //
  217. if ( rfcb->RawWriteCount != 0 ) {
  218. InsertTailList(
  219. &rfcb->RawWriteSerializationList,
  220. &WorkContext->ListEntry
  221. );
  222. //
  223. // These 2 fields must be set with the connection spinlock held
  224. // since the workitem might be picked up by another thread and
  225. // a race condition will occur.
  226. //
  227. WorkContext->FspRestartRoutine = SrvRestartSmbReceived;
  228. WorkContext->Rfcb = NULL;
  229. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  230. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  231. SmbStatus = SmbStatusInProgress;
  232. goto Cleanup;
  233. }
  234. //
  235. // If this is a pipe read, we do things differently.
  236. //
  237. shareType = rfcb->ShareType;
  238. if ( shareType == ShareTypePipe ) {
  239. //
  240. // Indicate that a raw read is in progress on the connection.
  241. //
  242. connection->RawReadsInProgress++;
  243. //
  244. // The raw read can be accepted. Reference the RFCB.
  245. //
  246. rfcb->BlockHeader.ReferenceCount++;
  247. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  248. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  249. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  250. WorkContext->Rfcb = rfcb;
  251. if ( !ReadRawPipe( WorkContext ) ) {
  252. goto error_exit_cleanup;
  253. }
  254. SmbStatus = SmbStatusInProgress;
  255. goto Cleanup;
  256. }
  257. //
  258. // If there is an oplock break in progress, return 0 bytes read. We
  259. // do this because our oplock break request SMB may have crossed on
  260. // the wire with the read raw request and it may have been received
  261. // in the client's raw read buffer. This would cause the raw data
  262. // to complete in the client's regular receive buffer and possibly
  263. // to overrun it.
  264. //
  265. // If this is not the case, the client will simply retry the read
  266. // using a different read protocol. If it is the case, the client
  267. // must detect this and break the oplock, then redo the read.
  268. //
  269. if ( connection->OplockBreaksInProgress > 0 ) {
  270. goto error_exit_no_cleanup_locked;
  271. }
  272. //
  273. // Check to see whether we got a round trip break/response. If so,
  274. // reject read raw.
  275. //
  276. if ( (LONG)(connection->LatestOplockBreakResponse -
  277. WorkContext->Timestamp) >= 0 ) {
  278. goto error_exit_no_cleanup_locked;
  279. }
  280. //
  281. // If this is the first SMB received after sending an oplock break
  282. // II to none, reject this read. We need to do this because there
  283. // is no response to such a break, so we don't know for sure if the
  284. // break crossed with the read, which would mean that the break
  285. // actually completed the client's read, which would mean that any
  286. // raw data that we sent would be incorrectly received.
  287. //
  288. if ( connection->BreakIIToNoneJustSent ) {
  289. connection->BreakIIToNoneJustSent = FALSE;
  290. goto error_exit_no_cleanup_locked;
  291. }
  292. //
  293. // Indicate that a raw read is in progress on the connection.
  294. //
  295. connection->RawReadsInProgress++;
  296. //
  297. // The raw read can be accepted. Reference the RFCB.
  298. //
  299. rfcb->BlockHeader.ReferenceCount++;
  300. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  301. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  302. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  303. WorkContext->Rfcb = rfcb;
  304. if( rfcb->Lfcb->Session->IsSessionExpired )
  305. {
  306. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  307. goto error_exit_cleanup;
  308. }
  309. //
  310. // Verify that the client has read access to the file via the
  311. // specified handle.
  312. //
  313. lfcb = rfcb->Lfcb;
  314. #if SRVCATCH
  315. if ( rfcb->SrvCatch ) {
  316. //
  317. // Force the client through the core read path for this file
  318. //
  319. goto error_exit_cleanup;
  320. }
  321. #endif
  322. if ( !rfcb->ReadAccessGranted ) {
  323. CHECK_PAGING_IO_ACCESS(
  324. WorkContext,
  325. rfcb->GrantedAccess,
  326. &status );
  327. if ( !NT_SUCCESS( status ) ) {
  328. SrvStatistics.GrantedAccessErrors++;
  329. IF_DEBUG(ERRORS) {
  330. KdPrint(( "SrvSmbReadRaw: Read access not granted.\n"));
  331. }
  332. goto error_exit_cleanup;
  333. }
  334. }
  335. //
  336. // Calculate and save the read offset.
  337. //
  338. if ( request->WordCount == 8 ) {
  339. //
  340. // The client supplied a 32-bit offset.
  341. //
  342. offset.QuadPart = SmbGetUlong( &request->Offset );
  343. } else if ( request->WordCount == 10 ) {
  344. //
  345. // The client supplied a 64-bit offset.
  346. //
  347. ntRequest = (PREQ_NT_READ_RAW)WorkContext->RequestParameters;
  348. offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  349. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  350. //
  351. // Reject negative offsets
  352. //
  353. if ( offset.QuadPart < 0 ) {
  354. IF_DEBUG(ERRORS) {
  355. KdPrint(( "SrvSmbReadRaw: Negative offset rejected.\n"));
  356. }
  357. goto error_exit_cleanup;
  358. }
  359. } else {
  360. //
  361. // Invalid word count. Return 0 bytes.
  362. //
  363. goto error_exit_cleanup;
  364. }
  365. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset = offset;
  366. //
  367. // If this operation may block, and we're running short of
  368. // resources, or if the target is a paused comm device, reject the
  369. // request.
  370. //
  371. //
  372. // Form the lock key using the FID and the PID.
  373. //
  374. // *** The FID must be included in the key in order to account for
  375. // the folding of multiple remote compatibility mode opens into
  376. // a single local open.
  377. //
  378. key = rfcb->ShiftedFid |
  379. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  380. //
  381. // If the SMB buffer is large enough, use it to do the local read.
  382. //
  383. readLength = SmbGetUshort( &request->MaxCount );
  384. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Length = readLength;
  385. if ( //0 &&
  386. (readLength <= SrvMdlReadSwitchover) ) {
  387. do_copy_read:
  388. WorkContext->Parameters.ReadRaw.SavedResponseBuffer = NULL;
  389. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  390. //
  391. // Try the fast I/O path first.
  392. //
  393. if ( lfcb->FastIoRead != NULL ) {
  394. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  395. try {
  396. if ( lfcb->FastIoRead(
  397. lfcb->FileObject,
  398. &offset,
  399. readLength,
  400. TRUE,
  401. key,
  402. WorkContext->ResponseBuffer->Buffer,
  403. &WorkContext->Irp->IoStatus,
  404. lfcb->DeviceObject
  405. ) ) {
  406. //
  407. // The fast I/O path worked. Send the data.
  408. //
  409. WorkContext->bAlreadyTrace = TRUE;
  410. SrvFsdRestartReadRaw( WorkContext );
  411. SmbStatus = SmbStatusInProgress;
  412. goto Cleanup;
  413. }
  414. }
  415. except( EXCEPTION_EXECUTE_HANDLER ) {
  416. // Fall through to the slow path on an exception
  417. NTSTATUS status = GetExceptionCode();
  418. IF_DEBUG(ERRORS) {
  419. KdPrint(("FastIoRead threw exception %x\n", status ));
  420. }
  421. }
  422. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  423. }
  424. //
  425. // The fast I/O path failed, so we need to use a regular copy
  426. // I/O request. Build an MDL describing the read buffer.
  427. //
  428. // *** Note the assumption that the response buffer already has
  429. // a valid full MDL from which a partial MDL can be built.
  430. //
  431. IoBuildPartialMdl(
  432. WorkContext->ResponseBuffer->Mdl,
  433. WorkContext->ResponseBuffer->PartialMdl,
  434. WorkContext->ResponseBuffer->Buffer,
  435. readLength
  436. );
  437. mdl = WorkContext->ResponseBuffer->PartialMdl;
  438. rawBuffer = WorkContext->ResponseHeader;
  439. ASSERT( minorFunction == 0 );
  440. } else {
  441. //
  442. // The SMB buffer isn't big enough. Does the target file system
  443. // support the cache manager routines?
  444. //
  445. if ( lfcb->FileObject->Flags & FO_CACHE_SUPPORTED ) {
  446. WorkContext->Parameters.ReadRaw.MdlRead = TRUE;
  447. //
  448. // We can use an MDL read. Try the fast I/O path first.
  449. //
  450. WorkContext->Irp->MdlAddress = NULL;
  451. WorkContext->Irp->IoStatus.Information = 0;
  452. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  453. if ( lfcb->MdlRead(
  454. lfcb->FileObject,
  455. &offset,
  456. readLength,
  457. key,
  458. &WorkContext->Irp->MdlAddress,
  459. &WorkContext->Irp->IoStatus,
  460. lfcb->DeviceObject
  461. ) && WorkContext->Irp->MdlAddress ) {
  462. //
  463. // The fast I/O path worked. Send the data.
  464. //
  465. WorkContext->bAlreadyTrace = TRUE;
  466. SrvFsdRestartReadRaw( WorkContext );
  467. SmbStatus = SmbStatusInProgress;
  468. goto Cleanup;
  469. }
  470. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  471. //
  472. // The fast I/O path failed. We need to issue a regular MDL
  473. // read request.
  474. //
  475. // The fast path may have partially succeeded, returning a
  476. // partial MDL chain. We need to adjust our read request
  477. // to account for that.
  478. //
  479. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  480. readLength -= (ULONG)WorkContext->Irp->IoStatus.Information;
  481. mdl = WorkContext->Irp->MdlAddress;
  482. minorFunction = IRP_MN_MDL;
  483. } else if (readLength > WorkContext->ResponseBuffer->BufferLength) {
  484. //
  485. // We have to use a normal "copy" read. We need to allocate
  486. // a separate raw buffer.
  487. //
  488. ASSERT( minorFunction == 0 );
  489. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  490. rawBuffer = ALLOCATE_NONPAGED_POOL(
  491. readLength,
  492. BlockTypeDataBuffer
  493. );
  494. IF_SMB_DEBUG(RAW2) KdPrint(( "rawBuffer: 0x%p\n", rawBuffer ));
  495. if ( rawBuffer == NULL ) {
  496. IF_DEBUG(ERRORS) {
  497. KdPrint(( "SrvSmbReadRaw: Unable to allocate raw "
  498. "buffer\n" ));
  499. }
  500. goto error_exit_cleanup;
  501. }
  502. //
  503. // We also need a buffer descriptor.
  504. //
  505. // *** Note: Currently, ResponseBuffer == RequestBuffer in a
  506. // WorkContext block, so we don't really have to save
  507. // the ResponseBuffer field. But we do so just to be on
  508. // the safe side.
  509. //
  510. WorkContext->Parameters.ReadRaw.SavedResponseBuffer =
  511. WorkContext->ResponseBuffer;
  512. WorkContext->ResponseBuffer = ALLOCATE_NONPAGED_POOL(
  513. sizeof(BUFFER),
  514. BlockTypeBuffer
  515. );
  516. if ( WorkContext->ResponseBuffer == NULL ) {
  517. INTERNAL_ERROR(
  518. ERROR_LEVEL_EXPECTED,
  519. "SrvSmbReadRaw: Unable to allocate %d bytes from "
  520. "nonpaged pool.",
  521. sizeof(BUFFER),
  522. NULL
  523. );
  524. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  525. WorkContext->ResponseBuffer =
  526. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  527. goto error_exit_cleanup;
  528. }
  529. WorkContext->ResponseBuffer->Buffer = rawBuffer;
  530. WorkContext->ResponseBuffer->BufferLength = readLength;
  531. //
  532. // Finally, we need an MDL to describe the raw buffer.
  533. //
  534. // *** We used to try to use the PartialMdl for the SMB
  535. // buffer here, if it was big enough. But since we
  536. // already decided that the buffer itself isn't big
  537. // enough, it's extremely likely that the MDL isn't big
  538. // enough either.
  539. //
  540. mdl = IoAllocateMdl( rawBuffer, readLength, FALSE, FALSE, NULL );
  541. if ( mdl == NULL ) {
  542. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  543. WorkContext->ResponseBuffer =
  544. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  545. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  546. goto error_exit_cleanup;
  547. }
  548. WorkContext->ResponseBuffer->Mdl = mdl;
  549. //
  550. // Build the mdl
  551. //
  552. MmBuildMdlForNonPagedPool( mdl );
  553. //
  554. // Try the fast I/O path first.
  555. //
  556. if ( lfcb->FastIoRead != NULL ) {
  557. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  558. try {
  559. if ( lfcb->FastIoRead(
  560. lfcb->FileObject,
  561. &offset,
  562. readLength,
  563. TRUE,
  564. key,
  565. WorkContext->ResponseBuffer->Buffer,
  566. &WorkContext->Irp->IoStatus,
  567. lfcb->DeviceObject
  568. ) ) {
  569. //
  570. // The fast I/O path worked. Send the data.
  571. //
  572. WorkContext->bAlreadyTrace = TRUE;
  573. SrvFsdRestartReadRaw( WorkContext );
  574. SmbStatus = SmbStatusInProgress;
  575. goto Cleanup;
  576. }
  577. }
  578. except( EXCEPTION_EXECUTE_HANDLER ) {
  579. // Fall through to the slow path on an exception
  580. NTSTATUS status = GetExceptionCode();
  581. IF_DEBUG(ERRORS) {
  582. KdPrint(("FastIoRead threw exception %x\n", status ));
  583. }
  584. }
  585. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  586. }
  587. //
  588. // The fast I/O path failed, so we need to use a regular copy
  589. // I/O request.
  590. //
  591. } else {
  592. goto do_copy_read;
  593. }
  594. } // read fits in SMB buffer?
  595. //
  596. // Build the read request, reusing the receive IRP.
  597. //
  598. SrvBuildReadOrWriteRequest(
  599. WorkContext->Irp, // input IRP address
  600. lfcb->FileObject, // target file object address
  601. WorkContext, // context
  602. IRP_MJ_READ, // major function code
  603. minorFunction, // minor function code
  604. rawBuffer, // buffer address
  605. readLength, // buffer length
  606. mdl, // MDL address
  607. offset, // byte offset
  608. key // lock key
  609. );
  610. //
  611. // Pass the request to the file system.
  612. //
  613. WorkContext->bAlreadyTrace = TRUE;
  614. WorkContext->FsdRestartRoutine = SrvFsdRestartReadRaw;
  615. DEBUG WorkContext->FspRestartRoutine = NULL;
  616. IF_SMB_DEBUG(RAW2) {
  617. KdPrint(( "SrvSmbReadRaw: reading from file 0x%p, offset %ld, length %ld, destination 0x%p, ",
  618. lfcb->FileObject, offset.LowPart, readLength,
  619. rawBuffer ));
  620. KdPrint(( "func 0x%lx\n", minorFunction ));
  621. }
  622. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  623. //
  624. // The read has been started. When it completes, processing
  625. // resumes in the FSD at SrvFsdRestartReadRaw.
  626. //
  627. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbReadRaw complete\n" ));
  628. SmbStatus = SmbStatusInProgress;
  629. goto Cleanup;
  630. error_exit_no_cleanup_locked:
  631. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  632. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  633. error_exit_no_cleanup:
  634. WorkContext->ResponseParameters = WorkContext->ResponseHeader;
  635. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsRejected );
  636. SmbStatus = SmbStatusSendResponse;
  637. goto Cleanup;
  638. error_exit_cleanup:
  639. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  640. //
  641. // We are about to release the work context and possibly free the
  642. // connection. Create a referenced pointer to the connection so
  643. // that we can send delayed oplock breaks, if necessary.
  644. //
  645. SrvReferenceConnectionLocked( connection );
  646. //
  647. // Since we cannot return an error code, we return zero bytes of
  648. // data.
  649. //
  650. WorkContext->ResponseParameters = WorkContext->ResponseHeader;
  651. //
  652. // If there is an oplock break request pending, then we must go to the
  653. // FSP to initiate the break, otherwise complete processing in the FSD.
  654. //
  655. if ( IsListEmpty( &connection->OplockWorkList ) ) {
  656. connection->RawReadsInProgress--;
  657. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  658. SrvFsdSendResponse( WorkContext );
  659. } else {
  660. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  661. SrvFsdSendResponse2( WorkContext, SrvRestartReadRawComplete );
  662. }
  663. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsRejected );
  664. //
  665. // Release the connection reference.
  666. //
  667. SrvDereferenceConnection( connection );
  668. SmbStatus = SmbStatusInProgress;
  669. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbReadRaw complete\n" ));
  670. Cleanup:
  671. SrvWmiEndContext(WorkContext);
  672. return SmbStatus;
  673. } // SrvSmbReadRaw
  674. SMB_PROCESSOR_RETURN_TYPE
  675. SrvSmbWriteRaw (
  676. SMB_PROCESSOR_PARAMETERS
  677. )
  678. /*++
  679. Routine Description:
  680. Processes the Write Block Raw SMB.
  681. Arguments:
  682. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description of the
  683. parameters to SMB processor routines.
  684. Return Value:
  685. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  686. --*/
  687. {
  688. PREQ_WRITE_RAW request;
  689. PREQ_NT_WRITE_RAW ntRequest;
  690. NTSTATUS status = STATUS_SUCCESS;
  691. SMB_STATUS SmbStatus = SmbStatusInProgress;
  692. PRFCB rfcb = NULL;
  693. PLFCB lfcb;
  694. ULONG immediateLength;
  695. BOOLEAN immediateWriteDone = FALSE;
  696. USHORT fid;
  697. PCHAR writeAddress;
  698. ULONG writeLength;
  699. ULONG key;
  700. SHARE_TYPE shareType;
  701. LARGE_INTEGER offset;
  702. PWORK_CONTEXT rawWorkContext;
  703. PVOID finalResponseBuffer = NULL;
  704. PCONNECTION connection;
  705. PAGED_CODE( );
  706. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  707. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_RAW;
  708. SrvWmiStartContext(WorkContext);
  709. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawWritesAttempted );
  710. request = (PREQ_WRITE_RAW)WorkContext->RequestParameters;
  711. ntRequest = (PREQ_NT_WRITE_RAW)WorkContext->RequestParameters;
  712. fid = SmbGetUshort( &request->Fid );
  713. //
  714. // If the client is MS-NET 1.03 or before, reject him. We don't
  715. // support raw writes from these clients.
  716. //
  717. connection = WorkContext->Connection;
  718. if ( connection->SmbDialect >= SmbDialectMsNet103 ) {
  719. IF_DEBUG(SMB_ERRORS) {
  720. KdPrint(( "Raw write request from MS-NET 1.03 client.\n" ));
  721. }
  722. status = STATUS_SMB_USE_STANDARD;
  723. goto error_exit_no_rfcb;
  724. }
  725. IF_SMB_DEBUG(RAW1) {
  726. KdPrint(( "Write Block Raw request; FID 0x%lx, count %ld, "
  727. "offset %ld, immediate length %ld\n",
  728. fid,
  729. SmbGetUshort( &request->Count ),
  730. SmbGetUlong( &request->Offset ),
  731. SmbGetUshort( &request->DataLength ) ));
  732. }
  733. immediateLength = SmbGetUshort( &request->DataLength );
  734. writeLength = SmbGetUshort( &request->Count );
  735. //
  736. // make sure the immediate length:
  737. // is not greater than the total bytes, and
  738. // does not go beyond what we are given
  739. //
  740. if ( ( immediateLength > writeLength ) ||
  741. ( immediateLength > ( WorkContext->ResponseBuffer->DataLength -
  742. SmbGetUshort(&request->DataOffset) ) )
  743. ) {
  744. status = STATUS_INVALID_SMB;
  745. goto error_exit_no_rfcb;
  746. }
  747. //
  748. // Verify the FID. If verified, the RFCB is referenced and its
  749. // address is stored in the WorkContext block, and the RFCB address
  750. // is returned. In addition, the active raw write count is
  751. // incremented.
  752. //
  753. //
  754. // See if the fid matches the cached fid.
  755. //
  756. rfcb = SrvVerifyFidForRawWrite(
  757. WorkContext,
  758. fid,
  759. &status
  760. );
  761. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  762. if ( !NT_SUCCESS( status ) ) {
  763. //
  764. // Invalid file ID or write behind error. Reject the request.
  765. //
  766. IF_DEBUG(ERRORS) {
  767. KdPrint((
  768. "SrvSmbWriteRaw: Status %X on FID: 0x%lx\n",
  769. status,
  770. SmbGetUshort( &request->Fid )
  771. ));
  772. }
  773. goto error_exit_no_rfcb;
  774. }
  775. //
  776. // The work item has been queued because a raw write is in
  777. // progress.
  778. //
  779. SmbStatus = SmbStatusInProgress;
  780. goto Cleanup;
  781. }
  782. lfcb = rfcb->Lfcb;
  783. shareType = rfcb->ShareType;
  784. if( lfcb->Session->IsSessionExpired )
  785. {
  786. status = SESSION_EXPIRED_STATUS_CODE;
  787. goto error_exit;
  788. }
  789. //
  790. // Validate the word count.
  791. //
  792. if ( shareType == ShareTypePipe ) {
  793. if ( (request->WordCount != 12) && (request->WordCount != 14) ) {
  794. status = STATUS_INVALID_SMB;
  795. goto error_exit;
  796. }
  797. } else {
  798. if ( request->WordCount == 12 ) {
  799. offset.QuadPart = SmbGetUlong( &request->Offset );
  800. } else if ( request->WordCount == 14 ) {
  801. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh ) ;
  802. offset.LowPart = SmbGetUlong( &ntRequest->Offset ) ;
  803. //
  804. // Reject negative offsets. Add the offset to the immediate
  805. // length and make sure that the result is not negative. We do the
  806. // first check ( highpart >= 0x7fffffff ) so that in most cases
  807. // we do only one check.
  808. //
  809. if ( (ULONG)offset.HighPart >= (ULONG)0x7fffffff &&
  810. ( (offset.QuadPart < 0) ||
  811. ((offset.QuadPart + immediateLength) < 0) ) ) {
  812. IF_DEBUG(ERRORS) {
  813. KdPrint(( "SrvSmbWriteRaw: Negative offset rejected.\n"));
  814. }
  815. status = STATUS_INVALID_SMB;
  816. goto error_exit;
  817. }
  818. } else {
  819. status = STATUS_INVALID_SMB;
  820. goto error_exit;
  821. }
  822. }
  823. //
  824. // Verify that the client has write access to the file via the
  825. // specified handle.
  826. //
  827. if ( !rfcb->WriteAccessGranted && !rfcb->AppendAccessGranted ) {
  828. SrvStatistics.GrantedAccessErrors++;
  829. IF_DEBUG(ERRORS) {
  830. KdPrint(( "SrvSmbWriteRaw: Read access not granted.\n"));
  831. }
  832. status = STATUS_ACCESS_DENIED;
  833. goto error_exit;
  834. }
  835. //
  836. // Ensure that the write is extending the file if the user only has append access
  837. //
  838. if( !rfcb->WriteAccessGranted &&
  839. offset.QuadPart < rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart ) {
  840. IF_DEBUG(ERRORS) {
  841. KdPrint(( "SrvSmbWriteRaw: Only append access to file allowed!\n" ));
  842. }
  843. SrvStatistics.GrantedAccessErrors++;
  844. status = STATUS_ACCESS_DENIED;
  845. goto error_exit;
  846. }
  847. #ifdef INCLUDE_SMB_IFMODIFIED
  848. rfcb->Lfcb->FileUpdated = TRUE;
  849. #endif
  850. rfcb->WrittenTo = TRUE;
  851. //
  852. // If this operation may block, and we're running short of
  853. // resources, or if the target is a paused comm device, reject the
  854. // request. Note that we do NOT write immediate data -- this is the
  855. // same behavior as the OS/2 server.
  856. //
  857. // !!! Implement the pause comm device test.
  858. //
  859. if ( rfcb->BlockingModePipe ) {
  860. if ( SrvReceiveBufferShortage( ) ) {
  861. //
  862. // Reject the request.
  863. //
  864. // !!! Consider routing the request to the FSP, instead.
  865. //
  866. IF_DEBUG(ERRORS) {
  867. KdPrint(( "SrvSmbWriteRaw: No resources for blocking "
  868. "write\n" ));
  869. }
  870. SrvFailedBlockingIoCount++;
  871. SrvStatistics.BlockingSmbsRejected++;
  872. status = STATUS_SMB_USE_STANDARD;
  873. goto error_exit;
  874. } else {
  875. //
  876. // It is okay to start a blocking operation.
  877. // SrvReceiveBufferShortage() has already incremented
  878. // SrvBlockingOpsInProgress.
  879. //
  880. WorkContext->BlockingOperation = TRUE;
  881. }
  882. } else if ( shareType == ShareTypeDisk &&
  883. ( ((ULONG)request->WriteMode & SMB_WMODE_WRITE_THROUGH) << 1 !=
  884. ((ULONG)lfcb->FileMode & FILE_WRITE_THROUGH) ) ) {
  885. //
  886. // Change the write through mode of the file, if necessary.
  887. //
  888. ASSERT( SMB_WMODE_WRITE_THROUGH == 0x01 );
  889. ASSERT( FILE_WRITE_THROUGH == 0x02 );
  890. SrvSetFileWritethroughMode(
  891. lfcb,
  892. (BOOLEAN)( (SmbGetUshort( &request->WriteMode )
  893. & SMB_WMODE_WRITE_THROUGH) != 0 )
  894. );
  895. }
  896. #ifdef SLMDBG
  897. {
  898. PRFCB_TRACE entry;
  899. ULONG immediateLength, rawLength;
  900. KIRQL oldIrql;
  901. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  902. rfcb->WriteCount++;
  903. rfcb->OperationCount++;
  904. entry = &rfcb->Trace[rfcb->NextTrace];
  905. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  906. rfcb->NextTrace = 0;
  907. rfcb->TraceWrapped = TRUE;
  908. }
  909. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  910. entry->Command = WorkContext->NextCommand;
  911. entry->Flags = 0;
  912. immediateLength = SmbGetUshort( &request->DataLength );
  913. rawLength = SmbGetUshort( &request->Count ) - immediateLength;
  914. if ( immediateLength != 0 ) {
  915. entry->Flags = (UCHAR)(entry->Flags | 2);
  916. }
  917. if ( ((lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) != 0)
  918. ) {
  919. entry->Flags = (UCHAR)(entry->Flags | 1);
  920. }
  921. #if 0
  922. if ( ((lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) != 0) &&
  923. (rawLength > SrvMaxCopyWriteLength) ) {
  924. entry->Flags = (UCHAR)(entry->Flags | 1);
  925. }
  926. #endif
  927. KeQuerySystemTime( &entry->Time );
  928. entry->Data.ReadWrite.Offset = SmbGetUlong( &request->Offset );
  929. entry->Data.ReadWrite.Length = SmbGetUshort( &request->Count );
  930. }
  931. #endif
  932. //
  933. // If immediate data was sent write it first.
  934. //
  935. // If this is a named pipe, do not write the data unless all of the
  936. // write data was sent in the original request. We cannot do the
  937. // write in 2 parts, in case this is a message mode pipe.
  938. //
  939. // *** Note that this is different from the OS/2 server. It turns
  940. // out to be easier for us to write the immediate data first,
  941. // rather than copying it into a staging buffer pending receipt
  942. // of the raw write data. This is largely due to using MDL
  943. // writes -- we don't allocate a staging buffer when we do an
  944. // MDL write.
  945. //
  946. //
  947. // Form the lock key using the FID and the PID.
  948. //
  949. // *** The FID must be included in the key in order to
  950. // account for the folding of multiple remote
  951. // compatibility mode opens into a single local
  952. // open.
  953. //
  954. key = rfcb->ShiftedFid |
  955. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  956. if ( immediateLength != 0 ) {
  957. if ( (shareType != ShareTypePipe) ||
  958. (SmbGetUshort( &request->Count ) == (USHORT)immediateLength) ) {
  959. if ( lfcb->FastIoWrite != NULL ) {
  960. writeAddress = (PCHAR)WorkContext->RequestHeader +
  961. SmbGetUshort( &request->DataOffset );
  962. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  963. try {
  964. immediateWriteDone = lfcb->FastIoWrite(
  965. lfcb->FileObject,
  966. &offset,
  967. immediateLength,
  968. TRUE,
  969. key,
  970. writeAddress,
  971. &WorkContext->Irp->IoStatus,
  972. lfcb->DeviceObject
  973. );
  974. IF_SMB_DEBUG(RAW2) {
  975. KdPrint(( "SrvSmbWriteRaw: fast immediate write %s\n",
  976. immediateWriteDone ? "worked" : "failed" ));
  977. }
  978. if ( immediateWriteDone ) {
  979. writeLength -= immediateLength;
  980. offset.QuadPart += immediateLength;
  981. } else {
  982. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  983. }
  984. }
  985. except( EXCEPTION_EXECUTE_HANDLER ) {
  986. // Fall through to the slow path on an exception
  987. NTSTATUS status = GetExceptionCode();
  988. immediateWriteDone = FALSE;
  989. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  990. IF_DEBUG(ERRORS) {
  991. KdPrint(("FastIoRead threw exception %x\n", status ));
  992. }
  993. }
  994. }
  995. }
  996. } else {
  997. immediateWriteDone = TRUE;
  998. }
  999. //
  1000. // If the remaining write length is 0 (strange but legal), send a
  1001. // success response.
  1002. //
  1003. if ( writeLength == 0 ) {
  1004. IF_SMB_DEBUG(RAW1) {
  1005. KdPrint(( "PrepareRawWrite: No raw data !?!\n" ));
  1006. }
  1007. status = STATUS_SUCCESS;
  1008. goto error_exit;
  1009. }
  1010. //
  1011. // Reject Raw write if:
  1012. // raw mode has been disabled, or
  1013. // connection is unreliable, or
  1014. // file is non-cached and it is a write behind and it is a disk
  1015. // file (this condition is necessary to prevent a client
  1016. // from getting old data back when it does a raw read
  1017. // immediately after a raw write. This can result in
  1018. // synchronization problems.
  1019. //
  1020. if ( !SrvEnableRawMode ||
  1021. !connection->EnableRawIo ) {
  1022. IF_SMB_DEBUG(RAW1) {
  1023. KdPrint(( "SrvSmbWriteRaw: Raw mode is disabled\n" ));
  1024. }
  1025. //
  1026. // Update server statistics.
  1027. //
  1028. status = STATUS_SMB_USE_STANDARD;
  1029. goto error_exit;
  1030. }
  1031. //
  1032. // Obtain a raw mode work item from the raw mode pool. If none are
  1033. // available, ask the client to use a standard write request.
  1034. //
  1035. rawWorkContext = SrvGetRawModeWorkItem( );
  1036. if ( rawWorkContext == NULL ) {
  1037. IF_DEBUG(ERRORS) {
  1038. KdPrint(( "SrvSmbWriteRaw: No raw mode work items "
  1039. "available\n" ));
  1040. }
  1041. SrvOutOfRawWorkItemCount++;
  1042. status = STATUS_SMB_USE_STANDARD;
  1043. goto error_exit;
  1044. }
  1045. IF_SMB_DEBUG(RAW2) KdPrint(( "rawWorkContext: 0x%p\n", rawWorkContext ));
  1046. //
  1047. // If writethough mode was specified, we'll need to send a final
  1048. // response SMB. Allocate a nonpaged buffer to contain the
  1049. // response. If this fails, ask the client to use a standard write
  1050. // request.
  1051. //
  1052. if ( (SmbGetUshort( &request->WriteMode ) &
  1053. SMB_WMODE_WRITE_THROUGH) != 0 ) {
  1054. finalResponseBuffer = ALLOCATE_NONPAGED_POOL(
  1055. sizeof(SMB_HEADER) +
  1056. SIZEOF_SMB_PARAMS(RESP_WRITE_COMPLETE,0),
  1057. BlockTypeDataBuffer
  1058. );
  1059. IF_SMB_DEBUG(RAW2) {
  1060. KdPrint(( "finalResponseBuffer: 0x%p\n", finalResponseBuffer ));
  1061. }
  1062. if ( finalResponseBuffer == NULL ) {
  1063. INTERNAL_ERROR(
  1064. ERROR_LEVEL_EXPECTED,
  1065. "SrvSmbWriteRaw: Unable to allocate %d bytes from "
  1066. "nonpaged pool",
  1067. sizeof(SMB_HEADER) + SIZEOF_SMB_PARAMS(RESP_WRITE_COMPLETE,0),
  1068. NULL
  1069. );
  1070. SrvRequeueRawModeWorkItem( rawWorkContext );
  1071. status = STATUS_SMB_USE_STANDARD;
  1072. goto error_exit;
  1073. }
  1074. }
  1075. //
  1076. // Save necessary context information in the additional work context
  1077. // block.
  1078. //
  1079. rawWorkContext->Parameters.WriteRaw.FinalResponseBuffer = finalResponseBuffer;
  1080. rawWorkContext->Parameters.WriteRaw.ImmediateWriteDone = immediateWriteDone;
  1081. rawWorkContext->Parameters.WriteRaw.ImmediateLength = immediateLength;
  1082. rawWorkContext->Parameters.WriteRaw.Offset = offset;
  1083. rawWorkContext->Parameters.WriteRaw.Pid =
  1084. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1085. WorkContext->Parameters.WriteRawPhase1.RawWorkContext = rawWorkContext;
  1086. //
  1087. // Copy the start time from the original work context. Indicate
  1088. // that no statistics should be saved from the original, and what
  1089. // kind of statistics should be saved from the raw work context.
  1090. //
  1091. rawWorkContext->StartTime = 0;
  1092. //
  1093. // Copy pointers from the original work context to the raw work
  1094. // context, referencing as necessary.
  1095. //
  1096. rawWorkContext->Endpoint = WorkContext->Endpoint; // not a referenced ptr
  1097. rawWorkContext->Connection = connection;
  1098. SrvReferenceConnection( connection );
  1099. rawWorkContext->Share = NULL;
  1100. rawWorkContext->Session = NULL;
  1101. rawWorkContext->TreeConnect = NULL;
  1102. rawWorkContext->Rfcb = rfcb;
  1103. SrvReferenceRfcb( rfcb );
  1104. //
  1105. // Prepare either a copy write or an MDL write, as appropriate.
  1106. //
  1107. if ( !(lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) ) {
  1108. //
  1109. // The file system doesn't support MDL write. Prepare a copy
  1110. // write.
  1111. //
  1112. rawWorkContext->Parameters.WriteRaw.MdlWrite = FALSE;
  1113. PrepareRawCopyWrite( WorkContext );
  1114. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1115. SmbStatus = SmbStatusInProgress;
  1116. goto Cleanup;
  1117. }
  1118. //
  1119. // The file system supports MDL write. Prepare an MDL write.
  1120. //
  1121. rawWorkContext->Parameters.WriteRaw.MdlWrite = TRUE;
  1122. rawWorkContext->Parameters.WriteRaw.Length = writeLength;
  1123. //
  1124. // Try the fast path first.
  1125. //
  1126. WorkContext->Irp->MdlAddress = NULL;
  1127. WorkContext->Irp->IoStatus.Information = 0;
  1128. IF_SMB_DEBUG(RAW2) {
  1129. KdPrint(( "SrvSmbWriteRaw: trying fast path for offset %ld, "
  1130. "length %ld\n", offset.LowPart, writeLength ));
  1131. }
  1132. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1133. if ( lfcb->PrepareMdlWrite(
  1134. lfcb->FileObject,
  1135. &offset,
  1136. writeLength,
  1137. key,
  1138. &WorkContext->Irp->MdlAddress,
  1139. &WorkContext->Irp->IoStatus,
  1140. lfcb->DeviceObject
  1141. ) && WorkContext->Irp->MdlAddress != NULL ) {
  1142. //
  1143. // The fast I/O path worked. Send the go-ahead response.
  1144. //
  1145. #if DBG
  1146. IF_SMB_DEBUG(RAW2) {
  1147. KdPrint(( "SrvSmbWriteRaw: fast path worked; MDL %p, length 0x%p\n", WorkContext->Irp->MdlAddress,
  1148. (PVOID)WorkContext->Irp->IoStatus.Information ));
  1149. DumpMdlChain( WorkContext->Irp->MdlAddress );
  1150. }
  1151. #endif
  1152. WorkContext->bAlreadyTrace = TRUE;
  1153. SrvFsdRestartPrepareRawMdlWrite( WorkContext );
  1154. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1155. SmbStatus = SmbStatusInProgress;
  1156. goto Cleanup;
  1157. }
  1158. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1159. //
  1160. // The fast I/O path failed. Build the write request, reusing the
  1161. // receive IRP.
  1162. //
  1163. // The fast path may have partially succeeded, returning a partial
  1164. // MDL chain. We need to adjust our write request to account for
  1165. // that.
  1166. //
  1167. IF_SMB_DEBUG(RAW2) {
  1168. KdPrint(( "SrvSmbWriteRaw: fast path failed; MDL %p, length 0x%p\n", WorkContext->Irp->MdlAddress,
  1169. (PVOID)WorkContext->Irp->IoStatus.Information ));
  1170. }
  1171. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  1172. writeLength -= (ULONG)WorkContext->Irp->IoStatus.Information;
  1173. SrvBuildReadOrWriteRequest(
  1174. WorkContext->Irp, // input IRP address
  1175. lfcb->FileObject, // target file object address
  1176. WorkContext, // context
  1177. IRP_MJ_WRITE, // major function code
  1178. IRP_MN_MDL, // minor function code
  1179. NULL, // buffer address (ignored)
  1180. writeLength, // buffer length
  1181. WorkContext->Irp->MdlAddress, // MDL address
  1182. offset, // byte offset
  1183. key // lock key
  1184. );
  1185. //
  1186. // Pass the request to the file system.
  1187. //
  1188. IF_SMB_DEBUG(RAW2) {
  1189. KdPrint(( "SrvSmbWriteRaw: write to file 0x%p, offset %ld, length %ld\n",
  1190. lfcb->FileObject, offset.LowPart, writeLength ));
  1191. }
  1192. WorkContext->bAlreadyTrace = TRUE;
  1193. WorkContext->FsdRestartRoutine = SrvFsdRestartPrepareRawMdlWrite;
  1194. DEBUG WorkContext->FspRestartRoutine = NULL;
  1195. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1196. //
  1197. // The MDL write has been started. When it completes, processing
  1198. // resumes at SrvFsdRestartPrepareRawMdlWrite.
  1199. //
  1200. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1201. SmbStatus = SmbStatusInProgress;
  1202. goto Cleanup;
  1203. error_exit:
  1204. SrvDecrementRawWriteCount( rfcb );
  1205. error_exit_no_rfcb:
  1206. SrvFsdBuildWriteCompleteResponse(
  1207. WorkContext,
  1208. status,
  1209. immediateWriteDone ? immediateLength : 0
  1210. );
  1211. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawWritesRejected );
  1212. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1213. SmbStatus = SmbStatusSendResponse;
  1214. Cleanup:
  1215. SrvWmiEndContext(WorkContext);
  1216. return SmbStatus;
  1217. } // SrvSmbWriteRaw
  1218. VOID SRVFASTCALL
  1219. AbortRawWrite(
  1220. IN OUT PWORK_CONTEXT WorkContext
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Handles cleanup when a raw write is aborted after the interim
  1225. "go-ahead" response has been sent. This routine is only used
  1226. when a catastrophic errors occurs -- for example, the connection
  1227. is closing. It does not send a final response to the client.
  1228. This routine is called in the FSP.
  1229. Arguments:
  1230. WorkContext - Supplies a pointer to the work context block
  1231. describing server-specific context for the request.
  1232. This must be a pointer to the raw mode work item -- not the
  1233. original work item that received the Write Raw SMB.
  1234. Return Value:
  1235. None.
  1236. --*/
  1237. {
  1238. PMDL cacheMdl;
  1239. PMDL partialMdl;
  1240. NTSTATUS status;
  1241. PAGED_CODE( );
  1242. //
  1243. // Deallocate the final response buffer, if any.
  1244. //
  1245. if ( WorkContext->Parameters.WriteRaw.FinalResponseBuffer != NULL ) {
  1246. DEALLOCATE_NONPAGED_POOL(
  1247. WorkContext->Parameters.WriteRaw.FinalResponseBuffer
  1248. );
  1249. WorkContext->Parameters.WriteRaw.FinalResponseBuffer = NULL;
  1250. }
  1251. if ( !WorkContext->Parameters.WriteRaw.MdlWrite ) {
  1252. //
  1253. // This was a copy write. Deallocate the raw receive buffer.
  1254. // Note that we do not need to unlock the raw buffer, because it
  1255. // was allocated out of nonpaged pool and locked using
  1256. // MmBuildMdlForNonPagedPool, which doesn't increment reference
  1257. // counts and therefore has no inverse.
  1258. //
  1259. if ( WorkContext->Parameters.WriteRaw.ImmediateWriteDone ) {
  1260. DEALLOCATE_NONPAGED_POOL( WorkContext->RequestBuffer->Buffer );
  1261. } else {
  1262. DEALLOCATE_NONPAGED_POOL(
  1263. (PCHAR)WorkContext->RequestBuffer->Buffer -
  1264. WorkContext->Parameters.WriteRaw.ImmediateLength );
  1265. }
  1266. //
  1267. // Dereference control blocks and requeue the raw mode work
  1268. // item.
  1269. //
  1270. WorkContext->ResponseBuffer->Buffer = NULL;
  1271. SrvRestartWriteCompleteResponse( WorkContext );
  1272. return;
  1273. }
  1274. //
  1275. // This was an MDL write. If a partial MDL was built (because of
  1276. // immediate data), unmap it. Then complete the MDL write,
  1277. // indicating that no data was actually written.
  1278. //
  1279. cacheMdl = WorkContext->Parameters.WriteRaw.FirstMdl;
  1280. partialMdl = WorkContext->Irp->MdlAddress;
  1281. if ( partialMdl != cacheMdl ) {
  1282. ASSERT( (partialMdl->MdlFlags & MDL_PARTIAL) != 0 );
  1283. MmPrepareMdlForReuse( partialMdl );
  1284. }
  1285. #if DBG
  1286. IF_SMB_DEBUG(RAW2) {
  1287. KdPrint(( "AbortRawWrite: Completing MDL write with length 0\n" ));
  1288. DumpMdlChain( cacheMdl );
  1289. }
  1290. #endif
  1291. if( WorkContext->Rfcb->Lfcb->MdlWriteComplete == NULL ||
  1292. WorkContext->Rfcb->Lfcb->MdlWriteComplete(
  1293. WorkContext->Rfcb->Lfcb->FileObject,
  1294. &WorkContext->Parameters.WriteRaw.Offset,
  1295. cacheMdl,
  1296. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  1297. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  1298. cacheMdl,
  1299. IRP_MJ_WRITE,
  1300. &WorkContext->Parameters.WriteRaw.Offset,
  1301. WorkContext->Parameters.WriteRaw.Length
  1302. );
  1303. if( !NT_SUCCESS( status ) ) {
  1304. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  1305. }
  1306. }
  1307. SrvRestartWriteCompleteResponse( WorkContext );
  1308. return;
  1309. } // AbortRawWrite
  1310. VOID SRVFASTCALL
  1311. PrepareRawCopyWrite (
  1312. IN OUT PWORK_CONTEXT WorkContext
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. Prepares for a raw "copy" write. Allocates a buffer to receive the
  1317. raw data, prepares a work context block and an IRP describing the
  1318. raw receive, queues it to the connection, and sends a "go-ahead"
  1319. response.
  1320. Any immediate data sent in the request SMB has already been written
  1321. when this routine is called, unless this is a named pipe write, in
  1322. which case the immediate data has not been written. In this case,
  1323. we alllocate a buffer big enough for the the immediate data plus the
  1324. raw data, then copy the immediate data to the raw buffer before
  1325. proceeding. The raw data will be received appended to the immediate
  1326. data. Then both peices can be written with a single write. This is
  1327. needed so that data written to a message mode pipe will not be
  1328. written in 2 pieces.
  1329. This routine is called in the FSP.
  1330. Arguments:
  1331. WorkContext - Supplies a pointer to the work context block
  1332. describing server-specific context for the request.
  1333. Return Value:
  1334. None.
  1335. --*/
  1336. {
  1337. PWORK_CONTEXT rawWorkContext;
  1338. PREQ_WRITE_RAW request;
  1339. PRESP_WRITE_RAW_INTERIM response;
  1340. NTSTATUS status;
  1341. PVOID rawBuffer;
  1342. PCHAR writeAddress;
  1343. PMDL mdl;
  1344. SHARE_TYPE shareType;
  1345. PVOID finalResponseBuffer;
  1346. ULONG immediateLength;
  1347. BOOLEAN immediateWriteDone;
  1348. ULONG writeLength;
  1349. ULONG bufferLength;
  1350. BOOLEAN sendWriteComplete = TRUE;
  1351. PIO_STACK_LOCATION irpSp;
  1352. PAGED_CODE( );
  1353. IF_DEBUG(WORKER1) KdPrint(( " - PrepareRawCopyWrite\n" ));
  1354. //
  1355. // Set up local variables.
  1356. //
  1357. rawWorkContext = WorkContext->Parameters.WriteRawPhase1.RawWorkContext;
  1358. request = (PREQ_WRITE_RAW)WorkContext->RequestParameters;
  1359. shareType = rawWorkContext->Rfcb->ShareType;
  1360. immediateLength = rawWorkContext->Parameters.WriteRaw.ImmediateLength;
  1361. immediateWriteDone =
  1362. rawWorkContext->Parameters.WriteRaw.ImmediateWriteDone;
  1363. writeLength = SmbGetUshort( &request->Count ) - immediateLength;
  1364. finalResponseBuffer =
  1365. rawWorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  1366. if ( !immediateWriteDone ) {
  1367. bufferLength = writeLength + immediateLength;
  1368. } else {
  1369. bufferLength = writeLength;
  1370. }
  1371. //
  1372. // Allocate a nonpaged buffer to contain the write data. If this
  1373. // fails, ask the client to use a standard write request.
  1374. //
  1375. rawBuffer = ALLOCATE_NONPAGED_POOL( bufferLength, BlockTypeDataBuffer );
  1376. IF_SMB_DEBUG(RAW2) KdPrint(( "rawBuffer: 0x%p\n", rawBuffer ));
  1377. if ( rawBuffer == NULL ) {
  1378. // !!! Should we log this error?
  1379. IF_DEBUG(ERRORS) {
  1380. KdPrint(( "PrepareRawCopyWrite: Unable to allocate "
  1381. "raw buffer\n" ));
  1382. }
  1383. status = STATUS_SMB_USE_STANDARD;
  1384. goto abort;
  1385. }
  1386. if ( !immediateWriteDone ) {
  1387. //
  1388. // Copy the immediate data to the raw buffer.
  1389. //
  1390. writeAddress = (PCHAR)WorkContext->RequestHeader +
  1391. SmbGetUshort( &request->DataOffset );
  1392. RtlCopyMemory( rawBuffer, writeAddress, immediateLength );
  1393. //
  1394. // Move the virtual start of the raw buffer to the end of the
  1395. // immediate data.
  1396. //
  1397. rawBuffer = (PCHAR)rawBuffer + immediateLength;
  1398. }
  1399. //
  1400. // If a final response is going to be sent, save information from
  1401. // the request in the final response buffer.
  1402. //
  1403. if ( finalResponseBuffer != NULL ) {
  1404. RtlCopyMemory(
  1405. (PSMB_HEADER)finalResponseBuffer,
  1406. WorkContext->RequestHeader,
  1407. sizeof(SMB_HEADER)
  1408. );
  1409. }
  1410. //
  1411. // Set up the buffer descriptor for the raw buffer.
  1412. //
  1413. rawWorkContext->RequestBuffer->Buffer = rawBuffer;
  1414. rawWorkContext->RequestBuffer->BufferLength = writeLength;
  1415. //
  1416. // Initialize the MDL to describe the raw buffer.
  1417. // (SrvBuildIoControlRequest will lock the buffer for I/O.)
  1418. //
  1419. mdl = rawWorkContext->RequestBuffer->Mdl;
  1420. MmInitializeMdl( mdl, rawBuffer, writeLength );
  1421. //
  1422. // Build the mdl
  1423. //
  1424. MmBuildMdlForNonPagedPool( mdl );
  1425. //
  1426. // Set up the restart routines in the work context block.
  1427. //
  1428. rawWorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1429. rawWorkContext->FspRestartRoutine = SrvRestartRawReceive;
  1430. //
  1431. // Build the I/O request packet.
  1432. //
  1433. (VOID)SrvBuildIoControlRequest(
  1434. rawWorkContext->Irp, // input IRP address
  1435. NULL, // target file object address
  1436. rawWorkContext, // context
  1437. IRP_MJ_INTERNAL_DEVICE_CONTROL, // major function
  1438. TDI_RECEIVE, // minor function
  1439. NULL, // input buffer address
  1440. 0, // input buffer length
  1441. rawBuffer, // output buffer address
  1442. writeLength, // output buffer length
  1443. mdl, // MDL address
  1444. NULL
  1445. );
  1446. irpSp = IoGetNextIrpStackLocation( rawWorkContext->Irp );
  1447. //
  1448. // If this is a writebehind write, tell the transport that we don't
  1449. // plan to reply to the received message.
  1450. //
  1451. if ( finalResponseBuffer == NULL ) {
  1452. ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveFlags |=
  1453. TDI_RECEIVE_NO_RESPONSE_EXP;
  1454. }
  1455. //
  1456. // Post the receive.
  1457. //
  1458. irpSp->Flags = 0;
  1459. irpSp->DeviceObject = rawWorkContext->Connection->DeviceObject;
  1460. irpSp->FileObject = rawWorkContext->Connection->FileObject;
  1461. ASSERT( rawWorkContext->Irp->StackCount >= irpSp->DeviceObject->StackSize );
  1462. (VOID)IoCallDriver( irpSp->DeviceObject, rawWorkContext->Irp );
  1463. //
  1464. // Build the interim (go-ahead) response.
  1465. //
  1466. response = (PRESP_WRITE_RAW_INTERIM)WorkContext->ResponseParameters;
  1467. response->WordCount = 1;
  1468. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  1469. SmbPutUshort( &response->ByteCount, 0 );
  1470. WorkContext->ResponseParameters = NEXT_LOCATION(
  1471. response,
  1472. RESP_WRITE_RAW_INTERIM,
  1473. 0
  1474. );
  1475. //
  1476. // Send off the interim response by ending processing of the SMB.
  1477. //
  1478. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1479. IF_DEBUG(TRACE2) KdPrint(( "PrepareRawCopyWrite complete\n" ));
  1480. return;
  1481. abort:
  1482. //
  1483. // For one reason or another, we are not going to receive any raw
  1484. // data, so clean up.
  1485. //
  1486. if ( finalResponseBuffer != NULL ) {
  1487. DEALLOCATE_NONPAGED_POOL( finalResponseBuffer );
  1488. }
  1489. SrvRestartWriteCompleteResponse( rawWorkContext );
  1490. //
  1491. // If a response is to be sent, send it now.
  1492. //
  1493. if ( sendWriteComplete ) {
  1494. SrvFsdBuildWriteCompleteResponse(
  1495. WorkContext,
  1496. status,
  1497. immediateWriteDone ? immediateLength : 0
  1498. );
  1499. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1500. } else {
  1501. SrvDereferenceWorkItem( WorkContext );
  1502. }
  1503. IF_DEBUG(TRACE2) KdPrint(( "PrepareRawCopyWrite complete\n" ));
  1504. return;
  1505. } // PrepareRawCopyWrite
  1506. BOOLEAN SRVFASTCALL
  1507. ReadRawPipe (
  1508. IN PWORK_CONTEXT WorkContext
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. Processes the Read Block Raw SMB for pipes.
  1513. Note that Read Block Raw cannot return an error response. When the
  1514. server is unable to process the request, for whatever reason, it
  1515. simply responds with a zero-length message. The client uses a
  1516. normal Read SMB to determine what happened.
  1517. Arguments:
  1518. WorkContext - Pointer to the work context block.
  1519. Return Value:
  1520. TRUE, if operation succeeds.
  1521. FALSE, otherwise
  1522. --*/
  1523. {
  1524. PREQ_READ_RAW request;
  1525. USHORT fid;
  1526. PRFCB rfcb;
  1527. PLFCB lfcb;
  1528. PCONNECTION connection;
  1529. UCHAR minorFunction = 0;
  1530. BOOLEAN byteModePipe;
  1531. PVOID rawBuffer = NULL;
  1532. CLONG readLength;
  1533. PMDL mdl = NULL;
  1534. ULONG key;
  1535. LARGE_INTEGER offset;
  1536. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  1537. PAGED_CODE( );
  1538. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsAttempted );
  1539. request = (PREQ_READ_RAW)WorkContext->RequestParameters;
  1540. fid = SmbGetUshort( &request->Fid );
  1541. readLength = SmbGetUshort( &request->MaxCount );
  1542. //
  1543. // If raw mode has been disabled or if the connection is unreliable,
  1544. // reject the raw read. Ask the client to use standard read by
  1545. // sending a zero-length response. The client will react by issuing
  1546. // a normal Read SMB, which we will be able to process.
  1547. //
  1548. connection = WorkContext->Connection;
  1549. rfcb = WorkContext->Rfcb;
  1550. lfcb = rfcb->Lfcb;
  1551. byteModePipe = rfcb->ByteModePipe;
  1552. //
  1553. // Verify that the client has read access to the file via the
  1554. // specified handle.
  1555. //
  1556. if ( !rfcb->ReadAccessGranted ) {
  1557. SrvStatistics.GrantedAccessErrors++;
  1558. IF_DEBUG(ERRORS) {
  1559. KdPrint(( "ReadRawPipe: Read access not granted.\n"));
  1560. }
  1561. return(FALSE);
  1562. }
  1563. //
  1564. // Verify the word counts
  1565. //
  1566. if ( (request->WordCount != 8) && (request->WordCount != 10) ) {
  1567. //
  1568. // Invalid word count. Return 0 bytes.
  1569. //
  1570. return(FALSE);
  1571. }
  1572. //
  1573. // If this operation may block, and we're running short of
  1574. // resources, or if the target is a paused comm device, reject the
  1575. // request.
  1576. //
  1577. if ( rfcb->BlockingModePipe ) {
  1578. if ( SrvReceiveBufferShortage( ) ) {
  1579. //
  1580. // Reject the request.
  1581. //
  1582. // !!! Consider routing the request to the FSP, instead.
  1583. //
  1584. IF_DEBUG(ERRORS) {
  1585. KdPrint(( "ReadRawPipe: No resources for blocking "
  1586. "read\n" ));
  1587. }
  1588. SrvFailedBlockingIoCount++;
  1589. SrvStatistics.BlockingSmbsRejected++;
  1590. return(FALSE);
  1591. }
  1592. //
  1593. // It is okay to start a blocking operation.
  1594. // SrvReceiveBufferShortage() has already incremented
  1595. // SrvBlockingOpsInProgress.
  1596. //
  1597. WorkContext->BlockingOperation = TRUE;
  1598. }
  1599. //
  1600. // Form the lock key using the FID and the PID.
  1601. //
  1602. // *** The FID must be included in the key in order to account for
  1603. // the folding of multiple remote compatibility mode opens into
  1604. // a single local open.
  1605. //
  1606. key = rfcb->ShiftedFid |
  1607. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1608. //
  1609. // If the SMB buffer is large enough, use it to do the local read.
  1610. //
  1611. if ( readLength <= WorkContext->ResponseBuffer->BufferLength ) {
  1612. WorkContext->Parameters.ReadRaw.SavedResponseBuffer = NULL;
  1613. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  1614. //
  1615. // Try the fast I/O path first.
  1616. //
  1617. if ( byteModePipe && (lfcb->FastIoRead != NULL) ) {
  1618. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1619. try {
  1620. if ( lfcb->FastIoRead(
  1621. lfcb->FileObject,
  1622. &offset,
  1623. readLength,
  1624. TRUE,
  1625. key,
  1626. WorkContext->ResponseBuffer->Buffer,
  1627. &WorkContext->Irp->IoStatus,
  1628. lfcb->DeviceObject
  1629. ) ) {
  1630. //
  1631. // The fast I/O path worked. Send the data.
  1632. //
  1633. WorkContext->bAlreadyTrace = TRUE;
  1634. SrvFsdRestartReadRaw( WorkContext );
  1635. return TRUE;
  1636. }
  1637. }
  1638. except( EXCEPTION_EXECUTE_HANDLER ) {
  1639. // Fall through to the slow path on an exception
  1640. NTSTATUS status = GetExceptionCode();
  1641. IF_DEBUG(ERRORS) {
  1642. KdPrint(("FastIoRead threw exception %x\n", status ));
  1643. }
  1644. }
  1645. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1646. }
  1647. //
  1648. // The fast I/O path failed, so we need to use a regular copy
  1649. // I/O request. Build an MDL describing the read buffer.
  1650. //
  1651. // *** Note the assumption that the response buffer already has
  1652. // a valid full MDL from which a partial MDL can be built.
  1653. //
  1654. IoBuildPartialMdl(
  1655. WorkContext->ResponseBuffer->Mdl,
  1656. WorkContext->ResponseBuffer->PartialMdl,
  1657. WorkContext->ResponseBuffer->Buffer,
  1658. readLength
  1659. );
  1660. mdl = WorkContext->ResponseBuffer->PartialMdl;
  1661. rawBuffer = WorkContext->ResponseHeader;
  1662. ASSERT( minorFunction == 0 );
  1663. } else {
  1664. //
  1665. // We have to use a normal "copy" read. We need to allocate
  1666. // a separate raw buffer.
  1667. //
  1668. ASSERT( minorFunction == 0 );
  1669. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  1670. rawBuffer = ALLOCATE_NONPAGED_POOL(
  1671. readLength,
  1672. BlockTypeDataBuffer
  1673. );
  1674. IF_SMB_DEBUG(RAW2) KdPrint(( "rawBuffer: 0x%p\n", rawBuffer ));
  1675. if ( rawBuffer == NULL ) {
  1676. IF_DEBUG(ERRORS) {
  1677. KdPrint(( "ReadRawPipe: Unable to allocate raw buffer\n" ));
  1678. }
  1679. return(FALSE);
  1680. }
  1681. //
  1682. // We also need a buffer descriptor.
  1683. //
  1684. // *** Note: Currently, ResponseBuffer == RequestBuffer in a
  1685. // WorkContext block, so we don't really have to save
  1686. // the ResponseBuffer field. But we do so just to be on
  1687. // the safe side.
  1688. //
  1689. WorkContext->Parameters.ReadRaw.SavedResponseBuffer =
  1690. WorkContext->ResponseBuffer;
  1691. WorkContext->ResponseBuffer = ALLOCATE_NONPAGED_POOL(
  1692. sizeof(BUFFER),
  1693. BlockTypeBuffer
  1694. );
  1695. if ( WorkContext->ResponseBuffer == NULL ) {
  1696. INTERNAL_ERROR(
  1697. ERROR_LEVEL_EXPECTED,
  1698. "ReadRawPipe: Unable to allocate %d bytes from "
  1699. "nonpaged pool.",
  1700. sizeof(BUFFER),
  1701. NULL
  1702. );
  1703. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  1704. WorkContext->ResponseBuffer =
  1705. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1706. return(FALSE);
  1707. }
  1708. WorkContext->ResponseBuffer->Buffer = rawBuffer;
  1709. WorkContext->ResponseBuffer->BufferLength = readLength;
  1710. //
  1711. // Finally, we need an MDL to describe the raw buffer.
  1712. //
  1713. // *** We used to try to use the PartialMdl for the SMB
  1714. // buffer here, if it was big enough. But since we
  1715. // already decided that the buffer itself isn't big
  1716. // enough, it's extremely likely that the MDL isn't big
  1717. // enough either.
  1718. //
  1719. mdl = IoAllocateMdl( rawBuffer, readLength, FALSE, FALSE, NULL );
  1720. if ( mdl == NULL ) {
  1721. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  1722. WorkContext->ResponseBuffer =
  1723. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1724. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  1725. return(FALSE);
  1726. }
  1727. WorkContext->ResponseBuffer->Mdl = mdl;
  1728. //
  1729. // Build the mdl
  1730. //
  1731. MmBuildMdlForNonPagedPool( mdl );
  1732. //
  1733. // Try the fast I/O path first.
  1734. //
  1735. if ( byteModePipe && (lfcb->FastIoRead != NULL) ) {
  1736. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1737. try {
  1738. if ( lfcb->FastIoRead(
  1739. lfcb->FileObject,
  1740. &offset,
  1741. readLength,
  1742. TRUE,
  1743. key,
  1744. WorkContext->ResponseBuffer->Buffer,
  1745. &WorkContext->Irp->IoStatus,
  1746. lfcb->DeviceObject
  1747. ) ) {
  1748. //
  1749. // The fast I/O path worked. Send the data.
  1750. //
  1751. WorkContext->bAlreadyTrace = TRUE;
  1752. SrvFsdRestartReadRaw( WorkContext );
  1753. return TRUE;
  1754. }
  1755. }
  1756. except( EXCEPTION_EXECUTE_HANDLER ) {
  1757. // Fall through to the slow path on an exception
  1758. NTSTATUS status = GetExceptionCode();
  1759. IF_DEBUG(ERRORS) {
  1760. KdPrint(("FastIoRead threw exception %x\n", status ));
  1761. }
  1762. }
  1763. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1764. }
  1765. //
  1766. // The fast I/O path failed, so we need to use a regular copy
  1767. // I/O request.
  1768. //
  1769. } // read fits in SMB buffer?
  1770. //
  1771. // This is a read block raw on a named pipe. If this is a
  1772. // non-blocking read on a blocking mode pipe, we need to do a
  1773. // peek first. This is to ensure that we don't end up waiting
  1774. // when we're not supposed to.
  1775. //
  1776. // *** We used to have to peek on message mode pipes, in case
  1777. // the message was too large or zero-length. But now we
  1778. // have a special pipe FSCTL for this. See below.
  1779. //
  1780. if ( (SmbGetUshort( &request->MinCount ) == 0) &&
  1781. rfcb->BlockingModePipe ) {
  1782. //
  1783. // Allocate a buffer to peek the pipe. This buffer is freed
  1784. // in RestartPipeReadRawPeek().
  1785. //
  1786. pipePeekBuffer = ALLOCATE_NONPAGED_POOL(
  1787. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  1788. BlockTypeDataBuffer
  1789. );
  1790. if ( pipePeekBuffer == NULL ) {
  1791. //
  1792. // Can't allocate a buffer to do a peek. Nothing to do
  1793. // but return zero bytes to the client.
  1794. //
  1795. INTERNAL_ERROR(
  1796. ERROR_LEVEL_EXPECTED,
  1797. "ReadRawPipe: Unable to allocate %d bytes from"
  1798. "nonpaged pool.",
  1799. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  1800. NULL
  1801. );
  1802. if ( WorkContext->Parameters.ReadRaw.SavedResponseBuffer !=
  1803. NULL ) {
  1804. if ( mdl != WorkContext->Parameters.ReadRaw.
  1805. SavedResponseBuffer->PartialMdl ) {
  1806. IoFreeMdl( mdl );
  1807. }
  1808. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  1809. WorkContext->ResponseBuffer =
  1810. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1811. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  1812. }
  1813. return(FALSE);
  1814. }
  1815. //
  1816. // Save the address of the pipe peek buffer for the restart
  1817. // routine.
  1818. //
  1819. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.PipePeekBuffer =
  1820. pipePeekBuffer;
  1821. //
  1822. // Build the pipe peek request. We just want the header
  1823. // information. We do not need any data.
  1824. //
  1825. SrvBuildIoControlRequest(
  1826. WorkContext->Irp,
  1827. lfcb->FileObject,
  1828. WorkContext,
  1829. IRP_MJ_FILE_SYSTEM_CONTROL,
  1830. FSCTL_PIPE_PEEK,
  1831. pipePeekBuffer,
  1832. 0,
  1833. NULL,
  1834. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  1835. NULL,
  1836. NULL
  1837. );
  1838. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1839. WorkContext->FspRestartRoutine = RestartPipeReadRawPeek;
  1840. //
  1841. // Pass the request to NPFS.
  1842. //
  1843. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1844. } else {
  1845. //
  1846. // This is a blocking read, or a non-blocking read on a
  1847. // non-blocking pipe. Build and issue the read request. If
  1848. // this is a message-mode pipe, use the special ReadOverflow
  1849. // FSCTL. This FSCTL returns an error if the pipe is a
  1850. // message mode pipe and the first message in the pipe is
  1851. // either too big or has length 0. We need this because we
  1852. // can't return an error on a raw read -- the best we can do
  1853. // is return a zero-length message. So we need the
  1854. // operation to act like a Peek if the message is the wrong
  1855. // size. That's what the special FSCTL gives us.
  1856. //
  1857. SrvBuildIoControlRequest(
  1858. WorkContext->Irp,
  1859. lfcb->FileObject,
  1860. WorkContext,
  1861. IRP_MJ_FILE_SYSTEM_CONTROL,
  1862. byteModePipe ?
  1863. FSCTL_PIPE_INTERNAL_READ : FSCTL_PIPE_INTERNAL_READ_OVFLOW,
  1864. WorkContext->ResponseBuffer->Buffer,
  1865. 0,
  1866. NULL,
  1867. SmbGetUshort( &request->MaxCount ),
  1868. NULL,
  1869. NULL
  1870. );
  1871. WorkContext->bAlreadyTrace = TRUE;
  1872. WorkContext->FsdRestartRoutine = SrvFsdRestartReadRaw;
  1873. DEBUG WorkContext->FspRestartRoutine = NULL;
  1874. IF_SMB_DEBUG(RAW2) {
  1875. KdPrint((
  1876. "ReadRawPipe: reading from file 0x%p, "
  1877. "length %ld, destination 0x%p\n",
  1878. lfcb->FileObject,
  1879. SmbGetUshort( &request->MaxCount ),
  1880. WorkContext->Parameters.ReadRaw.
  1881. SavedResponseBuffer->Buffer
  1882. ));
  1883. }
  1884. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1885. //
  1886. // The read has been started. When it completes, processing
  1887. // resumes at SrvFsdRestartReadRaw.
  1888. //
  1889. }
  1890. IF_DEBUG(TRACE2) KdPrint(( "ReadRawPipe complete\n" ));
  1891. return TRUE;
  1892. } // ReadRawPipe
  1893. VOID SRVFASTCALL
  1894. RestartMdlReadRawResponse (
  1895. IN OUT PWORK_CONTEXT WorkContext
  1896. )
  1897. /*++
  1898. Routine Description:
  1899. Processes response send completion for an MDL read. Releases the
  1900. MDL back to the file system.
  1901. This routine is called in the FSP.
  1902. Arguments:
  1903. WorkContext - Supplies a pointer to the work context block
  1904. describing server-specific context for the request.
  1905. Return Value:
  1906. None.
  1907. --*/
  1908. {
  1909. NTSTATUS status;
  1910. PAGED_CODE( );
  1911. IF_DEBUG(FSD2) KdPrint(( " - RestartMdlReadRawResponse\n" ));
  1912. //
  1913. // Call the Cache Manager to release the MDL chain. If the MDL read
  1914. // failed to return an MDL (for example, if the read was entirely
  1915. // beyond EOF), then we don't have to do this.
  1916. //
  1917. if ( WorkContext->Irp->MdlAddress ) {
  1918. if( WorkContext->Rfcb->Lfcb->MdlReadComplete == NULL ||
  1919. WorkContext->Rfcb->Lfcb->MdlReadComplete(
  1920. WorkContext->Rfcb->Lfcb->FileObject,
  1921. WorkContext->Irp->MdlAddress,
  1922. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  1923. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  1924. WorkContext->Irp->MdlAddress,
  1925. IRP_MJ_READ,
  1926. &WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset,
  1927. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Length
  1928. );
  1929. if( !NT_SUCCESS( status ) ) {
  1930. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  1931. }
  1932. }
  1933. }
  1934. //
  1935. // Start oplock break notifications, if any are outstanding.
  1936. // SrvSendDelayedOplockBreak also sets read raw in progress to FALSE.
  1937. //
  1938. SrvSendDelayedOplockBreak( WorkContext->Connection );
  1939. //
  1940. // Finish postprocessing of the SMB.
  1941. //
  1942. SrvDereferenceWorkItem( WorkContext );
  1943. IF_DEBUG(FSD2) KdPrint(( "RestartMdlReadRawResponse complete.\n" ));
  1944. return;
  1945. } // RestartMdlReadRawResponse
  1946. VOID SRVFASTCALL
  1947. RestartPipeReadRawPeek (
  1948. IN OUT PWORK_CONTEXT WorkContext
  1949. )
  1950. /*++
  1951. Routine Description:
  1952. This function continues a read raw on a named pipe handle.
  1953. This routine is called in the FSP.
  1954. Arguments:
  1955. WorkContext - Supplies a pointer to the work context block
  1956. describing server-specific context for the request.
  1957. Return Value:
  1958. None.
  1959. --*/
  1960. {
  1961. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  1962. PREQ_READ_RAW request;
  1963. ULONG readLength;
  1964. ULONG readDataAvailable;
  1965. ULONG messageLength;
  1966. ULONG numberOfMessages;
  1967. PLFCB lfcb;
  1968. PRFCB rfcb;
  1969. PAGED_CODE( );
  1970. pipePeekBuffer = WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.
  1971. PipePeekBuffer;
  1972. request = (PREQ_READ_RAW)WorkContext->RequestParameters;
  1973. readLength = SmbGetUshort( &request->MaxCount );
  1974. rfcb = WorkContext->Rfcb;
  1975. lfcb = rfcb->Lfcb;
  1976. //
  1977. // The pipe peek has completed. Extract the critical information,
  1978. // then free the buffer.
  1979. //
  1980. readDataAvailable = pipePeekBuffer->ReadDataAvailable;
  1981. messageLength = pipePeekBuffer->MessageLength;
  1982. numberOfMessages = pipePeekBuffer->NumberOfMessages;
  1983. DEALLOCATE_NONPAGED_POOL( pipePeekBuffer );
  1984. //
  1985. // The read request is a non-blocking read on a blocking mode pipe.
  1986. // We react differently based on whether it is a byte mode pipe or
  1987. // a message mode pipe.
  1988. //
  1989. // Byte mode: If there is _any_ data in the pipe, we go get it. The
  1990. // read will complete immediately, copying either as much data
  1991. // as is available, or enough to fill the buffer, whichever is
  1992. // less, and there will be no error. If there is no data in
  1993. // the pipe, we have to return immediately, because we can't
  1994. // wait for data to arrive.
  1995. //
  1996. // Message mode: If there are no messages available, or if the
  1997. // first message is either zero-length or bigger than the
  1998. // client's buffer, we return immediately. We can't indicate
  1999. // underflow or overflow, so we can't allow the message to be
  2000. // pulled out of the queue. Otherwise, we can do the read.
  2001. //
  2002. if ( ( rfcb->ByteModePipe &&
  2003. (readDataAvailable == 0)
  2004. )
  2005. ||
  2006. ( !rfcb->ByteModePipe &&
  2007. ( (numberOfMessages == 0)
  2008. ||
  2009. (messageLength == 0)
  2010. ||
  2011. (messageLength > readLength)
  2012. )
  2013. )
  2014. ) {
  2015. if ( WorkContext->Parameters.ReadRaw.SavedResponseBuffer != NULL ) {
  2016. if ( WorkContext->ResponseBuffer->Mdl != WorkContext->Parameters.
  2017. ReadRaw.SavedResponseBuffer->PartialMdl ) {
  2018. IoFreeMdl( WorkContext->ResponseBuffer->Mdl );
  2019. }
  2020. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer->Buffer );
  2021. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  2022. WorkContext->ResponseBuffer =
  2023. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  2024. }
  2025. WorkContext->ResponseParameters = WorkContext->ResponseHeader;
  2026. SrvFsdSendResponse( WorkContext );
  2027. IF_DEBUG(TRACE2) KdPrint(( "RestartPipeReadRawPeek complete\n" ));
  2028. return;
  2029. }
  2030. //
  2031. // We have bypassed all of the pitfalls of doing a read block raw
  2032. // on a named pipe.
  2033. //
  2034. // Build and issue the read request.
  2035. //
  2036. // *** Note that we do not use the special ReadOverflow FSCTL here
  2037. // because we know from the above tests that we don't need to.
  2038. //
  2039. SrvBuildIoControlRequest(
  2040. WorkContext->Irp,
  2041. lfcb->FileObject,
  2042. WorkContext,
  2043. IRP_MJ_FILE_SYSTEM_CONTROL,
  2044. FSCTL_PIPE_INTERNAL_READ,
  2045. WorkContext->ResponseBuffer->Buffer,
  2046. 0,
  2047. NULL,
  2048. readLength,
  2049. NULL,
  2050. NULL
  2051. );
  2052. WorkContext->bAlreadyTrace = TRUE;
  2053. WorkContext->FsdRestartRoutine = SrvFsdRestartReadRaw;
  2054. DEBUG WorkContext->FspRestartRoutine = NULL;
  2055. IF_SMB_DEBUG(RAW2) {
  2056. KdPrint(( "RestartPipeReadRawPeek: reading from file 0x%p, length %ld, destination 0x%p\n",
  2057. lfcb->FileObject, readLength,
  2058. WorkContext->ResponseBuffer->Buffer ));
  2059. }
  2060. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2061. //
  2062. // The read has been started. When it completes, processing resumes
  2063. // at SrvFsdRestartReadRaw.
  2064. //
  2065. IF_DEBUG(TRACE2) KdPrint(( "RestartPipeReadRawPeek complete\n" ));
  2066. return;
  2067. } // RestartPipeReadRawPeek
  2068. VOID SRVFASTCALL
  2069. SrvDecrementRawWriteCount (
  2070. IN PRFCB Rfcb
  2071. )
  2072. /*++
  2073. Routine Description:
  2074. This routine decrements the count of active raw writes for an RFCB.
  2075. If the count goes to zero, and there are work items queued pending
  2076. completion of the raw write, they are restarted. If the count goes
  2077. to zero, and the RFCB is closing, then the RFCB's cleanup is resumed
  2078. here.
  2079. This routine is called in both the FSP and the FSD.
  2080. Arguments:
  2081. Rfcb - Supplies a pointer to the RFCB.
  2082. Return Value:
  2083. None.
  2084. --*/
  2085. {
  2086. PLIST_ENTRY listEntry;
  2087. PWORK_CONTEXT workContext;
  2088. KIRQL oldIrql;
  2089. PCONNECTION connection = Rfcb->Connection;
  2090. //
  2091. // Acquire the spin lock that guards the count.
  2092. //
  2093. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  2094. //
  2095. // Decrement the active raw write count.
  2096. //
  2097. ASSERT( Rfcb->RawWriteCount > 0 );
  2098. Rfcb->RawWriteCount--;
  2099. if ( Rfcb->RawWriteCount == 0 ) {
  2100. //
  2101. // No raw writes are active. Flush the list of work items
  2102. // that were queued pending the completion of the raw write
  2103. // by restarting each of them.
  2104. //
  2105. while ( !IsListEmpty(&Rfcb->RawWriteSerializationList) ) {
  2106. listEntry = RemoveHeadList( &Rfcb->RawWriteSerializationList );
  2107. workContext = CONTAINING_RECORD(
  2108. listEntry,
  2109. WORK_CONTEXT,
  2110. ListEntry
  2111. );
  2112. QUEUE_WORK_TO_FSP( workContext );
  2113. }
  2114. if ( GET_BLOCK_STATE(Rfcb) == BlockStateClosing ) {
  2115. //
  2116. // The count is now zero and the RFCB is closing. The
  2117. // cleanup was deferred pending the completion of all raw
  2118. // writes. Do the cleanup now.
  2119. //
  2120. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2121. SrvCompleteRfcbClose( Rfcb );
  2122. } else {
  2123. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2124. }
  2125. } else {
  2126. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2127. }
  2128. return;
  2129. } // SrvDecrementRawWriteCount
  2130. VOID SRVFASTCALL
  2131. SrvRestartRawReceive (
  2132. IN OUT PWORK_CONTEXT WorkContext
  2133. )
  2134. /*++
  2135. Routine Description:
  2136. This is the restart routine that is invoked when Write Block Raw
  2137. write data is received. It starts the local write operation.
  2138. This routine is called in the FSP.
  2139. Arguments:
  2140. WorkContext - Supplies a pointer to the work context block
  2141. describing server-specific context for the request.
  2142. Return Value:
  2143. None.
  2144. --*/
  2145. {
  2146. PCONNECTION connection;
  2147. PIRP irp;
  2148. PRFCB rfcb;
  2149. PLFCB lfcb;
  2150. PMDL mdl;
  2151. PMDL partialMdl;
  2152. PCHAR writeAddress;
  2153. CLONG writeLength;
  2154. LARGE_INTEGER offset;
  2155. PVOID finalResponseBuffer;
  2156. CLONG immediateLength;
  2157. ULONG key;
  2158. NTSTATUS status;
  2159. PAGED_CODE( );
  2160. IF_DEBUG(FSD1) KdPrint(( " - SrvRestartRawReceive\n" ));
  2161. //
  2162. // If the I/O request failed or was canceled, or if the connection
  2163. // that received the message is no longer active, or if the server
  2164. // FSP isn't active, abort the request.
  2165. //
  2166. // *** Note that we don't send a final response in any of these
  2167. // cases. We assume that the failure is catastrophic, so
  2168. // there's no use sending a response.
  2169. //
  2170. connection = WorkContext->Connection;
  2171. irp = WorkContext->Irp;
  2172. WorkContext->CurrentWorkQueue->stats.BytesReceived += irp->IoStatus.Information;
  2173. if ( irp->Cancel ||
  2174. !NT_SUCCESS(irp->IoStatus.Status) ||
  2175. (GET_BLOCK_STATE(connection) != BlockStateActive) ||
  2176. SrvFspTransitioning ) {
  2177. IF_DEBUG(TRACE2) {
  2178. if ( irp->Cancel ) {
  2179. KdPrint(( " I/O canceled\n" ));
  2180. } else if ( !NT_SUCCESS(irp->IoStatus.Status) ) {
  2181. KdPrint(( " I/O failed: %X\n", irp->IoStatus.Status ));
  2182. } else if ( SrvFspTransitioning ) {
  2183. KdPrint(( " Server is shutting down.\n" ));
  2184. } else {
  2185. KdPrint(( " Connection no longer active\n" ));
  2186. }
  2187. }
  2188. //
  2189. // Abort the raw write.
  2190. //
  2191. AbortRawWrite( WorkContext );
  2192. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartRawReceive complete\n" ));
  2193. return;
  2194. }
  2195. //
  2196. // Set up local variables.
  2197. //
  2198. rfcb = WorkContext->Rfcb;
  2199. lfcb = rfcb->Lfcb;
  2200. finalResponseBuffer = WorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  2201. immediateLength = WorkContext->Parameters.WriteRaw.ImmediateLength;
  2202. //
  2203. // Determine whether we're doing "copy write" or "MDL write".
  2204. //
  2205. if ( WorkContext->Parameters.WriteRaw.MdlWrite ) {
  2206. #if DBG
  2207. IF_SMB_DEBUG(RAW2) {
  2208. KdPrint(( "SrvRestartRawReceive: Receive MDL chain after receive\n" ));
  2209. DumpMdlChain( irp->MdlAddress );
  2210. }
  2211. #endif
  2212. //
  2213. // This was an MDL write. If a partial MDL was built (because
  2214. // of immediate data), unmap it. Then complete the MDL write.
  2215. //
  2216. mdl = WorkContext->Parameters.WriteRaw.FirstMdl;
  2217. partialMdl = WorkContext->Irp->MdlAddress;
  2218. if ( partialMdl != mdl ) {
  2219. ASSERT( (partialMdl->MdlFlags & MDL_PARTIAL) != 0 );
  2220. MmPrepareMdlForReuse( partialMdl );
  2221. }
  2222. //
  2223. // Build the "complete MDL write" request. Note that
  2224. // irp->IoStatus.Information, which is where we're supposed to
  2225. // put the amount of data actually written, already contains the
  2226. // length of the received data.
  2227. //
  2228. irp->MdlAddress = mdl;
  2229. if ( !WorkContext->Parameters.WriteRaw.ImmediateWriteDone ) {
  2230. irp->IoStatus.Information += immediateLength;
  2231. }
  2232. #if DBG
  2233. IF_SMB_DEBUG(RAW2) {
  2234. KdPrint(( "SrvRestartRawReceive: Completing MDL write with length 0x%p\n",
  2235. (PVOID)irp->IoStatus.Information ));
  2236. DumpMdlChain( mdl );
  2237. }
  2238. #endif
  2239. if( lfcb->MdlWriteComplete == NULL ||
  2240. lfcb->MdlWriteComplete(
  2241. lfcb->FileObject,
  2242. &WorkContext->Parameters.WriteRaw.Offset,
  2243. mdl,
  2244. lfcb->DeviceObject ) == FALSE ) {
  2245. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  2246. mdl,
  2247. IRP_MJ_WRITE,
  2248. &WorkContext->Parameters.WriteRaw.Offset,
  2249. WorkContext->Parameters.WriteRaw.Length
  2250. );
  2251. if( !NT_SUCCESS( status ) ) {
  2252. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2253. }
  2254. }
  2255. SrvFsdRestartWriteRaw( WorkContext );
  2256. return;
  2257. }
  2258. //
  2259. // We're doing a copy write. Get parameters for the request.
  2260. //
  2261. offset = WorkContext->Parameters.WriteRaw.Offset;
  2262. mdl = WorkContext->RequestBuffer->Mdl;
  2263. //
  2264. // Determine the amount of data to write. This is the actual amount
  2265. // of data sent by the client. (Note that this cannot be more than
  2266. // the client originally requested.)
  2267. //
  2268. writeAddress = (PCHAR)WorkContext->RequestBuffer->Buffer;
  2269. writeLength = (ULONG)irp->IoStatus.Information;
  2270. //
  2271. // If the immediate data was not written earlier, it immedidately
  2272. // precedes the data we just received. Adjust writeAddress and
  2273. // writeLength so that it too is written.
  2274. //
  2275. if ( !WorkContext->Parameters.WriteRaw.ImmediateWriteDone ) {
  2276. writeAddress -= immediateLength;
  2277. writeLength += immediateLength;
  2278. }
  2279. //
  2280. // Form the lock key using the FID and the PID.
  2281. //
  2282. // *** The FID must be included in the key in order to account for
  2283. // the folding of multiple remote compatibility mode opens into
  2284. // a single local open.
  2285. //
  2286. key = rfcb->ShiftedFid | WorkContext->Parameters.WriteRaw.Pid;
  2287. //
  2288. // Try the fast I/O path first.
  2289. //
  2290. if ( lfcb->FastIoWrite != NULL ) {
  2291. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  2292. try {
  2293. if ( lfcb->FastIoWrite(
  2294. lfcb->FileObject,
  2295. &offset,
  2296. writeLength,
  2297. TRUE,
  2298. key,
  2299. writeAddress,
  2300. &WorkContext->Irp->IoStatus,
  2301. lfcb->DeviceObject
  2302. ) ) {
  2303. //
  2304. // The fast I/O path worked. Call the restart routine directly.
  2305. //
  2306. SrvFsdRestartWriteRaw( WorkContext );
  2307. return;
  2308. }
  2309. }
  2310. except( EXCEPTION_EXECUTE_HANDLER ) {
  2311. // Fall through to the slow path on an exception
  2312. NTSTATUS status = GetExceptionCode();
  2313. IF_DEBUG(ERRORS) {
  2314. KdPrint(("FastIoRead threw exception %x\n", status ));
  2315. }
  2316. }
  2317. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  2318. }
  2319. //
  2320. // The fast I/O path failed, so we need to issue a real I/O request.
  2321. //
  2322. // Remap the MDL to describe only the received data, which may be
  2323. // less than was originally mapped.
  2324. //
  2325. // !!! Is this really necessary? Can't we just pass in the entire
  2326. // MDL, and count on the file system to know when to stop?
  2327. //
  2328. if ( writeLength != WorkContext->RequestBuffer->BufferLength ) {
  2329. MmInitializeMdl( mdl, writeAddress, writeLength );
  2330. MmBuildMdlForNonPagedPool( mdl );
  2331. }
  2332. if ( rfcb->ShareType != ShareTypePipe ) {
  2333. //
  2334. // Start the write request, reusing the receive IRP.
  2335. //
  2336. SrvBuildReadOrWriteRequest(
  2337. irp, // input IRP address
  2338. lfcb->FileObject, // target file object address
  2339. WorkContext, // context
  2340. IRP_MJ_WRITE, // major function code
  2341. 0, // minor function code
  2342. writeAddress, // buffer address
  2343. writeLength, // buffer length
  2344. mdl, // MDL address
  2345. offset, // byte offset
  2346. key // lock key
  2347. );
  2348. } else {
  2349. //
  2350. // Build a write request for NPFS.
  2351. //
  2352. SrvBuildIoControlRequest(
  2353. WorkContext->Irp,
  2354. lfcb->FileObject,
  2355. WorkContext,
  2356. IRP_MJ_FILE_SYSTEM_CONTROL,
  2357. FSCTL_PIPE_INTERNAL_WRITE,
  2358. writeAddress,
  2359. writeLength,
  2360. NULL,
  2361. 0,
  2362. NULL,
  2363. NULL
  2364. );
  2365. }
  2366. IF_SMB_DEBUG(RAW2) {
  2367. KdPrint(( "SrvRestartRawReceive: writing to file 0x%p, offset %ld, length %ld\n",
  2368. lfcb->FileObject, offset.LowPart, writeLength ));
  2369. }
  2370. //
  2371. // Pass the request to the file system.
  2372. //
  2373. WorkContext->FsdRestartRoutine = SrvFsdRestartWriteRaw;
  2374. DEBUG WorkContext->FspRestartRoutine = NULL;
  2375. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2376. //
  2377. // The write has been started. When it completes, processing
  2378. // continues at SrvFsdRestartWriteRaw.
  2379. //
  2380. return;
  2381. } // SrvRestartRawReceive
  2382. VOID SRVFASTCALL
  2383. SrvRestartReadRawComplete (
  2384. IN OUT PWORK_CONTEXT WorkContext
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. This routine completes a read raw by starting any oplock breaks that
  2389. may have been deferred due to the read raw.
  2390. This routine is called in the FSP.
  2391. Arguments:
  2392. WorkContext - Supplies a pointer to the work context block
  2393. describing server-specific context for the request.
  2394. Return Value:
  2395. None.
  2396. --*/
  2397. {
  2398. PAGED_CODE( );
  2399. //
  2400. // Start oplock break notifications, if any are outstanding.
  2401. // SrvSendDelayedOplockBreak also sets read raw in progress to FALSE.
  2402. //
  2403. SrvSendDelayedOplockBreak( WorkContext->Connection );
  2404. //
  2405. // Finish postprocessing of the SMB.
  2406. //
  2407. SrvDereferenceWorkItem( WorkContext );
  2408. return;
  2409. } // SrvRestartReadRawComplete
  2410. VOID SRVFASTCALL
  2411. SrvRestartWriteCompleteResponse (
  2412. IN OUT PWORK_CONTEXT WorkContext
  2413. )
  2414. /*++
  2415. Routine Description:
  2416. This is the restart routine that is invoked to clean up after a
  2417. Write Block Raw/Mpx completes, and the necessary clean up could not
  2418. be done in the FSD. See RestartWriteCompleteResponse in fsd.c.
  2419. This routine is called in the FSP.
  2420. Arguments:
  2421. WorkContext - Supplies a pointer to the work context block
  2422. describing server-specific context for the request.
  2423. Return Value:
  2424. None.
  2425. --*/
  2426. {
  2427. PAGED_CODE( );
  2428. IF_DEBUG(WORKER1) KdPrint(( " - SrvRestartWriteCompleteResponse\n" ));
  2429. //
  2430. // Decrement the active raw write count for the RFCB, potentially
  2431. // allowing the RFCB to be closed. If WorkContext->Rfcb is NULL,
  2432. // then the count has been decremented in the fsd.
  2433. //
  2434. if ( WorkContext->Rfcb != NULL ) {
  2435. SrvDecrementRawWriteCount ( WorkContext->Rfcb );
  2436. }
  2437. //
  2438. // Dereference control blocks and the connection.
  2439. //
  2440. SrvReleaseContext( WorkContext );
  2441. SrvDereferenceConnection( WorkContext->Connection );
  2442. WorkContext->Connection = NULL;
  2443. WorkContext->Endpoint = NULL; // not a referenced pointer
  2444. //
  2445. // Put the work item back on the raw mode work item list.
  2446. //
  2447. SrvRequeueRawModeWorkItem( WorkContext );
  2448. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartWriteCompleteResponse complete\n" ));
  2449. return;
  2450. } // SrvRestartWriteCompleteResponse
  2451. VOID SRVFASTCALL
  2452. SrvBuildAndSendWriteCompleteResponse (
  2453. IN OUT PWORK_CONTEXT WorkContext
  2454. )
  2455. /*++
  2456. Routine Description:
  2457. Sets up and sends a final response to a Write Block Raw/Mpx request.
  2458. This routine is called in the FSP. It is invoked as a restart routine
  2459. from the FSD when the status to be returned is not STATUS_SUCCESS.
  2460. Arguments:
  2461. WorkContext - Supplies a pointer to the work context block
  2462. describing server-specific context for the request.
  2463. Return Value:
  2464. None.
  2465. --*/
  2466. {
  2467. PAGED_CODE( );
  2468. SrvFsdBuildWriteCompleteResponse(
  2469. WorkContext,
  2470. WorkContext->Irp->IoStatus.Status,
  2471. (ULONG)WorkContext->Irp->IoStatus.Information
  2472. );
  2473. WorkContext->ResponseBuffer->DataLength =
  2474. (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  2475. (PCHAR)WorkContext->ResponseHeader );
  2476. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  2477. SRV_START_SEND_2(
  2478. WorkContext,
  2479. SrvFsdSendCompletionRoutine,
  2480. WorkContext->FsdRestartRoutine,
  2481. NULL
  2482. );
  2483. return;
  2484. } // SrvBuildAndSendWriteCompleteResponse