3 * reactos/ntoskrnl/fs/filelock.c
9 #include <internal/debug.h>
13 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
14 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
16 UPDATE: I'm not sure about this! -Gunnar
19 FAST_MUTEX LockTocMutex
;
20 NPAGED_LOOKASIDE_LIST GrantedLookaside
;
21 NPAGED_LOOKASIDE_LIST LockTocLookaside
;
22 PAGED_LOOKASIDE_LIST LockLookaside
;
29 PLARGE_INTEGER StartOffset
,
30 PLARGE_INTEGER EndOffset
33 if ((ULONGLONG
)StartOffset
->QuadPart
> (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
38 if ((ULONGLONG
)EndOffset
->QuadPart
< (ULONGLONG
)Lock
->StartingByte
.QuadPart
)
50 PLARGE_INTEGER StartOffset
,
51 PLARGE_INTEGER EndOffset
54 if ((ULONGLONG
)StartOffset
->QuadPart
>= (ULONGLONG
)Lock
->StartingByte
.QuadPart
&&
55 (ULONGLONG
)EndOffset
->QuadPart
<= (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
64 /**********************************************************************
66 * FsRtlpInitFileLockingImplementation
71 FsRtlpInitFileLockingImplementation(VOID
)
73 ExInitializeNPagedLookasideList( &LockTocLookaside
,
77 sizeof(FILE_LOCK_TOC
),
82 ExInitializeNPagedLookasideList( &GrantedLookaside
,
86 sizeof(FILE_LOCK_GRANTED
),
91 ExInitializePagedLookasideList( &LockLookaside
,
100 ExInitializeFastMutex(&LockTocMutex
);
104 /**********************************************************************
106 * FsRtlpFileLockCancelRoutine
111 FsRtlpFileLockCancelRoutine(
112 IN PDEVICE_OBJECT DeviceObject
,
117 PKSPIN_LOCK SpinLock
;
119 //don't need this since we have our own sync. protecting irp cancellation
120 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
122 SpinLock
= Irp
->Tail
.Overlay
.DriverContext
[3];
124 KeAcquireSpinLock(SpinLock
, &oldIrql
);
126 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
128 KeReleaseSpinLock(SpinLock
, oldIrql
);
130 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
131 Irp
->IoStatus
.Information
= 0;
133 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
137 /**********************************************************************
139 * FsRtlpCheckLockForReadOrWriteAccess
142 * TRUE: can read/write
143 * FALSE: can't read/write
147 FsRtlpCheckLockForReadOrWriteAccess(
148 IN PFILE_LOCK FileLock
,
149 IN PLARGE_INTEGER FileOffset
,
150 IN PLARGE_INTEGER Length
,
152 IN PFILE_OBJECT FileObject
,
153 IN PEPROCESS Process
,
158 PFILE_LOCK_TOC LockToc
;
159 PFILE_LOCK_GRANTED Granted
;
160 PLIST_ENTRY EnumEntry
;
161 LARGE_INTEGER EndOffset
;
165 LockToc
= FileLock
->LockInformation
;
167 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
172 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
174 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
176 LIST_FOR_EACH(EnumEntry
, &LockToc
->GrantedListHead
)
178 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
181 if(IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
183 //No read conflict if (shared lock) OR (exclusive + our lock)
184 //No write conflict if exclusive lock AND our lock
185 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
186 (Granted
->Lock
.ExclusiveLock
&&
187 Granted
->Lock
.Process
== Process
&&
188 Granted
->Lock
.FileObject
== FileObject
&&
189 Granted
->Lock
.Key
== Key
) )
191 //AND if lock surround request region, stop searching and grant
192 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
) )
194 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
198 //else continue searching for conflicts
203 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
210 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
215 /**********************************************************************
217 * FsRtlCheckLockForReadAccess
223 FsRtlCheckLockForReadAccess (
224 IN PFILE_LOCK FileLock
,
228 PIO_STACK_LOCATION Stack
;
229 LARGE_INTEGER LocalLength
;
231 Stack
= IoGetCurrentIrpStackLocation(Irp
);
233 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
234 LocalLength
.u
.HighPart
= 0;
236 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
237 &Stack
->Parameters
.Read
.ByteOffset
,
239 Stack
->Parameters
.Read
.Key
,
241 IoGetRequestorProcess(Irp
),
247 /**********************************************************************
249 * FsRtlCheckLockForWriteAccess
255 FsRtlCheckLockForWriteAccess (
256 IN PFILE_LOCK FileLock
,
260 PIO_STACK_LOCATION Stack
;
261 LARGE_INTEGER LocalLength
;
263 Stack
= IoGetCurrentIrpStackLocation(Irp
);
265 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
266 LocalLength
.u
.HighPart
= 0;
268 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
269 &Stack
->Parameters
.Write
.ByteOffset
,
271 Stack
->Parameters
.Write
.Key
,
273 IoGetRequestorProcess(Irp
),
282 /**********************************************************************
284 * FsRtlFastCheckLockForRead
290 FsRtlFastCheckLockForRead (
291 IN PFILE_LOCK FileLock
,
292 IN PLARGE_INTEGER FileOffset
,
293 IN PLARGE_INTEGER Length
,
295 IN PFILE_OBJECT FileObject
,
299 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
310 /**********************************************************************
312 * FsRtlFastCheckLockForWrite
318 FsRtlFastCheckLockForWrite (
319 IN PFILE_LOCK FileLock
,
320 IN PLARGE_INTEGER FileOffset
,
321 IN PLARGE_INTEGER Length
,
323 IN PFILE_OBJECT FileObject
,
327 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
339 /**********************************************************************
341 * FsRtlpFastUnlockAllByKey
346 FsRtlpFastUnlockAllByKey(
347 IN PFILE_LOCK FileLock
,
348 IN PFILE_OBJECT FileObject
,
349 IN PEPROCESS Process
,
352 IN PVOID Context OPTIONAL
356 PFILE_LOCK_TOC LockToc
;
357 PLIST_ENTRY EnumEntry
;
358 PFILE_LOCK_GRANTED Granted
;
359 BOOLEAN Unlock
= FALSE
;
360 //must make local copy since FILE_LOCK struct is allowed to be paged
361 BOOLEAN GotUnlockRoutine
;
362 LIST_ENTRY UnlockedListHead
;
365 LockToc
= FileLock
->LockInformation
;
369 return STATUS_RANGE_NOT_LOCKED
;
372 InitializeListHead(&UnlockedListHead
);
373 GotUnlockRoutine
= FileLock
->UnlockRoutine
!= NULL
;
374 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
376 LIST_FOR_EACH_SAFE(EnumEntry
, &LockToc
->GrantedListHead
, Granted
, FILE_LOCK_GRANTED
, ListEntry
)
379 if (Granted
->Lock
.Process
== Process
&&
380 Granted
->Lock
.FileObject
== FileObject
&&
381 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
383 RemoveEntryList(&Granted
->ListEntry
);
386 if (GotUnlockRoutine
)
389 Put on unlocked list and call unlock routine for them afterwards.
390 This way we don't have to restart enum after each call
392 InsertHeadList(&UnlockedListHead
,&Granted
->ListEntry
);
396 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
401 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
405 //call unlock routine for each unlocked lock (if any)
406 while (!IsListEmpty(&UnlockedListHead
))
408 EnumEntry
= RemoveTailList(&UnlockedListHead
);
409 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
411 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
412 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
415 //NOTE: holding spinlock while calling this
416 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
417 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
419 if (IsListEmpty(&LockToc
->GrantedListHead
))
421 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
422 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
426 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
429 return STATUS_SUCCESS
;
432 return STATUS_RANGE_NOT_LOCKED
;
435 /**********************************************************************
443 FsRtlFastUnlockAll
/*ByProcess*/ (
444 IN PFILE_LOCK FileLock
,
445 IN PFILE_OBJECT FileObject
,
446 IN PEPROCESS Process
,
447 IN PVOID Context OPTIONAL
450 return FsRtlpFastUnlockAllByKey( FileLock
,
453 0, /* Key is ignored */
454 FALSE
, /* Do NOT use Key */
459 /**********************************************************************
461 * FsRtlFastUnlockAllByKey
467 FsRtlFastUnlockAllByKey (
468 IN PFILE_LOCK FileLock
,
469 IN PFILE_OBJECT FileObject
,
470 IN PEPROCESS Process
,
472 IN PVOID Context OPTIONAL
475 return FsRtlpFastUnlockAllByKey( FileLock
,
485 /**********************************************************************
490 * Spinlock held at entry !!
495 IN PFILE_LOCK_TOC LockToc
,
496 IN PFILE_OBJECT FileObject
,
497 IN PLARGE_INTEGER FileOffset
,
498 IN PLARGE_INTEGER Length
,
499 IN PEPROCESS Process
,
501 IN BOOLEAN ExclusiveLock
,
505 PLIST_ENTRY EnumEntry
;
506 PFILE_LOCK_GRANTED Granted
;
507 LARGE_INTEGER EndOffset
;
509 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
511 //loop and try to find conflicking locks
512 LIST_FOR_EACH(EnumEntry
, &LockToc
->GrantedListHead
)
514 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
516 if (IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
518 //we found a locks that overlap with the new lock
520 //if both locks are shared, we might have a fast path outa here...
521 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
523 //if existing lock surround new lock, we know that no other exclusive lock
524 //may overlap with our new lock;-D
525 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
530 //else keep locking for conflicts
534 //we found a conflict:
535 //we want shared access to an excl. lock OR exlc. access to a shared lock
540 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
543 Granted
->Lock
.StartingByte
= *FileOffset
;
544 Granted
->Lock
.Length
= *Length
;
545 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
546 Granted
->Lock
.Key
= Key
;
547 Granted
->Lock
.FileObject
= FileObject
;
548 Granted
->Lock
.Process
= Process
;
550 Granted
->Lock
.EndingByte
= EndOffset
;
551 Granted
->UnlockContext
= Context
;
553 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
559 /**********************************************************************
561 * FsRtlpCompletePendingLocks
564 * Spinlock held at entry !!
568 FsRtlpCompletePendingLocks(
569 IN PFILE_LOCK FileLock
,
570 IN PFILE_LOCK_TOC LockToc
,
571 IN OUT PKIRQL oldirql
,
575 //walk pending list, FIFO order, try 2 complete locks
576 PLIST_ENTRY EnumEntry
;
578 PIO_STACK_LOCATION Stack
;
579 LIST_ENTRY CompletedListHead
;
581 InitializeListHead(&CompletedListHead
);
583 LIST_FOR_EACH_SAFE(EnumEntry
, &LockToc
->PendingListHead
, Irp
, IRP
, Tail
.Overlay
.ListEntry
)
585 Stack
= IoGetCurrentIrpStackLocation(Irp
);
586 if (FsRtlpAddLock(LockToc
,
588 &Stack
->Parameters
.LockControl
.ByteOffset
,
589 Stack
->Parameters
.LockControl
.Length
,
590 IoGetRequestorProcess(Irp
),
591 Stack
->Parameters
.LockControl
.Key
,
592 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
593 Irp
->Tail
.Overlay
.DriverContext
[2] //Context
596 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
598 if (!IoSetCancelRoutine(Irp
, NULL
))
600 //irp is canceled and cancelroutine will run when we release the lock
601 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
606 Put on completed list and complete them all afterwards.
607 This way we don't have to restart enum after each completion.
609 InsertHeadList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
613 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);
615 //complete irp's (if any)
616 while (!IsListEmpty(&CompletedListHead
))
618 EnumEntry
= RemoveTailList(&CompletedListHead
);
620 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
622 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
623 Irp
->IoStatus
.Information
= 0;
625 if (FileLock
->CompleteLockIrpRoutine
)
627 if (FileLock
->CompleteLockIrpRoutine(Context
, Irp
)!=STATUS_SUCCESS
)
629 Stack
= IoGetCurrentIrpStackLocation(Irp
);
632 FsRtlpUnlockSingle ( FileLock
,
634 &Stack
->Parameters
.LockControl
.ByteOffset
,
635 Stack
->Parameters
.LockControl
.Length
,
636 IoGetRequestorProcess(Irp
),
637 Stack
->Parameters
.LockControl
.Key
,
638 NULL
, /* unused context */
639 FALSE
/* don't call unlock copletion rout.*/
645 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
650 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
655 /**********************************************************************
663 IN PFILE_LOCK FileLock
,
664 IN PFILE_OBJECT FileObject
,
665 IN PLARGE_INTEGER FileOffset
,
666 IN PLARGE_INTEGER Length
,
667 IN PEPROCESS Process
,
669 IN PVOID Context OPTIONAL
,
670 IN BOOLEAN CallUnlockRoutine
674 PFILE_LOCK_TOC LockToc
;
675 PFILE_LOCK_GRANTED Granted
;
676 PLIST_ENTRY EnumEntry
;
679 LockToc
= FileLock
->LockInformation
;
683 return STATUS_RANGE_NOT_LOCKED
;
686 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
688 LIST_FOR_EACH_SAFE(EnumEntry
, &LockToc
->GrantedListHead
, Granted
,FILE_LOCK_GRANTED
,ListEntry
)
691 //must be exact match
692 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
693 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
694 Granted
->Lock
.Process
== Process
&&
695 Granted
->Lock
.FileObject
== FileObject
&&
696 Granted
->Lock
.Key
== Key
)
698 RemoveEntryList(&Granted
->ListEntry
);
699 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
701 if (IsListEmpty(&LockToc
->GrantedListHead
))
703 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
705 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
; //paged data
709 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
712 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
714 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
717 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
719 return STATUS_SUCCESS
;
723 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
725 return STATUS_RANGE_NOT_LOCKED
;
731 /**********************************************************************
733 * FsRtlFastUnlockSingle
739 FsRtlFastUnlockSingle (
740 IN PFILE_LOCK FileLock
,
741 IN PFILE_OBJECT FileObject
,
742 IN PLARGE_INTEGER FileOffset
,
743 IN PLARGE_INTEGER Length
,
744 IN PEPROCESS Process
,
746 IN PVOID Context OPTIONAL
,
747 IN BOOLEAN AlreadySynchronized
750 return FsRtlpUnlockSingle( FileLock
,
757 TRUE
/* call unlock copletion routine */
761 /**********************************************************************
763 * FsRtlpDumpFileLocks
765 * NOTE: used for testing and debugging
770 IN PFILE_LOCK FileLock
774 PFILE_LOCK_TOC LockToc
;
775 PFILE_LOCK_GRANTED Granted
;
777 PLIST_ENTRY EnumEntry
;
778 PIO_STACK_LOCATION Stack
;
781 LockToc
= FileLock
->LockInformation
;
785 DPRINT1("No file locks\n");
789 DPRINT1("Dumping granted file locks, FIFO order\n");
791 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
793 LIST_FOR_EACH(EnumEntry
, &LockToc
->GrantedListHead
)
795 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
797 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
798 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
799 Granted
->Lock
.StartingByte
.QuadPart
,
800 Granted
->Lock
.Length
.QuadPart
,
801 Granted
->Lock
.EndingByte
.QuadPart
,
803 Granted
->Lock
.Process
,
804 Granted
->Lock
.FileObject
809 DPRINT1("Dumping pending file locks, FIFO order\n");
811 LIST_FOR_EACH(EnumEntry
, &LockToc
->PendingListHead
)
813 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
814 Stack
= IoGetCurrentIrpStackLocation(Irp
);
816 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
817 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
818 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
819 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
820 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
821 Stack
->Parameters
.LockControl
.Key
,
822 IoGetRequestorProcess(Irp
),
828 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
833 /**********************************************************************
835 * FsRtlGetNextFileLock
838 * NULL if no more locks.
844 FsRtlGetNextFileLock (
845 IN PFILE_LOCK FileLock
,
850 Messy enumeration of granted locks.
851 What our last ptr. in LastReturnedLock points at, might have been freed between
852 calls, so we have to scan thru the list every time, searching for our last lock.
853 If it's not there anymore, restart the enumeration...
856 PLIST_ENTRY EnumEntry
;
857 PFILE_LOCK_GRANTED Granted
;
858 PFILE_LOCK_TOC LockToc
;
859 BOOLEAN FoundPrevious
= FALSE
;
860 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
861 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
862 PVOID LocalLastReturnedLock
;
865 LockToc
= FileLock
->LockInformation
;
871 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
873 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
877 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
881 if (EnumEntry
!= &LockToc
->GrantedListHead
)
883 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
884 LocalLastReturnedLockInfo
= Granted
->Lock
;
885 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
887 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
888 FileLock
->LastReturnedLock
= EnumEntry
;
889 return &FileLock
->LastReturnedLockInfo
;
893 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
898 //else: continue enum
899 while (EnumEntry
!= &LockToc
->GrantedListHead
)
901 //found previous lock?
902 if (EnumEntry
== LocalLastReturnedLock
)
904 FoundPrevious
= TRUE
;
906 EnumEntry
= EnumEntry
->Flink
;
907 if (EnumEntry
!= &LockToc
->GrantedListHead
)
909 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
910 LocalLastReturnedLockInfo
= Granted
->Lock
;
911 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
913 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
914 FileLock
->LastReturnedLock
= EnumEntry
;
915 return &FileLock
->LastReturnedLockInfo
;
919 EnumEntry
= EnumEntry
->Flink
;
924 //got here? uh no, didn't find our last lock..must have been freed...restart
929 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
931 return NULL
;//no (more) locks
935 /**********************************************************************
937 * FsRtlInitializeFileLock
940 * Called when creating/allocating/initializing FCB
946 FsRtlInitializeFileLock (
947 IN PFILE_LOCK FileLock
,
948 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
949 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
953 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
954 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
955 FileLock
->UnlockRoutine
= UnlockRoutine
;
956 FileLock
->LockInformation
= NULL
;
961 /**********************************************************************
970 IN PFILE_LOCK FileLock
,
971 IN PFILE_OBJECT FileObject
,
972 IN PLARGE_INTEGER FileOffset
,
973 IN PLARGE_INTEGER Length
,
974 IN PEPROCESS Process
,
976 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
977 IN BOOLEAN ExclusiveLock
,
978 OUT PIO_STATUS_BLOCK IoStatus
,
979 IN PIRP Irp OPTIONAL
,
980 IN PVOID Context OPTIONAL
,
981 IN BOOLEAN AlreadySynchronized
984 PFILE_LOCK_TOC LockToc
;
988 if (FileLock
->LockInformation
== NULL
)
990 ExAcquireFastMutex(&LockTocMutex
);
992 if (FileLock
->LockInformation
== NULL
)
994 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
995 LockToc
= FileLock
->LockInformation
;
996 KeInitializeSpinLock(&LockToc
->SpinLock
);
997 InitializeListHead(&LockToc
->GrantedListHead
);
998 InitializeListHead(&LockToc
->PendingListHead
);
1000 ExReleaseFastMutex(&LockTocMutex
);
1003 LockToc
= FileLock
->LockInformation
;
1004 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1006 //try add new lock (while holding spin lock)
1007 if (FsRtlpAddLock(LockToc
,
1017 IoStatus
->Status
= STATUS_SUCCESS
;
1019 else if (Irp
&& !FailImmediately
)
1021 //failed + irp + no fail = make. pending
1023 Irp
->Tail
.Overlay
.DriverContext
[3] = &LockToc
->SpinLock
;
1024 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
1026 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
1027 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
1030 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1032 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1033 Irp
->IoStatus
.Information
= 0;
1034 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1039 IoMarkIrpPending(Irp
);
1040 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1041 Irp
->IoStatus
.Information
= 0;
1042 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1047 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1050 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1052 //never pending if no irp;-)
1053 ASSERT(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1055 if (IoStatus
->Status
!= STATUS_PENDING
)
1057 if (IoStatus
->Status
== STATUS_SUCCESS
)
1059 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1064 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1065 Irp
->IoStatus
.Information
= 0;
1066 if (FileLock
->CompleteLockIrpRoutine
)
1068 if (FileLock
->CompleteLockIrpRoutine(Context
,Irp
)!=STATUS_SUCCESS
)
1070 //CompleteLockIrpRoutine complain: revert changes
1071 FsRtlpUnlockSingle( FileLock
,
1078 FALSE
/* don't call unlock copletion routine */
1084 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1089 //NOTE: only fast io seems to care about this return value
1090 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1096 /**********************************************************************
1098 * FsRtlProcessFileLock
1104 FsRtlProcessFileLock (
1105 IN PFILE_LOCK FileLock
,
1107 IN PVOID Context OPTIONAL
1110 PIO_STACK_LOCATION Stack
;
1112 IO_STATUS_BLOCK LocalIoStatus
;
1115 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1116 Irp
->IoStatus
.Information
= 0;
1118 switch(Stack
->MinorFunction
)
1122 FsRtlPrivateLock( FileLock
,
1124 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1125 Stack
->Parameters
.LockControl
.Length
,
1126 IoGetRequestorProcess(Irp
),
1127 Stack
->Parameters
.LockControl
.Key
,
1128 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1129 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1135 return LocalIoStatus
.Status
;
1137 case IRP_MN_UNLOCK_SINGLE
:
1138 Status
= FsRtlFastUnlockSingle ( FileLock
,
1140 &Stack
->Parameters
.LockControl
.ByteOffset
,
1141 Stack
->Parameters
.LockControl
.Length
,
1142 IoGetRequestorProcess(Irp
),
1143 Stack
->Parameters
.LockControl
.Key
,
1148 case IRP_MN_UNLOCK_ALL
:
1149 Status
= FsRtlFastUnlockAll( FileLock
,
1151 IoGetRequestorProcess(Irp
),
1155 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1156 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1158 IoGetRequestorProcess(Irp
),
1159 Stack
->Parameters
.LockControl
.Key
,
1165 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1166 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1171 Irp
->IoStatus
.Status
= Status
;
1172 Irp
->IoStatus
.Information
= 0;
1174 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1180 /**********************************************************************
1182 * FsRtlUninitializeFileLock
1188 FsRtlUninitializeFileLock (
1189 IN PFILE_LOCK FileLock
1192 PFILE_LOCK_TOC LockToc
;
1194 PFILE_LOCK_GRANTED Granted
;
1195 PLIST_ENTRY EnumEntry
;
1199 if (FileLock
->LockInformation
== NULL
)
1204 LockToc
= FileLock
->LockInformation
;
1206 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1208 //remove and free granted locks
1209 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1211 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1212 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1213 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1216 //remove, complete and free all pending locks
1217 while (!IsListEmpty(&LockToc
->PendingListHead
))
1219 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1220 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1222 if (!IoSetCancelRoutine(Irp
, NULL
))
1224 //The cancel routine will be called. When we release the lock it will complete the irp.
1225 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1229 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1231 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1232 Irp
->IoStatus
.Information
= 0;
1233 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1235 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1239 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1241 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1243 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1244 FileLock
->LockInformation
= NULL
;
1249 /**********************************************************************
1251 * FsRtlAllocateFileLock
1254 * Only present in NT 5.0 or later.
1255 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1261 FsRtlAllocateFileLock(
1262 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1263 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1266 PFILE_LOCK FileLock
;
1268 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1270 FsRtlInitializeFileLock(FileLock
,
1271 CompleteLockIrpRoutine
,
1278 /**********************************************************************
1283 * Only present in NT 5.0 or later.
1284 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1291 IN PFILE_LOCK FileLock
1296 FsRtlUninitializeFileLock(FileLock
);
1297 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);
1305 FsRtlAcquireFileExclusive(
1306 IN PFILE_OBJECT FileObject
1309 PFAST_IO_DISPATCH FastDispatch
;
1310 PDEVICE_OBJECT DeviceObject
;
1311 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1313 /* Get the Device Object */
1314 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1316 /* Check if we have to do a Fast I/O Dispatch */
1317 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1319 /* Call the Fast I/O Routine */
1320 if (FastDispatch
->AcquireFileForNtCreateSection
) {
1321 FastDispatch
->AcquireFileForNtCreateSection(FileObject
);
1327 /* Do a normal acquire */
1328 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1330 /* Use a Resource Acquire */
1331 ExAcquireResourceExclusive(FcbHeader
->Resource
, TRUE
);
1336 /* Return...is there some kind of failure we should raise?? */
1346 IN PFILE_OBJECT FileObject
1349 PFAST_IO_DISPATCH FastDispatch
;
1350 PDEVICE_OBJECT DeviceObject
;
1351 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1353 /* Get the Device Object */
1354 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1356 /* Check if we have to do a Fast I/O Dispatch */
1357 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1360 if (FastDispatch
->ReleaseFileForNtCreateSection
) {
1361 FastDispatch
->ReleaseFileForNtCreateSection(FileObject
);
1367 /* Do a normal acquire */
1368 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1370 /* Use a Resource Release */
1371 ExReleaseResource(FcbHeader
->Resource
);
1376 /* Return...is there some kind of failure we should raise?? */