Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1601 lines
47 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Close.c
  5. Abstract:
  6. This module implements the File Close routine for Ntfs called by the
  7. dispatch driver.
  8. Author:
  9. Your Name [Email] dd-Mon-Year
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. //
  14. // The local debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_CLOSE)
  17. ULONG NtfsAsyncPassCount = 0;
  18. #ifdef LFS_CLUSTER_CHECK
  19. LONG
  20. NtfsFspCloseExceptionFilter (
  21. IN PIRP_CONTEXT IrpContext OPTIONAL,
  22. IN PEXCEPTION_POINTERS ExceptionPointer
  23. );
  24. #endif
  25. //
  26. // Local procedure prototypes
  27. //
  28. NTSTATUS
  29. NtfsCommonClose (
  30. IN PIRP_CONTEXT IrpContext,
  31. IN PSCB Scb,
  32. IN PFCB Fcb,
  33. IN PVCB Vcb,
  34. IN PCCB *Ccb,
  35. IN TYPE_OF_OPEN TypeOfOpen,
  36. IN BOOLEAN ReadOnly,
  37. IN BOOLEAN CalledFromFsp
  38. );
  39. VOID
  40. NtfsQueueClose (
  41. IN PIRP_CONTEXT IrpContext,
  42. IN BOOLEAN DelayClose
  43. );
  44. PIRP_CONTEXT
  45. NtfsRemoveClose (
  46. IN PVCB Vcb OPTIONAL,
  47. IN BOOLEAN ThrottleCreate
  48. );
  49. #ifdef ALLOC_PRAGMA
  50. #pragma alloc_text(PAGE, NtfsCommonClose)
  51. #pragma alloc_text(PAGE, NtfsFsdClose)
  52. #pragma alloc_text(PAGE, NtfsFspClose)
  53. #endif
  54. NTSTATUS
  55. NtfsFsdClose (
  56. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  57. IN PIRP Irp
  58. )
  59. /*++
  60. Routine Description:
  61. This routine implements the FSD part of Close.
  62. Arguments:
  63. VolumeDeviceObject - Supplies the volume device object where the
  64. file exists
  65. Irp - Supplies the Irp being processed
  66. Return Value:
  67. NTSTATUS - The FSD status for the IRP
  68. --*/
  69. {
  70. TOP_LEVEL_CONTEXT TopLevelContext;
  71. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  72. NTSTATUS Status = STATUS_SUCCESS;
  73. PIRP_CONTEXT IrpContext = NULL;
  74. PFILE_OBJECT FileObject;
  75. TYPE_OF_OPEN TypeOfOpen;
  76. BOOLEAN IsSystemFile;
  77. BOOLEAN IsReadOnly;
  78. PVCB Vcb;
  79. PFCB Fcb;
  80. PSCB Scb;
  81. PCCB Ccb;
  82. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  83. PAGED_CODE();
  84. ASSERT_IRP( Irp );
  85. //
  86. // If we were called with our file system device object instead of a
  87. // volume device object, just complete this request with STATUS_SUCCESS
  88. //
  89. if (VolumeDeviceObject->DeviceObject.Size == (USHORT)sizeof(DEVICE_OBJECT)) {
  90. Irp->IoStatus.Status = STATUS_SUCCESS;
  91. Irp->IoStatus.Information = FILE_OPENED;
  92. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  93. return STATUS_SUCCESS;
  94. }
  95. DebugTrace( +1, Dbg, ("NtfsFsdClose\n") );
  96. //
  97. // Extract and decode the file object, we are willing to handle the unmounted
  98. // file object.
  99. //
  100. FileObject = IrpSp->FileObject;
  101. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  102. //
  103. // Special case the unopened file object
  104. //
  105. if (TypeOfOpen == UnopenedFileObject) {
  106. DebugTrace( 0, Dbg, ("Close unopened file object\n") );
  107. Status = STATUS_SUCCESS;
  108. NtfsCompleteRequest( NULL, Irp, Status );
  109. DebugTrace( -1, Dbg, ("NtfsFsdClose -> %08lx\n", Status) );
  110. return Status;
  111. }
  112. //
  113. // If this is the log file object for the Vcb then clear the field in the Vcb and
  114. // return. We don't need to synchronize here since there is only one file object
  115. // and it is closed only once.
  116. //
  117. if (FileObject == Vcb->LogFileObject) {
  118. //
  119. // Clear the internal file name constant
  120. //
  121. NtfsClearInternalFilename( Vcb->LogFileObject );
  122. Vcb->LogFileObject = NULL;
  123. Status = STATUS_SUCCESS;
  124. NtfsCompleteRequest( NULL, Irp, Status );
  125. DebugTrace( -1, Dbg, ("NtfsFsdClose -> %08lx\n", Status) );
  126. return Status;
  127. }
  128. //
  129. // Call the common Close routine
  130. //
  131. FsRtlEnterFileSystem();
  132. //
  133. // Remember if this Ccb has gone through close.
  134. //
  135. if (Ccb != NULL) {
  136. //
  137. // We are not synchronized with the file resources at this point.
  138. // It is possible that NtfsUpdateFileDupInfo or the rename path may want to
  139. // update the name in the CCB. Our intention here is to mark this CCB_FLAG_CLOSE
  140. // so that these other operations know to skip this CCB. We need to deal with the
  141. // race condition where these other operations don't see the CLOSE flag but
  142. // then access the CCB name (which points back to the file object) after we
  143. // return the file object to the object manager (but put the CCB on the delayed
  144. // close queue).
  145. //
  146. // We will use the Fcb mutex to close the hole where DupInfo and rename need to look
  147. // at a CCB that might be in the close path.
  148. //
  149. NtfsLockFcb( NULL, Fcb );
  150. SetFlag( Ccb->Flags, CCB_FLAG_CLOSE );
  151. //
  152. // If we're protecting the name in dupinfo path - strip it from the fileobject and free it
  153. // with the ccb
  154. //
  155. if (FlagOn( Ccb->Flags, CCB_FLAG_PROTECT_NAME )) {
  156. SetFlag( Ccb->Flags, CCB_FLAG_ALLOCATED_FILE_NAME );
  157. FileObject->FileName.Buffer = NULL;
  158. FileObject->FileName.Length = FileObject->FileName.MaximumLength = 0;
  159. }
  160. NtfsUnlockFcb( NULL, Fcb );
  161. ASSERT( FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ));
  162. }
  163. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  164. IsSystemFile = FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) || (TypeOfOpen == StreamFileOpen);
  165. IsReadOnly = (BOOLEAN)IsFileObjectReadOnly( FileObject );
  166. do {
  167. try {
  168. //
  169. // Jam Wait to FALSE when we create the IrpContext, to avoid
  170. // deadlocks when coming in from cleanup.
  171. //
  172. if (IrpContext == NULL) {
  173. //
  174. // Allocate and initialize the Irp.
  175. //
  176. NtfsInitializeIrpContext( Irp, FALSE, &IrpContext );
  177. //
  178. // Set the level structure on the stack.
  179. //
  180. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  181. //
  182. // If this is a top level request and we are not in the
  183. // system process, then we can wait. If it is a top level
  184. // request and we are in the system process then we would
  185. // rather not block this thread at all. If the number of pending
  186. // async closes is not too large we will post this immediately.
  187. //
  188. if (NtfsIsTopLevelRequest( IrpContext )) {
  189. if (PsGetCurrentProcess() != NtfsData.OurProcess) {
  190. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  191. //
  192. // This close is within the system process. It could be
  193. // the segment derefernce thread. We want to be careful
  194. // about processing the close in this thread. If we
  195. // process the close too slowly we can eventually
  196. // cause a large backlog of file objects within
  197. // MM. We will consider posting under the following conditions.
  198. //
  199. // - There are more that four times as many file objects as handles (AND)
  200. // - The number of excess file objects (CloseCount - CleanupCount) is
  201. // over our async post threshold for this size system.
  202. // - we're the deref seg thread (identified by current priority being above real time )
  203. //
  204. } else {
  205. NtfsAsyncPassCount += 1;
  206. if ((KeQueryPriorityThread( PsGetCurrentThread() ) >= LOW_REALTIME_PRIORITY) ||
  207. (FlagOn( NtfsAsyncPassCount, 3 ) &&
  208. (Vcb->CleanupCount * 4 < Vcb->CloseCount) &&
  209. (Vcb->CloseCount - Vcb->CleanupCount > NtfsAsyncPostThreshold + NtfsMaxDelayedCloseCount))) {
  210. Status = STATUS_PENDING;
  211. break;
  212. }
  213. }
  214. //
  215. // This is a recursive Ntfs call. Post this unless we already
  216. // own this file. Otherwise we could deadlock walking
  217. // up the tree. Also if there was any error in the top level post it to
  218. // preserve stack
  219. //
  220. } else if (!NtfsIsExclusiveScb( Scb ) ||
  221. (IrpContext->TopLevelIrpContext->ExceptionStatus != STATUS_SUCCESS )) {
  222. Status = STATUS_PENDING;
  223. break;
  224. }
  225. } else if (Status == STATUS_LOG_FILE_FULL) {
  226. NtfsCheckpointForLogFileFull( IrpContext );
  227. }
  228. //
  229. // If this Scb should go on the delayed close queue then
  230. // status is STATUS_PENDING;
  231. //
  232. if (FlagOn( Scb->ScbState, SCB_STATE_DELAY_CLOSE ) &&
  233. (Scb->Fcb->DelayedCloseCount == 0)) {
  234. Status = STATUS_PENDING;
  235. } else {
  236. Status = NtfsCommonClose( IrpContext,
  237. Scb,
  238. Fcb,
  239. Vcb,
  240. &Ccb,
  241. TypeOfOpen,
  242. IsReadOnly,
  243. FALSE );
  244. }
  245. break;
  246. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  247. //
  248. // We had some trouble trying to perform the requested
  249. // operation, so we'll abort the I/O request with
  250. // the error status that we get back from the
  251. // exception code.
  252. //
  253. if (IrpContext == NULL) {
  254. //
  255. // We could've hit insufficient resources in trying to allocate
  256. // the IrpContext. Make sure we don't leave a reference
  257. // hanging around in this case. ProcessException will complete
  258. // the IRP for us.
  259. //
  260. PLCB Lcb;
  261. ASSERT( GetExceptionCode() == STATUS_INSUFFICIENT_RESOURCES );
  262. if (Ccb != NULL) {
  263. Lcb = Ccb->Lcb;
  264. NtfsUnlinkCcbFromLcb( NULL, Fcb, Ccb );
  265. NtfsDeleteCcb( Fcb, &Ccb );
  266. } else {
  267. Lcb = NULL;
  268. }
  269. //
  270. // This only decrements the close counts so it will not raise
  271. //
  272. NtfsDecrementCloseCounts( NULL,
  273. Scb,
  274. Lcb,
  275. IsSystemFile,
  276. IsReadOnly,
  277. TRUE,
  278. NULL );
  279. }
  280. Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
  281. }
  282. ASSERT( NT_SUCCESS( Status ) || (IrpContext == NULL) || IsListEmpty(&IrpContext->ExclusiveFcbList) );
  283. } while (Status == STATUS_CANT_WAIT ||
  284. Status == STATUS_LOG_FILE_FULL);
  285. //
  286. // Io believes that it needs to free the FileObject->FileName.Buffer ONLY
  287. // if FileObject->FileName.Length != 0. Ntfs hides the attribute name
  288. // between FileObject->FileName.Length and FileObject->Filename.MaximumLength
  289. // and for a attribute-name-open relative to a file opened by Id, the Length
  290. // field will be zero. This, alas, causes Io to leak names. So...
  291. //
  292. // If we have a buffer allocated, make sure that the length is not zero when
  293. // Io gets to see it.
  294. //
  295. if (FileObject->FileName.Buffer != NULL) {
  296. FileObject->FileName.Length = 1;
  297. }
  298. //
  299. // Trigger an assert on any unexpected cases.
  300. //
  301. ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_PENDING) ||
  302. (Status == STATUS_INSUFFICIENT_RESOURCES) );
  303. //
  304. // Post the request to the close queue on PENDING.
  305. //
  306. if (Status == STATUS_PENDING) {
  307. BOOLEAN DelayCloseQueue = FALSE;
  308. //
  309. // If the status is can't wait, then let's get the information we
  310. // need into the IrpContext, complete the request,
  311. // and post the IrpContext.
  312. //
  313. //
  314. // Restore the thread context pointer if associated with this IrpContext.
  315. //
  316. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )) {
  317. NtfsRestoreTopLevelIrp();
  318. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL );
  319. }
  320. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE );
  321. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  322. Status = STATUS_SUCCESS;
  323. IrpContext->OriginatingIrp = (PIRP) Scb;
  324. IrpContext->Union.SubjectContext = (PSECURITY_SUBJECT_CONTEXT) Ccb;
  325. IrpContext->TransactionId = (TRANSACTION_ID) TypeOfOpen;
  326. //
  327. // At this point the file is effectively readonly - by changing it
  328. // here we remove a race with implict locking through volume opens and
  329. // the async close queue. Note: we have NO synchroniation here other
  330. // than the interlocked operation. The vcb will not go away until
  331. // this close is done
  332. //
  333. if (Ccb != NULL) {
  334. if (!IsFileObjectReadOnly( FileObject )) {
  335. FileObject->WriteAccess = 0;
  336. FileObject->DeleteAccess = 0;
  337. InterlockedIncrement( &Vcb->ReadOnlyCloseCount );
  338. }
  339. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_READ_ONLY_FO );
  340. } else {
  341. //
  342. // System files should never be read-only. There will be
  343. // a ccb for all user fileobjects. Internal fileobjects are
  344. // also always marked as system
  345. //
  346. ASSERT( !IsFileObjectReadOnly( FileObject ));
  347. }
  348. //
  349. // Decide which close queue this will go on.
  350. //
  351. if (FlagOn( Scb->ScbState, SCB_STATE_DELAY_CLOSE )) {
  352. NtfsAcquireFsrtlHeader( Scb );
  353. ClearFlag( Scb->ScbState, SCB_STATE_DELAY_CLOSE );
  354. NtfsReleaseFsrtlHeader( Scb );
  355. if (Scb->Fcb->DelayedCloseCount == 0) {
  356. DelayCloseQueue = TRUE;
  357. }
  358. }
  359. NtfsQueueClose( IrpContext, DelayCloseQueue );
  360. //
  361. // Succeed in all other cases.
  362. //
  363. } else {
  364. if (Status == STATUS_SUCCESS) {
  365. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  366. }
  367. //
  368. // INSUFFICIENT_RESOURCES is the only other status that
  369. // we can hit at this point. We would've completed the IRP in
  370. // the except clause above in this case, so don't try doing it again.
  371. //
  372. ASSERT( Status == STATUS_SUCCESS || Status == STATUS_INSUFFICIENT_RESOURCES );
  373. }
  374. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  375. FsRtlExitFileSystem();
  376. //
  377. // And return to our caller
  378. //
  379. DebugTrace( -1, Dbg, ("NtfsFsdClose -> %08lx\n", Status) );
  380. return Status;
  381. }
  382. VOID
  383. NtfsFspClose (
  384. IN PVCB ThisVcb OPTIONAL
  385. )
  386. /*++
  387. Routine Description:
  388. This routine implements the FSP part of Close.
  389. Arguments:
  390. ThisVcb - If specified then we want to remove all closes for a given Vcb.
  391. Otherwise this routine will close all of the async closes and as many
  392. of the delayed closes as possible.
  393. Return Value:
  394. None.
  395. --*/
  396. {
  397. PIRP_CONTEXT IrpContext;
  398. TOP_LEVEL_CONTEXT TopLevelContext;
  399. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  400. TYPE_OF_OPEN TypeOfOpen;
  401. PSCB Scb;
  402. PCCB Ccb;
  403. BOOLEAN ReadOnly;
  404. NTSTATUS Status = STATUS_SUCCESS;
  405. PVCB CurrentVcb = NULL;
  406. BOOLEAN ThrottleCreate = FALSE;
  407. ULONG ClosedCount = 0;
  408. DebugTrace( +1, Dbg, ("NtfsFspClose\n") );
  409. PAGED_CODE();
  410. FsRtlEnterFileSystem();
  411. //
  412. // Occasionally we are called from some other routine to try to
  413. // reduce the backlog of closes. This is indicated by a pointer
  414. // value of 1.
  415. //
  416. if (ThisVcb == (PVCB) 1) {
  417. ThisVcb = NULL;
  418. ThrottleCreate = TRUE;
  419. }
  420. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, FALSE );
  421. ASSERT( ThreadTopLevelContext == &TopLevelContext );
  422. //
  423. // Extract and decode the file object, we are willing to handle the unmounted
  424. // file object. Note we normally get here via an IrpContext which really
  425. // just points to a file object. We should never see an Irp, unless it can
  426. // happen for verify or some other reason.
  427. //
  428. while (IrpContext = NtfsRemoveClose( ThisVcb, ThrottleCreate )) {
  429. ASSERT_IRP_CONTEXT( IrpContext );
  430. //
  431. // Recover the information about the file object being closed from
  432. // the data stored in the IrpContext. The following fields are
  433. // used for this.
  434. //
  435. // OriginatingIrp - Contains the Scb
  436. // SubjectContext - Contains the Ccb
  437. // TransactionId - Contains the TypeOfOpen
  438. // Flags - Has bit for read-only file.
  439. //
  440. Scb = (PSCB) IrpContext->OriginatingIrp;
  441. IrpContext->OriginatingIrp = NULL;
  442. Ccb = (PCCB) IrpContext->Union.SubjectContext;
  443. IrpContext->Union.SubjectContext = NULL;
  444. TypeOfOpen = (TYPE_OF_OPEN) IrpContext->TransactionId;
  445. IrpContext->TransactionId = 0;
  446. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_READ_ONLY_FO )) {
  447. ReadOnly = TRUE;
  448. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_READ_ONLY_FO );
  449. } else {
  450. ReadOnly = FALSE;
  451. }
  452. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
  453. SetFlag( IrpContext->State,
  454. IRP_CONTEXT_STATE_IN_FSP | IRP_CONTEXT_STATE_WAIT );
  455. //
  456. // Loop for retryable errors.
  457. //
  458. Status = STATUS_SUCCESS;
  459. do {
  460. //
  461. // Set the TopLevel structure.
  462. //
  463. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  464. //
  465. // Call the common Close routine.
  466. //
  467. try {
  468. //
  469. // Do logfile full checkpointing
  470. //
  471. if (Status == STATUS_LOG_FILE_FULL) {
  472. NtfsCheckpointForLogFileFull( IrpContext );
  473. }
  474. CurrentVcb = IrpContext->Vcb;
  475. Status = NtfsCommonClose( IrpContext,
  476. Scb,
  477. Scb->Fcb,
  478. IrpContext->Vcb,
  479. &Ccb,
  480. TypeOfOpen,
  481. ReadOnly,
  482. TRUE );
  483. ASSERT(Status == STATUS_SUCCESS);
  484. #ifdef LFS_CLUSTER_CHECK
  485. } except( NtfsFspCloseExceptionFilter( IrpContext, GetExceptionInformation() )) {
  486. #else
  487. } except( NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  488. #endif
  489. Status = NtfsProcessException( IrpContext, NULL, GetExceptionCode() );
  490. }
  491. ASSERT( NT_SUCCESS(Status) || IsListEmpty(&IrpContext->ExclusiveFcbList) );
  492. //
  493. // If we got a log file full, and our caller may have something
  494. // acquired, then clean up and raise again.
  495. //
  496. if (((Status == STATUS_LOG_FILE_FULL) ||
  497. (Status == STATUS_CANT_WAIT)) &&
  498. ARGUMENT_PRESENT( ThisVcb )) {
  499. //
  500. // If the status is can't wait, then let's get the information we
  501. // need into the IrpContext, complete the request,
  502. // and post the IrpContext.
  503. //
  504. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE );
  505. NtfsCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
  506. //
  507. // Restore the information on the file object being closed.
  508. //
  509. IrpContext->OriginatingIrp = (PIRP)Scb;
  510. IrpContext->Union.SubjectContext = (PVOID)Ccb;
  511. IrpContext->TransactionId = TypeOfOpen;
  512. if (ReadOnly) {
  513. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_READ_ONLY_FO );
  514. }
  515. //
  516. // Now queue the close as an async close and get out.
  517. //
  518. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )) {
  519. NtfsRestoreTopLevelIrp();
  520. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL );
  521. }
  522. NtfsQueueClose( IrpContext, FALSE );
  523. FsRtlExitFileSystem();
  524. ExRaiseStatus( Status );
  525. }
  526. } while ((Status == STATUS_LOG_FILE_FULL) || (Status == STATUS_CANT_WAIT));
  527. //
  528. // No more for us to do. Clean up the IrpContext in any case.
  529. //
  530. NtfsCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
  531. //
  532. // If we were just throttling creates and we made our last pass
  533. // then exit.
  534. //
  535. if (ThrottleCreate) {
  536. break;
  537. }
  538. }
  539. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  540. FsRtlExitFileSystem();
  541. //
  542. // And return to our caller
  543. //
  544. DebugTrace( -1, Dbg, ("NtfsFspClose -> NULL\n") );
  545. return;
  546. }
  547. BOOLEAN
  548. NtfsAddScbToFspClose (
  549. IN PIRP_CONTEXT IrpContext,
  550. IN PSCB Scb,
  551. IN BOOLEAN DelayClose
  552. )
  553. /*++
  554. Routine Description:
  555. This routine is called to add an entry for the current Scb onto one
  556. of the Fsp close queues. This is used when we want to guarantee that
  557. a teardown will be called on an Scb or Fcb when the current operation
  558. can't begin the operation.
  559. Arguments:
  560. Scb - Scb to add to the queue.
  561. DelayClose - Indicates which queue this should go into.
  562. Return Value:
  563. BOOLEAN - Indicates whether or not the SCB was added to the delayed
  564. close queue
  565. --*/
  566. {
  567. PIRP_CONTEXT NewIrpContext = NULL;
  568. BOOLEAN Result = TRUE;
  569. PAGED_CODE();
  570. //
  571. // Use a try-except to catch any allocation failures. The only valid
  572. // error here is an allocation failure for the new irp context.
  573. //
  574. try {
  575. NtfsInitializeIrpContext( NULL, TRUE, &NewIrpContext );
  576. //
  577. // Set the necessary fields to post this to the workqueue.
  578. //
  579. NewIrpContext->Vcb = Scb->Vcb;
  580. NewIrpContext->MajorFunction = IRP_MJ_CLOSE;
  581. NewIrpContext->OriginatingIrp = (PIRP) Scb;
  582. NewIrpContext->TransactionId = (TRANSACTION_ID) StreamFileOpen;
  583. //
  584. // Now increment the close counts for this Scb.
  585. //
  586. NtfsIncrementCloseCounts( Scb, TRUE, FALSE );
  587. //
  588. // Move the Scb to the end of the Fcb queue. We don't want to
  589. // keep other Scb's from being deleted because this one is on
  590. // the delayed close queue.
  591. //
  592. if (Scb->FcbLinks.Flink != &Scb->Fcb->ScbQueue) {
  593. NtfsLockFcb( IrpContext, Scb->Fcb );
  594. RemoveEntryList( &Scb->FcbLinks );
  595. InsertTailList( &Scb->Fcb->ScbQueue, &Scb->FcbLinks );
  596. ASSERT( Scb->FcbLinks.Flink == &Scb->Fcb->ScbQueue );
  597. NtfsUnlockFcb( IrpContext, Scb->Fcb );
  598. }
  599. //
  600. // Now add this to the correct queue.
  601. //
  602. NtfsQueueClose( NewIrpContext, DelayClose );
  603. } except( FsRtlIsNtstatusExpected( GetExceptionCode() ) ?
  604. EXCEPTION_EXECUTE_HANDLER :
  605. EXCEPTION_CONTINUE_SEARCH ) {
  606. NtfsMinimumExceptionProcessing( IrpContext );
  607. Result = FALSE;
  608. }
  609. return Result;
  610. UNREFERENCED_PARAMETER( IrpContext );
  611. }
  612. //
  613. // Internal support routine
  614. //
  615. NTSTATUS
  616. NtfsCommonClose (
  617. IN PIRP_CONTEXT IrpContext,
  618. IN PSCB Scb,
  619. IN PFCB Fcb,
  620. IN PVCB Vcb,
  621. IN PCCB *Ccb,
  622. IN TYPE_OF_OPEN TypeOfOpen,
  623. IN BOOLEAN ReadOnly,
  624. IN BOOLEAN CalledFromFsp
  625. )
  626. /*++
  627. Routine Description:
  628. This is the common routine for Close called by both the fsd and fsp
  629. threads. Key for this routine is how to acquire the Vcb and whether to
  630. leave the Vcb acquired on exit.
  631. Arguments:
  632. Scb - Scb for this stream.
  633. Fcb - Fcb for this stream.
  634. Vcb - Vcb for this volume.
  635. Ccb - User's Ccb for user files.
  636. TypeOfOpen - Indicates the type of open for this stream.
  637. ReadOnly - Indicates if the file object was for read-only access.
  638. CalledFromFsp - Indicates whether this function was called from NtfsFspClose.
  639. Return Value:
  640. NTSTATUS - The return status for the operation
  641. --*/
  642. {
  643. BOOLEAN ExclusiveVcb = FALSE;
  644. BOOLEAN AcquiredFcb = FALSE;
  645. BOOLEAN SystemFile;
  646. BOOLEAN RemovedFcb = FALSE;
  647. ULONG AcquireFlags = ACQUIRE_NO_DELETE_CHECK | ACQUIRE_HOLD_BITMAP;
  648. BOOLEAN NeedVcbExclusive = FALSE;
  649. BOOLEAN WriteFileSize;
  650. NTSTATUS Status = STATUS_SUCCESS;
  651. PLCB Lcb;
  652. ASSERT_IRP_CONTEXT( IrpContext );
  653. PAGED_CODE();
  654. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  655. //
  656. // Get the current Irp stack location
  657. //
  658. DebugTrace( +1, Dbg, ("NtfsCommonClose\n") );
  659. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  660. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  661. SetFlag( AcquireFlags, ACQUIRE_DONT_WAIT );
  662. }
  663. //
  664. // Loop here to acquire both the Vcb and Fcb. We want to acquire
  665. // the Vcb exclusively if the file has multiple links.
  666. //
  667. while (TRUE) {
  668. WriteFileSize = FALSE;
  669. //
  670. // Perform an unsafe test and optimistically acquire Vcb.
  671. //
  672. if (NeedVcbExclusive ||
  673. (Fcb->LcbQueue.Flink != Fcb->LcbQueue.Blink) ||
  674. FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT )) {
  675. if (!NtfsAcquireExclusiveVcb( IrpContext, Vcb, FALSE )) {
  676. return STATUS_PENDING;
  677. }
  678. ExclusiveVcb = TRUE;
  679. } else {
  680. if (!NtfsAcquireSharedVcb( IrpContext, Vcb, FALSE )) {
  681. return STATUS_PENDING;
  682. }
  683. }
  684. //
  685. // Now try to acquire the Fcb. If we are unable to acquire it then
  686. // release the Vcb and return. This can only be from the Fsd path
  687. // since otherwise Wait will be TRUE.
  688. //
  689. if (!NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, AcquireFlags )) {
  690. //
  691. // Always release the Vcb. This can only be from the Fsd thread.
  692. //
  693. NtfsReleaseVcb( IrpContext, Vcb );
  694. return STATUS_PENDING;
  695. }
  696. AcquiredFcb = TRUE;
  697. //
  698. // Recheck scbstate now that we own the fcb exclusive to see if we need
  699. // to write the filesize at this point
  700. //
  701. if ((!FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) &&
  702. (!FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) &&
  703. (FlagOn( Scb->ScbState, SCB_STATE_WRITE_FILESIZE_ON_CLOSE )) &&
  704. (Fcb->LinkCount > 0) &&
  705. (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED ))) {
  706. WriteFileSize = TRUE;
  707. NtfsReleaseFcb( IrpContext, Fcb );
  708. AcquiredFcb = FALSE;
  709. //
  710. // NtfsAcquireWithPaging only gets the paging if the irpcontext
  711. // flag is set. Also it assumes no delete check which we explictly
  712. // want here anyway.
  713. //
  714. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  715. if (!NtfsAcquireFcbWithPaging( IrpContext, Fcb, AcquireFlags )) {
  716. NtfsReleaseVcb( IrpContext, Vcb );
  717. return STATUS_PENDING;
  718. }
  719. AcquiredFcb = TRUE;
  720. //
  721. // Recapture whether we need to write file size since dropping
  722. //
  723. if ((!FlagOn( Scb->ScbState, SCB_STATE_WRITE_FILESIZE_ON_CLOSE )) ||
  724. (Fcb->LinkCount == 0) ||
  725. (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED ))) {
  726. WriteFileSize = FALSE;
  727. }
  728. }
  729. if (ExclusiveVcb) {
  730. break;
  731. }
  732. //
  733. // Otherwise we need to confirm that our unsafe test above was correct.
  734. //
  735. if ((Fcb->LcbQueue.Flink != Fcb->LcbQueue.Blink) ||
  736. FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT )) {
  737. NeedVcbExclusive = TRUE;
  738. NtfsReleaseFcbWithPaging( IrpContext, Fcb );
  739. NtfsReleaseVcb( IrpContext, Vcb );
  740. AcquiredFcb = FALSE;
  741. } else {
  742. break;
  743. }
  744. }
  745. //
  746. // Set the wait flag in the IrpContext so we can acquire any other files
  747. // we encounter.
  748. //
  749. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  750. try {
  751. //
  752. // See if we possibly have to do any Usn processing
  753. //
  754. if (Fcb->FcbUsnRecord != NULL) {
  755. //
  756. // If the file has no more user handles, but there is a pending Usn
  757. // update (this should normally only happen if a stream was mapped
  758. // by the user), then scan the streams to see if there are any
  759. // remaining datasections, and if not then post the close.
  760. //
  761. if ((Fcb->CleanupCount == 0) &&
  762. (Fcb->FcbUsnRecord->UsnRecord.Reason != 0)) {
  763. if (!FlagOn( Vcb->VcbState, VCB_STATE_LOCKED ) &&
  764. !FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED ) &&
  765. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_FAILED_CLOSE )) {
  766. PSCB TempScb;
  767. //
  768. // Leave if there are any streams with user-mapped files.
  769. //
  770. TempScb = (PSCB)CONTAINING_RECORD( Fcb->ScbQueue.Flink,
  771. SCB,
  772. FcbLinks );
  773. while (&TempScb->FcbLinks != &Fcb->ScbQueue) {
  774. if ((TempScb->NonpagedScb->SegmentObject.DataSectionObject != NULL) &&
  775. !MmCanFileBeTruncated( &TempScb->NonpagedScb->SegmentObject, &Li0)) {
  776. goto NoPost;
  777. }
  778. TempScb = (PSCB)CONTAINING_RECORD( TempScb->FcbLinks.Flink,
  779. SCB,
  780. FcbLinks );
  781. }
  782. //
  783. // If we are not supposed to wait, then we should force this request to
  784. // be posted. All recursive closes will go here since they are async
  785. //
  786. if (FlagOn( AcquireFlags, ACQUIRE_DONT_WAIT )) {
  787. Status = STATUS_PENDING;
  788. leave;
  789. }
  790. //
  791. // We cannot generate logfile fulls in a regular thread with a recursive close
  792. // safely without deadlocking
  793. //
  794. ASSERT( NtfsIsTopLevelRequest( IrpContext ) ||
  795. FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ) );
  796. //
  797. // Protect the call to the Usn routines with a try-except. If we hit
  798. // any non-fatal error then set the IrpContext flag which indicates
  799. // not to bother with the Usn and force a retry.
  800. //
  801. try {
  802. //
  803. // Now try to actually post the change.
  804. //
  805. NtfsPostUsnChange( IrpContext, Fcb, USN_REASON_CLOSE );
  806. //
  807. // Now write the journal, checkpoint the transaction, and free the UsnJournal to
  808. // reduce contention. We force the write now, because the Fcb may get deleted
  809. // before we normally would write the changes when the transaction commits.
  810. //
  811. NtfsWriteUsnJournalChanges( IrpContext );
  812. NtfsCheckpointCurrentTransaction( IrpContext );
  813. } except( (!FsRtlIsNtstatusExpected( Status = GetExceptionCode() ) ||
  814. (Status == STATUS_LOG_FILE_FULL) ||
  815. (Status == STATUS_CANT_WAIT)) ?
  816. EXCEPTION_CONTINUE_SEARCH :
  817. EXCEPTION_EXECUTE_HANDLER ) {
  818. //
  819. // We got some sort of error processing the Usn journal. We can't
  820. // handle it in the close path. Let's retry this request but don't
  821. // try to do the Usn operation.
  822. //
  823. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_FAILED_CLOSE );
  824. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  825. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  826. }
  827. //
  828. // Free any remaining resources before decrementing close counts below,
  829. // except for our Fcb. This reduces contention via the Usn Journal and
  830. // prevents deadlocks since the Usn Journal is acquired last.
  831. //
  832. ASSERT(Fcb->ExclusiveFcbLinks.Flink != NULL);
  833. while (!IsListEmpty(&IrpContext->ExclusiveFcbList)) {
  834. if (&Fcb->ExclusiveFcbLinks == IrpContext->ExclusiveFcbList.Flink) {
  835. RemoveEntryList( &Fcb->ExclusiveFcbLinks );
  836. Fcb->ExclusiveFcbLinks.Flink = NULL;
  837. } else {
  838. NtfsReleaseFcb( IrpContext,
  839. (PFCB)CONTAINING_RECORD(IrpContext->ExclusiveFcbList.Flink,
  840. FCB,
  841. ExclusiveFcbLinks ));
  842. }
  843. }
  844. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_USN_JRNL |
  845. IRP_CONTEXT_FLAG_RELEASE_MFT );
  846. //
  847. // Now reinsert our Fcb if we removed it from the list. Check the Flink
  848. // field to know if this is the case. Otherwise a higher level IrpContext
  849. // will own this.
  850. //
  851. if (Fcb->ExclusiveFcbLinks.Flink == NULL) {
  852. InsertTailList( &IrpContext->ExclusiveFcbList, &Fcb->ExclusiveFcbLinks );
  853. }
  854. //
  855. // Escape here if we are not posting the close due to a user-mapped file.
  856. //
  857. NoPost: NOTHING;
  858. }
  859. }
  860. }
  861. //
  862. // Now rewrite the filesizes if we have to
  863. //
  864. if (WriteFileSize) {
  865. ASSERT( IrpContext->CleanupStructure != NULL );
  866. //
  867. // If the call to write the file size or the commit produces a logfile full
  868. // we must retry in the fsp thread to prevent deadlocking from
  869. // a recursive caller's already owning the vcb and an attempt to
  870. // checkpoint
  871. //
  872. try {
  873. NtfsWriteFileSizes( IrpContext, Scb, &Scb->Header.ValidDataLength.QuadPart, TRUE, TRUE, FALSE );
  874. NtfsCheckpointCurrentTransaction( IrpContext );
  875. ClearFlag( Scb->ScbState, SCB_STATE_WRITE_FILESIZE_ON_CLOSE );
  876. } except( (Status = GetExceptionCode()), (Status != STATUS_LOG_FILE_FULL || FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP )) ?
  877. EXCEPTION_CONTINUE_SEARCH :
  878. EXCEPTION_EXECUTE_HANDLER ) {
  879. NtfsMinimumExceptionProcessing( IrpContext );
  880. Status = STATUS_PENDING;
  881. }
  882. if (Status == STATUS_PENDING) {
  883. leave;
  884. }
  885. } // endif writing filesize
  886. //
  887. // We take the same action for all open files. We
  888. // delete the Ccb if present, and we decrement the close
  889. // file counts.
  890. //
  891. if ((*Ccb) != NULL) {
  892. Lcb = (*Ccb)->Lcb;
  893. NtfsUnlinkCcbFromLcb( IrpContext, Fcb, (*Ccb) );
  894. NtfsDeleteCcb( Fcb, Ccb );
  895. } else {
  896. Lcb = NULL;
  897. }
  898. SystemFile = FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) || (TypeOfOpen == StreamFileOpen);
  899. NtfsDecrementCloseCounts( IrpContext,
  900. Scb,
  901. Lcb,
  902. SystemFile,
  903. ReadOnly,
  904. FALSE,
  905. &RemovedFcb );
  906. //
  907. // Now that we're holding the Vcb, and we're past the point where we might
  908. // raise log file full, we can safely adjust this field.
  909. //
  910. if (CalledFromFsp) {
  911. InterlockedDecrement( &Vcb->QueuedCloseCount );
  912. }
  913. //
  914. // If we had to write a log record for close, it can only be for duplicate
  915. // information. We will commit that transaction here and remove
  916. // the entry from the transaction table. We do it here so we won't
  917. // fail inside the 'except' of a 'try-except'.
  918. //
  919. if (IrpContext->TransactionId != 0) {
  920. try {
  921. NtfsCommitCurrentTransaction( IrpContext );
  922. } except( EXCEPTION_EXECUTE_HANDLER ) {
  923. NtfsMinimumExceptionProcessing( IrpContext );
  924. if (IrpContext->TransactionId != 0) {
  925. NtfsCleanupFailedTransaction( IrpContext );
  926. }
  927. }
  928. }
  929. } finally {
  930. DebugUnwind( NtfsCommonClose );
  931. //
  932. // Manage fcb explictly because we recursively come into this path
  933. // and its cleaner to release the fcb at the same level in which you acquire it
  934. //
  935. if (AcquiredFcb && !RemovedFcb) {
  936. NtfsReleaseFcbWithPaging( IrpContext, Fcb );
  937. }
  938. if (ExclusiveVcb) {
  939. NtfsReleaseVcbCheckDelete( IrpContext, Vcb, IRP_MJ_CLOSE, NULL );
  940. } else {
  941. NtfsReleaseVcb( IrpContext, Vcb );
  942. }
  943. DebugTrace( -1, Dbg, ("NtfsCommonClose -> returning\n") );
  944. }
  945. return Status;
  946. }
  947. //
  948. // Internal support routine, spinlock wrapper.
  949. //
  950. VOID
  951. NtfsQueueClose (
  952. IN PIRP_CONTEXT IrpContext,
  953. IN BOOLEAN DelayClose
  954. )
  955. {
  956. KIRQL SavedIrql;
  957. BOOLEAN StartWorker = FALSE;
  958. InterlockedIncrement( &(IrpContext->Vcb->QueuedCloseCount) );
  959. if (DelayClose) {
  960. //
  961. // Increment the delayed close count for the Fcb for this
  962. // file.
  963. //
  964. InterlockedIncrement( &((PSCB) IrpContext->OriginatingIrp)->Fcb->DelayedCloseCount );
  965. ASSERT( IsListEmpty( &IrpContext->ExclusiveFcbList ) );
  966. ASSERT( IsListEmpty( &IrpContext->RecentlyDeallocatedQueue ) );
  967. RtlZeroMemory( &IrpContext->WorkQueueItem, sizeof( WORK_QUEUE_ITEM ));
  968. SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  969. InsertTailList( &NtfsData.DelayedCloseList,
  970. &IrpContext->WorkQueueItem.List );
  971. NtfsData.DelayedCloseCount += 1;
  972. if (NtfsData.DelayedCloseCount > NtfsMaxDelayedCloseCount) {
  973. NtfsData.ReduceDelayedClose = TRUE;
  974. if (!NtfsData.AsyncCloseActive) {
  975. NtfsData.AsyncCloseActive = TRUE;
  976. StartWorker = TRUE;
  977. }
  978. }
  979. } else {
  980. SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  981. ASSERT( IsListEmpty( &IrpContext->ExclusiveFcbList ) );
  982. ASSERT( IsListEmpty( &IrpContext->RecentlyDeallocatedQueue ) );
  983. RtlZeroMemory( &IrpContext->WorkQueueItem, sizeof( WORK_QUEUE_ITEM ));
  984. InsertTailList( &NtfsData.AsyncCloseList,
  985. &IrpContext->WorkQueueItem.List );
  986. NtfsData.AsyncCloseCount += 1;
  987. if (!NtfsData.AsyncCloseActive) {
  988. NtfsData.AsyncCloseActive = TRUE;
  989. StartWorker = TRUE;
  990. }
  991. }
  992. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, SavedIrql );
  993. if (StartWorker) {
  994. ExQueueWorkItem( &NtfsData.NtfsCloseItem, CriticalWorkQueue );
  995. }
  996. }
  997. //
  998. // Internal support routine, spinlock wrapper.
  999. //
  1000. PIRP_CONTEXT
  1001. NtfsRemoveClose (
  1002. IN PVCB Vcb OPTIONAL,
  1003. IN BOOLEAN ThrottleCreate
  1004. )
  1005. {
  1006. PLIST_ENTRY Entry;
  1007. KIRQL SavedIrql;
  1008. PIRP_CONTEXT IrpContext = NULL;
  1009. BOOLEAN FromDelayedClose = FALSE;
  1010. SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  1011. //
  1012. // First check the list of async closes.
  1013. //
  1014. if (!IsListEmpty( &NtfsData.AsyncCloseList )) {
  1015. Entry = NtfsData.AsyncCloseList.Flink;
  1016. while (Entry != &NtfsData.AsyncCloseList) {
  1017. //
  1018. // Extract the IrpContext.
  1019. //
  1020. IrpContext = CONTAINING_RECORD( Entry,
  1021. IRP_CONTEXT,
  1022. WorkQueueItem.List );
  1023. //
  1024. // If no Vcb was specified or this Vcb is for our volume
  1025. // then perform the close.
  1026. //
  1027. if (!ARGUMENT_PRESENT( Vcb ) ||
  1028. IrpContext->Vcb == Vcb) {
  1029. RemoveEntryList( Entry );
  1030. NtfsData.AsyncCloseCount -= 1;
  1031. break;
  1032. } else {
  1033. IrpContext = NULL;
  1034. Entry = Entry->Flink;
  1035. }
  1036. }
  1037. }
  1038. //
  1039. // If we didn't find anything look through the delayed close
  1040. // queue.
  1041. //
  1042. if (IrpContext == NULL) {
  1043. //
  1044. // Now check our delayed close list.
  1045. //
  1046. if (ARGUMENT_PRESENT( Vcb )) {
  1047. Entry = NtfsData.DelayedCloseList.Flink;
  1048. IrpContext = NULL;
  1049. //
  1050. // If we were given a Vcb, only do the closes for this volume.
  1051. //
  1052. while (Entry != &NtfsData.DelayedCloseList) {
  1053. //
  1054. // Extract the IrpContext.
  1055. //
  1056. IrpContext = CONTAINING_RECORD( Entry,
  1057. IRP_CONTEXT,
  1058. WorkQueueItem.List );
  1059. //
  1060. // Is this close on our volume?
  1061. //
  1062. if (IrpContext->Vcb == Vcb) {
  1063. RemoveEntryList( Entry );
  1064. NtfsData.DelayedCloseCount -= 1;
  1065. FromDelayedClose = TRUE;
  1066. break;
  1067. } else {
  1068. IrpContext = NULL;
  1069. Entry = Entry->Flink;
  1070. }
  1071. }
  1072. //
  1073. // Check if need to reduce the delayed close count.
  1074. //
  1075. } else if (NtfsData.ReduceDelayedClose) {
  1076. if (NtfsData.DelayedCloseCount > NtfsMinDelayedCloseCount) {
  1077. //
  1078. // Do any closes over the limit.
  1079. //
  1080. Entry = RemoveHeadList( &NtfsData.DelayedCloseList );
  1081. NtfsData.DelayedCloseCount -= 1;
  1082. //
  1083. // Extract the IrpContext.
  1084. //
  1085. IrpContext = CONTAINING_RECORD( Entry,
  1086. IRP_CONTEXT,
  1087. WorkQueueItem.List );
  1088. FromDelayedClose = TRUE;
  1089. } else {
  1090. NtfsData.ReduceDelayedClose = FALSE;
  1091. }
  1092. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1093. } else {
  1094. ASSERT( NtfsData.DelayedCloseCount <= NtfsMaxDelayedCloseCount );
  1095. #endif
  1096. }
  1097. }
  1098. //
  1099. // If this is the delayed close case then decrement the delayed close count
  1100. // on this Fcb.
  1101. //
  1102. if (FromDelayedClose) {
  1103. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, SavedIrql );
  1104. InterlockedDecrement( &((PSCB) IrpContext->OriginatingIrp)->Fcb->DelayedCloseCount );
  1105. //
  1106. // If we are returning NULL, show that we are done.
  1107. //
  1108. } else {
  1109. if (!ARGUMENT_PRESENT( Vcb ) &&
  1110. (IrpContext == NULL) &&
  1111. !ThrottleCreate) {
  1112. NtfsData.AsyncCloseActive = FALSE;
  1113. }
  1114. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, SavedIrql );
  1115. }
  1116. if (IrpContext != NULL) {
  1117. //
  1118. // Reset the shared fields
  1119. //
  1120. InitializeListHead( &IrpContext->RecentlyDeallocatedQueue );
  1121. InitializeListHead( &IrpContext->ExclusiveFcbList );
  1122. }
  1123. ASSERT( (Vcb == NULL) || NtfsIsExclusiveVcb( Vcb ) || (IrpContext == NULL) );
  1124. return IrpContext;
  1125. }
  1126. #ifdef LFS_CLUSTER_CHECK
  1127. LONG
  1128. NtfsFspCloseExceptionFilter (
  1129. IN PIRP_CONTEXT IrpContext OPTIONAL,
  1130. IN PEXCEPTION_POINTERS ExceptionPointer
  1131. )
  1132. {
  1133. NTSTATUS ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
  1134. ASSERT( (ExceptionCode == STATUS_SUCCESS) ||
  1135. (ExceptionCode == STATUS_LOG_FILE_FULL) ||
  1136. (ExceptionCode == STATUS_CANT_WAIT) );
  1137. return NtfsExceptionFilter( IrpContext, ExceptionPointer );
  1138. }
  1139. #endif