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.

2996 lines
74 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ResrcSup.c
  5. Abstract:
  6. This module implements the Ntfs Resource acquisition routines
  7. Author:
  8. Gary Kimura [GaryKi] 21-May-1991
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. #undef _NTFSLOCKORDER_
  13. #define _NTFS_NTFSDBG_DEFINITIONS_
  14. #include "lockorder.h"
  15. #ifdef NTFSDBG
  16. ULONG NtfsAssertOnLockProb = TRUE;
  17. ULONG NtfsPrintOnLockProb = FALSE;
  18. LONG NtfsBreakOnState = -1;
  19. PIRP_CONTEXT NtfsBreakOnIrpContext = NULL;
  20. #endif
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE, NtfsAcquireAllFiles)
  23. #pragma alloc_text(PAGE, NtfsAcquireCheckpointSynchronization)
  24. #pragma alloc_text(PAGE, NtfsAcquireIndexCcb)
  25. #pragma alloc_text(PAGE, NtfsReleaseIndexCcb)
  26. #pragma alloc_text(PAGE, NtfsAcquireExclusiveFcb)
  27. #pragma alloc_text(PAGE, NtfsAcquireSharedFcbCheckWait)
  28. #pragma alloc_text(PAGE, NtfsAcquireExclusiveScb)
  29. #pragma alloc_text(PAGE, NtfsAcquireSharedScbForTransaction)
  30. #pragma alloc_text(PAGE, NtfsAcquireExclusiveVcb)
  31. #pragma alloc_text(PAGE, NtfsAcquireFcbWithPaging)
  32. #pragma alloc_text(PAGE, NtfsAcquireForCreateSection)
  33. #pragma alloc_text(PAGE, NtfsAcquireScbForLazyWrite)
  34. #pragma alloc_text(PAGE, NtfsAcquireFileForCcFlush)
  35. #pragma alloc_text(PAGE, NtfsAcquireFileForModWrite)
  36. #pragma alloc_text(PAGE, NtfsAcquireSharedVcb)
  37. #pragma alloc_text(PAGE, NtfsAcquireVolumeFileForLazyWrite)
  38. #pragma alloc_text(PAGE, NtfsReleaseAllFiles)
  39. #pragma alloc_text(PAGE, NtfsReleaseCheckpointSynchronization)
  40. #pragma alloc_text(PAGE, NtfsReleaseFcbWithPaging)
  41. #pragma alloc_text(PAGE, NtfsReleaseFileForCcFlush)
  42. #pragma alloc_text(PAGE, NtfsReleaseForCreateSection)
  43. #pragma alloc_text(PAGE, NtfsReleaseScbFromLazyWrite)
  44. #pragma alloc_text(PAGE, NtfsReleaseScbWithPaging)
  45. #pragma alloc_text(PAGE, NtfsReleaseSharedResources)
  46. #pragma alloc_text(PAGE, NtfsReleaseVolumeFileFromLazyWrite)
  47. #endif
  48. VOID
  49. NtfsAcquireAllFiles (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PVCB Vcb,
  52. IN ULONG Exclusive,
  53. IN ULONG AcquirePagingIo,
  54. IN ULONG AcquireAndDrop
  55. )
  56. /*++
  57. Routine Description:
  58. This routine non-recursively requires all files on a volume.
  59. Arguments:
  60. Vcb - Supplies the volume
  61. Exclusive - Indicates if we should be acquiring all the files exclusively.
  62. If FALSE then we acquire all the files shared except for files with
  63. streams which could be part of transactions.
  64. AcquirePagingIo - Indicates if we need to acquire the paging io resource
  65. exclusively. Only needed if a future call will flush the volume
  66. (i.e. shutdown)
  67. AcquireAndDrop - Indicates that we only want to acquire and drop each resource.
  68. Used in cases where we just want to set some state in the Vcb and then
  69. know that everyone has seen it before proceeding (i.e. Clearing the journal active
  70. flag). Should only be TRUE if we want to get the resources exclusive.
  71. Return Value:
  72. None
  73. --*/
  74. {
  75. PFCB Fcb;
  76. PSCB *Scb;
  77. PSCB NextScb;
  78. PVOID RestartKey;
  79. PAGED_CODE();
  80. //
  81. // Check for the correct combination of flags.
  82. //
  83. ASSERT( !AcquireAndDrop || Exclusive );
  84. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  85. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  86. RestartKey = NULL;
  87. while (TRUE) {
  88. NtfsAcquireFcbTable( IrpContext, Vcb );
  89. Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey);
  90. NtfsReleaseFcbTable( IrpContext, Vcb );
  91. if (Fcb == NULL) {
  92. break;
  93. }
  94. ASSERT_FCB( Fcb );
  95. //
  96. // We can skip over the Fcb's for any of the Scb's in the Vcb.
  97. // We delay acquiring those to avoid deadlocks.
  98. //
  99. if (!FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  100. //
  101. // If there is a paging Io resource then acquire this if required.
  102. //
  103. if (AcquirePagingIo && (Fcb->PagingIoResource != NULL)) {
  104. ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, TRUE );
  105. if (AcquireAndDrop) {
  106. ExReleaseResourceLite( Fcb->PagingIoResource );
  107. }
  108. }
  109. //
  110. // Acquire this Fcb whether or not the underlying file has been deleted.
  111. //
  112. if (Exclusive ||
  113. IsDirectory( &Fcb->Info )) {
  114. if (AcquireAndDrop) {
  115. NtfsAcquireResourceExclusive( IrpContext, Fcb, TRUE );
  116. NtfsReleaseResource( IrpContext, Fcb );
  117. } else {
  118. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  119. }
  120. } else {
  121. //
  122. // Assume that we only need this file shared. We will then
  123. // look for Lsn related streams.
  124. //
  125. NtfsAcquireSharedFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  126. //
  127. // Walk through all of the Scb's for the file and look for
  128. // an Lsn protected stream.
  129. //
  130. NtfsLockFcb( IrpContext, Fcb );
  131. NextScb = NULL;
  132. while (NextScb = NtfsGetNextChildScb( Fcb, NextScb )) {
  133. if (NextScb->AttributeTypeCode != $DATA) {
  134. break;
  135. }
  136. }
  137. NtfsUnlockFcb( IrpContext, Fcb );
  138. //
  139. // If we found a protected Scb then release and reacquire the Fcb
  140. // exclusively.
  141. //
  142. if (NextScb != NULL) {
  143. NtfsReleaseFcb( IrpContext, Fcb );
  144. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  145. }
  146. }
  147. }
  148. }
  149. //
  150. // Now acquire the Fcb's in the Vcb.
  151. //
  152. Scb = &Vcb->MftBitmapScb;
  153. //
  154. // Ordering dependent on the fact we acquired root up above because its not a system file
  155. //
  156. ASSERT( (NULL == Vcb->RootIndexScb) || !FlagOn( Vcb->RootIndexScb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE ) );
  157. while (TRUE) {
  158. if (Scb == &Vcb->UsnJournal) {
  159. break;
  160. }
  161. Scb -= 1;
  162. if ((*Scb != NULL)
  163. && (*Scb != Vcb->BitmapScb)) {
  164. if (AcquireAndDrop) {
  165. if (AcquirePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) {
  166. ExAcquireResourceExclusiveLite( (*Scb)->Fcb->PagingIoResource, TRUE );
  167. ExReleaseResourceLite( (*Scb)->Fcb->PagingIoResource );
  168. }
  169. NtfsAcquireResourceExclusive( IrpContext, (*Scb), TRUE );
  170. NtfsReleaseResource( IrpContext, (*Scb) );
  171. } else {
  172. if (AcquirePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) {
  173. ExAcquireResourceExclusiveLite( (*Scb)->Fcb->PagingIoResource, TRUE );
  174. }
  175. NtfsAcquireExclusiveFcb( IrpContext, (*Scb)->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  176. }
  177. }
  178. }
  179. //
  180. // Treat the bitmap as an end resource and acquire it last.
  181. //
  182. if (Vcb->BitmapScb != NULL) {
  183. ULONG AcquireFlags = ACQUIRE_NO_DELETE_CHECK;
  184. if (AcquireAndDrop) {
  185. if (AcquirePagingIo && (Vcb->BitmapScb->Fcb->PagingIoResource != NULL)) {
  186. ExAcquireResourceExclusiveLite( Vcb->BitmapScb->Fcb->PagingIoResource, TRUE );
  187. ExReleaseResourceLite( Vcb->BitmapScb->Fcb->PagingIoResource );
  188. }
  189. NtfsAcquireResourceExclusive( IrpContext, Vcb->BitmapScb, TRUE );
  190. NtfsReleaseResource( IrpContext, Vcb->BitmapScb );
  191. } else {
  192. if (AcquirePagingIo && (Vcb->BitmapScb->Fcb->PagingIoResource != NULL)) {
  193. ExAcquireResourceExclusiveLite( Vcb->BitmapScb->Fcb->PagingIoResource, TRUE );
  194. }
  195. NtfsAcquireExclusiveFcb( IrpContext, Vcb->BitmapScb->Fcb, NULL, AcquireFlags );
  196. }
  197. }
  198. //
  199. // If we don't have to release the files then don't bump this number.
  200. //
  201. if (!AcquireAndDrop) {
  202. Vcb->AcquireFilesCount += 1;
  203. } else {
  204. NtfsReleaseVcb( IrpContext, Vcb );
  205. }
  206. return;
  207. }
  208. VOID
  209. NtfsReleaseAllFiles (
  210. IN PIRP_CONTEXT IrpContext,
  211. IN PVCB Vcb,
  212. IN BOOLEAN ReleasePagingIo
  213. )
  214. /*++
  215. Routine Description:
  216. This routine non-recursively requires all files on a volume.
  217. Arguments:
  218. Vcb - Supplies the volume
  219. ReleasePagingIo - Indicates whether we should release the paging io resources
  220. as well.
  221. Return Value:
  222. None
  223. --*/
  224. {
  225. PFCB Fcb;
  226. PSCB *Scb;
  227. PVOID RestartKey;
  228. PAGED_CODE();
  229. ASSERT( Vcb->AcquireFilesCount != 0 );
  230. Vcb->AcquireFilesCount -= 1;
  231. //
  232. // Loop to flush all of the prerestart streams, to do the loop
  233. // we cycle through the Fcb Table and for each fcb we acquire it.
  234. //
  235. RestartKey = NULL;
  236. while (TRUE) {
  237. NtfsAcquireFcbTable( IrpContext, Vcb );
  238. Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey);
  239. NtfsReleaseFcbTable( IrpContext, Vcb );
  240. if (Fcb == NULL) {
  241. break;
  242. }
  243. ASSERT_FCB( Fcb );
  244. if (!FlagOn(Fcb->FcbState, FCB_STATE_SYSTEM_FILE)) {
  245. //
  246. // Release the file.
  247. //
  248. if (ReleasePagingIo && (Fcb->PagingIoResource != NULL)) {
  249. ExReleaseResourceLite( Fcb->PagingIoResource );
  250. }
  251. NtfsReleaseFcb( IrpContext, Fcb );
  252. }
  253. }
  254. //
  255. // Now release the Fcb's in the Vcb.
  256. //
  257. Scb = &Vcb->RootIndexScb;
  258. while (TRUE) {
  259. if (Scb == &Vcb->ObjectIdTableScb) {
  260. break;
  261. }
  262. Scb += 1;
  263. if (*Scb != NULL) {
  264. if (ReleasePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) {
  265. ExReleaseResourceLite( (*Scb)->Fcb->PagingIoResource );
  266. }
  267. NtfsReleaseFcb( IrpContext, (*Scb)->Fcb );
  268. }
  269. }
  270. NtfsReleaseVcb( IrpContext, Vcb );
  271. return;
  272. }
  273. VOID
  274. NtfsAcquireCheckpointSynchronization (
  275. IN PIRP_CONTEXT IrpContext,
  276. IN PVCB Vcb
  277. )
  278. /*++
  279. Routine Description:
  280. Synchronize with checkpointing - this blocks out all fuzzy / clean checkpoints
  281. Arguments:
  282. Vcb - Supplies the Vcb to synchronize with
  283. Return Value:
  284. --*/
  285. {
  286. PAGED_CODE();
  287. NtfsAcquireCheckpoint( IrpContext, Vcb );
  288. while (FlagOn( Vcb->CheckpointFlags, VCB_CHECKPOINT_SYNC_FLAGS )) {
  289. //
  290. // Release the checkpoint event because we cannot checkpoint now.
  291. //
  292. NtfsReleaseCheckpoint( IrpContext, Vcb );
  293. NtfsWaitOnCheckpointNotify( IrpContext, Vcb );
  294. NtfsAcquireCheckpoint( IrpContext, Vcb );
  295. }
  296. SetFlag( Vcb->CheckpointFlags, VCB_CHECKPOINT_SYNC_FLAGS );
  297. NtfsResetCheckpointNotify( IrpContext, Vcb );
  298. NtfsReleaseCheckpoint( IrpContext, Vcb );
  299. }
  300. VOID
  301. NtfsReleaseCheckpointSynchronization (
  302. IN PIRP_CONTEXT IrpContext,
  303. IN PVCB Vcb
  304. )
  305. /*++
  306. Routine Description:
  307. Synchronize with checkpointing - this blocks out all fuzzy / clean checkpoints
  308. Arguments:
  309. Vcb - Supplies the Vcb to synchronize with
  310. Return Value:
  311. --*/
  312. {
  313. PAGED_CODE();
  314. NtfsAcquireCheckpoint( IrpContext, Vcb );
  315. ClearFlag( Vcb->CheckpointFlags, VCB_CHECKPOINT_SYNC_FLAGS );
  316. NtfsSetCheckpointNotify( IrpContext, Vcb );
  317. NtfsReleaseCheckpoint( IrpContext, Vcb );
  318. UNREFERENCED_PARAMETER( IrpContext );
  319. }
  320. BOOLEAN
  321. NtfsAcquireExclusiveVcb (
  322. IN PIRP_CONTEXT IrpContext,
  323. IN PVCB Vcb,
  324. IN BOOLEAN RaiseOnCantWait
  325. )
  326. /*++
  327. Routine Description:
  328. This routine acquires exclusive access to the Vcb.
  329. This routine will raise if it cannot acquire the resource and wait
  330. in the IrpContext is false.
  331. Arguments:
  332. Vcb - Supplies the Vcb to acquire
  333. RaiseOnCantWait - Indicates if we should raise on an acquisition error
  334. or simply return a BOOLEAN indicating that we couldn't get the
  335. resource.
  336. Return Value:
  337. BOOLEAN - Indicates if we were able to acquire the resource. This is really
  338. only meaningful if the RaiseOnCantWait value is FALSE.
  339. --*/
  340. {
  341. ASSERT_IRP_CONTEXT(IrpContext);
  342. ASSERT_VCB(Vcb);
  343. PAGED_CODE();
  344. if (ExAcquireResourceExclusiveLite( &Vcb->Resource, (BOOLEAN) FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT))) {
  345. #ifdef NTFSDBG
  346. if (FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  347. if (1 == ExIsResourceAcquiredSharedLite( &Vcb->Resource )) {
  348. NtfsChangeResourceOrderState( IrpContext, NtfsResourceExVcb, FALSE, (BOOLEAN) !FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) );
  349. }
  350. }
  351. #endif
  352. return TRUE;
  353. }
  354. if (RaiseOnCantWait) {
  355. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  356. }
  357. return FALSE;
  358. }
  359. BOOLEAN
  360. NtfsAcquireSharedVcb (
  361. IN PIRP_CONTEXT IrpContext,
  362. IN PVCB Vcb,
  363. IN BOOLEAN RaiseOnCantWait
  364. )
  365. /*++
  366. Routine Description:
  367. This routine acquires shared access to the Vcb.
  368. This routine will raise if it cannot acquire the resource and wait
  369. in the IrpContext is false.
  370. Arguments:
  371. Vcb - Supplies the Vcb to acquire
  372. RaiseOnCantWait - Indicates if we should raise on an acquisition error
  373. or simply return a BOOLEAN indicating that we couldn't get the
  374. resource.
  375. N.B. -- If you pass FALSE for this parameter you ABSOLUTELY MUST
  376. test the return value. Otherwise you aren't certain that
  377. you hold the Vcb, and you don't know if it's safe to free it.
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. ASSERT_IRP_CONTEXT(IrpContext);
  383. ASSERT_VCB(Vcb);
  384. PAGED_CODE();
  385. if (ExAcquireResourceSharedLite( &Vcb->Resource, (BOOLEAN) FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT))) {
  386. #ifdef NTFSDBG
  387. if (FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  388. if (1 == ExIsResourceAcquiredSharedLite( &Vcb->Resource )) {
  389. NtfsChangeResourceOrderState( IrpContext, NtfsResourceSharedVcb, FALSE, (BOOLEAN) !FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) );
  390. }
  391. }
  392. #endif
  393. return TRUE;
  394. }
  395. if (RaiseOnCantWait) {
  396. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  397. } else {
  398. return FALSE;
  399. }
  400. }
  401. #ifdef NTFSDBG
  402. VOID
  403. NtfsReleaseVcb (
  404. IN PIRP_CONTEXT IrpContext,
  405. IN PVCB Vcb
  406. )
  407. /*++
  408. Routine Description:
  409. This routine will release the Vcb. Normally its a define for lock_order testing
  410. we use a function so we can easily change the owernship state
  411. Arguments:
  412. Vcb - Supplies the Vcb to release
  413. Return Value:
  414. None.
  415. --*/
  416. {
  417. if (FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  418. if ((ExIsResourceAcquiredExclusiveLite( &Vcb->Resource)) &&
  419. (1 == ExIsResourceAcquiredSharedLite( &Vcb->Resource ))) {
  420. NtfsChangeResourceOrderState( IrpContext, NtfsResourceExVcb, TRUE, FALSE );
  421. } else if (1 == ExIsResourceAcquiredSharedLite( &Vcb->Resource )) {
  422. NtfsChangeResourceOrderState( IrpContext, NtfsResourceSharedVcb, TRUE, FALSE );
  423. }
  424. } else {
  425. IrpContext->OwnershipState = None;
  426. }
  427. ExReleaseResourceLite( &Vcb->Resource );
  428. }
  429. #endif
  430. VOID
  431. NtfsReleaseVcbCheckDelete (
  432. IN PIRP_CONTEXT IrpContext,
  433. IN PVCB Vcb,
  434. IN UCHAR MajorCode,
  435. IN PFILE_OBJECT FileObject OPTIONAL
  436. )
  437. /*++
  438. Routine Description:
  439. This routine will release the Vcb. We will also test here whether we should
  440. teardown the Vcb at this point. If this is the last open queued to a dismounted
  441. volume or the last close from a failed mount or the failed mount then we will
  442. want to test the Vcb for a teardown.
  443. Arguments:
  444. Vcb - Supplies the Vcb to release
  445. MajorCode - Indicates what type of operation we were called from.
  446. FileObject - Optionally supplies the file object whose VPB pointer we need to
  447. zero out
  448. Return Value:
  449. None.
  450. --*/
  451. {
  452. BOOLEAN ReleaseVcb = TRUE;
  453. ASSERT_IRP_CONTEXT(IrpContext);
  454. ASSERT_VCB(Vcb);
  455. if (FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) &&
  456. (Vcb->CloseCount == 0)) {
  457. ULONG ReferenceCount;
  458. ULONG ResidualCount;
  459. KIRQL SavedIrql;
  460. BOOLEAN DeleteVcb = FALSE;
  461. ASSERT_EXCLUSIVE_RESOURCE( &Vcb->Resource );
  462. //
  463. // The volume has gone through dismount. Now we need to decide if this
  464. // release of the Vcb is the last reference for this volume. If so we
  465. // can tear the volume down.
  466. //
  467. // We compare the reference count in the Vpb with the state of the volume
  468. // and the type of operation. We also need to check if there is a
  469. // referenced log file object.
  470. //
  471. // If the temp vpb flag isn't set then we already let the iosubsys
  472. // delete it during dismount
  473. //
  474. if (FlagOn( Vcb->VcbState, VCB_STATE_TEMP_VPB )) {
  475. IoAcquireVpbSpinLock( &SavedIrql );
  476. ReferenceCount = Vcb->Vpb->ReferenceCount;
  477. IoReleaseVpbSpinLock( SavedIrql );
  478. } else {
  479. ReferenceCount = 0;
  480. }
  481. ResidualCount = 0;
  482. if ((Vcb->LogFileObject != NULL) &&
  483. !FlagOn( Vcb->CheckpointFlags, VCB_DEREFERENCED_LOG_FILE )) {
  484. ResidualCount = 1;
  485. }
  486. if (MajorCode == IRP_MJ_CREATE) {
  487. ResidualCount += 1;
  488. }
  489. //
  490. // If the residual count is the same as the count in the Vpb then we
  491. // can delete the Vpb.
  492. //
  493. if ((ResidualCount == ReferenceCount) &&
  494. !FlagOn( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY )) {
  495. SetFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY );
  496. //
  497. // Release the vcb before we grab the global
  498. //
  499. #ifdef NTFSDBG
  500. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  501. if (1 == ExIsResourceAcquiredExclusiveLite( &Vcb->Resource) ) {
  502. NtfsChangeResourceOrderState( IrpContext, NtfsResourceExVcb, TRUE, FALSE );
  503. }
  504. }
  505. #endif
  506. ExReleaseResourceLite( &Vcb->Resource );
  507. ReleaseVcb = FALSE;
  508. //
  509. // Never delete the Vcb unless this is the last release of
  510. // this Vcb.
  511. //
  512. if (ExIsResourceAcquiredSharedLite( &Vcb->Resource ) == 0) {
  513. if (ARGUMENT_PRESENT(FileObject)) { FileObject->Vpb = NULL; }
  514. //
  515. // If this is a create then the IO system will handle the
  516. // Vpb.
  517. //
  518. if (MajorCode == IRP_MJ_CREATE) {
  519. ClearFlag( Vcb->VcbState, VCB_STATE_TEMP_VPB );
  520. }
  521. //
  522. // Use the global resource to synchronize the DeleteVcb process.
  523. //
  524. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  525. RemoveEntryList( &Vcb->VcbLinks );
  526. NtfsReleaseGlobal( IrpContext );
  527. //
  528. // Try to delete the Vcb, reinsert into the queue if
  529. // the delete is blocked.
  530. //
  531. if (!NtfsDeleteVcb( IrpContext, &Vcb )) {
  532. ClearFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY );
  533. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  534. InsertHeadList( &NtfsData.VcbQueue, &Vcb->VcbLinks );
  535. NtfsReleaseGlobal( IrpContext );
  536. }
  537. } else {
  538. //
  539. // From test above we must still own the vcb so its safe to change the flag
  540. //
  541. ClearFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY );
  542. }
  543. }
  544. }
  545. if (ReleaseVcb) {
  546. #ifdef NTFSDBG
  547. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  548. if (1 == ExIsResourceAcquiredExclusiveLite( &Vcb->Resource) ) {
  549. NtfsChangeResourceOrderState( IrpContext, NtfsResourceExVcb, TRUE, FALSE );
  550. }
  551. }
  552. #endif
  553. ExReleaseResourceLite( &Vcb->Resource );
  554. }
  555. }
  556. BOOLEAN
  557. NtfsAcquireFcbWithPaging (
  558. IN PIRP_CONTEXT IrpContext,
  559. IN PFCB Fcb,
  560. IN ULONG AcquireFlags
  561. )
  562. /*++
  563. Routine Description:
  564. This routine is used in the create path, fsctl path and close path . It acquires the Fcb
  565. and also the paging IO resource if it exists but only if the irpcontext flag is set.
  566. i.e during a create supersede/overwrite operation.
  567. This routine will raise if it cannot acquire the resource and wait
  568. in the IrpContext is false.
  569. Arguments:
  570. Fcb - Supplies the Fcb to acquire
  571. AcquireFlags - ACQUIRE_DONT_WAIT overrides the wait value in the IrpContext.
  572. We won't wait for the resource and return whether the resource
  573. was acquired.
  574. Return Value:
  575. BOOLEAN - TRUE if acquired. FALSE otherwise.
  576. --*/
  577. {
  578. BOOLEAN Status = FALSE;
  579. BOOLEAN Wait = FALSE;
  580. BOOLEAN PagingIoAcquired = FALSE;
  581. ASSERT_IRP_CONTEXT(IrpContext);
  582. ASSERT_FCB(Fcb);
  583. PAGED_CODE();
  584. //
  585. // Sanity check that this is create. The supersede flag is only
  586. // set in the create path and only tested here.
  587. //
  588. ASSERT( IrpContext->MajorFunction == IRP_MJ_CREATE ||
  589. IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
  590. IrpContext->MajorFunction == IRP_MJ_CLOSE ||
  591. IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION ||
  592. IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION ||
  593. IrpContext->MajorFunction == IRP_MJ_SET_EA );
  594. if (!FlagOn( AcquireFlags, ACQUIRE_DONT_WAIT ) && FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  595. Wait = TRUE;
  596. }
  597. //
  598. // Free any exclusive paging I/O resource, we currently have, which
  599. // must presumably be from a directory with a paging I/O resource.
  600. //
  601. // We defer releasing the paging io resource when we have logged
  602. // changes against a stream. The only transaction that should be
  603. // underway at this point is the create file case where we allocated
  604. // a file record. In this case it is OK to release the paging io
  605. // resource for the parent.
  606. //
  607. if (IrpContext->CleanupStructure != NULL) {
  608. ASSERT( IrpContext->CleanupStructure != Fcb );
  609. // ASSERT(IrpContext->TransactionId == 0);
  610. NtfsReleasePagingIo( IrpContext, IrpContext->CleanupStructure );
  611. }
  612. //
  613. // Loop until we get it right - worst case is twice through loop.
  614. //
  615. while (TRUE) {
  616. //
  617. // Acquire Paging I/O first. Testing for the PagingIoResource
  618. // is not really safe without holding the main resource, so we
  619. // correct for that below.
  620. //
  621. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) &&
  622. (Fcb->PagingIoResource != NULL)) {
  623. if (!ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, Wait )) {
  624. break;
  625. }
  626. IrpContext->CleanupStructure = Fcb;
  627. PagingIoAcquired = TRUE;
  628. }
  629. //
  630. // Let's acquire this Fcb exclusively.
  631. //
  632. if (!NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK | AcquireFlags )) {
  633. if (PagingIoAcquired) {
  634. ASSERT(IrpContext->TransactionId == 0);
  635. NtfsReleasePagingIo( IrpContext, Fcb );
  636. }
  637. break;
  638. }
  639. //
  640. // If we now do not see a paging I/O resource we are golden,
  641. // othewise we can absolutely release and acquire the resources
  642. // safely in the right order, since a resource in the Fcb is
  643. // not going to go away.
  644. //
  645. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) ||
  646. PagingIoAcquired ||
  647. (Fcb->PagingIoResource == NULL)) {
  648. Status = TRUE;
  649. break;
  650. }
  651. NtfsReleaseFcb( IrpContext, Fcb );
  652. }
  653. return Status;
  654. }
  655. VOID
  656. NtfsReleaseFcbWithPaging (
  657. IN PIRP_CONTEXT IrpContext,
  658. IN PFCB Fcb
  659. )
  660. /*++
  661. Routine Description:
  662. This routine releases access to the Fcb, including its
  663. paging I/O resource if it exists.
  664. Arguments:
  665. Fcb - Supplies the Fcb to acquire
  666. Return Value:
  667. None.
  668. --*/
  669. {
  670. ASSERT_IRP_CONTEXT(IrpContext);
  671. ASSERT_FCB(Fcb);
  672. PAGED_CODE();
  673. //
  674. // We test that we currently hold the paging Io exclusive before releasing
  675. // it. Checking the ExclusivePagingFcb in the IrpContext tells us if
  676. // it is ours.
  677. //
  678. if ((IrpContext->TransactionId == 0) &&
  679. (IrpContext->CleanupStructure == Fcb)) {
  680. NtfsReleasePagingIo( IrpContext, Fcb );
  681. }
  682. NtfsReleaseFcb( IrpContext, Fcb );
  683. }
  684. VOID
  685. NtfsReleaseScbWithPaging (
  686. IN PIRP_CONTEXT IrpContext,
  687. IN PSCB Scb
  688. )
  689. /*++
  690. Routine Description:
  691. This routine releases access to the Scb, including its
  692. paging I/O resource if it exists.
  693. Arguments:
  694. Scb - Supplies the Fcb to acquire
  695. Return Value:
  696. None.
  697. --*/
  698. {
  699. PFCB Fcb = Scb->Fcb;
  700. ASSERT_IRP_CONTEXT(IrpContext);
  701. ASSERT_SCB(Scb);
  702. PAGED_CODE();
  703. //
  704. // Release the paging Io resource in the Scb under the following
  705. // conditions.
  706. //
  707. // - No transaction underway
  708. // - This paging Io resource is in the IrpContext
  709. // (This last test insures there is a paging IO resource
  710. // and we own it).
  711. //
  712. if ((IrpContext->TransactionId == 0) &&
  713. (IrpContext->CleanupStructure == Fcb)) {
  714. NtfsReleasePagingIo( IrpContext, Fcb );
  715. }
  716. NtfsReleaseScb( IrpContext, Scb );
  717. }
  718. BOOLEAN
  719. NtfsAcquireExclusiveFcb (
  720. IN PIRP_CONTEXT IrpContext,
  721. IN PFCB Fcb,
  722. IN PSCB Scb OPTIONAL,
  723. IN ULONG AcquireFlags
  724. )
  725. /*++
  726. Routine Description:
  727. This routine acquires exclusive access to the Fcb.
  728. This routine will raise if it cannot acquire the resource and wait
  729. in the IrpContext is false.
  730. Arguments:
  731. Fcb - Supplies the Fcb to acquire
  732. Scb - This is the Scb for which we are acquiring the Fcb
  733. AcquireFlags - Indicating whether to override the wait value in the IrpContext. Also whether
  734. to noop the check for a deleted file.
  735. Return Value:
  736. BOOLEAN - TRUE if acquired. FALSE otherwise.
  737. --*/
  738. {
  739. NTSTATUS Status;
  740. BOOLEAN Wait;
  741. ASSERT_IRP_CONTEXT(IrpContext);
  742. ASSERT_FCB(Fcb);
  743. PAGED_CODE();
  744. Status = STATUS_CANT_WAIT;
  745. if (FlagOn( AcquireFlags, ACQUIRE_DONT_WAIT )) {
  746. Wait = FALSE;
  747. } else if (FlagOn( AcquireFlags, ACQUIRE_WAIT )) {
  748. Wait = TRUE;
  749. } else {
  750. Wait = BooleanFlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  751. }
  752. if (NtfsAcquireResourceExclusive( IrpContext, Fcb, Wait )) {
  753. //
  754. // The link count should be non-zero or the file has been
  755. // deleted. We allow deleted files to be acquired for close and
  756. // also allow them to be acquired recursively in case we
  757. // acquire them a second time after marking them deleted (i.e. rename)
  758. //
  759. if (FlagOn( AcquireFlags, ACQUIRE_NO_DELETE_CHECK )
  760. ||
  761. (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED )
  762. && (!ARGUMENT_PRESENT( Scb )
  763. || !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))
  764. ||
  765. (IrpContext->MajorFunction == IRP_MJ_CLOSE)
  766. ||
  767. (IrpContext->MajorFunction == IRP_MJ_CREATE)
  768. ||
  769. (IrpContext->MajorFunction == IRP_MJ_CLEANUP)) {
  770. //
  771. // Put Fcb in the exclusive Fcb list for this IrpContext,
  772. // excluding the bitmap for the volume, since we do not need
  773. // to modify its file record and do not want unnecessary
  774. // serialization/deadlock problems.
  775. //
  776. // If we are growing the volume bitmap then we do want to put
  777. // it on the list and maintain the BaseExclusiveCount. Also
  778. // need to do this in the case where we see the volume bitmap
  779. // during close (it can happen during restart if we have log
  780. // records for the volume bitmap).
  781. //
  782. //
  783. // If Fcb already acquired then bump the count.
  784. //
  785. if (Fcb->ExclusiveFcbLinks.Flink != NULL) {
  786. Fcb->BaseExclusiveCount += 1;
  787. //
  788. // The fcb is not currently on an exclusive list.
  789. // Put it on a list if this is not the volume
  790. // bitmap or we explicitly want to put the volume
  791. // bitmap on the list.
  792. //
  793. } else if (FlagOn( AcquireFlags, ACQUIRE_HOLD_BITMAP ) ||
  794. (Fcb->Vcb->BitmapScb == NULL) ||
  795. (Fcb->Vcb->BitmapScb->Fcb != Fcb)) {
  796. ASSERT( Fcb->BaseExclusiveCount == 0 );
  797. InsertHeadList( &IrpContext->ExclusiveFcbList,
  798. &Fcb->ExclusiveFcbLinks );
  799. Fcb->BaseExclusiveCount += 1;
  800. }
  801. return TRUE;
  802. }
  803. //
  804. // We need to release the Fcb and remember the status code.
  805. //
  806. NtfsReleaseResource( IrpContext, Fcb );
  807. Status = STATUS_FILE_DELETED;
  808. } else if (FlagOn( AcquireFlags, ACQUIRE_DONT_WAIT )) {
  809. return FALSE;
  810. }
  811. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  812. }
  813. VOID
  814. NtfsAcquireSharedFcb (
  815. IN PIRP_CONTEXT IrpContext,
  816. IN PFCB Fcb,
  817. IN PSCB Scb OPTIONAL,
  818. IN ULONG AcquireFlags
  819. )
  820. /*++
  821. Routine Description:
  822. This routine acquires shared access to the Fcb.
  823. This routine will raise if it cannot acquire the resource and wait
  824. in the IrpContext is false.
  825. Arguments:
  826. Fcb - Supplies the Fcb to acquire
  827. Scb - This is the Scb for which we are acquiring the Fcb
  828. AcquireFlags - Indicates if we should acquire the file even if it has been
  829. deleted.
  830. Return Value:
  831. None.
  832. --*/
  833. {
  834. NTSTATUS Status;
  835. ASSERT_IRP_CONTEXT(IrpContext);
  836. ASSERT_FCB(Fcb);
  837. Status = STATUS_CANT_WAIT;
  838. if (NtfsAcquireResourceShared( IrpContext, Fcb, (BOOLEAN) FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT))) {
  839. //
  840. // The link count should be non-zero or the file has been
  841. // deleted.
  842. //
  843. if (FlagOn( AcquireFlags, ACQUIRE_NO_DELETE_CHECK ) ||
  844. (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) &&
  845. (!ARGUMENT_PRESENT( Scb ) ||
  846. !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))) {
  847. //
  848. // It's possible that this is a recursive shared aquisition of an
  849. // Fcb we own exclusively at the top level. In that case we
  850. // need to bump the acquisition count.
  851. //
  852. if (Fcb->ExclusiveFcbLinks.Flink != NULL) {
  853. Fcb->BaseExclusiveCount += 1;
  854. }
  855. return;
  856. }
  857. //
  858. // We need to release the Fcb and remember the status code.
  859. //
  860. NtfsReleaseResource( IrpContext, Fcb );
  861. Status = STATUS_FILE_DELETED;
  862. }
  863. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  864. }
  865. BOOLEAN
  866. NtfsAcquireSharedFcbCheckWait (
  867. IN PIRP_CONTEXT IrpContext,
  868. IN PFCB Fcb,
  869. IN ULONG AcquireFlags
  870. )
  871. /*++
  872. Routine Description:
  873. This routine acquires shared access to the Fcb but checks whether to wait.
  874. Arguments:
  875. Fcb - Supplies the Fcb to acquire
  876. AcquireFlags - Indicates if we should override the wait value in the IrpContext.
  877. We won't wait for the resource and return whether the resource
  878. was acquired.
  879. Return Value:
  880. BOOLEAN - TRUE if acquired. FALSE otherwise.
  881. --*/
  882. {
  883. BOOLEAN Wait;
  884. PAGED_CODE();
  885. if (FlagOn( AcquireFlags, ACQUIRE_DONT_WAIT )) {
  886. Wait = FALSE;
  887. } else if (FlagOn( AcquireFlags, ACQUIRE_WAIT )) {
  888. Wait = TRUE;
  889. } else {
  890. Wait = BooleanFlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  891. }
  892. if (NtfsAcquireResourceShared( IrpContext, Fcb, Wait )) {
  893. //
  894. // It's possible that this is a recursive shared aquisition of an
  895. // Fcb we own exclusively at the top level. In that case we
  896. // need to bump the acquisition count.
  897. //
  898. if (Fcb->ExclusiveFcbLinks.Flink != NULL) {
  899. Fcb->BaseExclusiveCount += 1;
  900. }
  901. return TRUE;
  902. } else {
  903. return FALSE;
  904. }
  905. }
  906. VOID
  907. NtfsReleaseFcb (
  908. IN PIRP_CONTEXT IrpContext,
  909. IN PFCB Fcb
  910. )
  911. /*++
  912. Routine Description:
  913. This routine releases the specified Fcb resource. If the Fcb is acquired
  914. exclusive, and a transaction is still active, then the release is nooped
  915. in order to preserve two-phase locking. If there is no longer an active
  916. transaction, then we remove the Fcb from the Exclusive Fcb List off the
  917. IrpContext, and clear the Flink as a sign. Fcbs are released when the
  918. transaction is commited.
  919. Arguments:
  920. Fcb - Fcb to release
  921. Return Value:
  922. None.
  923. --*/
  924. {
  925. //
  926. // Check if this resource is owned exclusively and we are at the last
  927. // release for this transaction.
  928. //
  929. if (Fcb->ExclusiveFcbLinks.Flink != NULL) {
  930. if (Fcb->BaseExclusiveCount == 1) {
  931. //
  932. // If there is a transaction then noop this request.
  933. //
  934. if (IrpContext->TransactionId != 0) {
  935. return;
  936. }
  937. RemoveEntryList( &Fcb->ExclusiveFcbLinks );
  938. Fcb->ExclusiveFcbLinks.Flink = NULL;
  939. //
  940. // This is a good time to free any Scb snapshots for this Fcb.
  941. //
  942. NtfsFreeSnapshotsForFcb( IrpContext, Fcb );
  943. }
  944. Fcb->BaseExclusiveCount -= 1;
  945. }
  946. ASSERT((Fcb->ExclusiveFcbLinks.Flink == NULL && Fcb->BaseExclusiveCount == 0) ||
  947. (Fcb->ExclusiveFcbLinks.Flink != NULL && Fcb->BaseExclusiveCount != 0));
  948. NtfsReleaseResource( IrpContext, Fcb );
  949. }
  950. VOID
  951. NtfsAcquireExclusiveScb (
  952. IN PIRP_CONTEXT IrpContext,
  953. IN PSCB Scb
  954. )
  955. /*++
  956. Routine Description:
  957. This routine acquires exclusive access to the Scb.
  958. This routine will raise if it cannot acquire the resource and wait
  959. in the IrpContext is false.
  960. Arguments:
  961. Scb - Scb to acquire
  962. Return Value:
  963. None.
  964. --*/
  965. {
  966. PAGED_CODE();
  967. NtfsAcquireExclusiveFcb( IrpContext, Scb->Fcb, Scb, 0 );
  968. ASSERT( Scb->Fcb->ExclusiveFcbLinks.Flink != NULL
  969. || (Scb->Vcb->BitmapScb != NULL
  970. && Scb->Vcb->BitmapScb == Scb) );
  971. if (FlagOn(Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED)) {
  972. NtfsSnapshotScb( IrpContext, Scb );
  973. }
  974. }
  975. VOID
  976. NtfsAcquireSharedScbForTransaction (
  977. IN PIRP_CONTEXT IrpContext,
  978. IN PSCB Scb
  979. )
  980. /*++
  981. Routine Description:
  982. This routine is called to acquire an Scb shared in order to perform updates to
  983. the an Scb stream. This is used if the transaction writes to a range of the
  984. stream without changing the size or position of the data. The caller must
  985. already provide synchronization to the data itself.
  986. There is no corresponding Scb release. It will be released when the transaction commits.
  987. We will acquire the Scb exclusive if it is not yet in the open attribute table.
  988. Arguments:
  989. Scb - Scb to acquire
  990. Return Value:
  991. None.
  992. --*/
  993. {
  994. PSCB *Position;
  995. PSCB *ScbArray;
  996. ULONG Count;
  997. PAGED_CODE();
  998. //
  999. // Make sure we have a free spot in the Scb array in the IrpContext.
  1000. //
  1001. if (IrpContext->SharedScb == NULL) {
  1002. Position = (PSCB *) &IrpContext->SharedScb;
  1003. IrpContext->SharedScbSize = 1;
  1004. //
  1005. // Too bad the first one is not available. If the current size is one then allocate a
  1006. // new block and copy the existing value to it.
  1007. //
  1008. } else if (IrpContext->SharedScbSize == 1) {
  1009. ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * 4 );
  1010. RtlZeroMemory( ScbArray, sizeof( PSCB ) * 4 );
  1011. *ScbArray = IrpContext->SharedScb;
  1012. IrpContext->SharedScb = ScbArray;
  1013. IrpContext->SharedScbSize = 4;
  1014. Position = ScbArray + 1;
  1015. //
  1016. // Otherwise look through the existing array and look for a free spot. Allocate a larger
  1017. // array if we need to grow it.
  1018. //
  1019. } else {
  1020. Position = IrpContext->SharedScb;
  1021. Count = IrpContext->SharedScbSize;
  1022. do {
  1023. if (*Position == NULL) {
  1024. break;
  1025. }
  1026. Count -= 1;
  1027. Position += 1;
  1028. } while (Count != 0);
  1029. //
  1030. // If we didn't find one then allocate a new structure.
  1031. //
  1032. if (Count == 0) {
  1033. ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 );
  1034. RtlZeroMemory( ScbArray, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 );
  1035. RtlCopyMemory( ScbArray,
  1036. IrpContext->SharedScb,
  1037. sizeof( PSCB ) * IrpContext->SharedScbSize );
  1038. NtfsFreePool( IrpContext->SharedScb );
  1039. IrpContext->SharedScb = ScbArray;
  1040. Position = ScbArray + IrpContext->SharedScbSize;
  1041. IrpContext->SharedScbSize *= 2;
  1042. }
  1043. }
  1044. NtfsAcquireResourceShared( IrpContext, Scb, TRUE );
  1045. if (Scb->NonpagedScb->OpenAttributeTableIndex == 0) {
  1046. NtfsReleaseResource( IrpContext, Scb );
  1047. NtfsAcquireResourceExclusive( IrpContext, Scb, TRUE );
  1048. }
  1049. *Position = Scb;
  1050. return;
  1051. }
  1052. VOID
  1053. NtfsReleaseSharedResources (
  1054. IN PIRP_CONTEXT IrpContext
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. The routine releases all of the resources acquired shared for
  1059. transaction. The SharedScb structure is freed if necessary and
  1060. the Irp Context field is cleared.
  1061. Arguments:
  1062. Return Value:
  1063. None.
  1064. --*/
  1065. {
  1066. PAGED_CODE();
  1067. //
  1068. // If only one then free the Scb main resource.
  1069. //
  1070. if (IrpContext->SharedScbSize == 1) {
  1071. if (SafeNodeType(IrpContext->SharedScb) == NTFS_NTC_QUOTA_CONTROL) {
  1072. NtfsReleaseQuotaControl( IrpContext,
  1073. (PQUOTA_CONTROL_BLOCK) IrpContext->SharedScb );
  1074. } else {
  1075. NtfsReleaseResource( IrpContext, ((PSCB) IrpContext->SharedScb) );
  1076. }
  1077. //
  1078. // Otherwise traverse the array and look for Scb's to release.
  1079. //
  1080. } else {
  1081. PSCB *NextScb;
  1082. ULONG Count;
  1083. NextScb = IrpContext->SharedScb;
  1084. Count = IrpContext->SharedScbSize;
  1085. do {
  1086. if (*NextScb != NULL) {
  1087. if (SafeNodeType(*NextScb) == NTFS_NTC_QUOTA_CONTROL) {
  1088. NtfsReleaseQuotaControl( IrpContext,
  1089. (PQUOTA_CONTROL_BLOCK) *NextScb );
  1090. } else {
  1091. NtfsReleaseResource( IrpContext, (*NextScb) );
  1092. }
  1093. *NextScb = NULL;
  1094. }
  1095. Count -= 1;
  1096. NextScb += 1;
  1097. } while (Count != 0);
  1098. NtfsFreePool( IrpContext->SharedScb );
  1099. }
  1100. IrpContext->SharedScb = NULL;
  1101. IrpContext->SharedScbSize = 0;
  1102. }
  1103. VOID
  1104. NtfsReleaseAllResources (
  1105. IN PIRP_CONTEXT IrpContext
  1106. )
  1107. /*++
  1108. Routine Description:
  1109. This routine release all resources tracked in the irpcontext including
  1110. exclusive fcb, paging / locked headers in the cleanup structure / cached file records
  1111. shared resources / quota blocks acquired for transactions
  1112. Does not release the vcb since this is hand-tracked.
  1113. Not paged since called by NtfsCleanupIrpContext which is not paged
  1114. Arguments:
  1115. Return Value:
  1116. None
  1117. --*/
  1118. {
  1119. PFCB Fcb;
  1120. //
  1121. // Release the cached file record map
  1122. //
  1123. NtfsPurgeFileRecordCache( IrpContext );
  1124. #ifdef MAPCOUNT_DBG
  1125. //
  1126. // Check all mapping are gone now that we cleaned out cache
  1127. //
  1128. ASSERT( IrpContext->MapCount == 0 );
  1129. #endif
  1130. //
  1131. // Go through and free any Scb's in the queue of shared Scb's for transactions.
  1132. //
  1133. if (IrpContext->SharedScb != NULL) {
  1134. NtfsReleaseSharedResources( IrpContext );
  1135. }
  1136. //
  1137. // Free any exclusive paging I/O resource, or IoAtEof condition,
  1138. // this field is overlayed, minimally in write.c.
  1139. //
  1140. Fcb = IrpContext->CleanupStructure;
  1141. if (Fcb != NULL) {
  1142. if (Fcb->NodeTypeCode == NTFS_NTC_FCB) {
  1143. NtfsReleasePagingIo( IrpContext, Fcb );
  1144. } else {
  1145. FsRtlUnlockFsRtlHeader( (PNTFS_ADVANCED_FCB_HEADER) Fcb );
  1146. IrpContext->CleanupStructure = NULL;
  1147. }
  1148. }
  1149. //
  1150. // Finally, now that we have written the forget record, we can free
  1151. // any exclusive Scbs that we have been holding.
  1152. //
  1153. ASSERT( IrpContext->TransactionId == 0 );
  1154. while (!IsListEmpty( &IrpContext->ExclusiveFcbList )) {
  1155. Fcb = (PFCB)CONTAINING_RECORD( IrpContext->ExclusiveFcbList.Flink,
  1156. FCB,
  1157. ExclusiveFcbLinks );
  1158. NtfsReleaseFcb( IrpContext, Fcb );
  1159. }
  1160. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_USN_JRNL |
  1161. IRP_CONTEXT_FLAG_RELEASE_MFT );
  1162. }
  1163. VOID
  1164. NtfsAcquireIndexCcb (
  1165. IN PSCB Scb,
  1166. IN PCCB Ccb,
  1167. IN PEOF_WAIT_BLOCK EofWaitBlock
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. This routine is called to serialize access to a Ccb for a directory.
  1172. We must serialize access to the index context or we will corrupt
  1173. the data structure.
  1174. Arguments:
  1175. Scb - Scb for the directory to enumerate.
  1176. Ccb - Pointer to the Ccb for the handle.
  1177. EofWaitBlock - Uninitialized structure used only to serialize Eof updates. Our
  1178. caller will put this on the stack.
  1179. Return Value:
  1180. None
  1181. --*/
  1182. {
  1183. PAGED_CODE();
  1184. //
  1185. // Acquire the mutex for serialization.
  1186. //
  1187. NtfsAcquireFsrtlHeader( Scb );
  1188. //
  1189. // Typical case is that we are the only active handle.
  1190. //
  1191. if (Ccb->EnumQueue.Flink == NULL) {
  1192. InitializeListHead( &Ccb->EnumQueue );
  1193. NtfsReleaseFsrtlHeader( Scb );
  1194. } else {
  1195. //
  1196. // Initialize our event an put ourselves on the stack.
  1197. //
  1198. KeInitializeEvent( &EofWaitBlock->Event, NotificationEvent, FALSE );
  1199. InsertTailList( &Ccb->EnumQueue, &EofWaitBlock->EofWaitLinks );
  1200. //
  1201. // Free the mutex and wait. When the wait is satisfied then we are
  1202. // the active handle.
  1203. //
  1204. NtfsReleaseFsrtlHeader( Scb );
  1205. KeWaitForSingleObject( &EofWaitBlock->Event,
  1206. Executive,
  1207. KernelMode,
  1208. FALSE,
  1209. (PLARGE_INTEGER)NULL);
  1210. }
  1211. return;
  1212. }
  1213. VOID
  1214. NtfsReleaseIndexCcb (
  1215. IN PSCB Scb,
  1216. IN PCCB Ccb
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. This routine is called to release a Ccb for other people to access.
  1221. Arguments:
  1222. Scb - Scb for the directory to enumerate.
  1223. Ccb - Pointer to the Ccb for the handle.
  1224. Return Value:
  1225. None
  1226. --*/
  1227. {
  1228. PEOF_WAIT_BLOCK EofWaitBlock;
  1229. PAGED_CODE();
  1230. //
  1231. // Acquire the header and wake the next waiter or clear the list if it
  1232. // is now empty.
  1233. //
  1234. NtfsAcquireFsrtlHeader( Scb );
  1235. ASSERT( Ccb->EnumQueue.Flink != NULL );
  1236. if (IsListEmpty( &Ccb->EnumQueue )) {
  1237. Ccb->EnumQueue.Flink = NULL;
  1238. } else {
  1239. EofWaitBlock = (PEOF_WAIT_BLOCK) RemoveHeadList( &Ccb->EnumQueue );
  1240. KeSetEvent( &EofWaitBlock->Event, 0, FALSE );
  1241. }
  1242. NtfsReleaseFsrtlHeader( Scb );
  1243. return;
  1244. }
  1245. BOOLEAN
  1246. NtfsAcquireScbForLazyWrite (
  1247. IN PVOID OpaqueScb,
  1248. IN BOOLEAN Wait
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. The address of this routine is specified when creating a CacheMap for
  1253. a file. It is subsequently called by the Lazy Writer prior to its
  1254. performing lazy writes to the file. This callback is necessary to
  1255. avoid deadlocks with the Lazy Writer. (Note that normal writes
  1256. acquire the Fcb, and then call the Cache Manager, who must acquire
  1257. some of his internal structures. If the Lazy Writer could not call
  1258. this routine first, and were to issue a write after locking Caching
  1259. data structures, then a deadlock could occur.)
  1260. Arguments:
  1261. OpaqueScb - The Scb which was specified as a context parameter for this
  1262. routine.
  1263. Wait - TRUE if the caller is willing to block.
  1264. Return Value:
  1265. FALSE - if Wait was specified as FALSE and blocking would have
  1266. been required. The Fcb is not acquired.
  1267. TRUE - if the Scb has been acquired
  1268. --*/
  1269. {
  1270. BOOLEAN AcquiredFile = FALSE;
  1271. ULONG CompressedStream = (ULONG)((ULONG_PTR)OpaqueScb & 1);
  1272. PSCB Scb = (PSCB)((ULONG_PTR)OpaqueScb & ~1);
  1273. PFCB Fcb = Scb->Fcb;
  1274. ASSERT_SCB(Scb);
  1275. PAGED_CODE();
  1276. //
  1277. // Acquire the Scb only for those files that the write will
  1278. // acquire it for, i.e., not the first set of system files.
  1279. // Otherwise we can deadlock, for example with someone needing
  1280. // a new Mft record.
  1281. //
  1282. if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) {
  1283. //
  1284. // We need to synchronize the lazy writer with the clean volume
  1285. // checkpoint. We do this by acquiring and immediately releasing this
  1286. // Scb. This is to prevent the lazy writer from flushing the log file
  1287. // when the space may be at a premium.
  1288. //
  1289. if (NtfsAcquireResourceShared( NULL, Scb, Wait )) {
  1290. if (ExAcquireResourceSharedLite( &Scb->Vcb->MftFlushResource, Wait )) {
  1291. //
  1292. // The mft bitmap will reacquire the mft resource in LookupAllocation
  1293. // if its not loaded during a write - this would deadlock with allocating
  1294. // a mft record. bcb exclusive - mft main vs mft main - bcb shared
  1295. //
  1296. ASSERT( (Scb != Scb->Vcb->MftBitmapScb) ||
  1297. ((Scb->Mcb.NtfsMcbArraySizeInUse > 0) &&
  1298. ((Scb->Mcb.NtfsMcbArray[ Scb->Mcb.NtfsMcbArraySizeInUse - 1].EndingVcn + 1) ==
  1299. LlClustersFromBytes( Scb->Vcb, Scb->Header.AllocationSize.QuadPart ))) );
  1300. AcquiredFile = TRUE;
  1301. }
  1302. NtfsReleaseResource( NULL, Scb );
  1303. }
  1304. //
  1305. // Now acquire either the main or paging io resource depending on the
  1306. // state of the file.
  1307. //
  1308. } else if (Scb->Header.PagingIoResource != NULL) {
  1309. AcquiredFile = ExAcquireResourceSharedLite( Scb->Header.PagingIoResource, Wait );
  1310. } else {
  1311. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT | SCB_STATE_CONVERT_UNDERWAY )) {
  1312. AcquiredFile = NtfsAcquireResourceExclusive( NULL, Scb, Wait );
  1313. } else {
  1314. AcquiredFile = NtfsAcquireResourceShared( NULL, Scb, Wait );
  1315. }
  1316. }
  1317. if (AcquiredFile) {
  1318. //
  1319. // We assume the Lazy Writer only acquires this Scb once. When he
  1320. // has acquired it, then he has eliminated anyone who would extend
  1321. // valid data, since they must take out the resource exclusive.
  1322. // Therefore, it should be guaranteed that this flag is currently
  1323. // clear (the ASSERT), and then we will set this flag, to insure
  1324. // that the Lazy Writer will never try to advance Valid Data, and
  1325. // also not deadlock by trying to get the Fcb exclusive.
  1326. //
  1327. ASSERT( Scb->LazyWriteThread[CompressedStream] == NULL );
  1328. Scb->LazyWriteThread[CompressedStream] = PsGetCurrentThread();
  1329. //
  1330. // Make Cc top level, so that we will not post or retry on errors.
  1331. // (If it is not NULL, it must be one of our internal calls to this
  1332. // routine, such as from Restart or Hot Fix.)
  1333. //
  1334. if (IoGetTopLevelIrp() == NULL) {
  1335. IoSetTopLevelIrp( (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP );
  1336. }
  1337. }
  1338. return AcquiredFile;
  1339. }
  1340. VOID
  1341. NtfsReleaseScbFromLazyWrite (
  1342. IN PVOID OpaqueScb
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. The address of this routine is specified when creating a CacheMap for
  1347. a file. It is subsequently called by the Lazy Writer after its
  1348. performing lazy writes to the file.
  1349. Arguments:
  1350. Scb - The Scb which was specified as a context parameter for this
  1351. routine.
  1352. Return Value:
  1353. None
  1354. --*/
  1355. {
  1356. ULONG CompressedStream = (ULONG)((ULONG_PTR)OpaqueScb & 1);
  1357. PSCB Scb = (PSCB)((ULONG_PTR)OpaqueScb & ~1);
  1358. PFCB Fcb = Scb->Fcb;
  1359. ULONG CleanCheckpoint = 0;
  1360. ASSERT_SCB(Scb);
  1361. PAGED_CODE();
  1362. //
  1363. // Clear the toplevel at this point, if we set it above.
  1364. //
  1365. if ((((ULONG_PTR) IoGetTopLevelIrp()) & ~0x80000000) == FSRTL_CACHE_TOP_LEVEL_IRP) {
  1366. //
  1367. // We use the upper bit of this field to indicate that we need to
  1368. // do a clean checkpoint.
  1369. //
  1370. CleanCheckpoint = (ULONG)FlagOn( (ULONG_PTR) IoGetTopLevelIrp(), 0x80000000 );
  1371. IoSetTopLevelIrp( NULL );
  1372. }
  1373. Scb->LazyWriteThread[CompressedStream] = NULL;
  1374. if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) {
  1375. ExReleaseResourceLite( &Scb->Vcb->MftFlushResource );
  1376. } else if (Scb->Header.PagingIoResource != NULL) {
  1377. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  1378. } else {
  1379. NtfsReleaseResource( NULL, Scb );
  1380. }
  1381. //
  1382. // Do a clean checkpoint if necessary.
  1383. //
  1384. if (CleanCheckpoint) {
  1385. NtfsCleanCheckpoint( Scb->Vcb );
  1386. }
  1387. return;
  1388. }
  1389. NTSTATUS
  1390. NtfsAcquireFileForModWrite (
  1391. IN PFILE_OBJECT FileObject,
  1392. IN PLARGE_INTEGER EndingOffset,
  1393. OUT PERESOURCE *ResourceToRelease,
  1394. IN PDEVICE_OBJECT DeviceObject
  1395. )
  1396. {
  1397. BOOLEAN AcquiredFile = FALSE;
  1398. PSCB Scb = (PSCB) (FileObject->FsContext);
  1399. PFCB Fcb = Scb->Fcb;
  1400. ASSERT_SCB( Scb );
  1401. UNREFERENCED_PARAMETER( DeviceObject );
  1402. PAGED_CODE();
  1403. //
  1404. // All files should not be mod-no-write and have paging resource
  1405. //
  1406. ASSERT( NtfsSegmentNumber( &Fcb->FileReference ) >= MASTER_FILE_TABLE2_NUMBER );
  1407. ASSERT( Scb->Header.PagingIoResource != NULL );
  1408. AcquiredFile = NtfsAcquirePagingResourceSharedWaitForExclusive( NULL, Scb, FALSE );
  1409. //
  1410. // If we got the resource, check if he is possibly trying to extend
  1411. // ValidDataLength. If so that will cause us to go into useless mode
  1412. // possibly doing actual I/O writing zeros out to the file past actual
  1413. // valid data in the cache. This is so inefficient that it is better
  1414. // to tell MM not to do this write.
  1415. //
  1416. if (AcquiredFile) {
  1417. *ResourceToRelease = Scb->Fcb->PagingIoResource;
  1418. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  1419. NtfsAcquireFsrtlHeader( Scb );
  1420. if ((EndingOffset->QuadPart > Scb->ValidDataToDisk) &&
  1421. (EndingOffset->QuadPart < Scb->Header.FileSize.QuadPart) &&
  1422. !FlagOn(Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE)) {
  1423. ExReleaseResourceLite( *ResourceToRelease );
  1424. AcquiredFile = FALSE;
  1425. *ResourceToRelease = NULL;
  1426. }
  1427. NtfsReleaseFsrtlHeader( Scb );
  1428. }
  1429. } else {
  1430. *ResourceToRelease = NULL;
  1431. }
  1432. return (AcquiredFile ? STATUS_SUCCESS : STATUS_CANT_WAIT);
  1433. }
  1434. NTSTATUS
  1435. NtfsAcquireFileForCcFlush (
  1436. IN PFILE_OBJECT FileObject,
  1437. IN PDEVICE_OBJECT DeviceObject
  1438. )
  1439. {
  1440. PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;
  1441. PAGED_CODE();
  1442. if (Header->PagingIoResource != NULL) {
  1443. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  1444. }
  1445. return STATUS_SUCCESS;
  1446. UNREFERENCED_PARAMETER( DeviceObject );
  1447. }
  1448. NTSTATUS
  1449. NtfsReleaseFileForCcFlush (
  1450. IN PFILE_OBJECT FileObject,
  1451. IN PDEVICE_OBJECT DeviceObject
  1452. )
  1453. {
  1454. PSCB Scb = (PSCB) FileObject->FsContext;
  1455. BOOLEAN CleanCheckpoint = FALSE;
  1456. PAGED_CODE();
  1457. if (Scb->Header.PagingIoResource != NULL) {
  1458. //
  1459. // If we are getting repeated log file fulls then we want to process that before retrying
  1460. // this request. This will prevent a section flush from failing and returning
  1461. // STATUS_FILE_LOCK_CONFLICT to the user.
  1462. //
  1463. if (Scb->Vcb->CleanCheckpointMark + 3 < Scb->Vcb->LogFileFullCount) {
  1464. CleanCheckpoint = TRUE;
  1465. }
  1466. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  1467. //
  1468. // We may be be in a recursive acquisition callback in that case even
  1469. // after releasing the resource we may still own it and be unable to
  1470. // checkpoint
  1471. //
  1472. if (CleanCheckpoint &&
  1473. (IoGetTopLevelIrp() == NULL) &&
  1474. !NtfsIsExclusiveScbPagingIo( Scb )) {
  1475. NtfsCleanCheckpoint( Scb->Vcb );
  1476. }
  1477. }
  1478. return STATUS_SUCCESS;
  1479. UNREFERENCED_PARAMETER( DeviceObject );
  1480. }
  1481. VOID
  1482. NtfsAcquireForCreateSection (
  1483. IN PFILE_OBJECT FileObject
  1484. )
  1485. {
  1486. PSCB Scb = (PSCB)FileObject->FsContext;
  1487. PAGED_CODE();
  1488. if (Scb->Header.PagingIoResource != NULL) {
  1489. //
  1490. // Use an unsafe test to see if a dummy checkpoint has been posted.
  1491. // We can use an unsafe test, since the top level caller must retry
  1492. // if a STATUS_FILE_LOCK_CONFLICT is returned.
  1493. //
  1494. if (FlagOn( Scb->Vcb->CheckpointFlags, VCB_DUMMY_CHECKPOINT_POSTED )) {
  1495. NtfsCleanCheckpoint( Scb->Vcb );
  1496. }
  1497. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  1498. }
  1499. }
  1500. VOID
  1501. NtfsReleaseForCreateSection (
  1502. IN PFILE_OBJECT FileObject
  1503. )
  1504. {
  1505. PSCB Scb = (PSCB)FileObject->FsContext;
  1506. PAGED_CODE();
  1507. if (Scb->Header.PagingIoResource != NULL) {
  1508. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  1509. }
  1510. }
  1511. BOOLEAN
  1512. NtfsAcquireScbForReadAhead (
  1513. IN PVOID OpaqueScb,
  1514. IN BOOLEAN Wait
  1515. )
  1516. /*++
  1517. Routine Description:
  1518. The address of this routine is specified when creating a CacheMap for
  1519. a file. It is subsequently called by the Lazy Writer prior to its
  1520. performing read ahead to the file.
  1521. Arguments:
  1522. Scb - The Scb which was specified as a context parameter for this
  1523. routine.
  1524. Wait - TRUE if the caller is willing to block.
  1525. Return Value:
  1526. FALSE - if Wait was specified as FALSE and blocking would have
  1527. been required. The Fcb is not acquired.
  1528. TRUE - if the Scb has been acquired
  1529. --*/
  1530. {
  1531. PREAD_AHEAD_THREAD ReadAheadThread;
  1532. PVOID CurrentThread;
  1533. KIRQL OldIrql;
  1534. PSCB Scb = (PSCB)OpaqueScb;
  1535. PFCB Fcb = Scb->Fcb;
  1536. BOOLEAN AcquiredFile = FALSE;
  1537. ASSERT_SCB(Scb);
  1538. //
  1539. // Acquire the Scb only for those files that the read wil
  1540. // acquire it for, i.e., not the first set of system files.
  1541. // Otherwise we can deadlock, for example with someone needing
  1542. // a new Mft record.
  1543. //
  1544. if ((Scb->Header.PagingIoResource == NULL) ||
  1545. ExAcquireResourceSharedLite( Scb->Header.PagingIoResource, Wait )) {
  1546. AcquiredFile = TRUE;
  1547. //
  1548. // Add our thread to the read ahead list.
  1549. //
  1550. OldIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  1551. CurrentThread = (PVOID)PsGetCurrentThread();
  1552. ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink;
  1553. while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) &&
  1554. (ReadAheadThread->Thread != NULL)) {
  1555. //
  1556. // We better not already see ourselves.
  1557. //
  1558. ASSERT( ReadAheadThread->Thread != CurrentThread );
  1559. ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink;
  1560. }
  1561. //
  1562. // If we hit the end of the list, then allocate a new one. Note we
  1563. // should have at most one entry per critical worker thread in the
  1564. // system.
  1565. //
  1566. if (ReadAheadThread == (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) {
  1567. ReadAheadThread = NtfsAllocatePoolWithTagNoRaise( NonPagedPool, sizeof(READ_AHEAD_THREAD), 'RftN' );
  1568. //
  1569. // If we failed to allocate an entry, clean up and raise.
  1570. //
  1571. if (ReadAheadThread == NULL) {
  1572. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, OldIrql );
  1573. if (NtfsSegmentNumber( &Fcb->FileReference ) > VOLUME_DASD_NUMBER) {
  1574. if (Scb->Header.PagingIoResource != NULL) {
  1575. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  1576. }
  1577. }
  1578. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1579. }
  1580. InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links );
  1581. }
  1582. ReadAheadThread->Thread = CurrentThread;
  1583. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, OldIrql );
  1584. }
  1585. return AcquiredFile;
  1586. }
  1587. VOID
  1588. NtfsReleaseScbFromReadAhead (
  1589. IN PVOID OpaqueScb
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. The address of this routine is specified when creating a CacheMap for
  1594. a file. It is subsequently called by the Lazy Writer after its
  1595. read ahead.
  1596. Arguments:
  1597. Scb - The Scb which was specified as a context parameter for this
  1598. routine.
  1599. Return Value:
  1600. None
  1601. --*/
  1602. {
  1603. PREAD_AHEAD_THREAD ReadAheadThread;
  1604. PVOID CurrentThread;
  1605. KIRQL OldIrql;
  1606. PSCB Scb = (PSCB)OpaqueScb;
  1607. PFCB Fcb = Scb->Fcb;
  1608. ASSERT_SCB(Scb);
  1609. //
  1610. // Free our read ahead entry.
  1611. //
  1612. OldIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  1613. CurrentThread = (PVOID)PsGetCurrentThread();
  1614. ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink;
  1615. while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) &&
  1616. (ReadAheadThread->Thread != CurrentThread)) {
  1617. ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink;
  1618. }
  1619. ASSERT(ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads);
  1620. ReadAheadThread->Thread = NULL;
  1621. //
  1622. // Move him to the end of the list so all the allocated entries are at
  1623. // the front, and we simplify our scans.
  1624. //
  1625. RemoveEntryList( &ReadAheadThread->Links );
  1626. InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links );
  1627. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, OldIrql );
  1628. if (Scb->Header.PagingIoResource != NULL) {
  1629. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  1630. }
  1631. return;
  1632. }
  1633. BOOLEAN
  1634. NtfsAcquireVolumeFileForLazyWrite (
  1635. IN PVOID Vcb,
  1636. IN BOOLEAN Wait
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. The address of this routine is specified when creating a CacheMap for
  1641. the volume file. It is subsequently called by the Lazy Writer prior to its
  1642. performing lazy writes to the volume file. This callback may one day be
  1643. necessary to avoid deadlocks with the Lazy Writer, however, now
  1644. NtfsCommonWrite does not need to acquire any resource for the volume file,
  1645. so this routine is simply a noop.
  1646. Arguments:
  1647. Vcb - The Vcb which was specified as a context parameter for this
  1648. routine.
  1649. Wait - TRUE if the caller is willing to block.
  1650. Return Value:
  1651. TRUE
  1652. --*/
  1653. {
  1654. UNREFERENCED_PARAMETER( Vcb );
  1655. UNREFERENCED_PARAMETER( Wait );
  1656. PAGED_CODE();
  1657. return TRUE;
  1658. }
  1659. VOID
  1660. NtfsReleaseVolumeFileFromLazyWrite (
  1661. IN PVOID Vcb
  1662. )
  1663. /*++
  1664. Routine Description:
  1665. The address of this routine is specified when creating a CacheMap for
  1666. a file. It is subsequently called by the Lazy Writer after its
  1667. performing lazy writes to the file.
  1668. Arguments:
  1669. Vcb - The Vcb which was specified as a context parameter for this
  1670. routine.
  1671. Return Value:
  1672. None
  1673. --*/
  1674. {
  1675. UNREFERENCED_PARAMETER( Vcb );
  1676. PAGED_CODE();
  1677. return;
  1678. }
  1679. NTFS_RESOURCE_NAME
  1680. NtfsIdentifyFcb (
  1681. IN PVCB Vcb,
  1682. IN PFCB Fcb
  1683. )
  1684. /*++
  1685. Routine Description:
  1686. Identifies the resource type of a given FCB. I.e is it the mft. Used for
  1687. lock order identification.
  1688. Arguments:
  1689. Vcb - The vcb for the volume
  1690. Fcb - The fcb to identify
  1691. Return Value:
  1692. TRUE
  1693. --*/
  1694. {
  1695. if ((NtfsSegmentNumber( &Fcb->FileReference ) == MASTER_FILE_TABLE_NUMBER)) {
  1696. return NtfsResourceMft;
  1697. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == MASTER_FILE_TABLE2_NUMBER)) {
  1698. return NtfsResourceMft2;
  1699. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == VOLUME_DASD_NUMBER)) {
  1700. return NtfsResourceVolume;
  1701. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == LOG_FILE_NUMBER)) {
  1702. return NtfsResourceLogFile;
  1703. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == BAD_CLUSTER_FILE_NUMBER)) {
  1704. return NtfsResourceBadClust;
  1705. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == SECURITY_FILE_NUMBER)) {
  1706. return NtfsResourceSecure;
  1707. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == ROOT_FILE_NAME_INDEX_NUMBER)) {
  1708. return NtfsResourceRootDir;
  1709. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == BIT_MAP_FILE_NUMBER)) {
  1710. return NtfsResourceBitmap;
  1711. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == BOOT_FILE_NUMBER)) {
  1712. return NtfsResourceBoot;
  1713. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == EXTEND_NUMBER)) {
  1714. return NtfsResourceExtendDir;
  1715. } else if ((Vcb->UsnJournal && (Fcb == Vcb->UsnJournal->Fcb)) ||
  1716. FlagOn( Fcb->FcbState, FCB_STATE_USN_JOURNAL)) {
  1717. return NtfsResourceUsnJournal;
  1718. } else if (Vcb->QuotaTableScb && (Fcb == Vcb->QuotaTableScb->Fcb)) {
  1719. return NtfsResourceQuotaTable;
  1720. } else if (Vcb->ObjectIdTableScb && (Fcb == Vcb->ObjectIdTableScb->Fcb)) {
  1721. return NtfsResourceObjectIdTable;
  1722. } else if (Vcb->ReparsePointTableScb && (Fcb == Vcb->ReparsePointTableScb->Fcb)) {
  1723. return NtfsResourceReparseTable;
  1724. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) == UPCASE_TABLE_NUMBER)) {
  1725. return NtfsResourceUpCase;
  1726. } else if (Vcb->AttributeDefTableScb && (Fcb == Vcb->AttributeDefTableScb->Fcb)) {
  1727. return NtfsResourceAttrDefTable;
  1728. } else {
  1729. return NtfsResourceFile;
  1730. }
  1731. }
  1732. #ifdef NTFSDBG
  1733. BOOLEAN
  1734. NtfsChangeResourceOrderState(
  1735. IN PIRP_CONTEXT IrpContext,
  1736. IN NTFS_RESOURCE_NAME NewResource,
  1737. IN BOOLEAN Release,
  1738. IN ULONG UnsafeTransition
  1739. )
  1740. /*++
  1741. Routine Description:
  1742. Update the state table because of the new acquired resource
  1743. Arguments:
  1744. IrpContext -- contains the state table
  1745. NewResource -- The new resource acquired
  1746. Return Value:
  1747. TRUE if this is a valid transition
  1748. --*/
  1749. {
  1750. PTOP_LEVEL_CONTEXT TopLevelContext;
  1751. PIRP_CONTEXT TopIrpContext = IrpContext;
  1752. ULONG_PTR StackBottom;
  1753. ULONG_PTR StackTop;
  1754. LONG Index;
  1755. LONG NumTransitions = sizeof( OwnershipTransitionTable ) / sizeof( NTFS_OWNERSHIP_TRANSITION );
  1756. //
  1757. // Work around the forced top level context of reads to find the real top level
  1758. //
  1759. IoGetStackLimits( &StackTop, &StackBottom );
  1760. TopLevelContext = NtfsGetTopLevelContext();
  1761. if ((TopLevelContext != NULL) && (TopLevelContext->SavedTopLevelIrp != NULL)) {
  1762. TopLevelContext = (PTOP_LEVEL_CONTEXT)TopLevelContext->SavedTopLevelIrp;
  1763. if (((ULONG_PTR) TopLevelContext <= StackBottom - sizeof( TOP_LEVEL_CONTEXT )) &&
  1764. ((ULONG_PTR) TopLevelContext >= StackTop) &&
  1765. !FlagOn( (ULONG_PTR) TopLevelContext, 0x3 ) &&
  1766. (TopLevelContext->Ntfs == 0x5346544e)) {
  1767. TopIrpContext = TopLevelContext->ThreadIrpContext;
  1768. }
  1769. }
  1770. TopIrpContext = TopIrpContext->TopLevelIrpContext;
  1771. //
  1772. // Skip verification on mounts
  1773. //
  1774. if ((TopIrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  1775. (TopIrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME)) {
  1776. return TRUE;
  1777. }
  1778. //
  1779. // Keep track of how many normal files we own
  1780. //
  1781. if (NtfsResourceFile == NewResource) {
  1782. if (Release) {
  1783. TopIrpContext->FilesOwnedCount -= 1;
  1784. //
  1785. // Only change state if back to 0 for files
  1786. //
  1787. if (TopIrpContext->FilesOwnedCount) {
  1788. return TRUE;
  1789. }
  1790. } else {
  1791. TopIrpContext->FilesOwnedCount += 1;
  1792. //
  1793. // Only change state if fwd to 0 for files
  1794. //
  1795. if (TopIrpContext->FilesOwnedCount > 1) {
  1796. return TRUE;
  1797. }
  1798. }
  1799. }
  1800. for (Index=0; Index < NumTransitions; Index += 1) {
  1801. if ((!Release &&
  1802. (OwnershipTransitionTable[Index].Begin == TopIrpContext->OwnershipState) &&
  1803. ((OwnershipTransitionTable[Index].Acquired == NewResource) ||
  1804. (OwnershipTransitionTable[Index].Acquired == NtfsResourceAny))) ||
  1805. ((OwnershipTransitionTable[Index].End == TopIrpContext->OwnershipState) &&
  1806. (OwnershipTransitionTable[Index].Acquired == NewResource))) {
  1807. if (Release) {
  1808. TopIrpContext->OwnershipState = OwnershipTransitionTable[Index].Begin;
  1809. } else {
  1810. TopIrpContext->OwnershipState = OwnershipTransitionTable[Index].End;
  1811. }
  1812. #ifdef NTFSDBG
  1813. if (TopIrpContext->OwnershipState == NtfsBreakOnState) {
  1814. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1815. KdPrint(( "NTFS: Breaking for matched state\n" ));
  1816. DbgBreakPoint();
  1817. }
  1818. }
  1819. if (NtfsPrintOnLockProb) {
  1820. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1821. KdPrint(( "NTFS: change context: 0x%x to 0x%x for 0x%x during 0x%x\n", TopIrpContext, TopIrpContext->OwnershipState, NewResource, Release ));
  1822. }
  1823. }
  1824. #endif
  1825. return TRUE;
  1826. }
  1827. }
  1828. //
  1829. // If an unsafe transition (not blocking) check the extra table
  1830. //
  1831. if (UnsafeTransition && !Release) {
  1832. NumTransitions = sizeof( OwnershipTransitionTableUnsafe ) / sizeof( NTFS_OWNERSHIP_TRANSITION );
  1833. for (Index=0; Index < NumTransitions; Index += 1) {
  1834. if (((OwnershipTransitionTableUnsafe[Index].Begin == TopIrpContext->OwnershipState) &&
  1835. ((OwnershipTransitionTableUnsafe[Index].Acquired == NewResource) ||
  1836. (OwnershipTransitionTableUnsafe[Index].Acquired == NtfsResourceAny)))) {
  1837. TopIrpContext->OwnershipState = OwnershipTransitionTableUnsafe[Index].End;
  1838. #ifdef NTFSDBG
  1839. if (TopIrpContext->OwnershipState == NtfsBreakOnState) {
  1840. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1841. KdPrint(( "NTFS: Breaking for matched state\n" ));
  1842. DbgBreakPoint();
  1843. }
  1844. }
  1845. if (NtfsPrintOnLockProb) {
  1846. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1847. KdPrint(( "NTFS: change context: 0x%x to 0x%x for 0x%x during 0x%x\n", TopIrpContext, TopIrpContext->OwnershipState, NewResource, Release ));
  1848. }
  1849. }
  1850. #endif
  1851. return TRUE;
  1852. }
  1853. }
  1854. }
  1855. //
  1856. // Check the one way transtions for release and acquire
  1857. //
  1858. if (Release) {
  1859. NumTransitions = sizeof( OwnershipTransitionTableRelease ) / sizeof( NTFS_OWNERSHIP_TRANSITION );
  1860. for (Index=0; Index < NumTransitions; Index += 1) {
  1861. if ((OwnershipTransitionTableRelease[Index].Begin == TopIrpContext->OwnershipState) &&
  1862. ((OwnershipTransitionTableRelease[Index].Acquired == NewResource) ||
  1863. (OwnershipTransitionTableRelease[Index].Acquired == NtfsResourceAny))) {
  1864. TopIrpContext->OwnershipState = OwnershipTransitionTableRelease[Index].End;
  1865. #ifdef NTFSDBG
  1866. if (TopIrpContext->OwnershipState == NtfsBreakOnState) {
  1867. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1868. KdPrint(( "NTFS: Breaking for matched state\n" ));
  1869. DbgBreakPoint();
  1870. }
  1871. }
  1872. if (NtfsPrintOnLockProb) {
  1873. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1874. KdPrint(( "NTFS: change context: 0x%x to 0x%x for 0x%x during 0x%x\n", TopIrpContext, TopIrpContext->OwnershipState, NewResource, Release ));
  1875. }
  1876. }
  1877. #endif
  1878. return TRUE;
  1879. }
  1880. }
  1881. } else {
  1882. NumTransitions = sizeof( OwnershipTransitionTableAcquire ) / sizeof( NTFS_OWNERSHIP_TRANSITION );
  1883. for (Index=0; Index < NumTransitions; Index += 1) {
  1884. if ((OwnershipTransitionTableAcquire[Index].Begin == TopIrpContext->OwnershipState) &&
  1885. ((OwnershipTransitionTableAcquire[Index].Acquired == NewResource) ||
  1886. (OwnershipTransitionTableAcquire[Index].Acquired == NtfsResourceAny))) {
  1887. TopIrpContext->OwnershipState = OwnershipTransitionTableAcquire[Index].End;
  1888. #ifdef NTFSDBG
  1889. if (TopIrpContext->OwnershipState == NtfsBreakOnState) {
  1890. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1891. KdPrint(( "NTFS: Breaking for matched state\n" ));
  1892. DbgBreakPoint();
  1893. }
  1894. }
  1895. if (NtfsPrintOnLockProb) {
  1896. if ((NULL == NtfsBreakOnIrpContext) || (TopIrpContext == NtfsBreakOnIrpContext) ) {
  1897. KdPrint(( "NTFS: change context: 0x%x to 0x%x for 0x%x during 0x%x\n", TopIrpContext, TopIrpContext->OwnershipState, NewResource, Release ));
  1898. }
  1899. }
  1900. #endif
  1901. return TRUE;
  1902. }
  1903. }
  1904. }
  1905. #ifdef NTFSDBG
  1906. if (NtfsAssertOnLockProb) {
  1907. KdPrint(( "NTFS: unknown transition from state: 0x%x resource: 0x%x release: %d unsafe: %d\n", TopIrpContext->OwnershipState, NewResource, Release, UnsafeTransition ));
  1908. ASSERT( FALSE );
  1909. }
  1910. #endif
  1911. return FALSE;
  1912. }
  1913. BOOLEAN
  1914. NtfsAcquireResourceExclusive (
  1915. IN PIRP_CONTEXT IrpContext OPTIONAL,
  1916. IN PVOID FcbOrScb,
  1917. IN BOOLEAN Wait
  1918. )
  1919. /*++
  1920. Routine Description:
  1921. This routine acquires the main resource of the specified structure useing the specified wait
  1922. flag. It will update the resource state in the IrpContext if present.
  1923. Arguments:
  1924. FcbOrScb - Data structure on which we are synchronizing.
  1925. Wait - Indicates if we can wait for the resource.
  1926. Return Value:
  1927. BOOLEAN - TRUE if the resource was acquired, FALSE otherwise.
  1928. --*/
  1929. {
  1930. NTFS_RESOURCE_NAME ResourceName;
  1931. PFCB Fcb;
  1932. BOOLEAN Result;
  1933. //
  1934. // Find the Fcb for either input structure.
  1935. //
  1936. if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
  1937. Fcb = (PFCB)FcbOrScb;
  1938. } else {
  1939. Fcb = ((PSCB)FcbOrScb)->Fcb;
  1940. ASSERT( Fcb->Resource == ((PSCB)FcbOrScb)->Header.Resource );
  1941. }
  1942. //
  1943. // For blocking calls check 1st
  1944. //
  1945. if (Wait &&
  1946. ARGUMENT_PRESENT( IrpContext ) &&
  1947. FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  1948. (0 == ExIsResourceAcquiredSharedLite( Fcb->Resource ))) {
  1949. ResourceName = NtfsIdentifyFcb( IrpContext->Vcb, Fcb );
  1950. NtfsChangeResourceOrderState( IrpContext, ResourceName, FALSE, FALSE );
  1951. }
  1952. Result = ExAcquireResourceExclusiveLite( Fcb->Resource, Wait );
  1953. //
  1954. // For nonblocking calls afterwards when own the resource
  1955. //
  1956. if (Result &&
  1957. !Wait &&
  1958. ARGUMENT_PRESENT( IrpContext ) &&
  1959. FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  1960. (1 == ExIsResourceAcquiredSharedLite( Fcb->Resource))) {
  1961. ResourceName = NtfsIdentifyFcb( IrpContext->Vcb, Fcb );
  1962. NtfsChangeResourceOrderState( IrpContext, ResourceName, FALSE, TRUE );
  1963. }
  1964. return Result;
  1965. }
  1966. BOOLEAN
  1967. NtfsAcquireResourceShared (
  1968. IN PIRP_CONTEXT IrpContext OPTIONAL,
  1969. IN PVOID FcbOrScb,
  1970. IN BOOLEAN Wait
  1971. )
  1972. /*++
  1973. Routine Description:
  1974. This routine is called to acquire the main resource of the specified structure shared using the
  1975. specified wait flag. It will also update the resource state in the IrpContext if present.
  1976. Arguments:
  1977. FcbOrScb - Data structure on which we are synchronizing.
  1978. Wait - Indicates if we can wait for the resource.
  1979. Return Value:
  1980. BOOLEAN - TRUE if the resource was acquired, FALSE otherwise.
  1981. --*/
  1982. {
  1983. NTFS_RESOURCE_NAME ResourceName;
  1984. BOOLEAN Result;
  1985. PFCB Fcb;
  1986. //
  1987. // Find the Fcb for either input structure.
  1988. //
  1989. if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
  1990. Fcb = (PFCB)FcbOrScb;
  1991. } else {
  1992. Fcb = ((PSCB)FcbOrScb)->Fcb;
  1993. ASSERT( Fcb->Resource == ((PSCB)FcbOrScb)->Header.Resource );
  1994. }
  1995. //
  1996. // For blocking calls check 1st
  1997. //
  1998. if (Wait &&
  1999. ARGUMENT_PRESENT( IrpContext ) &&
  2000. FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  2001. (0 == ExIsResourceAcquiredSharedLite( Fcb->Resource))) {
  2002. ResourceName = NtfsIdentifyFcb( IrpContext->Vcb, Fcb );
  2003. NtfsChangeResourceOrderState( IrpContext, ResourceName, FALSE, FALSE );
  2004. }
  2005. Result = ExAcquireResourceSharedLite( Fcb->Resource, Wait );
  2006. //
  2007. // For nonblocking calls afterwards when own the resource
  2008. //
  2009. if (Result &&
  2010. !Wait &&
  2011. ARGUMENT_PRESENT( IrpContext ) &&
  2012. FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  2013. (1 == ExIsResourceAcquiredSharedLite( Fcb->Resource ))) {
  2014. ResourceName = NtfsIdentifyFcb( IrpContext->Vcb, Fcb );
  2015. NtfsChangeResourceOrderState( IrpContext, ResourceName, FALSE, TRUE );
  2016. }
  2017. return Result;
  2018. }
  2019. VOID
  2020. NtfsReleaseResource (
  2021. IN PIRP_CONTEXT IrpContext OPTIONAL,
  2022. IN PVOID FcbOrScb
  2023. )
  2024. /*++
  2025. Routine Description:
  2026. This routine is called to release the main resource of the specified structure and update the
  2027. resource state in the IrpContext if present.
  2028. Arguments:
  2029. FcbOrScb - Data structure on which we are synchronizing.
  2030. Return Value:
  2031. None
  2032. --*/
  2033. {
  2034. NTFS_RESOURCE_NAME ResourceName;
  2035. PFCB Fcb;
  2036. //
  2037. // Find the Fcb for either input structure.
  2038. //
  2039. if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
  2040. Fcb = (PFCB)FcbOrScb;
  2041. } else {
  2042. Fcb = ((PSCB)FcbOrScb)->Fcb;
  2043. ASSERT( Fcb->Resource == ((PSCB)FcbOrScb)->Header.Resource );
  2044. }
  2045. if (ARGUMENT_PRESENT( IrpContext )) {
  2046. if (FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  2047. ResourceName = NtfsIdentifyFcb( IrpContext->Vcb, Fcb );
  2048. //
  2049. // Only change ownership state if we are really releasing the resource
  2050. //
  2051. if (1 == ExIsResourceAcquiredSharedLite( Fcb->Resource )) {
  2052. NtfsChangeResourceOrderState( IrpContext, ResourceName, TRUE, FALSE );
  2053. }
  2054. } else {
  2055. IrpContext->OwnershipState = None;
  2056. }
  2057. }
  2058. ExReleaseResourceLite( Fcb->Resource );
  2059. }
  2060. #endif // NTFSDBG