3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/fs/filelock.c
6 * PURPOSE: No purpose listed.
8 * PROGRAMMERS: No programmer listed.
13 #include <internal/debug.h>
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, FsRtlpInitFileLockingImplementation)
22 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
23 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
25 UPDATE: I'm not sure about this! -Gunnar
28 FAST_MUTEX LockTocMutex
;
29 NPAGED_LOOKASIDE_LIST GrantedLookaside
;
30 NPAGED_LOOKASIDE_LIST LockTocLookaside
;
31 PAGED_LOOKASIDE_LIST LockLookaside
;
38 PLARGE_INTEGER StartOffset
,
39 PLARGE_INTEGER EndOffset
42 if ((ULONGLONG
)StartOffset
->QuadPart
> (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
47 if ((ULONGLONG
)EndOffset
->QuadPart
< (ULONGLONG
)Lock
->StartingByte
.QuadPart
)
59 PLARGE_INTEGER StartOffset
,
60 PLARGE_INTEGER EndOffset
63 if ((ULONGLONG
)StartOffset
->QuadPart
>= (ULONGLONG
)Lock
->StartingByte
.QuadPart
&&
64 (ULONGLONG
)EndOffset
->QuadPart
<= (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
73 /**********************************************************************
75 * FsRtlpInitFileLockingImplementation
80 FsRtlpInitFileLockingImplementation(VOID
)
82 ExInitializeNPagedLookasideList( &LockTocLookaside
,
86 sizeof(FILE_LOCK_TOC
),
91 ExInitializeNPagedLookasideList( &GrantedLookaside
,
95 sizeof(FILE_LOCK_GRANTED
),
100 ExInitializePagedLookasideList( &LockLookaside
,
109 ExInitializeFastMutex(&LockTocMutex
);
113 /**********************************************************************
115 * FsRtlpFileLockCancelRoutine
120 FsRtlpFileLockCancelRoutine(
121 IN PDEVICE_OBJECT DeviceObject
,
126 PKSPIN_LOCK SpinLock
;
128 //don't need this since we have our own sync. protecting irp cancellation
129 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
131 SpinLock
= Irp
->Tail
.Overlay
.DriverContext
[3];
133 KeAcquireSpinLock(SpinLock
, &oldIrql
);
135 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
137 KeReleaseSpinLock(SpinLock
, oldIrql
);
139 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
140 Irp
->IoStatus
.Information
= 0;
142 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
146 /**********************************************************************
148 * FsRtlpCheckLockForReadOrWriteAccess
151 * TRUE: can read/write
152 * FALSE: can't read/write
156 FsRtlpCheckLockForReadOrWriteAccess(
157 IN PFILE_LOCK FileLock
,
158 IN PLARGE_INTEGER FileOffset
,
159 IN PLARGE_INTEGER Length
,
161 IN PFILE_OBJECT FileObject
,
162 IN PEPROCESS Process
,
167 PFILE_LOCK_TOC LockToc
;
168 PFILE_LOCK_GRANTED Granted
;
169 LARGE_INTEGER EndOffset
;
173 LockToc
= FileLock
->LockInformation
;
175 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
180 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
182 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
184 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
187 if(IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
189 //No read conflict if (shared lock) OR (exclusive + our lock)
190 //No write conflict if exclusive lock AND our lock
191 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
192 (Granted
->Lock
.ExclusiveLock
&&
193 Granted
->Lock
.Process
== Process
&&
194 Granted
->Lock
.FileObject
== FileObject
&&
195 Granted
->Lock
.Key
== Key
) )
197 //AND if lock surround request region, stop searching and grant
198 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
) )
200 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
204 //else continue searching for conflicts
209 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
216 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
221 /**********************************************************************
223 * FsRtlCheckLockForReadAccess
229 FsRtlCheckLockForReadAccess (
230 IN PFILE_LOCK FileLock
,
234 PIO_STACK_LOCATION Stack
;
235 LARGE_INTEGER LocalLength
;
237 Stack
= IoGetCurrentIrpStackLocation(Irp
);
239 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
240 LocalLength
.u
.HighPart
= 0;
242 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
243 &Stack
->Parameters
.Read
.ByteOffset
,
245 Stack
->Parameters
.Read
.Key
,
247 IoGetRequestorProcess(Irp
),
253 /**********************************************************************
255 * FsRtlCheckLockForWriteAccess
261 FsRtlCheckLockForWriteAccess (
262 IN PFILE_LOCK FileLock
,
266 PIO_STACK_LOCATION Stack
;
267 LARGE_INTEGER LocalLength
;
269 Stack
= IoGetCurrentIrpStackLocation(Irp
);
271 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
272 LocalLength
.u
.HighPart
= 0;
274 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
275 &Stack
->Parameters
.Write
.ByteOffset
,
277 Stack
->Parameters
.Write
.Key
,
279 IoGetRequestorProcess(Irp
),
288 /**********************************************************************
290 * FsRtlFastCheckLockForRead
296 FsRtlFastCheckLockForRead (
297 IN PFILE_LOCK FileLock
,
298 IN PLARGE_INTEGER FileOffset
,
299 IN PLARGE_INTEGER Length
,
301 IN PFILE_OBJECT FileObject
,
305 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
316 /**********************************************************************
318 * FsRtlFastCheckLockForWrite
324 FsRtlFastCheckLockForWrite (
325 IN PFILE_LOCK FileLock
,
326 IN PLARGE_INTEGER FileOffset
,
327 IN PLARGE_INTEGER Length
,
329 IN PFILE_OBJECT FileObject
,
333 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
345 /**********************************************************************
347 * FsRtlpFastUnlockAllByKey
352 FsRtlpFastUnlockAllByKey(
353 IN PFILE_LOCK FileLock
,
354 IN PFILE_OBJECT FileObject
,
355 IN PEPROCESS Process
,
358 IN PVOID Context OPTIONAL
362 PFILE_LOCK_TOC LockToc
;
363 PFILE_LOCK_GRANTED Granted
, tmp
;
364 BOOLEAN Unlock
= FALSE
;
365 //must make local copy since FILE_LOCK struct is allowed to be paged
366 BOOLEAN GotUnlockRoutine
;
367 LIST_ENTRY UnlockedListHead
;
368 PLIST_ENTRY EnumEntry
;
371 LockToc
= FileLock
->LockInformation
;
375 return STATUS_RANGE_NOT_LOCKED
;
378 InitializeListHead(&UnlockedListHead
);
379 GotUnlockRoutine
= FileLock
->UnlockRoutine
!= NULL
;
380 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
382 LIST_FOR_EACH_SAFE(Granted
, tmp
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
385 if (Granted
->Lock
.Process
== Process
&&
386 Granted
->Lock
.FileObject
== FileObject
&&
387 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
389 RemoveEntryList(&Granted
->ListEntry
);
392 if (GotUnlockRoutine
)
395 Put on unlocked list and call unlock routine for them afterwards.
396 This way we don't have to restart enum after each call
398 InsertHeadList(&UnlockedListHead
,&Granted
->ListEntry
);
402 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
407 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
411 //call unlock routine for each unlocked lock (if any)
412 while (!IsListEmpty(&UnlockedListHead
))
414 EnumEntry
= RemoveTailList(&UnlockedListHead
);
415 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
417 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
418 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
421 //NOTE: holding spinlock while calling this
422 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
423 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
425 if (IsListEmpty(&LockToc
->GrantedListHead
))
427 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
428 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
432 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
435 return STATUS_SUCCESS
;
438 return STATUS_RANGE_NOT_LOCKED
;
441 /**********************************************************************
449 FsRtlFastUnlockAll
/*ByProcess*/ (
450 IN PFILE_LOCK FileLock
,
451 IN PFILE_OBJECT FileObject
,
452 IN PEPROCESS Process
,
453 IN PVOID Context OPTIONAL
456 return FsRtlpFastUnlockAllByKey( FileLock
,
459 0, /* Key is ignored */
460 FALSE
, /* Do NOT use Key */
465 /**********************************************************************
467 * FsRtlFastUnlockAllByKey
473 FsRtlFastUnlockAllByKey (
474 IN PFILE_LOCK FileLock
,
475 IN PFILE_OBJECT FileObject
,
476 IN PEPROCESS Process
,
478 IN PVOID Context OPTIONAL
481 return FsRtlpFastUnlockAllByKey( FileLock
,
491 /**********************************************************************
496 * Spinlock held at entry !!
501 IN PFILE_LOCK_TOC LockToc
,
502 IN PFILE_OBJECT FileObject
,
503 IN PLARGE_INTEGER FileOffset
,
504 IN PLARGE_INTEGER Length
,
505 IN PEPROCESS Process
,
507 IN BOOLEAN ExclusiveLock
,
511 PFILE_LOCK_GRANTED Granted
;
512 LARGE_INTEGER EndOffset
;
514 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
516 //loop and try to find conflicking locks
517 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
519 if (IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
521 //we found a locks that overlap with the new lock
523 //if both locks are shared, we might have a fast path outa here...
524 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
526 //if existing lock surround new lock, we know that no other exclusive lock
527 //may overlap with our new lock;-D
528 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
533 //else keep locking for conflicts
537 //we found a conflict:
538 //we want shared access to an excl. lock OR exlc. access to a shared lock
543 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
546 Granted
->Lock
.StartingByte
= *FileOffset
;
547 Granted
->Lock
.Length
= *Length
;
548 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
549 Granted
->Lock
.Key
= Key
;
550 Granted
->Lock
.FileObject
= FileObject
;
551 Granted
->Lock
.Process
= Process
;
553 Granted
->Lock
.EndingByte
= EndOffset
;
554 Granted
->UnlockContext
= Context
;
556 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
562 /**********************************************************************
564 * FsRtlpCompletePendingLocks
567 * Spinlock held at entry !!
571 FsRtlpCompletePendingLocks(
572 IN PFILE_LOCK FileLock
,
573 IN PFILE_LOCK_TOC LockToc
,
574 IN OUT PKIRQL oldirql
,
578 //walk pending list, FIFO order, try 2 complete locks
579 PLIST_ENTRY EnumEntry
;
581 PIO_STACK_LOCATION Stack
;
582 LIST_ENTRY CompletedListHead
;
584 InitializeListHead(&CompletedListHead
);
586 LIST_FOR_EACH_SAFE(Irp
, tmp
, &LockToc
->PendingListHead
, IRP
, Tail
.Overlay
.ListEntry
)
588 Stack
= IoGetCurrentIrpStackLocation(Irp
);
589 if (FsRtlpAddLock(LockToc
,
591 &Stack
->Parameters
.LockControl
.ByteOffset
,
592 Stack
->Parameters
.LockControl
.Length
,
593 IoGetRequestorProcess(Irp
),
594 Stack
->Parameters
.LockControl
.Key
,
595 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
596 Irp
->Tail
.Overlay
.DriverContext
[2] //Context
599 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
601 if (!IoSetCancelRoutine(Irp
, NULL
))
603 //irp is canceled and cancelroutine will run when we release the lock
604 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
609 Put on completed list and complete them all afterwards.
610 This way we don't have to restart enum after each completion.
612 InsertHeadList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
616 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);
618 //complete irp's (if any)
619 while (!IsListEmpty(&CompletedListHead
))
621 EnumEntry
= RemoveTailList(&CompletedListHead
);
623 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
625 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
626 Irp
->IoStatus
.Information
= 0;
628 if (FileLock
->CompleteLockIrpRoutine
)
630 if (FileLock
->CompleteLockIrpRoutine(Context
, Irp
)!=STATUS_SUCCESS
)
632 Stack
= IoGetCurrentIrpStackLocation(Irp
);
635 FsRtlpUnlockSingle ( FileLock
,
637 &Stack
->Parameters
.LockControl
.ByteOffset
,
638 Stack
->Parameters
.LockControl
.Length
,
639 IoGetRequestorProcess(Irp
),
640 Stack
->Parameters
.LockControl
.Key
,
641 NULL
, /* unused context */
642 FALSE
/* don't call unlock copletion rout.*/
648 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
653 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
658 /**********************************************************************
666 IN PFILE_LOCK FileLock
,
667 IN PFILE_OBJECT FileObject
,
668 IN PLARGE_INTEGER FileOffset
,
669 IN PLARGE_INTEGER Length
,
670 IN PEPROCESS Process
,
672 IN PVOID Context OPTIONAL
,
673 IN BOOLEAN CallUnlockRoutine
677 PFILE_LOCK_TOC LockToc
;
678 PFILE_LOCK_GRANTED Granted
, tmp
;
681 LockToc
= FileLock
->LockInformation
;
685 return STATUS_RANGE_NOT_LOCKED
;
688 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
690 LIST_FOR_EACH_SAFE(Granted
, tmp
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
,ListEntry
)
693 //must be exact match
694 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
695 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
696 Granted
->Lock
.Process
== Process
&&
697 Granted
->Lock
.FileObject
== FileObject
&&
698 Granted
->Lock
.Key
== Key
)
700 RemoveEntryList(&Granted
->ListEntry
);
701 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
703 if (IsListEmpty(&LockToc
->GrantedListHead
))
705 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
707 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
; //paged data
711 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
714 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
716 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
719 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
721 return STATUS_SUCCESS
;
725 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
727 return STATUS_RANGE_NOT_LOCKED
;
733 /**********************************************************************
735 * FsRtlFastUnlockSingle
741 FsRtlFastUnlockSingle (
742 IN PFILE_LOCK FileLock
,
743 IN PFILE_OBJECT FileObject
,
744 IN PLARGE_INTEGER FileOffset
,
745 IN PLARGE_INTEGER Length
,
746 IN PEPROCESS Process
,
748 IN PVOID Context OPTIONAL
,
749 IN BOOLEAN AlreadySynchronized
752 return FsRtlpUnlockSingle( FileLock
,
759 TRUE
/* call unlock copletion routine */
763 /**********************************************************************
765 * FsRtlpDumpFileLocks
767 * NOTE: used for testing and debugging
772 IN PFILE_LOCK FileLock
776 PFILE_LOCK_TOC LockToc
;
777 PFILE_LOCK_GRANTED Granted
;
779 PIO_STACK_LOCATION Stack
;
782 LockToc
= FileLock
->LockInformation
;
786 DPRINT1("No file locks\n");
790 DPRINT1("Dumping granted file locks, FIFO order\n");
792 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
794 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
796 DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
797 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
798 Granted
->Lock
.StartingByte
.QuadPart
,
799 Granted
->Lock
.Length
.QuadPart
,
800 Granted
->Lock
.EndingByte
.QuadPart
,
802 Granted
->Lock
.Process
,
803 Granted
->Lock
.FileObject
808 DPRINT1("Dumping pending file locks, FIFO order\n");
810 LIST_FOR_EACH(Irp
, &LockToc
->PendingListHead
, IRP
, Tail
.Overlay
.ListEntry
)
812 Stack
= IoGetCurrentIrpStackLocation(Irp
);
814 DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
815 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
816 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
817 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
818 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
819 Stack
->Parameters
.LockControl
.Key
,
820 IoGetRequestorProcess(Irp
),
826 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
831 /**********************************************************************
833 * FsRtlGetNextFileLock
836 * NULL if no more locks.
842 FsRtlGetNextFileLock (
843 IN PFILE_LOCK FileLock
,
848 Messy enumeration of granted locks.
849 What our last ptr. in LastReturnedLock points at, might have been freed between
850 calls, so we have to scan thru the list every time, searching for our last lock.
851 If it's not there anymore, restart the enumeration...
854 PLIST_ENTRY EnumEntry
;
855 PFILE_LOCK_GRANTED Granted
;
856 PFILE_LOCK_TOC LockToc
;
857 BOOLEAN FoundPrevious
= FALSE
;
858 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
859 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
860 PVOID LocalLastReturnedLock
;
863 LockToc
= FileLock
->LockInformation
;
869 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
871 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
875 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
879 if (EnumEntry
!= &LockToc
->GrantedListHead
)
881 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
882 LocalLastReturnedLockInfo
= Granted
->Lock
;
883 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
885 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
886 FileLock
->LastReturnedLock
= EnumEntry
;
887 return &FileLock
->LastReturnedLockInfo
;
891 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
896 //else: continue enum
897 while (EnumEntry
!= &LockToc
->GrantedListHead
)
899 //found previous lock?
900 if (EnumEntry
== LocalLastReturnedLock
)
902 FoundPrevious
= TRUE
;
904 EnumEntry
= EnumEntry
->Flink
;
905 if (EnumEntry
!= &LockToc
->GrantedListHead
)
907 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
908 LocalLastReturnedLockInfo
= Granted
->Lock
;
909 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
911 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
912 FileLock
->LastReturnedLock
= EnumEntry
;
913 return &FileLock
->LastReturnedLockInfo
;
917 EnumEntry
= EnumEntry
->Flink
;
922 //got here? uh no, didn't find our last lock..must have been freed...restart
927 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
929 return NULL
;//no (more) locks
933 /**********************************************************************
935 * FsRtlInitializeFileLock
938 * Called when creating/allocating/initializing FCB
944 FsRtlInitializeFileLock (
945 IN PFILE_LOCK FileLock
,
946 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
947 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
951 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
952 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
953 FileLock
->UnlockRoutine
= UnlockRoutine
;
954 FileLock
->LockInformation
= NULL
;
959 /**********************************************************************
968 IN PFILE_LOCK FileLock
,
969 IN PFILE_OBJECT FileObject
,
970 IN PLARGE_INTEGER FileOffset
,
971 IN PLARGE_INTEGER Length
,
972 IN PEPROCESS Process
,
974 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
975 IN BOOLEAN ExclusiveLock
,
976 OUT PIO_STATUS_BLOCK IoStatus
,
977 IN PIRP Irp OPTIONAL
,
978 IN PVOID Context OPTIONAL
,
979 IN BOOLEAN AlreadySynchronized
982 PFILE_LOCK_TOC LockToc
;
986 if (FileLock
->LockInformation
== NULL
)
988 ExAcquireFastMutex(&LockTocMutex
);
990 if (FileLock
->LockInformation
== NULL
)
992 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
993 LockToc
= FileLock
->LockInformation
;
994 KeInitializeSpinLock(&LockToc
->SpinLock
);
995 InitializeListHead(&LockToc
->GrantedListHead
);
996 InitializeListHead(&LockToc
->PendingListHead
);
998 ExReleaseFastMutex(&LockTocMutex
);
1001 LockToc
= FileLock
->LockInformation
;
1002 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1004 //try add new lock (while holding spin lock)
1005 if (FsRtlpAddLock(LockToc
,
1015 IoStatus
->Status
= STATUS_SUCCESS
;
1017 else if (Irp
&& !FailImmediately
)
1019 //failed + irp + no fail = make. pending
1021 Irp
->Tail
.Overlay
.DriverContext
[3] = &LockToc
->SpinLock
;
1022 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
1024 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
1025 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
1028 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1030 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1031 Irp
->IoStatus
.Information
= 0;
1032 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1037 IoMarkIrpPending(Irp
);
1038 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1039 Irp
->IoStatus
.Information
= 0;
1040 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1045 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1048 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1050 //never pending if no irp;-)
1051 ASSERT(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1053 if (IoStatus
->Status
!= STATUS_PENDING
)
1055 if (IoStatus
->Status
== STATUS_SUCCESS
)
1057 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1062 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1063 Irp
->IoStatus
.Information
= 0;
1064 if (FileLock
->CompleteLockIrpRoutine
)
1066 if (FileLock
->CompleteLockIrpRoutine(Context
,Irp
)!=STATUS_SUCCESS
)
1068 //CompleteLockIrpRoutine complain: revert changes
1069 FsRtlpUnlockSingle( FileLock
,
1076 FALSE
/* don't call unlock copletion routine */
1082 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1087 //NOTE: only fast io seems to care about this return value
1088 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1094 /**********************************************************************
1096 * FsRtlProcessFileLock
1102 FsRtlProcessFileLock (
1103 IN PFILE_LOCK FileLock
,
1105 IN PVOID Context OPTIONAL
1108 PIO_STACK_LOCATION Stack
;
1110 IO_STATUS_BLOCK LocalIoStatus
;
1113 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1114 Irp
->IoStatus
.Information
= 0;
1116 switch(Stack
->MinorFunction
)
1120 FsRtlPrivateLock( FileLock
,
1122 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1123 Stack
->Parameters
.LockControl
.Length
,
1124 IoGetRequestorProcess(Irp
),
1125 Stack
->Parameters
.LockControl
.Key
,
1126 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1127 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1133 return LocalIoStatus
.Status
;
1135 case IRP_MN_UNLOCK_SINGLE
:
1136 Status
= FsRtlFastUnlockSingle ( FileLock
,
1138 &Stack
->Parameters
.LockControl
.ByteOffset
,
1139 Stack
->Parameters
.LockControl
.Length
,
1140 IoGetRequestorProcess(Irp
),
1141 Stack
->Parameters
.LockControl
.Key
,
1146 case IRP_MN_UNLOCK_ALL
:
1147 Status
= FsRtlFastUnlockAll( FileLock
,
1149 IoGetRequestorProcess(Irp
),
1153 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1154 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1156 IoGetRequestorProcess(Irp
),
1157 Stack
->Parameters
.LockControl
.Key
,
1163 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1164 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1169 Irp
->IoStatus
.Status
= Status
;
1170 Irp
->IoStatus
.Information
= 0;
1172 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1178 /**********************************************************************
1180 * FsRtlUninitializeFileLock
1186 FsRtlUninitializeFileLock (
1187 IN PFILE_LOCK FileLock
1190 PFILE_LOCK_TOC LockToc
;
1192 PFILE_LOCK_GRANTED Granted
;
1193 PLIST_ENTRY EnumEntry
;
1197 if (FileLock
->LockInformation
== NULL
)
1202 LockToc
= FileLock
->LockInformation
;
1204 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1206 //remove and free granted locks
1207 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1209 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1210 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1211 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1214 //remove, complete and free all pending locks
1215 while (!IsListEmpty(&LockToc
->PendingListHead
))
1217 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1218 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1220 if (!IoSetCancelRoutine(Irp
, NULL
))
1222 //The cancel routine will be called. When we release the lock it will complete the irp.
1223 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1227 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1229 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1230 Irp
->IoStatus
.Information
= 0;
1231 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1233 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1237 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1239 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1241 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1242 FileLock
->LockInformation
= NULL
;
1247 /**********************************************************************
1249 * FsRtlAllocateFileLock
1252 * Only present in NT 5.0 or later.
1253 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1259 FsRtlAllocateFileLock(
1260 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1261 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1264 PFILE_LOCK FileLock
;
1266 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1268 FsRtlInitializeFileLock(FileLock
,
1269 CompleteLockIrpRoutine
,
1276 /**********************************************************************
1281 * Only present in NT 5.0 or later.
1282 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1289 IN PFILE_LOCK FileLock
1294 FsRtlUninitializeFileLock(FileLock
);
1295 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);
1303 FsRtlAcquireFileExclusive(
1304 IN PFILE_OBJECT FileObject
1307 PFAST_IO_DISPATCH FastDispatch
;
1308 PDEVICE_OBJECT DeviceObject
;
1309 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1311 /* Get the Device Object */
1312 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1314 /* Check if we have to do a Fast I/O Dispatch */
1315 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1317 /* Call the Fast I/O Routine */
1318 if (FastDispatch
->AcquireFileForNtCreateSection
) {
1319 FastDispatch
->AcquireFileForNtCreateSection(FileObject
);
1325 /* Do a normal acquire */
1326 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1328 /* Use a Resource Acquire */
1329 ExAcquireResourceExclusive(FcbHeader
->Resource
, TRUE
);
1334 /* Return...is there some kind of failure we should raise?? */
1344 IN PFILE_OBJECT FileObject
1347 PFAST_IO_DISPATCH FastDispatch
;
1348 PDEVICE_OBJECT DeviceObject
;
1349 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1351 /* Get the Device Object */
1352 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1354 /* Check if we have to do a Fast I/O Dispatch */
1355 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1358 if (FastDispatch
->ReleaseFileForNtCreateSection
) {
1359 FastDispatch
->ReleaseFileForNtCreateSection(FileObject
);
1365 /* Do a normal acquire */
1366 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1368 /* Use a Resource Release */
1369 ExReleaseResourceLite(FcbHeader
->Resource
);
1374 /* Return...is there some kind of failure we should raise?? */