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.

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