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.

1243 lines
28 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. blksrch.c
  5. Abstract:
  6. This module implements routines for managing search blocks.
  7. Author:
  8. David Treadwell (davidtr) 23-Feb-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "blksrch.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKSRCH
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvAllocateSearch )
  17. #pragma alloc_text( PAGE, SrvCloseSearch )
  18. #pragma alloc_text( PAGE, SrvCloseSearches )
  19. #pragma alloc_text( PAGE, SrvDereferenceSearch )
  20. #pragma alloc_text( PAGE, SrvFreeSearch )
  21. #pragma alloc_text( PAGE, SrvReferenceSearch )
  22. #pragma alloc_text( PAGE, SrvSearchOnDelete )
  23. #pragma alloc_text( PAGE, SrvSearchOnPid )
  24. #pragma alloc_text( PAGE, SrvSearchOnSession )
  25. #pragma alloc_text( PAGE, SrvSearchOnTreeConnect )
  26. #pragma alloc_text( PAGE, SrvTimeoutSearches )
  27. #pragma alloc_text( PAGE, SrvForceTimeoutSearches )
  28. #pragma alloc_text( PAGE, RemoveDuplicateCoreSearches )
  29. #pragma alloc_text( PAGE, SrvAddToSearchHashTable )
  30. #endif
  31. VOID
  32. SrvAllocateSearch (
  33. OUT PSEARCH *Search,
  34. IN PUNICODE_STRING SearchName,
  35. IN BOOLEAN IsCoreSearch
  36. )
  37. /*++
  38. Routine Description:
  39. This function allocates a Search Block from the FSP heap.
  40. Arguments:
  41. Search - Returns a pointer to the search block, or NULL if no heap
  42. space was available.
  43. SearchName - Supplies a pointer to the string describing the search
  44. file name.
  45. IsCoreSearch - Indicates whether a core search block or regular
  46. search block should be allocated. A core search block has a
  47. different block type and has the LastUsedTime field set.
  48. Return Value:
  49. None.
  50. --*/
  51. {
  52. ULONG blockLength;
  53. PSEARCH search;
  54. PAGED_CODE( );
  55. blockLength = sizeof(SEARCH) + SearchName->Length +
  56. sizeof(*SearchName->Buffer);
  57. //
  58. // Attempt to allocate from the heap.
  59. //
  60. search = ALLOCATE_HEAP( blockLength, BlockTypeSearch );
  61. *Search = search;
  62. if ( search == NULL ) {
  63. INTERNAL_ERROR(
  64. ERROR_LEVEL_EXPECTED,
  65. "SrvAllocateSearch: Unable to allocate %d bytes from heap.",
  66. blockLength,
  67. NULL
  68. );
  69. // An error is logged by the caller
  70. return;
  71. }
  72. IF_DEBUG(HEAP) {
  73. SrvPrint1( "SrvAllocateSearch: Allocated search block at %p\n",
  74. search );
  75. }
  76. RtlZeroMemory( search, blockLength );
  77. search->BlockHeader.ReferenceCount = 2;
  78. //
  79. // If this is a core search, set the block type and the LastUsedTime
  80. // fields.
  81. //
  82. if ( IsCoreSearch ) {
  83. SET_BLOCK_TYPE_STATE_SIZE( search, BlockTypeSearchCore, BlockStateActive, blockLength );
  84. KeQuerySystemTime( &search->LastUseTime );
  85. } else {
  86. SET_BLOCK_TYPE_STATE_SIZE( search, BlockTypeSearch, BlockStateActive, blockLength );
  87. }
  88. //
  89. // Set the list entry fields to NULL. They will stay this way in
  90. // OS/2-style searches (non-core), but will change to include the
  91. // search block in a last-use list if a core search.
  92. //
  93. // We zeroed the block above, so we don't have to do it here.
  94. //
  95. //search->LastUseListEntry.Flink = NULL;
  96. //search->LastUseListEntry.Blink = NULL;
  97. //
  98. // Set the Buffer field of the LastFileNameReturned field to NULL
  99. // so that we know that it is not in use.
  100. //
  101. // We zeroed the block above, so we don't have to do it here.
  102. //
  103. //search->LastFileNameReturned.Buffer == NULL;
  104. //
  105. // Set the directory cache pointer to NULL so that we don't try to
  106. // free it when the search block closes.
  107. //
  108. //search->DirectoryCache = NULL;
  109. //
  110. // Put search name after search block.
  111. //
  112. search->SearchName.Buffer = (PWCH)(search + 1);
  113. search->SearchName.Length = SearchName->Length;
  114. search->SearchName.MaximumLength = (SHORT)(SearchName->Length +
  115. sizeof(*SearchName->Buffer));
  116. RtlCopyMemory(
  117. search->SearchName.Buffer,
  118. SearchName->Buffer,
  119. SearchName->Length
  120. );
  121. INITIALIZE_REFERENCE_HISTORY( search );
  122. InterlockedIncrement(
  123. (PLONG)&SrvStatistics.CurrentNumberOfOpenSearches
  124. );
  125. INCREMENT_DEBUG_STAT( SrvDbgStatistics.SearchInfo.Allocations );
  126. return;
  127. } // SrvAllocateSearch
  128. VOID
  129. SrvCloseSearch (
  130. IN PSEARCH Search
  131. )
  132. /*++
  133. Routine Description:
  134. This routine prepares a search block to be closed. It changes the
  135. block state to closing and dereferences the search block so that is
  136. will be closed as soon as all other references are closed.
  137. Arguments:
  138. Search - Supplies a pointer to the search block that is to be closed.
  139. Return Value:
  140. None.
  141. --*/
  142. {
  143. PAGED_CODE( );
  144. ACQUIRE_LOCK( &Search->Session->Connection->Lock );
  145. if ( GET_BLOCK_STATE(Search) == BlockStateActive ) {
  146. IF_DEBUG(BLOCK1) {
  147. SrvPrint2( "Closing search block at %p, %wZ\n",
  148. Search, &Search->SearchName );
  149. }
  150. SET_BLOCK_STATE( Search, BlockStateClosing );
  151. RELEASE_LOCK( &Search->Session->Connection->Lock );
  152. //
  153. // Dereference the search block (to indicate that it's no longer
  154. // open).
  155. //
  156. SrvDereferenceSearch( Search );
  157. INCREMENT_DEBUG_STAT( SrvDbgStatistics.SearchInfo.Closes );
  158. } else {
  159. RELEASE_LOCK( &Search->Session->Connection->Lock );
  160. }
  161. return;
  162. } // SrvCloseSearch
  163. VOID
  164. SrvCloseSearches (
  165. IN PCONNECTION Connection,
  166. IN PSEARCH_FILTER_ROUTINE SearchFilterRoutine,
  167. IN PVOID FunctionParameter1,
  168. IN PVOID FunctionParameter2
  169. )
  170. /*++
  171. Routine Description:
  172. This is the common routine to close searches based on the
  173. filter routine and the parameters passed.
  174. Arguments:
  175. Connection - the connection which contains the search blocks to be
  176. closed.
  177. SearchFilterRoutine - a routine that determines whether the
  178. search block is to be closed or not.
  179. FunctionParameter1
  180. FunctionParameter2 - parameters to be passed to the filter routine
  181. Return Value:
  182. None.
  183. --*/
  184. {
  185. PLIST_ENTRY searchEntry;
  186. PLIST_ENTRY nextSearchEntry;
  187. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  188. PSEARCH search;
  189. ULONG i;
  190. PAGED_CODE( );
  191. ACQUIRE_LOCK( &Connection->Lock );
  192. //
  193. // Go through the list's search blocks, closing those which passes
  194. // the check in the filter routine. While a search block is
  195. // being used it is taken off the lists, so there is no danger of
  196. // dereferencing a block whose last use time is about to be updated.
  197. //
  198. searchEntry = pagedConnection->CoreSearchList.Flink;
  199. while ( searchEntry != &pagedConnection->CoreSearchList ) {
  200. nextSearchEntry = searchEntry->Flink;
  201. search = CONTAINING_RECORD( searchEntry, SEARCH, LastUseListEntry );
  202. if ( SearchFilterRoutine(
  203. search,
  204. FunctionParameter1,
  205. FunctionParameter2
  206. ) ) {
  207. IF_SMB_DEBUG(SEARCH2) {
  208. SrvPrint1( "SrvCloseSearches: Closing search block at %p\n", search );
  209. }
  210. SrvCloseSearch( search );
  211. }
  212. searchEntry = nextSearchEntry;
  213. }
  214. //
  215. // Close all active non-core searches.
  216. //
  217. for ( i = 0; i < (ULONG)pagedConnection->SearchTable.TableSize; i++ ) {
  218. PSEARCH search = (PSEARCH)pagedConnection->SearchTable.Table[i].Owner;
  219. if ( (search != NULL) &&
  220. (GET_BLOCK_STATE( search ) == BlockStateActive) &&
  221. SearchFilterRoutine(
  222. search,
  223. FunctionParameter1,
  224. FunctionParameter2
  225. ) ) {
  226. IF_SMB_DEBUG(SEARCH2) {
  227. SrvPrint1( "SrvCloseSearches: Closing non-core search block at %p\n", search );
  228. }
  229. SrvCloseSearch( search );
  230. }
  231. }
  232. RELEASE_LOCK( &Connection->Lock );
  233. return;
  234. } // SrvCloseSearches
  235. VOID
  236. SrvDereferenceSearch (
  237. IN PSEARCH Search
  238. )
  239. /*++
  240. Routine Description:
  241. This function decrements the reference count on a search block. If
  242. the reference count goes to zero, the search block is deleted.
  243. Arguments:
  244. Search - Address of search block
  245. Return Value:
  246. None.
  247. --*/
  248. {
  249. PCONNECTION connection = Search->Session->Connection;
  250. PPAGED_CONNECTION pagedConnection = connection->PagedConnection;
  251. PAGED_CODE( );
  252. //
  253. // Enter a critical section and decrement the reference count on the
  254. // block.
  255. //
  256. ACQUIRE_LOCK( &connection->Lock );
  257. ASSERT( GET_BLOCK_TYPE(Search) == BlockTypeSearch ||
  258. GET_BLOCK_TYPE(Search) == BlockTypeSearchCore );
  259. IF_DEBUG(REFCNT) {
  260. SrvPrint2( "Dereferencing search block %p; old refcnt %lx\n",
  261. Search, Search->BlockHeader.ReferenceCount );
  262. }
  263. ASSERT( (LONG)Search->BlockHeader.ReferenceCount > 0 );
  264. UPDATE_REFERENCE_HISTORY( Search, TRUE );
  265. if ( --Search->BlockHeader.ReferenceCount == 0 ) {
  266. ASSERT( GET_BLOCK_STATE(Search) != BlockStateActive );
  267. //
  268. // The new reference count is 0, meaning that it's time to
  269. // delete this block. Free the search block entry in the search
  270. // table.
  271. //
  272. // If the search block is for a find unique, then the table
  273. // index will be -1, indicating that it has no entry on the
  274. // search table.
  275. //
  276. if ( Search->TableIndex != -1 ) {
  277. SrvRemoveEntryTable(
  278. &pagedConnection->SearchTable,
  279. Search->TableIndex
  280. );
  281. }
  282. //
  283. // If it was an old-style search, remove it from the hash table and
  284. // the last-use list it was on.
  285. //
  286. if ( Search->BlockHeader.Type == BlockTypeSearchCore ) {
  287. if (Search->LastUseListEntry.Flink != NULL ) {
  288. SrvRemoveEntryList(
  289. &pagedConnection->CoreSearchList,
  290. &Search->LastUseListEntry
  291. );
  292. DECREMENT_DEBUG_STAT2( SrvDbgStatistics.CoreSearches );
  293. }
  294. if (Search->HashTableEntry.Flink != NULL ) {
  295. SrvRemoveEntryList(
  296. &pagedConnection->SearchHashTable[Search->HashTableIndex].ListHead,
  297. &Search->HashTableEntry
  298. );
  299. }
  300. pagedConnection->CurrentNumberOfCoreSearches--;
  301. }
  302. // Decrement the count of open files in the session. Including
  303. // searches in the count of open files on the session ensures
  304. // that a session with an open search will not be closed.
  305. //
  306. ASSERT( Search->Session->CurrentSearchOpenCount != 0 );
  307. Search->Session->CurrentSearchOpenCount--;
  308. RELEASE_LOCK( &connection->Lock );
  309. //
  310. // Close the directory handle for the search.
  311. //
  312. if ( Search->DirectoryHandle != NULL ) {
  313. SRVDBG_RELEASE_HANDLE( Search->DirectoryHandle, "SCH", 7, Search );
  314. SrvNtClose( Search->DirectoryHandle, TRUE );
  315. }
  316. //
  317. // Dereference the session and tree connect.
  318. //
  319. SrvDereferenceSession( Search->Session );
  320. SrvDereferenceTreeConnect( Search->TreeConnect );
  321. //
  322. // Free the LastFileNameReturned buffer, if any.
  323. //
  324. if ( Search->LastFileNameReturned.Buffer != NULL ) {
  325. FREE_HEAP( Search->LastFileNameReturned.Buffer );
  326. }
  327. //
  328. // Free the directory cache, if any.
  329. //
  330. if ( Search->DirectoryCache != NULL ) {
  331. FREE_HEAP( Search->DirectoryCache );
  332. }
  333. //
  334. // Free the search block.
  335. //
  336. SrvFreeSearch( Search );
  337. } else {
  338. RELEASE_LOCK( &connection->Lock );
  339. }
  340. return;
  341. } // SrvDereferenceSearch
  342. VOID
  343. SrvFreeSearch (
  344. IN PSEARCH Search
  345. )
  346. /*++
  347. Routine Description:
  348. This function returns a Search Block to the server heap.
  349. Arguments:
  350. Search - Address of Search Block
  351. Return Value:
  352. None.
  353. --*/
  354. {
  355. PAGED_CODE( );
  356. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Search, BlockTypeGarbage, BlockStateDead, -1 );
  357. DEBUG Search->BlockHeader.ReferenceCount = (ULONG)-1;
  358. TERMINATE_REFERENCE_HISTORY( Search );
  359. FREE_HEAP( Search );
  360. IF_DEBUG(HEAP) {
  361. SrvPrint1( "SrvFreeSearch: Freed search block at %p\n", Search );
  362. }
  363. InterlockedDecrement(
  364. (PLONG)&SrvStatistics.CurrentNumberOfOpenSearches
  365. );
  366. INCREMENT_DEBUG_STAT( SrvDbgStatistics.SearchInfo.Frees );
  367. return;
  368. } // SrvFreeSearch
  369. VOID
  370. SrvReferenceSearch (
  371. PSEARCH Search
  372. )
  373. /*++
  374. Routine Description:
  375. This function increments the reference count on a search block.
  376. Arguments:
  377. Search - Address of search block.
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. PAGED_CODE( );
  383. ACQUIRE_LOCK( &Search->Session->Connection->Lock );
  384. ASSERT( (LONG)Search->BlockHeader.ReferenceCount > 0 );
  385. ASSERT( GET_BLOCK_TYPE(Search) == BlockTypeSearch ||
  386. GET_BLOCK_TYPE(Search) == BlockTypeSearchCore );
  387. ASSERT( GET_BLOCK_STATE(Search) == BlockStateActive );
  388. UPDATE_REFERENCE_HISTORY( Search, FALSE );
  389. //
  390. // Enter a critical section and increment the reference count on the
  391. // search block.
  392. //
  393. Search->BlockHeader.ReferenceCount++;
  394. IF_DEBUG(REFCNT) {
  395. SrvPrint2( "Referencing search block %p; new refcnt %lx\n",
  396. Search, Search->BlockHeader.ReferenceCount );
  397. }
  398. RELEASE_LOCK( &Search->Session->Connection->Lock );
  399. return;
  400. } // SrvReferenceSearch
  401. BOOLEAN
  402. SrvSearchOnDelete(
  403. IN PSEARCH Search,
  404. IN PUNICODE_STRING DirectoryName,
  405. IN PTREE_CONNECT TreeConnect
  406. )
  407. /*++
  408. Routine Description:
  409. Filter routine to determine to pick the search blocks on this
  410. directory.
  411. Arguments:
  412. Search - the search block currently being looked at.
  413. DirectoryName - name of directory currently being deleted.
  414. TreeConnect - the TreeConnect which is currently being looked at.
  415. Return Value:
  416. TRUE, if search block belongs to the TreeConnect.
  417. FALSE, otherwise.
  418. --*/
  419. {
  420. UNICODE_STRING searchDirectoryName;
  421. PAGED_CODE( );
  422. //
  423. // We'll use the same buffer as the SearchName string in the
  424. // search for the comparison, but use the length from the
  425. // passed-in directory name if it is less. This allows
  426. // all searches on subdirectories of a deleted directory to
  427. // be closed.
  428. //
  429. searchDirectoryName = Search->SearchName;
  430. if ( searchDirectoryName.Length > DirectoryName->Length ) {
  431. searchDirectoryName.Length = DirectoryName->Length;
  432. }
  433. return ( Search->TreeConnect == TreeConnect &&
  434. RtlCompareUnicodeString(
  435. &searchDirectoryName,
  436. DirectoryName,
  437. TRUE ) == 0 );
  438. }
  439. BOOLEAN
  440. SrvSearchOnPid(
  441. IN PSEARCH Search,
  442. IN USHORT Pid,
  443. IN PVOID Dummy
  444. )
  445. /*++
  446. Routine Description:
  447. Filter routine to determine to pick the search blocks on this
  448. Pid.
  449. Arguments:
  450. Search - the search block currently being looked at.
  451. Pid - the Pid which is currently being run down.
  452. Return Value:
  453. TRUE, if search block belongs to the pid.
  454. FALSE, otherwise.
  455. --*/
  456. {
  457. PAGED_CODE( );
  458. return ( Search->Pid == Pid );
  459. }
  460. BOOLEAN
  461. SrvSearchOnSession(
  462. IN PSEARCH Search,
  463. IN PSESSION Session,
  464. IN PVOID Dummy
  465. )
  466. /*++
  467. Routine Description:
  468. Filter routine to determine to pick the search blocks on this
  469. Session.
  470. Arguments:
  471. Search - the search block currently being looked at.
  472. Session - the session which is currently being closed.
  473. Return Value:
  474. TRUE, if search block belongs to the session.
  475. FALSE, otherwise.
  476. --*/
  477. {
  478. PAGED_CODE( );
  479. return ( Search->Session == Session );
  480. }
  481. BOOLEAN
  482. SrvSearchOnTreeConnect(
  483. IN PSEARCH Search,
  484. IN PTREE_CONNECT TreeConnect,
  485. IN PVOID Dummy
  486. )
  487. /*++
  488. Routine Description:
  489. Filter routine to determine to pick the search blocks on this
  490. Tree Connect.
  491. Arguments:
  492. Search - the search block currently being looked at.
  493. TreeConnect - the TreeConnect which is currently being run down.
  494. Return Value:
  495. TRUE, if search block belongs to the TreeConnect.
  496. FALSE, otherwise.
  497. --*/
  498. {
  499. PAGED_CODE( );
  500. return ( Search->TreeConnect == TreeConnect );
  501. }
  502. ULONG
  503. SrvTimeoutSearches (
  504. IN PLARGE_INTEGER SearchCutoffTime OPTIONAL,
  505. IN PCONNECTION Connection,
  506. IN BOOLEAN TimeoutAtLeastOne
  507. )
  508. /*++
  509. Routine Description:
  510. Goes through the lists of core search blocks, dereferencing those
  511. that have timed out.
  512. Arguments:
  513. SearchCutoffTime - The cutoff time for closing core search blocks.
  514. Connection - the connection whose search blocks are to be
  515. checked for timeouts.
  516. TimeoutAtLeastOne - if TRUE, a minimum of one block is closed. This
  517. is used when we are timing out because the search table is full
  518. and we need to allocate a search block and when the total number of
  519. search blocks have reached our limit.
  520. Return Value:
  521. The number of search blocks that were timed out.
  522. --*/
  523. {
  524. LARGE_INTEGER currentTime;
  525. LARGE_INTEGER searchCutoffTime;
  526. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  527. PLIST_ENTRY searchEntry;
  528. PLIST_ENTRY nextSearchEntry;
  529. ULONG count = 0;
  530. PAGED_CODE( );
  531. //
  532. // First, get the current time, then subtract off the timeout
  533. // value. Any block older than this result is too old.
  534. //
  535. if ( !ARGUMENT_PRESENT( SearchCutoffTime ) ) {
  536. KeQuerySystemTime( &currentTime );
  537. //
  538. // Get the current search timeout values. This must be protected
  539. // by the configuration lock because these values are changed
  540. // dynamically.
  541. //
  542. ACQUIRE_LOCK( &SrvConfigurationLock );
  543. searchCutoffTime.QuadPart =
  544. currentTime.QuadPart - SrvSearchMaxTimeout.QuadPart;
  545. RELEASE_LOCK( &SrvConfigurationLock );
  546. } else {
  547. searchCutoffTime = *SearchCutoffTime;
  548. }
  549. //
  550. // Acquire the connection lock.
  551. //
  552. ACQUIRE_LOCK( &Connection->Lock );
  553. IF_SMB_DEBUG(SEARCH2) {
  554. SrvPrint2( "Core blocks: Oldest valid time is %lx,%lx\n",
  555. searchCutoffTime.HighPart,
  556. searchCutoffTime.LowPart );
  557. }
  558. //
  559. // Go through the list's search blocks, dereferencing those who
  560. // are older than the list timeout. While a search block
  561. // is being used it is taken off the lists, so there is no
  562. // danger of dereferencing a block whose last use time is
  563. // about to be updated.
  564. //
  565. searchEntry = pagedConnection->CoreSearchList.Flink;
  566. while ( searchEntry != &pagedConnection->CoreSearchList ) {
  567. PSEARCH search;
  568. nextSearchEntry = searchEntry->Flink;
  569. search = CONTAINING_RECORD( searchEntry, SEARCH, LastUseListEntry );
  570. IF_SMB_DEBUG(SEARCH2) {
  571. SrvPrint2( "Comparing time %lx,%lx\n",
  572. search->LastUseTime.HighPart,
  573. search->LastUseTime.LowPart );
  574. }
  575. //
  576. // If the time on the current search block is greater than
  577. // the oldest valid time, it is sufficiently new, so
  578. // we can stop searching the list, as all further
  579. // search blocks are newer than this one.
  580. //
  581. if ( (search->LastUseTime.QuadPart > searchCutoffTime.QuadPart) &&
  582. ( !TimeoutAtLeastOne || (count != 0) ) ) {
  583. break;
  584. }
  585. IF_SMB_DEBUG(SEARCH2) {
  586. SrvPrint1( "Closing search block at %p\n", search );
  587. }
  588. SrvCloseSearch( search );
  589. count++;
  590. searchEntry = nextSearchEntry;
  591. }
  592. RELEASE_LOCK( &Connection->Lock );
  593. return count;
  594. } // SrvTimeoutSearches
  595. VOID
  596. SrvForceTimeoutSearches(
  597. IN PCONNECTION Connection
  598. )
  599. /*++
  600. Routine Description:
  601. Goes through the lists of core search blocks, closing those
  602. that have timed out. This forces the close of at least one
  603. search block.
  604. Arguments:
  605. Connection - Pointer to the connection from which a search
  606. block is to be closed first.
  607. Return Value:
  608. None.
  609. --*/
  610. {
  611. USHORT index;
  612. PENDPOINT endpoint;
  613. PLIST_ENTRY listEntry;
  614. PCONNECTION testConnection;
  615. LARGE_INTEGER currentTime;
  616. LARGE_INTEGER searchCutoffTime;
  617. ULONG count;
  618. PAGED_CODE( );
  619. //
  620. // Attempt to timeout the oldest search block for this connection.
  621. //
  622. KeQuerySystemTime( &currentTime );
  623. //
  624. // Get the current search timeout values. This must be protected
  625. // by the configuration lock because these values are changed
  626. // dynamically.
  627. //
  628. ACQUIRE_LOCK( &SrvConfigurationLock );
  629. searchCutoffTime.QuadPart =
  630. currentTime.QuadPart - SrvSearchMaxTimeout.QuadPart;
  631. RELEASE_LOCK( &SrvConfigurationLock );
  632. count = SrvTimeoutSearches(
  633. &searchCutoffTime,
  634. Connection,
  635. TRUE
  636. );
  637. //
  638. // Walk each connection and determine if we should close it.
  639. //
  640. ACQUIRE_LOCK( &SrvEndpointLock );
  641. listEntry = SrvEndpointList.ListHead.Flink;
  642. while ( listEntry != &SrvEndpointList.ListHead ) {
  643. endpoint = CONTAINING_RECORD(
  644. listEntry,
  645. ENDPOINT,
  646. GlobalEndpointListEntry
  647. );
  648. //
  649. //
  650. // If this endpoint is closing, skip to the next one.
  651. // Otherwise, reference the endpoint so that it can't go away.
  652. //
  653. if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ) {
  654. listEntry = listEntry->Flink;
  655. continue;
  656. }
  657. SrvReferenceEndpoint( endpoint );
  658. //
  659. // Walk the endpoint's connection table.
  660. //
  661. index = (USHORT)-1;
  662. while ( TRUE ) {
  663. //
  664. // Get the next active connection in the table. If no more
  665. // are available, WalkConnectionTable returns NULL.
  666. // Otherwise, it returns a referenced pointer to a
  667. // connection.
  668. //
  669. testConnection = WalkConnectionTable( endpoint, &index );
  670. if ( testConnection == NULL ) {
  671. break;
  672. }
  673. RELEASE_LOCK( &SrvEndpointLock );
  674. //
  675. // Time out old core search blocks.
  676. //
  677. count += SrvTimeoutSearches(
  678. &searchCutoffTime,
  679. testConnection,
  680. (BOOLEAN)(count == 0)
  681. );
  682. ACQUIRE_LOCK( &SrvEndpointLock );
  683. //
  684. // Dereference the connection to account for the reference
  685. // from WalkConnectionTable.
  686. //
  687. SrvDereferenceConnection( testConnection );
  688. } // walk connection table
  689. //
  690. // Capture a pointer to the next endpoint in the list (that one
  691. // can't go away because we hold the endpoint list), then
  692. // dereference the current endpoint.
  693. //
  694. listEntry = listEntry->Flink;
  695. SrvDereferenceEndpoint( endpoint );
  696. } // walk endpoint list
  697. RELEASE_LOCK( &SrvEndpointLock );
  698. } // SrvForceTimeoutSearches
  699. VOID
  700. RemoveDuplicateCoreSearches(
  701. IN PPAGED_CONNECTION PagedConnection
  702. )
  703. /*++
  704. Routine Description:
  705. Goes through the connection hash table and removes duplicate searches.
  706. *** Connection lock assumed held. Remains held on exit. ***
  707. Arguments:
  708. PagedConnection - Pointer to the paged portion of the connection block.
  709. Return Value:
  710. None.
  711. --*/
  712. {
  713. ULONG i, j;
  714. PSEARCH firstSearch;
  715. PSEARCH tmpSearch;
  716. PLIST_ENTRY listHead;
  717. PLIST_ENTRY searchEntry;
  718. PLIST_ENTRY nextSearchEntry;
  719. PTREE_CONNECT treeConnect;
  720. USHORT pid;
  721. PUNICODE_STRING searchName;
  722. PAGED_CODE( );
  723. for ( i = 0; i < SEARCH_HASH_TABLE_SIZE; i++ ) {
  724. //
  725. // If this slot has been idle, skip.
  726. //
  727. if ( !PagedConnection->SearchHashTable[i].Dirty ) {
  728. continue;
  729. }
  730. PagedConnection->SearchHashTable[i].Dirty = FALSE;
  731. listHead = &PagedConnection->SearchHashTable[i].ListHead;
  732. //
  733. // Skip the first 3 searches. This will hopefully take care of
  734. // weird dos apps that plays with multiple search blocks. 3 is
  735. // an arbitrary number.
  736. //
  737. searchEntry = listHead->Flink;
  738. for ( j = 0; j < 3; j++) {
  739. if ( searchEntry != listHead ) {
  740. searchEntry = searchEntry->Flink;
  741. } else {
  742. continue;
  743. }
  744. }
  745. next_search:
  746. firstSearch = CONTAINING_RECORD(
  747. searchEntry,
  748. SEARCH,
  749. HashTableEntry
  750. );
  751. //
  752. // Assign these to locals so they don't get recomputed each
  753. // time we go through the loop.
  754. //
  755. treeConnect = firstSearch->TreeConnect;
  756. pid = firstSearch->Pid;
  757. searchName = &firstSearch->SearchName;
  758. searchEntry = searchEntry->Flink;
  759. //
  760. // Close all duplicates.
  761. //
  762. while ( searchEntry != listHead ) {
  763. nextSearchEntry = searchEntry->Flink;
  764. tmpSearch = CONTAINING_RECORD(
  765. searchEntry,
  766. SEARCH,
  767. HashTableEntry
  768. );
  769. if ( ( tmpSearch->TreeConnect == treeConnect ) &&
  770. ( tmpSearch->Pid == pid ) &&
  771. ( RtlCompareUnicodeString(
  772. searchName,
  773. &tmpSearch->SearchName,
  774. FALSE // case sensitive
  775. ) == 0 ) ) {
  776. SrvCloseSearch( tmpSearch );
  777. }
  778. searchEntry = nextSearchEntry;
  779. }
  780. //
  781. // If we have another search candidate. Repeat.
  782. //
  783. if ( firstSearch->HashTableEntry.Flink != listHead ) {
  784. searchEntry = firstSearch->HashTableEntry.Flink;
  785. goto next_search;
  786. }
  787. }
  788. } // RemoveDuplicateCoreSearches
  789. VOID
  790. SrvAddToSearchHashTable(
  791. IN PPAGED_CONNECTION PagedConnection,
  792. IN PSEARCH Search
  793. )
  794. /*++
  795. Routine Description:
  796. Inserts a search block into the connection hash table.
  797. *** Connection lock assumed held. Remains held on exit. ***
  798. Arguments:
  799. PagedConnection - Pointer to the paged portion of the connection block.
  800. Search - Pointer to the search block to be inserted.
  801. Return Value:
  802. None.
  803. --*/
  804. {
  805. ULONG nameLength;
  806. ULONG lastChar;
  807. ULONG hashSum;
  808. ULONG i;
  809. PAGED_CODE( );
  810. //
  811. // Get the hash value
  812. //
  813. nameLength = Search->SearchName.Length / sizeof(WCHAR);
  814. //
  815. // add the length and the first 3 bytes of the tree connect block address
  816. //
  817. //
  818. // NT64: Note that before the port, this line read:
  819. //
  820. // hashSum = nameLength + (ULONG)Search->TreeConnect >> 4;
  821. //
  822. // It is likely true that the original author intended to right-shift
  823. // only the pointer, not the sum. However, after discussion with the
  824. // current owners of this component, it was decided to leave the current
  825. // precedence intact. As part of the 64-bit port, the actual precedence
  826. // has been made explicit.
  827. //
  828. hashSum = (ULONG)((nameLength + (ULONG_PTR)Search->TreeConnect) >> 4);
  829. //
  830. // If the length < 8, then this is probably not an interesting core
  831. // search.
  832. //
  833. if ( nameLength > 7 ) {
  834. lastChar = nameLength - 5;
  835. //
  836. // Add the last 5 characters
  837. //
  838. for ( i = nameLength-1 ; i >= lastChar ; i-- ) {
  839. hashSum += (ULONG)Search->SearchName.Buffer[i];
  840. }
  841. }
  842. //
  843. // get the slot number.
  844. //
  845. i = hashSum & (SEARCH_HASH_TABLE_SIZE-1);
  846. //
  847. // Tell the scavenger that a search has been inserted to this slot.
  848. //
  849. PagedConnection->SearchHashTable[i].Dirty = TRUE;
  850. //
  851. // Insert this new search block into the hash table
  852. //
  853. SrvInsertHeadList(
  854. &PagedConnection->SearchHashTable[i].ListHead,
  855. &Search->HashTableEntry
  856. );
  857. Search->HashTableIndex = (USHORT)i;
  858. return;
  859. } // SrvAddToSearchHashTable