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.

910 lines
30 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Cleanup.c
  5. Abstract:
  6. This module implements the File Cleanup routine for Rx called by the
  7. dispatch driver.
  8. Author:
  9. Joe Linn [JoeLinn] 12-sep-94
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // The Bug check file id for this module
  16. //
  17. #define BugCheckFileId (RDBSS_BUG_CHECK_CLEANUP)
  18. //
  19. // The local debug trace level
  20. //
  21. #define Dbg (DEBUG_TRACE_CLEANUP)
  22. BOOLEAN
  23. RxUninitializeCacheMap(
  24. IN OUT PRX_CONTEXT RxContext,
  25. IN PFILE_OBJECT FileObject,
  26. IN PLARGE_INTEGER TruncateSize
  27. );
  28. #if DBG
  29. //this is just a dbg thing
  30. extern
  31. BOOLEAN
  32. RxLockEnumerator (
  33. IN OUT struct _MRX_SRV_OPEN_ * SrvOpen,
  34. IN OUT PVOID *ContinuationHandle,
  35. OUT PLARGE_INTEGER FileOffset,
  36. OUT PLARGE_INTEGER LockRange,
  37. OUT PBOOLEAN IsLockExclusive
  38. );
  39. BOOLEAN
  40. RxFakeLockEnumerator (
  41. IN OUT struct _SRV_OPEN * SrvOpen,
  42. IN OUT PVOID *ContinuationHandle,
  43. OUT PLARGE_INTEGER FileOffset,
  44. OUT PLARGE_INTEGER LockRange,
  45. OUT PBOOLEAN IsLockExclusive
  46. );
  47. VOID
  48. RxDumpSerializationQueue(
  49. PLIST_ENTRY SQ,
  50. PSZ TagText1,
  51. PSZ TagText2
  52. );
  53. #ifdef ALLOC_PRAGMA
  54. #pragma alloc_text(PAGE, RxDumpSerializationQueue)
  55. #endif
  56. #endif //if DBG
  57. VOID
  58. RxCleanupPipeQueues (
  59. IN PRX_CONTEXT RxContext
  60. );
  61. #ifdef ALLOC_PRAGMA
  62. #pragma alloc_text(PAGE, RxCommonCleanup)
  63. #pragma alloc_text(PAGE, RxAdjustFileTimesAndSize)
  64. #pragma alloc_text(PAGE, RxCleanupPipeQueues)
  65. #pragma alloc_text(PAGE, RxUninitializeCacheMap)
  66. #endif
  67. NTSTATUS
  68. RxCommonCleanup ( RXCOMMON_SIGNATURE )
  69. /*++
  70. Routine Description:
  71. This is the common routine for cleanup of a file/directory called by
  72. both the fsd and fsp threads.
  73. Cleanup is invoked whenever the last handle to a file object is
  74. closed. This is different than the Close operation which is invoked
  75. when the last reference to a file object is deleted.
  76. The function of cleanup is to essentially "cleanup" the
  77. file/directory after a user is done with it. The Fcb/Dcb remains
  78. around (because MM still has the file object referenced) but is now
  79. available for another user to open (i.e., as far as the user is
  80. concerned the file object is now closed). See close for a more complete
  81. description of what close does.
  82. Please see the discussion in openclos.txt.
  83. Arguments:
  84. Irp - Supplies the Irp to process
  85. Return Value:
  86. RXSTATUS - The return status for the operation
  87. --*/
  88. {
  89. NTSTATUS Status;
  90. RxCaptureRequestPacket;
  91. RxCaptureFcb;
  92. RxCaptureFobx;
  93. RxCaptureParamBlock;
  94. RxCaptureFileObject;
  95. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  96. NET_ROOT_TYPE NetRootType;
  97. PNET_ROOT NetRoot;
  98. PSHARE_ACCESS ShareAccess = NULL;
  99. PLARGE_INTEGER TruncateSize = NULL;
  100. LARGE_INTEGER LocalTruncateSize;
  101. BOOLEAN UninitializeCacheMap = FALSE;
  102. BOOLEAN LastUncleanOnGoodFcb = FALSE;
  103. BOOLEAN NeedPurge = FALSE;
  104. BOOLEAN NeedDelete = FALSE;
  105. BOOLEAN AcquiredFcb = FALSE;
  106. BOOLEAN AcquiredTableLock = FALSE;
  107. PAGED_CODE();
  108. RxDbgTrace(+1, Dbg, ("RxCommonCleanup IrpC/Fobx/Fcb/FileObj = %08lx %08lx %08lx %08lx\n",
  109. RxContext,capFobx,capFcb,capFileObject));
  110. RxLog(("CommonCleanup %lx %lx %lx\n",RxContext,capFobx,capFcb));
  111. // If this cleanup is for the case of directories opened for renames etc.,
  112. // where there is no file object cleanup succeeds immediately.
  113. if (!capFobx) {
  114. if (capFcb->UncleanCount > 0) {
  115. InterlockedDecrement(&capFcb->UncleanCount);
  116. }
  117. //RxMarkFcbForScavengingAtCleanup(capFcb);
  118. RxDbgTrace(-1, Dbg, ("Cleanup nullfobx open\n", 0));
  119. return(STATUS_SUCCESS);
  120. }
  121. // Cleanup applies to certain types of opens. If it is not one of those
  122. // abort immediately.
  123. if ((TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) &&
  124. (TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) &&
  125. (TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_UNKNOWN) &&
  126. (TypeOfOpen != RDBSS_NTC_SPOOLFILE)) {
  127. RxLog(("RxCC Invalid Open %lx %lx %lx\n",RxContext,capFobx,capFcb));
  128. RxBugCheck( TypeOfOpen, 0, 0 );
  129. }
  130. // Ensure that the object has not been cleaned up before. This should
  131. // never occur.
  132. ASSERT( !FlagOn( capFileObject->Flags, FO_CLEANUP_COMPLETE ));
  133. RxMarkFobxOnCleanup(capFobx,&NeedPurge);
  134. // Acquire the FCB. In most cases no further resource acquisition is required
  135. // to complete the cleanup operation. The only exceptions are when the file
  136. // was initially opened with the DELETE_ON_CLOSE option. In such cases the
  137. // FCB table lock of the associated NET_ROOT instance is required.
  138. Status = RxAcquireExclusiveFcb( RxContext, capFcb );
  139. if (Status != STATUS_SUCCESS) {
  140. RxDbgTrace(-1, Dbg, ("RxCommonCleanup Failed to acquire FCB -> %lx\n)", Status));
  141. return Status;
  142. }
  143. AcquiredFcb = TRUE;
  144. capFobx->AssociatedFileObject = NULL;
  145. if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) {
  146. ASSERT( capFcb->UncleanCount );
  147. InterlockedDecrement(&capFcb->UncleanCount);
  148. if (FlagOn(capFileObject->Flags,FO_NO_INTERMEDIATE_BUFFERING)) {
  149. capFcb->UncachedUncleanCount--;
  150. }
  151. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxCleanupFobx,(RxContext));
  152. ASSERT( capFobx->SrvOpen->UncleanFobxCount );
  153. capFobx->SrvOpen->UncleanFobxCount--;
  154. RxUninitializeCacheMap( RxContext, capFileObject, NULL );
  155. RxReleaseFcb(RxContext,capFcb);
  156. return STATUS_SUCCESS;
  157. }
  158. NetRoot = (PNET_ROOT)capFcb->pNetRoot;
  159. NetRootType = capFcb->pNetRoot->Type ;
  160. if ( FlagOn(capFobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE) ) {
  161. SetFlag( capFcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  162. }
  163. RxCancelNotifyChangeDirectoryRequestsForFobx(capFobx);
  164. ShareAccess = &capFcb->ShareAccess;
  165. LastUncleanOnGoodFcb = (capFcb->UncleanCount == 1);
  166. if (LastUncleanOnGoodFcb && FlagOn(capFcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) {
  167. // if we can't get it right way, drop the Fcb and acquire/acquire
  168. // to perserve lock order. No one else can change the counts while we have
  169. // the fcb lock; neither can a file become DELETE_ON_CLOSE or be opened via
  170. // CommonCreate. If we are not deleting, get rid of the tablelock after we
  171. // verify the count.
  172. if ( RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE) ) {
  173. // this is the fast way....hope it works
  174. AcquiredTableLock = TRUE;
  175. } else {
  176. // Release the FCB and reqcquire the locks in the correct order.
  177. // PrefixTableLock followed by the FCB.
  178. AcquiredFcb = FALSE;
  179. RxReleaseFcb( RxContext, capFcb );
  180. (VOID)RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
  181. AcquiredTableLock = TRUE;
  182. Status = RxAcquireExclusiveFcb( RxContext, capFcb );
  183. if (Status != STATUS_SUCCESS) {
  184. AcquiredTableLock = FALSE;
  185. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  186. RxDbgTrace(-1, Dbg, ("RxCommonCleanup Failed to acquire FCB -> %lx\n)", Status));
  187. return Status;
  188. }
  189. AcquiredFcb = TRUE;
  190. }
  191. if (capFcb->UncleanCount != 1) {
  192. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  193. AcquiredTableLock = FALSE;
  194. NeedDelete = FALSE;
  195. } else {
  196. NeedDelete = TRUE;
  197. }
  198. }
  199. try {
  200. switch (NetRootType) {
  201. case NET_ROOT_PIPE:
  202. case NET_ROOT_PRINT:
  203. {
  204. // If the file object corresponds to a pipe or spool file additional
  205. // cleanup operations are required. This deals with the special
  206. // serialization mechanism for pipes.
  207. RxCleanupPipeQueues(RxContext);
  208. }
  209. break;
  210. case NET_ROOT_DISK:
  211. {
  212. switch (TypeOfOpen) {
  213. case RDBSS_NTC_STORAGE_TYPE_FILE :
  214. {
  215. // If the file object corresponds to a disk file, assert the locks
  216. // and update the associated file times and sizes.
  217. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  218. LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
  219. FsRtlFastUnlockAll(
  220. &capFcb->Specific.Fcb.FileLock,
  221. capFileObject,
  222. IoGetRequestorProcess( capReqPacket ),
  223. RxContext );
  224. if (LowIoContext->ParamsFor.Locks.LockList != NULL) {
  225. RxDbgTrace(0, Dbg, ("--->before init, locklist=%08lx\n", LowIoContext->ParamsFor.Locks.LockList));
  226. RxInitializeLowIoContext(LowIoContext,LOWIO_OP_UNLOCK_MULTIPLE);
  227. LowIoContext->ParamsFor.Locks.Flags = 0; //no flags
  228. Status = RxLowIoLockControlShell(RxContext);
  229. }
  230. RxAdjustFileTimesAndSize(RXCOMMON_ARGUMENTS);
  231. // If the file object corresponds to a disk file/directory and this
  232. // is the last cleanup call for the FCB additional processing is required.
  233. if (LastUncleanOnGoodFcb) {
  234. try {
  235. // If the file object was marked DELETE_ON_CLOSE set the file size to
  236. // zero ( synchronizing with the paging resource)
  237. if (NeedDelete) {
  238. RxAcquirePagingIoResource(capFcb,RxContext);
  239. capFcb->Header.FileSize.QuadPart = 0;
  240. if (TypeOfOpen == RDBSS_NTC_STORAGE_TYPE_FILE) {
  241. capFcb->Header.ValidDataLength.QuadPart = 0;
  242. }
  243. RxReleasePagingIoResource(capFcb,RxContext);
  244. } else {
  245. // If the file object was not marked for deletion and it is not
  246. // a paging file ensure that the portion between the valid data
  247. // length and the file size is zero extended.
  248. if (!FlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE) &&
  249. (capFcb->Header.ValidDataLength.QuadPart <
  250. capFcb->Header.FileSize.QuadPart)) {
  251. RxDbgTrace(0, Dbg, ("---------->zeroextend!!!!!!!\n", 0));
  252. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxZeroExtend,(RxContext));
  253. capFcb->Header.ValidDataLength.QuadPart =
  254. capFcb->Header.FileSize.QuadPart;
  255. }
  256. }
  257. // If the file object was marked for truncation capture the
  258. // sizes for uninitializing the cache maps subsequently.
  259. if (FlagOn(capFcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE)) {
  260. RxDbgTrace(0, Dbg, ("truncate file allocation\n", 0));
  261. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxTruncate,(RxContext));
  262. // Setup to truncate the Cache Map because
  263. // this is the only way we have of trashing the
  264. // truncated pages.
  265. LocalTruncateSize = capFcb->Header.FileSize;
  266. TruncateSize = &LocalTruncateSize;
  267. // Mark the Fcb as having now been truncated, just
  268. // in case we have to reprocess this later.
  269. capFcb->FcbState &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
  270. }
  271. } except ( CATCH_EXPECTED_EXCEPTIONS ) {
  272. DbgPrint("!!! Handling Exceptions\n");
  273. NOTHING;
  274. }
  275. }
  276. // Purging can be done now if this FCB does not support collapsed opens
  277. if (!NeedPurge) {
  278. NeedPurge = (LastUncleanOnGoodFcb &&
  279. (NeedDelete ||
  280. !FlagOn(capFcb->FcbState,FCB_STATE_COLLAPSING_ENABLED)));
  281. } else {
  282. if (!LastUncleanOnGoodFcb) {
  283. NeedPurge = FALSE;
  284. }
  285. }
  286. UninitializeCacheMap = TRUE;
  287. }
  288. break;
  289. case RDBSS_NTC_STORAGE_TYPE_DIRECTORY :
  290. case RDBSS_NTC_STORAGE_TYPE_UNKNOWN :
  291. default:
  292. break;
  293. }
  294. }
  295. break;
  296. default:
  297. break;
  298. }
  299. // We've just finished everything associated with an unclean
  300. // fcb so now decrement the unclean count before releasing
  301. // the resource.
  302. ASSERT( capFcb->UncleanCount );
  303. InterlockedDecrement(&capFcb->UncleanCount);
  304. if (FlagOn(capFileObject->Flags,FO_NO_INTERMEDIATE_BUFFERING)) {
  305. capFcb->UncachedUncleanCount--;
  306. }
  307. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxCleanupFobx,(RxContext));
  308. ASSERT( capFobx->SrvOpen->UncleanFobxCount );
  309. capFobx->SrvOpen->UncleanFobxCount--;
  310. // If this was the last cached open, and there are open
  311. // non-cached handles, attempt a flush and purge operation
  312. // to avoid cache coherency overhead from these non-cached
  313. // handles later. We ignore any I/O errors from the flush.
  314. if (capFcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) {
  315. RxLog(("Cleanup Flush %lx\n",RxContext));
  316. RxFlushFcbInSystemCache(capFcb, TRUE);
  317. }
  318. if (!FlagOn( capFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
  319. (capFcb->UncachedUncleanCount != 0) &&
  320. (capFcb->UncachedUncleanCount == capFcb->UncleanCount) &&
  321. (capFcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)) {
  322. RxLog(("Cleanup Flush 1111 %lx\n",RxContext));
  323. RxPurgeFcbInSystemCache(
  324. capFcb,
  325. NULL,
  326. 0,
  327. FALSE,
  328. TRUE );
  329. }
  330. // do we need a flush?
  331. if (!NeedDelete && NeedPurge) {
  332. RxDbgTrace(0, Dbg, ("CleanupPurge:CCFlush\n", 0));
  333. RxLog(("Cleanup Flush 2222 %lx\n",RxContext));
  334. RxFlushFcbInSystemCache( capFcb, TRUE );
  335. }
  336. // cleanup the cache map to get rid of pages that are no longer part
  337. // of the file. amazingly, this works even if we didn't init the Cachemap!!!!!
  338. if (UninitializeCacheMap) {
  339. RxLog(("Cleanup Flush 3333 %lx\n",RxContext));
  340. RxUninitializeCacheMap( RxContext, capFileObject, TruncateSize );
  341. }
  342. // finish up a delete...we have to purge because MM is holding the file open....
  343. // just for the record, NeedPurge is set for files and clear for directories......
  344. if (NeedDelete || NeedPurge) {
  345. RxLog(("Cleanup Flush 4444 %lx\n",RxContext));
  346. RxPurgeFcbInSystemCache(
  347. capFcb,
  348. NULL,
  349. 0,
  350. FALSE,
  351. !NeedDelete );
  352. if (NeedDelete) {
  353. RxRemoveNameNetFcb( capFcb );
  354. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  355. AcquiredTableLock = FALSE;
  356. }
  357. }
  358. // The Close Call and the Cleanup Call may be far apart. The share access
  359. // must be cleaned up if the file was mapped through this File Object.
  360. if ((ShareAccess != NULL) &&
  361. (NetRootType == NET_ROOT_DISK)) {
  362. ASSERT (NetRootType == NET_ROOT_DISK);
  363. RxRemoveShareAccess( capFileObject, ShareAccess, "Cleanup the Share access", "ClnUpShr" );
  364. }
  365. if (TypeOfOpen == RDBSS_NTC_STORAGE_TYPE_FILE) {
  366. // Coordinate the cleanup operation with the oplock state.
  367. // Cleanup operations can always cleanup immediately.
  368. FsRtlCheckOplock( &capFcb->Specific.Fcb.Oplock, capReqPacket,
  369. RxContext, NULL, NULL );
  370. //capFcb->Header.IsFastIoPossible = RxIsFastIoPossible( capFcb );
  371. }
  372. if (AcquiredFcb) {
  373. AcquiredFcb = FALSE;
  374. RxReleaseFcb( RxContext, capFcb );
  375. }
  376. // A local filesystem would do this..........
  377. // If the NET_ROOT is on a removeable media, flush the volume. We do
  378. // this in lieu of write through for removeable media for
  379. // performance considerations. That is, data is guaranteed
  380. // to be out when NtCloseFile returns.
  381. // The file needs to be flushed
  382. // The cleanup for this file object has been successfully completed at
  383. // this point.
  384. SetFlag( capFileObject->Flags, FO_CLEANUP_COMPLETE );
  385. Status = STATUS_SUCCESS;
  386. } finally {
  387. DebugUnwind( RxCommonCleanup );
  388. if (AcquiredFcb) {
  389. RxReleaseFcb( RxContext, capFcb );
  390. }
  391. if (AcquiredTableLock) {
  392. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  393. }
  394. IF_DEBUG {
  395. if (AbnormalTermination()) {
  396. RxDbgTrace(-1, Dbg, ("RxCommonCleanup -> Abnormal Termination %08lx\n", Status));
  397. } else {
  398. RxDbgTrace(-1, Dbg, ("RxCommonCleanup -> %08lx\n", Status));
  399. }
  400. }
  401. }
  402. return Status;
  403. }
  404. VOID
  405. RxAdjustFileTimesAndSize ( RXCOMMON_SIGNATURE )
  406. /*++
  407. Routine Description:
  408. This routine is used to adjust the times and the filesize on a cleanup
  409. or a flush.
  410. Arguments:
  411. Irp - Supplies the Irp to process
  412. Return Value:
  413. RXSTATUS - The return status for the operation
  414. --*/
  415. {
  416. RxCaptureFcb;
  417. RxCaptureFobx;
  418. RxCaptureParamBlock;
  419. RxCaptureFileObject;
  420. BOOLEAN UpdateFileSize;
  421. BOOLEAN UpdateLastWriteTime;
  422. BOOLEAN UpdateLastAccessTime;
  423. BOOLEAN UpdateLastChangeTime;
  424. LARGE_INTEGER CurrentTime;
  425. PAGED_CODE();
  426. //if there's no cachemap then we don't have to send because the guy is
  427. //tracking everything on the other end.
  428. //LOCAL.MINI for a localminiFS we would still have to do this; so the answer to this question
  429. // (whether to do it or not) should be exposed in the fcb/fobx
  430. if ( capFileObject->PrivateCacheMap == NULL ) return;
  431. KeQuerySystemTime( &CurrentTime );
  432. //
  433. // Note that we HAVE to use BooleanFlagOn() here because
  434. // FO_FILE_SIZE_CHANGED > 0x80 (i.e., not in the first byte).
  435. //
  436. UpdateFileSize = BooleanFlagOn(capFileObject->Flags, FO_FILE_SIZE_CHANGED);
  437. UpdateLastWriteTime = FlagOn(capFileObject->Flags, FO_FILE_MODIFIED) &&
  438. !FlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
  439. UpdateLastChangeTime = FlagOn(capFileObject->Flags, FO_FILE_MODIFIED) &&
  440. !FlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
  441. UpdateLastAccessTime =
  442. (UpdateLastWriteTime ||
  443. (FlagOn(capFileObject->Flags, FO_FILE_FAST_IO_READ) &&
  444. !FlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS)));
  445. if (UpdateFileSize ||
  446. UpdateLastWriteTime ||
  447. UpdateLastChangeTime ||
  448. UpdateLastAccessTime ) {
  449. ULONG NotifyFilter = 0;
  450. BOOLEAN DoTheTimeUpdate = FALSE;
  451. FILE_BASIC_INFORMATION BasicInformation;
  452. FILE_END_OF_FILE_INFORMATION EofInformation;
  453. RxDbgTrace(0, Dbg, ("Update Time and/or file size on File\n", 0));
  454. RtlZeroMemory(&BasicInformation,sizeof(BasicInformation));
  455. try { //for finally
  456. try { //for exceptions
  457. if (UpdateLastWriteTime) {
  458. //
  459. // Update its time of last write
  460. DoTheTimeUpdate = TRUE;
  461. capFcb->LastWriteTime = CurrentTime;
  462. BasicInformation.LastWriteTime = CurrentTime;
  463. NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES
  464. | FILE_NOTIFY_CHANGE_LAST_WRITE;
  465. }
  466. if (UpdateLastChangeTime) {
  467. //
  468. // Update its time of last write
  469. DoTheTimeUpdate = TRUE;
  470. BasicInformation.ChangeTime = capFcb->LastChangeTime;
  471. //NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES
  472. // | FILE_NOTIFY_CHANGE_LAST_CHANGE;
  473. }
  474. if (UpdateLastAccessTime) {
  475. DoTheTimeUpdate = TRUE;
  476. capFcb->LastAccessTime = CurrentTime;
  477. BasicInformation.LastAccessTime = CurrentTime;
  478. NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
  479. }
  480. if (DoTheTimeUpdate) {
  481. NTSTATUS Status; //if it doesn't work.....sigh
  482. RxContext->Info.FileInformationClass = (FileBasicInformation);
  483. RxContext->Info.Buffer = &BasicInformation;
  484. RxContext->Info.Length = sizeof(BasicInformation);
  485. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfoAtCleanup,(RxContext));
  486. }
  487. if (UpdateFileSize) {
  488. NTSTATUS Status; //if it doesn't work.....sigh
  489. EofInformation.EndOfFile = capFcb->Header.FileSize;
  490. RxContext->Info.FileInformationClass = (FileEndOfFileInformation);
  491. RxContext->Info.Buffer = &EofInformation;
  492. RxContext->Info.Length = sizeof(EofInformation);
  493. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfoAtCleanup,(RxContext));
  494. NotifyFilter |= FILE_NOTIFY_CHANGE_SIZE;
  495. }
  496. //RxNotifyReportChange( RxContext, Vcb, Fcb,
  497. // NotifyFilter,
  498. // FILE_ACTION_MODIFIED );
  499. //MINIRDR_CALL(Status,capFcb->MRxDispatch,MRxSetTimeAndSize,(RxContext));
  500. } except( CATCH_EXPECTED_EXCEPTIONS ) {
  501. NOTHING;
  502. }
  503. } finally {
  504. NOTHING;
  505. }
  506. }
  507. }
  508. #define RxMoveAllButFirstToAnotherList(List1,List2) { \
  509. PLIST_ENTRY FrontListEntry = (List1)->Flink; \
  510. if (FrontListEntry->Flink == (List1)) { \
  511. (List2)->Flink = (List2)->Blink = (List2); \
  512. } else { \
  513. (List2)->Blink = (List1)->Blink; \
  514. (List2)->Blink->Flink = (List2); \
  515. (List1)->Blink = FrontListEntry; \
  516. (List2)->Flink = FrontListEntry->Flink; \
  517. FrontListEntry->Flink = (List1); \
  518. (List2)->Flink->Blink = (List2); \
  519. } \
  520. }
  521. #if DBG
  522. PSZ RxDSQTagText[FOBX_NUMBER_OF_SERIALIZATION_QUEUES] = {"read","write"};
  523. VOID
  524. RxDumpSerializationQueue(
  525. PLIST_ENTRY SQ,
  526. PSZ TagText1,
  527. PSZ TagText2
  528. )
  529. {
  530. PLIST_ENTRY ListEntry;
  531. PAGED_CODE();
  532. if (IsListEmpty(SQ)) {
  533. RxDbgTrace(0, Dbg, ("RxDumpSerializationQueue %s%s is empty\n", TagText1, TagText2));
  534. return;
  535. }
  536. RxDbgTrace(0, Dbg, ("RxDumpSerializationQueue %s%s:\n", TagText1, TagText2));
  537. for (ListEntry=SQ->Flink;
  538. ListEntry!=SQ;
  539. ListEntry=ListEntry->Flink) {
  540. //print out the contexts and the major op for validation
  541. PRX_CONTEXT RxContext = CONTAINING_RECORD( ListEntry,RX_CONTEXT,RxContextSerializationQLinks);
  542. RxDbgTrace(0, Dbg, (" rxc=%08lx op=%02lx\n", RxContext, RxContext->MajorFunction));
  543. }
  544. }
  545. #else
  546. #define RxDumpSerializationQueue(___r,___t12,___t13) {NOTHING;}
  547. #endif
  548. VOID
  549. RxCleanupPipeQueues (
  550. IN PRX_CONTEXT RxContext
  551. )
  552. {
  553. RxCaptureFcb; RxCaptureFobx;
  554. LIST_ENTRY SecondaryBlockedQs[FOBX_NUMBER_OF_SERIALIZATION_QUEUES];
  555. PLIST_ENTRY PrimaryBlockedQs = &capFobx->Specific.NamedPipe.ReadSerializationQueue;
  556. ULONG i;
  557. PAGED_CODE();
  558. RxDbgTrace(+1, Dbg, ("RxCleanupPipeQueues \n"));
  559. //for pipes there are two sources of unhappiness...........
  560. //first, we have to get rid of any blocked operations.
  561. //second, if there are blocking operations that have already gone by then we have to send the
  562. // close smb early so that the server will, in turn, complete the outstanding
  563. ExAcquireFastMutexUnsafe(&RxContextPerFileSerializationMutex);
  564. for (i=0;i<FOBX_NUMBER_OF_SERIALIZATION_QUEUES;i++) {
  565. RxDumpSerializationQueue(&PrimaryBlockedQs[i],RxDSQTagText[i],"Primary");
  566. if (!IsListEmpty(&PrimaryBlockedQs[i])) {
  567. RxMoveAllButFirstToAnotherList(
  568. &PrimaryBlockedQs[i],
  569. &SecondaryBlockedQs[i]);
  570. RxDumpSerializationQueue(&PrimaryBlockedQs[i],RxDSQTagText[i],"Primary");
  571. RxDumpSerializationQueue(&SecondaryBlockedQs[i],RxDSQTagText[i],"Secondary");
  572. } else {
  573. InitializeListHead(&SecondaryBlockedQs[i]);
  574. }
  575. }
  576. ExReleaseFastMutexUnsafe(&RxContextPerFileSerializationMutex);
  577. for (i=0;i<FOBX_NUMBER_OF_SERIALIZATION_QUEUES;i++) {
  578. for (;!IsListEmpty(&SecondaryBlockedQs[i]);) {
  579. PLIST_ENTRY FrontListEntry = (&SecondaryBlockedQs[i])->Flink;
  580. PRX_CONTEXT FrontRxContext = CONTAINING_RECORD( FrontListEntry,RX_CONTEXT,RxContextSerializationQLinks);
  581. RemoveEntryList(FrontListEntry);
  582. FrontRxContext->RxContextSerializationQLinks.Flink = NULL;
  583. FrontRxContext->RxContextSerializationQLinks.Blink = NULL;
  584. if (!FlagOn(FrontRxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  585. RxDbgTrace(0, Dbg, (" unblocking %08lx\n",FrontRxContext));
  586. RxContext->StoredStatus = STATUS_PIPE_CLOSING;
  587. RxSignalSynchronousWaiter(FrontRxContext);
  588. } else {
  589. RxDbgTrace(0, Dbg, (" completing %08lx\n",FrontRxContext));
  590. RxCompleteAsynchronousRequest( FrontRxContext, STATUS_PIPE_CLOSING );
  591. }
  592. }
  593. }
  594. RxDbgTrace(-1, Dbg, ("RxCleanupPipeQueues exit\n"));
  595. return;
  596. }
  597. BOOLEAN
  598. RxFakeLockEnumerator (
  599. IN OUT struct _SRV_OPEN * SrvOpen,
  600. IN OUT PVOID *ContinuationHandle,
  601. OUT PLARGE_INTEGER FileOffset,
  602. OUT PLARGE_INTEGER LockRange,
  603. OUT PBOOLEAN IsLockExclusive
  604. )
  605. /*++
  606. Routine Description:
  607. THIS ROUTINE IS A FAKE THAT IS JUST USED FOR TESTING PURPOSES!
  608. This routine is called from a minirdr to enumerate the filelocks on an FCB; it gets
  609. one lock on each call. currently, we just pass thru to the fsrtl routine which is very funky
  610. because it keeps the enumeration state internally; as a result, only one enumeration can be in progress
  611. at any time. we can change over to something better if it's ever required.
  612. Arguments:
  613. SrvOpen - a srvopen on the fcb to be enumerated.
  614. ContinuationHandle - a handle passed back and forth representing the state of the enumeration.
  615. if a NULL is passed in, then we are to start at the beginning.
  616. FileOffset,LockRange,IsLockExclusive - the description of the returned lock
  617. Return Value:
  618. a BOOLEAN. FALSE means you've reached the end of the list; TRUE means the returned lock data is valid
  619. --*/
  620. {
  621. ULONG LockNumber;
  622. LockNumber = PtrToUlong(*ContinuationHandle);
  623. if (LockNumber>=12) {
  624. return(FALSE);
  625. }
  626. LockNumber++;
  627. RxDbgTrace(0, Dbg, ("Rxlockenum %08lx\n", LockNumber ));
  628. FileOffset->QuadPart = LockNumber;
  629. LockRange->QuadPart = 1;
  630. *IsLockExclusive = (LockNumber&0x4)==0;
  631. *ContinuationHandle = LongToPtr(LockNumber);
  632. return TRUE;
  633. }
  634. BOOLEAN
  635. RxUninitializeCacheMap(
  636. IN OUT PRX_CONTEXT RxContext,
  637. IN PFILE_OBJECT FileObject,
  638. IN PLARGE_INTEGER TruncateSize
  639. )
  640. /*++
  641. Routine Description:
  642. This routine is a wrapper for CcUninitializeCacheMap.
  643. Arguments:
  644. IN PFILE_OBJECT FileObject - Supplies the file object for the file to purge.
  645. IN PLARGE_INTEGER TruncateSize - Specifies the new size for the file.
  646. Return Value:
  647. BOOLEAN - TRUE if file has been immediately purged, FALSE if we had to wait.
  648. Note:
  649. The file must be locked exclusively before calling this routine.
  650. --*/
  651. {
  652. BOOLEAN CacheReturnValue;
  653. CACHE_UNINITIALIZE_EVENT PurgeCompleteEvent;
  654. PFCB Fcb = FileObject->FsContext;
  655. NTSTATUS Status;
  656. PAGED_CODE();
  657. ASSERT ( NodeTypeIsFcb(Fcb) );
  658. //
  659. // Make sure that this thread owns the FCB.
  660. //
  661. ASSERT ( RxIsFcbAcquiredExclusive ( Fcb ) );
  662. //
  663. // Now uninitialize the cache managers own file object. This is
  664. // done basically simply to allow us to wait until the cache purge
  665. // is complete.
  666. //
  667. KeInitializeEvent(&PurgeCompleteEvent.Event, SynchronizationEvent, FALSE);
  668. //RxLog(( "ccunini1", &Fcb->FileName, 2,
  669. // (TruncateSize == NULL) ? 0xffffffff : TruncateSize->LowPart,
  670. // (ULONG)&PurgeCompleteEvent ));
  671. CacheReturnValue = CcUninitializeCacheMap(FileObject, TruncateSize, &PurgeCompleteEvent);
  672. //
  673. // Release the lock on the FCB that our caller applied.
  674. //
  675. RxReleaseFcb( RxContext, Fcb );
  676. //
  677. // Now wait for the cache manager to finish purging the file.
  678. //
  679. KeWaitForSingleObject(&PurgeCompleteEvent.Event,
  680. Executive,
  681. KernelMode,
  682. FALSE,
  683. NULL);
  684. //
  685. // Re-acquire the FCB lock once we've waited for the
  686. // cache manager to finish the uninitialize.
  687. //
  688. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  689. ASSERT(Status == STATUS_SUCCESS);
  690. return(CacheReturnValue);
  691. }