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.

3099 lines
78 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. Write.c
  5. Abstract:
  6. This module implements support for NtWriteFile for the
  7. NetWare redirector called by the dispatch driver.
  8. Author:
  9. Colin Watson [ColinW] 07-Apr-1993
  10. Revision History:
  11. --*/
  12. #include "Procs.h"
  13. #include <stdlib.h>
  14. //
  15. // The local debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_WRITE)
  18. //
  19. // The header overhead in the first packet of a burst write.
  20. //
  21. #define BURST_WRITE_HEADER_SIZE \
  22. ( sizeof( NCP_BURST_WRITE_REQUEST ) - sizeof( NCP_BURST_HEADER ) )
  23. //
  24. // Local procedure prototypes
  25. //
  26. NTSTATUS
  27. NwCommonWrite (
  28. IN PIRP_CONTEXT IrpContext
  29. );
  30. NTSTATUS
  31. WriteNcp(
  32. PIRP_CONTEXT IrpContext,
  33. LARGE_INTEGER ByteOffset,
  34. ULONG BufferLength,
  35. PVOID WriteBuffer,
  36. PMDL WriteMdl
  37. );
  38. NTSTATUS
  39. QueryEofForWriteCallback (
  40. IN PIRP_CONTEXT IrpContext,
  41. IN ULONG BytesAvailable,
  42. IN PUCHAR Response
  43. );
  44. NTSTATUS
  45. WriteNcpCallback (
  46. IN PIRP_CONTEXT IrpContext,
  47. IN ULONG BytesAvailable,
  48. IN PUCHAR Response
  49. );
  50. NTSTATUS
  51. BurstWrite(
  52. PIRP_CONTEXT IrpContext,
  53. LARGE_INTEGER ByteOffset,
  54. ULONG BufferLength,
  55. PVOID WriteBuffer,
  56. PMDL WriteMdl
  57. );
  58. NTSTATUS
  59. SendWriteBurst(
  60. PIRP_CONTEXT IrpContext,
  61. ULONG Offset,
  62. USHORT Length,
  63. BOOLEAN EndOfBurst,
  64. BOOLEAN Retransmission
  65. );
  66. VOID
  67. BuildBurstWriteFirstReq(
  68. PIRP_CONTEXT IrpContext,
  69. PVOID Buffer,
  70. ULONG DataSize,
  71. PMDL BurstMdl,
  72. UCHAR Flags,
  73. ULONG Handle,
  74. ULONG FileOffset
  75. );
  76. VOID
  77. BuildBurstWriteNextReq(
  78. PIRP_CONTEXT IrpContext,
  79. PVOID Buffer,
  80. ULONG DataSize,
  81. UCHAR BurstFlags,
  82. ULONG BurstOffset,
  83. PMDL BurstHeaderMdl,
  84. PMDL BurstDataMdl
  85. );
  86. NTSTATUS
  87. BurstWriteCompletionSend(
  88. IN PDEVICE_OBJECT DeviceObject,
  89. IN PIRP Irp,
  90. IN PVOID Context
  91. );
  92. NTSTATUS
  93. BurstWriteCallback (
  94. IN PIRP_CONTEXT IrpContext,
  95. IN ULONG BytesAvailable,
  96. IN PUCHAR Response
  97. );
  98. VOID
  99. BurstWriteTimeout(
  100. PIRP_CONTEXT IrpContext
  101. );
  102. NTSTATUS
  103. BurstWriteReconnect(
  104. PIRP_CONTEXT IrpContext
  105. );
  106. NTSTATUS
  107. NwCommonFlushBuffers (
  108. IN PIRP_CONTEXT IrpContext
  109. );
  110. NTSTATUS
  111. FlushBuffersCallback (
  112. IN PIRP_CONTEXT IrpContext,
  113. IN ULONG BytesAvailable,
  114. IN PUCHAR Response
  115. );
  116. NTSTATUS
  117. SendSecondaryPacket(
  118. PIRP_CONTEXT IrpContext,
  119. PIRP Irp
  120. );
  121. #ifdef ALLOC_PRAGMA
  122. #pragma alloc_text( PAGE, NwFsdWrite )
  123. #pragma alloc_text( PAGE, NwCommonWrite )
  124. #pragma alloc_text( PAGE, DoWrite )
  125. #pragma alloc_text( PAGE, WriteNcp )
  126. #pragma alloc_text( PAGE, BurstWrite )
  127. #pragma alloc_text( PAGE, SendWriteBurst )
  128. #pragma alloc_text( PAGE, ResubmitBurstWrite )
  129. #pragma alloc_text( PAGE, NwFsdFlushBuffers )
  130. #pragma alloc_text( PAGE, NwCommonFlushBuffers )
  131. #pragma alloc_text( PAGE, BuildBurstWriteFirstReq )
  132. #pragma alloc_text( PAGE, BuildBurstWriteNextReq )
  133. #ifndef QFE_BUILD
  134. #pragma alloc_text( PAGE1, WriteNcpCallback )
  135. #pragma alloc_text( PAGE1, BurstWriteCompletionSend )
  136. #pragma alloc_text( PAGE1, BurstWriteCallback )
  137. #pragma alloc_text( PAGE1, BurstWriteTimeout )
  138. #pragma alloc_text( PAGE1, FlushBuffersCallback )
  139. #pragma alloc_text( PAGE1, SendSecondaryPacket )
  140. #pragma alloc_text( PAGE1, BurstWriteReconnect )
  141. #endif
  142. #endif
  143. #if 0 // Not pageable
  144. // see ifndef QFE_BUILD above
  145. #endif
  146. NTSTATUS
  147. NwFsdWrite(
  148. IN PDEVICE_OBJECT DeviceObject,
  149. IN PIRP Irp
  150. )
  151. /*++
  152. Routine Description:
  153. This routine is the FSD routine that handles NtWriteFile.
  154. Arguments:
  155. NwfsDeviceObject - Supplies the device object for the write function.
  156. Irp - Supplies the IRP to process.
  157. Return Value:
  158. NTSTATUS - The result status.
  159. --*/
  160. {
  161. PIRP_CONTEXT pIrpContext = NULL;
  162. NTSTATUS status;
  163. BOOLEAN TopLevel;
  164. PAGED_CODE();
  165. DebugTrace(+1, Dbg, "NwFsdWrite\n", 0);
  166. //
  167. // Call the common write routine.
  168. //
  169. FsRtlEnterFileSystem();
  170. TopLevel = NwIsIrpTopLevel( Irp );
  171. try {
  172. pIrpContext = AllocateIrpContext( Irp );
  173. status = NwCommonWrite( pIrpContext );
  174. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  175. if ( pIrpContext == NULL ) {
  176. //
  177. // If we couldn't allocate an irp context, just complete
  178. // irp without any fanfare.
  179. //
  180. status = STATUS_INSUFFICIENT_RESOURCES;
  181. Irp->IoStatus.Status = status;
  182. Irp->IoStatus.Information = 0;
  183. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  184. } else {
  185. //
  186. // We had some trouble trying to perform the requested
  187. // operation, so we'll abort the I/O request with
  188. // the error Status that we get back from the
  189. // execption code
  190. //
  191. status = NwProcessException( pIrpContext, GetExceptionCode() );
  192. }
  193. }
  194. if ( pIrpContext ) {
  195. if ( status != STATUS_PENDING ) {
  196. NwDequeueIrpContext( pIrpContext, FALSE );
  197. }
  198. NwCompleteRequest( pIrpContext, status );
  199. }
  200. if ( TopLevel ) {
  201. NwSetTopLevelIrp( NULL );
  202. }
  203. FsRtlExitFileSystem();
  204. //
  205. // Return to the caller.
  206. //
  207. DebugTrace(-1, Dbg, "NwFsdWrite -> %08lx\n", status );
  208. Stats.WriteOperations++;
  209. return status;
  210. }
  211. NTSTATUS
  212. NwCommonWrite (
  213. IN PIRP_CONTEXT IrpContext
  214. )
  215. /*++
  216. Routine Description:
  217. This routine does the common code for NtWriteFile.
  218. Arguments:
  219. IrpContext - Supplies the request being processed.
  220. Return Value:
  221. NTSTATUS - The return status for the operation
  222. --*/
  223. {
  224. NTSTATUS status;
  225. PIRP Irp;
  226. PIO_STACK_LOCATION irpSp;
  227. NODE_TYPE_CODE nodeTypeCode;
  228. PICB icb;
  229. PFCB fcb;
  230. PNONPAGED_FCB pNpFcb;
  231. PVOID fsContext;
  232. BOOLEAN WroteToCache;
  233. LARGE_INTEGER ByteOffset;
  234. LARGE_INTEGER PreviousByteOffset;
  235. ULONG BufferLength;
  236. PULONG pFileSize;
  237. // ULONG FileLength;
  238. PAGED_CODE();
  239. //
  240. // Get the current stack location
  241. //
  242. Irp = IrpContext->pOriginalIrp;
  243. irpSp = IoGetCurrentIrpStackLocation( Irp );
  244. DebugTrace(+1, Dbg, "CommonWrite...\n", 0);
  245. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG_PTR)Irp);
  246. //
  247. // Decode the file object to figure out who we are. If the result
  248. // is not the root DCB then its an illegal parameter.
  249. //
  250. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  251. &fsContext,
  252. (PVOID *)&icb );
  253. fcb = (PFCB)icb->SuperType.Fcb;
  254. if (((nodeTypeCode != NW_NTC_ICB) &&
  255. (nodeTypeCode != NW_NTC_ICB_SCB)) ||
  256. (!icb->HasRemoteHandle) ) {
  257. DebugTrace(0, Dbg, "Not a file\n", 0);
  258. status = STATUS_INVALID_PARAMETER;
  259. DebugTrace(-1, Dbg, "CommonWrite -> %08lx\n", status );
  260. return status;
  261. }
  262. //
  263. // Make sure that this ICB is still active.
  264. //
  265. NwVerifyIcbSpecial( icb );
  266. if ( fcb->NodeTypeCode == NW_NTC_FCB ) {
  267. IrpContext->pScb = fcb->Scb;
  268. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  269. IrpContext->Icb = icb;
  270. pFileSize = &icb->NpFcb->Header.FileSize.LowPart;
  271. } else if ( fcb->NodeTypeCode == NW_NTC_SCB ) {
  272. IrpContext->pScb = icb->SuperType.Scb;
  273. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  274. IrpContext->Icb = icb;
  275. fcb = NULL;
  276. pFileSize = &icb->FileSize;
  277. } else {
  278. DebugTrace(0, Dbg, "Not a file or a server\n", 0);
  279. status = STATUS_INVALID_PARAMETER;
  280. DebugTrace(-1, Dbg, "CommonWrite -> %08lx\n", status );
  281. return status;
  282. }
  283. ByteOffset = irpSp->Parameters.Write.ByteOffset;
  284. BufferLength = irpSp->Parameters.Write.Length;
  285. //
  286. // Can't handle large byte offset, but write to EOF is okay.
  287. //
  288. if ( ByteOffset.HighPart != 0 ) {
  289. if ( ByteOffset.HighPart != 0xFFFFFFFF ||
  290. ByteOffset.LowPart != 0xFFFFFFFF ) {
  291. return( STATUS_INVALID_PARAMETER );
  292. }
  293. }
  294. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  295. !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  296. PreviousByteOffset.QuadPart = irpSp->FileObject->CurrentByteOffset.QuadPart;
  297. irpSp->FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart;
  298. }
  299. //
  300. // Paging I/O is not allowed to extend the file
  301. //
  302. if ((FlagOn(Irp->Flags, IRP_PAGING_IO)) &&
  303. (ByteOffset.LowPart + BufferLength > *pFileSize )) {
  304. NwAppendToQueueAndWait( IrpContext );
  305. if ( ByteOffset.LowPart + BufferLength <= *pFileSize ) {
  306. //
  307. // Someone else extended the file. Do nothing.
  308. //
  309. // continue;
  310. } else if ( ByteOffset.LowPart > *pFileSize ) {
  311. //
  312. // Whole write is off the end of the buffer
  313. //
  314. NwDequeueIrpContext( IrpContext, FALSE );
  315. Irp->IoStatus.Information = 0;
  316. return( STATUS_SUCCESS );
  317. } else {
  318. //
  319. // Truncate request to size of file
  320. //
  321. BufferLength = *pFileSize - ByteOffset.LowPart;
  322. }
  323. NwDequeueIrpContext( IrpContext, FALSE );
  324. }
  325. //
  326. // Special case 0 length write.
  327. //
  328. if ( BufferLength == 0 ) {
  329. Irp->IoStatus.Information = 0;
  330. return( STATUS_SUCCESS );
  331. }
  332. //
  333. // Remember the original MDL, so that we can restore it when we are done.
  334. //
  335. IrpContext->pOriginalMdlAddress = Irp->MdlAddress;
  336. //
  337. // Attempt to write this data to our private cache
  338. //
  339. if ( fcb != NULL && Irp->UserBuffer != NULL ) {
  340. WroteToCache = CacheWrite(
  341. IrpContext,
  342. fcb->NonPagedFcb,
  343. ByteOffset.LowPart,
  344. BufferLength,
  345. Irp->UserBuffer );
  346. if ( WroteToCache ) {
  347. Irp->IoStatus.Information = BufferLength;
  348. //
  349. // Update the current byte offset in the file if it is a
  350. // synchronous file (and this is not paging I/O).
  351. //
  352. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  353. !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  354. irpSp->FileObject->CurrentByteOffset.QuadPart += BufferLength;
  355. }
  356. //
  357. // Record write offset and size to discover a sequential write pattern.
  358. //
  359. fcb->LastReadOffset = irpSp->Parameters.Write.ByteOffset.LowPart;
  360. fcb->LastReadSize = irpSp->Parameters.Write.Length;
  361. //
  362. // If the file was extended, record the new file size.
  363. //
  364. if ( fcb->LastReadOffset + fcb->LastReadSize >
  365. fcb->NonPagedFcb->Header.FileSize.LowPart ) {
  366. fcb->NonPagedFcb->Header.FileSize.LowPart =
  367. fcb->LastReadOffset + fcb->LastReadSize;
  368. }
  369. DebugTrace(-1, Dbg, "NwCommonWrite -> %08lx\n", STATUS_SUCCESS );
  370. return( STATUS_SUCCESS );
  371. }
  372. }
  373. status = DoWrite(
  374. IrpContext,
  375. ByteOffset,
  376. BufferLength,
  377. Irp->UserBuffer,
  378. IrpContext->pOriginalMdlAddress );
  379. if ( NT_SUCCESS( status ) ) {
  380. //
  381. // We actually wrote something out to the wire. If there was a read
  382. // cache and this write overlapped it, invalidate the read cache data
  383. // so that we get good data on future reads.
  384. //
  385. if ( fcb != NULL ) {
  386. pNpFcb = fcb->NonPagedFcb;
  387. if ( ( pNpFcb->CacheBuffer != NULL ) &&
  388. ( pNpFcb->CacheSize != 0 ) &&
  389. ( pNpFcb->CacheType == ReadAhead ) ) {
  390. //
  391. // Two cases: (1) offset is less than cache offset
  392. // (2) offset is inside cached region
  393. //
  394. if ( ByteOffset.LowPart < pNpFcb->CacheFileOffset ) {
  395. //
  396. // Did we run into the read cache?
  397. //
  398. if ( BufferLength >
  399. (pNpFcb->CacheFileOffset - ByteOffset.LowPart) ) {
  400. DebugTrace( 0, Dbg, "Invalidated read cache for %08lx.\n", pNpFcb );
  401. pNpFcb->CacheDataSize = 0;
  402. }
  403. } else {
  404. //
  405. // Did we write over any of the cached region.
  406. //
  407. if ( ByteOffset.LowPart <= ( pNpFcb->CacheFileOffset + pNpFcb->CacheDataSize ) ) {
  408. DebugTrace( 0, Dbg, "Invalidated read cache for %08lx.\n", pNpFcb );
  409. pNpFcb->CacheDataSize = 0;
  410. }
  411. }
  412. }
  413. }
  414. Irp->IoStatus.Information = IrpContext->Specific.Write.WriteOffset;
  415. //
  416. // Update the current byte offset in the file if it is a
  417. // synchronous file (and this is not paging I/O).
  418. //
  419. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  420. !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  421. irpSp->FileObject->CurrentByteOffset.QuadPart += BufferLength;
  422. }
  423. NwAppendToQueueAndWait( IrpContext );
  424. if (ByteOffset.LowPart + BufferLength > *pFileSize ) {
  425. *pFileSize = ByteOffset.LowPart + BufferLength;
  426. }
  427. } else {
  428. //
  429. // The request failed, don't move the file pointer.
  430. //
  431. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  432. !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  433. irpSp->FileObject->CurrentByteOffset.QuadPart = PreviousByteOffset.QuadPart;
  434. }
  435. }
  436. DebugTrace(-1, Dbg, "CommonWrite -> %08lx\n", status);
  437. return status;
  438. }
  439. NTSTATUS
  440. DoWrite(
  441. PIRP_CONTEXT IrpContext,
  442. LARGE_INTEGER ByteOffset,
  443. ULONG BufferLength,
  444. PVOID WriteBuffer,
  445. PMDL WriteMdl OPTIONAL
  446. )
  447. /*++
  448. Routine Description:
  449. This routine does a write to the network via the most efficient
  450. available protocol.
  451. Arguments:
  452. IrpContext - A pointer to IRP context information for this request.
  453. ByteOffset - The file offset to write.
  454. BufferLength - The number of bytes to write.
  455. WriteBuffer - A pointer to the source buffer.
  456. WriteMdl = An optional MDL for the write buffer.
  457. Return Value:
  458. Status of transfer.
  459. --*/
  460. {
  461. NTSTATUS status;
  462. PAGED_CODE();
  463. if ( IrpContext->pNpScb->SendBurstModeEnabled &&
  464. BufferLength > IrpContext->pNpScb->BufferSize ) {
  465. status = BurstWrite( IrpContext, ByteOffset, BufferLength, WriteBuffer, WriteMdl );
  466. } else {
  467. status = WriteNcp( IrpContext, ByteOffset, BufferLength, WriteBuffer, WriteMdl );
  468. }
  469. //
  470. // Reset IrpContext parameters
  471. //
  472. IrpContext->TxMdl->Next = NULL;
  473. IrpContext->CompletionSendRoutine = NULL;
  474. IrpContext->TimeoutRoutine = NULL;
  475. IrpContext->Flags &= ~(IRP_FLAG_RETRY_SEND | IRP_FLAG_BURST_REQUEST | IRP_FLAG_BURST_PACKET |
  476. IRP_FLAG_BURST_WRITE | IRP_FLAG_NOT_SYSTEM_PACKET );
  477. IrpContext->pTdiStruct = NULL;
  478. IrpContext->pOriginalIrp->MdlAddress = IrpContext->pOriginalMdlAddress;
  479. IrpContext->pOriginalIrp->AssociatedIrp.SystemBuffer = IrpContext->pOriginalSystemBuffer;
  480. return( status );
  481. }
  482. NTSTATUS
  483. WriteNcp(
  484. PIRP_CONTEXT IrpContext,
  485. LARGE_INTEGER ByteOffset,
  486. ULONG BufferLength,
  487. PVOID WriteBuffer,
  488. PMDL WriteMdl
  489. )
  490. /*++
  491. Routine Description:
  492. This routine exchanges a series of write NCPs with the server.
  493. Arguments:
  494. IrpContext - A pointer to IRP context information for this request.
  495. Icb - Supplies the file specific information.
  496. Return Value:
  497. Status of transfer.
  498. --*/
  499. {
  500. PICB Icb;
  501. PIRP irp;
  502. PIO_STACK_LOCATION irpSp;
  503. ULONG Length; // Size we will send to the server
  504. ULONG FileLength;
  505. PSCB pScb;
  506. NTSTATUS status = STATUS_UNSUCCESSFUL;
  507. PMDL DataMdl;
  508. BOOLEAN Done;
  509. PAGED_CODE();
  510. Icb = IrpContext->Icb;
  511. irp = IrpContext->pOriginalIrp;
  512. irpSp = IoGetCurrentIrpStackLocation( irp );
  513. DebugTrace(+1, Dbg, "WriteNcp...\n", 0);
  514. DebugTrace( 0, Dbg, "irp = %08lx\n", (ULONG_PTR)irp);
  515. DebugTrace( 0, Dbg, "WriteLen= %ld\n", BufferLength);
  516. DebugTrace( 0, Dbg, "HOffset = %lx\n", ByteOffset.HighPart);
  517. DebugTrace( 0, Dbg, "LOffset = %lx\n", ByteOffset.LowPart);
  518. if (Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_FCB) {
  519. pScb = Icb->SuperType.Fcb->Scb;
  520. DebugTrace( 0, Dbg, "File = %wZ\n", &Icb->SuperType.Fcb->FullFileName);
  521. } else {
  522. //
  523. // Write to a queue
  524. //
  525. pScb = Icb->SuperType.Scb;
  526. }
  527. ASSERT (pScb->NodeTypeCode == NW_NTC_SCB);
  528. if ( ByteOffset.HighPart == 0xFFFFFFFF &&
  529. ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE ) {
  530. //
  531. // Ensure that you are at the head of the queue
  532. //
  533. NwAppendToQueueAndWait( IrpContext );
  534. //
  535. // Write relative to end of file. Find the end of file.
  536. //
  537. status = ExchangeWithWait(
  538. IrpContext,
  539. SynchronousResponseCallback,
  540. "F-r",
  541. NCP_GET_FILE_SIZE,
  542. &Icb->Handle, sizeof( Icb->Handle ) );
  543. if ( NT_SUCCESS( status ) ) {
  544. status = ParseResponse(
  545. IrpContext,
  546. IrpContext->rsp,
  547. IrpContext->ResponseLength,
  548. "Nd",
  549. &FileLength );
  550. if ( !NT_SUCCESS( status ) ) {
  551. return status;
  552. }
  553. }
  554. IrpContext->Specific.Write.FileOffset = FileLength;
  555. }
  556. Length = MIN( (ULONG)IrpContext->pNpScb->BufferSize, BufferLength );
  557. DebugTrace( 0, Dbg, "Length = %ld\n", Length);
  558. //
  559. // The server will not accept writes that cross 4k boundaries in the file
  560. //
  561. if ((IrpContext->pNpScb->PageAlign) &&
  562. (DIFFERENT_PAGES( ByteOffset.LowPart, Length ))) {
  563. Length = 4096 -
  564. ((ULONG)ByteOffset.LowPart & (4096-1));
  565. }
  566. IrpContext->Specific.Write.Buffer = WriteBuffer;
  567. IrpContext->Specific.Write.WriteOffset = 0;
  568. IrpContext->Specific.Write.RemainingLength = BufferLength;
  569. IrpContext->Specific.Write.LastWriteLength = Length;
  570. IrpContext->Specific.Write.FileOffset = ByteOffset.LowPart;
  571. IrpContext->Specific.Write.PartialMdl = NULL;
  572. Done = FALSE;
  573. while ( !Done ) {
  574. //
  575. // Setup to do at most 64K of i/o asynchronously, or buffer length.
  576. //
  577. IrpContext->Specific.Write.BurstLength =
  578. MIN( 64 * 1024, IrpContext->Specific.Write.RemainingLength );
  579. IrpContext->Specific.Write.BurstOffset = 0;
  580. //
  581. // Try to allocate an MDL for this i/o.
  582. //
  583. DataMdl = ALLOCATE_MDL(
  584. (PCHAR)IrpContext->Specific.Write.Buffer +
  585. IrpContext->Specific.Write.WriteOffset,
  586. IrpContext->Specific.Write.BurstLength,
  587. FALSE, // Secondary Buffer
  588. FALSE, // Charge Quota
  589. NULL);
  590. if ( DataMdl == NULL ) {
  591. if ( IrpContext->Specific.Write.PartialMdl != NULL ) {
  592. FREE_MDL( IrpContext->Specific.Write.PartialMdl );
  593. }
  594. DebugTrace(-1, Dbg, "WriteNcp -> %X\n", STATUS_INSUFFICIENT_RESOURCES );
  595. return STATUS_INSUFFICIENT_RESOURCES;
  596. }
  597. IrpContext->Specific.Write.FullMdl = DataMdl;
  598. //
  599. // If there is no MDL for this write probe the data MDL to
  600. // lock it's pages down. Otherwise, use the data MDL as
  601. // a partial MDL.
  602. //
  603. if ( WriteMdl == NULL ) {
  604. //
  605. // The Probe may cause us to page in some data. If the data is from
  606. // the same server we are writing to then we had better not be at
  607. // the front of the queue otherwise it will wait indefinitely behind us.
  608. // Its a good idea to Dequeue ourselves after each burst anyway because
  609. // its a quick operation and it alow smaller requests to overtake a very
  610. // large series of bursts.
  611. //
  612. NwDequeueIrpContext( IrpContext, FALSE );
  613. try {
  614. MmProbeAndLockPages( DataMdl, irp->RequestorMode, IoReadAccess);
  615. } except (EXCEPTION_EXECUTE_HANDLER) {
  616. FREE_MDL( DataMdl );
  617. DebugTrace(-1, Dbg, "WriteNcp -> %X\n", GetExceptionCode() );
  618. return GetExceptionCode();
  619. }
  620. } else {
  621. IoBuildPartialMdl(
  622. WriteMdl,
  623. DataMdl,
  624. (PCHAR)IrpContext->Specific.Write.Buffer,
  625. IrpContext->Specific.Write.BurstLength );
  626. }
  627. //
  628. // Allocate a partial Mdl for the worst possible case of alignment
  629. //
  630. IrpContext->Specific.Write.PartialMdl =
  631. ALLOCATE_MDL( 0 , IrpContext->pNpScb->BufferSize + PAGE_SIZE-1, FALSE, FALSE, NULL);
  632. if ( IrpContext->Specific.Write.PartialMdl == NULL ) {
  633. if ( WriteMdl == NULL ) {
  634. MmUnlockPages( DataMdl );
  635. }
  636. FREE_MDL( DataMdl );
  637. DebugTrace(-1, Dbg, "WriteNcp -> %X\n", STATUS_INSUFFICIENT_RESOURCES );
  638. return STATUS_INSUFFICIENT_RESOURCES;
  639. }
  640. //
  641. // Build a partial MDL for this write NCP.
  642. //
  643. IoBuildPartialMdl(
  644. DataMdl,
  645. IrpContext->Specific.Write.PartialMdl,
  646. MmGetMdlVirtualAddress( DataMdl ),
  647. Length );
  648. if ( IrpContext->Specific.Write.BurstLength ==
  649. IrpContext->Specific.Write.RemainingLength ) {
  650. Done = TRUE;
  651. }
  652. //
  653. // Ensure that you are at the head of the queue
  654. //
  655. NwAppendToQueueAndWait( IrpContext );
  656. //
  657. // Send the request.
  658. //
  659. status = ExchangeWithWait(
  660. IrpContext,
  661. WriteNcpCallback,
  662. "F-rdwf",
  663. NCP_WRITE_FILE,
  664. &Icb->Handle, sizeof( Icb->Handle ),
  665. IrpContext->Specific.Write.FileOffset,
  666. Length,
  667. IrpContext->Specific.Write.PartialMdl );
  668. Stats.WriteNcps+=2;
  669. FREE_MDL( IrpContext->Specific.Write.PartialMdl );
  670. //
  671. // Unlock locked pages, and free our MDL.
  672. //
  673. if ( WriteMdl == NULL ) {
  674. MmUnlockPages( DataMdl );
  675. }
  676. FREE_MDL( DataMdl );
  677. //
  678. // If we had a failure, we need to terminate this loop.
  679. // The only status that is set is the Specific->Write
  680. // status. We can not trust what comes back from the
  681. // ExchangeWithWait by design.
  682. //
  683. if ( !NT_SUCCESS( IrpContext->Specific.Write.Status ) ) {
  684. Done = TRUE;
  685. }
  686. //
  687. // Reset the packet length since we may have less than
  688. // a packet to send.
  689. //
  690. Length = MIN( (ULONG)IrpContext->pNpScb->BufferSize,
  691. IrpContext->Specific.Write.RemainingLength );
  692. IrpContext->Specific.Write.LastWriteLength = Length;
  693. }
  694. status = IrpContext->Specific.Write.Status;
  695. DebugTrace(-1, Dbg, "WriteNcp -> %08lx\n", status );
  696. return status;
  697. }
  698. NTSTATUS
  699. WriteNcpCallback (
  700. IN PIRP_CONTEXT IrpContext,
  701. IN ULONG BytesAvailable,
  702. IN PUCHAR Response
  703. )
  704. /*++
  705. Routine Description:
  706. This routine receives the response from a user NCP.
  707. Arguments:
  708. Return Value:
  709. VOID
  710. --*/
  711. {
  712. NTSTATUS Status = STATUS_SUCCESS;
  713. ULONG Length;
  714. ULONG LastLength;
  715. DebugTrace(0, Dbg, "WriteNcpCallback...\n", 0);
  716. if ( BytesAvailable == 0) {
  717. //
  718. // No response from server. Status is in pIrpContext->
  719. // ResponseParameters.Error
  720. //
  721. IrpContext->Specific.Write.Status = STATUS_REMOTE_NOT_LISTENING;
  722. NwSetIrpContextEvent( IrpContext );
  723. return STATUS_REMOTE_NOT_LISTENING;
  724. }
  725. LastLength = IrpContext->Specific.Write.LastWriteLength;
  726. Status = ParseResponse( IrpContext, Response, BytesAvailable, "N" );
  727. if ( NT_SUCCESS(Status) ) {
  728. // If the last write worked then move the pointers appropriately
  729. IrpContext->Specific.Write.RemainingLength -= LastLength;
  730. IrpContext->Specific.Write.BurstLength -= LastLength;
  731. IrpContext->Specific.Write.WriteOffset += LastLength;
  732. IrpContext->Specific.Write.FileOffset += LastLength;
  733. IrpContext->Specific.Write.BurstOffset += LastLength;
  734. // If this is a print job, remember that we actually wrote data
  735. if ( IrpContext->Icb->IsPrintJob ) {
  736. IrpContext->Icb->ActuallyPrinted = TRUE;
  737. }
  738. } else {
  739. //
  740. // Abandon this request
  741. //
  742. IrpContext->Specific.Write.Status = Status;
  743. NwSetIrpContextEvent( IrpContext );
  744. DebugTrace( 0, Dbg, "WriteNcpCallback -> %08lx\n", Status );
  745. return Status;
  746. }
  747. if ( IrpContext->Specific.Write.BurstLength != 0 ) {
  748. // Write the next packet.
  749. DebugTrace( 0, Dbg, "RemainingLength = %ld\n", IrpContext->Specific.Write.RemainingLength);
  750. DebugTrace( 0, Dbg, "FileOffset = %ld\n", IrpContext->Specific.Write.FileOffset);
  751. DebugTrace( 0, Dbg, "WriteOffset = %ld\n", IrpContext->Specific.Write.WriteOffset);
  752. DebugTrace( 0, Dbg, "BurstOffset = %ld\n", IrpContext->Specific.Write.BurstOffset);
  753. Length = MIN( (ULONG)IrpContext->pNpScb->BufferSize,
  754. IrpContext->Specific.Write.BurstLength );
  755. //
  756. // The server will not accept writes that cross 4k boundaries
  757. // in the file.
  758. //
  759. if ((IrpContext->pNpScb->PageAlign) &&
  760. (DIFFERENT_PAGES( IrpContext->Specific.Write.FileOffset, Length ))) {
  761. Length = 4096 -
  762. ((ULONG)IrpContext->Specific.Write.FileOffset & (4096-1));
  763. }
  764. IrpContext->Specific.Write.LastWriteLength = Length;
  765. DebugTrace( 0, Dbg, "Length = %ld\n", Length);
  766. MmPrepareMdlForReuse( IrpContext->Specific.Write.PartialMdl );
  767. IoBuildPartialMdl(
  768. IrpContext->Specific.Write.FullMdl,
  769. IrpContext->Specific.Write.PartialMdl,
  770. (PUCHAR)MmGetMdlVirtualAddress( IrpContext->Specific.Write.FullMdl ) +
  771. IrpContext->Specific.Write.BurstOffset,
  772. Length );
  773. //
  774. // Send the request.
  775. //
  776. BuildRequestPacket(
  777. IrpContext,
  778. WriteNcpCallback,
  779. "F-rdwf",
  780. NCP_WRITE_FILE,
  781. &IrpContext->Icb->Handle, sizeof( IrpContext->Icb->Handle ),
  782. IrpContext->Specific.Write.FileOffset,
  783. Length,
  784. IrpContext->Specific.Write.PartialMdl );
  785. Status = PrepareAndSendPacket( IrpContext );
  786. Stats.WriteNcps+=2;
  787. DebugTrace(-1, Dbg, "WriteNcbCallBack -> %08lx\n", Status );
  788. if ( !NT_SUCCESS(Status) ) {
  789. //
  790. // Abandon this request
  791. //
  792. IrpContext->Specific.Write.Status = Status;
  793. NwSetIrpContextEvent( IrpContext );
  794. DebugTrace( 0, Dbg, "WriteNcpCallback -> %08lx\n", Status );
  795. return Status;
  796. }
  797. } else {
  798. //
  799. // We're done with this request, signal the writing thread.
  800. //
  801. IrpContext->Specific.Write.Status = STATUS_SUCCESS;
  802. NwSetIrpContextEvent( IrpContext );
  803. }
  804. DebugTrace( 0, Dbg, "WriteNcpCallback -> %08lx\n", Status );
  805. return STATUS_SUCCESS;
  806. }
  807. NTSTATUS
  808. BurstWrite(
  809. PIRP_CONTEXT IrpContext,
  810. LARGE_INTEGER ByteOffset,
  811. ULONG BufferLength,
  812. PVOID WriteBuffer,
  813. PMDL WriteMdl
  814. )
  815. /*++
  816. Routine Description:
  817. This routine exchanges a series of burst write NCPs with the server.
  818. Arguments:
  819. IrpContext - A pointer to IRP context information for this request.
  820. Return Value:
  821. Status of the transfer.
  822. --*/
  823. {
  824. PICB Icb;
  825. PIRP irp;
  826. PIO_STACK_LOCATION irpSp;
  827. ULONG Length; // Size we will send to the server
  828. PSCB pScb;
  829. PNONPAGED_SCB pNpScb;
  830. NTSTATUS status = STATUS_UNSUCCESSFUL;
  831. PMDL DataMdl;
  832. BOOLEAN Done;
  833. BOOLEAN MissingData;
  834. ULONG TimeInNwUnits;
  835. ULONG LastLength;
  836. ULONG Result;
  837. UCHAR BurstFlags;
  838. USHORT MissingFragmentCount;
  839. USHORT i;
  840. ULONG FragmentOffset;
  841. USHORT FragmentLength;
  842. Icb = IrpContext->Icb;
  843. pNpScb = IrpContext->pNpScb;
  844. irp = IrpContext->pOriginalIrp;
  845. irpSp = IoGetCurrentIrpStackLocation( irp );
  846. IrpContext->Specific.Write.WriteOffset = 0;
  847. IrpContext->Specific.Write.RemainingLength = BufferLength;
  848. IrpContext->Specific.Write.TotalWriteLength = BufferLength;
  849. IrpContext->Specific.Write.TotalWriteOffset = ByteOffset.LowPart;
  850. DebugTrace(+1, Dbg, "BurstWrite...\n", 0);
  851. DebugTrace( 0, Dbg, "irp = %08lx\n", (ULONG_PTR)irp);
  852. DebugTrace( 0, Dbg, "WriteLen= %ld\n", BufferLength);
  853. DebugTrace( 0, Dbg, "HOffset = %lx\n", ByteOffset.HighPart);
  854. DebugTrace( 0, Dbg, "LOffset = %lx\n", ByteOffset.LowPart);
  855. //
  856. // Renegotiate burst mode, if necessary
  857. //
  858. if ( pNpScb->BurstRenegotiateReqd ) {
  859. pNpScb->BurstRenegotiateReqd = FALSE;
  860. RenegotiateBurstMode( IrpContext, pNpScb );
  861. }
  862. SetFlag( IrpContext->Flags, IRP_FLAG_BURST_WRITE );
  863. if (Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_FCB) {
  864. pScb = Icb->SuperType.Fcb->Scb;
  865. DebugTrace( 0, Dbg, "File = %wZ\n", &Icb->SuperType.Fcb->FullFileName);
  866. } else {
  867. //
  868. // Write to a queue
  869. //
  870. pScb = Icb->SuperType.Scb;
  871. }
  872. ASSERT (pScb->NodeTypeCode == NW_NTC_SCB);
  873. //
  874. // Calculate the length of the burst to send.
  875. //
  876. Length = MIN( (ULONG)pNpScb->MaxSendSize, BufferLength );
  877. DebugTrace( 0, Dbg, "Length = %ld\n", Length);
  878. if ( ByteOffset.HighPart == 0xFFFFFFFF &&
  879. ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE ) {
  880. ULONG FileLength;
  881. //
  882. // Ensure that you are at the head of the queue
  883. //
  884. NwAppendToQueueAndWait( IrpContext );
  885. //
  886. // Write relative to end of file. Find the end of file.
  887. //
  888. status = ExchangeWithWait(
  889. IrpContext,
  890. SynchronousResponseCallback,
  891. "F-r",
  892. NCP_GET_FILE_SIZE,
  893. &Icb->Handle, sizeof(Icb->Handle) );
  894. if ( NT_SUCCESS( status ) ) {
  895. status = ParseResponse(
  896. IrpContext,
  897. IrpContext->rsp,
  898. IrpContext->ResponseLength,
  899. "Nd",
  900. &FileLength );
  901. }
  902. if ( !NT_SUCCESS( status ) ) {
  903. return( status );
  904. }
  905. IrpContext->Specific.Write.FileOffset = FileLength;
  906. } else {
  907. IrpContext->Specific.Write.FileOffset = ByteOffset.LowPart;
  908. }
  909. //
  910. // Setup context parameters for burst write.
  911. //
  912. IrpContext->Specific.Write.LastWriteLength = Length;
  913. IrpContext->Destination = pNpScb->RemoteAddress;
  914. IrpContext->Specific.Write.Buffer = WriteBuffer;
  915. //
  916. // Set the timeout to be the time for all te burst packets to be sent plus a round
  917. // trip delay plus a second.
  918. //
  919. TimeInNwUnits = pNpScb->NwSingleBurstPacketTime * ((Length / IrpContext->pNpScb->MaxPacketSize) + 1) +
  920. IrpContext->pNpScb->NwLoopTime;
  921. IrpContext->pNpScb->SendTimeout =
  922. (SHORT)(((TimeInNwUnits / 555) *
  923. (ULONG)WriteTimeoutMultiplier) / 100 + 1) ;
  924. if (IrpContext->pNpScb->SendTimeout < 2)
  925. {
  926. IrpContext->pNpScb->SendTimeout = 2 ;
  927. }
  928. if (IrpContext->pNpScb->SendTimeout > (SHORT)MaxWriteTimeout)
  929. {
  930. IrpContext->pNpScb->SendTimeout = (SHORT)MaxWriteTimeout ;
  931. }
  932. IrpContext->pNpScb->TimeOut = IrpContext->pNpScb->SendTimeout;
  933. //
  934. // tommye - MS bug 2743 changed the RetryCount from 20 to be based off the
  935. // default retry count, nudged up a little.
  936. //
  937. pNpScb->RetryCount = DefaultRetryCount * 2;
  938. DebugTrace( 0, DEBUG_TRACE_LIP, "pNpScb->SendTimeout = %08lx\n", IrpContext->pNpScb->SendTimeout );
  939. Done = FALSE;
  940. do {
  941. DataMdl = ALLOCATE_MDL(
  942. (PCHAR)IrpContext->Specific.Write.Buffer +
  943. IrpContext->Specific.Write.WriteOffset,
  944. Length,
  945. FALSE, // Secondary Buffer
  946. FALSE, // Charge Quota
  947. NULL);
  948. if ( DataMdl == NULL ) {
  949. return ( STATUS_INSUFFICIENT_RESOURCES );
  950. }
  951. //
  952. // If there is no MDL for this write, probe the data MDL to lock it's
  953. // pages down.
  954. //
  955. // Otherwise, use the data MDL as a partial MDL and lock the pages
  956. // accordingly.
  957. //
  958. if ( WriteMdl == NULL ) {
  959. //
  960. // The Probe may cause us to page in some data. If the data is from
  961. // the same server we are writing to then we had better not be at
  962. // the front of the queue otherwise it will wait indefinitely behind us.
  963. // Its a good idea to Dequeue ourselves after each burst anyway because
  964. // its a quick operation and it alow smaller requests to overtake a very
  965. // large series of bursts.
  966. //
  967. NwDequeueIrpContext( IrpContext, FALSE );
  968. try {
  969. MmProbeAndLockPages( DataMdl, irp->RequestorMode, IoReadAccess);
  970. } except (EXCEPTION_EXECUTE_HANDLER) {
  971. FREE_MDL( DataMdl );
  972. return GetExceptionCode();
  973. }
  974. } else {
  975. IoBuildPartialMdl(
  976. WriteMdl,
  977. DataMdl,
  978. (PCHAR)IrpContext->Specific.Write.Buffer +
  979. IrpContext->Specific.Write.WriteOffset,
  980. Length );
  981. }
  982. pNpScb->BurstDataWritten += Length;
  983. if (( SendExtraNcp ) &&
  984. ( pNpScb->BurstDataWritten >= 0x0000ffff )) {
  985. ULONG Flags;
  986. //
  987. // VLM client sends an NCP when starting a burst mode request
  988. // if the last request was not a write. It also does this every
  989. // 0xfe00 bytes written
  990. //
  991. // When going to a queue we will use handle 2. This is what the vlm
  992. // client always seems to do.
  993. //
  994. Flags = IrpContext->Flags;
  995. //
  996. // Reset IrpContext parameters
  997. //
  998. IrpContext->TxMdl->Next = NULL;
  999. IrpContext->CompletionSendRoutine = NULL;
  1000. IrpContext->TimeoutRoutine = NULL;
  1001. IrpContext->Flags &= ~(IRP_FLAG_RETRY_SEND | IRP_FLAG_BURST_REQUEST | IRP_FLAG_BURST_PACKET |
  1002. IRP_FLAG_BURST_WRITE | IRP_FLAG_NOT_SYSTEM_PACKET );
  1003. IrpContext->pTdiStruct = NULL;
  1004. //
  1005. // Ensure that you are at the head of the queue
  1006. //
  1007. NwAppendToQueueAndWait( IrpContext );
  1008. ExchangeWithWait (
  1009. IrpContext,
  1010. SynchronousResponseCallback,
  1011. "Sb", // NCP Get Directory Path
  1012. NCP_DIR_FUNCTION, NCP_GET_DIRECTORY_PATH,
  1013. (Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_FCB)?
  1014. Icb->SuperType.Fcb->Vcb->Specific.Disk.Handle : 2 );
  1015. pNpScb->BurstDataWritten = Length;
  1016. IrpContext->Flags = Flags;
  1017. SetFlag( IrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  1018. }
  1019. IrpContext->TimeoutRoutine = BurstWriteTimeout;
  1020. IrpContext->CompletionSendRoutine = BurstWriteCompletionSend;
  1021. IrpContext->pTdiStruct = &IrpContext->pNpScb->Burst;
  1022. IrpContext->PacketType = NCP_BURST;
  1023. IrpContext->pEx = BurstWriteCallback;
  1024. IrpContext->Specific.Write.FullMdl = DataMdl;
  1025. MmGetSystemAddressForMdlSafe( DataMdl, NormalPagePriority );
  1026. //
  1027. // Allocate a partial Mdl for the worst possible case of alignment
  1028. //
  1029. IrpContext->Specific.Write.PartialMdl =
  1030. ALLOCATE_MDL( 0, IrpContext->pNpScb->MaxPacketSize + PAGE_SIZE - 1, FALSE, FALSE, NULL);
  1031. if ( IrpContext->Specific.Write.PartialMdl == NULL ) {
  1032. if ( WriteMdl == NULL ) {
  1033. MmUnlockPages( DataMdl );
  1034. }
  1035. FREE_MDL( DataMdl );
  1036. return STATUS_INSUFFICIENT_RESOURCES;
  1037. }
  1038. //
  1039. // Get to the front of the SCB queue, if we are not already there.
  1040. // Note that can't append this IrpContext to the SCB until after
  1041. // the probe and lock, since the probe and lock may cause a paging
  1042. // read on this SCB.
  1043. //
  1044. NwAppendToQueueAndWait( IrpContext );
  1045. status = SendWriteBurst(
  1046. IrpContext,
  1047. BURST_WRITE_HEADER_SIZE,
  1048. (USHORT)Length,
  1049. TRUE,
  1050. FALSE );
  1051. MissingData = TRUE;
  1052. while ( MissingData ) {
  1053. KeWaitForSingleObject( &IrpContext->Event, Executive, KernelMode, FALSE, NULL );
  1054. MmPrepareMdlForReuse( IrpContext->Specific.Write.PartialMdl );
  1055. if ( BooleanFlagOn( IrpContext->Flags, IRP_FLAG_RETRY_SEND ) ) {
  1056. //
  1057. // This burst has timed out, simply resend the burst.
  1058. //
  1059. NwProcessSendBurstFailure( pNpScb, 1 );
  1060. status = SendWriteBurst(
  1061. IrpContext,
  1062. BURST_WRITE_HEADER_SIZE,
  1063. (USHORT)Length,
  1064. TRUE,
  1065. TRUE );
  1066. continue;
  1067. }
  1068. if ( !NT_SUCCESS( IrpContext->Specific.Write.Status ) ) {
  1069. status = IrpContext->Specific.Write.Status;
  1070. Done = TRUE;
  1071. goto EndOfLoop;
  1072. } else {
  1073. status = ParseResponse(
  1074. IrpContext,
  1075. IrpContext->rsp,
  1076. IrpContext->ResponseLength,
  1077. "B_d",
  1078. &BurstFlags,
  1079. 8,
  1080. &Result );
  1081. }
  1082. if ( BurstFlags & BURST_FLAG_SYSTEM_PACKET ) {
  1083. //
  1084. // The server dropped at least one packet.
  1085. //
  1086. MissingData = TRUE;
  1087. DebugTrace( 0, Dbg, "Received system packet\n", 0 );
  1088. //
  1089. // This is a missing fragment request.
  1090. //
  1091. status = ParseResponse(
  1092. IrpContext,
  1093. IrpContext->rsp,
  1094. IrpContext->ResponseLength,
  1095. "G_w",
  1096. 34,
  1097. &MissingFragmentCount );
  1098. ASSERT( NT_SUCCESS( status ) );
  1099. ASSERT( MissingFragmentCount != 0 );
  1100. NwProcessSendBurstFailure( pNpScb, MissingFragmentCount );
  1101. DebugTrace( 0, Dbg, "Received request for %d missing fragment\n", MissingFragmentCount );
  1102. ClearFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1103. //
  1104. // Walk the missing fragment list and send the missing fragments.
  1105. //
  1106. for ( i = 0; i < MissingFragmentCount && NT_SUCCESS( status ); i++ ) {
  1107. status = ParseResponse(
  1108. IrpContext,
  1109. IrpContext->rsp,
  1110. IrpContext->ResponseLength,
  1111. "G_dw",
  1112. 34 + 2 + 6 * i,
  1113. &FragmentOffset,
  1114. &FragmentLength
  1115. );
  1116. ASSERT( NT_SUCCESS( status ) );
  1117. if ( FragmentOffset < Length + BURST_WRITE_HEADER_SIZE &&
  1118. FragmentOffset + FragmentLength <=
  1119. Length + BURST_WRITE_HEADER_SIZE ) {
  1120. //
  1121. // Send a burst with the missing data. Do no set the
  1122. // end of burst bit until we have sent the last
  1123. // missing fragment packet.
  1124. //
  1125. status = SendWriteBurst(
  1126. IrpContext,
  1127. FragmentOffset,
  1128. FragmentLength,
  1129. (BOOLEAN)( i == (MissingFragmentCount - 1)),
  1130. FALSE );
  1131. } else {
  1132. //
  1133. // Received a bogus missing fragment request.
  1134. // Ignore the remainder of the request.
  1135. //
  1136. status = STATUS_INVALID_NETWORK_RESPONSE;
  1137. Done = TRUE;
  1138. goto EndOfLoop;
  1139. }
  1140. }
  1141. Stats.PacketBurstWriteTimeouts++;
  1142. } else {
  1143. NwProcessSendBurstSuccess( pNpScb );
  1144. MissingData = FALSE;
  1145. //
  1146. // This is not a system packets, check the response.
  1147. //
  1148. if ( Result == 0 ) {
  1149. //
  1150. // If the last write worked then move the pointers appropriately
  1151. //
  1152. LastLength = IrpContext->Specific.Write.LastWriteLength;
  1153. IrpContext->Specific.Write.RemainingLength -= LastLength;
  1154. IrpContext->Specific.Write.WriteOffset += LastLength;
  1155. IrpContext->Specific.Write.FileOffset += LastLength;
  1156. //
  1157. // If this is a print job, remember that we actually wrote data
  1158. //
  1159. if ( IrpContext->Icb->IsPrintJob ) {
  1160. IrpContext->Icb->ActuallyPrinted = TRUE;
  1161. }
  1162. } else {
  1163. //
  1164. // Abandon this request
  1165. //
  1166. Done = TRUE;
  1167. }
  1168. //
  1169. // Do we need to send another burst to satisfy the write IRP?
  1170. //
  1171. if ( IrpContext->Specific.Write.RemainingLength != 0 ) {
  1172. //
  1173. // Write the next packet.
  1174. //
  1175. DebugTrace( 0, Dbg, "RemainingLength = %ld\n", IrpContext->Specific.Write.RemainingLength);
  1176. DebugTrace( 0, Dbg, "FileOffset = %ld\n", IrpContext->Specific.Write.FileOffset);
  1177. DebugTrace( 0, Dbg, "WriteOffset = %ld\n", IrpContext->Specific.Write.WriteOffset);
  1178. Length = MIN( (ULONG)IrpContext->pNpScb->MaxSendSize,
  1179. IrpContext->Specific.Write.RemainingLength );
  1180. IrpContext->Specific.Write.LastWriteLength = Length;
  1181. } else {
  1182. Done = TRUE;
  1183. }
  1184. } // else ( not a system packet )
  1185. } // while ( missing data )
  1186. //
  1187. // Update the burst request number now.
  1188. //
  1189. if ( status != STATUS_REMOTE_NOT_LISTENING ) {
  1190. IrpContext->pNpScb->BurstRequestNo++;
  1191. }
  1192. //
  1193. // If we need to reconnect, do it now.
  1194. //
  1195. if ( BooleanFlagOn( IrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT ) ) {
  1196. BurstWriteReconnect( IrpContext );
  1197. }
  1198. //
  1199. // Dequeue this Irp context in preparation for the next run
  1200. // through the loop.
  1201. //
  1202. EndOfLoop:
  1203. ASSERT( status != STATUS_PENDING );
  1204. FREE_MDL( IrpContext->Specific.Write.PartialMdl );
  1205. //
  1206. // Unlock locked pages, and free our MDL.
  1207. //
  1208. if ( WriteMdl == NULL ) {
  1209. MmUnlockPages( DataMdl );
  1210. }
  1211. FREE_MDL( DataMdl );
  1212. } while ( !Done );
  1213. DebugTrace(-1, Dbg, "BurstWrite -> %08lx\n", status );
  1214. return status;
  1215. }
  1216. #ifdef NWDBG
  1217. int DropWritePackets;
  1218. #endif
  1219. NTSTATUS
  1220. BurstWriteCompletionSend(
  1221. IN PDEVICE_OBJECT DeviceObject,
  1222. IN PIRP Irp,
  1223. IN PVOID Context
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. This routine handles completion of a burst write send. If the sending
  1228. thread is waiting for send completion notification, it signals the
  1229. IrpContext Event.
  1230. Note that this routine can be called from SendWriteBurst (i.e. not
  1231. at DPC level), if an allocation fails.
  1232. Arguments:
  1233. DeviceObject - unused.
  1234. Irp - Supplies Irp that the transport has finished processing.
  1235. Context - Supplies the IrpContext associated with the Irp.
  1236. Return Value:
  1237. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  1238. processing Irp stack locations at this point.
  1239. --*/
  1240. {
  1241. PIRP_CONTEXT pIrpContext = (PIRP_CONTEXT) Context;
  1242. INTERLOCKED_RESULT Result;
  1243. KIRQL OldIrql;
  1244. NTSTATUS Status;
  1245. //
  1246. // Avoid completing the Irp because the Mdl etc. do not contain
  1247. // their original values.
  1248. //
  1249. DebugTrace( +1, Dbg, "BurstWriteCompletionSend\n", 0);
  1250. DebugTrace( +0, Dbg, "Irp %X\n", Irp);
  1251. DebugTrace( +0, Dbg, "pIrpC %X\n", pIrpContext);
  1252. if ( Irp != NULL ) {
  1253. DebugTrace( 0, Dbg, "Burst Write Send = %08lx\n", Irp->IoStatus.Status );
  1254. Status = Irp->IoStatus.Status;
  1255. } else {
  1256. Status = STATUS_SUCCESS;
  1257. }
  1258. //
  1259. // If this was a secondary IRP, free it now.
  1260. //
  1261. if ( pIrpContext->NodeTypeCode == NW_NTC_MINI_IRP_CONTEXT ) {
  1262. PMINI_IRP_CONTEXT MiniIrpContext;
  1263. MiniIrpContext = (PMINI_IRP_CONTEXT)pIrpContext;
  1264. ASSERT( MiniIrpContext->Mdl2->Next == NULL );
  1265. pIrpContext = MiniIrpContext->IrpContext;
  1266. FreeMiniIrpContext( MiniIrpContext );
  1267. }
  1268. //
  1269. // Nothing to do unless the last send has completed.
  1270. //
  1271. Result = InterlockedDecrement(
  1272. &pIrpContext->Specific.Write.PacketCount );
  1273. if ( Result ) {
  1274. DebugTrace( 0, Dbg, "Packets to go = %d\n", pIrpContext->Specific.Write.PacketCount );
  1275. if (Status == STATUS_BAD_NETWORK_PATH) {
  1276. //
  1277. // IPX has ripped for the destination but failed to find the net. Minimise the
  1278. // difference between this case and sending a normal burst by completing the
  1279. // transmission as soon as possible.
  1280. //
  1281. pIrpContext->pNpScb->NwSendDelay = 0;
  1282. }
  1283. return STATUS_MORE_PROCESSING_REQUIRED;
  1284. }
  1285. KeAcquireSpinLock( &pIrpContext->pNpScb->NpScbSpinLock, &OldIrql );
  1286. ASSERT( pIrpContext->pNpScb->Sending == TRUE );
  1287. pIrpContext->pNpScb->Sending = FALSE;
  1288. //
  1289. // Signal to the writing thread that the send has completed, if it
  1290. // is waiting.
  1291. //
  1292. if ( BooleanFlagOn( pIrpContext->Flags, IRP_FLAG_SIGNAL_EVENT ) ) {
  1293. ClearFlag( pIrpContext->Flags, IRP_FLAG_SIGNAL_EVENT );
  1294. NwSetIrpContextEvent( pIrpContext );
  1295. }
  1296. //
  1297. // If we processed a receive while waiting for send
  1298. // completion call the receive handler routine now.
  1299. //
  1300. if ( pIrpContext->pNpScb->Received ) {
  1301. pIrpContext->pNpScb->Receiving = FALSE;
  1302. pIrpContext->pNpScb->Received = FALSE;
  1303. KeReleaseSpinLock( &pIrpContext->pNpScb->NpScbSpinLock, OldIrql );
  1304. pIrpContext->pEx(
  1305. pIrpContext,
  1306. pIrpContext->ResponseLength,
  1307. pIrpContext->rsp );
  1308. } else {
  1309. if ((Status == STATUS_BAD_NETWORK_PATH) &&
  1310. (pIrpContext->pNpScb->Receiving == FALSE)) {
  1311. //
  1312. // Usually means a ras connection has gone down during the burst.
  1313. // Go through the timeout logic now because the ras timeouts take
  1314. // a long time and unless we re rip things won't get better.
  1315. //
  1316. pIrpContext->Specific.Write.Status = STATUS_REMOTE_NOT_LISTENING;
  1317. ClearFlag( pIrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1318. NwSetIrpContextEvent( pIrpContext );
  1319. }
  1320. KeReleaseSpinLock( &pIrpContext->pNpScb->NpScbSpinLock, OldIrql );
  1321. }
  1322. DebugTrace( -1, Dbg, "BurstWriteCompletionSend -> STATUS_MORE_PROCESSING_REQUIRED\n", 0);
  1323. return STATUS_MORE_PROCESSING_REQUIRED;
  1324. UNREFERENCED_PARAMETER( DeviceObject );
  1325. }
  1326. NTSTATUS
  1327. BurstWriteCallback (
  1328. IN PIRP_CONTEXT IrpContext,
  1329. IN ULONG BytesAvailable,
  1330. IN PUCHAR Response
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. This routine receives the response a burst write.
  1335. Arguments:
  1336. IrpContext - A pointer to the context information for this IRP.
  1337. BytesAvailable - Actual number of bytes in the received message.
  1338. Response - Points to the receive buffer.
  1339. Return Value:
  1340. VOID
  1341. --*/
  1342. {
  1343. NTSTATUS Status = STATUS_SUCCESS;
  1344. DebugTrace(0, Dbg, "BurstWriteCallback...\n", 0);
  1345. if ( BytesAvailable == 0) {
  1346. //
  1347. // No response from server. Status is in pIrpContext->Write.Status
  1348. // Clear the retry send bit so we don't keep retrying.
  1349. //
  1350. IrpContext->Specific.Write.Status = STATUS_REMOTE_NOT_LISTENING;
  1351. ClearFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1352. NwSetIrpContextEvent( IrpContext );
  1353. DebugTrace(-1, Dbg, "BurstWriteCallback -> %X\n", STATUS_REMOTE_NOT_LISTENING );
  1354. return STATUS_REMOTE_NOT_LISTENING;
  1355. }
  1356. IrpContext->Specific.Write.Status = STATUS_SUCCESS;
  1357. ASSERT( BytesAvailable < MAX_RECV_DATA );
  1358. ++Stats.PacketBurstWriteNcps;
  1359. //
  1360. // Clear the retry send bit, since we have a response.
  1361. //
  1362. ClearFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1363. //
  1364. // Copy the burst write response, and signal the users thread
  1365. // to continue.
  1366. //
  1367. TdiCopyLookaheadData(
  1368. IrpContext->rsp,
  1369. Response,
  1370. BytesAvailable < MAX_RECV_DATA ? BytesAvailable : MAX_RECV_DATA,
  1371. 0
  1372. );
  1373. IrpContext->ResponseLength = BytesAvailable;
  1374. NwSetIrpContextEvent( IrpContext );
  1375. return STATUS_SUCCESS;
  1376. }
  1377. NTSTATUS
  1378. SendWriteBurst(
  1379. PIRP_CONTEXT IrpContext,
  1380. ULONG BurstOffset,
  1381. USHORT Length,
  1382. BOOLEAN EndOfBurst,
  1383. BOOLEAN Retransmission
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. This routine does the actual work of sending a series of burst write
  1388. NCPs to the server.
  1389. Arguments:
  1390. IrpContext - A pointer to IRP context information for this request.
  1391. BurstOffset - The offset in the burst to start sending. If BurstOffset
  1392. equals BURST_WRITE_HEADER_SIZE, start from the beginning of the burst.
  1393. Length - The length of the burst.
  1394. EndOfBurst - If TRUE set the end of burst bit when sending the last
  1395. frame. Otherwise there is more (discontiguous) data to come in
  1396. the current burst.
  1397. Retransmission - If TRUE, this is a burst write timeout retransmission.
  1398. Send the first packet only.
  1399. Return Value:
  1400. Status of transfer.
  1401. --*/
  1402. {
  1403. UCHAR BurstFlags;
  1404. NTSTATUS Status;
  1405. BOOLEAN MoreData;
  1406. PIRP SendIrp;
  1407. PMINI_IRP_CONTEXT MiniIrpContext;
  1408. PAGED_CODE();
  1409. DebugTrace( +1, Dbg, "SendWriteBurst...\n", 0);
  1410. DebugTrace( 0, Dbg, "Data offset = %d\n", BurstOffset );
  1411. DebugTrace( 0, Dbg, "Data length = %d\n", Length );
  1412. DebugTrace( 0, Dbg, "End of burst = %d\n", EndOfBurst );
  1413. //
  1414. // Send the request.
  1415. //
  1416. SetFlag( IrpContext->Flags, IRP_FLAG_BURST_REQUEST | IRP_FLAG_BURST_PACKET );
  1417. //
  1418. // Set the burst flags
  1419. //
  1420. IrpContext->Specific.Write.BurstLength =
  1421. MIN( IrpContext->pNpScb->MaxPacketSize, Length );
  1422. //
  1423. // Set the end-of-burst bit (and enable receiving the response), if this
  1424. // is the last packet we expect to send.
  1425. //
  1426. if ( ( !EndOfBurst || IrpContext->Specific.Write.BurstLength < Length )
  1427. && !Retransmission ) {
  1428. IrpContext->pNpScb->OkToReceive = FALSE;
  1429. SetFlag( IrpContext->Flags, IRP_FLAG_NOT_OK_TO_RECEIVE );
  1430. BurstFlags = 0;
  1431. } else {
  1432. DebugTrace( 0, Dbg, "Last packet in the burst\n", 0);
  1433. ClearFlag( IrpContext->Flags, IRP_FLAG_NOT_OK_TO_RECEIVE );
  1434. BurstFlags = BURST_FLAG_END_OF_BURST;
  1435. }
  1436. if ( !EndOfBurst ) {
  1437. SetFlag( IrpContext->Flags, IRP_FLAG_SIGNAL_EVENT );
  1438. }
  1439. //
  1440. // Build the partial MDL for the first packet in the burst.
  1441. //
  1442. IoBuildPartialMdl(
  1443. IrpContext->Specific.Write.FullMdl,
  1444. IrpContext->Specific.Write.PartialMdl,
  1445. (PUCHAR)MmGetMdlVirtualAddress( IrpContext->Specific.Write.FullMdl ) +
  1446. BurstOffset - BURST_WRITE_HEADER_SIZE,
  1447. IrpContext->Specific.Write.BurstLength );
  1448. //
  1449. // Set the burst flags
  1450. //
  1451. if ( BurstOffset == BURST_WRITE_HEADER_SIZE ) {
  1452. SetFlag( IrpContext->Flags, IRP_FLAG_BURST_REQUEST | IRP_FLAG_BURST_PACKET );
  1453. }
  1454. if ( ( IrpContext->Specific.Write.BurstLength < Length ) &&
  1455. !Retransmission ) {
  1456. MoreData = TRUE;
  1457. } else {
  1458. MoreData = FALSE;
  1459. }
  1460. if ( BurstOffset == BURST_WRITE_HEADER_SIZE ) {
  1461. BuildBurstWriteFirstReq(
  1462. IrpContext,
  1463. IrpContext->req,
  1464. Length,
  1465. IrpContext->Specific.Write.PartialMdl,
  1466. BurstFlags,
  1467. *(ULONG UNALIGNED *)(&IrpContext->Icb->Handle[2]),
  1468. IrpContext->Specific.Write.FileOffset );
  1469. } else {
  1470. BuildBurstWriteNextReq(
  1471. IrpContext,
  1472. IrpContext->req,
  1473. IrpContext->Specific.Write.LastWriteLength + BURST_WRITE_HEADER_SIZE,
  1474. BurstFlags,
  1475. BurstOffset,
  1476. IrpContext->TxMdl,
  1477. IrpContext->Specific.Write.PartialMdl
  1478. );
  1479. }
  1480. if ( !Retransmission ) {
  1481. IrpContext->Specific.Write.PacketCount =
  1482. ( Length + IrpContext->pNpScb->MaxPacketSize - 1 ) /
  1483. IrpContext->pNpScb->MaxPacketSize;
  1484. } else {
  1485. IrpContext->Specific.Write.PacketCount = 1;
  1486. }
  1487. DebugTrace( 0, Dbg, "Packet count = %d\n", IrpContext->Specific.Write.PacketCount );
  1488. DebugTrace( 0, DEBUG_TRACE_LIP, "Send delay = %d\n", IrpContext->pNpScb->NwSendDelay );
  1489. //
  1490. // Use the original IRP context to format the first packet.
  1491. //
  1492. ++Stats.PacketBurstWriteNcps;
  1493. PreparePacket( IrpContext, IrpContext->pOriginalIrp, IrpContext->TxMdl );
  1494. Status = SendPacket( IrpContext, IrpContext->pNpScb );
  1495. while ( MoreData ) {
  1496. if ( IrpContext->pNpScb->NwSendDelay > 0 ) {
  1497. //
  1498. // Introduce a send delay between packets.
  1499. //
  1500. KeDelayExecutionThread(
  1501. KernelMode,
  1502. FALSE,
  1503. &IrpContext->pNpScb->NtSendDelay );
  1504. }
  1505. MiniIrpContext = AllocateMiniIrpContext( IrpContext );
  1506. DebugTrace( 0, Dbg, "Allocated mini IrpContext = %X\n", MiniIrpContext );
  1507. //
  1508. // Calculate the total number of bytes to send during this burst. Do this before
  1509. // checking to see if MiniIrpContext is NULL so that we skip the packet rather
  1510. // than sitting in a tight loop.
  1511. //
  1512. BurstOffset += IrpContext->Specific.Write.BurstLength;
  1513. //
  1514. // Do we need to send another burst write packet?
  1515. //
  1516. Length -= (USHORT)IrpContext->Specific.Write.BurstLength;
  1517. ASSERT ( Length > 0 );
  1518. IrpContext->Specific.Write.BurstLength =
  1519. MIN( IrpContext->pNpScb->MaxPacketSize, (ULONG)Length );
  1520. DebugTrace( +0, Dbg, "More data, sending %d bytes\n", IrpContext->Specific.Write.BurstLength );
  1521. //
  1522. // If we can't allocate a mini irp context to send the packet,
  1523. // just skip it and wait for the server to ask a retranmit. At
  1524. // this point performance isn't exactly stellar, so don't worry
  1525. // about having to wait for a timeout.
  1526. //
  1527. if ( MiniIrpContext == NULL ) {
  1528. InterlockedDecrement(
  1529. &IrpContext->Specific.Write.PacketCount );
  1530. if ( Length == IrpContext->Specific.Write.BurstLength ) {
  1531. MoreData = FALSE;
  1532. break;
  1533. }
  1534. continue;
  1535. }
  1536. #ifdef NWDBG
  1537. //
  1538. // If DropWritePackets is enabled, simulate missing packets, by
  1539. // occasionally dropping 500 bytes of data.
  1540. //
  1541. if ( DropWritePackets != 0 ) {
  1542. if ( ( rand() % DropWritePackets ) == 0 &&
  1543. Length != IrpContext->Specific.Write.BurstLength ) {
  1544. FreeMiniIrpContext( MiniIrpContext );
  1545. InterlockedDecrement(
  1546. &IrpContext->Specific.Write.PacketCount );
  1547. continue;
  1548. }
  1549. }
  1550. #endif
  1551. //
  1552. // Build the MDL for the data to send.
  1553. //
  1554. IoBuildPartialMdl(
  1555. IrpContext->Specific.Write.FullMdl,
  1556. MiniIrpContext->Mdl2,
  1557. (PUCHAR)MmGetMdlVirtualAddress( IrpContext->Specific.Write.FullMdl ) +
  1558. BurstOffset - BURST_WRITE_HEADER_SIZE,
  1559. IrpContext->Specific.Write.BurstLength );
  1560. //
  1561. // Set the burst flags
  1562. //
  1563. if ( !EndOfBurst || IrpContext->Specific.Write.BurstLength < Length ) {
  1564. IrpContext->pNpScb->OkToReceive = FALSE;
  1565. SetFlag( IrpContext->Flags, IRP_FLAG_NOT_OK_TO_RECEIVE );
  1566. BurstFlags = 0;
  1567. } else {
  1568. DebugTrace( 0, Dbg, "Last packet in the burst\n", 0);
  1569. ClearFlag( IrpContext->Flags, IRP_FLAG_NOT_OK_TO_RECEIVE );
  1570. BurstFlags = BURST_FLAG_END_OF_BURST;
  1571. }
  1572. if ( IrpContext->Specific.Write.BurstLength == Length ) {
  1573. MoreData = FALSE;
  1574. }
  1575. BuildBurstWriteNextReq(
  1576. IrpContext,
  1577. MiniIrpContext->Mdl1->MappedSystemVa,
  1578. IrpContext->Specific.Write.LastWriteLength +
  1579. BURST_WRITE_HEADER_SIZE,
  1580. BurstFlags,
  1581. BurstOffset,
  1582. MiniIrpContext->Mdl1,
  1583. MiniIrpContext->Mdl2
  1584. );
  1585. ++Stats.PacketBurstWriteNcps;
  1586. SendIrp = MiniIrpContext->Irp;
  1587. PreparePacket( IrpContext, SendIrp, MiniIrpContext->Mdl1 );
  1588. IoSetCompletionRoutine( SendIrp, BurstWriteCompletionSend, MiniIrpContext, TRUE, TRUE, TRUE);
  1589. ASSERT( MiniIrpContext->Mdl2->Next == NULL );
  1590. Status = SendSecondaryPacket( IrpContext, SendIrp );
  1591. }
  1592. //
  1593. // If this is not the end-of-burst, wait for send completion here,
  1594. // since the caller is about to send more data.
  1595. //
  1596. if ( !EndOfBurst ) {
  1597. KeWaitForSingleObject( &IrpContext->Event, Executive, KernelMode, FALSE, NULL );
  1598. }
  1599. DebugTrace( -1, Dbg, "SendWriteBurst -> %X\n", Status );
  1600. return( Status );
  1601. }
  1602. VOID
  1603. BurstWriteTimeout(
  1604. PIRP_CONTEXT IrpContext
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. This routine handles a burst write timeout.
  1609. Arguments:
  1610. IrpContext - A pointer to IRP context information for this request.
  1611. Return Value:
  1612. None
  1613. --*/
  1614. {
  1615. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1616. PIRP Irp;
  1617. DebugTrace(0, Dbg, "BurstWriteTimeout\n", 0 );
  1618. Irp = IrpContext->pOriginalIrp;
  1619. //
  1620. // Set the RetrySend flag, so that we know to retransmit the request.
  1621. //
  1622. SetFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1623. //
  1624. // Signal the write thread to wakeup and resend the burst.
  1625. //
  1626. NwSetIrpContextEvent( IrpContext );
  1627. Stats.PacketBurstWriteTimeouts++;
  1628. return;
  1629. }
  1630. NTSTATUS
  1631. ResubmitBurstWrite(
  1632. PIRP_CONTEXT IrpContext
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. This routine resubmits a burst write over a new burst connection.
  1637. Arguments:
  1638. IrpContext - A pointer to IRP context information for this request.
  1639. Return Value:
  1640. None
  1641. --*/
  1642. {
  1643. PNONPAGED_SCB pNpScb = IrpContext->pNpScb;
  1644. PAGED_CODE();
  1645. //
  1646. // Remember that we need to establish a new burst connection.
  1647. //
  1648. SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT );
  1649. //
  1650. // Set the packet size down the largest packet we can use, that
  1651. // is guaranteed to be routable.
  1652. //
  1653. pNpScb->MaxPacketSize = DEFAULT_PACKET_SIZE;
  1654. //
  1655. // Crank the delay times down so we give the new connection a chance.
  1656. //
  1657. pNpScb->NwGoodSendDelay = pNpScb->NwBadSendDelay = pNpScb->NwSendDelay = MinSendDelay;
  1658. pNpScb->NwGoodReceiveDelay = pNpScb->NwBadReceiveDelay = pNpScb->NwReceiveDelay = MinReceiveDelay;
  1659. pNpScb->SendBurstSuccessCount = 0;
  1660. pNpScb->ReceiveBurstSuccessCount = 0;
  1661. pNpScb->NtSendDelay.QuadPart = MinSendDelay;
  1662. //
  1663. // Signal the write thread to wakeup and resend the burst.
  1664. //
  1665. NwSetIrpContextEvent( IrpContext );
  1666. return( STATUS_PENDING );
  1667. }
  1668. NTSTATUS
  1669. BurstWriteReconnect(
  1670. PIRP_CONTEXT IrpContext
  1671. )
  1672. /*++
  1673. Routine Description:
  1674. This routine allocates a new IRP context and renegotiates burst mode.
  1675. Arguments:
  1676. IrpContext - A pointer to IRP context information for this request.
  1677. Return Value:
  1678. None
  1679. --*/
  1680. {
  1681. PIRP_CONTEXT pNewIrpContext;
  1682. PNONPAGED_SCB pNpScb = IrpContext->pNpScb;
  1683. BOOLEAN LIPNegotiated ;
  1684. PAGED_CODE();
  1685. //
  1686. // Attempt to allocate an extra IRP context.
  1687. //
  1688. if ( !NwAllocateExtraIrpContext( &pNewIrpContext, pNpScb ) ) {
  1689. return STATUS_INSUFFICIENT_RESOURCES;
  1690. }
  1691. pNewIrpContext->Specific.Create.UserUid = IrpContext->Specific.Create.UserUid;
  1692. SetFlag( pNewIrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT );
  1693. pNewIrpContext->pNpScb = pNpScb;
  1694. //
  1695. // Insert this new IrpContext to the head of
  1696. // the SCB queue for processing. We can get away with this
  1697. // because we own the IRP context currently at the front of
  1698. // the queue.
  1699. //
  1700. ExInterlockedInsertHeadList(
  1701. &pNpScb->Requests,
  1702. &pNewIrpContext->NextRequest,
  1703. &pNpScb->NpScbSpinLock );
  1704. SetFlag( pNewIrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  1705. //
  1706. // Renegotiate the burst connection, this will automatically re-sync
  1707. // the burst connection.
  1708. //
  1709. NegotiateBurstMode( pNewIrpContext, pNpScb, &LIPNegotiated );
  1710. //
  1711. // Reset the sequence numbers.
  1712. //
  1713. pNpScb->BurstSequenceNo = 0;
  1714. pNpScb->BurstRequestNo = 0;
  1715. //
  1716. // Dequeue and free the bonus IRP context.
  1717. //
  1718. ExInterlockedRemoveHeadList(
  1719. &pNpScb->Requests,
  1720. &pNpScb->NpScbSpinLock );
  1721. ClearFlag( pNewIrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  1722. NwFreeExtraIrpContext( pNewIrpContext );
  1723. ClearFlag( IrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT );
  1724. return( STATUS_SUCCESS );
  1725. }
  1726. NTSTATUS
  1727. NwFsdFlushBuffers(
  1728. IN PDEVICE_OBJECT DeviceObject,
  1729. IN PIRP Irp
  1730. )
  1731. /*++
  1732. Routine Description:
  1733. This routine is the FSD routine that handles NtFlushBuffersFile.
  1734. Arguments:
  1735. DeviceObject - Supplies the device object for the write function.
  1736. Irp - Supplies the IRP to process.
  1737. Return Value:
  1738. NTSTATUS - The result status.
  1739. --*/
  1740. {
  1741. PIRP_CONTEXT pIrpContext = NULL;
  1742. NTSTATUS status;
  1743. BOOLEAN TopLevel;
  1744. PAGED_CODE();
  1745. DebugTrace(+1, Dbg, "NwFsdFlushBuffers\n", 0);
  1746. //
  1747. // Call the common write routine.
  1748. //
  1749. FsRtlEnterFileSystem();
  1750. TopLevel = NwIsIrpTopLevel( Irp );
  1751. try {
  1752. pIrpContext = AllocateIrpContext( Irp );
  1753. status = NwCommonFlushBuffers( pIrpContext );
  1754. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  1755. if ( pIrpContext == NULL ) {
  1756. //
  1757. // If we couldn't allocate an irp context, just complete
  1758. // irp without any fanfare.
  1759. //
  1760. status = STATUS_INSUFFICIENT_RESOURCES;
  1761. Irp->IoStatus.Status = status;
  1762. Irp->IoStatus.Information = 0;
  1763. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  1764. } else {
  1765. //
  1766. // We had some trouble trying to perform the requested
  1767. // operation, so we'll abort the I/O request with
  1768. // the error Status that we get back from the
  1769. // execption code
  1770. //
  1771. status = NwProcessException( pIrpContext, GetExceptionCode() );
  1772. }
  1773. }
  1774. if ( pIrpContext ) {
  1775. NwCompleteRequest( pIrpContext, status );
  1776. }
  1777. if ( TopLevel ) {
  1778. NwSetTopLevelIrp( NULL );
  1779. }
  1780. FsRtlExitFileSystem();
  1781. //
  1782. // Return to the caller.
  1783. //
  1784. DebugTrace(-1, Dbg, "NwFsdFlushBuffers -> %08lx\n", status );
  1785. return status;
  1786. }
  1787. NTSTATUS
  1788. NwCommonFlushBuffers (
  1789. IN PIRP_CONTEXT IrpContext
  1790. )
  1791. /*++
  1792. Routine Description:
  1793. This routine requests all dirty cache buffers to be flushed for a
  1794. given file.
  1795. Arguments:
  1796. IrpContext - Supplies the request being processed.
  1797. Return Value:
  1798. The status of the operation.
  1799. --*/
  1800. {
  1801. PIRP Irp;
  1802. PIO_STACK_LOCATION IrpSp;
  1803. NTSTATUS Status;
  1804. PFCB Fcb;
  1805. PICB Icb;
  1806. NODE_TYPE_CODE NodeTypeCode;
  1807. PVOID FsContext;
  1808. PAGED_CODE();
  1809. DebugTrace(0, Dbg, "NwCommonFlushBuffers...\n", 0);
  1810. //
  1811. // Get the current stack location
  1812. //
  1813. Irp = IrpContext->pOriginalIrp;
  1814. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1815. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG_PTR)Irp);
  1816. //
  1817. // Decode the file object to figure out who we are. If the result
  1818. // is not the a file then its an illegal parameter.
  1819. //
  1820. if (( NodeTypeCode = NwDecodeFileObject( IrpSp->FileObject,
  1821. &FsContext,
  1822. (PVOID *)&Icb )) != NW_NTC_ICB) {
  1823. DebugTrace(0, Dbg, "Not a file\n", 0);
  1824. Status = STATUS_INVALID_PARAMETER;
  1825. DebugTrace(-1, Dbg, "NwCommonFlushBuffers -> %08lx\n", Status );
  1826. return Status;
  1827. }
  1828. //
  1829. // Make sure that this ICB is still active.
  1830. //
  1831. NwVerifyIcbSpecial( Icb );
  1832. Fcb = (PFCB)Icb->SuperType.Fcb;
  1833. NodeTypeCode = Fcb->NodeTypeCode;
  1834. if ( NodeTypeCode != NW_NTC_FCB ) {
  1835. DebugTrace(0, Dbg, "Not a file\n", 0);
  1836. Status = STATUS_INVALID_PARAMETER;
  1837. DebugTrace(-1, Dbg, "CommonFlushBuffers -> %08lx\n", Status );
  1838. return Status;
  1839. }
  1840. //
  1841. // Set up the IRP context to do an exchange
  1842. //
  1843. IrpContext->pScb = Fcb->Scb;
  1844. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  1845. IrpContext->Icb = Icb;
  1846. //
  1847. // Send any user data to the server. Note we must not be on the
  1848. // queue when we do this.
  1849. //
  1850. MmFlushImageSection(&Icb->NpFcb->SegmentObject, MmFlushForWrite);
  1851. //
  1852. // Flush our dirty data.
  1853. //
  1854. Status = AcquireFcbAndFlushCache( IrpContext, Fcb->NonPagedFcb );
  1855. if ( !NT_SUCCESS( Status )) {
  1856. return( Status );
  1857. }
  1858. //
  1859. // Send a flush NCP
  1860. //
  1861. Status = Exchange (
  1862. IrpContext,
  1863. FlushBuffersCallback,
  1864. "F-r",
  1865. NCP_FLUSH_FILE,
  1866. &Icb->Handle, sizeof( Icb->Handle ) );
  1867. return( Status );
  1868. }
  1869. NTSTATUS
  1870. FlushBuffersCallback (
  1871. IN PIRP_CONTEXT IrpContext,
  1872. IN ULONG BytesAvailable,
  1873. IN PUCHAR Response
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This routine receives the flush file size response and completes the
  1878. flush IRP.
  1879. Arguments:
  1880. Return Value:
  1881. VOID
  1882. --*/
  1883. {
  1884. NTSTATUS Status;
  1885. DebugTrace(0, Dbg, "FlushBuffersCallback...\n", 0);
  1886. if ( BytesAvailable == 0) {
  1887. //
  1888. // We're done with this request. Dequeue the IRP context from
  1889. // SCB and complete the request.
  1890. //
  1891. NwDequeueIrpContext( IrpContext, FALSE );
  1892. NwCompleteRequest( IrpContext, STATUS_REMOTE_NOT_LISTENING );
  1893. //
  1894. // No response from server. Status is in pIrpContext->
  1895. // ResponseParameters.Error
  1896. //
  1897. DebugTrace( 0, Dbg, "Timeout\n", 0);
  1898. return STATUS_REMOTE_NOT_LISTENING;
  1899. }
  1900. //
  1901. // Get the data from the response.
  1902. //
  1903. Status = ParseResponse(
  1904. IrpContext,
  1905. Response,
  1906. BytesAvailable,
  1907. "N" );
  1908. //
  1909. // We're done with this request. Dequeue the IRP context from
  1910. // SCB and complete the request.
  1911. //
  1912. NwDequeueIrpContext( IrpContext, FALSE );
  1913. NwCompleteRequest( IrpContext, Status );
  1914. return Status;
  1915. }
  1916. VOID
  1917. BuildBurstWriteFirstReq(
  1918. PIRP_CONTEXT IrpContext,
  1919. PVOID Buffer,
  1920. ULONG DataSize,
  1921. PMDL BurstMdl,
  1922. UCHAR Flags,
  1923. ULONG Handle,
  1924. ULONG FileOffset
  1925. )
  1926. {
  1927. PNCP_BURST_WRITE_REQUEST BurstWrite;
  1928. PNONPAGED_SCB pNpScb;
  1929. ULONG RealDataLength;
  1930. USHORT RealBurstLength;
  1931. PAGED_CODE();
  1932. BurstWrite = (PNCP_BURST_WRITE_REQUEST)Buffer;
  1933. pNpScb = IrpContext->pNpScb;
  1934. RealDataLength = DataSize + sizeof( *BurstWrite ) - sizeof( NCP_BURST_HEADER );
  1935. RealBurstLength = (USHORT)MdlLength( BurstMdl ) + sizeof( *BurstWrite ) - sizeof( NCP_BURST_HEADER );
  1936. BurstWrite->BurstHeader.Command = PEP_COMMAND_BURST;
  1937. BurstWrite->BurstHeader.Flags = Flags;
  1938. BurstWrite->BurstHeader.StreamType = 0x02;
  1939. BurstWrite->BurstHeader.SourceConnection = pNpScb->SourceConnectionId;
  1940. BurstWrite->BurstHeader.DestinationConnection = pNpScb->DestinationConnectionId;
  1941. if ( !BooleanFlagOn( IrpContext->Flags, IRP_FLAG_RETRY_SEND ) ) {
  1942. //
  1943. // Use the same delay on all retransmissions of the burst. Save
  1944. // the current time.
  1945. //
  1946. pNpScb->CurrentBurstDelay = pNpScb->NwSendDelay;
  1947. //
  1948. // Send system packet next retransmission.
  1949. //
  1950. ClearFlag( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET );
  1951. } else {
  1952. //
  1953. // This is a retransmission. Alternate between sending a system
  1954. // packet and the first write.
  1955. //
  1956. if ( !BooleanFlagOn( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET ) ) {
  1957. SetFlag( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET );
  1958. BurstWrite->BurstHeader.Flags = BURST_FLAG_SYSTEM_PACKET;
  1959. LongByteSwap( BurstWrite->BurstHeader.SendDelayTime, pNpScb->CurrentBurstDelay );
  1960. BurstWrite->BurstHeader.DataSize = 0;
  1961. BurstWrite->BurstHeader.BurstOffset = 0;
  1962. BurstWrite->BurstHeader.BurstLength = 0;
  1963. BurstWrite->BurstHeader.MissingFragmentCount = 0;
  1964. IrpContext->TxMdl->ByteCount = sizeof( NCP_BURST_HEADER );
  1965. IrpContext->TxMdl->Next = NULL;
  1966. return;
  1967. }
  1968. //
  1969. // Send system packet next retransmission.
  1970. //
  1971. ClearFlag( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET );
  1972. }
  1973. LongByteSwap( BurstWrite->BurstHeader.SendDelayTime, pNpScb->CurrentBurstDelay );
  1974. LongByteSwap( BurstWrite->BurstHeader.DataSize, RealDataLength );
  1975. BurstWrite->BurstHeader.BurstOffset = 0;
  1976. ShortByteSwap( BurstWrite->BurstHeader.BurstLength, RealBurstLength );
  1977. BurstWrite->BurstHeader.MissingFragmentCount = 0;
  1978. BurstWrite->Function = BURST_REQUEST_WRITE;
  1979. BurstWrite->Handle = Handle;
  1980. LongByteSwap( BurstWrite->TotalWriteOffset, IrpContext->Specific.Write.TotalWriteOffset );
  1981. LongByteSwap( BurstWrite->TotalWriteLength, IrpContext->Specific.Write.TotalWriteLength );
  1982. LongByteSwap( BurstWrite->Offset, FileOffset );
  1983. LongByteSwap( BurstWrite->Length, DataSize );
  1984. IrpContext->TxMdl->ByteCount = sizeof( *BurstWrite );
  1985. IrpContext->TxMdl->Next = BurstMdl;
  1986. return;
  1987. }
  1988. VOID
  1989. BuildBurstWriteNextReq(
  1990. PIRP_CONTEXT IrpContext,
  1991. PVOID Buffer,
  1992. ULONG DataSize,
  1993. UCHAR BurstFlags,
  1994. ULONG BurstOffset,
  1995. PMDL BurstHeaderMdl,
  1996. PMDL BurstDataMdl
  1997. )
  1998. {
  1999. PNCP_BURST_HEADER BurstHeader;
  2000. PNONPAGED_SCB pNpScb;
  2001. USHORT BurstLength;
  2002. PAGED_CODE();
  2003. BurstHeader = (PNCP_BURST_HEADER)Buffer;
  2004. pNpScb = IrpContext->pNpScb;
  2005. BurstLength = (USHORT)MdlLength( BurstDataMdl );
  2006. BurstHeader->Command = PEP_COMMAND_BURST;
  2007. BurstHeader->Flags = BurstFlags;
  2008. BurstHeader->StreamType = 0x02;
  2009. BurstHeader->SourceConnection = pNpScb->SourceConnectionId;
  2010. BurstHeader->DestinationConnection = pNpScb->DestinationConnectionId;
  2011. LongByteSwap( BurstHeader->SendDelayTime, pNpScb->CurrentBurstDelay );
  2012. if ( BooleanFlagOn( IrpContext->Flags, IRP_FLAG_RETRY_SEND ) ) {
  2013. //
  2014. // This is a retransmission. Alternate between sending a system
  2015. // packet and the first write.
  2016. //
  2017. if ( !BooleanFlagOn( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET ) ) {
  2018. SetFlag( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET );
  2019. BurstHeader->Flags = BURST_FLAG_SYSTEM_PACKET;
  2020. LongByteSwap( BurstHeader->SendDelayTime, pNpScb->CurrentBurstDelay );
  2021. BurstHeader->DataSize = 0;
  2022. BurstHeader->BurstOffset = 0;
  2023. BurstHeader->BurstLength = 0;
  2024. BurstHeader->MissingFragmentCount = 0;
  2025. IrpContext->TxMdl->ByteCount = sizeof( NCP_BURST_HEADER );
  2026. IrpContext->TxMdl->Next = NULL;
  2027. return;
  2028. }
  2029. //
  2030. // Send system packet next retransmission.
  2031. //
  2032. ClearFlag( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET );
  2033. } else {
  2034. //
  2035. // Send system packet next retransmission.
  2036. //
  2037. ClearFlag( IrpContext->Flags, IRP_FLAG_NOT_SYSTEM_PACKET );
  2038. }
  2039. LongByteSwap( BurstHeader->DataSize, DataSize );
  2040. LongByteSwap( BurstHeader->BurstOffset, BurstOffset );
  2041. ShortByteSwap( BurstHeader->BurstLength, BurstLength );
  2042. BurstHeader->MissingFragmentCount = 0;
  2043. BurstHeaderMdl->ByteCount = sizeof( *BurstHeader );
  2044. BurstHeaderMdl->Next = BurstDataMdl;
  2045. return;
  2046. }
  2047. NTSTATUS
  2048. SendSecondaryPacket(
  2049. PIRP_CONTEXT IrpContext,
  2050. PIRP Irp
  2051. )
  2052. /*++
  2053. Routine Description:
  2054. This routine submits a TDI send request to the tranport layer.
  2055. Arguments:
  2056. IrpContext - A pointer to IRP context information for the request
  2057. being processed.
  2058. Irp - The IRP for the packet to send.
  2059. Return Value:
  2060. None.
  2061. --*/
  2062. {
  2063. PNONPAGED_SCB pNpScb;
  2064. NTSTATUS Status;
  2065. PNCP_BURST_HEADER BurstHeader;
  2066. pNpScb = IrpContext->pNpScb;
  2067. DebugTrace( 0, Dbg, "SendSecondaryPacket\n", 0 );
  2068. BurstHeader = (PNCP_BURST_HEADER)( MmGetMdlVirtualAddress( Irp->MdlAddress ) );
  2069. if ( !BooleanFlagOn( IrpContext->Flags, IRP_FLAG_NOT_OK_TO_RECEIVE ) ) {
  2070. pNpScb->OkToReceive = TRUE;
  2071. }
  2072. LongByteSwap( BurstHeader->PacketSequenceNo, pNpScb->BurstSequenceNo );
  2073. pNpScb->BurstSequenceNo++;
  2074. ShortByteSwap( BurstHeader->BurstSequenceNo, pNpScb->BurstRequestNo );
  2075. ShortByteSwap( BurstHeader->AckSequenceNo, pNpScb->BurstRequestNo );
  2076. DebugTrace( +0, Dbg, "Irp %X\n", Irp );
  2077. DebugTrace( +0, Dbg, "pIrpC %X\n", IrpContext);
  2078. #if NWDBG
  2079. dumpMdl( Dbg, IrpContext->TxMdl);
  2080. #endif
  2081. Stats.BytesTransmitted.QuadPart += MdlLength( Irp->MdlAddress );
  2082. Stats.NcpsTransmitted.QuadPart += 1;
  2083. Status = IoCallDriver( pNpScb->Server.pDeviceObject, Irp );
  2084. DebugTrace( -1, Dbg, " %X\n", Status );
  2085. if ( !NT_SUCCESS( Status ) ) {
  2086. Error( EVENT_NWRDR_NETWORK_ERROR, Status, NULL, 0, 0 );
  2087. }
  2088. return Status;
  2089. }
  2090. #if NWFASTIO
  2091. BOOLEAN
  2092. NwFastWrite (
  2093. IN PFILE_OBJECT FileObject,
  2094. IN PLARGE_INTEGER FileOffset,
  2095. IN ULONG Length,
  2096. IN BOOLEAN Wait,
  2097. IN ULONG LockKey,
  2098. OUT PVOID Buffer,
  2099. OUT PIO_STATUS_BLOCK IoStatus,
  2100. IN PDEVICE_OBJECT DeviceObject
  2101. )
  2102. /*++
  2103. Routine Description:
  2104. This routine does a fast cached read bypassing the usual file system
  2105. entry routine (i.e., without the Irp). It is used to do a copy read
  2106. of a cached file object. For a complete description of the arguments
  2107. see CcCopyRead.
  2108. Arguments:
  2109. FileObject - Pointer to the file object being read.
  2110. FileOffset - Byte offset in file for desired data.
  2111. Length - Length of desired data in bytes.
  2112. Wait - FALSE if caller may not block, TRUE otherwise
  2113. Buffer - Pointer to output buffer to which data should be copied.
  2114. IoStatus - Pointer to standard I/O status block to receive the status
  2115. for the transfer.
  2116. Return Value:
  2117. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  2118. if there is an I/O error.
  2119. TRUE - if the data is being delivered
  2120. --*/
  2121. {
  2122. NODE_TYPE_CODE nodeTypeCode;
  2123. PICB icb;
  2124. PFCB fcb;
  2125. PVOID fsContext;
  2126. ULONG offset;
  2127. BOOLEAN wroteToCache;
  2128. try {
  2129. FsRtlEnterFileSystem();
  2130. DebugTrace(+1, Dbg, "NwFastWrite...\n", 0);
  2131. //
  2132. // Special case a read of zero length
  2133. //
  2134. if (Length == 0) {
  2135. //
  2136. // A zero length transfer was requested.
  2137. //
  2138. IoStatus->Status = STATUS_SUCCESS;
  2139. IoStatus->Information = 0;
  2140. DebugTrace(+1, Dbg, "NwFastWrite -> TRUE\n", 0);
  2141. return TRUE;
  2142. }
  2143. //
  2144. // Decode the file object to figure out who we are. If the result
  2145. // is not FCB then its an illegal parameter.
  2146. //
  2147. if ((nodeTypeCode = NwDecodeFileObject( FileObject,
  2148. &fsContext,
  2149. (PVOID *)&icb )) != NW_NTC_ICB) {
  2150. DebugTrace(0, Dbg, "Not a file\n", 0);
  2151. DebugTrace(-1, Dbg, "NwFastWrite -> FALSE\n", 0);
  2152. return FALSE;
  2153. }
  2154. fcb = (PFCB)icb->SuperType.Fcb;
  2155. nodeTypeCode = fcb->NodeTypeCode;
  2156. offset = FileOffset->LowPart;
  2157. IoStatus->Status = STATUS_SUCCESS;
  2158. IoStatus->Information = Length;
  2159. wroteToCache = CacheWrite(
  2160. NULL,
  2161. fcb->NonPagedFcb,
  2162. offset,
  2163. Length,
  2164. Buffer );
  2165. DebugTrace(-1, Dbg, "NwFastWrite -> %s\n", wroteToCache ? "TRUE" : "FALSE" );
  2166. if ( wroteToCache ) {
  2167. //
  2168. // If the file was extended, record the new file size.
  2169. //
  2170. if ( ( offset + Length ) > fcb->NonPagedFcb->Header.FileSize.LowPart ) {
  2171. fcb->NonPagedFcb->Header.FileSize.LowPart = ( offset + Length );
  2172. }
  2173. }
  2174. #ifndef NT1057
  2175. //
  2176. // Update the file object if we succeeded. We know that this
  2177. // is synchronous and not paging io because it's coming in through
  2178. // the cache.
  2179. //
  2180. if ( wroteToCache ) {
  2181. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + Length;
  2182. }
  2183. #endif
  2184. return( wroteToCache );
  2185. } finally {
  2186. FsRtlExitFileSystem();
  2187. }
  2188. }
  2189. #endif