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

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