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.

602 lines
14 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blktree.c
  5. Abstract:
  6. This module implements routines for managing tree connect blocks.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 4-Oct-1989
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "blktree.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKTREE
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvAllocateTreeConnect )
  17. #pragma alloc_text( PAGE, SrvCheckAndReferenceTreeConnect )
  18. #pragma alloc_text( PAGE, SrvCloseTreeConnect )
  19. #pragma alloc_text( PAGE, SrvCloseTreeConnectsOnShare )
  20. #pragma alloc_text( PAGE, SrvDereferenceTreeConnect )
  21. #pragma alloc_text( PAGE, SrvFreeTreeConnect )
  22. #endif
  23. VOID
  24. SrvAllocateTreeConnect (
  25. OUT PTREE_CONNECT *TreeConnect,
  26. IN PUNICODE_STRING ServerName OPTIONAL
  27. )
  28. /*++
  29. Routine Description:
  30. This function allocates a TreeConnect Block from the FSP heap.
  31. Arguments:
  32. TreeConnect - Returns a pointer to the tree connect block, or NULL
  33. if no heap space was available.
  34. ServerName - the name of the server to which the client is connecting
  35. Return Value:
  36. None.
  37. --*/
  38. {
  39. PNONPAGED_HEADER header;
  40. PTREE_CONNECT treeConnect;
  41. CLONG numberOfBytes;
  42. PAGED_CODE( );
  43. //
  44. // Attempt to allocate from the heap.
  45. //
  46. numberOfBytes = sizeof( TREE_CONNECT );
  47. if( ARGUMENT_PRESENT( ServerName ) ) {
  48. numberOfBytes += ServerName->Length;
  49. }
  50. treeConnect = ALLOCATE_HEAP( numberOfBytes, BlockTypeTreeConnect );
  51. *TreeConnect = treeConnect;
  52. if ( treeConnect == NULL ) {
  53. INTERNAL_ERROR(
  54. ERROR_LEVEL_EXPECTED,
  55. "SrvAllocateTreeConnect: Unable to allocate %d bytes from heap",
  56. sizeof( TREE_CONNECT ),
  57. NULL
  58. );
  59. // An error will be logged by the caller.
  60. return;
  61. }
  62. IF_DEBUG(HEAP) {
  63. SrvPrint1( "SrvAllocateTreeConnect: Allocated tree connect at %p\n",
  64. treeConnect );
  65. }
  66. //
  67. // Allocate the nonpaged header.
  68. //
  69. header = ALLOCATE_NONPAGED_POOL(
  70. sizeof(NONPAGED_HEADER),
  71. BlockTypeNonpagedHeader
  72. );
  73. if ( header == NULL ) {
  74. INTERNAL_ERROR(
  75. ERROR_LEVEL_EXPECTED,
  76. "SrvAllocateTreeConnect: Unable to allocate %d bytes from pool.",
  77. sizeof( NONPAGED_HEADER ),
  78. NULL
  79. );
  80. FREE_HEAP( treeConnect );
  81. *TreeConnect = NULL;
  82. return;
  83. }
  84. header->Type = BlockTypeTreeConnect;
  85. header->PagedBlock = treeConnect;
  86. RtlZeroMemory( treeConnect, numberOfBytes );
  87. treeConnect->NonpagedHeader = header;
  88. SET_BLOCK_TYPE_STATE_SIZE( treeConnect, BlockTypeTreeConnect, BlockStateActive, sizeof( TREE_CONNECT) );
  89. header->ReferenceCount = 2; // allow for Active status and caller's pointer
  90. //
  91. // Set up the time at which the tree connect block was allocated.
  92. //
  93. KeQuerySystemTime( &treeConnect->StartTime );
  94. //
  95. // Save the ServerName, if supplied
  96. //
  97. if( ARGUMENT_PRESENT( ServerName ) ) {
  98. treeConnect->ServerName.Buffer = (PWCHAR)(treeConnect + 1);
  99. treeConnect->ServerName.MaximumLength = ServerName->Length;
  100. RtlCopyUnicodeString( &treeConnect->ServerName, ServerName );
  101. }
  102. #if SRVDBG2
  103. treeConnect->BlockHeader.ReferenceCount = 2; // for INITIALIZE_REFERENCE_HISTORY
  104. #endif
  105. INITIALIZE_REFERENCE_HISTORY( treeConnect );
  106. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TreeConnectInfo.Allocations );
  107. return;
  108. } // SrvAllocateTreeConnect
  109. BOOLEAN SRVFASTCALL
  110. SrvCheckAndReferenceTreeConnect (
  111. PTREE_CONNECT TreeConnect
  112. )
  113. /*++
  114. Routine Description:
  115. This function atomically verifies that a tree connect is active and
  116. increments the reference count on the tree connect if it is.
  117. Arguments:
  118. TreeConnect - Address of tree connect
  119. Return Value:
  120. BOOLEAN - Returns TRUE if the tree connect is active, FALSE otherwise.
  121. --*/
  122. {
  123. PAGED_CODE( );
  124. //
  125. // Acquire the lock that guards the tree connect's state field.
  126. //
  127. ACQUIRE_LOCK( &TreeConnect->Connection->Lock );
  128. //
  129. // If the tree connect is active, reference it and return TRUE.
  130. //
  131. if ( GET_BLOCK_STATE(TreeConnect) == BlockStateActive ) {
  132. SrvReferenceTreeConnect( TreeConnect );
  133. RELEASE_LOCK( &TreeConnect->Connection->Lock );
  134. return TRUE;
  135. }
  136. //
  137. // The tree connect isn't active. Return FALSE.
  138. //
  139. RELEASE_LOCK( &TreeConnect->Connection->Lock );
  140. return FALSE;
  141. } // SrvCheckAndReferenceTreeConnect
  142. VOID
  143. SrvCloseTreeConnect (
  144. IN PTREE_CONNECT TreeConnect
  145. )
  146. /*++
  147. Routine Description:
  148. This routine does the core of a tree disconnect. It sets the state
  149. of the tree connect to Closing, closes all files open on the tree
  150. connect, and dereferences the tree connect block. The block will be
  151. destroyed as soon as all other references to it are eliminated.
  152. Arguments:
  153. TreeConnect - Supplies a pointer to the tree connect block that is
  154. to be closed.
  155. Return Value:
  156. None.
  157. --*/
  158. {
  159. PAGED_CODE( );
  160. ACQUIRE_LOCK( &TreeConnect->Connection->Lock );
  161. if ( GET_BLOCK_STATE(TreeConnect) == BlockStateActive ) {
  162. IF_DEBUG(BLOCK1) SrvPrint1( "Closing tree at %p\n", TreeConnect );
  163. SET_BLOCK_STATE( TreeConnect, BlockStateClosing );
  164. RELEASE_LOCK( &TreeConnect->Connection->Lock );
  165. //
  166. // Close any open files or pending transactions on this tree
  167. // connect.
  168. //
  169. SrvCloseRfcbsOnTree( TreeConnect );
  170. SrvCloseTransactionsOnTree( TreeConnect );
  171. //
  172. // Close any open DOS searches on this tree connect.
  173. //
  174. SrvCloseSearches(
  175. TreeConnect->Connection,
  176. (PSEARCH_FILTER_ROUTINE)SrvSearchOnTreeConnect,
  177. (PVOID)TreeConnect,
  178. NULL
  179. );
  180. //
  181. // Close any cached directories on this connection
  182. //
  183. SrvCloseCachedDirectoryEntries( TreeConnect->Connection );
  184. //
  185. // Dereference the tree connect (to indicate that it's no longer
  186. // open).
  187. //
  188. SrvDereferenceTreeConnect( TreeConnect );
  189. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TreeConnectInfo.Closes );
  190. } else {
  191. RELEASE_LOCK( &TreeConnect->Connection->Lock );
  192. }
  193. return;
  194. } // SrvCloseTreeConnect
  195. VOID
  196. SrvCloseTreeConnectsOnShare (
  197. IN PSHARE Share
  198. )
  199. /*++
  200. Routine Description:
  201. This function close all tree connects on a given share.
  202. Arguments:
  203. Share - A pointer to the share block.
  204. Return Value:
  205. None.
  206. --*/
  207. {
  208. PLIST_ENTRY treeConnectEntry, nextTreeConnectEntry;
  209. PTREE_CONNECT treeConnect;
  210. PAGED_CODE( );
  211. //
  212. // Acquire the lock that protects the share's tree connect list.
  213. //
  214. // *** Note that this routine can be called with this lock already
  215. // held by SrvCloseShare from SrvNetShareDel.
  216. //
  217. ACQUIRE_LOCK( &SrvShareLock );
  218. //
  219. // Loop through the list of TreeConnects for the given share,
  220. // closing all of them. The share block and the list are guaranteed
  221. // to remain valid because we hold the share lock.
  222. //
  223. treeConnectEntry = Share->TreeConnectList.Flink;
  224. while ( treeConnectEntry != &Share->TreeConnectList ) {
  225. //
  226. // Capture the address of the next tree connect now, because
  227. // we're about to close the current one, and we can look at it
  228. // after we've done that.
  229. //
  230. nextTreeConnectEntry = treeConnectEntry->Flink;
  231. //
  232. // Close the tree connect. This will close all files open on
  233. // this tree connect, and will stop blocked activity on the tree
  234. // connect. The tree connect itself will not be removed from
  235. // the share's TreeConnect list until its reference count
  236. // reaches zero.
  237. //
  238. treeConnect = CONTAINING_RECORD(
  239. treeConnectEntry,
  240. TREE_CONNECT,
  241. ShareListEntry
  242. );
  243. SrvCloseTreeConnect( treeConnect );
  244. //
  245. // Point to the next tree connect.
  246. //
  247. treeConnectEntry = nextTreeConnectEntry;
  248. }
  249. //
  250. // Release the share's tree connect list lock.
  251. //
  252. RELEASE_LOCK( &SrvShareLock );
  253. } // SrvCloseTreeConnectsOnShare
  254. VOID SRVFASTCALL
  255. SrvDereferenceTreeConnect (
  256. IN PTREE_CONNECT TreeConnect
  257. )
  258. /*++
  259. Routine Description:
  260. This function decrements the reference count on a tree connect. If
  261. the reference count goes to zero, the tree connect block is deleted.
  262. Since this routine may call SrvDereferenceConnection, the caller
  263. must be careful if he holds the connection lock that he also
  264. holds a referenced pointer to the connection.
  265. Arguments:
  266. TreeConnect - Address of tree connect
  267. Return Value:
  268. None.
  269. --*/
  270. {
  271. PCONNECTION connection;
  272. LONG result;
  273. PAGED_CODE( );
  274. //
  275. // Enter a critical section and decrement the reference count on the
  276. // block.
  277. //
  278. connection = TreeConnect->Connection;
  279. IF_DEBUG(REFCNT) {
  280. SrvPrint2( "Dereferencing tree connect %p; old refcnt %lx\n",
  281. TreeConnect, TreeConnect->NonpagedHeader->ReferenceCount );
  282. }
  283. ASSERT( GET_BLOCK_TYPE( TreeConnect ) == BlockTypeTreeConnect );
  284. ASSERT( TreeConnect->NonpagedHeader->ReferenceCount > 0 );
  285. UPDATE_REFERENCE_HISTORY( TreeConnect, TRUE );
  286. result = InterlockedDecrement(
  287. &TreeConnect->NonpagedHeader->ReferenceCount
  288. );
  289. if ( result == 0 ) {
  290. //
  291. // The new reference count is 0, meaning that it's time to
  292. // delete this block.
  293. //
  294. // Free the tree connect entry in the tree table. (Note that
  295. // the connection lock guards this table.)
  296. //
  297. ACQUIRE_LOCK( &connection->Lock );
  298. SrvRemoveEntryTable(
  299. &connection->PagedConnection->TreeConnectTable,
  300. TID_INDEX( TreeConnect->Tid )
  301. );
  302. if( TreeConnect->Session )
  303. {
  304. DEBUG TreeConnect->Session = NULL;
  305. RELEASE_LOCK( &connection->Lock );
  306. SrvDereferenceSession( TreeConnect->Session );
  307. }
  308. else
  309. {
  310. RELEASE_LOCK( &connection->Lock );
  311. }
  312. //
  313. // Remove the tree connect from the list of active tree connects
  314. // for the share.
  315. //
  316. SrvRemoveEntryOrderedList( &SrvTreeConnectList, TreeConnect );
  317. //
  318. // Take the tree connect off the list of tree connects for the
  319. // share and decrement the count of active uses of the share.
  320. //
  321. ACQUIRE_LOCK( &SrvShareLock );
  322. SrvRemoveEntryList(
  323. &TreeConnect->Share->TreeConnectList,
  324. &TreeConnect->ShareListEntry
  325. );
  326. RELEASE_LOCK( &SrvShareLock );
  327. //
  328. // Dereference the share and the connection.
  329. //
  330. SrvDereferenceShareForTreeConnect( TreeConnect->Share );
  331. DEBUG TreeConnect->Share = NULL;
  332. SrvDereferenceConnection( connection );
  333. DEBUG TreeConnect->Connection = NULL;
  334. //
  335. // Free the tree connect block.
  336. //
  337. SrvFreeTreeConnect( TreeConnect );
  338. }
  339. return;
  340. } // SrvDereferenceTreeConnect
  341. VOID
  342. SrvFreeTreeConnect (
  343. IN PTREE_CONNECT TreeConnect
  344. )
  345. /*++
  346. Routine Description:
  347. This function returns a TreeConnect Block to the FSP heap.
  348. Arguments:
  349. TreeConnect - Address of tree connect
  350. Return Value:
  351. None.
  352. --*/
  353. {
  354. PAGED_CODE( );
  355. DEBUG SET_BLOCK_TYPE_STATE_SIZE( TreeConnect, BlockTypeGarbage, BlockStateDead, -1 );
  356. DEBUG TreeConnect->NonpagedHeader->ReferenceCount = -1;
  357. TERMINATE_REFERENCE_HISTORY( TreeConnect );
  358. DEALLOCATE_NONPAGED_POOL( TreeConnect->NonpagedHeader );
  359. FREE_HEAP( TreeConnect );
  360. IF_DEBUG(HEAP) {
  361. SrvPrint1( "SrvFreeTreeConnect: Freed tree connect block at %p\n",
  362. TreeConnect );
  363. }
  364. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TreeConnectInfo.Frees );
  365. return;
  366. } // SrvFreeTreeConnect
  367. VOID
  368. SrvDisconnectTreeConnectsFromSession (
  369. PCONNECTION connection,
  370. PSESSION Session
  371. )
  372. /*++
  373. Routine Description:
  374. This routine removes the session association on all associated
  375. TreeConnects and dereferences the session, allowing the session
  376. to exit normally. The caller MUST have the Connection Lock acquired.
  377. Arguments:
  378. Connection - The connection we're walking
  379. Session - Supplies a pointer to the session block for which
  380. transactions are to be closed.
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. PTABLE_HEADER tableHeader;
  386. PLIST_ENTRY entry;
  387. USHORT i;
  388. PAGED_CODE( );
  389. SrvReferenceSession( Session );
  390. tableHeader = &connection->PagedConnection->SessionTable;
  391. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  392. PTREE_CONNECT treeConnect =
  393. (PTREE_CONNECT)tableHeader->Table[i].Owner;
  394. if ( treeConnect != NULL ) {
  395. if( treeConnect->Session == Session )
  396. {
  397. SrvDereferenceSession( Session );
  398. treeConnect->Session = NULL;
  399. }
  400. }
  401. }
  402. SrvDereferenceSession( Session );
  403. } // SrvDisconnectTreeConnectsFromSession