[NTFS] - Fix some errors that break building in C89 mode, and remove an extraneous...
[reactos.git] / drivers / filesystems / cdfs_new / close.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 Close.c
8
9 Abstract:
10
11 This module implements the File Close routine for Cdfs called by the
12 Fsd/Fsp dispatch routines.
13
14 The close operation interacts with both the async and delayed close queues
15 in the CdData structure. Since close may be called recursively we may
16 violate the locking order in acquiring the Vcb or Fcb. In this case
17 we may move the request to the async close queue. If this is the last
18 reference on the Fcb and there is a chance the user may reopen this
19 file again soon we would like to defer the close. In this case we
20 may move the request to the async close queue.
21
22 Once we are past the decode file operation there is no need for the
23 file object. If we are moving the request to either of the work
24 queues then we remember all of the information from the file object and
25 complete the request with STATUS_SUCCESS. The Io system can then
26 reuse the file object and we can complete the request when convenient.
27
28 The async close queue consists of requests which we would like to
29 complete as soon as possible. They are queued using the original
30 IrpContext where some of the fields have been overwritten with
31 information from the file object. We will extract this information,
32 cleanup the IrpContext and then call the close worker routine.
33
34 The delayed close queue consists of requests which we would like to
35 defer the close for. We keep size of this list within a range
36 determined by the size of the system. We let it grow to some maximum
37 value and then shrink to some minimum value. We allocate a small
38 structure which contains the key information from the file object
39 and use this information along with an IrpContext on the stack
40 to complete the request.
41
42
43 --*/
44
45 #include "CdProcs.h"
46
47 //
48 // The Bug check file id for this module
49 //
50
51 #define BugCheckFileId (CDFS_BUG_CHECK_CLOSE)
52
53 //
54 // Local support routines
55 //
56
57 BOOLEAN
58 CdCommonClosePrivate (
59 IN PIRP_CONTEXT IrpContext,
60 IN PVCB Vcb,
61 IN PFCB Fcb,
62 IN ULONG UserReference,
63 IN BOOLEAN FromFsd
64 );
65
66 VOID
67 CdQueueClose (
68 IN PIRP_CONTEXT IrpContext,
69 IN PFCB Fcb,
70 IN ULONG UserReference,
71 IN BOOLEAN DelayedClose
72 );
73
74 PIRP_CONTEXT
75 CdRemoveClose (
76 IN PVCB Vcb OPTIONAL
77 );
78
79 VOID
80 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
81 CdCloseWorker (
82 IN PDEVICE_OBJECT DeviceObject,
83 IN PVOID Context
84 );
85
86 #ifdef ALLOC_PRAGMA
87 #pragma alloc_text(PAGE, CdCommonClose)
88 #pragma alloc_text(PAGE, CdCommonClosePrivate)
89 #pragma alloc_text(PAGE, CdQueueClose)
90 #pragma alloc_text(PAGE, CdRemoveClose)
91 #pragma alloc_text(PAGE, CdCloseWorker)
92 #endif
93
94
95 VOID
96 CdFspClose (
97 IN PVCB Vcb OPTIONAL
98 )
99
100 /*++
101
102 Routine Description:
103
104 This routine is called to process the close queues in the CdData. If the
105 Vcb is passed then we want to remove all of the closes for this Vcb.
106 Otherwise we will do as many of the delayed closes as we need to do.
107
108 Arguments:
109
110 Vcb - If specified then we are looking for all of the closes for the
111 given Vcb.
112
113 Return Value:
114
115 None
116
117 --*/
118
119 {
120 PIRP_CONTEXT IrpContext;
121 IRP_CONTEXT StackIrpContext;
122
123 THREAD_CONTEXT ThreadContext;
124
125 PFCB Fcb;
126 ULONG UserReference;
127
128 ULONG VcbHoldCount = 0;
129 PVCB CurrentVcb = NULL;
130
131 BOOLEAN PotentialVcbTeardown = FALSE;
132
133 PAGED_CODE();
134
135 FsRtlEnterFileSystem();
136
137 //
138 // Continue processing until there are no more closes to process.
139 //
140 /* ReactOS Change: "GCC suggest parentheses around assignment used as truth value" */
141 while ((IrpContext = CdRemoveClose( Vcb ))) {
142
143 //
144 // If we don't have an IrpContext then use the one on the stack.
145 // Initialize it for this request.
146 //
147
148 if (SafeNodeType( IrpContext ) != CDFS_NTC_IRP_CONTEXT ) {
149
150 //
151 // Update the local values from the IrpContextLite.
152 //
153
154 Fcb = ((PIRP_CONTEXT_LITE) IrpContext)->Fcb;
155 UserReference = ((PIRP_CONTEXT_LITE) IrpContext)->UserReference;
156
157 //
158 // Update the stack irp context with the values from the
159 // IrpContextLite.
160 //
161
162 CdInitializeStackIrpContext( &StackIrpContext,
163 (PIRP_CONTEXT_LITE) IrpContext );
164
165 //
166 // Free the IrpContextLite.
167 //
168
169 CdFreeIrpContextLite( IrpContext ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
170
171 //
172 // Remember we have the IrpContext from the stack.
173 //
174
175 IrpContext = &StackIrpContext;
176
177 //
178 // Otherwise cleanup the existing IrpContext.
179 //
180
181 } else {
182
183 //
184 // Remember the Fcb and user reference count.
185 //
186
187 Fcb = (PFCB) IrpContext->Irp;
188 IrpContext->Irp = NULL;
189
190 UserReference = (ULONG) IrpContext->ExceptionStatus;
191 IrpContext->ExceptionStatus = STATUS_SUCCESS;
192 }
193
194 //
195 // We have an IrpContext. Now we need to set the top level thread
196 // context.
197 //
198
199 SetFlag( IrpContext->Flags, IRP_CONTEXT_FSP_FLAGS );
200
201 //
202 // If we were given a Vcb then there is a request on top of this.
203 //
204
205 if (ARGUMENT_PRESENT( Vcb )) {
206
207 ClearFlag( IrpContext->Flags,
208 IRP_CONTEXT_FLAG_TOP_LEVEL | IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS );
209 }
210
211 CdSetThreadContext( IrpContext, &ThreadContext );
212
213 //
214 // If we have hit the maximum number of requests to process without
215 // releasing the Vcb then release the Vcb now. If we are holding
216 // a different Vcb to this one then release the previous Vcb.
217 //
218 // In either case acquire the current Vcb.
219 //
220 // We use the MinDelayedCloseCount from the CdData since it is
221 // a convenient value based on the system size. Only thing we are trying
222 // to do here is prevent this routine starving other threads which
223 // may need this Vcb exclusively.
224 //
225 // Note that the check for potential teardown below is unsafe. We'll
226 // repeat later within the cddata lock.
227 //
228
229 PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) &&
230 (Fcb->Vcb->VcbCondition != VcbMounted) &&
231 (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
232 (Fcb->Vcb->VcbCleanup == 0);
233
234 if (PotentialVcbTeardown ||
235 (VcbHoldCount > CdData.MinDelayedCloseCount) ||
236 (Fcb->Vcb != CurrentVcb)) {
237
238 if (CurrentVcb != NULL) {
239
240 CdReleaseVcb( IrpContext, CurrentVcb );
241 }
242
243 if (PotentialVcbTeardown) {
244
245 CdAcquireCdData( IrpContext );
246
247 //
248 // Repeat the checks with global lock held. The volume could have
249 // been remounted while we didn't hold the lock.
250 //
251
252 PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) &&
253 (Fcb->Vcb->VcbCondition != VcbMounted) &&
254 (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
255 (Fcb->Vcb->VcbCleanup == 0);
256
257 if (!PotentialVcbTeardown) {
258
259 CdReleaseCdData( IrpContext);
260 }
261 }
262
263 CurrentVcb = Fcb->Vcb;
264 CdAcquireVcbShared( IrpContext, CurrentVcb, FALSE );
265
266 VcbHoldCount = 0;
267
268 } else {
269
270 VcbHoldCount += 1;
271 }
272
273 //
274 // Call our worker routine to perform the close operation.
275 //
276
277 CdCommonClosePrivate( IrpContext, CurrentVcb, Fcb, UserReference, FALSE );
278
279 //
280 // If the reference count on this Vcb is below our residual reference
281 // then check if we should dismount the volume.
282 //
283
284 if (PotentialVcbTeardown) {
285
286 CdReleaseVcb( IrpContext, CurrentVcb );
287 CdCheckForDismount( IrpContext, CurrentVcb, FALSE );
288
289 CurrentVcb = NULL;
290
291 CdReleaseCdData( IrpContext );
292 PotentialVcbTeardown = FALSE;
293 }
294
295 //
296 // Complete the current request to cleanup the IrpContext.
297 //
298
299 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
300 }
301
302 //
303 // Release any Vcb we may still hold.
304 //
305
306 if (CurrentVcb != NULL) {
307
308 CdReleaseVcb( IrpContext, CurrentVcb );
309
310 }
311
312 FsRtlExitFileSystem();
313 }
314
315
316 NTSTATUS
317 CdCommonClose (
318 IN PIRP_CONTEXT IrpContext,
319 IN PIRP Irp
320 )
321
322 /*++
323
324 Routine Description:
325
326 This routine is the Fsd entry for the close operation. We decode the file
327 object to find the CDFS structures and type of open. We call our internal
328 worker routine to perform the actual work. If the work wasn't completed
329 then we post to one of our worker queues. The Ccb isn't needed after this
330 point so we delete the Ccb and return STATUS_SUCCESS to our caller in all
331 cases.
332
333 Arguments:
334
335 Irp - Supplies the Irp to process
336
337 Return Value:
338
339 STATUS_SUCCESS
340
341 --*/
342
343 {
344 TYPE_OF_OPEN TypeOfOpen;
345
346 PVCB Vcb;
347 PFCB Fcb;
348 PCCB Ccb;
349 ULONG UserReference = 0;
350
351 BOOLEAN PotentialVcbTeardown = FALSE;
352 BOOLEAN ForceDismount = FALSE;
353
354 PAGED_CODE();
355
356 ASSERT_IRP_CONTEXT( IrpContext );
357 ASSERT_IRP( Irp );
358
359 //
360 // If we were called with our file system device object instead of a
361 // volume device object, just complete this request with STATUS_SUCCESS.
362 //
363
364 if (IrpContext->Vcb == NULL) {
365
366 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
367 return STATUS_SUCCESS;
368 }
369
370 //
371 // Decode the file object to get the type of open and Fcb/Ccb.
372 //
373
374 TypeOfOpen = CdDecodeFileObject( IrpContext,
375 IoGetCurrentIrpStackLocation( Irp )->FileObject,
376 &Fcb,
377 &Ccb );
378
379 //
380 // No work to do for unopened file objects.
381 //
382
383 if (TypeOfOpen == UnopenedFileObject) {
384
385 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
386
387 return STATUS_SUCCESS;
388 }
389
390 Vcb = Fcb->Vcb;
391
392 //
393 // Clean up any CCB associated with this open.
394 //
395
396 if (Ccb != NULL) {
397
398 UserReference = 1;
399
400 //
401 // Was a FSCTL_DISMOUNT issued on this handle? If so, we need to
402 // force a dismount of the volume now.
403 //
404
405 ForceDismount = BooleanFlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE);
406
407 //
408 // We can always deallocate the Ccb if present.
409 //
410
411 CdDeleteCcb( IrpContext, Ccb );
412 }
413
414 //
415 // If this is the last reference to a user file or directory on a
416 // currently mounted volume, then post it to the delayed close queue. Note
417 // that the VcbCondition check is unsafe, but it doesn't really matter -
418 // we just might delay the volume teardown a little by posting this close.
419 //
420
421 if ((Vcb->VcbCondition == VcbMounted) &&
422 (Fcb->FcbReference == 1) &&
423 ((TypeOfOpen == UserFileOpen) ||
424 (TypeOfOpen == UserDirectoryOpen))) {
425
426 CdQueueClose( IrpContext, Fcb, UserReference, TRUE );
427 IrpContext = NULL;
428
429 //
430 // Otherwise try to process this close. Post to the async close queue
431 // if we can't acquire all of the resources.
432 //
433
434 } else {
435
436 //
437 // If we may be dismounting this volume then acquire the CdData
438 // resource.
439 //
440 // Since we now must make volumes go away as soon as reasonable after
441 // the last user handles closes, key off of the cleanup count. It is
442 // OK to do this more than necessary. Since this Fcb could be holding
443 // a number of other Fcbs (and thus their references), a simple check
444 // on reference count is not appropriate.
445 //
446 // Do an unsafe check first to avoid taking the (global) cddata lock in the
447 // common case.
448 //
449
450 if (((Vcb->VcbCleanup == 0) || ForceDismount) &&
451 (Vcb->VcbCondition != VcbMounted)) {
452
453 //
454 // Possible. Acquire CdData to synchronise with the remount path, and
455 // then repeat the tests.
456 //
457 // Note that we must send the notification outside of any locks, since
458 // the worker that processes the notify could also be calling into our
459 // pnp path which wants both CdData and VcbResource. For a force dismount
460 // the volume will be marked invalid (no going back), so we will definitely
461 // go ahead and dismount below.
462 //
463
464 if (ForceDismount) {
465
466 //
467 // Send notification.
468 //
469
470 FsRtlNotifyVolumeEvent( IoGetCurrentIrpStackLocation( Irp )->FileObject,
471 FSRTL_VOLUME_DISMOUNT );
472 }
473
474 CdAcquireCdData( IrpContext );
475
476 if (((Vcb->VcbCleanup == 0) || ForceDismount) &&
477 (Vcb->VcbCondition != VcbMounted) &&
478 (Vcb->VcbCondition != VcbMountInProgress) &&
479 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS )) {
480
481 PotentialVcbTeardown = TRUE;
482 }
483 else {
484
485 //
486 // We can't dismount this volume now, there are other references or
487 // it's just been remounted.
488 //
489
490 CdReleaseCdData( IrpContext);
491 }
492 }
493
494 if (ForceDismount) {
495
496 //
497 // Physically disconnect this Vcb from the device so a new mount can
498 // occur. Vcb deletion cannot happen at this time since there is
499 // a handle on it associated with this very request, but we'll call
500 // check for dismount again later anyway.
501 //
502
503 CdCheckForDismount( IrpContext, Vcb, TRUE );
504 }
505
506 //
507 // Call the worker routine to perform the actual work. This routine
508 // should never raise except for a fatal error.
509 //
510
511 if (!CdCommonClosePrivate( IrpContext, Vcb, Fcb, UserReference, TRUE )) {
512
513 //
514 // If we didn't complete the request then post the request as needed.
515 //
516
517 CdQueueClose( IrpContext, Fcb, UserReference, FALSE );
518 IrpContext = NULL;
519
520 //
521 // Check whether we should be dismounting the volume and then complete
522 // the request.
523 //
524
525 } else if (PotentialVcbTeardown) {
526
527 CdCheckForDismount( IrpContext, Vcb, FALSE );
528 }
529 }
530
531 //
532 // Always complete this request with STATUS_SUCCESS.
533 //
534
535 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
536
537 if (PotentialVcbTeardown) {
538
539 CdReleaseCdData( IrpContext );
540 }
541
542 //
543 // Always return STATUS_SUCCESS for closes.
544 //
545
546 return STATUS_SUCCESS;
547 }
548
549 \f
550 //
551 // Local support routine
552 //
553
554 BOOLEAN
555 CdCommonClosePrivate (
556 IN PIRP_CONTEXT IrpContext,
557 IN PVCB Vcb,
558 IN PFCB Fcb,
559 IN ULONG UserReference,
560 IN BOOLEAN FromFsd
561 )
562
563 /*++
564
565 Routine Description:
566
567 This is the worker routine for the close operation. We can be called in
568 an Fsd thread or from a worker Fsp thread. If called from the Fsd thread
569 then we acquire the resources without waiting. Otherwise we know it is
570 safe to wait.
571
572 We check to see whether we should post this request to the delayed close
573 queue. If we are to process the close here then we acquire the Vcb and
574 Fcb. We will adjust the counts and call our teardown routine to see
575 if any of the structures should go away.
576
577 Arguments:
578
579 Vcb - Vcb for this volume.
580
581 Fcb - Fcb for this request.
582
583 UserReference - Number of user references for this file object. This is
584 zero for an internal stream.
585
586 FromFsd - This request was called from an Fsd thread. Indicates whether
587 we should wait to acquire resources.
588
589 DelayedClose - Address to store whether we should try to put this on
590 the delayed close queue. Ignored if this routine can process this
591 close.
592
593 Return Value:
594
595 BOOLEAN - TRUE if this thread processed the close, FALSE otherwise.
596
597 --*/
598
599 {
600 BOOLEAN RemovedFcb;
601
602 PAGED_CODE();
603
604 ASSERT_IRP_CONTEXT( IrpContext );
605 ASSERT_FCB( Fcb );
606
607 //
608 // Try to acquire the Vcb and Fcb. If we can't acquire them then return
609 // and let our caller know he should post the request to the async
610 // queue.
611 //
612
613 if (CdAcquireVcbShared( IrpContext, Vcb, FromFsd )) {
614
615 if (!CdAcquireFcbExclusive( IrpContext, Fcb, FromFsd )) {
616
617 //
618 // We couldn't get the Fcb. Release the Vcb and let our caller
619 // know to post this request.
620 //
621
622 CdReleaseVcb( IrpContext, Vcb );
623 return FALSE;
624 }
625
626 //
627 // We didn't get the Vcb. Let our caller know to post this request.
628 //
629
630 } else {
631
632 return FALSE;
633 }
634
635 //
636 // Lock the Vcb and decrement the reference counts.
637 //
638
639 CdLockVcb( IrpContext, Vcb );
640 CdDecrementReferenceCounts( IrpContext, Fcb, 1, UserReference );
641 CdUnlockVcb( IrpContext, Vcb );
642
643 //
644 // Call our teardown routine to see if this object can go away.
645 // If we don't remove the Fcb then release it.
646 //
647
648 CdTeardownStructures( IrpContext, Fcb, &RemovedFcb );
649
650 if (!RemovedFcb) {
651
652 CdReleaseFcb( IrpContext, Fcb );
653 }
654
655 //
656 // Release the Vcb and return to our caller. Let him know we completed
657 // this request.
658 //
659
660 CdReleaseVcb( IrpContext, Vcb );
661
662 return TRUE;
663 }
664
665 VOID
666 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
667 CdCloseWorker (
668 IN PDEVICE_OBJECT DeviceObject,
669 IN PVOID Context
670 )
671 /*++
672
673 Routine Description:
674
675 Worker routine to call CsFspClose.
676
677 Arguments:
678
679 DeviceObject - Filesystem registration device object
680
681 Context - Callers context
682
683 Return Value:
684
685 None
686
687 --*/
688
689 {
690 CdFspClose (NULL);
691 }
692
693 \f
694 VOID
695 CdQueueClose (
696 IN PIRP_CONTEXT IrpContext,
697 IN PFCB Fcb,
698 IN ULONG UserReference,
699 IN BOOLEAN DelayedClose
700 )
701
702 /*++
703
704 Routine Description:
705
706 This routine is called to queue a request to either the async or delayed
707 close queue. For the delayed queue we need to allocate a smaller
708 structure to contain the information about the file object. We do
709 that so we don't put the larger IrpContext structures into this long
710 lived queue. If we can allocate this structure then we put this
711 on the async queue instead.
712
713 Arguments:
714
715 Fcb - Fcb for this file object.
716
717 UserReference - Number of user references for this file object. This is
718 zero for an internal stream.
719
720 DelayedClose - Indicates whether this should go on the async or delayed
721 close queue.
722
723 Return Value:
724
725 None
726
727 --*/
728
729 {
730 PIRP_CONTEXT_LITE IrpContextLite = NULL;
731 BOOLEAN StartWorker = FALSE;
732
733 PAGED_CODE();
734
735 ASSERT_IRP_CONTEXT( IrpContext );
736 ASSERT_FCB( Fcb );
737
738 //
739 // Start with the delayed queue request. We can move this to the async
740 // queue if there is an allocation failure.
741 //
742
743 if (DelayedClose) {
744
745 //
746 // Try to allocate non-paged pool for the IRP_CONTEXT_LITE.
747 //
748
749 IrpContextLite = CdCreateIrpContextLite( IrpContext );
750 }
751
752 //
753 // We want to clear the top level context in this thread if
754 // necessary. Call our cleanup routine to do the work.
755 //
756
757 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
758 CdCleanupIrpContext( IrpContext, TRUE );
759
760 //
761 // Synchronize with the CdData lock.
762 //
763
764 CdLockCdData();
765
766 //
767 // If we have an IrpContext then put the request on the delayed close queue.
768 //
769
770 if (IrpContextLite != NULL) {
771
772 //
773 // Initialize the IrpContextLite.
774 //
775
776 IrpContextLite->NodeTypeCode = CDFS_NTC_IRP_CONTEXT_LITE;
777 IrpContextLite->NodeByteSize = sizeof( IRP_CONTEXT_LITE );
778 IrpContextLite->Fcb = Fcb;
779 IrpContextLite->UserReference = UserReference;
780 IrpContextLite->RealDevice = IrpContext->RealDevice;
781
782 //
783 // Add this to the delayed close list and increment
784 // the count.
785 //
786
787 InsertTailList( &CdData.DelayedCloseQueue,
788 &IrpContextLite->DelayedCloseLinks );
789
790 CdData.DelayedCloseCount += 1;
791
792 //
793 // If we are above our threshold then start the delayed
794 // close operation.
795 //
796
797 if (CdData.DelayedCloseCount > CdData.MaxDelayedCloseCount) {
798
799 CdData.ReduceDelayedClose = TRUE;
800
801 if (!CdData.FspCloseActive) {
802
803 CdData.FspCloseActive = TRUE;
804 StartWorker = TRUE;
805 }
806 }
807
808 //
809 // Unlock the CdData.
810 //
811
812 CdUnlockCdData();
813
814 //
815 // Cleanup the IrpContext.
816 //
817
818 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
819
820 //
821 // Otherwise drop into the async case below.
822 //
823
824 } else {
825
826 //
827 // Store the information about the file object into the IrpContext.
828 //
829
830 IrpContext->Irp = (PIRP) Fcb;
831 IrpContext->ExceptionStatus = (NTSTATUS) UserReference;
832
833 //
834 // Add this to the async close list and increment the count.
835 //
836
837 InsertTailList( &CdData.AsyncCloseQueue,
838 &IrpContext->WorkQueueItem.List );
839
840 CdData.AsyncCloseCount += 1;
841
842 //
843 // Remember to start the Fsp close thread if not currently started.
844 //
845
846 if (!CdData.FspCloseActive) {
847
848 CdData.FspCloseActive = TRUE;
849
850 StartWorker = TRUE;
851 }
852
853 //
854 // Unlock the CdData.
855 //
856
857 CdUnlockCdData();
858 }
859
860 //
861 // Start the FspClose thread if we need to.
862 //
863
864 if (StartWorker) {
865
866 IoQueueWorkItem( CdData.CloseItem, CdCloseWorker, CriticalWorkQueue, NULL );
867 }
868
869 //
870 // Return to our caller.
871 //
872
873 return;
874 }
875
876 \f
877 //
878 // Local support routine
879 //
880
881 PIRP_CONTEXT
882 CdRemoveClose (
883 IN PVCB Vcb OPTIONAL
884 )
885
886 /*++
887
888 Routine Description:
889
890 Arguments:
891
892 This routine is called to scan the async and delayed close queues looking
893 for a suitable entry. If the Vcb is specified then we scan both queues
894 looking for an entry with the same Vcb. Otherwise we will look in the
895 async queue first for any close item. If none found there then we look
896 in the delayed close queue provided that we have triggered the delayed
897 close operation.
898
899 Return Value:
900
901 PIRP_CONTEXT - NULL if no work item found. Otherwise it is the pointer to
902 either the IrpContext or IrpContextLite for this request.
903
904 --*/
905
906 {
907 PIRP_CONTEXT IrpContext = NULL;
908 PIRP_CONTEXT NextIrpContext;
909 PIRP_CONTEXT_LITE NextIrpContextLite;
910
911 PLIST_ENTRY Entry;
912
913 PAGED_CODE();
914
915 ASSERT_OPTIONAL_VCB( Vcb );
916
917 //
918 // Lock the CdData to perform the scan.
919 //
920
921 CdLockCdData();
922
923 //
924 // First check the list of async closes.
925 //
926
927 Entry = CdData.AsyncCloseQueue.Flink;
928
929 while (Entry != &CdData.AsyncCloseQueue) {
930
931 //
932 // Extract the IrpContext.
933 //
934
935 NextIrpContext = CONTAINING_RECORD( Entry,
936 IRP_CONTEXT,
937 WorkQueueItem.List );
938
939 //
940 // If no Vcb was specified or this Vcb is for our volume
941 // then perform the close.
942 //
943
944 if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContext->Vcb == Vcb)) {
945
946 RemoveEntryList( Entry );
947 CdData.AsyncCloseCount -= 1;
948
949 IrpContext = NextIrpContext;
950 break;
951 }
952
953 //
954 // Move to the next entry.
955 //
956
957 Entry = Entry->Flink;
958 }
959
960 //
961 // If we didn't find anything look through the delayed close
962 // queue.
963 //
964 // We will only check the delayed close queue if we were given
965 // a Vcb or the delayed close operation is active.
966 //
967
968 if ((IrpContext == NULL) &&
969 (ARGUMENT_PRESENT( Vcb ) ||
970 (CdData.ReduceDelayedClose &&
971 (CdData.DelayedCloseCount > CdData.MinDelayedCloseCount)))) {
972
973 Entry = CdData.DelayedCloseQueue.Flink;
974
975 while (Entry != &CdData.DelayedCloseQueue) {
976
977 //
978 // Extract the IrpContext.
979 //
980
981 NextIrpContextLite = CONTAINING_RECORD( Entry,
982 IRP_CONTEXT_LITE,
983 DelayedCloseLinks );
984
985 //
986 // If no Vcb was specified or this Vcb is for our volume
987 // then perform the close.
988 //
989
990 if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContextLite->Fcb->Vcb == Vcb)) {
991
992 RemoveEntryList( Entry );
993 CdData.DelayedCloseCount -= 1;
994
995 IrpContext = (PIRP_CONTEXT) NextIrpContextLite;
996 break;
997 }
998
999 //
1000 // Move to the next entry.
1001 //
1002
1003 Entry = Entry->Flink;
1004 }
1005 }
1006
1007 //
1008 // If the Vcb wasn't specified and we couldn't find an entry
1009 // then turn off the Fsp thread.
1010 //
1011
1012 if (!ARGUMENT_PRESENT( Vcb ) && (IrpContext == NULL)) {
1013
1014 CdData.FspCloseActive = FALSE;
1015 CdData.ReduceDelayedClose = FALSE;
1016 }
1017
1018 //
1019 // Unlock the CdData.
1020 //
1021
1022 CdUnlockCdData();
1023
1024 return IrpContext;
1025 }
1026
1027
1028