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.

2056 lines
68 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Write.c
  5. Abstract:
  6. This module implements the File Write routine for Write called by the
  7. dispatch driver.
  8. Author:
  9. Joe Linn [JoeLinn] 2-Nov-94
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // The local debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_WRITE)
  18. BOOLEAN RxNoAsync = FALSE;
  19. extern LONG LDWCount;
  20. extern NTSTATUS LDWLastStatus;
  21. extern LARGE_INTEGER LDWLastTime;
  22. extern PVOID LDWContext;
  23. NTSTATUS
  24. RxLowIoWriteShell (
  25. IN PRX_CONTEXT RxContext,
  26. IN PIRP Irp,
  27. IN PFCB Fcb
  28. );
  29. NTSTATUS
  30. RxLowIoWriteShellCompletion (
  31. IN PRX_CONTEXT RxContext
  32. );
  33. #if DBG
  34. //
  35. // defined in read.c
  36. //
  37. VOID CheckForLoudOperations (
  38. IN PRX_CONTEXT RxContext,
  39. IN PFCB Fcb
  40. );
  41. #endif
  42. #ifdef RDBSS_TRACKER
  43. VOID
  44. __RxWriteReleaseResources(
  45. IN PRX_CONTEXT RxContext,
  46. IN PFCB Fcb,
  47. IN BOOL fSetResourceOwner,
  48. IN ULONG LineNumber,
  49. IN PSZ FileName,
  50. IN ULONG SerialNumber
  51. );
  52. #else
  53. VOID
  54. __RxWriteReleaseResources(
  55. IN PRX_CONTEXT RxContext,
  56. IN PFCB Fcb,
  57. IN BOOL fSetResourceOwner
  58. );
  59. #endif
  60. #ifdef ALLOC_PRAGMA
  61. #pragma alloc_text(PAGE, RxCommonWrite)
  62. #pragma alloc_text(PAGE, __RxWriteReleaseResources)
  63. #pragma alloc_text(PAGE, RxLowIoWriteShellCompletion)
  64. #pragma alloc_text(PAGE, RxLowIoWriteShell)
  65. #endif
  66. #if DBG
  67. #define DECLARE_POSTIRP() PCHAR PostIrp = NULL
  68. #define SET_POSTIRP(__XXX__) (PostIrp = (__XXX__))
  69. #define RESET_POSTIRP() (PostIrp = NULL)
  70. #else
  71. #define DECLARE_POSTIRP() BOOLEAN PostIrp = FALSE
  72. #define SET_POSTIRP(__XXX__) (PostIrp = TRUE)
  73. #define RESET_POSTIRP() (PostIrp = FALSE)
  74. #endif
  75. #ifdef RDBSS_TRACKER
  76. #define RxWriteReleaseResources(CTX,FCB, IS_TID) __RxWriteReleaseResources( CTX, FCB, IS_TID, __LINE__, __FILE__, 0 )
  77. #else
  78. #define RxWriteReleaseResources(CTX,FCB, IS_TID) __RxWriteReleaseResources( CTX, FCB, IS_TID )
  79. #endif
  80. #ifdef RDBSS_TRACKER
  81. VOID
  82. __RxWriteReleaseResources (
  83. IN PRX_CONTEXT RxContext,
  84. IN PFCB Fcb,
  85. IN BOOL fSetResourceOwner,
  86. IN ULONG LineNumber,
  87. IN PSZ FileName,
  88. IN ULONG SerialNumber
  89. )
  90. #else
  91. VOID
  92. __RxWriteReleaseResources (
  93. IN PRX_CONTEXT RxContext,
  94. IN PFCB Fcb,
  95. IN BOOL fSetResourceOwner
  96. )
  97. #endif
  98. /*++
  99. Routine Description:
  100. This function frees resources and tracks the state
  101. Arguments:
  102. RxContext -
  103. Return Value:
  104. none
  105. --*/
  106. {
  107. PAGED_CODE();
  108. ASSERT( (RxContext != NULL) && (Fcb != NULL) );
  109. if (RxContext->FcbResourceAcquired) {
  110. RxDbgTrace( 0, Dbg,("RxCommonWrite ReleasingFcb\n") );
  111. if( fSetResourceOwner ) {
  112. RxReleaseFcbForThread( RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId );
  113. } else {
  114. RxReleaseFcb( RxContext, Fcb );
  115. }
  116. RxContext->FcbResourceAcquired = FALSE;
  117. }
  118. if (RxContext->FcbPagingIoResourceAcquired) {
  119. RxDbgTrace( 0, Dbg,("RxCommonWrite ReleasingPaginIo\n") );
  120. if( fSetResourceOwner ) {
  121. RxReleasePagingIoResourceForThread( RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId );
  122. } else {
  123. RxReleasePagingIoResource( RxContext, Fcb );
  124. }
  125. }
  126. }
  127. NTSTATUS
  128. RxCommonWrite (
  129. IN PRX_CONTEXT RxContext,
  130. IN PIRP Irp
  131. )
  132. /*++
  133. Routine Description:
  134. This is the common write routine for NtWriteFile, called from both
  135. the Fsd, or from the Fsp if a request could not be completed without
  136. blocking in the Fsd. This routine's actions are
  137. conditionalized by the Wait input parameter, which determines whether
  138. it is allowed to block or not. If a blocking condition is encountered
  139. with Wait == FALSE, however, the request is posted to the Fsp, who
  140. always calls with WAIT == TRUE.
  141. Arguments:
  142. Irp - Supplies the Irp to process
  143. Return Value:
  144. RXSTATUS - The return status for the operation
  145. --*/
  146. {
  147. NTSTATUS Status;
  148. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  149. PFILE_OBJECT FileObject = IrpSp->FileObject;
  150. NODE_TYPE_CODE TypeOfOpen;
  151. PFCB Fcb;
  152. PFOBX Fobx;
  153. PSRV_OPEN SrvOpen;
  154. PNET_ROOT NetRoot;
  155. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  156. LARGE_INTEGER StartingByte;
  157. RXVBO StartingVbo;
  158. ULONG ByteCount;
  159. LONGLONG FileSize;
  160. LONGLONG ValidDataLength;
  161. LONGLONG InitialFileSize;
  162. LONGLONG InitialValidDataLength;
  163. ULONG CapturedRxContextSerialNumber = RxContext->SerialNumber;
  164. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  165. #if DBG
  166. PCHAR PostIrp = NULL;
  167. #else
  168. BOOLEAN PostIrp = FALSE;
  169. #endif
  170. BOOLEAN ExtendingFile = FALSE;
  171. BOOLEAN SwitchBackToAsync = FALSE;
  172. BOOLEAN CalledByLazyWriter = FALSE;
  173. BOOLEAN ExtendingValidData = FALSE;
  174. BOOLEAN WriteFileSizeToDirent = FALSE;
  175. BOOLEAN RecursiveWriteThrough = FALSE;
  176. BOOLEAN UnwindOutstandingAsync = FALSE;
  177. BOOLEAN RefdContextForTracker = FALSE;
  178. BOOLEAN SynchronousIo;
  179. BOOLEAN WriteToEof;
  180. BOOLEAN PagingIo;
  181. BOOLEAN NonCachedIo;
  182. BOOLEAN Wait;
  183. BOOLEAN DiskWrite = FALSE;
  184. BOOLEAN PipeWrite = FALSE;
  185. BOOLEAN BlockingResume = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME );
  186. BOOLEAN fSetResourceOwner = FALSE;
  187. BOOLEAN InFsp = FALSE;
  188. PAGED_CODE();
  189. TypeOfOpen = RxDecodeFileObject( FileObject, &Fcb, &Fobx );
  190. //
  191. // Get rid of invalid write requests right away.
  192. //
  193. if ((TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) &&
  194. (TypeOfOpen != RDBSS_NTC_VOLUME_FCB) &&
  195. (TypeOfOpen != RDBSS_NTC_SPOOLFILE) &&
  196. (TypeOfOpen != RDBSS_NTC_MAILSLOT)) {
  197. RxDbgTrace( 0, Dbg, ("Invalid file object for write\n", 0) );
  198. RxDbgTrace( -1, Dbg, ("RxCommonWrite: Exit -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST) );
  199. return STATUS_INVALID_DEVICE_REQUEST;
  200. }
  201. #ifdef RX_WJ_DBG_SUPPORT
  202. RxdUpdateJournalOnWriteInitiation( Fcb, IrpSp->Parameters.Write.ByteOffset, IrpSp->Parameters.Write.Length );
  203. #endif
  204. NetRoot = (PNET_ROOT)Fcb->NetRoot;
  205. switch (NetRoot->Type) {
  206. case NET_ROOT_DISK:
  207. //
  208. // Fallthrough
  209. //
  210. case NET_ROOT_WILD:
  211. DiskWrite = TRUE;
  212. break;
  213. case NET_ROOT_PIPE:
  214. PipeWrite = TRUE;
  215. break;
  216. }
  217. BlockingResume = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME );
  218. //
  219. // Initialize the appropriate local variables.
  220. //
  221. Wait = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  222. PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
  223. NonCachedIo = BooleanFlagOn( Irp->Flags, IRP_NOCACHE );
  224. SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  225. InFsp = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP );
  226. //
  227. // pick up a write-through specified only for this irp
  228. //
  229. if (FlagOn( IrpSp->Flags, SL_WRITE_THROUGH )) {
  230. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH );
  231. }
  232. RxDbgTrace( +1, Dbg, ("RxCommonWrite...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
  233. RxContext, Fobx, Fcb) );
  234. RxDbgTrace( 0, Dbg, (" ->ByteCount = %08lx, ByteOffset = %08lx %lx\n",
  235. IrpSp->Parameters.Write.Length,
  236. IrpSp->Parameters.Write.ByteOffset.LowPart,
  237. IrpSp->Parameters.Write.ByteOffset.HighPart) );
  238. RxDbgTrace( 0, Dbg,(" ->%s%s%s%s\n",
  239. Wait ?"Wait ":"",
  240. PagingIo ?"PagingIo ":"",
  241. NonCachedIo ?"NonCachedIo ":"",
  242. SynchronousIo ?"SynchronousIo ":"") );
  243. RxLog(( "CommonWrite %lx %lx %lx\n", RxContext, Fobx, Fcb ));
  244. RxWmiLog( LOG,
  245. RxCommonWrite_1,
  246. LOGPTR( RxContext )
  247. LOGPTR( Fobx )
  248. LOGPTR( Fcb ) );
  249. RxLog(( " write %lx@%lx %lx %s%s%s%s\n",
  250. IrpSp->Parameters.Write.Length,
  251. IrpSp->Parameters.Write.ByteOffset.LowPart,
  252. IrpSp->Parameters.Write.ByteOffset.HighPart,
  253. Wait?"Wt":"",
  254. PagingIo?"Pg":"",
  255. NonCachedIo?"Nc":"",
  256. SynchronousIo?"Sy":"" ));
  257. RxWmiLog( LOG,
  258. RxCommonWrite_2,
  259. LOGULONG( IrpSp->Parameters.Write.Length )
  260. LOGULONG( IrpSp->Parameters.Write.ByteOffset.LowPart )
  261. LOGULONG( IrpSp->Parameters.Write.ByteOffset.HighPart )
  262. LOGUCHAR( Wait )
  263. LOGUCHAR( PagingIo )
  264. LOGUCHAR( NonCachedIo )
  265. LOGUCHAR( SynchronousIo ) );
  266. RxItsTheSameContext();
  267. RxContext->FcbResourceAcquired = FALSE;
  268. RxContext->FcbPagingIoResourceAcquired = FALSE;
  269. //
  270. // Extract starting Vbo and offset.
  271. //
  272. StartingByte = IrpSp->Parameters.Write.ByteOffset;
  273. StartingVbo = StartingByte.QuadPart;
  274. ByteCount = IrpSp->Parameters.Write.Length;
  275. WriteToEof = (StartingVbo < 0);
  276. #if DBG
  277. CheckForLoudOperations( RxContext, Fcb );
  278. if (FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS )) {
  279. DbgPrint( "LoudWrite %lx/%lx on %lx vdl/size/alloc %lx/%lx/%lx\n",
  280. StartingByte.LowPart,ByteCount,
  281. Fcb,
  282. Fcb->Header.ValidDataLength.LowPart,
  283. Fcb->Header.FileSize.LowPart,
  284. Fcb->Header.AllocationSize.LowPart );
  285. }
  286. #endif
  287. //
  288. // Statistics............
  289. //
  290. if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP ) &&
  291. (Fcb->CachedNetRootType == NET_ROOT_DISK)) {
  292. InterlockedIncrement( &RxDeviceObject->WriteOperations );
  293. if (StartingVbo != Fobx->Specific.DiskFile.PredictedWriteOffset) {
  294. InterlockedIncrement( &RxDeviceObject->RandomWriteOperations );
  295. }
  296. Fobx->Specific.DiskFile.PredictedWriteOffset = StartingVbo + ByteCount;
  297. if (PagingIo) {
  298. ExInterlockedAddLargeStatistic( &RxDeviceObject->PagingWriteBytesRequested,ByteCount );
  299. } else if (NonCachedIo) {
  300. ExInterlockedAddLargeStatistic( &RxDeviceObject->NonPagingWriteBytesRequested,ByteCount );
  301. } else {
  302. ExInterlockedAddLargeStatistic( &RxDeviceObject->CacheWriteBytesRequested,ByteCount );
  303. }
  304. }
  305. //
  306. // If there is nothing to write, return immediately or if the buffers are invalid
  307. // return the appropriate status
  308. //
  309. if (DiskWrite && (ByteCount == 0)) {
  310. return STATUS_SUCCESS;
  311. } else if ((Irp->UserBuffer == NULL) && (Irp->MdlAddress == NULL)) {
  312. return STATUS_INVALID_PARAMETER;
  313. } else if ((MAXLONGLONG - StartingVbo < ByteCount) && (!WriteToEof)) {
  314. return STATUS_INVALID_PARAMETER;
  315. }
  316. if (Fobx != NULL ) {
  317. SrvOpen = Fobx->SrvOpen;
  318. } else {
  319. SrvOpen = NULL;
  320. }
  321. //
  322. // See if we have to defer the write. Note that if write cacheing is
  323. // disabled then we don't have to check.
  324. //
  325. if (!NonCachedIo &&
  326. RxWriteCachingAllowed( Fcb, SrvOpen ) &&
  327. !CcCanIWrite( FileObject,
  328. ByteCount,
  329. (BOOLEAN)(Wait && !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP )),
  330. BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE ))) {
  331. BOOLEAN Retrying = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE );
  332. RxPrePostIrp( RxContext, Irp );
  333. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE );
  334. CcDeferWrite( FileObject,
  335. (PCC_POST_DEFERRED_WRITE)RxAddToWorkque,
  336. RxContext,
  337. Irp,
  338. ByteCount,
  339. Retrying );
  340. return STATUS_PENDING;
  341. }
  342. //
  343. // Initialize LowIO_CONTEXT block in the RxContext
  344. //
  345. RxInitializeLowIoContext( RxContext, LOWIO_OP_WRITE, LowIoContext );
  346. //
  347. // Use a try-finally to free Fcb and buffers on the way out.
  348. //
  349. try {
  350. BOOLEAN DoLowIoWrite = TRUE;
  351. //
  352. // This case corresponds to a normal user write file.
  353. //
  354. ASSERT ((TypeOfOpen == RDBSS_NTC_STORAGE_TYPE_FILE ) ||
  355. (TypeOfOpen == RDBSS_NTC_SPOOLFILE) ||
  356. (TypeOfOpen == RDBSS_NTC_MAILSLOT) );
  357. RxDbgTrace( 0, Dbg, ("Type of write is user file open\n", 0) );
  358. //
  359. // If this is a noncached transfer and is not a paging I/O, and
  360. // the file has been opened cached, then we will do a flush here
  361. // to avoid stale data problems.
  362. //
  363. // The Purge following the flush will guarantee cache coherency.
  364. //
  365. if ((NonCachedIo || !RxWriteCachingAllowed( Fcb, SrvOpen )) &&
  366. !PagingIo &&
  367. (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
  368. LARGE_INTEGER FlushBase;
  369. //
  370. // We need the Fcb exclusive to do the CcPurgeCache
  371. //
  372. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  373. if (Status == STATUS_LOCK_NOT_GRANTED) {
  374. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb) );
  375. #if DBG
  376. PostIrp = "Couldn't acquireex for flush";
  377. #else
  378. PostIrp = TRUE;
  379. #endif
  380. try_return( PostIrp );
  381. } else if (Status != STATUS_SUCCESS) {
  382. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb) );
  383. try_return( PostIrp = FALSE );
  384. }
  385. RxContext->FcbResourceAcquired = TRUE;
  386. //
  387. // we don't set fcbacquiredexclusive here since we either return or release
  388. //
  389. if (WriteToEof) {
  390. RxGetFileSizeWithLock( Fcb, &FlushBase.QuadPart );
  391. } else {
  392. FlushBase = StartingByte;
  393. }
  394. RxAcquirePagingIoResource( RxContext, Fcb );
  395. CcFlushCache( FileObject->SectionObjectPointer, // ok4flush
  396. &FlushBase,
  397. ByteCount,
  398. &Irp->IoStatus );
  399. RxReleasePagingIoResource( RxContext, Fcb );
  400. if (!NT_SUCCESS( Irp->IoStatus.Status)) {
  401. try_return( Status = Irp->IoStatus.Status );
  402. }
  403. RxAcquirePagingIoResource( RxContext, Fcb );
  404. RxReleasePagingIoResource( RxContext, Fcb );
  405. CcPurgeCacheSection( FileObject->SectionObjectPointer,
  406. &FlushBase,
  407. ByteCount,
  408. FALSE );
  409. }
  410. //
  411. // We assert that Paging Io writes will never WriteToEof.
  412. //
  413. ASSERT( !(WriteToEof && PagingIo) );
  414. //
  415. // First let's acquire the Fcb shared. Shared is enough if we
  416. // are not writing beyond EOF.
  417. //
  418. RxItsTheSameContext();
  419. if (PagingIo) {
  420. BOOLEAN AcquiredFile;
  421. ASSERT( !PipeWrite );
  422. AcquiredFile = RxAcquirePagingIoResourceShared( RxContext, Fcb, TRUE );
  423. LowIoContext->Resource = Fcb->Header.PagingIoResource;
  424. } else if (!BlockingResume) {
  425. //
  426. // If this could be async, noncached IO we need to check that
  427. // we don't exhaust the number of times a single thread can
  428. // acquire the resource.
  429. //
  430. // The writes which extend the valid data length result in the the
  431. // capability of collapsing opens being renounced. This is required to
  432. // ensure that directory control can see the updated state of the file
  433. // on close. If this is not done the extended file length is not visible
  434. // on directory control immediately after a close. In such cases the FCB
  435. // is accquired exclusive, the changes are made to the buffering state
  436. // and then downgraded to a shared accquisition.
  437. //
  438. if (!RxContext->FcbResourceAcquired) {
  439. if (!PipeWrite) {
  440. if (!Wait &&
  441. (NonCachedIo || !RxWriteCachingAllowed( Fcb, SrvOpen ))) {
  442. Status = RxAcquireSharedFcbWaitForEx( RxContext, Fcb );
  443. } else {
  444. Status = RxAcquireSharedFcb( RxContext, Fcb );
  445. }
  446. } else {
  447. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  448. }
  449. if (Status == STATUS_LOCK_NOT_GRANTED) {
  450. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb ));
  451. #if DBG
  452. PostIrp = "Couldn't get mainr w/o waiting sh";
  453. #else
  454. PostIrp = TRUE;
  455. #endif
  456. try_return( PostIrp );
  457. } else if (Status != STATUS_SUCCESS) {
  458. RxDbgTrace( 0, Dbg, ("RxCommonWrite : Cannot acquire Fcb(%lx) %lx\n", Fcb, Status) );
  459. try_return( PostIrp = FALSE );
  460. }
  461. RxContext->FcbResourceAcquired = TRUE;
  462. } else {
  463. ASSERT( !PipeWrite );
  464. }
  465. if (!PipeWrite) {
  466. //
  467. // Check for extending write and convert to an exlusive lock
  468. //
  469. if (ExIsResourceAcquiredSharedLite( Fcb->Header.Resource ) &&
  470. (StartingVbo + ByteCount > Fcb->Header.ValidDataLength.QuadPart) &&
  471. FlagOn( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED )) {
  472. RxReleaseFcb( RxContext,Fcb );
  473. RxContext->FcbResourceAcquired = FALSE;
  474. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  475. if (Status == STATUS_LOCK_NOT_GRANTED) {
  476. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb) );
  477. #if DBG
  478. PostIrp = "Couldn't get mainr w/o waiting sh";
  479. #else
  480. PostIrp = TRUE;
  481. #endif
  482. try_return( PostIrp );
  483. } else if (Status != STATUS_SUCCESS) {
  484. RxDbgTrace( 0, Dbg, ("RxCommonWrite : Cannot acquire Fcb(%lx) %lx\n", Fcb, Status) );
  485. try_return( PostIrp = FALSE );
  486. } else {
  487. RxContext->FcbResourceAcquired = TRUE;
  488. }
  489. }
  490. //
  491. // We need to retest for extending writes after dropping the resources
  492. //
  493. if ((StartingVbo + ByteCount > Fcb->Header.ValidDataLength.QuadPart) &&
  494. (FlagOn( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED ))) {
  495. ASSERT( RxIsFcbAcquiredExclusive ( Fcb ) );
  496. RxLog(("RxCommonWrite Disable Collapsing %lx\n",Fcb));
  497. RxWmiLog( LOG,
  498. RxCommonWrite_3,
  499. LOGPTR( Fcb ));
  500. //
  501. // If we are still extending the file disable collapsing to ensure that
  502. // once the file is closed directory control will reflect the sizes
  503. // correctly.
  504. //
  505. ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
  506. } else {
  507. //
  508. // If the resource has been acquired exclusive we downgrade it
  509. // to shared. This enables a combination of buffered and
  510. // unbuffered writes to be synchronized correctly.
  511. //
  512. if (ExIsResourceAcquiredExclusiveLite( Fcb->Header.Resource )) {
  513. ExConvertExclusiveToSharedLite( Fcb->Header.Resource );
  514. }
  515. }
  516. }
  517. ASSERT( RxContext->FcbResourceAcquired );
  518. LowIoContext->Resource = Fcb->Header.Resource;
  519. }
  520. //
  521. // for pipe writes, bail out now. we avoid a goto by duplicating the calldown
  522. // indeed, pipe writes should be removed from the main path.
  523. //
  524. if (PipeWrite) {
  525. //
  526. // In order to prevent corruption on multi-threaded multi-block
  527. // message mode pipe reads, we do this little dance with the fcb resource
  528. //
  529. if (!BlockingResume) {
  530. if ((Fobx != NULL) &&
  531. ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_MESSAGE_TYPE) ||
  532. ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_BYTE_STREAM_TYPE) &&
  533. !FlagOn( Fobx->Specific.NamedPipe.CompletionMode, FILE_PIPE_COMPLETE_OPERATION )))) {
  534. //
  535. // Synchronization is effected here that will prevent other
  536. // threads from coming in and reading from this file while the
  537. // message pipe read is continuing.
  538. //
  539. // This is necessary because we will release the FCB lock while
  540. // actually performing the I/O to allow open (and other) requests
  541. // to continue on this file while the I/O is in progress.
  542. //
  543. RxDbgTrace( 0,Dbg,("Message pipe write: Fobx: %lx, Fcb: %lx, Enqueuing...\n", Fobx, Fcb ));
  544. Status = RxSynchronizeBlockingOperationsAndDropFcbLock( RxContext,
  545. Fcb,
  546. &Fobx->Specific.NamedPipe.WriteSerializationQueue );
  547. //
  548. // this happens in the above routine
  549. //
  550. RxContext->FcbResourceAcquired = FALSE;
  551. RxItsTheSameContext();
  552. if (!NT_SUCCESS(Status) ||
  553. (Status == STATUS_PENDING)) {
  554. try_return( Status );
  555. }
  556. RxDbgTrace( 0,Dbg,("Succeeded: Fobx: %lx\n", Fobx) );
  557. }
  558. }
  559. LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
  560. LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
  561. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION );
  562. //
  563. // If we are in FSP, set the resource owner so that the reosurce package doesnt
  564. // try to boost the priority of the owner thread. There is no guarantee that the
  565. // FSP thred will remain alive while the I/O is pending.
  566. //
  567. // (there is no PagingIoResource for pipes !)
  568. //
  569. if( InFsp && RxContext->FcbResourceAcquired ) {
  570. LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
  571. ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId);
  572. fSetResourceOwner = TRUE;
  573. }
  574. Status = RxLowIoWriteShell( RxContext, Irp, Fcb );
  575. RxItsTheSameContext();
  576. try_return( Status );
  577. }
  578. //
  579. // If this is the normal data stream object we have to check for
  580. // write access according to the current state of the file locks.
  581. //
  582. if (!PagingIo &&
  583. !FsRtlCheckLockForWriteAccess( &Fcb->FileLock, Irp )) {
  584. try_return( Status = STATUS_FILE_LOCK_CONFLICT );
  585. }
  586. //
  587. // we never write these without protextion...so the following comment is bogus.
  588. // also, we manipulate the vdl and filesize as if we owned them.....in fact, we don't unless
  589. // the file is cached for writing! i'm leaving the comment in case i understand it later
  590. // HERE IS THE BOGUS COMMENT!!! (the part about not being protected.......)
  591. // Get a first tentative file size and valid data length.
  592. // We must get ValidDataLength first since it is always
  593. // increased second (the case we are unprotected) and
  594. // we don't want to capture ValidDataLength > FileSize.
  595. //
  596. ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
  597. RxGetFileSizeWithLock( Fcb, &FileSize );
  598. ASSERT( ValidDataLength <= FileSize );
  599. //
  600. // If this is paging io, then we do not want
  601. // to write beyond end of file. If the base is beyond Eof, we will just
  602. // Noop the call. If the transfer starts before Eof, but extends
  603. // beyond, we will limit write to file size.
  604. // Otherwise, in case of write through, since Mm rounds up
  605. // to a page, we might try to acquire the resource exclusive
  606. // when our top level guy only acquired it shared. Thus, =><=.
  607. //
  608. //
  609. // finally, if this is for a minirdr (as opposed to a local miniFS) AND
  610. // if cacheing is not enabled then i have no idea what VDL is! so, i have to just pass
  611. // it thru. Currently we do not provide for this case and let the RDBSS
  612. // throw the write on the floor. A better fix would be to let the mini
  613. // redirectors deal with it.
  614. //
  615. if (PagingIo) {
  616. if (StartingVbo >= FileSize) {
  617. RxDbgTrace( 0, Dbg, ("PagingIo started beyond EOF.\n", 0) );
  618. try_return( Status = STATUS_SUCCESS );
  619. }
  620. if (ByteCount > FileSize - StartingVbo) {
  621. RxDbgTrace( 0, Dbg, ("PagingIo extending beyond EOF.\n", 0) );
  622. ByteCount = (ULONG)(FileSize - StartingVbo);
  623. }
  624. }
  625. //
  626. // Determine if we were called by the lazywriter.
  627. // see resrcsup.c for where we captured the lazywriter's thread
  628. //
  629. if (RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) {
  630. RxDbgTrace( 0, Dbg,("RxCommonWrite ThisIsCalledByLazyWriter%c\n",'!'));
  631. CalledByLazyWriter = TRUE;
  632. if (FlagOn( Fcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE )) {
  633. //
  634. // Fail if the start of this request is beyond valid data length.
  635. // Don't worry if this is an unsafe test. MM and CC won't
  636. // throw this page away if it is really dirty.
  637. //
  638. if ((StartingVbo + ByteCount > ValidDataLength) &&
  639. (StartingVbo < FileSize)) {
  640. //
  641. // It's OK if byte range is within the page containing valid data length,
  642. // since we will use ValidDataToDisk as the start point.
  643. //
  644. if (StartingVbo + ByteCount > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
  645. //
  646. // Don't flush this now.
  647. //
  648. try_return( Status = STATUS_FILE_LOCK_CONFLICT );
  649. }
  650. }
  651. }
  652. }
  653. //
  654. // This code detects if we are a recursive synchronous page write
  655. // on a write through file object.
  656. //
  657. if (FlagOn( Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO ) &&
  658. FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL )) {
  659. PIRP TopIrp;
  660. TopIrp = RxGetTopIrpIfRdbssIrp();
  661. //
  662. // This clause determines if the top level request was
  663. // in the FastIo path.
  664. //
  665. if ((TopIrp != NULL) &&
  666. ((ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG) ) {
  667. PIO_STACK_LOCATION IrpStack;
  668. ASSERT( NodeType(TopIrp) == IO_TYPE_IRP );
  669. IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
  670. //
  671. // Finally this routine detects if the Top irp was a
  672. // write to this file and thus we are the writethrough.
  673. //
  674. if ((IrpStack->MajorFunction == IRP_MJ_WRITE) &&
  675. (IrpStack->FileObject->FsContext == FileObject->FsContext)) { // ok4->FileObj butmove
  676. RecursiveWriteThrough = TRUE;
  677. RxDbgTrace( 0, Dbg,("RxCommonWrite ThisIsRecursiveWriteThru%c\n",'!') );
  678. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH );
  679. }
  680. }
  681. }
  682. //
  683. // Here is the deal with ValidDataLength and FileSize:
  684. //
  685. // Rule 1: PagingIo is never allowed to extend file size.
  686. //
  687. // Rule 2: Only the top level requestor may extend Valid
  688. // Data Length. This may be paging IO, as when a
  689. // a user maps a file, but will never be as a result
  690. // of cache lazy writer writes since they are not the
  691. // top level request.
  692. //
  693. // Rule 3: If, using Rules 1 and 2, we decide we must extend
  694. // file size or valid data, we take the Fcb exclusive.
  695. //
  696. //
  697. // Now see if we are writing beyond valid data length, and thus
  698. // maybe beyond the file size. If so, then we must
  699. // release the Fcb and reacquire it exclusive. Note that it is
  700. // important that when not writing beyond EOF that we check it
  701. // while acquired shared and keep the FCB acquired, in case some
  702. // turkey truncates the file.
  703. //
  704. //
  705. // Note that the lazy writer must not be allowed to try and
  706. // acquire the resource exclusive. This is not a problem since
  707. // the lazy writer is paging IO and thus not allowed to extend
  708. // file size, and is never the top level guy, thus not able to
  709. // extend valid data length.
  710. //
  711. // finally, all the discussion of VDL and filesize is conditioned on the fact
  712. // that cacheing is enabled. if not, we don't know the VDL OR the filesize and
  713. // we have to just send out the IOs
  714. //
  715. if (!CalledByLazyWriter &&
  716. !RecursiveWriteThrough &&
  717. (WriteToEof || (StartingVbo + ByteCount > ValidDataLength))) {
  718. //
  719. // If this was an asynchronous write, we are going to make
  720. // the request synchronous at this point, but only temporarily.
  721. // At the last moment, before sending the write off to the
  722. // driver, we may shift back to async.
  723. //
  724. // The modified page writer already has the resources
  725. // he requires, so this will complete in small finite
  726. // time.
  727. //
  728. if (!SynchronousIo) {
  729. Wait = TRUE;
  730. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  731. ClearFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  732. SynchronousIo = TRUE;
  733. if (NonCachedIo) {
  734. SwitchBackToAsync = TRUE;
  735. }
  736. }
  737. //
  738. // We need Exclusive access to the Fcb since we will
  739. // probably have to extend valid data and/or file. Drop
  740. // whatever we have and grab the normal resource exclusive.
  741. //
  742. ASSERT(fSetResourceOwner == FALSE);
  743. RxWriteReleaseResources( RxContext, Fcb, fSetResourceOwner );
  744. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  745. if (Status == STATUS_LOCK_NOT_GRANTED) {
  746. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb) );
  747. #if DBG
  748. PostIrp = "could get excl for extend";
  749. #else
  750. PostIrp = TRUE;
  751. #endif
  752. try_return( PostIrp);
  753. } else if (Status != STATUS_SUCCESS) {
  754. RxDbgTrace( 0, Dbg, ("RxCommonWrite : Cannot acquire Fcb(%lx) : %lx\n", Fcb,Status) );
  755. try_return( PostIrp = FALSE );
  756. }
  757. RxItsTheSameContext();
  758. RxContext->FcbResourceAcquired = TRUE;
  759. //
  760. // Now that we have the Fcb exclusive, get a new batch of
  761. // filesize and ValidDataLength.
  762. //
  763. ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
  764. RxGetFileSizeWithLock( Fcb, &FileSize );
  765. ASSERT( ValidDataLength <= FileSize );
  766. //
  767. // Now that we have the Fcb exclusive, see if this write
  768. // qualifies for being made async again. The key point
  769. // here is that we are going to update ValidDataLength in
  770. // the Fcb before returning. We must make sure this will
  771. // not cause a problem. So, if we are extending the file OR if we have
  772. // a section on the file, we can't go async.
  773. //
  774. // Another thing we must do is keep out
  775. // the FastIo path.....this is done since we have the resource exclusive
  776. //
  777. if (SwitchBackToAsync) {
  778. if ((Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
  779. ((StartingVbo + ByteCount) > FileSize) ||
  780. RxNoAsync) {
  781. SwitchBackToAsync = FALSE;
  782. }
  783. }
  784. //
  785. // If this is PagingIo check again if any pruning is
  786. // required.
  787. //
  788. if (PagingIo) {
  789. if (StartingVbo >= FileSize) {
  790. try_return( Status = STATUS_SUCCESS );
  791. }
  792. if (ByteCount > FileSize - StartingVbo) {
  793. ByteCount = (ULONG)(FileSize - StartingVbo);
  794. }
  795. }
  796. }
  797. //
  798. // Remember the initial file size and valid data length,
  799. // just in case .....
  800. //
  801. InitialFileSize = FileSize;
  802. InitialValidDataLength = ValidDataLength;
  803. //
  804. // Check for writing to end of File. If we are, then we have to
  805. // recalculate a number of fields. These may have changed if we dropped
  806. // and regained the resource.
  807. //
  808. if (WriteToEof) {
  809. StartingVbo = FileSize;
  810. StartingByte.QuadPart = FileSize;
  811. }
  812. //
  813. // If this is the normal data stream object we have to check for
  814. // write access according to the current state of the file locks.
  815. //
  816. if (!PagingIo &&
  817. !FsRtlCheckLockForWriteAccess( &Fcb->FileLock, Irp )) {
  818. try_return( Status = STATUS_FILE_LOCK_CONFLICT );
  819. }
  820. //
  821. // Determine if we will deal with extending the file.
  822. //
  823. if (!PagingIo &&
  824. DiskWrite &&
  825. (StartingVbo >= 0) &&
  826. (StartingVbo + ByteCount > FileSize)) {
  827. LARGE_INTEGER OriginalFileSize;
  828. LARGE_INTEGER OriginalAllocationSize;
  829. LARGE_INTEGER OriginalValidDataLength;
  830. RxLog(( "NeedToExtending %lx", RxContext ));
  831. RxWmiLog( LOG,
  832. RxCommonWrite_4,
  833. LOGPTR( RxContext ) );
  834. ExtendingFile = TRUE;
  835. SetFlag( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE );
  836. //
  837. // EXTENDING THE FILE
  838. //
  839. // Update our local copy of FileSize
  840. //
  841. OriginalFileSize.QuadPart = Fcb->Header.FileSize.QuadPart;
  842. OriginalAllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
  843. OriginalValidDataLength.QuadPart = Fcb->Header.ValidDataLength.QuadPart;
  844. FileSize = StartingVbo + ByteCount;
  845. if (FileSize > Fcb->Header.AllocationSize.QuadPart) {
  846. LARGE_INTEGER AllocationSize;
  847. RxLog(( "Extending %lx", RxContext ));
  848. RxWmiLog( LOG,
  849. RxCommonWrite_5,
  850. LOGPTR( RxContext ) );
  851. if (NonCachedIo || !RxWriteCachingAllowed( Fcb, SrvOpen )) {
  852. MINIRDR_CALL( Status,
  853. RxContext,
  854. Fcb->MRxDispatch,
  855. MRxExtendForNonCache,
  856. (RxContext,
  857. (PLARGE_INTEGER)&FileSize, &AllocationSize) );
  858. } else {
  859. MINIRDR_CALL( Status,
  860. RxContext,
  861. Fcb->MRxDispatch,
  862. MRxExtendForCache,
  863. (RxContext,(PLARGE_INTEGER)&FileSize,&AllocationSize) );
  864. }
  865. if (!NT_SUCCESS( Status )) {
  866. RxDbgTrace(0, Dbg, ("Couldn't extend for cacheing.\n", 0) );
  867. try_return( Status );
  868. }
  869. if (FileSize > AllocationSize.QuadPart) {
  870. //
  871. // When the file is sparse this test is not valid. exclude
  872. // this case by resetting the allocation size to file size.
  873. // This effectively implies that we will go to the server
  874. // for sparse I/O.
  875. //
  876. // This test is also not valid for compressed files. NTFS
  877. // keeps track of the compressed file size and the uncompressed
  878. // file size. It however returns the compressed file size for
  879. // directory queries and information queries.
  880. //
  881. // For now we rely on the servers return code. If it returned
  882. // success and the allocation size is less we believe that
  883. // it is one of the two cases above and set allocation size
  884. // to the desired file size.
  885. //
  886. AllocationSize.QuadPart = FileSize;
  887. }
  888. //
  889. // Set the new file allocation in the Fcb.
  890. //
  891. Fcb->Header.AllocationSize = AllocationSize;
  892. }
  893. //
  894. // Set the new file size in the Fcb.
  895. //
  896. RxSetFileSizeWithLock( Fcb, &FileSize );
  897. RxAdjustAllocationSizeforCC( Fcb );
  898. //
  899. // Extend the cache map, letting mm knows the new file size.
  900. // We only have to do this if the file is cached.
  901. //
  902. if (CcIsFileCached( FileObject )) {
  903. try {
  904. CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  905. } except (EXCEPTION_EXECUTE_HANDLER) {
  906. Status = GetExceptionCode();
  907. }
  908. if (Status != STATUS_SUCCESS) {
  909. //
  910. // Restore the original file sizes in the FCB and File object
  911. //
  912. Fcb->Header.FileSize.QuadPart = OriginalFileSize.QuadPart;
  913. Fcb->Header.AllocationSize.QuadPart = OriginalAllocationSize.QuadPart;
  914. Fcb->Header.ValidDataLength.QuadPart = OriginalValidDataLength.QuadPart;
  915. if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
  916. *CcGetFileSizePointer( FileObject ) = Fcb->Header.FileSize;
  917. }
  918. try_return( Status );
  919. }
  920. }
  921. }
  922. //
  923. // Determine if we will deal with extending valid data.
  924. //
  925. if (!CalledByLazyWriter &&
  926. !RecursiveWriteThrough &&
  927. (WriteToEof || (StartingVbo + ByteCount > ValidDataLength ))) {
  928. ExtendingValidData = TRUE;
  929. SetFlag( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL );
  930. }
  931. //
  932. // HANDLE CACHED CASE
  933. //
  934. if (!PagingIo &&
  935. !NonCachedIo && // this part is not discretionary
  936. RxWriteCachingAllowed( Fcb, SrvOpen ) ) {
  937. ASSERT( !PagingIo );
  938. //
  939. // We delay setting up the file cache until now, in case the
  940. // caller never does any I/O to the file, and thus
  941. // FileObject->PrivateCacheMap == NULL.
  942. //
  943. if (FileObject->PrivateCacheMap == NULL) {
  944. RxDbgTrace( 0, Dbg, ("Initialize cache mapping.\n", 0) );
  945. //
  946. // If this FileObject has gone through CleanUp, we cannot
  947. // CcInitializeCacheMap it.
  948. //
  949. if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
  950. Status = STATUS_FILE_CLOSED;
  951. try_return( Status );
  952. }
  953. RxAdjustAllocationSizeforCC( Fcb );
  954. //
  955. // Now initialize the cache map.
  956. //
  957. try {
  958. Status = STATUS_SUCCESS;
  959. CcInitializeCacheMap( FileObject,
  960. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
  961. FALSE,
  962. &RxData.CacheManagerCallbacks,
  963. Fcb );
  964. } except(EXCEPTION_EXECUTE_HANDLER) {
  965. Status = GetExceptionCode();
  966. }
  967. if (Status != STATUS_SUCCESS) {
  968. try_return( Status );
  969. }
  970. CcSetReadAheadGranularity( FileObject,
  971. NetRoot->DiskParameters.ReadAheadGranularity );
  972. }
  973. //
  974. // For local file systems, there's a call here to zero data from VDL
  975. // to starting VBO....for remote FSs, that happens on the other end.
  976. //
  977. //
  978. // DO A NORMAL CACHED WRITE, if the MDL bit is not set,
  979. //
  980. if (!FlagOn( RxContext->MinorFunction, IRP_MN_MDL )) {
  981. PVOID SystemBuffer;
  982. #if DBG
  983. ULONG SaveExceptionFlag;
  984. #endif
  985. RxDbgTrace( 0, Dbg, ("Cached write.\n", 0) );
  986. //
  987. // Get hold of the user's buffer.
  988. //
  989. SystemBuffer = RxMapUserBuffer( RxContext, Irp );
  990. if (SystemBuffer == NULL) {
  991. Status = STATUS_INSUFFICIENT_RESOURCES;
  992. try_return( Status );
  993. }
  994. //
  995. // Make sure that a returned exception clears the breakpoint in the filter
  996. //
  997. RxSaveAndSetExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
  998. //
  999. // Do the write, possibly writing through
  1000. //
  1001. RxItsTheSameContext();
  1002. if (!CcCopyWrite( FileObject,
  1003. &StartingByte,
  1004. ByteCount,
  1005. Wait,
  1006. SystemBuffer )) {
  1007. RxDbgTrace( 0, Dbg, ("Cached Write could not wait\n", 0) );
  1008. RxRestoreExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
  1009. RxItsTheSameContext();
  1010. RxLog(( "CcCW2 FO %lx Of %lx Si %lx St %lx\n", FileObject, Fcb->Header.FileSize.LowPart, ByteCount, Status ));
  1011. RxWmiLog( LOG,
  1012. RxCommonWrite_6,
  1013. LOGPTR( FileObject )
  1014. LOGULONG( Fcb->Header.FileSize.LowPart )
  1015. LOGULONG( ByteCount )
  1016. LOGULONG( Status ));
  1017. try_return( SET_POSTIRP("cccopywritefailed") );
  1018. }
  1019. Irp->IoStatus.Status = STATUS_SUCCESS;
  1020. Irp->IoStatus.Information = ByteCount;
  1021. RxRestoreExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
  1022. RxItsTheSameContext();
  1023. RxLog(( "CcCW3 FO %lx Of %lx Si %lx St %lx\n", FileObject, Fcb->Header.FileSize.LowPart, ByteCount, Status ));
  1024. RxWmiLog( LOG,
  1025. RxCommonWrite_7,
  1026. LOGPTR( FileObject )
  1027. LOGULONG( Fcb->Header.FileSize.LowPart )
  1028. LOGULONG( ByteCount )
  1029. LOGULONG( Status ) );
  1030. try_return( Status = STATUS_SUCCESS );
  1031. } else {
  1032. //
  1033. // DO AN MDL WRITE
  1034. //
  1035. RxDbgTrace( 0, Dbg, ("MDL write.\n", 0) );
  1036. ASSERT( FALSE ); // NOT YET IMPLEMENTED
  1037. ASSERT( Wait );
  1038. CcPrepareMdlWrite( FileObject,
  1039. &StartingByte,
  1040. ByteCount,
  1041. &Irp->MdlAddress,
  1042. &Irp->IoStatus );
  1043. Status = Irp->IoStatus.Status;
  1044. try_return( Status );
  1045. }
  1046. }
  1047. //
  1048. // HANDLE THE NON-CACHED CASE
  1049. //
  1050. if (SwitchBackToAsync) {
  1051. Wait = FALSE;
  1052. SynchronousIo = FALSE;
  1053. ClearFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  1054. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  1055. }
  1056. if (!SynchronousIo) {
  1057. //
  1058. // here we have to setup for async writes. there is a special dance in acquiring
  1059. // the fcb that looks at these variables..........
  1060. //
  1061. //
  1062. // only init on the first usage
  1063. //
  1064. if (!Fcb->NonPaged->OutstandingAsyncEvent) {
  1065. Fcb->NonPaged->OutstandingAsyncEvent = &Fcb->NonPaged->TheActualEvent;
  1066. KeInitializeEvent( Fcb->NonPaged->OutstandingAsyncEvent, NotificationEvent, FALSE );
  1067. }
  1068. //
  1069. // If we are transitioning from 0 to 1, reset the event.
  1070. //
  1071. if (ExInterlockedAddUlong( &Fcb->NonPaged->OutstandingAsyncWrites, 1, &RxStrucSupSpinLock ) == 0) {
  1072. KeResetEvent( Fcb->NonPaged->OutstandingAsyncEvent );
  1073. }
  1074. //
  1075. // this says that we counted an async write
  1076. //
  1077. UnwindOutstandingAsync = TRUE;
  1078. LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged;
  1079. }
  1080. LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
  1081. LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
  1082. RxDbgTrace( 0, Dbg,("RxCommonWriteJustBeforeCalldown %s%s%s lowiononpaged is \n",
  1083. RxContext->FcbResourceAcquired ?"FcbAcquired ":"",
  1084. RxContext->FcbPagingIoResourceAcquired ?"PagingIoResourceAcquired ":"",
  1085. (LowIoContext->ParamsFor.ReadWrite.NonPagedFcb)?"NonNull":"Null" ));
  1086. RxItsTheSameContext();
  1087. ASSERT ( RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired );
  1088. //
  1089. // If we are in FSP, set the resource owner so that the reosurce package doesnt
  1090. // try to boost the priority of the owner thread. There is no guarantee that the
  1091. // FSP thred will remain alive while the I/O is pending.
  1092. //
  1093. if(InFsp) {
  1094. LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
  1095. if ( RxContext->FcbResourceAcquired ) {
  1096. ExSetResourceOwnerPointer( Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId );
  1097. }
  1098. if ( RxContext->FcbPagingIoResourceAcquired ) {
  1099. ExSetResourceOwnerPointer( Fcb->Header.PagingIoResource, (PVOID)LowIoContext->ResourceThreadId );
  1100. }
  1101. fSetResourceOwner = TRUE;
  1102. }
  1103. Status = RxLowIoWriteShell( RxContext, Irp, Fcb );
  1104. RxItsTheSameContext();
  1105. if (UnwindOutstandingAsync && (Status == STATUS_PENDING)) {
  1106. UnwindOutstandingAsync = FALSE;
  1107. }
  1108. try_return( Status );
  1109. try_exit: NOTHING;
  1110. ASSERT( Irp );
  1111. RxItsTheSameContext();
  1112. if (!PostIrp) {
  1113. RxDbgTrace( 0, Dbg, ("CommonWrite InnerFinally-> %08lx,%08lx\n",
  1114. Status, Irp->IoStatus.Information) );
  1115. if (!PipeWrite) {
  1116. //
  1117. // Record the total number of bytes actually written
  1118. //
  1119. if (!PagingIo && NT_SUCCESS( Status ) &&
  1120. FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO )) {
  1121. FileObject->CurrentByteOffset.QuadPart = StartingVbo + Irp->IoStatus.Information;
  1122. }
  1123. //
  1124. // The following are things we only do if we were successful
  1125. //
  1126. if (NT_SUCCESS( Status ) && (Status != STATUS_PENDING)) {
  1127. //
  1128. // If this was not PagingIo, mark that the modify
  1129. // time on the dirent needs to be updated on close.
  1130. //
  1131. if (!PagingIo) {
  1132. SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
  1133. }
  1134. if (ExtendingFile) {
  1135. SetFlag( FileObject->Flags, FO_FILE_SIZE_CHANGED );
  1136. }
  1137. if (ExtendingValidData) {
  1138. LONGLONG EndingVboWritten = StartingVbo + Irp->IoStatus.Information;
  1139. //
  1140. // Never set a ValidDataLength greater than FileSize.
  1141. //
  1142. if (FileSize < EndingVboWritten) {
  1143. Fcb->Header.ValidDataLength.QuadPart = FileSize;
  1144. } else {
  1145. Fcb->Header.ValidDataLength.QuadPart = EndingVboWritten;
  1146. }
  1147. //
  1148. // Now, if we are noncached and the file is cached, we must
  1149. // tell the cache manager about the VDL extension so that
  1150. // async cached IO will not be optimized into zero-page faults
  1151. // beyond where it believes VDL is.
  1152. //
  1153. // In the cached case, since Cc did the work, it has updated
  1154. // itself already.
  1155. //
  1156. if (NonCachedIo && CcIsFileCached( FileObject )) {
  1157. CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  1158. }
  1159. }
  1160. }
  1161. }
  1162. } else {
  1163. //
  1164. // Take action on extending writes if we're going to post
  1165. //
  1166. if (ExtendingFile && !PipeWrite) {
  1167. ASSERT( RxWriteCachingAllowed( Fcb,SrvOpen ) );
  1168. //
  1169. // We need the PagingIo resource exclusive whenever we
  1170. // pull back either file size or valid data length.
  1171. //
  1172. ASSERT( Fcb->Header.PagingIoResource != NULL );
  1173. RxAcquirePagingIoResource( RxContext, Fcb );
  1174. RxSetFileSizeWithLock( Fcb, &InitialFileSize );
  1175. RxReleasePagingIoResource( RxContext, Fcb );
  1176. //
  1177. // Pull back the cache map as well
  1178. //
  1179. if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
  1180. *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
  1181. }
  1182. }
  1183. RxDbgTrace( 0, Dbg, ("Passing request to Fsp\n", 0) );
  1184. InterlockedIncrement( &RxContext->ReferenceCount );
  1185. RefdContextForTracker = TRUE;
  1186. //
  1187. // we only do this here because we're having a problem finding out why resources
  1188. // are not released.
  1189. //
  1190. //
  1191. // release whatever resources we may have
  1192. //
  1193. ASSERT(fSetResourceOwner == FALSE);
  1194. RxWriteReleaseResources( RxContext, Fcb, fSetResourceOwner );
  1195. #ifdef RDBSS_TRACKER
  1196. if (RxContext->AcquireReleaseFcbTrackerX != 0) {
  1197. DbgPrint("TrackerNBadBeforePost %08lx %08lx\n",RxContext,&PostIrp);
  1198. ASSERT(!"BadTrackerBeforePost");
  1199. }
  1200. #endif // ifdef RDBSS_TRACKER
  1201. Status = RxFsdPostRequest( RxContext );
  1202. }
  1203. } finally {
  1204. DebugUnwind( RxCommonWrite );
  1205. if (AbnormalTermination()) {
  1206. //
  1207. // Restore initial file size and valid data length
  1208. //
  1209. if ((ExtendingFile || ExtendingValidData) && !PipeWrite) {
  1210. //
  1211. // We got an error, pull back the file size if we extended it.
  1212. //
  1213. // We need the PagingIo resource exclusive whenever we
  1214. // pull back either file size or valid data length.
  1215. //
  1216. ASSERT( Fcb->Header.PagingIoResource != NULL );
  1217. RxAcquirePagingIoResource( RxContext, Fcb );
  1218. RxSetFileSizeWithLock( Fcb, &InitialFileSize );
  1219. Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength;
  1220. RxReleasePagingIoResource( RxContext, Fcb );
  1221. //
  1222. // Pull back the cache map as well
  1223. //
  1224. if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
  1225. *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
  1226. }
  1227. }
  1228. }
  1229. //
  1230. // Check if this needs to be backed out.
  1231. //
  1232. if (UnwindOutstandingAsync) {
  1233. ASSERT( !PipeWrite );
  1234. ExInterlockedAddUlong( &Fcb->NonPaged->OutstandingAsyncWrites,
  1235. 0xffffffff,
  1236. &RxStrucSupSpinLock );
  1237. KeSetEvent( LowIoContext->ParamsFor.ReadWrite.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
  1238. }
  1239. #if 0
  1240. //
  1241. // If we did an MDL write, and we are going to complete the request
  1242. // successfully, keep the resource acquired, reducing to shared
  1243. // if it was acquired exclusive.
  1244. //
  1245. if (FlagOn( RxContext->MinorFunction, IRP_MN_MDL ) &&
  1246. !PostIrp &&
  1247. !AbnormalTermination() &&
  1248. NT_SUCCESS( Status )) {
  1249. ASSERT( FcbAcquired && !PagingIoResourceAcquired );
  1250. FcbAcquired = FALSE;
  1251. if (FcbAcquiredExclusive) {
  1252. ExConvertExclusiveToSharedLite( Fcb->Header.Resource );
  1253. }
  1254. }
  1255. #endif
  1256. //
  1257. // If resources have been acquired, release them under the right conditions.
  1258. // the right conditions are these:
  1259. // 1) if we have abnormal termination. here we obviously release the since no one else will.
  1260. // 2) if the underlying call did not succeed: Status==Pending.
  1261. // 3) if we posted the request
  1262. //
  1263. if (AbnormalTermination() || (Status != STATUS_PENDING) || PostIrp) {
  1264. if (!PostIrp) {
  1265. //
  1266. // release whatever resources we may have
  1267. //
  1268. RxWriteReleaseResources( RxContext, Fcb, fSetResourceOwner );
  1269. }
  1270. if (RefdContextForTracker) {
  1271. RxDereferenceAndDeleteRxContext( RxContext );
  1272. }
  1273. if (!PostIrp) {
  1274. if (FlagOn( RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION )) {
  1275. RxResumeBlockedOperations_Serially( RxContext, &Fobx->Specific.NamedPipe.WriteSerializationQueue );
  1276. }
  1277. }
  1278. if (Status == STATUS_SUCCESS) {
  1279. ASSERT( Irp->IoStatus.Information <= IrpSp->Parameters.Write.Length );
  1280. }
  1281. } else {
  1282. //
  1283. // here the guy below is going to handle the completion....but, we don't know the finish
  1284. // order....in all likelihood the deletecontext call below just reduces the refcount
  1285. // but the guy may already have finished in which case this will really delete the context.
  1286. //
  1287. ASSERT( !SynchronousIo );
  1288. RxDereferenceAndDeleteRxContext( RxContext );
  1289. }
  1290. RxDbgTrace( -1, Dbg, ("CommonWrite -> %08lx\n", Status) );
  1291. if ((Status != STATUS_PENDING) && (Status != STATUS_SUCCESS) && PagingIo) {
  1292. RxLogRetail(( "PgWrtFail %x %x %x\n", Fcb, NetRoot, Status ));
  1293. InterlockedIncrement( &LDWCount );
  1294. KeQuerySystemTime( &LDWLastTime );
  1295. LDWLastStatus = Status;
  1296. LDWContext = Fcb;
  1297. }
  1298. } // finally
  1299. return Status;
  1300. }
  1301. //
  1302. // Internal support routine
  1303. //
  1304. NTSTATUS
  1305. RxLowIoWriteShellCompletion (
  1306. IN PRX_CONTEXT RxContext
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. This routine postprocesses a write request after it comes back from the
  1311. minirdr. It does callouts to handle compression, buffering and
  1312. shadowing. It is the opposite number of LowIoWriteShell.
  1313. This will be called from LowIo; for async, originally in the
  1314. completion routine. If RxStatus(MORE_PROCESSING_REQUIRED) is returned,
  1315. LowIo will call again in a thread. If this was syncIo, you'll be back
  1316. in the user's thread; if async, lowIo will requeue to a thread.
  1317. Currrently, we always get to a thread before anything; this is a bit slower
  1318. than completing at DPC time,
  1319. but it's aheckuva lot safer and we may often have stuff to do
  1320. (like decompressing, shadowing, etc) that we don't want to do at DPC
  1321. time.
  1322. Arguments:
  1323. RxContext - the usual
  1324. Return Value:
  1325. whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
  1326. --*/
  1327. {
  1328. NTSTATUS Status;
  1329. PIRP Irp = RxContext->CurrentIrp;
  1330. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1331. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1332. PFCB Fcb;
  1333. PFOBX Fobx;
  1334. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  1335. BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION );
  1336. BOOLEAN PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
  1337. BOOLEAN PipeOperation = BooleanFlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION );
  1338. BOOLEAN SynchronousPipe = BooleanFlagOn( RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
  1339. PAGED_CODE();
  1340. RxDecodeFileObject( FileObject, &Fcb, &Fobx );
  1341. Status = RxContext->StoredStatus;
  1342. Irp->IoStatus.Information = RxContext->InformationToReturn;
  1343. RxDbgTrace( +1, Dbg, ("RxLowIoWriteShellCompletion entry Status = %08lx\n", Status ));
  1344. RxLog(( "WtShlComp %lx %lx %lx\n", RxContext, Status, Irp->IoStatus.Information ));
  1345. RxWmiLog( LOG,
  1346. RxLowIoWriteShellCompletion_1,
  1347. LOGPTR( RxContext )
  1348. LOGULONG( Status )
  1349. LOGPTR( Irp->IoStatus.Information ) );
  1350. ASSERT( RxLowIoIsBufferLocked( LowIoContext ) );
  1351. switch (Status) {
  1352. case STATUS_SUCCESS:
  1353. if(FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED )){
  1354. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED )) {
  1355. //
  1356. // NOT YET IMPLEMENTED should decompress and put away
  1357. //
  1358. ASSERT( FALSE );
  1359. } else if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED )) {
  1360. //
  1361. // NOT YET IMPLEMENTED should decompress and put away
  1362. //
  1363. ASSERT(FALSE);
  1364. }
  1365. }
  1366. #ifdef RX_WJ_DBG_SUPPORT
  1367. RxdUpdateJournalOnLowIoWriteCompletion( Fcb, IrpSp->Parameters.Write.ByteOffset, IrpSp->Parameters.Write.Length );
  1368. #endif
  1369. break;
  1370. case STATUS_FILE_LOCK_CONFLICT:
  1371. break;
  1372. case STATUS_CONNECTION_INVALID:
  1373. //
  1374. // NOT YET IMPLEMENTED here is where the failover will happen
  1375. // first we give the local guy current minirdr another chance...then we go
  1376. // to fullscale retry
  1377. // return(RxStatus(DISCONNECTED)); //special....let LowIo get us back
  1378. break;
  1379. }
  1380. if (Status != STATUS_SUCCESS) {
  1381. if (PagingIo) {
  1382. RxLogRetail(( "PgWrtFail %x %x %x\n", Fcb, Fcb->NetRoot, Status ));
  1383. InterlockedIncrement( &LDWCount );
  1384. KeQuerySystemTime( &LDWLastTime );
  1385. LDWLastStatus = Status;
  1386. LDWContext = Fcb;
  1387. }
  1388. }
  1389. if (FlagOn( LowIoContext->Flags,LOWIO_CONTEXT_FLAG_SYNCCALL )){
  1390. //
  1391. // if we're being called from lowioubmit then just get out
  1392. //
  1393. RxDbgTrace( -1, Dbg, ("RxLowIoWriteShellCompletion syncexit Status = %08lx\n", Status) );
  1394. return Status;
  1395. }
  1396. //
  1397. // otherwise we have to do the end of the write from here
  1398. //
  1399. if (NT_SUCCESS( Status ) && !PipeOperation) {
  1400. ASSERT( Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount );
  1401. //
  1402. // If this was not PagingIo, mark that the modify
  1403. // time on the dirent needs to be updated on close.
  1404. //
  1405. if (!PagingIo) {
  1406. SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
  1407. }
  1408. if (FlagOn( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE )) {
  1409. SetFlag( FileObject->Flags, FO_FILE_SIZE_CHANGED );
  1410. }
  1411. if (FlagOn( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL )) {
  1412. //
  1413. // this flag will not be set unless we have a valid filesize and therefore the starting
  1414. // vbo will not be write-to-end-of-file
  1415. //
  1416. LONGLONG StartingVbo = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  1417. LONGLONG EndingVboWritten = StartingVbo + Irp->IoStatus.Information;
  1418. LONGLONG FileSize;
  1419. //
  1420. // Never set a ValidDataLength greater than FileSize.
  1421. //
  1422. RxGetFileSizeWithLock( Fcb, &FileSize );
  1423. if (FileSize < EndingVboWritten) {
  1424. Fcb->Header.ValidDataLength.QuadPart = FileSize;
  1425. } else {
  1426. Fcb->Header.ValidDataLength.QuadPart = EndingVboWritten;
  1427. }
  1428. }
  1429. }
  1430. if ((!SynchronousPipe) &&
  1431. (LowIoContext->ParamsFor.ReadWrite.NonPagedFcb != NULL) &&
  1432. (ExInterlockedAddUlong( &LowIoContext->ParamsFor.ReadWrite.NonPagedFcb->OutstandingAsyncWrites, 0xffffffff, &RxStrucSupSpinLock ) == 1) ) {
  1433. KeSetEvent( LowIoContext->ParamsFor.ReadWrite.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
  1434. }
  1435. if (RxContext->FcbPagingIoResourceAcquired) {
  1436. RxReleasePagingIoResourceForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  1437. }
  1438. if ((!SynchronousPipe) && (RxContext->FcbResourceAcquired)) {
  1439. RxReleaseFcbForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  1440. }
  1441. if (SynchronousPipe) {
  1442. RxResumeBlockedOperations_Serially( RxContext, &Fobx->Specific.NamedPipe.WriteSerializationQueue );
  1443. }
  1444. ASSERT( Status != STATUS_RETRY );
  1445. ASSERT( (Status != STATUS_SUCCESS) ||
  1446. (Irp->IoStatus.Information <= IrpSp->Parameters.Write.Length ));
  1447. ASSERT( RxContext->MajorFunction == IRP_MJ_WRITE );
  1448. if (PipeOperation) {
  1449. if (Irp->IoStatus.Information != 0) {
  1450. //
  1451. // if we have been throttling on this pipe, stop because our writing to the pipe may
  1452. // cause the pipeserver (not smbserver) on the other end to unblock so we should go back
  1453. // and see
  1454. //
  1455. RxTerminateThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
  1456. RxLog(( "WThrottlNo %lx %lx %lx %ld\n", RxContext, Fobx, &Fobx->Specific.NamedPipe.ThrottlingState, Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
  1457. RxWmiLog( LOG,
  1458. RxLowIoWriteShellCompletion_2,
  1459. LOGPTR( RxContext )
  1460. LOGPTR( Fobx )
  1461. LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
  1462. }
  1463. }
  1464. RxDbgTrace( -1, Dbg, ("RxLowIoWriteShellCompletion exit Status = %08lx\n", Status) );
  1465. return Status;
  1466. }
  1467. NTSTATUS
  1468. RxLowIoWriteShell (
  1469. IN PRX_CONTEXT RxContext,
  1470. IN PIRP Irp,
  1471. IN PFCB Fcb
  1472. )
  1473. /*++
  1474. Routine Description:
  1475. This routine preprocesses a write request before it goes down to the minirdr.
  1476. It does callouts to handle compression, buffering and shadowing. It is the
  1477. opposite number of LowIoWriteShellCompletion. By the time we get here, we are
  1478. going to the wire. Write buffering was already tried in the UncachedWrite strategy
  1479. Arguments:
  1480. RxContext - the usual
  1481. Return Value:
  1482. whatever value is returned by a callout....or by LowIo.
  1483. --*/
  1484. {
  1485. NTSTATUS Status;
  1486. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1487. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  1488. PAGED_CODE();
  1489. RxDbgTrace( +1, Dbg, ("RxLowIoWriteShell entry %08lx\n", 0) );
  1490. RxLog(( "WrtShl in %lx\n", RxContext ));
  1491. RxWmiLog( LOG,
  1492. RxLowIoWriteShell_1,
  1493. LOGPTR( RxContext ) );
  1494. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED )) {
  1495. //
  1496. // NOT YET IMPLEMENTED should translated to a buffered but not held diskcompressed write
  1497. //
  1498. ASSERT( FALSE );
  1499. } else if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED )) {
  1500. //
  1501. // NOT YET IMPLEMENTED should translated to a buffered and bufcompressed write
  1502. //
  1503. ASSERT( FALSE );
  1504. }
  1505. if (Fcb->CachedNetRootType == NET_ROOT_DISK) {
  1506. ExInterlockedAddLargeStatistic( &RxContext->RxDeviceObject->NetworkReadBytesRequested, LowIoContext->ParamsFor.ReadWrite.ByteCount );
  1507. }
  1508. #ifdef RX_WJ_DBG_SUPPORT
  1509. RxdUpdateJournalOnLowIoWriteInitiation( Fcb, IrpSp->Parameters.Write.ByteOffset, IrpSp->Parameters.Write.Length );
  1510. #endif
  1511. Status = RxLowIoSubmit( RxContext, Irp, Fcb, RxLowIoWriteShellCompletion );
  1512. RxDbgTrace( -1, Dbg, ("RxLowIoWriteShell exit Status = %08lx\n", Status) );
  1513. RxLog(( "WrtShl out %lx %lx\n", RxContext, Status ));
  1514. RxWmiLog( LOG,
  1515. RxLowIoWriteShell_2,
  1516. LOGPTR( RxContext )
  1517. LOGULONG( Status ) );
  1518. return Status;
  1519. }