Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1929 lines
54 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. scavengr.c
  5. Abstract:
  6. This module implements the scavenging routines in RDBSS.
  7. Author:
  8. Balan Sethu Raman [SethuR] 9-sep-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // only one of these!
  15. //
  16. KMUTEX RxScavengerMutex;
  17. VOID
  18. RxScavengerFinalizeEntries (
  19. PRDBSS_DEVICE_OBJECT RxDeviceObject
  20. );
  21. PRDBSS_DEVICE_OBJECT
  22. RxGetDeviceObjectOfInstance (
  23. PVOID pInstance
  24. );
  25. VOID
  26. RxScavengerTimerRoutine (
  27. PVOID Context
  28. );
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(PAGE, RxPurgeFobxFromCache)
  31. #pragma alloc_text(PAGE, RxMarkFobxOnCleanup)
  32. #pragma alloc_text(PAGE, RxMarkFobxOnClose)
  33. #pragma alloc_text(PAGE, RxPurgeFobx)
  34. #pragma alloc_text(PAGE, RxInitializePurgeSyncronizationContext)
  35. #pragma alloc_text(PAGE, RxPurgeRelatedFobxs)
  36. #pragma alloc_text(PAGE, RxPurgeAllFobxs)
  37. #pragma alloc_text(PAGE, RxGetDeviceObjectOfInstance)
  38. #pragma alloc_text(PAGE, RxpMarkInstanceForScavengedFinalization)
  39. #pragma alloc_text(PAGE, RxpUndoScavengerFinalizationMarking)
  40. #pragma alloc_text(PAGE, RxScavengeVNetRoots)
  41. #pragma alloc_text(PAGE, RxScavengeRelatedFobxs)
  42. #pragma alloc_text(PAGE, RxScavengeAllFobxs)
  43. #pragma alloc_text(PAGE, RxScavengerFinalizeEntries)
  44. #pragma alloc_text(PAGE, RxScavengerTimerRoutine)
  45. #pragma alloc_text(PAGE, RxTerminateScavenging)
  46. #endif
  47. //
  48. // Local debug trace level
  49. //
  50. #define Dbg (DEBUG_TRACE_SCAVENGER)
  51. #define RxAcquireFcbScavengerMutex(FcbScavenger) \
  52. RxAcquireScavengerMutex(); \
  53. SetFlag((FcbScavenger)->State, RX_SCAVENGER_MUTEX_ACQUIRED )
  54. #define RxReleaseFcbScavengerMutex(FcbScavenger) \
  55. ClearFlag((FcbScavenger)->State, RX_SCAVENGER_MUTEX_ACQUIRED ); \
  56. RxReleaseScavengerMutex()
  57. #define RX_SCAVENGER_FINALIZATION_TIME_INTERVAL (10 * 1000 * 1000 * 10)
  58. NTSTATUS
  59. RxPurgeFobxFromCache (
  60. PFOBX Fobx
  61. )
  62. /*++
  63. Routine Description:
  64. This routine purges an FOBX for which a close is pending
  65. Arguments:
  66. Fobx -- the FOBX instance
  67. Notes:
  68. At cleanup there are no more user handles associated with the file object.
  69. In such cases the time window between close and clanup is dictated by the
  70. additional references maintained by the memory manager / cache manager.
  71. This routine unlike the one that follows does not attempt to force the
  72. operations from the memory manager. It merely purges the underlying FCB
  73. from the cache
  74. The FOBX must have been referenced on entry to this routine and it will
  75. lose that reference on exit.
  76. --*/
  77. {
  78. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  79. PFCB Fcb = Fobx->SrvOpen->Fcb;
  80. PAGED_CODE();
  81. ASSERT( Fcb != NULL );
  82. Status = RxAcquireExclusiveFcb( NULL, Fcb );
  83. if (Status == STATUS_SUCCESS) {
  84. BOOLEAN Result;
  85. RxReferenceNetFcb( Fcb );
  86. if (!FlagOn( Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED ) &&
  87. (Fobx->SrvOpen->UncleanFobxCount == 0)) {
  88. Status = RxPurgeFcbInSystemCache( Fcb,
  89. NULL,
  90. 0,
  91. FALSE,
  92. TRUE );
  93. } else {
  94. RxLog(( "Skipping Purging %lx\n", Fobx ));
  95. RxWmiLog( LOG,
  96. RxPurgeFobxFromCache,
  97. LOGPTR( Fobx ) );
  98. }
  99. RxDereferenceNetFobx( Fobx, LHS_ExclusiveLockHeld );
  100. if (!RxDereferenceAndFinalizeNetFcb( Fcb, NULL, FALSE, FALSE )) {
  101. RxReleaseFcb( NULL, Fcb );
  102. }
  103. } else {
  104. RxDereferenceNetFobx( Fobx, LHS_LockNotHeld );
  105. }
  106. return Status;
  107. }
  108. VOID
  109. RxMarkFobxOnCleanup (
  110. PFOBX Fobx,
  111. PBOOLEAN NeedPurge
  112. )
  113. /*++
  114. Routine Description:
  115. Thie routine marks a FOBX for special processing on cleanup
  116. Arguments:
  117. Fobx -- the FOBX instance
  118. Notes:
  119. At cleanup there are no more user handles associated with the file object.
  120. In such cases the time window between close and clanup is dictated by the
  121. additional references maintained by the memory manager / cache manager.
  122. On cleanup the FOBX is put on a close pending list and removed from it
  123. when the corresponding list when a close operation is received. In the interim
  124. if an OPEN is failing with ACCESS_DENIED status then the RDBSS can force a
  125. purge.
  126. Only diskfile type fobxs are placed on the delayed-close list.
  127. --*/
  128. {
  129. PAGED_CODE();
  130. if (Fobx != NULL) {
  131. PFCB Fcb = (PFCB)Fobx->SrvOpen->Fcb;
  132. PLIST_ENTRY ListEntry;
  133. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  134. PRDBSS_SCAVENGER RxScavenger;
  135. PFOBX FobxToBePurged = NULL;
  136. ASSERT( NodeTypeIsFcb( Fcb ));
  137. RxDeviceObject = Fcb->RxDeviceObject;
  138. RxScavenger = RxDeviceObject->pRdbssScavenger;
  139. RxAcquireScavengerMutex();
  140. if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) ||
  141. (Fcb->VNetRoot->NetRoot->DeviceType != FILE_DEVICE_DISK)) {
  142. //
  143. // the markfobxatclose will want to remove this from a list. just fix up
  144. // the list pointers and get out
  145. //
  146. SetFlag( Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT );
  147. InitializeListHead( &Fobx->ClosePendingList );
  148. RxScavenger->NumberOfDormantFiles += 1;
  149. } else {
  150. //
  151. // Ensure that the limit of dormant files specified for the given server is
  152. // not exceeded. If the limit will be exceeded pick an entry from the
  153. // list of files that are currently dormant and purge it.
  154. //
  155. ASSERT( RxScavenger->NumberOfDormantFiles >= 0 );
  156. if (RxScavenger->NumberOfDormantFiles >= RxScavenger->MaximumNumberOfDormantFiles) {
  157. //
  158. // If the number of dormant files exceeds the limit specified for the
  159. // given server a currently dormant file needs to be picked up for
  160. // purging.
  161. //
  162. ListEntry = RxScavenger->ClosePendingFobxsList.Flink;
  163. if (ListEntry != &RxScavenger->ClosePendingFobxsList) {
  164. FobxToBePurged = (PFOBX)(CONTAINING_RECORD( ListEntry,
  165. FOBX,
  166. ClosePendingList ));
  167. if ((FobxToBePurged->SrvOpen != NULL) &&
  168. (FobxToBePurged->SrvOpen->Fcb == Fcb)) {
  169. //
  170. // The first FOBX in the close pending list and the one about to be
  171. // inserted share the same FCB. Instaed of removing the first one
  172. // a purge is forced on the current FOBX. This avoids the resource
  173. // release/acquire that would have been required otherwise
  174. //
  175. *NeedPurge = TRUE;
  176. FobxToBePurged = NULL;
  177. } else {
  178. RxReferenceNetFobx( FobxToBePurged );
  179. }
  180. }
  181. }
  182. SetFlag( Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT );
  183. InsertTailList( &RxScavenger->ClosePendingFobxsList, &Fobx->ClosePendingList);
  184. if (RxScavenger->NumberOfDormantFiles == 0) {
  185. BOOLEAN PostTimerRequest;
  186. if (RxScavenger->State == RDBSS_SCAVENGER_INACTIVE) {
  187. RxScavenger->State = RDBSS_SCAVENGER_DORMANT;
  188. PostTimerRequest = TRUE;
  189. } else {
  190. PostTimerRequest = FALSE;
  191. }
  192. if (PostTimerRequest) {
  193. LARGE_INTEGER TimeInterval;
  194. //
  195. // Post a one shot timer request for scheduling the scavenger after a
  196. // predetermined amount of time.
  197. //
  198. TimeInterval.QuadPart = RX_SCAVENGER_FINALIZATION_TIME_INTERVAL;
  199. RxPostOneShotTimerRequest( RxFileSystemDeviceObject,
  200. &RxScavenger->WorkItem,
  201. RxScavengerTimerRoutine,
  202. RxDeviceObject,
  203. TimeInterval );
  204. }
  205. }
  206. RxScavenger->NumberOfDormantFiles += 1;
  207. }
  208. RxReleaseScavengerMutex();
  209. if (FobxToBePurged != NULL) {
  210. NTSTATUS Status;
  211. Status = RxPurgeFobxFromCache( FobxToBePurged );
  212. if (Status != STATUS_SUCCESS) {
  213. *NeedPurge = TRUE;
  214. }
  215. }
  216. }
  217. }
  218. VOID
  219. RxMarkFobxOnClose (
  220. PFOBX Fobx
  221. )
  222. /*++
  223. Routine Description:
  224. This routine undoes the marking done on cleanup
  225. Arguments:
  226. Fobx -- the FOBX instance
  227. Notes:
  228. At cleanup there are no more user handles associated with the file object.
  229. In such cases the time window between close and clanup is dictated by the
  230. additional references maintained by the memory manager / cache manager.
  231. On cleanup the FOBX is put on a close pending list and removed from it
  232. when the corresponding list when a close operation is received. In the interim
  233. if an OPEN is failing with ACCESS_DENIED status then the RDBSS can force a
  234. purge.
  235. --*/
  236. {
  237. PAGED_CODE();
  238. if (Fobx != NULL) {
  239. PFCB Fcb = Fobx->SrvOpen->Fcb;
  240. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  241. PRDBSS_SCAVENGER RxScavenger;
  242. ASSERT( NodeTypeIsFcb( Fcb ));
  243. RxDeviceObject = Fcb->RxDeviceObject;
  244. RxScavenger = RxDeviceObject->pRdbssScavenger;
  245. RxAcquireScavengerMutex();
  246. if (FlagOn( Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT )) {
  247. if (!Fobx->fOpenCountDecremented) {
  248. InterlockedDecrement( &Fcb->OpenCount );
  249. Fobx->fOpenCountDecremented = TRUE;
  250. }
  251. InterlockedDecrement( &RxScavenger->NumberOfDormantFiles );
  252. ClearFlag( Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT );
  253. }
  254. if (!IsListEmpty( &Fobx->ClosePendingList )) {
  255. RemoveEntryList( &Fobx->ClosePendingList );
  256. InitializeListHead( &Fobx->ClosePendingList );
  257. }
  258. RxReleaseScavengerMutex();
  259. }
  260. }
  261. BOOLEAN
  262. RxPurgeFobx (
  263. PFOBX Fobx
  264. )
  265. /*++
  266. Routine Description:
  267. This routine purges an FOBX for which a close is pending
  268. Arguments:
  269. Fobx -- the FOBX instance
  270. Notes:
  271. At cleanup there are no more user handles associated with the file object.
  272. In such cases the time window between close and clanup is dictated by the
  273. additional references maintained by the memory manager / cache manager.
  274. On cleanup the FOBX is put on a close pending list and removed from it
  275. when the corresponding list when a close operation is received. In the interim
  276. if an OPEN is failing with ACCESS_DENIED status then the RDBSS can force a
  277. purge.
  278. --*/
  279. {
  280. NTSTATUS Status;
  281. PFCB Fcb = Fobx->SrvOpen->Fcb;
  282. PAGED_CODE();
  283. Status = RxAcquireExclusiveFcb( NULL, Fcb );
  284. ASSERT( Status == STATUS_SUCCESS );
  285. //
  286. // Carry out the purge operation
  287. //
  288. Status = RxPurgeFcbInSystemCache( Fcb,
  289. NULL,
  290. 0,
  291. FALSE,
  292. TRUE );
  293. RxReleaseFcb( NULL, Fcb );
  294. if (Status != STATUS_SUCCESS) {
  295. RxLog(( "PurgeFobxCCFail %lx %lx %lx", Fobx, Fcb, FALSE ));
  296. RxWmiLog( LOG,
  297. RxPurgeFobx_1,
  298. LOGPTR( Fobx )
  299. LOGPTR( Fcb ) );
  300. return FALSE;
  301. }
  302. //
  303. // try to flush the image section....it may fail
  304. //
  305. if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite )) {
  306. RxLog(( "PurgeFobxImFail %lx %lx %lx", Fobx, Fcb, FALSE ));
  307. RxWmiLog( LOG,
  308. RxPurgeFobx_2,
  309. LOGPTR( Fobx )
  310. LOGPTR( Fcb ) );
  311. return FALSE;
  312. }
  313. //
  314. // try to flush the user data sections section....it may fail
  315. //
  316. if (!MmForceSectionClosed( &Fcb->NonPaged->SectionObjectPointers, TRUE )) {
  317. RxLog(( "PurgeFobxUsFail %lx %lx %lx", Fobx, Fcb, FALSE ));
  318. RxWmiLog( LOG,
  319. RxPurgeFobx_3,
  320. LOGPTR( Fobx )
  321. LOGPTR( Fcb ) );
  322. return FALSE;
  323. }
  324. RxLog(( "PurgeFobx %lx %lx %lx", Fobx, Fcb, TRUE ));
  325. RxWmiLog( LOG,
  326. RxPurgeFobx_4,
  327. LOGPTR( Fobx )
  328. LOGPTR( Fcb ) );
  329. return TRUE;
  330. }
  331. VOID
  332. RxInitializePurgeSyncronizationContext (
  333. PPURGE_SYNCHRONIZATION_CONTEXT Context
  334. )
  335. /*++
  336. Routine Description:
  337. This routine inits a purge synchronization context
  338. Arguments:
  339. Context - synchronization context
  340. Notes:
  341. --*/
  342. {
  343. PAGED_CODE();
  344. InitializeListHead( &Context->ContextsAwaitingPurgeCompletion );
  345. Context->PurgeInProgress = FALSE;
  346. }
  347. VOID
  348. RxSynchronizeWithScavenger (
  349. IN PRX_CONTEXT RxContext,
  350. IN PFCB Fcb
  351. )
  352. /*++
  353. Routine Description:
  354. This routine synchronizes the current thread with any scavenger finalization
  355. occuring on the current fcb
  356. Arguments:
  357. RxContext -
  358. Notes:
  359. --*/
  360. {
  361. NTSTATUS Status;
  362. BOOLEAN ReacquireFcbLock = FALSE;
  363. PRDBSS_SCAVENGER RxScavenger = Fcb->RxDeviceObject->pRdbssScavenger;
  364. RxAcquireScavengerMutex();
  365. if ((RxScavenger->CurrentScavengerThread != PsGetCurrentThread()) &&
  366. (RxScavenger->CurrentFcbForClosePendingProcessing == Fcb)) {
  367. ReacquireFcbLock = TRUE;
  368. RxReleaseFcb( RxContext, Fcb );
  369. while (RxScavenger->CurrentFcbForClosePendingProcessing == Fcb) {
  370. RxReleaseScavengerMutex();
  371. KeWaitForSingleObject( &(RxScavenger->ClosePendingProcessingSyncEvent),
  372. Executive,
  373. KernelMode,
  374. TRUE,
  375. NULL);
  376. RxAcquireScavengerMutex();
  377. }
  378. }
  379. RxReleaseScavengerMutex();
  380. if (ReacquireFcbLock) {
  381. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  382. ASSERT( Status == STATUS_SUCCESS );
  383. }
  384. }
  385. NTSTATUS
  386. RxPurgeRelatedFobxs (
  387. PNET_ROOT NetRoot,
  388. PRX_CONTEXT RxContext,
  389. BOOLEAN AttemptFinalize,
  390. PFCB PurgingFcb
  391. )
  392. /*++
  393. Routine Description:
  394. This routine purges all the FOBX's associated with a NET_ROOT
  395. Arguments:
  396. NetRoot -- the NET_ROOT for which the FOBX's need to be purged
  397. RxContext -- the RX_CONTEXT instance
  398. Notes:
  399. At cleanup there are no more user handles associated with the file object.
  400. In such cases the time window between close and clanup is dictated by the
  401. additional references maintained by the memory manager / cache manager.
  402. On cleanup the FOBX is put on a close pending list and removed from it
  403. when the corresponding list when a close operation is received. In the interim
  404. if an OPEN is failing with ACCESS_DENIED status then the RDBSS can force a
  405. purge.
  406. This is a synchronous operation.
  407. --*/
  408. {
  409. BOOLEAN ScavengerMutexAcquired = FALSE;
  410. NTSTATUS Status;
  411. ULONG FobxsSuccessfullyPurged = 0;
  412. PPURGE_SYNCHRONIZATION_CONTEXT PurgeContext;
  413. LIST_ENTRY FailedToPurgeFobxList;
  414. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  415. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  416. PLIST_ENTRY ListEntry = NULL;
  417. PAGED_CODE();
  418. PurgeContext = &NetRoot->PurgeSyncronizationContext;
  419. InitializeListHead( &FailedToPurgeFobxList );
  420. RxAcquireScavengerMutex();
  421. //
  422. // If the purge operation for this net root is currently under way hold
  423. // this request till it completes else initiate the operation after
  424. // updating the state of the net root.
  425. //
  426. if (PurgeContext->PurgeInProgress) {
  427. InsertTailList( &PurgeContext->ContextsAwaitingPurgeCompletion,
  428. &RxContext->RxContextSerializationQLinks );
  429. RxReleaseScavengerMutex();
  430. RxWaitSync( RxContext );
  431. RxAcquireScavengerMutex();
  432. }
  433. PurgeContext->PurgeInProgress = TRUE;
  434. RxWmiLog( LOG,
  435. RxPurgeRelatedFobxs_3,
  436. LOGPTR( RxContext )
  437. LOGPTR( NetRoot ) );
  438. while (RxScavenger->CurrentNetRootForClosePendingProcessing == NetRoot) {
  439. RxReleaseScavengerMutex();
  440. KeWaitForSingleObject( &(RxScavenger->ClosePendingProcessingSyncEvent),
  441. Executive,
  442. KernelMode,
  443. TRUE,
  444. NULL );
  445. RxAcquireScavengerMutex();
  446. }
  447. ScavengerMutexAcquired = TRUE;
  448. //
  449. // An attempt should be made to purge all the FOBX's that had a close
  450. // pending before the purge request was received.
  451. //
  452. for (;;) {
  453. PFOBX Fobx;
  454. PFCB Fcb;
  455. BOOLEAN PurgeResult;
  456. Fobx = NULL;
  457. ListEntry = RxScavenger->ClosePendingFobxsList.Flink;
  458. while (ListEntry != &RxScavenger->ClosePendingFobxsList) {
  459. PFOBX TempFobx;
  460. TempFobx = (PFOBX)(CONTAINING_RECORD( ListEntry, FOBX, ClosePendingList ));
  461. RxLog(( "TempFobx=%lx", TempFobx ));
  462. RxWmiLog( LOG,
  463. RxPurgeRelatedFobxs_1,
  464. LOGPTR( TempFobx ) );
  465. if ((TempFobx->SrvOpen != NULL) &&
  466. (TempFobx->SrvOpen->Fcb != NULL) &&
  467. (TempFobx->SrvOpen->Fcb->VNetRoot != NULL) &&
  468. ((PNET_ROOT)TempFobx->SrvOpen->Fcb->VNetRoot->NetRoot == NetRoot)) {
  469. NTSTATUS PurgeStatus = STATUS_MORE_PROCESSING_REQUIRED;
  470. if ((PurgingFcb != NULL) &&
  471. (TempFobx->SrvOpen->Fcb != PurgingFcb)) {
  472. MINIRDR_CALL_THROUGH( PurgeStatus,
  473. RxDeviceObject->Dispatch,
  474. MRxAreFilesAliased,
  475. (TempFobx->SrvOpen->Fcb,PurgingFcb) );
  476. }
  477. if (PurgeStatus != STATUS_SUCCESS) {
  478. RemoveEntryList( ListEntry );
  479. InitializeListHead( ListEntry );
  480. Fobx = TempFobx;
  481. break;
  482. } else {
  483. ListEntry = ListEntry->Flink;
  484. }
  485. } else {
  486. ListEntry = ListEntry->Flink;
  487. }
  488. }
  489. if (Fobx != NULL) {
  490. RxReferenceNetFobx( Fobx );
  491. } else {
  492. //
  493. // Try to wake up the next waiter if any.
  494. //
  495. if (!IsListEmpty(&PurgeContext->ContextsAwaitingPurgeCompletion)) {
  496. PRX_CONTEXT NextContext;
  497. ListEntry = PurgeContext->ContextsAwaitingPurgeCompletion.Flink;
  498. RemoveEntryList( ListEntry );
  499. NextContext = (PRX_CONTEXT)(CONTAINING_RECORD( ListEntry,
  500. RX_CONTEXT,
  501. RxContextSerializationQLinks ));
  502. RxSignalSynchronousWaiter( NextContext );
  503. } else {
  504. PurgeContext->PurgeInProgress = FALSE;
  505. }
  506. }
  507. ScavengerMutexAcquired = FALSE;
  508. RxReleaseScavengerMutex();
  509. if (Fobx == NULL) {
  510. break;
  511. }
  512. //
  513. // Purge the FOBX.
  514. //
  515. PurgeResult = RxPurgeFobx( Fobx );
  516. if (PurgeResult) {
  517. FobxsSuccessfullyPurged += 1;
  518. }
  519. Fcb = Fobx->SrvOpen->Fcb;
  520. if (AttemptFinalize &&
  521. (RxAcquireExclusiveFcb(NULL,Fcb) == STATUS_SUCCESS)) {
  522. RxReferenceNetFcb( Fcb );
  523. RxDereferenceNetFobx( Fobx, LHS_ExclusiveLockHeld );
  524. if (!RxDereferenceAndFinalizeNetFcb( Fcb, NULL, FALSE, FALSE )) {
  525. RxReleaseFcb( NULL, Fcb );
  526. }
  527. } else {
  528. RxDereferenceNetFobx( Fobx, LHS_LockNotHeld );
  529. }
  530. if (!PurgeResult) {
  531. RxLog(( "SCVNGR:FailedToPurge %lx\n", Fcb ));
  532. RxWmiLog( LOG,
  533. RxPurgeRelatedFobxs_2,
  534. LOGPTR( Fcb ) );
  535. }
  536. RxAcquireScavengerMutex();
  537. ScavengerMutexAcquired = TRUE;
  538. }
  539. if (ScavengerMutexAcquired) {
  540. RxReleaseScavengerMutex();
  541. }
  542. if (FobxsSuccessfullyPurged > 0) {
  543. Status = STATUS_SUCCESS;
  544. } else {
  545. Status = STATUS_UNSUCCESSFUL;
  546. }
  547. return Status;
  548. }
  549. VOID
  550. RxPurgeAllFobxs (
  551. PRDBSS_DEVICE_OBJECT RxDeviceObject
  552. )
  553. /*++
  554. Routine Description:
  555. This routine purges all the FOBX's while stopping the scavenger
  556. Arguments:
  557. RxDeviceObject -- the mini redirector device for which the purge should be done
  558. --*/
  559. {
  560. PLIST_ENTRY ListEntry = NULL;
  561. PFOBX Fobx;
  562. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  563. PAGED_CODE();
  564. for (;;) {
  565. PFCB Fcb;
  566. RxAcquireScavengerMutex();
  567. ListEntry = RxScavenger->ClosePendingFobxsList.Flink;
  568. ASSERT( ListEntry != NULL );
  569. if (ListEntry != &RxScavenger->ClosePendingFobxsList) {
  570. Fobx = (PFOBX)(CONTAINING_RECORD( ListEntry, FOBX, ClosePendingList ));
  571. ASSERT( FlagOn( Fobx->NodeTypeCode, ~RX_SCAVENGER_MASK ) == RDBSS_NTC_FOBX );
  572. ASSERT( ListEntry->Flink != NULL );
  573. ASSERT( ListEntry->Blink != NULL );
  574. RemoveEntryList( ListEntry );
  575. InitializeListHead( ListEntry );
  576. RxReferenceNetFobx( Fobx );
  577. } else {
  578. Fobx = NULL;
  579. }
  580. RxReleaseScavengerMutex();
  581. if (Fobx == NULL) {
  582. break;
  583. }
  584. Fcb = Fobx->SrvOpen->Fcb;
  585. RxPurgeFobx( Fobx );
  586. if (RxAcquireExclusiveFcb( NULL, Fcb ) == STATUS_SUCCESS) {
  587. RxReferenceNetFcb( Fcb );
  588. RxDereferenceNetFobx( Fobx, LHS_ExclusiveLockHeld );
  589. if ( !RxDereferenceAndFinalizeNetFcb( Fcb, NULL, FALSE, FALSE )) {
  590. RxReleaseFcb( NULL, Fcb );
  591. }
  592. } else {
  593. RxLog(( "RxPurgeAllFobxs: FCB %lx not accqd.\n", Fcb ));
  594. RxWmiLog( LOG,
  595. RxPurgeAllFobxs,
  596. LOGPTR( Fcb ) );
  597. RxDereferenceNetFobx( Fobx, LHS_LockNotHeld );
  598. }
  599. }
  600. }
  601. PRDBSS_DEVICE_OBJECT
  602. RxGetDeviceObjectOfInstance (
  603. PVOID Instance
  604. )
  605. /*++
  606. Routine Description:
  607. The routine finds out the device object of an upper structure.
  608. Arguments:
  609. Instance - the instance
  610. Return Value:
  611. none.
  612. --*/
  613. {
  614. ULONG NodeTypeCode = NodeType( Instance ) & ~RX_SCAVENGER_MASK;
  615. PAGED_CODE();
  616. ASSERT( (NodeTypeCode == RDBSS_NTC_SRVCALL) ||
  617. (NodeTypeCode == RDBSS_NTC_NETROOT) ||
  618. (NodeTypeCode == RDBSS_NTC_V_NETROOT) ||
  619. (NodeTypeCode == RDBSS_NTC_SRVOPEN) ||
  620. (NodeTypeCode == RDBSS_NTC_FOBX) );
  621. switch ( NodeTypeCode ) {
  622. case RDBSS_NTC_SRVCALL:
  623. return ((PSRV_CALL)Instance)->RxDeviceObject;
  624. // no break;
  625. case RDBSS_NTC_NETROOT:
  626. return ((PNET_ROOT)Instance)->SrvCall->RxDeviceObject;
  627. // no break;
  628. case RDBSS_NTC_V_NETROOT:
  629. return ((PV_NET_ROOT)Instance)->NetRoot->SrvCall->RxDeviceObject;
  630. // no break;
  631. case RDBSS_NTC_SRVOPEN:
  632. return ((PSRV_OPEN)Instance)->Fcb->RxDeviceObject;
  633. // no break;
  634. case RDBSS_NTC_FOBX:
  635. return ((PFOBX)Instance)->SrvOpen->Fcb->RxDeviceObject;
  636. // no break;
  637. default:
  638. return NULL;
  639. }
  640. }
  641. VOID
  642. RxpMarkInstanceForScavengedFinalization (
  643. PVOID Instance
  644. )
  645. /*++
  646. Routine Description:
  647. Thie routine marks a reference counted instance for scavenging
  648. Arguments:
  649. Instance -- the instance to be marked for finalization by the scavenger
  650. Notes:
  651. Currently scavenging has been implemented for SRV_CALL,NET_ROOT and V_NET_ROOT.
  652. The FCB scavenging is handled separately. The FOBX can and should always be
  653. synchronously finalized. The only data structure that will have to be potentially
  654. enabled for scavenged finalization are SRV_OPEN's.
  655. The Scavenger as it is implemented currently will not consume any system resources
  656. till there is a need for scavenged finalization. The first entry to be marked for
  657. scavenged finalization results in a timer request being posted for the scavenger.
  658. In the current implementation the timer requests are posted as one shot timer requests.
  659. This implies that there are no guarantess as regards the time interval within which
  660. the entries will be finalized. The scavenger activation mechanism is a potential
  661. candidate for fine tuning at a later stage.
  662. On Entry -- Scavenger Mutex must have been accquired
  663. On Exit -- no change in resource ownership.
  664. --*/
  665. {
  666. BOOLEAN PostTimerRequest = FALSE;
  667. PLIST_ENTRY ListHead = NULL;
  668. PLIST_ENTRY ListEntry = NULL;
  669. PNODE_TYPE_CODE_AND_SIZE Node = (PNODE_TYPE_CODE_AND_SIZE)Instance;
  670. USHORT InstanceType;
  671. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxGetDeviceObjectOfInstance( Instance );
  672. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  673. PAGED_CODE();
  674. RxDbgTrace( 0, Dbg, ("Marking %lx of type %lx for scavenged finalization\n", Instance, NodeType( Instance )) );
  675. InstanceType = Node->NodeTypeCode;
  676. if (Node->NodeReferenceCount <= 1) {
  677. //
  678. // Mark the entry for scavenging.
  679. //
  680. SetFlag( Node->NodeTypeCode, RX_SCAVENGER_MASK );
  681. RxLog(( "Marked for scavenging %lx", Node ));
  682. RxWmiLog( LOG,
  683. RxpMarkInstanceForScavengedFinalization,
  684. LOGPTR( Node ) );
  685. switch (InstanceType) {
  686. case RDBSS_NTC_SRVCALL:
  687. {
  688. PSRV_CALL SrvCall = (PSRV_CALL)Instance;
  689. RxScavenger->SrvCallsToBeFinalized += 1;
  690. ListHead = &RxScavenger->SrvCallFinalizationList;
  691. ListEntry = &SrvCall->ScavengerFinalizationList;
  692. }
  693. break;
  694. case RDBSS_NTC_NETROOT:
  695. {
  696. PNET_ROOT NetRoot = (PNET_ROOT)Instance;
  697. RxScavenger->NetRootsToBeFinalized += 1;
  698. ListHead = &RxScavenger->NetRootFinalizationList;
  699. ListEntry = &NetRoot->ScavengerFinalizationList;
  700. }
  701. break;
  702. case RDBSS_NTC_V_NETROOT:
  703. {
  704. PV_NET_ROOT VNetRoot = (PV_NET_ROOT)Instance;
  705. RxScavenger->VNetRootsToBeFinalized += 1;
  706. ListHead = &RxScavenger->VNetRootFinalizationList;
  707. ListEntry = &VNetRoot->ScavengerFinalizationList;
  708. }
  709. break;
  710. case RDBSS_NTC_SRVOPEN:
  711. {
  712. PSRV_OPEN SrvOpen = (PSRV_OPEN)Instance;
  713. RxScavenger->SrvOpensToBeFinalized += 1;
  714. ListHead = &RxScavenger->SrvOpenFinalizationList;
  715. ListEntry = &SrvOpen->ScavengerFinalizationList;
  716. }
  717. break;
  718. case RDBSS_NTC_FOBX:
  719. {
  720. PFOBX Fobx = (PFOBX)Instance;
  721. RxScavenger->FobxsToBeFinalized += 1;
  722. ListHead = &RxScavenger->FobxFinalizationList;
  723. ListEntry = &Fobx->ScavengerFinalizationList;
  724. }
  725. break;
  726. default:
  727. break;
  728. }
  729. InterlockedIncrement( &Node->NodeReferenceCount );
  730. }
  731. if (ListHead != NULL) {
  732. InsertTailList( ListHead, ListEntry );
  733. if (RxScavenger->State == RDBSS_SCAVENGER_INACTIVE) {
  734. RxScavenger->State = RDBSS_SCAVENGER_DORMANT;
  735. PostTimerRequest = TRUE;
  736. } else {
  737. PostTimerRequest = FALSE;
  738. }
  739. }
  740. if (PostTimerRequest) {
  741. LARGE_INTEGER TimeInterval;
  742. //
  743. // Post a one shot timer request for scheduling the scavenger after a
  744. // predetermined amount of time.
  745. //
  746. TimeInterval.QuadPart = RX_SCAVENGER_FINALIZATION_TIME_INTERVAL;
  747. RxPostOneShotTimerRequest( RxFileSystemDeviceObject,
  748. &RxScavenger->WorkItem,
  749. RxScavengerTimerRoutine,
  750. RxDeviceObject,
  751. TimeInterval );
  752. }
  753. }
  754. VOID
  755. RxpUndoScavengerFinalizationMarking (
  756. PVOID Instance
  757. )
  758. /*++
  759. Routine Description:
  760. This routine undoes the marking for scavenged finalization
  761. Arguments:
  762. Instance -- the instance to be unmarked
  763. Notes:
  764. This routine is typically invoked when a reference is made to an entry that has
  765. been marked for scavenging. Since the scavenger routine that does the finalization
  766. needs to acquire the exclusive lock this routine should be called with the
  767. appropriate lock held in a shared mode atleast. This routine removes it from the list
  768. of entries marked for scavenging and rips off the scavenger mask from the node type.
  769. --*/
  770. {
  771. PLIST_ENTRY ListEntry;
  772. PNODE_TYPE_CODE_AND_SIZE Node = (PNODE_TYPE_CODE_AND_SIZE)Instance;
  773. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxGetDeviceObjectOfInstance( Instance );
  774. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  775. PAGED_CODE();
  776. RxDbgTrace( 0, Dbg, ("SCAVENGER -- undoing the marking for %lx of type %lx\n", Node, Node->NodeTypeCode) );
  777. if (FlagOn( Node->NodeTypeCode, RX_SCAVENGER_MASK )) {
  778. ClearFlag( Node->NodeTypeCode, RX_SCAVENGER_MASK );
  779. switch (Node->NodeTypeCode) {
  780. case RDBSS_NTC_SRVCALL:
  781. {
  782. PSRV_CALL SrvCall = (PSRV_CALL)Instance;
  783. RxScavenger->SrvCallsToBeFinalized -= 1;
  784. ListEntry = &SrvCall->ScavengerFinalizationList;
  785. }
  786. break;
  787. case RDBSS_NTC_NETROOT:
  788. {
  789. PNET_ROOT NetRoot = (PNET_ROOT)Instance;
  790. RxScavenger->NetRootsToBeFinalized -= 1;
  791. ListEntry = &NetRoot->ScavengerFinalizationList;
  792. }
  793. break;
  794. case RDBSS_NTC_V_NETROOT:
  795. {
  796. PV_NET_ROOT VNetRoot = (PV_NET_ROOT)Instance;
  797. RxScavenger->VNetRootsToBeFinalized -= 1;
  798. ListEntry = &VNetRoot->ScavengerFinalizationList;
  799. }
  800. break;
  801. case RDBSS_NTC_SRVOPEN:
  802. {
  803. PSRV_OPEN SrvOpen = (PSRV_OPEN)Instance;
  804. RxScavenger->SrvOpensToBeFinalized -= 1;
  805. ListEntry = &SrvOpen->ScavengerFinalizationList;
  806. }
  807. break;
  808. case RDBSS_NTC_FOBX:
  809. {
  810. PFOBX Fobx = (PFOBX)Instance;
  811. RxScavenger->FobxsToBeFinalized -= 1;
  812. ListEntry = &Fobx->ScavengerFinalizationList;
  813. }
  814. break;
  815. default:
  816. return;
  817. }
  818. RemoveEntryList( ListEntry );
  819. InitializeListHead( ListEntry );
  820. InterlockedDecrement( &Node->NodeReferenceCount );
  821. }
  822. }
  823. VOID
  824. RxUndoScavengerFinalizationMarking (
  825. PVOID Instance
  826. )
  827. /*++
  828. Routine Description:
  829. This routine undoes the marking for scavenged finalization
  830. Arguments:
  831. Instance -- the instance to be unmarked
  832. --*/
  833. {
  834. RxAcquireScavengerMutex();
  835. RxpUndoScavengerFinalizationMarking( Instance );
  836. RxReleaseScavengerMutex();
  837. }
  838. BOOLEAN
  839. RxScavengeRelatedFobxs (
  840. PFCB Fcb
  841. )
  842. /*++
  843. Routine Description:
  844. Thie routine scavenges all the file objects pertaining to the given FCB.
  845. Notes:
  846. On Entry -- FCB must have been accquired exclusive.
  847. On Exit -- no change in resource acquistion.
  848. --*/
  849. {
  850. BOOLEAN ScavengerMutexAcquired = FALSE;
  851. BOOLEAN AtleastOneFobxScavenged = FALSE;
  852. PRDBSS_DEVICE_OBJECT RxDeviceObject = Fcb->RxDeviceObject;
  853. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  854. PAGED_CODE();
  855. RxAcquireScavengerMutex();
  856. ScavengerMutexAcquired = TRUE;
  857. if (RxScavenger->FobxsToBeFinalized > 0) {
  858. PLIST_ENTRY Entry;
  859. PFOBX Fobx;
  860. LIST_ENTRY FobxList;
  861. InitializeListHead( &FobxList );
  862. Entry = RxScavenger->FobxFinalizationList.Flink;
  863. while (Entry != &RxScavenger->FobxFinalizationList) {
  864. Fobx = (PFOBX)CONTAINING_RECORD( Entry, FOBX, ScavengerFinalizationList );
  865. Entry = Entry->Flink;
  866. if (Fobx->SrvOpen != NULL &&
  867. Fobx->SrvOpen->Fcb == Fcb) {
  868. RxpUndoScavengerFinalizationMarking( Fobx );
  869. ASSERT( NodeType( Fobx ) == RDBSS_NTC_FOBX);
  870. InsertTailList( &FobxList, &Fobx->ScavengerFinalizationList );
  871. }
  872. }
  873. ScavengerMutexAcquired = FALSE;
  874. RxReleaseScavengerMutex();
  875. AtleastOneFobxScavenged = !IsListEmpty( &FobxList );
  876. Entry = FobxList.Flink;
  877. while (!IsListEmpty( &FobxList )) {
  878. Entry = FobxList.Flink;
  879. RemoveEntryList( Entry );
  880. Fobx = (PFOBX)CONTAINING_RECORD( Entry, FOBX, ScavengerFinalizationList );
  881. RxFinalizeNetFobx( Fobx, TRUE, TRUE );
  882. }
  883. }
  884. if (ScavengerMutexAcquired) {
  885. RxReleaseScavengerMutex();
  886. }
  887. return AtleastOneFobxScavenged;
  888. }
  889. VOID
  890. RxpScavengeFobxs(
  891. PRDBSS_SCAVENGER RxScavenger,
  892. PLIST_ENTRY FobxList
  893. )
  894. /*++
  895. Routine Description:
  896. Thie routine scavenges all the file objects in the given list. This routine
  897. does the actual work of scavenging while RxScavengeFobxsForNetRoot and
  898. RxScavengeAllFobxs gather the file object extensions and call this routine
  899. Notes:
  900. --*/
  901. {
  902. while (!IsListEmpty( FobxList )) {
  903. PFCB Fcb;
  904. PFOBX Fobx;
  905. NTSTATUS Status;
  906. PLIST_ENTRY Entry;
  907. Entry = FobxList->Flink;
  908. RemoveEntryList( Entry );
  909. Fobx = (PFOBX)CONTAINING_RECORD( Entry, FOBX, ScavengerFinalizationList );
  910. Fcb = Fobx->SrvOpen->Fcb;
  911. Status = RxAcquireExclusiveFcb( NULL, Fcb );
  912. if (Status == (STATUS_SUCCESS)) {
  913. RxReferenceNetFcb( Fcb );
  914. RxDereferenceNetFobx( Fobx, LHS_ExclusiveLockHeld );
  915. if (!RxDereferenceAndFinalizeNetFcb( Fcb, NULL, FALSE, FALSE )) {
  916. RxReleaseFcb( NULL, Fcb );
  917. }
  918. } else {
  919. RxDereferenceNetFobx( Fobx, LHS_LockNotHeld );
  920. }
  921. }
  922. }
  923. VOID
  924. RxScavengeFobxsForNetRoot (
  925. PNET_ROOT NetRoot,
  926. PFCB PurgingFcb
  927. )
  928. /*++
  929. Routine Description:
  930. Thie routine scavenges all the file objects pertaining to the given net root
  931. instance
  932. Notes:
  933. --*/
  934. {
  935. BOOLEAN ScavengerMutexAcquired = FALSE;
  936. PRDBSS_DEVICE_OBJECT RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
  937. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  938. PAGED_CODE();
  939. RxAcquireScavengerMutex();
  940. ScavengerMutexAcquired = TRUE;
  941. if (RxScavenger->FobxsToBeFinalized > 0) {
  942. PLIST_ENTRY Entry;
  943. PFOBX Fobx;
  944. LIST_ENTRY FobxList;
  945. InitializeListHead( &FobxList );
  946. Entry = RxScavenger->FobxFinalizationList.Flink;
  947. while (Entry != &RxScavenger->FobxFinalizationList) {
  948. Fobx = (PFOBX)CONTAINING_RECORD( Entry, FOBX, ScavengerFinalizationList );
  949. Entry = Entry->Flink;
  950. if ((Fobx->SrvOpen != NULL) &&
  951. (Fobx->SrvOpen->Fcb->NetRoot == NetRoot)) {
  952. NTSTATUS PurgeStatus = STATUS_MORE_PROCESSING_REQUIRED;
  953. if ((PurgingFcb != NULL) &&
  954. (Fobx->SrvOpen->Fcb != PurgingFcb)) {
  955. MINIRDR_CALL_THROUGH( PurgeStatus,
  956. RxDeviceObject->Dispatch,
  957. MRxAreFilesAliased,
  958. (Fobx->SrvOpen->Fcb,PurgingFcb) );
  959. }
  960. if (PurgeStatus != STATUS_SUCCESS) {
  961. RxReferenceNetFobx( Fobx );
  962. ASSERT(NodeType( Fobx ) == RDBSS_NTC_FOBX );
  963. InsertTailList( &FobxList, &Fobx->ScavengerFinalizationList );
  964. }
  965. }
  966. }
  967. ScavengerMutexAcquired = FALSE;
  968. RxReleaseScavengerMutex();
  969. RxpScavengeFobxs( RxScavenger, &FobxList );
  970. }
  971. if (ScavengerMutexAcquired) {
  972. RxReleaseScavengerMutex();
  973. }
  974. return;
  975. }
  976. VOID
  977. RxScavengeAllFobxs (
  978. PRDBSS_DEVICE_OBJECT RxDeviceObject
  979. )
  980. /*++
  981. Routine Description:
  982. Thie routine scavenges all the file objects pertaining to the given mini
  983. redirector device object
  984. Notes:
  985. --*/
  986. {
  987. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  988. PAGED_CODE();
  989. if (RxScavenger->FobxsToBeFinalized > 0) {
  990. PLIST_ENTRY Entry;
  991. PFOBX Fobx;
  992. LIST_ENTRY FobxList;
  993. InitializeListHead( &FobxList );
  994. RxAcquireScavengerMutex();
  995. Entry = RxScavenger->FobxFinalizationList.Flink;
  996. while (Entry != &RxScavenger->FobxFinalizationList) {
  997. Fobx = (PFOBX)CONTAINING_RECORD( Entry, FOBX, ScavengerFinalizationList );
  998. Entry = Entry->Flink;
  999. RxReferenceNetFobx( Fobx );
  1000. ASSERT( NodeType( Fobx ) == RDBSS_NTC_FOBX );
  1001. InsertTailList( &FobxList, &Fobx->ScavengerFinalizationList );
  1002. }
  1003. RxReleaseScavengerMutex();
  1004. RxpScavengeFobxs( RxScavenger, &FobxList );
  1005. }
  1006. }
  1007. BOOLEAN
  1008. RxScavengeVNetRoots (
  1009. PRDBSS_DEVICE_OBJECT RxDeviceObject
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. Notes:
  1014. Return:
  1015. TRUE if at least one vnetroot was scavenged
  1016. --*/
  1017. {
  1018. BOOLEAN AtleastOneEntryScavenged = FALSE;
  1019. PRX_PREFIX_TABLE RxNetNameTable = RxDeviceObject->pRxNetNameTable;
  1020. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  1021. PV_NET_ROOT VNetRoot;
  1022. PAGED_CODE();
  1023. do {
  1024. PVOID Entry;
  1025. RxDbgTrace( 0, Dbg, ("RDBSS SCAVENGER -- Scavenging VNetRoots\n") );
  1026. RxAcquirePrefixTableLockExclusive( RxNetNameTable, TRUE );
  1027. RxAcquireScavengerMutex();
  1028. if (RxScavenger->VNetRootsToBeFinalized > 0) {
  1029. Entry = RemoveHeadList( &RxScavenger->VNetRootFinalizationList );
  1030. VNetRoot = (PV_NET_ROOT) CONTAINING_RECORD( Entry, V_NET_ROOT, ScavengerFinalizationList );
  1031. RxpUndoScavengerFinalizationMarking( VNetRoot );
  1032. ASSERT( NodeType( VNetRoot ) == RDBSS_NTC_V_NETROOT );
  1033. } else {
  1034. VNetRoot = NULL;
  1035. }
  1036. RxReleaseScavengerMutex();
  1037. if (VNetRoot != NULL) {
  1038. RxFinalizeVNetRoot( VNetRoot, TRUE, TRUE );
  1039. AtleastOneEntryScavenged = TRUE;
  1040. }
  1041. RxReleasePrefixTableLock( RxNetNameTable );
  1042. } while (VNetRoot != NULL);
  1043. return AtleastOneEntryScavenged;
  1044. }
  1045. VOID
  1046. RxScavengerFinalizeEntries (
  1047. PRDBSS_DEVICE_OBJECT RxDeviceObject
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Thie routine initiates the delayed finalization of entries
  1052. Notes:
  1053. This routine must always be called only after acquiring the Scavenger Mutex.
  1054. On return from this routine it needs to be reacquired. This is required
  1055. to avoid redundant copying of data structures.
  1056. The performance metric for the scavenger is different from the other routines. In
  1057. the other routines the goal is to do as much work as possible once the lock is
  1058. acquired without having to release it. On the other hand for the scavenger the
  1059. goal is to hold the lock for as short a duration as possible because this
  1060. interferes with the regular activity. This is preferred even if it entails
  1061. frequent relaesing/acquisition of locks since it enables higher degrees of
  1062. concurrency.
  1063. --*/
  1064. {
  1065. BOOLEAN AtleastOneEntryScavenged;
  1066. PRX_PREFIX_TABLE RxNetNameTable = RxDeviceObject->pRxNetNameTable;
  1067. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  1068. PAGED_CODE();
  1069. do {
  1070. AtleastOneEntryScavenged = FALSE;
  1071. RxAcquireScavengerMutex();
  1072. if (RxScavenger->NumberOfDormantFiles > 0) {
  1073. PLIST_ENTRY ListEntry;
  1074. PFOBX Fobx;
  1075. //
  1076. // If the number of dormant files exceeds the limit specified for the
  1077. // given server a currently dormant file needs to be picked up for
  1078. // purging.
  1079. //
  1080. ListEntry = RxScavenger->ClosePendingFobxsList.Flink;
  1081. if (ListEntry != &RxScavenger->ClosePendingFobxsList) {
  1082. Fobx = (PFOBX)(CONTAINING_RECORD( ListEntry, FOBX, ClosePendingList ));
  1083. RemoveEntryList( &Fobx->ClosePendingList );
  1084. InitializeListHead( &Fobx->ClosePendingList );
  1085. RxReferenceNetFobx( Fobx );
  1086. RxScavenger->CurrentScavengerThread = PsGetCurrentThread();
  1087. RxScavenger->CurrentFcbForClosePendingProcessing =
  1088. (PFCB)(Fobx->SrvOpen->Fcb);
  1089. RxScavenger->CurrentNetRootForClosePendingProcessing =
  1090. (PNET_ROOT)(Fobx->SrvOpen->Fcb->NetRoot);
  1091. KeResetEvent( &(RxScavenger->ClosePendingProcessingSyncEvent) );
  1092. } else {
  1093. Fobx = NULL;
  1094. }
  1095. if (Fobx != NULL) {
  1096. NTSTATUS Status;
  1097. RxReleaseScavengerMutex();
  1098. Status = RxPurgeFobxFromCache( Fobx );
  1099. AtleastOneEntryScavenged = (Status == STATUS_SUCCESS);
  1100. RxAcquireScavengerMutex();
  1101. RxScavenger->CurrentScavengerThread = NULL;
  1102. RxScavenger->CurrentFcbForClosePendingProcessing = NULL;
  1103. RxScavenger->CurrentNetRootForClosePendingProcessing = NULL;
  1104. KeSetEvent( &(RxScavenger->ClosePendingProcessingSyncEvent),
  1105. 0,
  1106. FALSE );
  1107. }
  1108. }
  1109. if (RxScavenger->FobxsToBeFinalized > 0) {
  1110. PVOID Entry;
  1111. PFOBX Fobx = NULL;
  1112. PFCB Fcb = NULL;
  1113. RxDbgTrace( 0, Dbg, ("RDBSS SCAVENGER -- Scavenging Fobxs\n") );
  1114. if (RxScavenger->FobxsToBeFinalized > 0) {
  1115. Entry = RxScavenger->FobxFinalizationList.Flink;
  1116. Fobx = (PFOBX) CONTAINING_RECORD( Entry, FOBX, ScavengerFinalizationList );
  1117. Fcb = Fobx->SrvOpen->Fcb;
  1118. RxReferenceNetFcb( Fcb );
  1119. RxScavenger->CurrentScavengerThread = PsGetCurrentThread();
  1120. RxScavenger->CurrentFcbForClosePendingProcessing =
  1121. (PFCB)(Fobx->SrvOpen->Fcb);
  1122. RxScavenger->CurrentNetRootForClosePendingProcessing =
  1123. (PNET_ROOT)(Fobx->SrvOpen->Fcb->NetRoot);
  1124. KeResetEvent( &(RxScavenger->ClosePendingProcessingSyncEvent) );
  1125. } else {
  1126. Fobx = NULL;
  1127. }
  1128. if (Fobx != NULL) {
  1129. NTSTATUS Status;
  1130. RxReleaseScavengerMutex();
  1131. Status = RxAcquireExclusiveFcb( NULL, Fcb );
  1132. if (Status == STATUS_SUCCESS) {
  1133. AtleastOneEntryScavenged = RxScavengeRelatedFobxs(Fcb);
  1134. if (!RxDereferenceAndFinalizeNetFcb( Fcb, NULL, FALSE, FALSE )) {
  1135. RxReleaseFcb( NULL, Fcb );
  1136. }
  1137. } else {
  1138. RxLog(( "Delayed Close Failure FOBX(%lx) FCB(%lx)\n", Fobx, Fcb) );
  1139. RxWmiLog( LOG,
  1140. RxScavengerFinalizeEntries,
  1141. LOGPTR( Fobx )
  1142. LOGPTR( Fcb ) );
  1143. }
  1144. RxAcquireScavengerMutex();
  1145. RxScavenger->CurrentScavengerThread = NULL;
  1146. RxScavenger->CurrentFcbForClosePendingProcessing = NULL;
  1147. RxScavenger->CurrentNetRootForClosePendingProcessing = NULL;
  1148. KeSetEvent( &(RxScavenger->ClosePendingProcessingSyncEvent),
  1149. 0,
  1150. FALSE );
  1151. }
  1152. }
  1153. RxReleaseScavengerMutex();
  1154. if (RxScavenger->SrvOpensToBeFinalized > 0) {
  1155. //
  1156. // SRV_OPEN List should not be empty, potential memory leak
  1157. //
  1158. ASSERT( RxScavenger->SrvOpensToBeFinalized == 0 );
  1159. }
  1160. if (RxScavenger->FcbsToBeFinalized > 0) {
  1161. //
  1162. // FCB list should be empty , potential memory leak
  1163. //
  1164. ASSERT( RxScavenger->FcbsToBeFinalized == 0 );
  1165. }
  1166. if (RxScavenger->VNetRootsToBeFinalized > 0) {
  1167. PVOID Entry;
  1168. PV_NET_ROOT VNetRoot;
  1169. RxDbgTrace( 0, Dbg, ("RDBSS SCAVENGER -- Scavenging VNetRoots\n") );
  1170. RxAcquirePrefixTableLockExclusive( RxNetNameTable, TRUE );
  1171. RxAcquireScavengerMutex();
  1172. if (RxScavenger->VNetRootsToBeFinalized > 0) {
  1173. Entry = RemoveHeadList( &RxScavenger->VNetRootFinalizationList );
  1174. VNetRoot = (PV_NET_ROOT) CONTAINING_RECORD( Entry, V_NET_ROOT, ScavengerFinalizationList );
  1175. RxpUndoScavengerFinalizationMarking( VNetRoot );
  1176. ASSERT( NodeType( VNetRoot ) == RDBSS_NTC_V_NETROOT );
  1177. } else {
  1178. VNetRoot = NULL;
  1179. }
  1180. RxReleaseScavengerMutex();
  1181. if (VNetRoot != NULL) {
  1182. RxFinalizeVNetRoot( VNetRoot, TRUE, TRUE );
  1183. AtleastOneEntryScavenged = TRUE;
  1184. }
  1185. RxReleasePrefixTableLock( RxNetNameTable );
  1186. }
  1187. if (RxScavenger->NetRootsToBeFinalized > 0) {
  1188. PVOID Entry;
  1189. PNET_ROOT NetRoot;
  1190. RxDbgTrace( 0, Dbg, ("RDBSS SCAVENGER -- Scavenging NetRoots\n") );
  1191. RxAcquirePrefixTableLockExclusive( RxNetNameTable, TRUE );
  1192. RxAcquireScavengerMutex();
  1193. if (RxScavenger->NetRootsToBeFinalized > 0) {
  1194. Entry = RemoveHeadList(&RxScavenger->NetRootFinalizationList);
  1195. NetRoot = (PNET_ROOT) CONTAINING_RECORD( Entry, NET_ROOT, ScavengerFinalizationList );
  1196. RxpUndoScavengerFinalizationMarking( NetRoot );
  1197. ASSERT( NodeType( NetRoot ) == RDBSS_NTC_NETROOT);
  1198. } else {
  1199. NetRoot = NULL;
  1200. }
  1201. RxReleaseScavengerMutex();
  1202. if (NetRoot != NULL) {
  1203. RxFinalizeNetRoot( NetRoot, TRUE, TRUE );
  1204. AtleastOneEntryScavenged = TRUE;
  1205. }
  1206. RxReleasePrefixTableLock(RxNetNameTable);
  1207. }
  1208. if (RxScavenger->SrvCallsToBeFinalized > 0) {
  1209. PVOID Entry;
  1210. PSRV_CALL SrvCall;
  1211. RxDbgTrace( 0, Dbg, ("RDBSS SCAVENGER -- Scavenging SrvCalls\n") );
  1212. RxAcquirePrefixTableLockExclusive( RxNetNameTable, TRUE );
  1213. RxAcquireScavengerMutex();
  1214. if (RxScavenger->SrvCallsToBeFinalized > 0) {
  1215. Entry = RemoveHeadList( &RxScavenger->SrvCallFinalizationList );
  1216. SrvCall = (PSRV_CALL) CONTAINING_RECORD( Entry, SRV_CALL, ScavengerFinalizationList );
  1217. RxpUndoScavengerFinalizationMarking( SrvCall );
  1218. ASSERT( NodeType( SrvCall ) == RDBSS_NTC_SRVCALL );
  1219. } else {
  1220. SrvCall = NULL;
  1221. }
  1222. RxReleaseScavengerMutex();
  1223. if (SrvCall != NULL) {
  1224. RxFinalizeSrvCall( SrvCall, TRUE );
  1225. AtleastOneEntryScavenged = TRUE;
  1226. }
  1227. RxReleasePrefixTableLock( RxNetNameTable );
  1228. }
  1229. } while (AtleastOneEntryScavenged);
  1230. }
  1231. VOID
  1232. RxScavengerTimerRoutine (
  1233. PVOID Context
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine is the timer routine that periodically initiates the finalization of
  1238. entries.
  1239. Arguments:
  1240. Context -- the context (actually the RxDeviceObject)
  1241. Notes:
  1242. --*/
  1243. {
  1244. PRDBSS_DEVICE_OBJECT RxDeviceObject = (PRDBSS_DEVICE_OBJECT)Context;
  1245. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  1246. BOOLEAN PostTimerRequest = FALSE;
  1247. PAGED_CODE();
  1248. RxAcquireScavengerMutex();
  1249. KeResetEvent( &RxScavenger->SyncEvent );
  1250. if (RxScavenger->State == RDBSS_SCAVENGER_DORMANT) {
  1251. RxScavenger->State = RDBSS_SCAVENGER_ACTIVE;
  1252. RxReleaseScavengerMutex();
  1253. RxScavengerFinalizeEntries( RxDeviceObject );
  1254. RxAcquireScavengerMutex();
  1255. if (RxScavenger->State == RDBSS_SCAVENGER_ACTIVE) {
  1256. ULONG EntriesToBeFinalized;
  1257. //
  1258. // Check if the scavenger needs to be activated again.
  1259. //
  1260. EntriesToBeFinalized = RxScavenger->SrvCallsToBeFinalized +
  1261. RxScavenger->NetRootsToBeFinalized +
  1262. RxScavenger->VNetRootsToBeFinalized +
  1263. RxScavenger->FcbsToBeFinalized +
  1264. RxScavenger->SrvOpensToBeFinalized +
  1265. RxScavenger->FobxsToBeFinalized +
  1266. RxScavenger->NumberOfDormantFiles;
  1267. if (EntriesToBeFinalized > 0) {
  1268. PostTimerRequest = TRUE;
  1269. RxScavenger->State = RDBSS_SCAVENGER_DORMANT;
  1270. } else {
  1271. RxScavenger->State = RDBSS_SCAVENGER_INACTIVE;
  1272. }
  1273. }
  1274. RxReleaseScavengerMutex();
  1275. if (PostTimerRequest) {
  1276. LARGE_INTEGER TimeInterval;
  1277. TimeInterval.QuadPart = RX_SCAVENGER_FINALIZATION_TIME_INTERVAL;
  1278. RxPostOneShotTimerRequest( RxFileSystemDeviceObject,
  1279. &RxScavenger->WorkItem,
  1280. RxScavengerTimerRoutine,
  1281. RxDeviceObject,
  1282. TimeInterval );
  1283. }
  1284. } else {
  1285. RxReleaseScavengerMutex();
  1286. }
  1287. //
  1288. // Trigger the event.
  1289. //
  1290. KeSetEvent( &RxScavenger->SyncEvent, 0, FALSE );
  1291. }
  1292. VOID
  1293. RxTerminateScavenging (
  1294. PRX_CONTEXT RxContext
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. This routine terminates all scavenging activities in the RDBSS. The termination is
  1299. effected in an orderly fashion after all the entries currently marked for scavenging
  1300. are finalized.
  1301. Arguments:
  1302. RxContext -- the context
  1303. Notes:
  1304. In implementing the scavenger there are two options. The scavenger can latch onto a
  1305. thread and hold onto it from the moment RDBSS comes into existence till it is unloaded.
  1306. Such an implementation renders a thread useless throughout the lifetime of RDBSS.
  1307. If this is to be avoided the alternative is to trigger the scavenger as and when
  1308. required. While this technique addresses the conservation of system resources it
  1309. poses some tricky synchronization problems having to do with start/stop of the RDR.
  1310. Since the RDR can be started/stopped at any time the Scavenger can be in one of three
  1311. states when the RDR is stopped.
  1312. 1) Scavenger is active.
  1313. 2) Scavenger request is in the timer queue.
  1314. 3) Scavenger is inactive.
  1315. Of these case (3) is the easiest since no special action is required.
  1316. If the scavenger is active then this routine has to synchronize with the timer routine
  1317. that is finzalizing the entries. This is achieved by allowing the termination routine to
  1318. modify the Scavenger state under a mutex and waiting for it to signal the event on
  1319. completion.
  1320. --*/
  1321. {
  1322. NTSTATUS Status = STATUS_SUCCESS;
  1323. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  1324. PRDBSS_SCAVENGER RxScavenger = RxDeviceObject->pRdbssScavenger;
  1325. RDBSS_SCAVENGER_STATE PreviousState;
  1326. PAGED_CODE();
  1327. RxAcquireScavengerMutex();
  1328. PreviousState = RxScavenger->State;
  1329. RxScavenger->State = RDBSS_SCAVENGER_SUSPENDED;
  1330. RxReleaseScavengerMutex();
  1331. if (PreviousState == RDBSS_SCAVENGER_DORMANT) {
  1332. //
  1333. // There is a timer request currently active. cancel it
  1334. //
  1335. Status = RxCancelTimerRequest( RxFileSystemDeviceObject, RxScavengerTimerRoutine, RxDeviceObject );
  1336. }
  1337. if ((PreviousState == RDBSS_SCAVENGER_ACTIVE) || (Status == STATUS_NOT_FOUND)) {
  1338. //
  1339. // Either the timer routine was previously active or it could not be cancelled
  1340. // Wait for it to complete
  1341. //
  1342. KeWaitForSingleObject( &RxScavenger->SyncEvent, Executive, KernelMode, FALSE, NULL );
  1343. }
  1344. RxPurgeAllFobxs( RxContext->RxDeviceObject );
  1345. RxScavengerFinalizeEntries( RxContext->RxDeviceObject );
  1346. }