1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     ResrcSup.c
8 
9 Abstract:
10 
11     This module implements the Fat Resource acquisition routines
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 #ifdef ALLOC_PRAGMA
19 #pragma alloc_text(PAGE, FatAcquireFcbForLazyWrite)
20 #pragma alloc_text(PAGE, FatAcquireFcbForReadAhead)
21 #pragma alloc_text(PAGE, FatAcquireExclusiveFcb)
22 #pragma alloc_text(PAGE, FatAcquireSharedFcb)
23 #pragma alloc_text(PAGE, FatAcquireSharedFcbWaitForEx)
24 #pragma alloc_text(PAGE, FatAcquireExclusiveVcb_Real)
25 #pragma alloc_text(PAGE, FatAcquireSharedVcb)
26 #pragma alloc_text(PAGE, FatNoOpAcquire)
27 #pragma alloc_text(PAGE, FatNoOpRelease)
28 #pragma alloc_text(PAGE, FatReleaseFcbFromLazyWrite)
29 #pragma alloc_text(PAGE, FatReleaseFcbFromReadAhead)
30 #pragma alloc_text(PAGE, FatAcquireForCcFlush)
31 #pragma alloc_text(PAGE, FatReleaseForCcFlush)
32 #pragma alloc_text(PAGE, FatFilterCallbackAcquireForCreateSection)
33 #endif
34 
35 _Requires_lock_held_(_Global_critical_region_)
36 _When_(return != FALSE && NoOpCheck != FALSE, _Acquires_exclusive_lock_(Vcb->Resource))
37 FINISHED
FatAcquireExclusiveVcb_Real(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN BOOLEAN NoOpCheck)38 FatAcquireExclusiveVcb_Real (
39     IN PIRP_CONTEXT IrpContext,
40     IN PVCB Vcb,
41     IN BOOLEAN NoOpCheck
42     )
43 
44 /*++
45 
46 Routine Description:
47 
48     This routine acquires exclusive access to the Vcb.
49 
50     After we acquire the resource check to see if this operation is legal.
51     If it isn't (ie. we get an exception), release the resource.
52 
53 Arguments:
54 
55     Vcb - Supplies the Vcb to acquire
56 
57     NoOpCheck - if TRUE then don't do any verification of the request/volume state.
58 
59 Return Value:
60 
61     FINISHED - TRUE if we have the resource and FALSE if we needed to block
62         for the resource but Wait is FALSE.
63 
64 --*/
65 
66 {
67     PAGED_CODE();
68 
69 #ifdef _MSC_VER
70 #pragma prefast( suppress: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
71 #endif
72     if (ExAcquireResourceExclusiveLite( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
73 
74         if (!NoOpCheck) {
75 
76             _SEH2_TRY {
77 
78                 FatVerifyOperationIsLegal( IrpContext );
79 
80             } _SEH2_FINALLY {
81 
82                 if ( _SEH2_AbnormalTermination() ) {
83 
84                     FatReleaseVcb( IrpContext, Vcb );
85                 }
86             } _SEH2_END;
87         }
88 
89         return TRUE;
90     }
91 
92     return FALSE;
93 }
94 
95 _Requires_lock_held_(_Global_critical_region_)
96 _When_(return != 0, _Acquires_shared_lock_(Vcb->Resource))
97 FINISHED
FatAcquireSharedVcb(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb)98 FatAcquireSharedVcb (
99     IN PIRP_CONTEXT IrpContext,
100     IN PVCB Vcb
101     )
102 
103 /*++
104 
105 Routine Description:
106 
107     This routine acquires shared access to the Vcb.
108 
109     After we acquire the resource check to see if this operation is legal.
110     If it isn't (ie. we get an exception), release the resource.
111 
112 Arguments:
113 
114     Vcb - Supplies the Vcb to acquire
115 
116 Return Value:
117 
118     FINISHED - TRUE if we have the resource and FALSE if we needed to block
119         for the resource but Wait is FALSE.
120 
121 --*/
122 
123 {
124     PAGED_CODE();
125 
126     if (ExAcquireResourceSharedLite( &Vcb->Resource,
127                                      BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
128 
129         _SEH2_TRY {
130 
131             FatVerifyOperationIsLegal( IrpContext );
132 
133         } _SEH2_FINALLY {
134 
135             if ( _SEH2_AbnormalTermination() ) {
136 
137                 FatReleaseVcb( IrpContext, Vcb );
138             }
139         } _SEH2_END;
140 
141         return TRUE;
142     }
143 
144     return FALSE;
145 }
146 
147 _Requires_lock_held_(_Global_critical_region_)
148 _Acquires_exclusive_lock_(*Fcb->Header.Resource)
149 FINISHED
FatAcquireExclusiveFcb(IN PIRP_CONTEXT IrpContext,IN PFCB Fcb)150 FatAcquireExclusiveFcb (
151     IN PIRP_CONTEXT IrpContext,
152     IN PFCB Fcb
153     )
154 
155 /*++
156 
157 Routine Description:
158 
159     This routine acquires exclusive access to the Fcb.
160 
161     After we acquire the resource check to see if this operation is legal.
162     If it isn't (ie. we get an exception), release the resource.
163 
164 Arguments:
165 
166     Fcb - Supplies the Fcb to acquire
167 
168 Return Value:
169 
170     FINISHED - TRUE if we have the resource and FALSE if we needed to block
171         for the resource but Wait is FALSE.
172 
173 --*/
174 
175 {
176     PAGED_CODE();
177 
178 RetryFcbExclusive:
179 
180 #ifdef _MSC_VER
181 #pragma prefast( suppress: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
182 #endif
183     if (ExAcquireResourceExclusiveLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
184 
185         //
186         //  Check for anything other than a non-cached write if the
187         //  async count is non-zero in the Fcb, or if others are waiting
188         //  for the resource.  Then wait for all outstanding I/O to finish,
189         //  drop the resource, and wait again.
190         //
191 
192         if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
193             ((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
194              !FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ||
195              (ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) ||
196              (ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) {
197 
198             KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
199                                    Executive,
200                                    KernelMode,
201                                    FALSE,
202                                    (PLARGE_INTEGER) NULL );
203 
204             FatReleaseFcb( IrpContext, Fcb );
205 
206             goto RetryFcbExclusive;
207         }
208 
209         _SEH2_TRY {
210 
211             FatVerifyOperationIsLegal( IrpContext );
212 
213         } _SEH2_FINALLY {
214 
215             if ( _SEH2_AbnormalTermination() ) {
216 
217                 FatReleaseFcb( IrpContext, Fcb );
218             }
219         } _SEH2_END;
220 
221         return TRUE;
222     }
223 
224     return FALSE;
225 }
226 
227 
228  _Requires_lock_held_(_Global_critical_region_)
229 _Acquires_shared_lock_(*Fcb->Header.Resource)
230 FINISHED
FatAcquireSharedFcb(IN PIRP_CONTEXT IrpContext,IN PFCB Fcb)231 FatAcquireSharedFcb (
232     IN PIRP_CONTEXT IrpContext,
233     IN PFCB Fcb
234     )
235 
236 /*++
237 
238 Routine Description:
239 
240     This routine acquires shared access to the Fcb.
241 
242     After we acquire the resource check to see if this operation is legal.
243     If it isn't (ie. we get an exception), release the resource.
244 
245 Arguments:
246 
247     Fcb - Supplies the Fcb to acquire
248 
249 Return Value:
250 
251     FINISHED - TRUE if we have the resource and FALSE if we needed to block
252         for the resource but Wait is FALSE.
253 
254 --*/
255 
256 {
257     PAGED_CODE();
258 
259 RetryFcbShared:
260 
261     if (ExAcquireResourceSharedLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
262 
263         //
264         //  Check for anything other than a non-cached write if the
265         //  async count is non-zero in the Fcb, or if others are waiting
266         //  for the resource.  Then wait for all outstanding I/O to finish,
267         //  drop the resource, and wait again.
268         //
269 
270         if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
271             ((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
272              !FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ||
273              (ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) ||
274              (ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) {
275 
276             KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
277                                    Executive,
278                                    KernelMode,
279                                    FALSE,
280                                    (PLARGE_INTEGER) NULL );
281 
282             FatReleaseFcb( IrpContext, Fcb );
283 
284             goto RetryFcbShared;
285         }
286 
287         _SEH2_TRY {
288 
289             FatVerifyOperationIsLegal( IrpContext );
290 
291         } _SEH2_FINALLY {
292 
293             if ( _SEH2_AbnormalTermination() ) {
294 
295                 FatReleaseFcb( IrpContext, Fcb );
296             }
297         } _SEH2_END;
298 
299 
300         return TRUE;
301 
302     } else {
303 
304         return FALSE;
305     }
306 }
307 
308 
309 _Requires_lock_held_(_Global_critical_region_)
310 _When_(return != 0, _Acquires_shared_lock_(*Fcb->Header.Resource))
311 FINISHED
FatAcquireSharedFcbWaitForEx(IN PIRP_CONTEXT IrpContext,IN PFCB Fcb)312 FatAcquireSharedFcbWaitForEx (
313     IN PIRP_CONTEXT IrpContext,
314     IN PFCB Fcb
315     )
316 
317 /*++
318 
319 Routine Description:
320 
321     This routine acquires shared access to the Fcb, waiting first for any
322     exclusive accessors to get the Fcb first.
323 
324     After we acquire the resource check to see if this operation is legal.
325     If it isn't (ie. we get an exception), release the resource.
326 
327 Arguments:
328 
329     Fcb - Supplies the Fcb to acquire
330 
331 Return Value:
332 
333     FINISHED - TRUE if we have the resource and FALSE if we needed to block
334         for the resource but Wait is FALSE.
335 
336 --*/
337 
338 {
339     PAGED_CODE();
340 
341     NT_ASSERT( FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) );
342     NT_ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
343 
344 RetryFcbSharedWaitEx:
345 
346     if (ExAcquireSharedWaitForExclusive( Fcb->Header.Resource, FALSE )) {
347 
348         //
349         //  Check for anything other than a non-cached write if the
350         //  async count is non-zero in the Fcb. Then wait for all
351         //  outstanding I/O to finish, drop the resource, and wait again.
352         //
353 
354         if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
355             (IrpContext->MajorFunction != IRP_MJ_WRITE)) {
356 
357             KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
358                                    Executive,
359                                    KernelMode,
360                                    FALSE,
361                                    (PLARGE_INTEGER) NULL );
362 
363             FatReleaseFcb( IrpContext, Fcb );
364 
365             goto RetryFcbSharedWaitEx;
366         }
367 
368         _SEH2_TRY {
369 
370             FatVerifyOperationIsLegal( IrpContext );
371 
372         } _SEH2_FINALLY {
373 
374             if ( _SEH2_AbnormalTermination() ) {
375 
376                 FatReleaseFcb( IrpContext, Fcb );
377             }
378         } _SEH2_END;
379 
380 
381         return TRUE;
382 
383     } else {
384 
385         return FALSE;
386     }
387 }
388 
389 
_Requires_lock_held_(_Global_critical_region_)390 _Requires_lock_held_(_Global_critical_region_)
391 BOOLEAN
392 NTAPI
393 FatAcquireFcbForLazyWrite (
394     IN PVOID Fcb,
395     IN BOOLEAN Wait
396     )
397 
398 /*++
399 
400 Routine Description:
401 
402     The address of this routine is specified when creating a CacheMap for
403     a file.  It is subsequently called by the Lazy Writer prior to its
404     performing lazy writes to the file.
405 
406 Arguments:
407 
408     Fcb - The Fcb which was specified as a context parameter for this
409           routine.
410 
411     Wait - TRUE if the caller is willing to block.
412 
413 Return Value:
414 
415     FALSE - if Wait was specified as FALSE and blocking would have
416             been required.  The Fcb is not acquired.
417 
418     TRUE - if the Fcb has been acquired
419 
420 --*/
421 
422 {
423     PAGED_CODE();
424 
425     //
426     //  Check here for the EA File.  It turns out we need the normal
427     //  resource shared in this case.  Otherwise we take the paging
428     //  I/O resource shared.
429     //
430 
431     //
432     //  Note that we do not need to disable APC delivery to guard
433     //  against a rogue user issuing a suspend APC. That is because
434     //  it is guaranteed that the caller is either in the system context,
435     //  to which a user cannot deliver a suspend APC, or the caller has
436     //  already disabled kernel APC delivery before calling. This is true
437     //  for all the other pre-acquire routines as well.
438     //
439 
440     if (!ExAcquireResourceSharedLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ?
441                                   ((PFCB)Fcb)->Header.Resource :
442                                   ((PFCB)Fcb)->Header.PagingIoResource,
443                                   Wait )) {
444 
445         return FALSE;
446     }
447 
448     //
449     // We assume the Lazy Writer only acquires this Fcb once.
450     // Therefore, it should be guaranteed that this flag is currently
451     // clear (the ASSERT), and then we will set this flag, to insure
452     // that the Lazy Writer will never try to advance Valid Data, and
453     // also not deadlock by trying to get the Fcb exclusive.
454     //
455 
456 
457     NT_ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB );
458     NT_ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == NULL );
459 
460     ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
461 
462     NT_ASSERT( NULL != PsGetCurrentThread() );
463 
464     if (NULL == FatData.LazyWriteThread) {
465 
466         FatData.LazyWriteThread = PsGetCurrentThread();
467     }
468 
469     //
470     //  This is a kludge because Cc is really the top level.  When it
471     //  enters the file system, we will think it is a resursive call
472     //  and complete the request with hard errors or verify.  It will
473     //  then have to deal with them, somehow....
474     //
475 
476     NT_ASSERT(IoGetTopLevelIrp() == NULL);
477 
478     IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
479 
480     return TRUE;
481 }
482 
483 
_Requires_lock_held_(_Global_critical_region_)484 _Requires_lock_held_(_Global_critical_region_)
485 VOID
486 NTAPI
487 FatReleaseFcbFromLazyWrite (
488     IN PVOID Fcb
489     )
490 
491 /*++
492 
493 Routine Description:
494 
495     The address of this routine is specified when creating a CacheMap for
496     a file.  It is subsequently called by the Lazy Writer after its
497     performing lazy writes to the file.
498 
499 Arguments:
500 
501     Fcb - The Fcb which was specified as a context parameter for this
502           routine.
503 
504 Return Value:
505 
506     None
507 
508 --*/
509 
510 {
511     PAGED_CODE();
512 
513     //
514     //  Assert that this really is an fcb and that this thread really owns
515     //  the lazy writer mark in the fcb.
516     //
517 
518     NT_ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB );
519     NT_ASSERT( NULL != PsGetCurrentThread() );
520     NT_ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == PsGetCurrentThread() );
521 
522     //
523     //  Release the lazy writer mark.
524     //
525 
526     ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = NULL;
527 
528     //
529     //  Check here for the EA File.  It turns out we needed the normal
530     //  resource shared in this case.  Otherwise it was the PagingIoResource.
531     //
532 
533     ExReleaseResourceLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ?
534                        ((PFCB)Fcb)->Header.Resource :
535                        ((PFCB)Fcb)->Header.PagingIoResource );
536 
537     //
538     //  Clear the kludge at this point.
539     //
540 
541     NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
542 
543     IoSetTopLevelIrp( NULL );
544 
545     return;
546 }
547 
548 
_Requires_lock_held_(_Global_critical_region_)549 _Requires_lock_held_(_Global_critical_region_)
550 BOOLEAN
551 NTAPI
552 FatAcquireFcbForReadAhead (
553     IN PVOID Fcb,
554     IN BOOLEAN Wait
555     )
556 
557 /*++
558 
559 Routine Description:
560 
561     The address of this routine is specified when creating a CacheMap for
562     a file.  It is subsequently called by the Lazy Writer prior to its
563     performing read ahead to the file.
564 
565 Arguments:
566 
567     Fcb - The Fcb which was specified as a context parameter for this
568           routine.
569 
570     Wait - TRUE if the caller is willing to block.
571 
572 Return Value:
573 
574     FALSE - if Wait was specified as FALSE and blocking would have
575             been required.  The Fcb is not acquired.
576 
577     TRUE - if the Fcb has been acquired
578 
579 --*/
580 
581 {
582     PAGED_CODE();
583 
584     //
585     //  We acquire the normal file resource shared here to synchronize
586     //  correctly with purges.
587     //
588 
589     //
590     //  Note that we do not need to disable APC delivery to guard
591     //  against a rogue user issuing a suspend APC. That is because
592     //  it is guaranteed that the caller is either in the system context,
593     //  to which a user cannot deliver a suspend APC, or the caller has
594     //  already disabled kernel APC delivery before calling. This is true
595     //  for all the other pre-acquire routines as well.
596     //
597 
598     if (!ExAcquireResourceSharedLite( ((PFCB)Fcb)->Header.Resource,
599                                   Wait )) {
600 
601         return FALSE;
602     }
603 
604     //
605     //  This is a kludge because Cc is really the top level.  We it
606     //  enters the file system, we will think it is a resursive call
607     //  and complete the request with hard errors or verify.  It will
608     //  have to deal with them, somehow....
609     //
610 
611     NT_ASSERT(IoGetTopLevelIrp() == NULL);
612 
613     IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
614 
615     return TRUE;
616 }
617 
618 
_Requires_lock_held_(_Global_critical_region_)619 _Requires_lock_held_(_Global_critical_region_)
620 VOID
621 NTAPI
622 FatReleaseFcbFromReadAhead (
623     IN PVOID Fcb
624     )
625 
626 /*++
627 
628 Routine Description:
629 
630     The address of this routine is specified when creating a CacheMap for
631     a file.  It is subsequently called by the Lazy Writer after its
632     read ahead.
633 
634 Arguments:
635 
636     Fcb - The Fcb which was specified as a context parameter for this
637           routine.
638 
639 Return Value:
640 
641     None
642 
643 --*/
644 
645 {
646     PAGED_CODE();
647 
648     //
649     //  Clear the kludge at this point.
650     //
651 
652     NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
653 
654     IoSetTopLevelIrp( NULL );
655 
656     ExReleaseResourceLite( ((PFCB)Fcb)->Header.Resource );
657 
658     return;
659 }
660 
661 
662 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH)
_Requires_lock_held_(_Global_critical_region_)663 _Requires_lock_held_(_Global_critical_region_)
664 NTSTATUS
665 NTAPI
666 FatAcquireForCcFlush (
667     IN PFILE_OBJECT FileObject,
668     IN PDEVICE_OBJECT DeviceObject
669     )
670 {
671     PFCB Fcb;
672     PCCB Ccb;
673     PVCB Vcb;
674     PFSRTL_COMMON_FCB_HEADER Header;
675     TYPE_OF_OPEN Type;
676 
677     PAGED_CODE();
678     UNREFERENCED_PARAMETER( DeviceObject );
679 
680     //
681     //  Once again, the hack for making this look like
682     //  a recursive call if needed. We cannot let ourselves
683     //  verify under something that has resources held.
684     //
685     //  This value is good.  We should never try to acquire
686     //  the file this way underneath of the cache.
687     //
688 
689     NT_ASSERT( IoGetTopLevelIrp() != (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP );
690 
691     if (IoGetTopLevelIrp() == NULL) {
692 
693         IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
694     }
695 
696     //
697     //  Time for some exposition.
698     //
699     //  Lockorder for FAT is main->bcb->pagingio. Invert this at your obvious peril.
700     //  The default logic for AcquireForCcFlush breaks this since in writethrough
701     //  unpinrepinned we will grab the bcb then Mm will use the callback (which
702     //  orders us with respect to the MmCollidedFlushEvent) to help us. If for
703     //  directories/ea we then grab the main we are out of order.
704     //
705     //  Fortunately, we do not need main. We only need paging - just look at the write
706     //  path. This is basic pre-acquisition.
707     //
708     //  Regular files require both resources, and are safe since we never pin them.
709     //
710 
711     //
712     //  Note that we do not need to disable APC delivery to guard
713     //  against a rogue user issuing a suspend APC. That is because
714     //  it is guaranteed that the caller is either in the system context,
715     //  to which a user cannot deliver a suspend APC, or the caller has
716     //  already disabled kernel APC delivery before calling. This is true
717     //  for all the other pre-acquire routines as well.
718     //
719 
720     Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
721     Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
722 
723     if (Type < DirectoryFile) {
724 
725         if (Header->Resource) {
726 
727             if (!ExIsResourceAcquiredSharedLite( Header->Resource )) {
728 
729                 ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
730 
731             } else {
732 
733                 ExAcquireResourceSharedLite( Header->Resource, TRUE );
734             }
735         }
736     }
737 
738     if (Header->PagingIoResource) {
739 
740         ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
741     }
742 
743     return STATUS_SUCCESS;
744 }
745 
746 
_Requires_lock_held_(_Global_critical_region_)747 _Requires_lock_held_(_Global_critical_region_)
748 NTSTATUS
749 NTAPI
750 FatReleaseForCcFlush (
751     IN PFILE_OBJECT FileObject,
752     IN PDEVICE_OBJECT DeviceObject
753     )
754 {
755     PFCB Fcb;
756     PCCB Ccb;
757     PVCB Vcb;
758     PFSRTL_COMMON_FCB_HEADER Header;
759     TYPE_OF_OPEN Type;
760 
761     PAGED_CODE();
762     UNREFERENCED_PARAMETER( DeviceObject );
763 
764     //
765     //  Clear up our hint.
766     //
767 
768     if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) {
769 
770         IoSetTopLevelIrp( NULL );
771     }
772 
773     Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
774     Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
775 
776     if (Type < DirectoryFile) {
777 
778         if (Header->Resource) {
779 
780             ExReleaseResourceLite( Header->Resource );
781         }
782     }
783 
784     if (Header->PagingIoResource) {
785 
786         ExReleaseResourceLite( Header->PagingIoResource );
787     }
788 
789     return STATUS_SUCCESS;
790 }
791 
792 
793 BOOLEAN
794 NTAPI
FatNoOpAcquire(IN PVOID Fcb,IN BOOLEAN Wait)795 FatNoOpAcquire (
796     IN PVOID Fcb,
797     IN BOOLEAN Wait
798     )
799 
800 /*++
801 
802 Routine Description:
803 
804     This routine does nothing.
805 
806 Arguments:
807 
808     Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this
809           routine.
810 
811     Wait - TRUE if the caller is willing to block.
812 
813 Return Value:
814 
815     TRUE
816 
817 --*/
818 
819 {
820     UNREFERENCED_PARAMETER( Fcb );
821     UNREFERENCED_PARAMETER( Wait );
822 
823     PAGED_CODE();
824 
825     //
826     //  This is a kludge because Cc is really the top level.  We it
827     //  enters the file system, we will think it is a resursive call
828     //  and complete the request with hard errors or verify.  It will
829     //  have to deal with them, somehow....
830     //
831 
832     NT_ASSERT(IoGetTopLevelIrp() == NULL);
833 
834     IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
835 
836     return TRUE;
837 }
838 
839 
840 VOID
841 NTAPI
FatNoOpRelease(IN PVOID Fcb)842 FatNoOpRelease (
843     IN PVOID Fcb
844     )
845 
846 /*++
847 
848 Routine Description:
849 
850     This routine does nothing.
851 
852 Arguments:
853 
854     Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this
855           routine.
856 
857 Return Value:
858 
859     None
860 
861 --*/
862 
863 {
864     PAGED_CODE();
865 
866     //
867     //  Clear the kludge at this point.
868     //
869 
870     NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
871 
872     IoSetTopLevelIrp( NULL );
873 
874     UNREFERENCED_PARAMETER( Fcb );
875 
876     return;
877 }
878 
879 
_Requires_lock_held_(_Global_critical_region_)880 _Requires_lock_held_(_Global_critical_region_)
881 NTSTATUS
882 NTAPI
883 FatFilterCallbackAcquireForCreateSection (
884     IN PFS_FILTER_CALLBACK_DATA CallbackData,
885     OUT PVOID *CompletionContext
886     )
887 
888 /*++
889 
890 Routine Description:
891 
892     This is the callback routine for MM to use to acquire the file exclusively.
893 
894     NOTE:  This routine expects the default FSRTL routine to be used to release
895            the resource.  If this routine is ever changed to acquire something
896            other than main, a corresponding release routine will be required.
897 
898 Arguments:
899 
900     FS_FILTER_CALLBACK_DATA - Filter based callback data that provides the file object we
901                               want to acquire.
902 
903     CompletionContext - Ignored.
904 
905 Return Value:
906 
907     On success we return STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY.
908 
909     If SyncType is SyncTypeCreateSection, we return a status that indicates whether there
910     are any writers to this file.  Note that main is acquired, so new handles cannot be opened.
911 
912 --*/
913 
914 {
915     PFCB Fcb;
916 
917     PAGED_CODE();
918 
919     NT_ASSERT( CallbackData->Operation == FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION );
920     NT_ASSERT( CallbackData->SizeOfFsFilterCallbackData == sizeof(FS_FILTER_CALLBACK_DATA) );
921 
922     //
923     //  Grab the Fcb from the callback data file object.
924     //
925 
926     Fcb = CallbackData->FileObject->FsContext;
927 
928     //
929     //  Take main exclusive.
930     //
931 
932     //
933     //  Note that we do not need to disable APC delivery to guard
934     //  against a rogue user issuing a suspend APC. That is because
935     //  it is guaranteed that the caller is either in the system context,
936     //  to which a user cannot deliver a suspend APC, or the caller has
937     //  already disabled kernel APC delivery before calling. This is true
938     //  for all the other pre-acquire routines as well.
939     //
940 
941     if (Fcb->Header.Resource) {
942 
943         ExAcquireResourceExclusiveLite( Fcb->Header.Resource, TRUE );
944     }
945 
946     //
947     //  Return the appropriate status based on the type of synchronization and whether anyone
948     //  has write access to this file.
949     //
950 
951     if (CallbackData->Parameters.AcquireForSectionSynchronization.SyncType != SyncTypeCreateSection) {
952 
953         return STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY;
954 
955     } else if (Fcb->ShareAccess.Writers == 0) {
956 
957         return STATUS_FILE_LOCKED_WITH_ONLY_READERS;
958 
959     } else {
960 
961         return STATUS_FILE_LOCKED_WITH_WRITERS;
962     }
963 
964     UNREFERENCED_PARAMETER( CompletionContext );
965 }
966 
967