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.

3049 lines
74 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blkfile.c
  5. Abstract:
  6. This module implements routines for managing various kinds of file
  7. control blocks.
  8. Master File Control Block (MFCB) -- one per named file that is open
  9. at least once. Used to support compatibility mode and oplocks.
  10. Local File Control Block (LFCB) -- one for each local open instance.
  11. Represents local file object/handle. There may be multiple
  12. LFCBs linked to a single MFCB.
  13. Remote File Control Block (RFCB) -- one for each remote open instance.
  14. Represents remote FID. There is usually one RFCB per LFCB, but
  15. multiple compatibility mode RFCBs may be linked to a single LFCB.
  16. Multiple remote FCB opens for a single file from a single session
  17. are folded into one RFCB, because old DOS redirectors only send
  18. one close.
  19. Author:
  20. Chuck Lenzmeier (chuckl) 4-Oct-1989
  21. Revision History:
  22. --*/
  23. #include "precomp.h"
  24. #include "blkfile.tmh"
  25. #pragma hdrstop
  26. #define BugCheckFileId SRV_FILE_BLKFILE
  27. //
  28. // Get the address of the SRV_LOCK which corresponds to FileNameHashValue bucket
  29. //
  30. #define MFCB_LOCK_ADDR( _hash ) SrvMfcbHashTable[ HASH_TO_MFCB_INDEX( _hash ) ].Lock
  31. //
  32. // Forward declarations of local functions.
  33. //
  34. VOID
  35. AllocateMfcb(
  36. OUT PMFCB *Mfcb,
  37. IN PUNICODE_STRING FileName,
  38. IN ULONG FileNameHashValue,
  39. IN PWORK_CONTEXT WorkContext
  40. );
  41. STATIC
  42. VOID
  43. CloseRfcbInternal (
  44. IN PRFCB Rfcb,
  45. IN KIRQL OldIrql
  46. );
  47. STATIC
  48. VOID
  49. DereferenceRfcbInternal (
  50. IN PRFCB Rfcb,
  51. IN KIRQL OldIrql
  52. );
  53. STATIC
  54. VOID
  55. ReferenceRfcbInternal (
  56. PRFCB Rfcb,
  57. IN KIRQL OldIrql
  58. );
  59. STATIC
  60. VOID
  61. UnlinkLfcbFromMfcb (
  62. IN PLFCB Lfcb
  63. );
  64. STATIC
  65. VOID
  66. UnlinkRfcbFromLfcb (
  67. IN PRFCB Rfcb
  68. );
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text( PAGE, AllocateMfcb )
  71. #pragma alloc_text( PAGE, SrvCreateMfcb )
  72. #pragma alloc_text( PAGE, SrvFindMfcb )
  73. #pragma alloc_text( PAGE, SrvFreeMfcb )
  74. #pragma alloc_text( PAGE, UnlinkLfcbFromMfcb )
  75. #pragma alloc_text( PAGE, SrvDereferenceMfcb )
  76. #pragma alloc_text( PAGE, SrvAllocateLfcb )
  77. #pragma alloc_text( PAGE, SrvDereferenceLfcb )
  78. #pragma alloc_text( PAGE, SrvFreeLfcb )
  79. #pragma alloc_text( PAGE, UnlinkRfcbFromLfcb )
  80. #pragma alloc_text( PAGE, SrvAllocateRfcb )
  81. #pragma alloc_text( PAGE, SrvCloseRfcbsOnLfcb )
  82. #pragma alloc_text( PAGE, SrvFreeRfcb )
  83. #pragma alloc_text( PAGE8FIL, SrvCheckAndReferenceRfcb )
  84. #pragma alloc_text( PAGE8FIL, SrvCloseRfcb )
  85. #pragma alloc_text( PAGE8FIL, CloseRfcbInternal )
  86. #pragma alloc_text( PAGE8FIL, SrvCompleteRfcbClose )
  87. //#pragma alloc_text( PAGE8FIL, SrvDereferenceRfcb )
  88. //#pragma alloc_text( PAGE8FIL, DereferenceRfcbInternal )
  89. #pragma alloc_text( PAGE8FIL, SrvReferenceRfcb )
  90. #pragma alloc_text( PAGE8FIL, ReferenceRfcbInternal )
  91. #pragma alloc_text( PAGE8FIL, SrvCloseCachedRfcb )
  92. //#pragma alloc_text( PAGE8FIL, SrvCloseCachedRfcbsOnConnection )
  93. #pragma alloc_text( PAGE8FIL, SrvCloseCachedRfcbsOnLfcb )
  94. #endif
  95. #if 0
  96. #pragma alloc_text( PAGECONN, SrvCloseRfcbsOnSessionOrPid )
  97. #pragma alloc_text( PAGECONN, SrvCloseRfcbsOnTree )
  98. #pragma alloc_text( PAGECONN, SrvFindCachedRfcb )
  99. #endif
  100. //
  101. // Master File Control Block (MFCB) routines.
  102. //
  103. VOID
  104. AllocateMfcb (
  105. OUT PMFCB *Mfcb,
  106. IN PUNICODE_STRING FileName,
  107. IN ULONG FileNameHashValue,
  108. IN PWORK_CONTEXT WorkContext
  109. )
  110. /*++
  111. Routine Description:
  112. This function allocates an MFCB from pool and places it in the hash table.
  113. The bucket's Lock must be held exclusive when this is called!!
  114. Arguments:
  115. Mfcb - Returns a pointer to the MFCB, or NULL if no space was
  116. available.
  117. Return Value:
  118. None.
  119. --*/
  120. {
  121. CLONG blockLength;
  122. PMFCB mfcb;
  123. PNONPAGED_MFCB nonpagedMfcb = NULL;
  124. PWORK_QUEUE queue = WorkContext->CurrentWorkQueue;
  125. PLIST_ENTRY listHead;
  126. PSINGLE_LIST_ENTRY listEntry;
  127. PAGED_CODE();
  128. //
  129. // Attempt to allocate from pool.
  130. //
  131. blockLength = sizeof(MFCB) + FileName->Length + sizeof(WCHAR);
  132. mfcb = ALLOCATE_HEAP( blockLength, BlockTypeMfcb );
  133. *Mfcb = mfcb;
  134. if ( mfcb == NULL ) {
  135. INTERNAL_ERROR(
  136. ERROR_LEVEL_EXPECTED,
  137. "AllocateMfcb: Unable to allocate %d bytes from pool\n",
  138. blockLength,
  139. NULL
  140. );
  141. // The caller will log the error
  142. return;
  143. }
  144. nonpagedMfcb = (PNONPAGED_MFCB)InterlockedExchangePointer(
  145. &queue->CachedFreeMfcb,
  146. nonpagedMfcb );
  147. if( nonpagedMfcb == NULL ) {
  148. listEntry = ExInterlockedPopEntrySList(
  149. &queue->MfcbFreeList,
  150. &queue->SpinLock
  151. );
  152. if( listEntry != NULL ) {
  153. InterlockedDecrement( &queue->FreeMfcbs );
  154. nonpagedMfcb = CONTAINING_RECORD( listEntry, NONPAGED_MFCB, SingleListEntry );
  155. } else {
  156. nonpagedMfcb = ALLOCATE_NONPAGED_POOL(
  157. sizeof(NONPAGED_MFCB),
  158. BlockTypeNonpagedMfcb );
  159. if ( nonpagedMfcb == NULL ) {
  160. INTERNAL_ERROR(
  161. ERROR_LEVEL_EXPECTED,
  162. "AllocateMfcb: Unable to allocate %d bytes from pool\n",
  163. sizeof(NONPAGED_MFCB),
  164. NULL
  165. );
  166. // The caller will log the error
  167. FREE_HEAP( mfcb );
  168. *Mfcb = NULL;
  169. return;
  170. }
  171. IF_DEBUG(HEAP) {
  172. KdPrint(( "AllocateMfcb: Allocated MFCB at 0x%p\n", mfcb ));
  173. }
  174. nonpagedMfcb->Type = BlockTypeNonpagedMfcb;
  175. }
  176. }
  177. nonpagedMfcb->PagedBlock = mfcb;
  178. RtlZeroMemory( mfcb, blockLength );
  179. mfcb->NonpagedMfcb = nonpagedMfcb;
  180. //
  181. // Initialize the MFCB.
  182. //
  183. SET_BLOCK_TYPE_STATE_SIZE( mfcb, BlockTypeMfcb, BlockStateClosing, blockLength );
  184. mfcb->BlockHeader.ReferenceCount = 1;
  185. InitializeListHead( &mfcb->LfcbList );
  186. INITIALIZE_LOCK( &nonpagedMfcb->Lock, MFCB_LOCK_LEVEL, "MfcbLock" );
  187. //
  188. // Store the filename as it was passed into us
  189. //
  190. mfcb->FileName.Length = FileName->Length;
  191. mfcb->FileName.MaximumLength = (SHORT)(FileName->Length + sizeof(WCHAR));
  192. mfcb->FileName.Buffer = (PWCH)(mfcb + 1);
  193. RtlCopyMemory( mfcb->FileName.Buffer, FileName->Buffer, FileName->Length );
  194. //
  195. // Store the hash value for the filename
  196. //
  197. mfcb->FileNameHashValue = FileNameHashValue;
  198. //
  199. // Store the SnapShot time if set
  200. //
  201. mfcb->SnapShotTime.QuadPart = WorkContext->SnapShotTime.QuadPart;
  202. INITIALIZE_REFERENCE_HISTORY( mfcb );
  203. //
  204. // Add it to the hash table
  205. //
  206. listHead = &SrvMfcbHashTable[ HASH_TO_MFCB_INDEX( FileNameHashValue ) ].List;
  207. InsertHeadList( listHead, &mfcb->MfcbHashTableEntry );
  208. #if SRVCATCH
  209. if( SrvCatch.Length ) {
  210. UNICODE_STRING baseName;
  211. SrvGetBaseFileName( FileName, &baseName );
  212. if( RtlCompareUnicodeString( &SrvCatch, &baseName, TRUE ) == 0 ) {
  213. mfcb->SrvCatch = 1;
  214. }
  215. }
  216. if( SrvCatchExt.Length && WorkContext->TreeConnect->Share->IsCatchShare ) {
  217. UNICODE_STRING baseName;
  218. SrvGetBaseFileName( FileName, &baseName );
  219. if( baseName.Length > 6 )
  220. {
  221. baseName.Buffer += (baseName.Length-6)>>1;
  222. baseName.Length = 6;
  223. if( RtlCompareUnicodeString( &SrvCatchExt, &baseName, TRUE ) == 0 ) {
  224. mfcb->SrvCatch = 2;
  225. }
  226. }
  227. }
  228. #endif
  229. INCREMENT_DEBUG_STAT( SrvDbgStatistics.MfcbInfo.Allocations );
  230. return;
  231. } // AllocateMfcb
  232. PMFCB
  233. SrvCreateMfcb(
  234. IN PUNICODE_STRING FileName,
  235. IN PWORK_CONTEXT WorkContext,
  236. IN ULONG HashValue
  237. )
  238. /*++
  239. Routine Description:
  240. Called when a file is about to be opened. Searches the Master File
  241. Table to see if the named file is already open. If it isn't, a
  242. Master File Control Block is allocated and added to the list.
  243. *** The MFCB list lock must be held when this routine is called. It
  244. remains held on exit.
  245. *** Note that the master file list CANNOT be walked to find and
  246. possibly delete open file instances. This is because new
  247. instances are added to the list before the file is actually
  248. opened. The connection file tables must be used to find "real"
  249. open file instances.
  250. Arguments:
  251. FileName - Fully qualified name of file being opened. If a new
  252. master file block is created, the string data is copied to that
  253. block, so the original data is no longer needed.
  254. HashValue - the pre-computed hash value for this filename
  255. Return Value:
  256. PMFCB - Pointer to existing or newly created MFCB; NULL if unable
  257. allocate space for MFCB.
  258. --*/
  259. {
  260. PMFCB mfcb;
  261. PLIST_ENTRY listEntryRoot, listEntry;
  262. PAGED_CODE( );
  263. //
  264. // Search the Hash File List to determine whether the named file
  265. // is already open.
  266. //
  267. ASSERT( ExIsResourceAcquiredExclusiveLite( MFCB_LOCK_ADDR( HashValue )) );
  268. listEntryRoot = &SrvMfcbHashTable[ HASH_TO_MFCB_INDEX( HashValue ) ].List;
  269. for( listEntry = listEntryRoot->Flink;
  270. listEntry != listEntryRoot;
  271. listEntry = listEntry->Flink ) {
  272. mfcb = CONTAINING_RECORD( listEntry, MFCB, MfcbHashTableEntry );
  273. if( mfcb->FileNameHashValue == HashValue &&
  274. mfcb->FileName.Length == FileName->Length &&
  275. mfcb->SnapShotTime.QuadPart == WorkContext->SnapShotTime.QuadPart &&
  276. RtlEqualMemory( mfcb->FileName.Buffer,
  277. FileName->Buffer,
  278. FileName->Length ) ) {
  279. //
  280. // We've found a matching entry!
  281. //
  282. return mfcb;
  283. }
  284. }
  285. //
  286. // The named file is not yet open. Allocate an MFCB
  287. //
  288. AllocateMfcb( &mfcb, FileName, HashValue, WorkContext );
  289. return mfcb;
  290. } // SrvCreateMfcb
  291. PMFCB
  292. SrvFindMfcb(
  293. IN PUNICODE_STRING FileName,
  294. IN BOOLEAN CaseInsensitive,
  295. OUT PSRV_LOCK *Lock,
  296. OUT PULONG HashValue,
  297. IN PWORK_CONTEXT WorkContext
  298. )
  299. /*++
  300. Routine Description:
  301. Searches the Master File Table to see if the named file is already
  302. open, returning the address of an MFCB if it is.
  303. *** The MFCB list lock will be acquire exclusively whether or not
  304. this routine succeeds. The address of the lock is placed in *Lock
  305. Arguments:
  306. FileName - Fully qualified name of file being opened.
  307. CaseInsensitive - TRUE if the search should be case-insensitive.
  308. HashValue - if the MFCB was NOT found, *HashValue filled in with the hash
  309. value derived from the filename. This can then be passed into
  310. SrvCreateMfcb later
  311. Return Value:
  312. PMFCB - Pointer to existing created MFCB, if the named file is
  313. already open; NULL otherwise.
  314. --*/
  315. {
  316. PLIST_ENTRY listEntry, listEntryRoot;
  317. ULONG localHashValue;
  318. PMFCB mfcb;
  319. PAGED_CODE( );
  320. //
  321. // Search the Master File List to determine whether the named file
  322. // is already open. If the length of the file name is zero, then
  323. // do not actually look in the list--the prefix routines do not
  324. // work with zero-length strings, and we know that we'll never
  325. // open a file with a name length == 0.
  326. //
  327. // !!! For SMB 4.0 (NT-NT), do we need to worry about share root
  328. // directories?
  329. if ( FileName->Length == 0 ) {
  330. *HashValue = 0;
  331. *Lock = NULL;
  332. return NULL;
  333. }
  334. COMPUTE_STRING_HASH( FileName, &localHashValue );
  335. listEntryRoot = &SrvMfcbHashTable[ HASH_TO_MFCB_INDEX( localHashValue ) ].List;
  336. *Lock = MFCB_LOCK_ADDR( localHashValue );
  337. ACQUIRE_LOCK( *Lock );
  338. //
  339. // Search the Hash File List to determine whether the named file
  340. // is already open.
  341. //
  342. for( listEntry = listEntryRoot->Flink;
  343. listEntry != listEntryRoot;
  344. listEntry = listEntry->Flink ) {
  345. mfcb = CONTAINING_RECORD( listEntry, MFCB, MfcbHashTableEntry );
  346. if( mfcb->FileNameHashValue == localHashValue &&
  347. mfcb->FileName.Length == FileName->Length &&
  348. mfcb->SnapShotTime.QuadPart == WorkContext->SnapShotTime.QuadPart &&
  349. RtlEqualUnicodeString( &mfcb->FileName, FileName,CaseInsensitive)) {
  350. //
  351. // We've found a matching entry!
  352. //
  353. ASSERT( GET_BLOCK_TYPE(mfcb) == BlockTypeMfcb );
  354. ASSERT( GET_BLOCK_STATE(mfcb) == BlockStateClosing );
  355. mfcb->BlockHeader.ReferenceCount++;
  356. UPDATE_REFERENCE_HISTORY( mfcb, FALSE );
  357. IF_DEBUG(REFCNT) {
  358. KdPrint(( "Referencing MFCB %p; new refcnt %lx\n",
  359. mfcb, mfcb->BlockHeader.ReferenceCount ));
  360. }
  361. return mfcb;
  362. }
  363. }
  364. //
  365. // We didn't find the entry! The file is not open
  366. //
  367. *HashValue = localHashValue;
  368. return NULL;
  369. } // SrvFindMfcb
  370. VOID
  371. SrvFreeMfcb (
  372. IN PMFCB Mfcb
  373. )
  374. /*++
  375. Routine Description:
  376. This function returns an MFCB to the FSP heap.
  377. If you change this code, you should also look in FreeIdleWorkItems
  378. in scavengr.c
  379. Arguments:
  380. Mfcb - Address of MFCB
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. PWORK_QUEUE queue = PROCESSOR_TO_QUEUE();
  386. PNONPAGED_MFCB nonpagedMfcb = Mfcb->NonpagedMfcb;
  387. PAGED_CODE();
  388. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Mfcb, BlockTypeGarbage, BlockStateDead, -1 );
  389. TERMINATE_REFERENCE_HISTORY( Mfcb );
  390. //
  391. // Delete the lock on the MFCB. The lock must not be held.
  392. //
  393. ASSERT( RESOURCE_OF(nonpagedMfcb->Lock).ActiveCount == 0 );
  394. DELETE_LOCK( &nonpagedMfcb->Lock );
  395. nonpagedMfcb = (PNONPAGED_MFCB)InterlockedExchangePointer(
  396. &queue->CachedFreeMfcb,
  397. nonpagedMfcb );
  398. if( nonpagedMfcb != NULL ) {
  399. //
  400. // This check allows for the possibility that FreeMfcbs might exceed
  401. // MaxFreeMfcbs, but it's fairly unlikely given the operation of kernel
  402. // queue objects. But even so, it probably won't exceed it by much and
  403. // is really only advisory anyway.
  404. //
  405. if( queue->FreeMfcbs < queue->MaxFreeMfcbs ) {
  406. ExInterlockedPushEntrySList(
  407. &queue->MfcbFreeList,
  408. &nonpagedMfcb->SingleListEntry,
  409. &queue->SpinLock
  410. );
  411. InterlockedIncrement( &queue->FreeMfcbs );
  412. } else {
  413. DEALLOCATE_NONPAGED_POOL( nonpagedMfcb );
  414. }
  415. }
  416. FREE_HEAP( Mfcb );
  417. IF_DEBUG(HEAP) KdPrint(( "SrvFreeMfcb: Freed MFCB at 0x%p\n", Mfcb ));
  418. INCREMENT_DEBUG_STAT( SrvDbgStatistics.MfcbInfo.Frees );
  419. return;
  420. } // SrvFreeMfcb
  421. VOID
  422. UnlinkLfcbFromMfcb (
  423. IN PLFCB Lfcb
  424. )
  425. /*++
  426. Routine Description:
  427. This function unlinks an LFCB from its parent MFCB and decrements
  428. the MFCB's reference count. If the count goes to zero, the MFCB
  429. is removed from the Master File Table and deleted.
  430. *** The MFCB lock must be held when this routine is called. It
  431. is released before exit.
  432. Arguments:
  433. Lfcb - Address of LFCB
  434. Return Value:
  435. None.
  436. --*/
  437. {
  438. PMFCB mfcb = Lfcb->Mfcb;
  439. PAGED_CODE( );
  440. ASSERT( mfcb != NULL );
  441. ASSERT( ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(mfcb->NonpagedMfcb->Lock)) );
  442. //
  443. // Remove the LFCB from the MFCB's list. Decrement the reference
  444. // count on the MFCB. The MFCB lock must be released before
  445. // dereferencing the MFCB, because that may cause the MFCB to be
  446. // deleted.
  447. //
  448. SrvRemoveEntryList( &mfcb->LfcbList, &Lfcb->MfcbListEntry );
  449. RELEASE_LOCK( &mfcb->NonpagedMfcb->Lock );
  450. SrvDereferenceMfcb( mfcb );
  451. return;
  452. } // UnlinkLfcbFromMfcb
  453. VOID
  454. SrvDereferenceMfcb (
  455. IN PMFCB Mfcb
  456. )
  457. /*++
  458. Routine Description:
  459. This function decrements the reference count for an MFCB. If
  460. the reference count reaches zero, the block is freed.
  461. *** The MFCB lock (not the MFCB _list_ lock) must not be held when
  462. this routine is called, unless the caller has an extra reference
  463. to the MFCB, because otherwise this routine could destroy the
  464. MFCB and the lock. Note that sequences beginning in DoDelete
  465. and SrvMoveFile and coming here via SrvCloseRfcbsOnLfcb cause
  466. this routine to be called with the MFCB lock held.
  467. Arguments:
  468. Mfcb - A pointer to the MFCB
  469. Return Value:
  470. None.
  471. --*/
  472. {
  473. PSRV_LOCK lock = MFCB_LOCK_ADDR( Mfcb->FileNameHashValue );
  474. PAGED_CODE( );
  475. IF_DEBUG(REFCNT) {
  476. KdPrint(( "Dereferencing MFCB %p; old refcnt %lx\n",
  477. Mfcb, Mfcb->BlockHeader.ReferenceCount ));
  478. }
  479. //
  480. // Acquire the MFCB table lock. This lock protects the reference
  481. // count on the MFCB.
  482. //
  483. ACQUIRE_LOCK( lock );
  484. ASSERT( GET_BLOCK_TYPE( Mfcb ) == BlockTypeMfcb );
  485. ASSERT( (LONG)Mfcb->BlockHeader.ReferenceCount > 0 );
  486. UPDATE_REFERENCE_HISTORY( Mfcb, TRUE );
  487. if ( --Mfcb->BlockHeader.ReferenceCount == 0 ) {
  488. //
  489. // This is the last reference to the MFCB. Delete the block.
  490. // Unlink the MFCB from the Master File Table.
  491. //
  492. ASSERT( Mfcb->LfcbList.Flink == &Mfcb->LfcbList );
  493. RemoveEntryList( &Mfcb->MfcbHashTableEntry );
  494. RELEASE_LOCK( lock );
  495. //
  496. // Free the MFCB. Note that SrvFreeMfcb deletes the MFCB's
  497. // lock.
  498. //
  499. SrvFreeMfcb( Mfcb );
  500. } else {
  501. RELEASE_LOCK( lock );
  502. }
  503. } // SrvDereferenceMfcb
  504. //
  505. // Local File Control Block (LFCB) routines.
  506. //
  507. VOID
  508. SrvAllocateLfcb (
  509. OUT PLFCB *Lfcb,
  510. IN PWORK_CONTEXT WorkContext
  511. )
  512. /*++
  513. Routine Description:
  514. This function allocates an LFCB from pool.
  515. Arguments:
  516. Lfcb - Returns a pointer to the LFCB, or NULL if no space was
  517. available.
  518. Return Value:
  519. None.
  520. --*/
  521. {
  522. PLFCB lfcb = NULL;
  523. PWORK_QUEUE queue = WorkContext->CurrentWorkQueue;
  524. PAGED_CODE();
  525. //
  526. // Attempt to allocate from pool.
  527. //
  528. lfcb = ALLOCATE_HEAP( sizeof(LFCB), BlockTypeLfcb );
  529. *Lfcb = lfcb;
  530. if ( lfcb == NULL ) {
  531. ULONG size = sizeof( LFCB );
  532. INTERNAL_ERROR(
  533. ERROR_LEVEL_EXPECTED,
  534. "SrvAllocateLfcb: Unable to allocate %d bytes from paged pool.",
  535. sizeof( LFCB ),
  536. NULL
  537. );
  538. // The caller will log the error
  539. return;
  540. }
  541. IF_DEBUG(HEAP) {
  542. KdPrint(( "SrvAllocateLfcb: Allocated LFCB at 0x%p\n", lfcb ));
  543. }
  544. //
  545. // Initialize the LFCB. Zero it first.
  546. //
  547. RtlZeroMemory( lfcb, sizeof(LFCB) );
  548. //
  549. // Initialize the LFCB.
  550. //
  551. SET_BLOCK_TYPE_STATE_SIZE( lfcb, BlockTypeLfcb, BlockStateClosing, sizeof( LFCB ) );
  552. //
  553. // !!! Note that the block's reference count is set to 1 to account
  554. // for the open handle. No other reference is needed
  555. // because 1) the LFCB is a temporary object, and 2) the
  556. // caller (SrvAddOpenFileInstance) doesn't really need to
  557. // reference the block, because it owns the appropriate lock
  558. // for the entire time that it's doing its thing.
  559. //
  560. lfcb->BlockHeader.ReferenceCount = 1;
  561. InitializeListHead( &lfcb->RfcbList );
  562. INITIALIZE_REFERENCE_HISTORY( lfcb );
  563. INCREMENT_DEBUG_STAT( SrvDbgStatistics.LfcbInfo.Allocations );
  564. return;
  565. } // SrvAllocateLfcb
  566. VOID
  567. SrvDereferenceLfcb (
  568. IN PLFCB Lfcb
  569. )
  570. /*++
  571. Routine Description:
  572. This function dereference the LFCB and frees the LFCB if the reference
  573. count reaches 0.
  574. *** The caller of this function must own the MFCB lock for the file.
  575. The lock is released by this function.
  576. Arguments:
  577. Lfcb - The LFCB to dereference
  578. Return Value:
  579. None.
  580. --*/
  581. {
  582. PAGED_CODE( );
  583. ASSERT( ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(Lfcb->Mfcb->NonpagedMfcb->Lock)) );
  584. ASSERT( GET_BLOCK_TYPE( Lfcb ) == BlockTypeLfcb );
  585. ASSERT( (LONG)Lfcb->BlockHeader.ReferenceCount > 0 );
  586. UPDATE_REFERENCE_HISTORY( Lfcb, TRUE );
  587. if ( --Lfcb->BlockHeader.ReferenceCount == 0 ) {
  588. //
  589. // This is the last reference to the LFCB. Unlink the
  590. // LFCB from the MFCB's list.
  591. //
  592. ASSERT( Lfcb->RfcbList.Flink == &Lfcb->RfcbList );
  593. ASSERT( Lfcb->HandleCount == 0 );
  594. IF_DEBUG( CREATE ) {
  595. KdPrint(( "SrvDereferenceLfcb: deref %wZ fileObject\n",
  596. &Lfcb->Mfcb->FileName ));
  597. }
  598. //
  599. // UnlinkLfcbFromMfcb will release the MFCB lock that we hold.
  600. //
  601. UnlinkLfcbFromMfcb( Lfcb );
  602. //
  603. // Dereference the file object.
  604. //
  605. ObDereferenceObject( Lfcb->FileObject );
  606. DEBUG Lfcb->FileObject = NULL;
  607. //
  608. // Decrement the count of open files on the session and tree
  609. // connect.
  610. //
  611. ACQUIRE_LOCK( &Lfcb->Connection->Lock );
  612. ASSERT( Lfcb->Session->CurrentFileOpenCount != 0 );
  613. Lfcb->Session->CurrentFileOpenCount--;
  614. ASSERT( Lfcb->TreeConnect->CurrentFileOpenCount != 0 );
  615. Lfcb->TreeConnect->CurrentFileOpenCount--;
  616. RELEASE_LOCK( &Lfcb->Connection->Lock );
  617. //
  618. // Dereference the tree connect, session, and connection that
  619. // the LFCB points to.
  620. //
  621. SrvDereferenceTreeConnect( Lfcb->TreeConnect );
  622. DEBUG Lfcb->TreeConnect = NULL;
  623. SrvDereferenceSession( Lfcb->Session );
  624. DEBUG Lfcb->Session = NULL;
  625. SrvDereferenceConnection( Lfcb->Connection );
  626. DEBUG Lfcb->Connection = NULL;
  627. //
  628. // Free the LFCB.
  629. //
  630. SrvFreeLfcb( Lfcb, PROCESSOR_TO_QUEUE() );
  631. } else {
  632. RELEASE_LOCK( &Lfcb->Mfcb->NonpagedMfcb->Lock );
  633. }
  634. } // SrvDereferenceLfcb
  635. VOID
  636. SrvFreeLfcb (
  637. IN PLFCB Lfcb,
  638. IN PWORK_QUEUE queue
  639. )
  640. /*++
  641. Routine Description:
  642. This function returns an LFCB to the system nonpaged pool.
  643. If you change this routine, look also in FreeIdleWorkItems in scavengr.c
  644. Arguments:
  645. Lfcb - Address of LFCB
  646. Return Value:
  647. None.
  648. --*/
  649. {
  650. PAGED_CODE();
  651. ASSERT ( Lfcb->HandleCount == 0 );
  652. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Lfcb, BlockTypeGarbage, BlockStateDead, -1 );
  653. DEBUG Lfcb->BlockHeader.ReferenceCount = (ULONG)-1;
  654. TERMINATE_REFERENCE_HISTORY( Lfcb );
  655. FREE_HEAP( Lfcb );
  656. INCREMENT_DEBUG_STAT( SrvDbgStatistics.LfcbInfo.Frees );
  657. IF_DEBUG(HEAP) KdPrint(( "SrvFreeLfcb: Freed LFCB at 0x%p\n", Lfcb ));
  658. return;
  659. } // SrvFreeLfcb
  660. VOID
  661. UnlinkRfcbFromLfcb (
  662. IN PRFCB Rfcb
  663. )
  664. /*++
  665. Routine Description:
  666. This function unlinks an RFCB from its parent LFCB and decrements
  667. the LFCB's reference count. If the count goes to zero, the LFCB
  668. is unlinked from its parent MFCB and deleted.
  669. Arguments:
  670. Rfcb - Address of RFCB
  671. Return Value:
  672. None.
  673. --*/
  674. {
  675. PLFCB lfcb = Rfcb->Lfcb;
  676. LARGE_INTEGER offset;
  677. HANDLE handle;
  678. PAGED_CODE( );
  679. UpdateRfcbHistory( Rfcb, 'klnu' );
  680. ASSERT( lfcb != NULL );
  681. if( Rfcb->PagedRfcb->IpxSmartCardContext ) {
  682. IF_DEBUG( SIPX ) {
  683. KdPrint(("Calling Smart Card Close for Rfcb %p\n", Rfcb ));
  684. }
  685. SrvIpxSmartCard.Close( Rfcb->PagedRfcb->IpxSmartCardContext );
  686. }
  687. #ifdef INCLUDE_SMB_PERSISTENT
  688. if (Rfcb->PersistentHandle) {
  689. // SrvPostPersistentClose( Rfcb );
  690. }
  691. #endif
  692. //
  693. // Acquire the lock that guards access to the LFCB's RFCB list.
  694. //
  695. ACQUIRE_LOCK( &lfcb->Mfcb->NonpagedMfcb->Lock );
  696. //
  697. // Decrement the active RFCB count for the LFCB. This must be here
  698. // instead of in SrvCloseRfcb because the MFCB lock must be held to
  699. // update the count.
  700. //
  701. --lfcb->Mfcb->ActiveRfcbCount;
  702. UPDATE_REFERENCE_HISTORY( lfcb, FALSE );
  703. //
  704. // Decrement the open handle count on the LFCB.
  705. //
  706. if ( --lfcb->HandleCount == 0 ) {
  707. handle = lfcb->FileHandle;
  708. //
  709. // Other SMB processors may still have a referenced pointer to
  710. // the LFCB. Ensure that any attempt to use the file handle fails.
  711. //
  712. lfcb->FileHandle = 0;
  713. //
  714. // This was the last open RFCB referencing the LFCB. Close the
  715. // file handle.
  716. //
  717. SRVDBG_RELEASE_HANDLE( handle, "FIL", 3, lfcb );
  718. IF_DEBUG( CREATE ) {
  719. KdPrint(( "UnlinkRfcbFromLfcb: rfcb %p, close handle for %wZ\n",
  720. Rfcb, &lfcb->Mfcb->FileName ));
  721. }
  722. SrvNtClose( handle, TRUE );
  723. //
  724. // If this is a print spool file, schedule the job on the
  725. // printer.
  726. //
  727. if ( Rfcb->ShareType == ShareTypePrint ) {
  728. SrvSchedulePrintJob(
  729. lfcb->TreeConnect->Share->Type.hPrinter,
  730. lfcb->JobId
  731. );
  732. }
  733. //
  734. // Release the open handle reference to the LFCB. The open
  735. // lock is release by SrvDereferenceLfcb(). Note that this
  736. // releases the MFCB lock.
  737. //
  738. SrvDereferenceLfcb( lfcb );
  739. } else {
  740. //
  741. // Other RFCBs have references to the LFCB, so we can't close
  742. // the file yet. (This must be a compatibility mode open.)
  743. // Release all locks taken out by the process that opened the
  744. // file.
  745. //
  746. // *** Note that if any locks were taken out using PIDs other
  747. // than that which opened the FID, those locks cannot be
  748. // automatically deleted. We count on the redirector to do
  749. // the right thing in this case.
  750. //
  751. offset.QuadPart = 0;
  752. IF_SMB_DEBUG(LOCK1) {
  753. KdPrint(( "UnlinkRfcbFromLfcb: Issuing UnlockAllByKey for "
  754. "file object 0x%p, key 0x%lx\n",
  755. lfcb->FileObject,
  756. Rfcb->ShiftedFid | Rfcb->Pid ));
  757. }
  758. (VOID)SrvIssueUnlockRequest(
  759. lfcb->FileObject,
  760. &lfcb->DeviceObject,
  761. IRP_MN_UNLOCK_ALL_BY_KEY,
  762. offset,
  763. offset,
  764. Rfcb->ShiftedFid | Rfcb->Pid
  765. );
  766. //
  767. // Release the MFCB lock.
  768. //
  769. RELEASE_LOCK( &lfcb->Mfcb->NonpagedMfcb->Lock );
  770. }
  771. return;
  772. } // UnlinkRfcbFromLfcb
  773. //
  774. // Remote File Control Block (RFCB) routines.
  775. //
  776. VOID SRVFASTCALL
  777. SrvAllocateRfcb (
  778. OUT PRFCB *Rfcb,
  779. IN PWORK_CONTEXT WorkContext
  780. )
  781. /*++
  782. Routine Description:
  783. This function allocates an RFCB from nonpaged pool. Nonpaged pool
  784. is used so that read/write completion can be handled in the FSD.
  785. Arguments:
  786. Rfcb - Returns a pointer to the RFCB, or NULL if no space was
  787. available.
  788. Return Value:
  789. None.
  790. --*/
  791. {
  792. PRFCB rfcb = NULL;
  793. PPAGED_RFCB pagedRfcb;
  794. PWORK_QUEUE queue = WorkContext->CurrentWorkQueue;
  795. PAGED_CODE();
  796. //
  797. // Attempt to grab an rfcb structure off the per-queue free list
  798. //
  799. rfcb = (PRFCB)InterlockedExchangePointer( &queue->CachedFreeRfcb,
  800. rfcb );
  801. if( rfcb != NULL ) {
  802. *Rfcb = rfcb;
  803. pagedRfcb = rfcb->PagedRfcb;
  804. } else {
  805. if( queue->FreeRfcbs ) {
  806. PSINGLE_LIST_ENTRY listEntry;
  807. listEntry = ExInterlockedPopEntrySList(
  808. &queue->RfcbFreeList,
  809. &queue->SpinLock
  810. );
  811. if( listEntry != NULL ) {
  812. InterlockedIncrement( &queue->FreeRfcbs );
  813. rfcb = CONTAINING_RECORD( listEntry, RFCB, SingleListEntry );
  814. *Rfcb= rfcb;
  815. pagedRfcb = rfcb->PagedRfcb;
  816. }
  817. }
  818. if( rfcb == NULL ) {
  819. //
  820. // Attempt to allocate from nonpaged pool.
  821. //
  822. rfcb = ALLOCATE_NONPAGED_POOL( sizeof(RFCB), BlockTypeRfcb );
  823. *Rfcb = rfcb;
  824. if ( rfcb == NULL ) {
  825. INTERNAL_ERROR (
  826. ERROR_LEVEL_EXPECTED,
  827. "SrvAllocateRfcb: Unable to allocate %d bytes from nonpaged pool.",
  828. sizeof( RFCB ),
  829. NULL
  830. );
  831. return;
  832. }
  833. pagedRfcb = ALLOCATE_HEAP( sizeof(PAGED_RFCB), BlockTypePagedRfcb );
  834. if ( pagedRfcb == NULL ) {
  835. INTERNAL_ERROR (
  836. ERROR_LEVEL_EXPECTED,
  837. "SrvAllocateRfcb: Unable to allocate %d bytes from paged pool.",
  838. sizeof( PAGED_RFCB ),
  839. NULL
  840. );
  841. DEALLOCATE_NONPAGED_POOL( rfcb );
  842. *Rfcb = NULL;
  843. return;
  844. }
  845. IF_DEBUG(HEAP) {
  846. KdPrint(( "SrvAllocateRfcb: Allocated RFCB at 0x%p\n", rfcb ));
  847. }
  848. }
  849. }
  850. //
  851. // Initialize the RFCB. Zero it first.
  852. //
  853. RtlZeroMemory( rfcb, sizeof( RFCB ));
  854. RtlZeroMemory( pagedRfcb, sizeof(PAGED_RFCB) );
  855. rfcb->PagedRfcb = pagedRfcb;
  856. pagedRfcb->PagedHeader.NonPagedBlock = rfcb;
  857. pagedRfcb->PagedHeader.Type = BlockTypePagedRfcb;
  858. SET_BLOCK_TYPE_STATE_SIZE( rfcb, BlockTypeRfcb, BlockStateActive, sizeof(RFCB) );
  859. rfcb->BlockHeader.ReferenceCount = 2; // allow for Active status
  860. // and caller's pointer
  861. INITIALIZE_REFERENCE_HISTORY( rfcb );
  862. rfcb->NewOplockLevel = NO_OPLOCK_BREAK_IN_PROGRESS;
  863. pagedRfcb->LastFailingLockOffset.QuadPart = -1;
  864. rfcb->IsCacheable = ( SrvCachedOpenLimit > 0 );
  865. InterlockedIncrement(
  866. (PLONG)&SrvStatistics.CurrentNumberOfOpenFiles
  867. );
  868. INCREMENT_DEBUG_STAT( SrvDbgStatistics.RfcbInfo.Allocations );
  869. //
  870. // Lock the file-based code section.
  871. //
  872. REFERENCE_UNLOCKABLE_CODE( 8FIL );
  873. InitializeListHead( &rfcb->RawWriteSerializationList );
  874. InitializeListHead( &rfcb->WriteMpx.GlomDelayList );
  875. #ifdef INCLUDE_SMB_PERSISTENT
  876. InitializeListHead( &pagedRfcb->ByteRangeLocks );
  877. #endif
  878. return;
  879. } // SrvAllocateRfcb
  880. BOOLEAN SRVFASTCALL
  881. SrvCheckAndReferenceRfcb (
  882. PRFCB Rfcb
  883. )
  884. /*++
  885. Routine Description:
  886. This function atomically verifies that an RFCB is active and
  887. increments the reference count on the RFCB if it is.
  888. Arguments:
  889. Rfcb - Address of RFCB
  890. Return Value:
  891. BOOLEAN - Returns TRUE if the RFCB is active, FALSE otherwise.
  892. --*/
  893. {
  894. KIRQL oldIrql;
  895. UNLOCKABLE_CODE( 8FIL );
  896. //
  897. // Acquire the lock that guards the RFCB's state field.
  898. //
  899. ACQUIRE_SPIN_LOCK( &Rfcb->Connection->SpinLock, &oldIrql );
  900. //
  901. // If the RFCB is active, reference it and return TRUE. Note that
  902. // ReferenceRfcbInternal releases the spin lock.
  903. //
  904. if ( GET_BLOCK_STATE(Rfcb) == BlockStateActive ) {
  905. ReferenceRfcbInternal( Rfcb, oldIrql );
  906. return TRUE;
  907. }
  908. //
  909. // The RFCB isn't active. Return FALSE.
  910. //
  911. RELEASE_SPIN_LOCK( &Rfcb->Connection->SpinLock, oldIrql );
  912. return FALSE;
  913. } // SrvCheckAndReferenceRfcb
  914. VOID SRVFASTCALL
  915. SrvCloseRfcb (
  916. PRFCB Rfcb
  917. )
  918. /*++
  919. Routine Description:
  920. This is the external routine for closing a file. It acquires the
  921. appropriate spin lock, then calls CloseRfcbInternal.
  922. Arguments:
  923. Rfcb - Supplies a pointer to the RFCB to be closed.
  924. Return Value:
  925. None.
  926. --*/
  927. {
  928. KIRQL oldIrql;
  929. UNLOCKABLE_CODE( 8FIL );
  930. //
  931. // Acquire the lock that guards the RFCB's state field. Call the
  932. // internal close routine. That routine releases the spin lock.
  933. //
  934. ACQUIRE_SPIN_LOCK( &Rfcb->Connection->SpinLock, &oldIrql );
  935. CloseRfcbInternal( Rfcb, oldIrql );
  936. return;
  937. } // SrvCloseRfcb
  938. VOID
  939. CloseRfcbInternal (
  940. PRFCB Rfcb,
  941. IN KIRQL OldIrql
  942. )
  943. /*++
  944. Routine Description:
  945. This internal function does the core of a file close. It sets the
  946. state of the RFCB to Closing, unlinks it from its parent LFCB, and
  947. dereferences the RFCB. The RFCB will be destroyed as soon as all
  948. other references to it are eliminated.
  949. *** This routine must be called with the spin lock synchronizing
  950. access to the RFCB's state field (the connection spin lock)
  951. held. The lock is released on exit from this routine.
  952. Arguments:
  953. Rfcb - Supplies a pointer to the RFCB to be closed.
  954. OldIrql - The previous IRQL value obtained when the spin lock was
  955. acquired.
  956. Return Value:
  957. None.
  958. --*/
  959. {
  960. KIRQL oldIrql = OldIrql;
  961. LARGE_INTEGER cacheOffset;
  962. PMDL mdlChain;
  963. PCONNECTION connection = Rfcb->Connection;
  964. PWORK_CONTEXT workContext;
  965. ULONG i;
  966. ULONG writeLength;
  967. NTSTATUS status;
  968. UNLOCKABLE_CODE( 8FIL );
  969. ASSERT( GET_BLOCK_TYPE( Rfcb ) == BlockTypeRfcb );
  970. //
  971. // If the RFCB's state is still Active, change it to Closing and
  972. // cause cleanup to happen.
  973. //
  974. if ( GET_BLOCK_STATE(Rfcb) == BlockStateActive ) {
  975. IF_DEBUG(BLOCK1) KdPrint(( "Closing RFCB at 0x%p\n", Rfcb ));
  976. UpdateRfcbHistory( Rfcb, 'solc' );
  977. SET_BLOCK_STATE( Rfcb, BlockStateClosing );
  978. //
  979. // Invalidate the cached rfcb
  980. //
  981. if ( connection->CachedFid == (ULONG)Rfcb->Fid ) {
  982. connection->CachedFid = (ULONG)-1;
  983. }
  984. //
  985. // Don't cleanup if raw writes are still in progress
  986. //
  987. if ( Rfcb->RawWriteCount != 0 ) {
  988. //
  989. // Cleanup will happen in SrvDecrementRawWriteCount
  990. //
  991. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  992. return;
  993. }
  994. //
  995. // Do we have write mpx outstanding?
  996. //
  997. if ( Rfcb->WriteMpx.ReferenceCount != 0 ) {
  998. //
  999. // Cleanup will happen when the ref count drops to 0
  1000. //
  1001. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1002. return;
  1003. } else if ( Rfcb->WriteMpx.Glomming ) {
  1004. //
  1005. // We need to complete this write mdl
  1006. //
  1007. Rfcb->WriteMpx.Glomming = FALSE;
  1008. Rfcb->WriteMpx.GlomComplete = FALSE;
  1009. //
  1010. // Save the offset and MDL address.
  1011. //
  1012. cacheOffset.QuadPart = Rfcb->WriteMpx.StartOffset;
  1013. mdlChain = Rfcb->WriteMpx.MdlChain;
  1014. writeLength = Rfcb->WriteMpx.Length;
  1015. DEBUG Rfcb->WriteMpx.MdlChain = NULL;
  1016. DEBUG Rfcb->WriteMpx.StartOffset = 0;
  1017. DEBUG Rfcb->WriteMpx.Length = 0;
  1018. //
  1019. // Now we can release the lock.
  1020. //
  1021. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1022. //
  1023. // Tell the cache manager that we're done with this MDL write.
  1024. //
  1025. if( Rfcb->Lfcb->MdlWriteComplete == NULL ||
  1026. Rfcb->Lfcb->MdlWriteComplete(
  1027. Rfcb->WriteMpx.FileObject,
  1028. &cacheOffset,
  1029. mdlChain,
  1030. Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  1031. status = SrvIssueMdlCompleteRequest( NULL, Rfcb->WriteMpx.FileObject,
  1032. mdlChain,
  1033. IRP_MJ_WRITE,
  1034. &cacheOffset,
  1035. writeLength
  1036. );
  1037. if( !NT_SUCCESS( status ) ) {
  1038. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  1039. }
  1040. }
  1041. } else {
  1042. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1043. }
  1044. //
  1045. // Do the actual close
  1046. //
  1047. SrvCompleteRfcbClose( Rfcb );
  1048. } else {
  1049. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1050. }
  1051. return;
  1052. } // CloseRfcbInternal
  1053. VOID
  1054. SrvCloseRfcbsOnLfcb (
  1055. PLFCB Lfcb
  1056. )
  1057. /*++
  1058. Routine Description:
  1059. This routine closes all RFCBs on an LFCB. It is used by Delete and
  1060. Rename processors to close all open instances of a file opened in
  1061. compability mode (or FCB).
  1062. *** The MFCB lock of the MFCB corresponding to this LFCB must be
  1063. held on entry to this routine; the lock remains held on exit.
  1064. The caller must also have an additional reference to the MFCB,
  1065. in order to prevent it from being deleted while the MFCB lock
  1066. is held.
  1067. Arguments:
  1068. Lfcb - Supplies a pointer to the LFCB whose RFCBs are to be closed.
  1069. Return Value:
  1070. None.
  1071. --*/
  1072. {
  1073. PPAGED_RFCB pagedRfcb;
  1074. PPAGED_RFCB nextPagedRfcb;
  1075. PRFCB rfcb;
  1076. PAGED_CODE( );
  1077. ASSERT( ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(Lfcb->Mfcb->NonpagedMfcb->Lock)) );
  1078. //
  1079. // Loop through the LFCB's RFCB list. Note that the fact that we
  1080. // hold the MFCB lock throughout this routine means that no changes
  1081. // to the list, other than the ones we make, can occur. This makes
  1082. // it safe to capture the address of the next RFCB in the list
  1083. // before closing the current one.
  1084. //
  1085. pagedRfcb = CONTAINING_RECORD(
  1086. Lfcb->RfcbList.Flink,
  1087. PAGED_RFCB,
  1088. LfcbListEntry
  1089. );
  1090. while ( &pagedRfcb->LfcbListEntry != &Lfcb->RfcbList ) {
  1091. nextPagedRfcb = CONTAINING_RECORD(
  1092. pagedRfcb->LfcbListEntry.Flink,
  1093. PAGED_RFCB,
  1094. LfcbListEntry
  1095. );
  1096. //
  1097. // A file owned by the specified LFCB has been found. Close it.
  1098. //
  1099. rfcb = pagedRfcb->PagedHeader.NonPagedBlock;
  1100. if ( GET_BLOCK_STATE(rfcb) == BlockStateActive ) {
  1101. SrvCloseRfcb( rfcb );
  1102. }
  1103. //
  1104. // Move to the next RFCB in the LFCB's list.
  1105. //
  1106. pagedRfcb = nextPagedRfcb;
  1107. }
  1108. //
  1109. // Close cached RFCBs. These aren't dealt with in the loop above
  1110. // because their state is BlockStateClosing.
  1111. //
  1112. SrvCloseCachedRfcbsOnLfcb( Lfcb );
  1113. return;
  1114. } // SrvCloseRfcbsOnLfcb
  1115. VOID
  1116. SrvCloseRfcbsOnSessionOrPid (
  1117. IN PSESSION Session,
  1118. IN PUSHORT Pid OPTIONAL
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. This routine closes all files "owned" by the specified session and/or
  1123. PID in response to a Process Exit SMB. PIDs are unique within the
  1124. session that creates them. This routine walks the file table of the
  1125. connection that owns the specified session, closing all RFCBs whose
  1126. owning session and PID are equal to the PID passed to this routine.
  1127. Each session has a unique UID, so we can compare Uid's instead of comparing
  1128. the actual session pointer.
  1129. Arguments:
  1130. Session - Supplies a pointer to the session block corresponding to
  1131. the specified PID, if specified.
  1132. Pid - if present, Supplies pointer to the PID for which files are
  1133. to be closed.
  1134. Return Value:
  1135. None.
  1136. --*/
  1137. {
  1138. PTABLE_HEADER tableHeader;
  1139. PCONNECTION connection;
  1140. PRFCB rfcb;
  1141. USHORT i;
  1142. KIRQL oldIrql;
  1143. USHORT Uid;
  1144. PLIST_ENTRY listEntry;
  1145. //UNLOCKABLE_CODE( CONN );
  1146. //
  1147. // Get the address of the connection's file table.
  1148. //
  1149. connection = Session->Connection;
  1150. tableHeader = &connection->FileTable;
  1151. Uid = Session->Uid;
  1152. //
  1153. // Acquire the lock that guards the file table. This lock is held
  1154. // while walking the table, in order to prevent the table from
  1155. // changing.
  1156. //
  1157. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1158. //
  1159. // Walk the file table, looking for files owned by the specified
  1160. // session and/or PID.
  1161. //
  1162. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  1163. rfcb = (PRFCB)tableHeader->Table[i].Owner;
  1164. if((rfcb != NULL) &&
  1165. (GET_BLOCK_STATE(rfcb) == BlockStateActive) &&
  1166. (rfcb->Uid == Uid) &&
  1167. (!ARGUMENT_PRESENT( Pid ) || (rfcb->Pid == *Pid)) ) {
  1168. //
  1169. // A file owned by the specified session/process has
  1170. // been found. Close the RFCB, and make sure it doesn't
  1171. // end up in the RFCB cache.
  1172. //
  1173. rfcb->IsCacheable = FALSE;
  1174. CloseRfcbInternal( rfcb, oldIrql );
  1175. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1176. }
  1177. }
  1178. //
  1179. // Now walk the RFCB cache to see if we have cached files that refer
  1180. // to this session that need to be closed.
  1181. //
  1182. again:
  1183. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvCloseRfcbsOnSessionOrPid: "
  1184. "checking for cached RFCBS\n" ));
  1185. for ( listEntry = connection->CachedOpenList.Flink;
  1186. listEntry != &connection->CachedOpenList;
  1187. listEntry = listEntry->Flink ) {
  1188. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  1189. if( (rfcb->Uid == Uid) &&
  1190. ( !ARGUMENT_PRESENT( Pid ) || rfcb->Pid == *Pid) ) {
  1191. //
  1192. // This cached file is owned by session and/or process.
  1193. // Close the RFCB.
  1194. //
  1195. SrvCloseCachedRfcb( rfcb, oldIrql );
  1196. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1197. goto again;
  1198. }
  1199. }
  1200. //
  1201. // All done. Release the lock.
  1202. //
  1203. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1204. return;
  1205. } // SrvCloseRfcbsOnSessionOrPid
  1206. VOID
  1207. SrvCloseRfcbsOnTree (
  1208. PTREE_CONNECT TreeConnect
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This routine closes all files "owned" by the specified tree connect.
  1213. It walks the file table of the connection that owns the tree
  1214. connection. Each file in that table that is owned by the tree
  1215. connect is closed.
  1216. Arguments:
  1217. TreeConnect - Supplies a pointer to the tree connect block for which
  1218. files are to be closed.
  1219. Return Value:
  1220. None.
  1221. --*/
  1222. {
  1223. PRFCB rfcb;
  1224. PTABLE_HEADER tableHeader;
  1225. PCONNECTION connection;
  1226. USHORT i;
  1227. KIRQL oldIrql;
  1228. PLIST_ENTRY listEntry;
  1229. USHORT Tid;
  1230. //UNLOCKABLE_CODE( CONN );
  1231. //
  1232. // Get the address of the connection's file table.
  1233. //
  1234. connection = TreeConnect->Connection;
  1235. tableHeader = &connection->FileTable;
  1236. Tid = TreeConnect->Tid;
  1237. //
  1238. // Acquire the lock that guards the file table. This lock is held
  1239. // while walking the table, in order to prevent the table from
  1240. // changing.
  1241. //
  1242. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1243. //
  1244. // Walk the file table, looking for files owned by the specified
  1245. // tree and PID.
  1246. //
  1247. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  1248. rfcb = (PRFCB)tableHeader->Table[i].Owner;
  1249. if((rfcb != NULL) &&
  1250. (GET_BLOCK_STATE(rfcb) == BlockStateActive) &&
  1251. (rfcb->Tid == Tid )) {
  1252. //
  1253. // A file owned by the specified tree connect has been found.
  1254. // Close the RFCB and make sure it doesn't get cached
  1255. //
  1256. rfcb->IsCacheable = FALSE;
  1257. CloseRfcbInternal( rfcb, oldIrql );
  1258. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1259. }
  1260. }
  1261. //
  1262. // Walk the cached open list, looking for files open on this tree
  1263. // Close any that we find.
  1264. //
  1265. again:
  1266. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvCloseRfcbsOnTree: checking for cached RFCBS\n" ));
  1267. for ( listEntry = connection->CachedOpenList.Flink;
  1268. listEntry != &connection->CachedOpenList;
  1269. listEntry = listEntry->Flink ) {
  1270. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  1271. if( rfcb->Tid == Tid ) {
  1272. //
  1273. // This cached file is owned by the specifiec tree connect.
  1274. // Close the RFCB.
  1275. //
  1276. SrvCloseCachedRfcb( rfcb, oldIrql );
  1277. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1278. goto again;
  1279. }
  1280. }
  1281. //
  1282. // All done. Release the lock.
  1283. //
  1284. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1285. return;
  1286. } // SrvCloseRfcbsOnTree
  1287. VOID
  1288. SrvCompleteRfcbClose (
  1289. IN PRFCB Rfcb
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. This routine completes the rfcb close.
  1294. Arguments:
  1295. Rfcb - Supplies a pointer to the RFCB to be closed.
  1296. Return Value:
  1297. None.
  1298. --*/
  1299. {
  1300. KIRQL oldIrql;
  1301. PCONNECTION connection = Rfcb->Connection;
  1302. UNLOCKABLE_CODE( 8FIL );
  1303. UpdateRfcbHistory( Rfcb, 'tlpc' );
  1304. //
  1305. // Remove the Rfcb from the oplockbreaksinprogresslist. When the
  1306. // Rfcb gets closed, we don't process any more oplock breaks
  1307. // responses.
  1308. //
  1309. ACQUIRE_LOCK( &SrvOplockBreakListLock );
  1310. if ( Rfcb->OnOplockBreaksInProgressList ) {
  1311. Rfcb->NewOplockLevel = NO_OPLOCK_BREAK_IN_PROGRESS;
  1312. Rfcb->OplockState = OplockStateNone;
  1313. //
  1314. // Remove the Rfcb from the Oplock breaks in progress list, and
  1315. // release the Rfcb reference.
  1316. //
  1317. SrvRemoveEntryList( &SrvOplockBreaksInProgressList, &Rfcb->ListEntry );
  1318. Rfcb->OnOplockBreaksInProgressList = FALSE;
  1319. #if DBG
  1320. Rfcb->ListEntry.Flink = Rfcb->ListEntry.Blink = NULL;
  1321. #endif
  1322. RELEASE_LOCK( &SrvOplockBreakListLock );
  1323. SrvDereferenceRfcb( Rfcb );
  1324. ExInterlockedAddUlong(
  1325. &connection->OplockBreaksInProgress,
  1326. (ULONG)-1,
  1327. connection->EndpointSpinLock
  1328. );
  1329. } else {
  1330. RELEASE_LOCK( &SrvOplockBreakListLock );
  1331. }
  1332. //
  1333. // If this RFCB has a batch oplock, then it is eligible for caching.
  1334. //
  1335. if ( Rfcb->IsCacheable && Rfcb->NumberOfLocks == 0 &&
  1336. ((Rfcb->OplockState == OplockStateOwnBatch) ||
  1337. (Rfcb->OplockState == OplockStateOwnServerBatch)) &&
  1338. (Rfcb->PagedRfcb->FcbOpenCount == 0) &&
  1339. !Rfcb->Mfcb->CompatibilityOpen ) {
  1340. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1341. if ( Rfcb->IsCacheable &&
  1342. ((Rfcb->OplockState == OplockStateOwnBatch) ||
  1343. (Rfcb->OplockState == OplockStateOwnServerBatch)) &&
  1344. (GET_BLOCK_STATE(connection) == BlockStateActive) ) {
  1345. //
  1346. // Indicate that this RFCB now has a server-owned batch
  1347. // oplock. Indicate that it is on the cached-after-close
  1348. // list. Insert it on that list.
  1349. //
  1350. UpdateRfcbHistory( Rfcb, 'hcac' );
  1351. Rfcb->OplockState = OplockStateOwnServerBatch;
  1352. Rfcb->CachedOpen = TRUE;
  1353. InsertHeadList(
  1354. &connection->CachedOpenList,
  1355. &Rfcb->CachedOpenListEntry
  1356. );
  1357. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvCompleteRfcbClose: caching rfcb %p\n", Rfcb ));
  1358. //
  1359. // Increment the count of cached RFCBs. If there are now
  1360. // too many cached RFCBs, close the oldest one.
  1361. //
  1362. if ( ++connection->CachedOpenCount > SrvCachedOpenLimit ) {
  1363. PRFCB rfcbToClose;
  1364. rfcbToClose = CONTAINING_RECORD(
  1365. connection->CachedOpenList.Blink,
  1366. RFCB,
  1367. CachedOpenListEntry
  1368. );
  1369. //
  1370. // SrvCloseCachedRfcb releases the spin lock.
  1371. //
  1372. SrvCloseCachedRfcb( rfcbToClose, oldIrql );
  1373. } else {
  1374. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1375. }
  1376. if( Rfcb->PagedRfcb->IpxSmartCardContext ) {
  1377. IF_DEBUG( SIPX ) {
  1378. KdPrint(("Calling Smart Card Close for Rfcb %p\n", Rfcb ));
  1379. }
  1380. SrvIpxSmartCard.Close( Rfcb->PagedRfcb->IpxSmartCardContext );
  1381. Rfcb->PagedRfcb->IpxSmartCardContext = NULL;
  1382. }
  1383. return;
  1384. }
  1385. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1386. }
  1387. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvCompleteRfcbClose: can't cache rfcb %p, %wZ\n",
  1388. Rfcb, &Rfcb->Lfcb->Mfcb->FileName ));
  1389. //
  1390. // Unlink the RFCB from the LFCB. If this is the last RFCB for
  1391. // this LFCB, this will force the file closed even if there are
  1392. // still references to the RFCB. This will unblock blocked I/O.
  1393. //
  1394. UnlinkRfcbFromLfcb( Rfcb );
  1395. //
  1396. // Now reacquire the spin lock so that we can release the "open"
  1397. // reference to the Rfcb. DereferenceRfcbInternal releases the
  1398. // spin lock before returning.
  1399. //
  1400. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1401. DereferenceRfcbInternal( Rfcb, oldIrql );
  1402. INCREMENT_DEBUG_STAT( SrvDbgStatistics.RfcbInfo.Closes );
  1403. return;
  1404. } // SrvCompleteRfcbClose
  1405. VOID SRVFASTCALL
  1406. SrvDereferenceRfcb (
  1407. IN PRFCB Rfcb
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This function decrements the reference count on an RFCB. If the
  1412. reference count goes to zero, the RFCB is deleted.
  1413. Arguments:
  1414. Rfcb - Address of RFCB.
  1415. Return Value:
  1416. None.
  1417. --*/
  1418. {
  1419. KIRQL oldIrql;
  1420. UNLOCKABLE_CODE( 8FIL );
  1421. //
  1422. // Acquire the lock that guards the RFCB's reference count and the
  1423. // connection's file table. Then call the internal routine to
  1424. // decrement the count and possibly delete the RFCB. That function
  1425. // releases the spin lock before returning.
  1426. //
  1427. //
  1428. // !!! If you change the way this routine and
  1429. // DereferenceRfcbInternal work, make sure you check
  1430. // fsd.c\SrvFsdRestartSmbComplete to see if it needs to be
  1431. // changed too.
  1432. //
  1433. ACQUIRE_SPIN_LOCK( &Rfcb->Connection->SpinLock, &oldIrql );
  1434. DereferenceRfcbInternal( Rfcb, oldIrql );
  1435. return;
  1436. } // SrvDereferenceRfcb
  1437. VOID
  1438. DereferenceRfcbInternal (
  1439. IN PRFCB Rfcb,
  1440. IN KIRQL OldIrql
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. This internal function decrements the reference count on an RFCB.
  1445. If the reference count goes to zero, the RFCB is deleted. This
  1446. function is called from other routines in this module.
  1447. *** The spin lock synchronizing access to the RFCB's reference count
  1448. must be held when this function is called. The lock is released
  1449. before this function returns.
  1450. Arguments:
  1451. Rfcb - Address of RFCB.
  1452. OldIrql - The previous IRQL value obtained when the spin lock was
  1453. acquired.
  1454. Return Value:
  1455. None.
  1456. --*/
  1457. {
  1458. PLFCB lfcb;
  1459. PPAGED_RFCB pagedRfcb;
  1460. PCONNECTION connection;
  1461. PWORK_QUEUE queue;
  1462. UNLOCKABLE_CODE( 8FIL );
  1463. ASSERT( GET_BLOCK_TYPE( Rfcb ) == BlockTypeRfcb );
  1464. ASSERT( (LONG)Rfcb->BlockHeader.ReferenceCount > 0 );
  1465. //
  1466. // The lock that guards the RFCB's reference count is held when this
  1467. // function is called.
  1468. //
  1469. // Decrement the reference count. If it goes to zero, remove the
  1470. // RFCB's entry in the file table, remove the RFCB from its parent
  1471. // LFCB's list, and deallocate the RFCB.
  1472. //
  1473. //
  1474. // !!! If you change the way this routine and SrvDereferenceRfcb
  1475. // work, make sure you check fsd.c\SrvFsdRestartSmbComplete to
  1476. // see if it needs to be changed too.
  1477. //
  1478. IF_DEBUG(REFCNT) {
  1479. KdPrint(( "Dereferencing RFCB 0x%p; old refcnt 0x%lx\n",
  1480. Rfcb, Rfcb->BlockHeader.ReferenceCount ));
  1481. }
  1482. connection = Rfcb->Connection;
  1483. queue = connection->CurrentWorkQueue;
  1484. Rfcb->BlockHeader.ReferenceCount--;
  1485. UPDATE_REFERENCE_HISTORY( Rfcb, TRUE );
  1486. if ( Rfcb->BlockHeader.ReferenceCount != 0 ) {
  1487. //
  1488. // Release the spin lock.
  1489. //
  1490. RELEASE_SPIN_LOCK( &connection->SpinLock, OldIrql );
  1491. } else {
  1492. ASSERT( GET_BLOCK_STATE(Rfcb) == BlockStateClosing );
  1493. ASSERT( Rfcb->ListEntry.Flink == NULL && \
  1494. Rfcb->ListEntry.Blink == NULL );
  1495. UpdateRfcbHistory( Rfcb, '0fer' );
  1496. //
  1497. // Remove the file entry from the appropriate connection file
  1498. // table.
  1499. //
  1500. SrvRemoveEntryTable(
  1501. &connection->FileTable,
  1502. FID_INDEX( Rfcb->Fid )
  1503. );
  1504. //
  1505. // Release the spin lock.
  1506. //
  1507. RELEASE_SPIN_LOCK( &connection->SpinLock, OldIrql );
  1508. //
  1509. // Free the IRP if one has been allocated.
  1510. //
  1511. if ( Rfcb->Irp != NULL ) {
  1512. UpdateRfcbHistory( Rfcb, 'prif' );
  1513. IoFreeIrp( Rfcb->Irp );
  1514. }
  1515. //
  1516. // Remove the RFCB from the LFCB's list and dereference the LFCB.
  1517. // Acquire the MFCB lock. SrvDereferenceLfcb will release it.
  1518. //
  1519. pagedRfcb = Rfcb->PagedRfcb;
  1520. lfcb = Rfcb->Lfcb;
  1521. ACQUIRE_LOCK( &lfcb->Mfcb->NonpagedMfcb->Lock);
  1522. //
  1523. // Remove the RFCB from the global list of RFCBs.
  1524. //
  1525. SrvRemoveEntryOrderedList( &SrvRfcbList, Rfcb );
  1526. SrvRemoveEntryList( &lfcb->RfcbList, &pagedRfcb->LfcbListEntry );
  1527. SrvDereferenceLfcb( lfcb );
  1528. DEBUG Rfcb->Lfcb = 0;
  1529. //
  1530. // Free the RFCB.
  1531. //
  1532. SrvFreeRfcb( Rfcb, queue );
  1533. }
  1534. return;
  1535. } // DereferenceRfcbInternal
  1536. VOID SRVFASTCALL
  1537. SrvFreeRfcb (
  1538. IN PRFCB Rfcb,
  1539. PWORK_QUEUE queue
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. This function returns an RFCB to the system nonpaged pool. If changes are
  1544. made here, check out FreeIdleWorkItems in scavengr.c!
  1545. Arguments:
  1546. Rfcb - Address of RFCB
  1547. Return Value:
  1548. None.
  1549. --*/
  1550. {
  1551. PAGED_CODE();
  1552. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvFreeRfcb: %p\n", Rfcb ));
  1553. ASSERT( Rfcb->RawWriteCount == 0 );
  1554. ASSERT( IsListEmpty(&Rfcb->RawWriteSerializationList) );
  1555. UpdateRfcbHistory( Rfcb, 'eerf' );
  1556. //
  1557. // Free the the RFCB.
  1558. //
  1559. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Rfcb, BlockTypeGarbage, BlockStateDead, -1 );
  1560. DEBUG Rfcb->BlockHeader.ReferenceCount = (ULONG)-1;
  1561. TERMINATE_REFERENCE_HISTORY( Rfcb );
  1562. Rfcb = (PRFCB)InterlockedExchangePointer( &queue->CachedFreeRfcb,
  1563. Rfcb );
  1564. if( Rfcb != NULL ) {
  1565. //
  1566. // This check allows for the possibility that FreeRfcbs might exceed
  1567. // MaxFreeRfcbs, but it's fairly unlikely given the operation of kernel
  1568. // queue objects. But even so, it probably won't exceed it by much and
  1569. // is really only advisory anyway.
  1570. //
  1571. if( queue->FreeRfcbs < queue->MaxFreeRfcbs ) {
  1572. ExInterlockedPushEntrySList(
  1573. &queue->RfcbFreeList,
  1574. &Rfcb->SingleListEntry,
  1575. &queue->SpinLock
  1576. );
  1577. InterlockedIncrement( &queue->FreeRfcbs );
  1578. } else {
  1579. FREE_HEAP( Rfcb->PagedRfcb );
  1580. DEALLOCATE_NONPAGED_POOL( Rfcb );
  1581. IF_DEBUG(HEAP) KdPrint(( "SrvFreeRfcb: Freed RFCB at 0x%p\n", Rfcb ));
  1582. INCREMENT_DEBUG_STAT( SrvDbgStatistics.RfcbInfo.Frees );
  1583. }
  1584. }
  1585. //
  1586. // Unlock the file-based code section.
  1587. //
  1588. DEREFERENCE_UNLOCKABLE_CODE( 8FIL );
  1589. InterlockedDecrement(
  1590. (PLONG)&SrvStatistics.CurrentNumberOfOpenFiles
  1591. );
  1592. return;
  1593. } // SrvFreeRfcb
  1594. VOID SRVFASTCALL
  1595. SrvReferenceRfcb (
  1596. PRFCB Rfcb
  1597. )
  1598. /*++
  1599. Routine Description:
  1600. This function increments the reference count on an RFCB.
  1601. Arguments:
  1602. Rfcb - Address of RFCB
  1603. Return Value:
  1604. None.
  1605. --*/
  1606. {
  1607. KIRQL oldIrql;
  1608. UNLOCKABLE_CODE( 8FIL );
  1609. //
  1610. // Acquire the spin lock that protects the RFCB's reference count,
  1611. // then call an internal routine to increment the RFCB's reference
  1612. // count. That routine releases the spin lock.
  1613. //
  1614. ACQUIRE_SPIN_LOCK( &Rfcb->Connection->SpinLock, &oldIrql );
  1615. ReferenceRfcbInternal( Rfcb, oldIrql );
  1616. return;
  1617. } // SrvReferenceRfcb
  1618. VOID
  1619. ReferenceRfcbInternal (
  1620. PRFCB Rfcb,
  1621. KIRQL OldIrql
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. This function increments the reference count on an RFCB.
  1626. *** The spin lock synchronizing access to the RFCB's reference count
  1627. must be held when this function is called. The lock is released
  1628. before this function returns.
  1629. Arguments:
  1630. Rfcb - Address of RFCB
  1631. Return Value:
  1632. None.
  1633. --*/
  1634. {
  1635. UNLOCKABLE_CODE( 8FIL );
  1636. ASSERT( (LONG)Rfcb->BlockHeader.ReferenceCount > 0 );
  1637. ASSERT( GET_BLOCK_TYPE(Rfcb) == BlockTypeRfcb );
  1638. // ASSERT( GET_BLOCK_STATE(Rfcb) == BlockStateActive );
  1639. UPDATE_REFERENCE_HISTORY( Rfcb, FALSE );
  1640. //
  1641. // Increment the RFCB's reference count.
  1642. //
  1643. Rfcb->BlockHeader.ReferenceCount++;
  1644. IF_DEBUG(REFCNT) {
  1645. KdPrint(( "Referencing RFCB 0x%p; new refcnt 0x%lx\n",
  1646. Rfcb, Rfcb->BlockHeader.ReferenceCount ));
  1647. }
  1648. //
  1649. // Release the spin lock before returning to the caller.
  1650. //
  1651. RELEASE_SPIN_LOCK( &Rfcb->Connection->SpinLock, OldIrql );
  1652. return;
  1653. } // ReferenceRfcbInternal
  1654. BOOLEAN
  1655. SrvFindCachedRfcb (
  1656. IN PWORK_CONTEXT WorkContext,
  1657. IN PMFCB Mfcb,
  1658. IN ACCESS_MASK DesiredAccess,
  1659. IN ULONG ShareAccess,
  1660. IN ULONG CreateDisposition,
  1661. IN ULONG CreateOptions,
  1662. IN OPLOCK_TYPE RequestedOplockType,
  1663. OUT PNTSTATUS Status
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. This routine searches a connection's cached-after-close RFCB list
  1668. to attempt to find an existing handle that can be matched up with
  1669. a new open attempt. If one is found, it is removed from the list
  1670. and reactivated.
  1671. Arguments:
  1672. WorkContext - Pointer to work context block.
  1673. Mfcb - Address of MFCB for file being opened.
  1674. DesiredAccess - Desired access for new open. Used for matching
  1675. purposes.
  1676. ShareAccess - Share access for new open. Used for matching
  1677. purposes.
  1678. CreateDisposition - Create disposition for new open. Used for
  1679. matching purposes.
  1680. CreateOptions - Create options for new open. Used for matching
  1681. purposes.
  1682. RequestedOplockType - Oplock type requested by the client (or the
  1683. server) for the new open. Used for matching purposes.
  1684. Status - Returns the status of the search. Only valid if return
  1685. value is TRUE. Will be STATUS_SUCCESS if a cached open was
  1686. found and taken out of the cache. In this case, the RFCB
  1687. address is stored in WorkContext->Rfcb. Status will be
  1688. STATUS_OBJECT_NAME_COLLISION if the file is cached but the
  1689. caller wants the open to file if the file exists.
  1690. Return Value:
  1691. BOOLEAN - TRUE if a cached open was found and returned.
  1692. --*/
  1693. {
  1694. PCONNECTION connection = WorkContext->Connection;
  1695. PLIST_ENTRY listEntry;
  1696. PRFCB rfcb;
  1697. KIRQL oldIrql;
  1698. USHORT uid, tid;
  1699. BOOLEAN wantsWriteThrough, isWriteThrough;
  1700. ACCESS_MASK nongenericDesiredAccess;
  1701. //UNLOCKABLE_CODE( CONN );
  1702. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvFindCachedRfcb: called for %wZ\n", &Mfcb->FileName ));
  1703. //
  1704. // If the client doesn't want an oplock, then the server should have
  1705. // asked for its own batch oplock.
  1706. //
  1707. ASSERT( (RequestedOplockType == OplockTypeBatch) ||
  1708. (RequestedOplockType == OplockTypeExclusive) ||
  1709. (RequestedOplockType == OplockTypeServerBatch) );
  1710. //
  1711. // This routine must not be called for create dispositions that are
  1712. // inconsistent with reusing a cached open. Specifically, supersede
  1713. // and overwrite are not allowed.
  1714. //
  1715. ASSERT( (CreateDisposition == FILE_OPEN) ||
  1716. (CreateDisposition == FILE_CREATE) ||
  1717. (CreateDisposition == FILE_OPEN_IF) );
  1718. //
  1719. // If the connection has no cached RFCBs, get out quick.
  1720. //
  1721. if ( connection->CachedOpenCount == 0 ) {
  1722. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvFindCachedRfcb: connection has no cached RFCBs\n" ));
  1723. return FALSE;
  1724. }
  1725. //
  1726. // The input DesiredAccess may include generic access modes, but the
  1727. // RFCB has specific access modes, so we have to translate
  1728. // DesiredAccess.
  1729. //
  1730. nongenericDesiredAccess = DesiredAccess;
  1731. IoCheckDesiredAccess( &nongenericDesiredAccess, 0 );
  1732. uid = WorkContext->Session->Uid;
  1733. tid = WorkContext->TreeConnect->Tid;
  1734. //
  1735. // Lock the cached open list and look for a matching RFCB.
  1736. //
  1737. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1738. for ( listEntry = connection->CachedOpenList.Flink;
  1739. listEntry != &connection->CachedOpenList;
  1740. listEntry = listEntry->Flink ) {
  1741. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  1742. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvFindCachedRfcb: checking rfcb %p; mfcb = %p\n",
  1743. rfcb, rfcb->Mfcb ));
  1744. ASSERT( rfcb->OplockState == OplockStateOwnServerBatch );
  1745. ASSERT( rfcb->CachedOpen );
  1746. ASSERT( GET_BLOCK_STATE(rfcb) == BlockStateClosing );
  1747. //
  1748. // If this RFCB is for the right file, we can proceed with other
  1749. // checks.
  1750. //
  1751. if ( rfcb->Mfcb == Mfcb ) {
  1752. //
  1753. // If the client asked for FILE_CREATE, we can fail the open
  1754. // now, because the file exists.
  1755. //
  1756. if ( CreateDisposition == FILE_CREATE ) {
  1757. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvFindCachedRfcb: client wants to create\n" ));
  1758. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1759. *Status = STATUS_OBJECT_NAME_COLLISION;
  1760. return TRUE;
  1761. }
  1762. //
  1763. // Check the access modes to make sure they're compatible.
  1764. // The new open must:
  1765. //
  1766. // a) have the same desired access as what was granted before;
  1767. // b) have the same share access;
  1768. // c) have the create disposition (in the bits we care about);
  1769. // d) be requesting a batch oplock;
  1770. // e) be for the same UID and TID.
  1771. //
  1772. #define FILE_MODE_FLAGS (FILE_DIRECTORY_FILE | \
  1773. FILE_SEQUENTIAL_ONLY | \
  1774. FILE_NON_DIRECTORY_FILE | \
  1775. FILE_NO_EA_KNOWLEDGE | \
  1776. FILE_RANDOM_ACCESS | \
  1777. FILE_OPEN_REPARSE_POINT | \
  1778. FILE_OPEN_FOR_BACKUP_INTENT)
  1779. if ( (rfcb->GrantedAccess != nongenericDesiredAccess) ||
  1780. (rfcb->ShareAccess != ShareAccess) ||
  1781. ((rfcb->FileMode & FILE_MODE_FLAGS) !=
  1782. (CreateOptions & FILE_MODE_FLAGS)) ||
  1783. (RequestedOplockType == OplockTypeExclusive) ||
  1784. (rfcb->Uid != uid) ||
  1785. (rfcb->Tid != tid) ) {
  1786. #if 0
  1787. IF_DEBUG(FILE_CACHE) {
  1788. if ( rfcb->GrantedAccess != nongenericDesiredAccess )
  1789. KdPrint(( "SrvFindCachedRfcb: granted access %x doesn't match desired access %x\n",
  1790. rfcb->GrantedAccess, nongenericDesiredAccess ));
  1791. if ( rfcb->ShareAccess != ShareAccess )
  1792. KdPrint(( "SrvFindCachedRfcb: share access %x doesn't match share access %x\n",
  1793. rfcb->ShareAccess, ShareAccess ));
  1794. if ( (rfcb->FileMode & FILE_MODE_FLAGS) != (CreateOptions & FILE_MODE_FLAGS))
  1795. KdPrint(( "SrvFindCachedRfcb: share access %x doesn't match share access %x\n",
  1796. rfcb->FileMode&FILE_MODE_FLAGS, CreateOptions&FILE_MODE_FLAGS ));
  1797. if ( RequestedOplockType == OplockTypeExclusive )
  1798. KdPrint(( "SrvFindCachedRfcb: client wants exclusive oplock\n" ));
  1799. if ( rfcb->Uid != uid )
  1800. KdPrint(( "SrvFindCachedRfcb: UID %x doesn't match UID %x\n", rfcb->Uid, uid ));
  1801. if ( rfcb->Tid != tid )
  1802. KdPrint(( "SrvFindCachedRfcb: TID %x doesn't match TID %x\n", rfcb->Tid, tid ));
  1803. }
  1804. #endif
  1805. //
  1806. // The file is cached, but the new open is inconsistent
  1807. // with the cached open. We must not use the cached
  1808. // open. It would be more efficient to close the cached
  1809. // RFCB here, since we know the caller is going to turn
  1810. // around and open the file because we're returning
  1811. // FALSE, thus breaking the batch oplock. However, our
  1812. // caller owns the MFCB lock, while closing an RFCB
  1813. // requires obtaining the MFCB list lock. Acquiring
  1814. // these locks in this order leads to deadlock.
  1815. //
  1816. // Note that there is no need to continue the list walk.
  1817. // We have a batch oplock, so we can only have the file
  1818. // open once.
  1819. //
  1820. #if 0
  1821. SrvCloseCachedRfcb( rfcb, oldIrql );
  1822. #else
  1823. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1824. #endif
  1825. return FALSE;
  1826. }
  1827. //
  1828. // The file is cached and the new open is consistent with the
  1829. // cached open. Remove the open from the cache and give it
  1830. // to the new opener.
  1831. //
  1832. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvFindCachedRfcb: Reusing cached RFCB %p\n", rfcb ));
  1833. UpdateRfcbHistory( rfcb, ' $nu' );
  1834. RemoveEntryList( &rfcb->CachedOpenListEntry );
  1835. connection->CachedOpenCount--;
  1836. ASSERT( (LONG)connection->CachedOpenCount >= 0 );
  1837. rfcb->CachedOpen = FALSE;
  1838. if ( RequestedOplockType == OplockTypeBatch ) {
  1839. rfcb->OplockState = OplockStateOwnBatch;
  1840. }
  1841. SET_BLOCK_STATE( rfcb, BlockStateActive );
  1842. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1843. WorkContext->Rfcb = rfcb;
  1844. SrvReferenceRfcb( rfcb );
  1845. rfcb->IsActive = FALSE;
  1846. rfcb->WrittenTo = FALSE;
  1847. wantsWriteThrough = (BOOLEAN)((CreateOptions & FILE_WRITE_THROUGH) != 0);
  1848. isWriteThrough = (BOOLEAN)((rfcb->Lfcb->FileMode & FILE_WRITE_THROUGH) == 0);
  1849. if ( wantsWriteThrough != isWriteThrough ) {
  1850. SrvSetFileWritethroughMode( rfcb->Lfcb, wantsWriteThrough );
  1851. }
  1852. INCREMENT_DEBUG_STAT( SrvDbgStatistics.OpensSatisfiedWithCachedRfcb );
  1853. WorkContext->Irp->IoStatus.Information = FILE_OPENED;
  1854. *Status = STATUS_SUCCESS;
  1855. return TRUE;
  1856. }
  1857. }
  1858. //
  1859. // We couldn't find the requested file in the cache.
  1860. //
  1861. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1862. return FALSE;
  1863. } // SrvFindCachedRfcb
  1864. ULONG
  1865. SrvCountCachedRfcbsForTid(
  1866. PCONNECTION connection,
  1867. USHORT Tid
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. This returns the number of RFCBS in the cache that are associated with Tid
  1872. Arguments:
  1873. connection - Address of the CONNECTION structure of interest
  1874. Return Value:
  1875. Count of cached RFCBs
  1876. --*/
  1877. {
  1878. PLIST_ENTRY listEntry;
  1879. PRFCB rfcb;
  1880. KIRQL oldIrql;
  1881. USHORT count = 0;
  1882. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1883. for ( listEntry = connection->CachedOpenList.Flink;
  1884. listEntry != &connection->CachedOpenList;
  1885. listEntry = listEntry->Flink ) {
  1886. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  1887. if( rfcb->Tid == Tid ) {
  1888. ++count;
  1889. }
  1890. }
  1891. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1892. return count;
  1893. }
  1894. ULONG
  1895. SrvCountCachedRfcbsForUid(
  1896. PCONNECTION connection,
  1897. USHORT Uid
  1898. )
  1899. /*++
  1900. Routine Description:
  1901. This returns the number of RFCBS in the cache that are associated with Uid
  1902. Arguments:
  1903. connection - Address of the CONNECTION structure of interest
  1904. Return Value:
  1905. Count of cached RFCBs
  1906. --*/
  1907. {
  1908. PLIST_ENTRY listEntry;
  1909. PRFCB rfcb;
  1910. KIRQL oldIrql;
  1911. ULONG count = 0;
  1912. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1913. for ( listEntry = connection->CachedOpenList.Flink;
  1914. listEntry != &connection->CachedOpenList;
  1915. listEntry = listEntry->Flink ) {
  1916. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  1917. if( rfcb->Uid == Uid ) {
  1918. ++count;
  1919. }
  1920. }
  1921. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  1922. return count;
  1923. }
  1924. VOID
  1925. SrvCloseCachedRfcb (
  1926. IN PRFCB Rfcb,
  1927. IN KIRQL OldIrql
  1928. )
  1929. /*++
  1930. Routine Description:
  1931. This routine closes a cached open.
  1932. *** This routine must be called with the connection spin lock held.
  1933. Arguments:
  1934. Rfcb - Address of RFCB to close.
  1935. OldIrql - IRQL at which the called acquired the connection spin
  1936. lock. This must be lower than DISPATCH_LEVEL!
  1937. Return Value:
  1938. None.
  1939. --*/
  1940. {
  1941. PCONNECTION connection = Rfcb->Connection;
  1942. KIRQL oldIrql;
  1943. UNLOCKABLE_CODE( 8FIL );
  1944. UpdateRfcbHistory( Rfcb, '$slc' );
  1945. //
  1946. // This routine must be called with the connection spin lock held.
  1947. // The caller must have been at low IRQL before acquiring the spin
  1948. // lock.
  1949. //
  1950. IF_DEBUG(FILE_CACHE) KdPrint(( "SrvCloseCachedRfcb called for rfcb %p", Rfcb ));
  1951. ASSERT( OldIrql < DISPATCH_LEVEL );
  1952. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  1953. //
  1954. // Remove the RFCB from the connection's cache.
  1955. //
  1956. ASSERT( Rfcb->CachedOpen );
  1957. Rfcb->CachedOpen = FALSE;
  1958. Rfcb->OplockState = OplockStateNone;
  1959. RemoveEntryList( &Rfcb->CachedOpenListEntry );
  1960. connection->CachedOpenCount--;
  1961. ASSERT( (LONG)connection->CachedOpenCount >= 0 );
  1962. RELEASE_SPIN_LOCK( &connection->SpinLock, OldIrql );
  1963. IF_DEBUG(FILE_CACHE) KdPrint(( "; file %wZ\n", &Rfcb->Mfcb->FileName ));
  1964. //
  1965. // Unlink the RFCB from the LFCB. If this is the last RFCB for
  1966. // this LFCB, this will force the file closed even if there are
  1967. // still references to the RFCB. This will unblock blocked I/O.
  1968. //
  1969. UnlinkRfcbFromLfcb( Rfcb );
  1970. //
  1971. // Now acquire the FSD spin lock so that we can release the "open"
  1972. // reference to the Rfcb. DereferenceRfcbInternal releases the spin
  1973. // lock before returning.
  1974. //
  1975. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  1976. DereferenceRfcbInternal( Rfcb, oldIrql );
  1977. INCREMENT_DEBUG_STAT( SrvDbgStatistics.RfcbInfo.Closes );
  1978. return;
  1979. } // SrvCloseCachedRfcb
  1980. VOID
  1981. SrvCloseCachedRfcbsOnConnection (
  1982. IN PCONNECTION Connection
  1983. )
  1984. /*++
  1985. Routine Description:
  1986. This routine closes all cached opens on a connection.
  1987. Arguments:
  1988. Connection - Address of connection for which cached opens are to be closed.
  1989. Return Value:
  1990. None.
  1991. --*/
  1992. {
  1993. PLIST_ENTRY listEntry;
  1994. PRFCB rfcb;
  1995. KIRQL OldIrql;
  1996. IF_DEBUG(FILE_CACHE) {
  1997. KdPrint(( "SrvCloseCachedRfcbsOnConnection called for connection %p\n", Connection ));
  1998. }
  1999. //
  2000. // Remove all RFCBs from the connection's open file cache.
  2001. //
  2002. // This routine needs to be protected from the situation where a Blocking Rename causes us to close all
  2003. // cached opens, but an Oplock break comes during that time and sees that Cached Open is still set to TRUE
  2004. // (Since we didn't hold the SpinLock during the operation)
  2005. ACQUIRE_SPIN_LOCK( &Connection->SpinLock, &OldIrql );
  2006. while ( IsListEmpty( &Connection->CachedOpenList ) == FALSE ) {
  2007. listEntry = RemoveHeadList( &Connection->CachedOpenList );
  2008. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  2009. UpdateRfcbHistory( rfcb, 'nc$c' );
  2010. //
  2011. // Remove the RFCB from the connection's cache.
  2012. //
  2013. Connection->CachedOpenCount--;
  2014. ASSERT( rfcb->CachedOpen );
  2015. rfcb->CachedOpen = FALSE;
  2016. ASSERT( rfcb->OplockState == OplockStateOwnServerBatch );
  2017. rfcb->OplockState = OplockStateNone;
  2018. IF_DEBUG(FILE_CACHE) {
  2019. KdPrint(( "SrvCloseCachedRfcbsOnConnection; closing rfcb %p file %wZ\n",
  2020. rfcb, &rfcb->Mfcb->FileName ));
  2021. }
  2022. RELEASE_SPIN_LOCK( &Connection->SpinLock, OldIrql );
  2023. //
  2024. // Unlink the RFCB from the LFCB. If this is the last RFCB for
  2025. // this LFCB, this will force the file closed even if there are
  2026. // still references to the RFCB. This will unblock blocked I/O.
  2027. //
  2028. UnlinkRfcbFromLfcb( rfcb );
  2029. //
  2030. // Release the "open" reference to the Rfcb.
  2031. //
  2032. SrvDereferenceRfcb( rfcb );
  2033. INCREMENT_DEBUG_STAT( SrvDbgStatistics.RfcbInfo.Closes );
  2034. ACQUIRE_SPIN_LOCK( &Connection->SpinLock, &OldIrql );
  2035. }
  2036. RELEASE_SPIN_LOCK( &Connection->SpinLock, OldIrql );
  2037. return;
  2038. } // SrvCloseCachedRfcbsOnConnection
  2039. VOID
  2040. SrvCloseCachedRfcbsOnLfcb (
  2041. IN PLFCB Lfcb
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. This routine closes all cached opens associated with a specific LFCB.
  2046. Arguments:
  2047. Lfcb - Address of LFCB for which cached opens are to be closed.
  2048. Return Value:
  2049. None.
  2050. --*/
  2051. {
  2052. PCONNECTION connection;
  2053. PLIST_ENTRY listEntry;
  2054. PLIST_ENTRY nextListEntry;
  2055. PRFCB rfcb;
  2056. KIRQL oldIrql;
  2057. LIST_ENTRY rfcbsToClose;
  2058. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  2059. connection = Lfcb->Connection;
  2060. IF_DEBUG(FILE_CACHE) {
  2061. KdPrint(( "SrvCloseCachedRfcbsOnLfcb called for lfcb %p connection %p", Lfcb, connection ));
  2062. }
  2063. InitializeListHead( &rfcbsToClose );
  2064. //
  2065. // Lock and walk the connection's cached open list. We don't
  2066. // actually closed the RFCBs on the first pass, since that would
  2067. // require releasing the lock. Instead, we remove them from the
  2068. // connection list and add them to a local list.
  2069. //
  2070. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  2071. for ( listEntry = connection->CachedOpenList.Flink;
  2072. listEntry != &connection->CachedOpenList;
  2073. listEntry = nextListEntry ) {
  2074. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  2075. nextListEntry = listEntry->Flink;
  2076. if ( rfcb->Lfcb == Lfcb ) {
  2077. //
  2078. // Remove the RFCB from the connection's cache.
  2079. //
  2080. UpdateRfcbHistory( rfcb, 'fl$c' );
  2081. RemoveEntryList( listEntry );
  2082. connection->CachedOpenCount--;
  2083. InsertTailList( &rfcbsToClose, listEntry );
  2084. ASSERT( rfcb->CachedOpen );
  2085. rfcb->CachedOpen = FALSE;
  2086. ASSERT( rfcb->OplockState == OplockStateOwnServerBatch );
  2087. rfcb->OplockState = OplockStateNone;
  2088. }
  2089. }
  2090. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2091. //
  2092. // Walk the local list and close each RFCB.
  2093. //
  2094. for ( listEntry = rfcbsToClose.Flink;
  2095. listEntry != &rfcbsToClose;
  2096. listEntry = nextListEntry ) {
  2097. rfcb = CONTAINING_RECORD( listEntry, RFCB, CachedOpenListEntry );
  2098. nextListEntry = listEntry->Flink;
  2099. IF_DEBUG(FILE_CACHE) {
  2100. KdPrint(( "SrvCloseCachedRfcbsOnConnection; closing rfcb %p file %wZ\n",
  2101. rfcb, &rfcb->Mfcb->FileName ));
  2102. }
  2103. //
  2104. // Unlink the RFCB from the LFCB. If this is the last RFCB for
  2105. // this LFCB, this will force the file closed even if there are
  2106. // still references to the RFCB. This will unblock blocked I/O.
  2107. //
  2108. UnlinkRfcbFromLfcb( rfcb );
  2109. //
  2110. // Release the "open" reference to the Rfcb.
  2111. //
  2112. SrvDereferenceRfcb( rfcb );
  2113. INCREMENT_DEBUG_STAT( SrvDbgStatistics.RfcbInfo.Closes );
  2114. }
  2115. return;
  2116. } // SrvCloseCachedRfcbsOnLfcb
  2117. #ifdef SRVDBG_RFCBHIST
  2118. VOID
  2119. UpdateRfcbHistory (
  2120. IN PRFCB Rfcb,
  2121. IN ULONG Event
  2122. )
  2123. {
  2124. KIRQL oldIrql;
  2125. ACQUIRE_SPIN_LOCK( &Rfcb->SpinLock, &oldIrql );
  2126. Rfcb->History[Rfcb->HistoryIndex++] = Event;
  2127. RELEASE_SPIN_LOCK( &Rfcb->SpinLock, oldIrql );
  2128. return;
  2129. }
  2130. #endif