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