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.

807 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. ResrcSup.c
  5. Abstract:
  6. This module implements the Fat Resource acquisition routines
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Gary Kimura [GaryKi] 22-Mar-1990
  10. Revision History:
  11. // @@END_DDKSPLIT
  12. --*/
  13. #include "FatProcs.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, FatAcquireExclusiveVcb)
  16. #pragma alloc_text(PAGE, FatAcquireFcbForLazyWrite)
  17. #pragma alloc_text(PAGE, FatAcquireFcbForReadAhead)
  18. #pragma alloc_text(PAGE, FatAcquireExclusiveFcb)
  19. #pragma alloc_text(PAGE, FatAcquireSharedFcb)
  20. #pragma alloc_text(PAGE, FatAcquireSharedFcbWaitForEx)
  21. #pragma alloc_text(PAGE, FatAcquireExclusiveVcb)
  22. #pragma alloc_text(PAGE, FatAcquireSharedVcb)
  23. #pragma alloc_text(PAGE, FatNoOpAcquire)
  24. #pragma alloc_text(PAGE, FatNoOpRelease)
  25. #pragma alloc_text(PAGE, FatReleaseFcbFromLazyWrite)
  26. #pragma alloc_text(PAGE, FatReleaseFcbFromReadAhead)
  27. #pragma alloc_text(PAGE, FatAcquireForCcFlush)
  28. #pragma alloc_text(PAGE, FatReleaseForCcFlush)
  29. #endif
  30. FINISHED
  31. FatAcquireExclusiveVcb (
  32. IN PIRP_CONTEXT IrpContext,
  33. IN PVCB Vcb
  34. )
  35. /*++
  36. Routine Description:
  37. This routine acquires exclusive access to the Vcb.
  38. After we acquire the resource check to see if this operation is legal.
  39. If it isn't (ie. we get an exception), release the resource.
  40. Arguments:
  41. Vcb - Supplies the Vcb to acquire
  42. Return Value:
  43. FINISHED - TRUE if we have the resource and FALSE if we needed to block
  44. for the resource but Wait is FALSE.
  45. --*/
  46. {
  47. if (ExAcquireResourceExclusiveLite( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
  48. try {
  49. FatVerifyOperationIsLegal( IrpContext );
  50. } finally {
  51. if ( AbnormalTermination() ) {
  52. FatReleaseVcb( IrpContext, Vcb );
  53. }
  54. }
  55. return TRUE;
  56. } else {
  57. return FALSE;
  58. }
  59. }
  60. FINISHED
  61. FatAcquireSharedVcb (
  62. IN PIRP_CONTEXT IrpContext,
  63. IN PVCB Vcb
  64. )
  65. /*++
  66. Routine Description:
  67. This routine acquires shared access to the Vcb.
  68. After we acquire the resource check to see if this operation is legal.
  69. If it isn't (ie. we get an exception), release the resource.
  70. Arguments:
  71. Vcb - Supplies the Vcb to acquire
  72. Return Value:
  73. FINISHED - TRUE if we have the resource and FALSE if we needed to block
  74. for the resource but Wait is FALSE.
  75. --*/
  76. {
  77. if (ExAcquireResourceSharedLite( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
  78. try {
  79. FatVerifyOperationIsLegal( IrpContext );
  80. } finally {
  81. if ( AbnormalTermination() ) {
  82. FatReleaseVcb( IrpContext, Vcb );
  83. }
  84. }
  85. return TRUE;
  86. } else {
  87. return FALSE;
  88. }
  89. }
  90. FINISHED
  91. FatAcquireExclusiveFcb (
  92. IN PIRP_CONTEXT IrpContext,
  93. IN PFCB Fcb
  94. )
  95. /*++
  96. Routine Description:
  97. This routine acquires exclusive access to the Fcb.
  98. After we acquire the resource check to see if this operation is legal.
  99. If it isn't (ie. we get an exception), release the resource.
  100. Arguments:
  101. Fcb - Supplies the Fcb to acquire
  102. Return Value:
  103. FINISHED - TRUE if we have the resource and FALSE if we needed to block
  104. for the resource but Wait is FALSE.
  105. --*/
  106. {
  107. RetryFcbExclusive:
  108. if (ExAcquireResourceExclusiveLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
  109. //
  110. // Check for anything other than a non-cached write if the
  111. // async count is non-zero in the Fcb, or if others are waiting
  112. // for the resource. Then wait for all outstanding I/O to finish,
  113. // drop the resource, and wait again.
  114. //
  115. if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
  116. ((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
  117. !FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ||
  118. (ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) ||
  119. (ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) {
  120. KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
  121. Executive,
  122. KernelMode,
  123. FALSE,
  124. (PLARGE_INTEGER) NULL );
  125. FatReleaseFcb( IrpContext, Fcb );
  126. goto RetryFcbExclusive;
  127. }
  128. try {
  129. FatVerifyOperationIsLegal( IrpContext );
  130. } finally {
  131. if ( AbnormalTermination() ) {
  132. FatReleaseFcb( IrpContext, Fcb );
  133. }
  134. }
  135. return TRUE;
  136. } else {
  137. return FALSE;
  138. }
  139. }
  140. FINISHED
  141. FatAcquireSharedFcb (
  142. IN PIRP_CONTEXT IrpContext,
  143. IN PFCB Fcb
  144. )
  145. /*++
  146. Routine Description:
  147. This routine acquires shared access to the Fcb.
  148. After we acquire the resource check to see if this operation is legal.
  149. If it isn't (ie. we get an exception), release the resource.
  150. Arguments:
  151. Fcb - Supplies the Fcb to acquire
  152. Return Value:
  153. FINISHED - TRUE if we have the resource and FALSE if we needed to block
  154. for the resource but Wait is FALSE.
  155. --*/
  156. {
  157. RetryFcbShared:
  158. if (ExAcquireResourceSharedLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
  159. //
  160. // Check for anything other than a non-cached write if the
  161. // async count is non-zero in the Fcb, or if others are waiting
  162. // for the resource. Then wait for all outstanding I/O to finish,
  163. // drop the resource, and wait again.
  164. //
  165. if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
  166. ((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
  167. !FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ||
  168. (ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) ||
  169. (ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) {
  170. KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
  171. Executive,
  172. KernelMode,
  173. FALSE,
  174. (PLARGE_INTEGER) NULL );
  175. FatReleaseFcb( IrpContext, Fcb );
  176. goto RetryFcbShared;
  177. }
  178. try {
  179. FatVerifyOperationIsLegal( IrpContext );
  180. } finally {
  181. if ( AbnormalTermination() ) {
  182. FatReleaseFcb( IrpContext, Fcb );
  183. }
  184. }
  185. return TRUE;
  186. } else {
  187. return FALSE;
  188. }
  189. }
  190. FINISHED
  191. FatAcquireSharedFcbWaitForEx (
  192. IN PIRP_CONTEXT IrpContext,
  193. IN PFCB Fcb
  194. )
  195. /*++
  196. Routine Description:
  197. This routine acquires shared access to the Fcb, waiting first for any
  198. exclusive accessors to get the Fcb first.
  199. After we acquire the resource check to see if this operation is legal.
  200. If it isn't (ie. we get an exception), release the resource.
  201. Arguments:
  202. Fcb - Supplies the Fcb to acquire
  203. Return Value:
  204. FINISHED - TRUE if we have the resource and FALSE if we needed to block
  205. for the resource but Wait is FALSE.
  206. --*/
  207. {
  208. ASSERT( FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) );
  209. ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  210. RetryFcbSharedWaitEx:
  211. if (ExAcquireSharedWaitForExclusive( Fcb->Header.Resource, FALSE )) {
  212. //
  213. // Check for anything other than a non-cached write if the
  214. // async count is non-zero in the Fcb. Then wait for all
  215. // outstanding I/O to finish, drop the resource, and wait again.
  216. //
  217. if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
  218. (IrpContext->MajorFunction != IRP_MJ_WRITE)) {
  219. KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
  220. Executive,
  221. KernelMode,
  222. FALSE,
  223. (PLARGE_INTEGER) NULL );
  224. FatReleaseFcb( IrpContext, Fcb );
  225. goto RetryFcbSharedWaitEx;
  226. }
  227. try {
  228. FatVerifyOperationIsLegal( IrpContext );
  229. } finally {
  230. if ( AbnormalTermination() ) {
  231. FatReleaseFcb( IrpContext, Fcb );
  232. }
  233. }
  234. return TRUE;
  235. } else {
  236. return FALSE;
  237. }
  238. }
  239. BOOLEAN
  240. FatAcquireFcbForLazyWrite (
  241. IN PVOID Fcb,
  242. IN BOOLEAN Wait
  243. )
  244. /*++
  245. Routine Description:
  246. The address of this routine is specified when creating a CacheMap for
  247. a file. It is subsequently called by the Lazy Writer prior to its
  248. performing lazy writes to the file.
  249. Arguments:
  250. Fcb - The Fcb which was specified as a context parameter for this
  251. routine.
  252. Wait - TRUE if the caller is willing to block.
  253. Return Value:
  254. FALSE - if Wait was specified as FALSE and blocking would have
  255. been required. The Fcb is not acquired.
  256. TRUE - if the Fcb has been acquired
  257. --*/
  258. {
  259. //
  260. // Check here for the EA File. It turns out we need the normal
  261. // resource shared in this case. Otherwise we take the paging
  262. // I/O resource shared.
  263. //
  264. if (!ExAcquireResourceSharedLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ?
  265. ((PFCB)Fcb)->Header.Resource :
  266. ((PFCB)Fcb)->Header.PagingIoResource,
  267. Wait )) {
  268. return FALSE;
  269. }
  270. //
  271. // We assume the Lazy Writer only acquires this Fcb once.
  272. // Therefore, it should be guaranteed that this flag is currently
  273. // clear (the ASSERT), and then we will set this flag, to insure
  274. // that the Lazy Writer will never try to advance Valid Data, and
  275. // also not deadlock by trying to get the Fcb exclusive.
  276. //
  277. ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB );
  278. ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == NULL );
  279. ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
  280. ASSERT( NULL != PsGetCurrentThread() );
  281. if (NULL == FatData.LazyWriteThread) {
  282. FatData.LazyWriteThread = PsGetCurrentThread();
  283. }
  284. //
  285. // This is a kludge because Cc is really the top level. When it
  286. // enters the file system, we will think it is a resursive call
  287. // and complete the request with hard errors or verify. It will
  288. // then have to deal with them, somehow....
  289. //
  290. ASSERT(IoGetTopLevelIrp() == NULL);
  291. IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  292. return TRUE;
  293. }
  294. VOID
  295. FatReleaseFcbFromLazyWrite (
  296. IN PVOID Fcb
  297. )
  298. /*++
  299. Routine Description:
  300. The address of this routine is specified when creating a CacheMap for
  301. a file. It is subsequently called by the Lazy Writer after its
  302. performing lazy writes to the file.
  303. Arguments:
  304. Fcb - The Fcb which was specified as a context parameter for this
  305. routine.
  306. Return Value:
  307. None
  308. --*/
  309. {
  310. //
  311. // Assert that this really is an fcb and that this thread really owns
  312. // the lazy writer mark in the fcb.
  313. //
  314. ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB );
  315. ASSERT( NULL != PsGetCurrentThread() );
  316. ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == PsGetCurrentThread() );
  317. //
  318. // Release the lazy writer mark.
  319. //
  320. ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = NULL;
  321. //
  322. // Check here for the EA File. It turns out we needed the normal
  323. // resource shared in this case. Otherwise it was the PagingIoResource.
  324. //
  325. ExReleaseResourceLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ?
  326. ((PFCB)Fcb)->Header.Resource :
  327. ((PFCB)Fcb)->Header.PagingIoResource );
  328. //
  329. // Clear the kludge at this point.
  330. //
  331. ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  332. IoSetTopLevelIrp( NULL );
  333. return;
  334. }
  335. BOOLEAN
  336. FatAcquireFcbForReadAhead (
  337. IN PVOID Fcb,
  338. IN BOOLEAN Wait
  339. )
  340. /*++
  341. Routine Description:
  342. The address of this routine is specified when creating a CacheMap for
  343. a file. It is subsequently called by the Lazy Writer prior to its
  344. performing read ahead to the file.
  345. Arguments:
  346. Fcb - The Fcb which was specified as a context parameter for this
  347. routine.
  348. Wait - TRUE if the caller is willing to block.
  349. Return Value:
  350. FALSE - if Wait was specified as FALSE and blocking would have
  351. been required. The Fcb is not acquired.
  352. TRUE - if the Fcb has been acquired
  353. --*/
  354. {
  355. //
  356. // We acquire the normal file resource shared here to synchronize
  357. // correctly with purges.
  358. //
  359. if (!ExAcquireResourceSharedLite( ((PFCB)Fcb)->Header.Resource,
  360. Wait )) {
  361. return FALSE;
  362. }
  363. //
  364. // This is a kludge because Cc is really the top level. We it
  365. // enters the file system, we will think it is a resursive call
  366. // and complete the request with hard errors or verify. It will
  367. // have to deal with them, somehow....
  368. //
  369. ASSERT(IoGetTopLevelIrp() == NULL);
  370. IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  371. return TRUE;
  372. }
  373. VOID
  374. FatReleaseFcbFromReadAhead (
  375. IN PVOID Fcb
  376. )
  377. /*++
  378. Routine Description:
  379. The address of this routine is specified when creating a CacheMap for
  380. a file. It is subsequently called by the Lazy Writer after its
  381. read ahead.
  382. Arguments:
  383. Fcb - The Fcb which was specified as a context parameter for this
  384. routine.
  385. Return Value:
  386. None
  387. --*/
  388. {
  389. //
  390. // Clear the kludge at this point.
  391. //
  392. ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  393. IoSetTopLevelIrp( NULL );
  394. ExReleaseResourceLite( ((PFCB)Fcb)->Header.Resource );
  395. return;
  396. }
  397. NTSTATUS
  398. FatAcquireForCcFlush (
  399. IN PFILE_OBJECT FileObject,
  400. IN PDEVICE_OBJECT DeviceObject
  401. )
  402. {
  403. PFCB Fcb;
  404. PCCB Ccb;
  405. PVCB Vcb;
  406. PFSRTL_COMMON_FCB_HEADER Header;
  407. TYPE_OF_OPEN Type;
  408. //
  409. // Once again, the hack for making this look like
  410. // a recursive call if needed. We cannot let ourselves
  411. // verify under something that has resources held.
  412. //
  413. // This value is good. We should never try to acquire
  414. // the file this way underneath of the cache.
  415. //
  416. ASSERT( IoGetTopLevelIrp() != (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP );
  417. if (IoGetTopLevelIrp() == NULL) {
  418. IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  419. }
  420. //
  421. // Time for some exposition.
  422. //
  423. // Lockorder for FAT is main->bcb->pagingio. Invert this at your obvious peril.
  424. // The default logic for AcquireForCcFlush breaks this since in writethrough
  425. // unpinrepinned we will grab the bcb then Mm will use the callback (which
  426. // orders us with respect to the MmCollidedFlushEvent) to help us. If for
  427. // directories/ea we then grab the main we are out of order.
  428. //
  429. // Fortunately, we do not need main. We only need paging - just look at the write
  430. // path. This is basic pre-acquisition.
  431. //
  432. // Regular files require both resources, and are safe since we never pin them.
  433. //
  434. Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  435. Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
  436. if (Type < DirectoryFile) {
  437. if (Header->Resource) {
  438. if (!ExIsResourceAcquiredSharedLite( Header->Resource )) {
  439. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  440. } else {
  441. ExAcquireResourceSharedLite( Header->Resource, TRUE );
  442. }
  443. }
  444. }
  445. if (Header->PagingIoResource) {
  446. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  447. }
  448. return STATUS_SUCCESS;
  449. }
  450. NTSTATUS
  451. FatReleaseForCcFlush (
  452. IN PFILE_OBJECT FileObject,
  453. IN PDEVICE_OBJECT DeviceObject
  454. )
  455. {
  456. PFCB Fcb;
  457. PCCB Ccb;
  458. PVCB Vcb;
  459. PFSRTL_COMMON_FCB_HEADER Header;
  460. TYPE_OF_OPEN Type;
  461. //
  462. // Clear up our hint.
  463. //
  464. if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) {
  465. IoSetTopLevelIrp( NULL );
  466. }
  467. Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  468. Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
  469. if (Type < DirectoryFile) {
  470. if (Header->Resource) {
  471. ExReleaseResourceLite( Header->Resource );
  472. }
  473. }
  474. if (Header->PagingIoResource) {
  475. ExReleaseResourceLite( Header->PagingIoResource );
  476. }
  477. return STATUS_SUCCESS;
  478. }
  479. BOOLEAN
  480. FatNoOpAcquire (
  481. IN PVOID Fcb,
  482. IN BOOLEAN Wait
  483. )
  484. /*++
  485. Routine Description:
  486. This routine does nothing.
  487. Arguments:
  488. Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this
  489. routine.
  490. Wait - TRUE if the caller is willing to block.
  491. Return Value:
  492. TRUE
  493. --*/
  494. {
  495. UNREFERENCED_PARAMETER( Fcb );
  496. UNREFERENCED_PARAMETER( Wait );
  497. //
  498. // This is a kludge because Cc is really the top level. We it
  499. // enters the file system, we will think it is a resursive call
  500. // and complete the request with hard errors or verify. It will
  501. // have to deal with them, somehow....
  502. //
  503. ASSERT(IoGetTopLevelIrp() == NULL);
  504. IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  505. return TRUE;
  506. }
  507. VOID
  508. FatNoOpRelease (
  509. IN PVOID Fcb
  510. )
  511. /*++
  512. Routine Description:
  513. This routine does nothing.
  514. Arguments:
  515. Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this
  516. routine.
  517. Return Value:
  518. None
  519. --*/
  520. {
  521. //
  522. // Clear the kludge at this point.
  523. //
  524. ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
  525. IoSetTopLevelIrp( NULL );
  526. UNREFERENCED_PARAMETER( Fcb );
  527. return;
  528. }