1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     LockCtrl.c
8 
9 Abstract:
10 
11     This module implements the Lock Control routines for Fat called
12     by the dispatch driver.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 //  The local debug trace level
21 //
22 
23 #define Dbg                              (DEBUG_TRACE_LOCKCTRL)
24 
25 #ifdef ALLOC_PRAGMA
26 #pragma alloc_text(PAGE, FatCommonLockControl)
27 #pragma alloc_text(PAGE, FatFastLock)
28 #pragma alloc_text(PAGE, FatFastUnlockAll)
29 #pragma alloc_text(PAGE, FatFastUnlockAllByKey)
30 #pragma alloc_text(PAGE, FatFastUnlockSingle)
31 #pragma alloc_text(PAGE, FatFsdLockControl)
32 #endif
33 
34 
35 _Function_class_(IRP_MJ_LOCK_CONTROL)
_Function_class_(DRIVER_DISPATCH)36 _Function_class_(DRIVER_DISPATCH)
37 NTSTATUS
38 NTAPI
39 FatFsdLockControl (
40     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
41     _Inout_ PIRP Irp
42     )
43 
44 /*++
45 
46 Routine Description:
47 
48     This routine implements the FSD part of Lock control operations
49 
50 Arguments:
51 
52     VolumeDeviceObject - Supplies the volume device object where the
53         file exists
54 
55     Irp - Supplies the Irp being processed
56 
57 Return Value:
58 
59     NTSTATUS - The FSD status for the IRP
60 
61 --*/
62 
63 {
64     NTSTATUS Status;
65     PIRP_CONTEXT IrpContext = NULL;
66 
67     BOOLEAN TopLevel;
68 
69     PAGED_CODE();
70 
71     DebugTrace(+1, Dbg, "FatFsdLockControl\n", 0);
72 
73     //
74     //  Call the common Lock Control routine, with blocking allowed if
75     //  synchronous
76     //
77 
78     FsRtlEnterFileSystem();
79 
80     TopLevel = FatIsIrpTopLevel( Irp );
81 
82     _SEH2_TRY {
83 
84         IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
85 
86         Status = FatCommonLockControl( IrpContext, Irp );
87 
88     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
89 
90         //
91         //  We had some trouble trying to perform the requested
92         //  operation, so we'll abort the I/O request with
93         //  the error status that we get back from the
94         //  execption code
95         //
96 
97         Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
98     } _SEH2_END;
99 
100     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
101 
102     FsRtlExitFileSystem();
103 
104     //
105     //  And return to our caller
106     //
107 
108     DebugTrace(-1, Dbg, "FatFsdLockControl -> %08lx\n", Status);
109 
110     UNREFERENCED_PARAMETER( VolumeDeviceObject );
111 
112     return Status;
113 }
114 
115 
_Function_class_(FAST_IO_LOCK)116 _Function_class_(FAST_IO_LOCK)
117 BOOLEAN
118 NTAPI
119 FatFastLock (
120     IN PFILE_OBJECT FileObject,
121     IN PLARGE_INTEGER FileOffset,
122     IN PLARGE_INTEGER Length,
123     PEPROCESS ProcessId,
124     ULONG Key,
125     BOOLEAN FailImmediately,
126     BOOLEAN ExclusiveLock,
127     OUT PIO_STATUS_BLOCK IoStatus,
128     IN PDEVICE_OBJECT DeviceObject
129     )
130 
131 /*++
132 
133 Routine Description:
134 
135     This is a call back routine for doing the fast lock call.
136 
137 Arguments:
138 
139     FileObject - Supplies the file object used in this operation
140 
141     FileOffset - Supplies the file offset used in this operation
142 
143     Length - Supplies the length used in this operation
144 
145     ProcessId - Supplies the process ID used in this operation
146 
147     Key - Supplies the key used in this operation
148 
149     FailImmediately - Indicates if the request should fail immediately
150         if the lock cannot be granted.
151 
152     ExclusiveLock - Indicates if this is a request for an exclusive or
153         shared lock
154 
155     IoStatus - Receives the Status if this operation is successful
156 
157 Return Value:
158 
159     BOOLEAN - TRUE if this operation completed and FALSE if caller
160         needs to take the long route.
161 
162 --*/
163 
164 {
165     BOOLEAN Results = FALSE;
166     PVCB Vcb;
167     PFCB Fcb;
168     PCCB Ccb;
169 
170     PAGED_CODE();
171     UNREFERENCED_PARAMETER( DeviceObject );
172 
173     DebugTrace(+1, Dbg, "FatFastLock\n", 0);
174 
175     //
176     //  Decode the type of file object we're being asked to process and make
177     //  sure it is only a user file open.
178     //
179 
180     if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) {
181 
182         IoStatus->Status = STATUS_INVALID_PARAMETER;
183         IoStatus->Information = 0;
184 
185         DebugTrace(-1, Dbg, "FatFastLock -> TRUE (STATUS_INVALID_PARAMETER)\n", 0);
186         return TRUE;
187     }
188 
189     //
190     //  Acquire shared access to the Fcb
191     //
192 
193     FsRtlEnterFileSystem();
194     ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE );
195 
196     _SEH2_TRY {
197 
198         //
199         //  We check whether we can proceed
200         //  based on the state of the file oplocks.
201         //
202 
203         if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) {
204 
205             try_return( Results = FALSE );
206         }
207 
208         //
209         //  Now call the FsRtl routine to do the actual processing of the
210         //  Lock request
211         //
212 
213 #ifdef _MSC_VER
214 #pragma prefast( suppress:28159, "prefast indicates this API is obsolete but it is ok for fastfat to continue using it" )
215 #endif
216         Results = FsRtlFastLock( &Fcb->Specific.Fcb.FileLock,
217                                  FileObject,
218                                  FileOffset,
219                                  Length,
220                                  ProcessId,
221                                  Key,
222                                  FailImmediately,
223                                  ExclusiveLock,
224                                  IoStatus,
225                                  NULL,
226                                  FALSE );
227 
228         if (Results) {
229 
230             //
231             //  Set the flag indicating if Fast I/O is possible
232             //
233 
234             Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
235         }
236 
237     try_exit:  NOTHING;
238     } _SEH2_FINALLY {
239 
240         DebugUnwind( FatFastLock );
241 
242         //
243         //  Release the Fcb, and return to our caller
244         //
245 
246         ExReleaseResourceLite( Fcb->Header.Resource );
247         FsRtlExitFileSystem();
248 
249         DebugTrace(-1, Dbg, "FatFastLock -> %08lx\n", Results);
250     } _SEH2_END;
251 
252     return Results;
253 }
254 
255 
_Function_class_(FAST_IO_UNLOCK_SINGLE)256 _Function_class_(FAST_IO_UNLOCK_SINGLE)
257 BOOLEAN
258 NTAPI
259 FatFastUnlockSingle (
260     IN PFILE_OBJECT FileObject,
261     IN PLARGE_INTEGER FileOffset,
262     IN PLARGE_INTEGER Length,
263     PEPROCESS ProcessId,
264     ULONG Key,
265     OUT PIO_STATUS_BLOCK IoStatus,
266     IN PDEVICE_OBJECT DeviceObject
267     )
268 
269 /*++
270 
271 Routine Description:
272 
273     This is a call back routine for doing the fast unlock single call.
274 
275 Arguments:
276 
277     FileObject - Supplies the file object used in this operation
278 
279     FileOffset - Supplies the file offset used in this operation
280 
281     Length - Supplies the length used in this operation
282 
283     ProcessId - Supplies the process ID used in this operation
284 
285     Key - Supplies the key used in this operation
286 
287     Status - Receives the Status if this operation is successful
288 
289 Return Value:
290 
291     BOOLEAN - TRUE if this operation completed and FALSE if caller
292         needs to take the long route.
293 
294 --*/
295 
296 {
297     BOOLEAN Results = FALSE;
298     PVCB Vcb;
299     PFCB Fcb;
300     PCCB Ccb;
301 
302     PAGED_CODE();
303     UNREFERENCED_PARAMETER( DeviceObject );
304 
305     DebugTrace(+1, Dbg, "FatFastUnlockSingle\n", 0);
306 
307     IoStatus->Information = 0;
308 
309     //
310     //  Decode the type of file object we're being asked to process and make sure
311     //  it is only a user file open
312     //
313 
314     if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) {
315 
316         IoStatus->Status = STATUS_INVALID_PARAMETER;
317 
318         DebugTrace(-1, Dbg, "FatFastUnlockSingle -> TRUE (STATUS_INVALID_PARAMETER)\n", 0);
319         return TRUE;
320     }
321 
322     //
323     //  Acquire exclusive access to the Fcb this operation can always wait
324     //
325 
326     FsRtlEnterFileSystem();
327 
328     _SEH2_TRY {
329 
330         //
331         //  We check whether we can proceed based on the state of the file oplocks.
332         //
333 
334         if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) {
335 
336             try_return( Results = FALSE );
337         }
338 
339         //
340         //  Now call the FsRtl routine to do the actual processing of the
341         //  Lock request.  The call will always succeed.
342         //
343 
344         Results = TRUE;
345         IoStatus->Status = FsRtlFastUnlockSingle( &Fcb->Specific.Fcb.FileLock,
346                                                   FileObject,
347                                                   FileOffset,
348                                                   Length,
349                                                   ProcessId,
350                                                   Key,
351                                                   NULL,
352                                                   FALSE );
353 
354         //
355         //  Set the flag indicating if Fast I/O is possible
356         //
357 
358         Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
359 
360     try_exit:  NOTHING;
361     } _SEH2_FINALLY {
362 
363         DebugUnwind( FatFastUnlockSingle );
364 
365         //
366         //  Release the Fcb, and return to our caller
367         //
368 
369         FsRtlExitFileSystem();
370 
371         DebugTrace(-1, Dbg, "FatFastUnlockSingle -> %08lx\n", Results);
372     } _SEH2_END;
373 
374     return Results;
375 }
376 
377 
_Function_class_(FAST_IO_UNLOCK_ALL)378 _Function_class_(FAST_IO_UNLOCK_ALL)
379 BOOLEAN
380 NTAPI
381 FatFastUnlockAll (
382     IN PFILE_OBJECT FileObject,
383     PEPROCESS ProcessId,
384     OUT PIO_STATUS_BLOCK IoStatus,
385     IN PDEVICE_OBJECT DeviceObject
386     )
387 
388 /*++
389 
390 Routine Description:
391 
392     This is a call back routine for doing the fast unlock all call.
393 
394 Arguments:
395 
396     FileObject - Supplies the file object used in this operation
397 
398     ProcessId - Supplies the process ID used in this operation
399 
400     Status - Receives the Status if this operation is successful
401 
402 Return Value:
403 
404     BOOLEAN - TRUE if this operation completed and FALSE if caller
405         needs to take the long route.
406 
407 --*/
408 
409 {
410     BOOLEAN Results = FALSE;
411     PVCB Vcb;
412     PFCB Fcb;
413     PCCB Ccb;
414 
415     PAGED_CODE();
416     UNREFERENCED_PARAMETER( DeviceObject );
417 
418     DebugTrace(+1, Dbg, "FatFastUnlockAll\n", 0);
419 
420     IoStatus->Information = 0;
421 
422     //
423     //  Decode the type of file object we're being asked to process and make sure
424     //  it is only a user file open.
425     //
426 
427     if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) {
428 
429         IoStatus->Status = STATUS_INVALID_PARAMETER;
430 
431         DebugTrace(-1, Dbg, "FatFastUnlockAll -> TRUE (STATUS_INVALID_PARAMETER)\n", 0);
432         return TRUE;
433     }
434 
435     //
436     //  Acquire exclusive access to the Fcb this operation can always wait
437     //
438 
439     FsRtlEnterFileSystem();
440 
441     (VOID) ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE );
442 
443     _SEH2_TRY {
444 
445         //
446         //  We check whether we can proceed based on the state of the file oplocks.
447         //
448 
449         if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) {
450 
451             try_return( Results = FALSE );
452         }
453 
454         //
455         //  Now call the FsRtl routine to do the actual processing of the
456         //  Lock request.  The call will always succeed.
457         //
458 
459         Results = TRUE;
460         IoStatus->Status = FsRtlFastUnlockAll( &Fcb->Specific.Fcb.FileLock,
461                                                FileObject,
462                                                ProcessId,
463                                                NULL );
464 
465         //
466         //  Set the flag indicating if Fast I/O is possible
467         //
468 
469         Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
470 
471     try_exit:  NOTHING;
472     } _SEH2_FINALLY {
473 
474         DebugUnwind( FatFastUnlockAll );
475 
476         //
477         //  Release the Fcb, and return to our caller
478         //
479 
480         ExReleaseResourceLite( (Fcb)->Header.Resource );
481 
482         FsRtlExitFileSystem();
483 
484         DebugTrace(-1, Dbg, "FatFastUnlockAll -> %08lx\n", Results);
485     } _SEH2_END;
486 
487     return Results;
488 }
489 
490 
_Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY)491 _Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY)
492 BOOLEAN
493 NTAPI
494 FatFastUnlockAllByKey (
495     IN PFILE_OBJECT FileObject,
496     PVOID ProcessId,
497     ULONG Key,
498     OUT PIO_STATUS_BLOCK IoStatus,
499     IN PDEVICE_OBJECT DeviceObject
500     )
501 
502 /*++
503 
504 Routine Description:
505 
506     This is a call back routine for doing the fast unlock all by key call.
507 
508 Arguments:
509 
510     FileObject - Supplies the file object used in this operation
511 
512     ProcessId - Supplies the process ID used in this operation
513 
514     Key - Supplies the key used in this operation
515 
516     Status - Receives the Status if this operation is successful
517 
518 Return Value:
519 
520     BOOLEAN - TRUE if this operation completed and FALSE if caller
521         needs to take the long route.
522 
523 --*/
524 
525 {
526     BOOLEAN Results = FALSE;
527     PVCB Vcb;
528     PFCB Fcb;
529     PCCB Ccb;
530 
531     PAGED_CODE();
532     UNREFERENCED_PARAMETER( DeviceObject );
533 
534     DebugTrace(+1, Dbg, "FatFastUnlockAllByKey\n", 0);
535 
536     IoStatus->Information = 0;
537 
538     //
539     //  Decode the type of file object we're being asked to process and make sure
540     //  it is only a user file open.
541     //
542 
543     if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) {
544 
545         IoStatus->Status = STATUS_INVALID_PARAMETER;
546 
547         DebugTrace(-1, Dbg, "FatFastUnlockAll -> TRUE (STATUS_INVALID_PARAMETER)\n", 0);
548         return TRUE;
549     }
550 
551     //
552     //  Acquire exclusive access to the Fcb this operation can always wait
553     //
554 
555     FsRtlEnterFileSystem();
556 
557     (VOID) ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE );
558 
559     _SEH2_TRY {
560 
561         //
562         //  We check whether we can proceed based on the state of the file oplocks.
563         //
564 
565         if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) {
566 
567             try_return( Results = FALSE );
568         }
569 
570         //
571         //  Now call the FsRtl routine to do the actual processing of the
572         //  Lock request.  The call will always succeed.
573         //
574 
575         Results = TRUE;
576         IoStatus->Status = FsRtlFastUnlockAllByKey( &Fcb->Specific.Fcb.FileLock,
577                                                     FileObject,
578                                                     ProcessId,
579                                                     Key,
580                                                     NULL );
581 
582         //
583         //  Set the flag indicating if Fast I/O is possible
584         //
585 
586         Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
587 
588     try_exit:  NOTHING;
589     } _SEH2_FINALLY {
590 
591         DebugUnwind( FatFastUnlockAllByKey );
592 
593         //
594         //  Release the Fcb, and return to our caller
595         //
596 
597         ExReleaseResourceLite( (Fcb)->Header.Resource );
598 
599         FsRtlExitFileSystem();
600 
601         DebugTrace(-1, Dbg, "FatFastUnlockAllByKey -> %08lx\n", Results);
602     } _SEH2_END;
603 
604     return Results;
605 }
606 
607 
_Requires_lock_held_(_Global_critical_region_)608 _Requires_lock_held_(_Global_critical_region_)
609 NTSTATUS
610 FatCommonLockControl (
611     IN PIRP_CONTEXT IrpContext,
612     IN PIRP Irp
613     )
614 
615 /*++
616 
617 Routine Description:
618 
619     This is the common routine for doing Lock control operations called
620     by both the fsd and fsp threads
621 
622 Arguments:
623 
624     Irp - Supplies the Irp to process
625 
626 Return Value:
627 
628     NTSTATUS - The return status for the operation
629 
630 --*/
631 
632 {
633     NTSTATUS Status = STATUS_SUCCESS;
634     PIO_STACK_LOCATION IrpSp;
635 
636     TYPE_OF_OPEN TypeOfOpen;
637 
638     PVCB Vcb;
639     PFCB Fcb;
640     PCCB Ccb;
641 
642     BOOLEAN OplockPostIrp = FALSE;
643 
644     PAGED_CODE();
645 
646     //
647     //  Get a pointer to the current Irp stack location
648     //
649 
650     IrpSp = IoGetCurrentIrpStackLocation( Irp );
651 
652     DebugTrace(+1, Dbg, "FatCommonLockControl\n", 0);
653     DebugTrace( 0, Dbg, "Irp           = %p\n", Irp);
654     DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);
655 
656     //
657     //  Decode the type of file object we're being asked to process
658     //
659 
660     TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
661 
662     //
663     //  If the file is not a user file open then we reject the request
664     //  as an invalid parameter
665     //
666 
667     if (TypeOfOpen != UserFileOpen) {
668 
669         FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
670 
671         DebugTrace(-1, Dbg, "FatCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0);
672         return STATUS_INVALID_PARAMETER;
673     }
674 
675     //
676     //  Acquire exclusive access to the Fcb and enqueue the Irp if we didn't
677     //  get access
678     //
679 
680     if (!FatAcquireSharedFcb( IrpContext, Fcb )) {
681 
682         Status = FatFsdPostRequest( IrpContext, Irp );
683 
684         DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status);
685         return Status;
686     }
687 
688     _SEH2_TRY {
689 
690         //
691         //  We check whether we can proceed
692         //  based on the state of the file oplocks.
693         //
694 
695 #if (NTDDI_VERSION >= NTDDI_WIN8)
696 
697         if (((IRP_MN_LOCK == IrpSp->MinorFunction) &&
698              ((ULONGLONG)IrpSp->Parameters.LockControl.ByteOffset.QuadPart <
699               (ULONGLONG)Fcb->Header.AllocationSize.QuadPart)) ||
700             ((IRP_MN_LOCK != IrpSp->MinorFunction) &&
701              FsRtlAreThereWaitingFileLocks( &Fcb->Specific.Fcb.FileLock ))) {
702 
703             //
704             //  Check whether we can proceed based on the state of file oplocks if doing
705             //  an operation that interferes with oplocks. Those operations are:
706             //
707             //      1. Lock a range within the file's AllocationSize.
708             //      2. Unlock a range when there are waiting locks on the file. This one
709             //         is not guaranteed to interfere with oplocks, but it could, as
710             //         unlocking this range might cause a waiting lock to be granted
711             //         within AllocationSize!
712             //
713 
714 #endif
715             Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb),
716                                        Irp,
717                                        IrpContext,
718                                        FatOplockComplete,
719                                        NULL );
720 
721 #if (NTDDI_VERSION >= NTDDI_WIN8)
722         }
723 #endif
724 
725         if (Status != STATUS_SUCCESS) {
726 
727             OplockPostIrp = TRUE;
728             try_return( NOTHING );
729         }
730 
731         //
732         //  Now call the FsRtl routine to do the actual processing of the
733         //  Lock request
734         //
735 
736         Status = FsRtlProcessFileLock( &Fcb->Specific.Fcb.FileLock, Irp, NULL );
737 
738         //
739         //  Set the flag indicating if Fast I/O is possible
740         //
741 
742         Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
743 
744     try_exit:  NOTHING;
745     } _SEH2_FINALLY {
746 
747         DebugUnwind( FatCommonLockControl );
748 
749         //
750         //  Only if this is not an abnormal termination do we delete the
751         //  irp context
752         //
753 
754         if (!_SEH2_AbnormalTermination() && !OplockPostIrp) {
755 
756             FatCompleteRequest( IrpContext, FatNull, 0 );
757         }
758 
759         //
760         //  Release the Fcb, and return to our caller
761         //
762 
763         FatReleaseFcb( IrpContext, Fcb );
764 
765         DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status);
766     } _SEH2_END;
767 
768     return Status;
769 }
770 
771