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.

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