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.

922 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. if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) {
  145. ASSERT( capFcb->UncleanCount );
  146. InterlockedDecrement(&capFcb->UncleanCount);
  147. if (FlagOn(capFileObject->Flags,FO_NO_INTERMEDIATE_BUFFERING)) {
  148. capFcb->UncachedUncleanCount--;
  149. }
  150. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxCleanupFobx,(RxContext));
  151. ASSERT( capFobx->SrvOpen->UncleanFobxCount );
  152. capFobx->SrvOpen->UncleanFobxCount--;
  153. RxReleaseFcb(RxContext,capFcb);
  154. return STATUS_SUCCESS;
  155. }
  156. NetRootType = capFcb->VNetRoot->NetRoot->Type ;
  157. NetRoot = (PNET_ROOT)capFcb->VNetRoot->NetRoot;
  158. if ( FlagOn(capFobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE) ) {
  159. SetFlag( capFcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  160. }
  161. ShareAccess = &capFcb->ShareAccess;
  162. LastUncleanOnGoodFcb = (capFcb->UncleanCount == 1);
  163. if (LastUncleanOnGoodFcb && FlagOn(capFcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) {
  164. // if we can't get it right way, drop the Fcb and acquire/acquire
  165. // to perserve lock order. No one else can change the counts while we have
  166. // the fcb lock; neither can a file become DELETE_ON_CLOSE or be opened via
  167. // CommonCreate. If we are not deleting, get rid of the tablelock after we
  168. // verify the count.
  169. if ( RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE) ) {
  170. // this is the fast way....hope it works
  171. AcquiredTableLock = TRUE;
  172. } else {
  173. // Release the FCB and reqcquire the locks in the correct order.
  174. // PrefixTableLock followed by the FCB.
  175. RxReleaseFcb( RxContext, capFcb );
  176. AcquiredFcb = FALSE;
  177. (VOID)RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
  178. AcquiredTableLock = TRUE;
  179. Status = RxAcquireExclusiveFcb( RxContext, capFcb );
  180. if (Status != STATUS_SUCCESS) {
  181. RxDbgTrace(-1, Dbg, ("RxCommonCleanup Failed to acquire FCB -> %lx\n)", Status));
  182. return Status;
  183. }
  184. AcquiredFcb = TRUE;
  185. }
  186. if (capFcb->UncleanCount != 1) {
  187. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  188. AcquiredTableLock = FALSE;
  189. NeedDelete = FALSE;
  190. } else {
  191. NeedDelete = TRUE;
  192. }
  193. }
  194. try {
  195. switch (NetRootType) {
  196. case NET_ROOT_PIPE:
  197. case NET_ROOT_PRINT:
  198. {
  199. // If the file object corresponds to a pipe or spool file additional
  200. // cleanup operations are required. This deals with the special
  201. // serialization mechanism for pipes.
  202. RxCleanupPipeQueues(RxContext);
  203. }
  204. break;
  205. case NET_ROOT_DISK:
  206. {
  207. switch (TypeOfOpen) {
  208. case RDBSS_NTC_STORAGE_TYPE_FILE :
  209. {
  210. // If the file object corresponds to a disk file, assert the locks
  211. // and update the associated file times and sizes.
  212. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  213. LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
  214. FsRtlFastUnlockAll(
  215. &capFcb->Specific.Fcb.FileLock,
  216. capFileObject,
  217. IoGetRequestorProcess( capReqPacket ),
  218. RxContext );
  219. if (LowIoContext->ParamsFor.Locks.LockList != NULL) {
  220. RxDbgTrace(0, Dbg, ("--->before init, locklist=%08lx\n", LowIoContext->ParamsFor.Locks.LockList));
  221. RxInitializeLowIoContext(LowIoContext,LOWIO_OP_UNLOCK_MULTIPLE);
  222. LowIoContext->ParamsFor.Locks.Flags = 0; //no flags
  223. Status = RxLowIoLockControlShell(RxContext);
  224. }
  225. RxAdjustFileTimesAndSize(RXCOMMON_ARGUMENTS);
  226. // If the file object corresponds to a disk file/directory and this
  227. // is the last cleanup call for the FCB additional processing is required.
  228. if (LastUncleanOnGoodFcb) {
  229. try {
  230. // If the file object was marked DELETE_ON_CLOSE set the file size to
  231. // zero ( synchronizing with the paging resource)
  232. if (NeedDelete) {
  233. RxAcquirePagingIoResource( capFcb );
  234. capFcb->Header.FileSize.QuadPart = 0;
  235. if (TypeOfOpen == RDBSS_NTC_STORAGE_TYPE_FILE) {
  236. capFcb->Header.ValidDataLength.QuadPart = 0;
  237. }
  238. RxReleasePagingIoResource( capFcb );
  239. } else {
  240. // If the file object was not marked for deletion and it is not
  241. // a paging file ensure that the portion between the valid data
  242. // length and the file size is zero extended.
  243. if (!FlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE) &&
  244. (capFcb->Header.ValidDataLength.QuadPart <
  245. capFcb->Header.FileSize.QuadPart)) {
  246. RxDbgTrace(0, Dbg, ("---------->zeroextend!!!!!!!\n", 0));
  247. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxZeroExtend,(RxContext));
  248. capFcb->Header.ValidDataLength.QuadPart =
  249. capFcb->Header.FileSize.QuadPart;
  250. }
  251. }
  252. // If the file object was marked for truncation capture the
  253. // sizes for uninitializing the cache maps subsequently.
  254. if (FlagOn(capFcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE)) {
  255. RxDbgTrace(0, Dbg, ("truncate file allocation\n", 0));
  256. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxTruncate,(RxContext));
  257. // Setup to truncate the Cache Map because
  258. // this is the only way we have of trashing the
  259. // truncated pages.
  260. LocalTruncateSize = capFcb->Header.FileSize;
  261. TruncateSize = &LocalTruncateSize;
  262. // Mark the Fcb as having now been truncated, just
  263. // in case we have to reprocess this later.
  264. capFcb->FcbState &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
  265. }
  266. } except ( CATCH_EXPECTED_EXCEPTIONS ) {
  267. DbgPrint("!!! Handling Exceptions\n");
  268. NOTHING;
  269. }
  270. }
  271. // Purging can be done now if this FCB does not support collapsed opens
  272. if (!NeedPurge) {
  273. NeedPurge = (LastUncleanOnGoodFcb &&
  274. (NeedDelete ||
  275. !FlagOn(capFcb->FcbState,FCB_STATE_COLLAPSING_ENABLED)));
  276. }
  277. UninitializeCacheMap = TRUE;
  278. }
  279. break;
  280. case RDBSS_NTC_STORAGE_TYPE_DIRECTORY :
  281. case RDBSS_NTC_STORAGE_TYPE_UNKNOWN :
  282. default:
  283. break;
  284. }
  285. }
  286. break;
  287. default:
  288. break;
  289. }
  290. // We've just finished everything associated with an unclean
  291. // fcb so now decrement the unclean count before releasing
  292. // the resource.
  293. ASSERT( capFcb->UncleanCount );
  294. InterlockedDecrement(&capFcb->UncleanCount);
  295. if (FlagOn(capFileObject->Flags,FO_NO_INTERMEDIATE_BUFFERING)) {
  296. capFcb->UncachedUncleanCount--;
  297. }
  298. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxCleanupFobx,(RxContext));
  299. ASSERT( capFobx->SrvOpen->UncleanFobxCount );
  300. capFobx->SrvOpen->UncleanFobxCount--;
  301. // If this was the last cached open, and there are open
  302. // non-cached handles, attempt a flush and purge operation
  303. // to avoid cache coherency overhead from these non-cached
  304. // handles later. We ignore any I/O errors from the flush.
  305. if (capFcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) {
  306. RxFlushFile( RxContext, capFcb );
  307. }
  308. if (!FlagOn( capFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
  309. (capFcb->UncachedUncleanCount != 0) &&
  310. (capFcb->UncachedUncleanCount == capFcb->UncleanCount) &&
  311. (capFcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)) {
  312. RxFlushFile( RxContext, capFcb );
  313. CcPurgeCacheSection(
  314. &capFcb->NonPaged->SectionObjectPointers,
  315. NULL,
  316. 0,
  317. FALSE );
  318. }
  319. // do we need a flush?
  320. if (!NeedDelete && NeedPurge) {
  321. RxDbgTrace(0, Dbg, ("CleanupPurge:CCFlush\n", 0));
  322. RxFlushFile( RxContext, capFcb );
  323. }
  324. // cleanup the cache map to get rid of pages that are no longer part
  325. // of the file. amazingly, this works even if we didn't init the Cachemap!!!!!
  326. if (UninitializeCacheMap) {
  327. RxUninitializeCacheMap( RxContext, capFileObject, TruncateSize );
  328. }
  329. // finish up a delete...we have to purge because MM is holding the file open....
  330. // just for the record, NeedPurge is set for files and clear for directories......
  331. if (NeedDelete || NeedPurge) {
  332. RxDbgTrace(0, Dbg, ("CleanupPurge:MmFlushImage\n", 0));
  333. MmFlushImageSection(&capFcb->NonPaged->SectionObjectPointers,
  334. MmFlushForWrite);
  335. ASSERT((AcquiredFcb));
  336. RxReleaseFcb( RxContext, capFcb );
  337. AcquiredFcb = FALSE;
  338. MmForceSectionClosed(&capFcb->NonPaged->SectionObjectPointers, TRUE);
  339. RxAcquireExclusiveFcb(RxContext,capFcb);
  340. AcquiredFcb = TRUE;
  341. RxDbgTrace(0, Dbg, ("CleanupPurge:PurgingFinished\n", 0));
  342. if (NeedDelete) {
  343. RxRemoveNameNetFcb( capFcb );
  344. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  345. AcquiredTableLock = FALSE;
  346. }
  347. }
  348. // The Close Call and the Cleanup Call may be far apart. The share access
  349. // must be cleaned up if the file was mapped through this File Object.
  350. if ((ShareAccess != NULL) &&
  351. (NetRootType == NET_ROOT_DISK)) {
  352. ASSERT (NetRootType == NET_ROOT_DISK);
  353. RxRemoveShareAccess( capFileObject, ShareAccess, "Cleanup the Share access", "ClnUpShr" );
  354. }
  355. if (TypeOfOpen == RDBSS_NTC_STORAGE_TYPE_FILE) {
  356. // Coordinate the cleanup operation with the oplock state.
  357. // Cleanup operations can always cleanup immediately.
  358. FsRtlCheckOplock( &capFcb->Specific.Fcb.Oplock, capReqPacket,
  359. RxContext, NULL, NULL );
  360. //capFcb->Header.IsFastIoPossible = RxIsFastIoPossible( capFcb );
  361. }
  362. if (AcquiredFcb) {
  363. RxReleaseFcb( RxContext, capFcb );
  364. AcquiredFcb = FALSE;
  365. }
  366. // A local filesystem would do this..........
  367. // If the NET_ROOT is on a removeable media, flush the volume. We do
  368. // this in lieu of write through for removeable media for
  369. // performance considerations. That is, data is guaranteed
  370. // to be out when NtCloseFile returns.
  371. // The file needs to be flushed
  372. // The cleanup for this file object has been successfully completed at
  373. // this point.
  374. SetFlag( capFileObject->Flags, FO_CLEANUP_COMPLETE );
  375. Status = STATUS_SUCCESS;
  376. } finally {
  377. DebugUnwind( RxCommonCleanup );
  378. if (AcquiredFcb) {
  379. RxReleaseFcb( RxContext, capFcb );
  380. }
  381. if (AcquiredTableLock) {
  382. RxReleaseFcbTableLock(&NetRoot->FcbTable);
  383. }
  384. IF_DEBUG {
  385. if (AbnormalTermination()) {
  386. RxDbgTrace(-1, Dbg, ("RxCommonCleanup -> Abnormal Termination %08lx\n", Status));
  387. } else {
  388. RxDbgTrace(-1, Dbg, ("RxCommonCleanup -> %08lx\n", Status));
  389. }
  390. }
  391. }
  392. return Status;
  393. }
  394. VOID
  395. RxAdjustFileTimesAndSize ( RXCOMMON_SIGNATURE )
  396. /*++
  397. Routine Description:
  398. This routine is used to adjust the times and the filesize on a cleanup
  399. or a flush.
  400. Arguments:
  401. Irp - Supplies the Irp to process
  402. Return Value:
  403. RXSTATUS - The return status for the operation
  404. --*/
  405. {
  406. RxCaptureFcb;
  407. RxCaptureFobx;
  408. RxCaptureParamBlock;
  409. RxCaptureFileObject;
  410. BOOLEAN UpdateFileSize;
  411. BOOLEAN UpdateLastWriteTime;
  412. BOOLEAN UpdateLastAccessTime;
  413. BOOLEAN UpdateLastChangeTime;
  414. LARGE_INTEGER CurrentTime;
  415. PAGED_CODE();
  416. //if there's no cachemap then we don't have to send because the guy is
  417. //tracking everything on the other end.
  418. //LOCAL.MINI for a localminiFS we would still have to do this; so the answer to this question
  419. // (whether to do it or not) should be exposed in the fcb/fobx
  420. if ( capFileObject->PrivateCacheMap == NULL ) return;
  421. KeQuerySystemTime( &CurrentTime );
  422. //
  423. // Note that we HAVE to use BooleanFlagOn() here because
  424. // FO_FILE_SIZE_CHANGED > 0x80 (i.e., not in the first byte).
  425. //
  426. UpdateFileSize = BooleanFlagOn(capFileObject->Flags, FO_FILE_SIZE_CHANGED);
  427. UpdateLastWriteTime = FlagOn(capFileObject->Flags, FO_FILE_MODIFIED) &&
  428. !FlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
  429. UpdateLastChangeTime = FlagOn(capFileObject->Flags, FO_FILE_MODIFIED) &&
  430. !FlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
  431. UpdateLastAccessTime =
  432. (UpdateLastWriteTime ||
  433. (FlagOn(capFileObject->Flags, FO_FILE_FAST_IO_READ) &&
  434. !FlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS)));
  435. if (UpdateFileSize ||
  436. UpdateLastWriteTime ||
  437. UpdateLastChangeTime ||
  438. UpdateLastAccessTime ) {
  439. ULONG NotifyFilter = 0;
  440. BOOLEAN DoTheTimeUpdate = FALSE;
  441. FILE_BASIC_INFORMATION BasicInformation;
  442. FILE_END_OF_FILE_INFORMATION EofInformation;
  443. RxDbgTrace(0, Dbg, ("Update Time and/or file size on File\n", 0));
  444. RtlZeroMemory(&BasicInformation,sizeof(BasicInformation));
  445. try { //for finally
  446. try { //for exceptions
  447. if (UpdateLastWriteTime) {
  448. //
  449. // Update its time of last write
  450. DoTheTimeUpdate = TRUE;
  451. capFcb->LastWriteTime = CurrentTime;
  452. BasicInformation.LastWriteTime = CurrentTime;
  453. NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES
  454. | FILE_NOTIFY_CHANGE_LAST_WRITE;
  455. }
  456. if (UpdateLastChangeTime) {
  457. //
  458. // Update its time of last write
  459. DoTheTimeUpdate = TRUE;
  460. BasicInformation.ChangeTime = capFcb->LastChangeTime;
  461. //NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES
  462. // | FILE_NOTIFY_CHANGE_LAST_CHANGE;
  463. }
  464. if (UpdateLastAccessTime) {
  465. DoTheTimeUpdate = TRUE;
  466. capFcb->LastAccessTime = CurrentTime;
  467. BasicInformation.LastAccessTime = CurrentTime;
  468. NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
  469. }
  470. if (DoTheTimeUpdate) {
  471. NTSTATUS Status; //if it doesn't work.....sigh
  472. RxContext->Info.FileInformationClass = (FileBasicInformation);
  473. RxContext->Info.Buffer = &BasicInformation;
  474. RxContext->Info.Length = sizeof(BasicInformation);
  475. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfoAtCleanup,(RxContext));
  476. }
  477. if (UpdateFileSize) {
  478. NTSTATUS Status; //if it doesn't work.....sigh
  479. EofInformation.EndOfFile = capFcb->Header.FileSize;
  480. RxContext->Info.FileInformationClass = (FileEndOfFileInformation);
  481. RxContext->Info.Buffer = &EofInformation;
  482. RxContext->Info.Length = sizeof(EofInformation);
  483. MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfoAtCleanup,(RxContext));
  484. NotifyFilter |= FILE_NOTIFY_CHANGE_SIZE;
  485. }
  486. //RxNotifyReportChange( RxContext, Vcb, Fcb,
  487. // NotifyFilter,
  488. // FILE_ACTION_MODIFIED );
  489. //MINIRDR_CALL(Status,capFcb->MRxDispatch,MRxSetTimeAndSize,(RxContext));
  490. } except( CATCH_EXPECTED_EXCEPTIONS ) {
  491. NOTHING;
  492. }
  493. } finally {
  494. NOTHING;
  495. }
  496. }
  497. }
  498. #define RxMoveAllButFirstToAnotherList(List1,List2) { \
  499. PLIST_ENTRY FrontListEntry = (List1)->Flink; \
  500. if (FrontListEntry->Flink == (List1)) { \
  501. (List2)->Flink = (List2)->Blink = (List2); \
  502. } else { \
  503. (List2)->Blink = (List1)->Blink; \
  504. (List2)->Blink->Flink = (List2); \
  505. (List1)->Blink = FrontListEntry; \
  506. (List2)->Flink = FrontListEntry->Flink; \
  507. FrontListEntry->Flink = (List1); \
  508. (List2)->Flink->Blink = (List2); \
  509. } \
  510. }
  511. #if DBG
  512. PSZ RxDSQTagText[FOBX_NUMBER_OF_SERIALIZATION_QUEUES] = {"read","write"};
  513. VOID
  514. RxDumpSerializationQueue(
  515. PLIST_ENTRY SQ,
  516. PSZ TagText1,
  517. PSZ TagText2
  518. )
  519. {
  520. PLIST_ENTRY ListEntry;
  521. PAGED_CODE();
  522. if (IsListEmpty(SQ)) {
  523. RxDbgTrace(0, Dbg, ("RxDumpSerializationQueue %s%s is empty\n", TagText1, TagText2));
  524. return;
  525. }
  526. RxDbgTrace(0, Dbg, ("RxDumpSerializationQueue %s%s:\n", TagText1, TagText2));
  527. for (ListEntry=SQ->Flink;
  528. ListEntry!=SQ;
  529. ListEntry=ListEntry->Flink) {
  530. //print out the contexts and the major op for validation
  531. PRX_CONTEXT RxContext = CONTAINING_RECORD( ListEntry,RX_CONTEXT,RxContextSerializationQLinks);
  532. RxDbgTrace(0, Dbg, (" rxc=%08lx op=%02lx\n", RxContext, RxContext->MajorFunction));
  533. }
  534. }
  535. #else
  536. #define RxDumpSerializationQueue(___r,___t12,___t13) {NOTHING;}
  537. #endif
  538. VOID
  539. RxCleanupPipeQueues (
  540. IN PRX_CONTEXT RxContext
  541. )
  542. {
  543. RxCaptureFcb; RxCaptureFobx;
  544. LIST_ENTRY SecondaryBlockedQs[FOBX_NUMBER_OF_SERIALIZATION_QUEUES];
  545. PLIST_ENTRY PrimaryBlockedQs = &capFobx->Specific.NamedPipe.ReadSerializationQueue;
  546. ULONG i;
  547. PAGED_CODE();
  548. RxDbgTrace(+1, Dbg, ("RxCleanupPipeQueues \n"));
  549. //for pipes there are two sources of unhappiness...........
  550. //first, we have to get rid of any blocked operations.
  551. //second, if there are blocking operations that have already gone by then we have to send the
  552. // close smb early so that the server will, in turn, complete the outstanding
  553. ExAcquireFastMutexUnsafe(&RxContextPerFileSerializationMutex);
  554. for (i=0;i<FOBX_NUMBER_OF_SERIALIZATION_QUEUES;i++) {
  555. RxDumpSerializationQueue(&PrimaryBlockedQs[i],RxDSQTagText[i],"Primary");
  556. if (!IsListEmpty(&PrimaryBlockedQs[i])) {
  557. RxMoveAllButFirstToAnotherList(
  558. &PrimaryBlockedQs[i],
  559. &SecondaryBlockedQs[i]);
  560. RxDumpSerializationQueue(&PrimaryBlockedQs[i],RxDSQTagText[i],"Primary");
  561. RxDumpSerializationQueue(&SecondaryBlockedQs[i],RxDSQTagText[i],"Secondary");
  562. } else {
  563. InitializeListHead(&SecondaryBlockedQs[i]);
  564. }
  565. }
  566. ExReleaseFastMutexUnsafe(&RxContextPerFileSerializationMutex);
  567. for (i=0;i<FOBX_NUMBER_OF_SERIALIZATION_QUEUES;i++) {
  568. for (;!IsListEmpty(&SecondaryBlockedQs[i]);) {
  569. PLIST_ENTRY FrontListEntry = (&SecondaryBlockedQs[i])->Flink;
  570. PRX_CONTEXT FrontRxContext = CONTAINING_RECORD( FrontListEntry,RX_CONTEXT,RxContextSerializationQLinks);
  571. RemoveEntryList(FrontListEntry);
  572. if (!FlagOn(FrontRxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  573. RxDbgTrace(0, Dbg, (" unblocking %08lx\n",FrontRxContext));
  574. RxContext->StoredStatus = STATUS_PIPE_CLOSING;
  575. RxSignalSynchronousWaiter(FrontRxContext);
  576. } else {
  577. RxDbgTrace(0, Dbg, (" completing %08lx\n",FrontRxContext));
  578. RxCompleteAsynchronousRequest( RxContext, STATUS_PIPE_CLOSING );
  579. }
  580. }
  581. }
  582. RxDbgTrace(-1, Dbg, ("RxCleanupPipeQueues exit\n"));
  583. return;
  584. }
  585. BOOLEAN
  586. RxFakeLockEnumerator (
  587. IN OUT struct _SRV_OPEN * SrvOpen,
  588. IN OUT PVOID *ContinuationHandle,
  589. OUT PLARGE_INTEGER FileOffset,
  590. OUT PLARGE_INTEGER LockRange,
  591. OUT PBOOLEAN IsLockExclusive
  592. )
  593. /*++
  594. Routine Description:
  595. THIS ROUTINE IS A FAKE THAT IS JUST USED FOR TESTING PURPOSES!
  596. This routine is called from a minirdr to enumerate the filelocks on an FCB; it gets
  597. one lock on each call. currently, we just pass thru to the fsrtl routine which is very funky
  598. because it keeps the enumeration state internally; as a result, only one enumeration can be in progress
  599. at any time. we can change over to something better if it's ever required.
  600. Arguments:
  601. SrvOpen - a srvopen on the fcb to be enumerated.
  602. ContinuationHandle - a handle passed back and forth representing the state of the enumeration.
  603. if a NULL is passed in, then we are to start at the beginning.
  604. FileOffset,LockRange,IsLockExclusive - the description of the returned lock
  605. Return Value:
  606. a BOOLEAN. FALSE means you've reached the end of the list; TRUE means the returned lock data is valid
  607. --*/
  608. {
  609. ULONG LockNumber;
  610. LockNumber = (ULONG)(*ContinuationHandle);
  611. if (LockNumber>=12) {
  612. return(FALSE);
  613. }
  614. LockNumber++;
  615. RxDbgTrace(0, Dbg, ("Rxlockenum %08lx\n", LockNumber ));
  616. FileOffset->QuadPart = LockNumber;
  617. LockRange->QuadPart = 1;
  618. *IsLockExclusive = (LockNumber&0x4)==0;
  619. *ContinuationHandle = (PVOID)LockNumber;
  620. }
  621. BOOLEAN
  622. RxUninitializeCacheMap(
  623. IN OUT PRX_CONTEXT RxContext,
  624. IN PFILE_OBJECT FileObject,
  625. IN PLARGE_INTEGER TruncateSize
  626. )
  627. /*++
  628. Routine Description:
  629. This routine is a wrapper for CcUninitializeCacheMap.
  630. Arguments:
  631. IN PFILE_OBJECT FileObject - Supplies the file object for the file to purge.
  632. IN PLARGE_INTEGER TruncateSize - Specifies the new size for the file.
  633. Return Value:
  634. BOOLEAN - TRUE if file has been immediately purged, FALSE if we had to wait.
  635. Note:
  636. The file must be locked exclusively before calling this routine.
  637. --*/
  638. {
  639. BOOLEAN CacheReturnValue;
  640. CACHE_UNINITIALIZE_EVENT PurgeCompleteEvent;
  641. PFCB Fcb = FileObject->FsContext;
  642. PAGED_CODE();
  643. ASSERT ( NodeTypeIsFcb(Fcb) );
  644. //
  645. // Make sure that this thread owns the FCB.
  646. //
  647. ASSERT ( RxIsFcbAcquiredExclusive ( Fcb ) );
  648. #if 0
  649. BUGBUG do we need this part too? [joejoe] of course we do. or something similar. we have to synchronize openers
  650. with this piece of code.
  651. //
  652. // In order to guarantee that only one thread is calling
  653. // RxPurgeCacheFile, we reset this event to the
  654. // not-signalled state before calling CcUninitializeCacheMap,
  655. // and then set it when we exit. If any other threads come in
  656. // while we are waiting on the event, they will find that
  657. // CacheFileObject is NULL, and thus wait until the cache purge
  658. // completes.
  659. //
  660. KeClearEvent(&Fcb->NonPagedFcb->PurgeCacheSynchronizer);
  661. #endif
  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. //
  669. // Release the lock on the FCB that our caller applied.
  670. //
  671. RxReleaseFcb( RxContext, Fcb );
  672. //RxLog(( "ccunini1", &Fcb->FileName, 2,
  673. // (TruncateSize == NULL) ? 0xffffffff : TruncateSize->LowPart,
  674. // (ULONG)&PurgeCompleteEvent ));
  675. CacheReturnValue = CcUninitializeCacheMap(FileObject, TruncateSize, &PurgeCompleteEvent);
  676. #if 0
  677. //
  678. // Make sure that this thread doesn't own the FCB.
  679. //
  680. ASSERT (!ExIsResourceAcquiredExclusive(Fcb->Header.Resource));
  681. #endif
  682. //
  683. // Now wait for the cache manager to finish purging the file.
  684. //
  685. KeWaitForSingleObject(&PurgeCompleteEvent.Event,
  686. Executive,
  687. KernelMode,
  688. FALSE,
  689. NULL);
  690. //
  691. // Re-acquire the FCB lock once we've waited for the
  692. // cache manager to finish the uninitialize.
  693. //
  694. RxAcquireExclusiveFcb( RxContext, Fcb );
  695. #if 0
  696. //
  697. // Now set the purge cache event to the signalled state to allow
  698. // other threads waiting on the cache purge to continue.
  699. //
  700. KeSetEvent(&Fcb->NonPagedFcb->PurgeCacheSynchronizer, 0, FALSE);
  701. #endif
  702. return(CacheReturnValue);
  703. }
  704.