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>
17 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
18 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
20 UPDATE: I'm not sure about this! -Gunnar
23 FAST_MUTEX LockTocMutex
;
24 NPAGED_LOOKASIDE_LIST GrantedLookaside
;
25 NPAGED_LOOKASIDE_LIST LockTocLookaside
;
26 PAGED_LOOKASIDE_LIST LockLookaside
;
33 PLARGE_INTEGER StartOffset
,
34 PLARGE_INTEGER EndOffset
37 if ((ULONGLONG
)StartOffset
->QuadPart
> (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
42 if ((ULONGLONG
)EndOffset
->QuadPart
< (ULONGLONG
)Lock
->StartingByte
.QuadPart
)
54 PLARGE_INTEGER StartOffset
,
55 PLARGE_INTEGER EndOffset
58 if ((ULONGLONG
)StartOffset
->QuadPart
>= (ULONGLONG
)Lock
->StartingByte
.QuadPart
&&
59 (ULONGLONG
)EndOffset
->QuadPart
<= (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
68 /**********************************************************************
70 * FsRtlpInitFileLockingImplementation
75 FsRtlpInitFileLockingImplementation(VOID
)
77 ExInitializeNPagedLookasideList( &LockTocLookaside
,
81 sizeof(FILE_LOCK_TOC
),
86 ExInitializeNPagedLookasideList( &GrantedLookaside
,
90 sizeof(FILE_LOCK_GRANTED
),
95 ExInitializePagedLookasideList( &LockLookaside
,
104 ExInitializeFastMutex(&LockTocMutex
);
108 /**********************************************************************
110 * FsRtlpFileLockCancelRoutine
115 FsRtlpFileLockCancelRoutine(
116 IN PDEVICE_OBJECT DeviceObject
,
121 PKSPIN_LOCK SpinLock
;
123 //don't need this since we have our own sync. protecting irp cancellation
124 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
126 SpinLock
= Irp
->Tail
.Overlay
.DriverContext
[3];
128 KeAcquireSpinLock(SpinLock
, &oldIrql
);
130 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
132 KeReleaseSpinLock(SpinLock
, oldIrql
);
134 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
135 Irp
->IoStatus
.Information
= 0;
137 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
141 /**********************************************************************
143 * FsRtlpCheckLockForReadOrWriteAccess
146 * TRUE: can read/write
147 * FALSE: can't read/write
151 FsRtlpCheckLockForReadOrWriteAccess(
152 IN PFILE_LOCK FileLock
,
153 IN PLARGE_INTEGER FileOffset
,
154 IN PLARGE_INTEGER Length
,
156 IN PFILE_OBJECT FileObject
,
157 IN PEPROCESS Process
,
162 PFILE_LOCK_TOC LockToc
;
163 PFILE_LOCK_GRANTED Granted
;
164 PLIST_ENTRY EnumEntry
;
165 LARGE_INTEGER EndOffset
;
169 LockToc
= FileLock
->LockInformation
;
171 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
176 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
178 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
180 LIST_FOR_EACH(EnumEntry
, &LockToc
->GrantedListHead
)
182 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
185 if(IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
187 //No read conflict if (shared lock) OR (exclusive + our lock)
188 //No write conflict if exclusive lock AND our lock
189 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
190 (Granted
->Lock
.ExclusiveLock
&&
191 Granted
->Lock
.Process
== Process
&&
192 Granted
->Lock
.FileObject
== FileObject
&&
193 Granted
->Lock
.Key
== Key
) )
195 //AND if lock surround request region, stop searching and grant
196 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
) )
198 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
202 //else continue searching for conflicts
207 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
214 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
219 /**********************************************************************
221 * FsRtlCheckLockForReadAccess
227 FsRtlCheckLockForReadAccess (
228 IN PFILE_LOCK FileLock
,
232 PIO_STACK_LOCATION Stack
;
233 LARGE_INTEGER LocalLength
;
235 Stack
= IoGetCurrentIrpStackLocation(Irp
);
237 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
238 LocalLength
.u
.HighPart
= 0;
240 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
241 &Stack
->Parameters
.Read
.ByteOffset
,
243 Stack
->Parameters
.Read
.Key
,
245 IoGetRequestorProcess(Irp
),
251 /**********************************************************************
253 * FsRtlCheckLockForWriteAccess
259 FsRtlCheckLockForWriteAccess (
260 IN PFILE_LOCK FileLock
,
264 PIO_STACK_LOCATION Stack
;
265 LARGE_INTEGER LocalLength
;
267 Stack
= IoGetCurrentIrpStackLocation(Irp
);
269 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
270 LocalLength
.u
.HighPart
= 0;
272 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
273 &Stack
->Parameters
.Write
.ByteOffset
,
275 Stack
->Parameters
.Write
.Key
,
277 IoGetRequestorProcess(Irp
),
286 /**********************************************************************
288 * FsRtlFastCheckLockForRead
294 FsRtlFastCheckLockForRead (
295 IN PFILE_LOCK FileLock
,
296 IN PLARGE_INTEGER FileOffset
,
297 IN PLARGE_INTEGER Length
,
299 IN PFILE_OBJECT FileObject
,
303 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
314 /**********************************************************************
316 * FsRtlFastCheckLockForWrite
322 FsRtlFastCheckLockForWrite (
323 IN PFILE_LOCK FileLock
,
324 IN PLARGE_INTEGER FileOffset
,
325 IN PLARGE_INTEGER Length
,
327 IN PFILE_OBJECT FileObject
,
331 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
343 /**********************************************************************
345 * FsRtlpFastUnlockAllByKey
350 FsRtlpFastUnlockAllByKey(
351 IN PFILE_LOCK FileLock
,
352 IN PFILE_OBJECT FileObject
,
353 IN PEPROCESS Process
,
356 IN PVOID Context OPTIONAL
360 PFILE_LOCK_TOC LockToc
;
361 PLIST_ENTRY EnumEntry
;
362 PFILE_LOCK_GRANTED Granted
;
363 BOOLEAN Unlock
= FALSE
;
364 //must make local copy since FILE_LOCK struct is allowed to be paged
365 BOOLEAN GotUnlockRoutine
;
366 LIST_ENTRY UnlockedListHead
;
369 LockToc
= FileLock
->LockInformation
;
373 return STATUS_RANGE_NOT_LOCKED
;
376 InitializeListHead(&UnlockedListHead
);
377 GotUnlockRoutine
= FileLock
->UnlockRoutine
!= NULL
;
378 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
380 LIST_FOR_EACH_SAFE(EnumEntry
, &LockToc
->GrantedListHead
, Granted
, FILE_LOCK_GRANTED
, ListEntry
)
383 if (Granted
->Lock
.Process
== Process
&&
384 Granted
->Lock
.FileObject
== FileObject
&&
385 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
387 RemoveEntryList(&Granted
->ListEntry
);
390 if (GotUnlockRoutine
)
393 Put on unlocked list and call unlock routine for them afterwards.
394 This way we don't have to restart enum after each call
396 InsertHeadList(&UnlockedListHead
,&Granted
->ListEntry
);
400 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
405 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
409 //call unlock routine for each unlocked lock (if any)
410 while (!IsListEmpty(&UnlockedListHead
))
412 EnumEntry
= RemoveTailList(&UnlockedListHead
);
413 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
415 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
416 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
419 //NOTE: holding spinlock while calling this
420 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
421 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
423 if (IsListEmpty(&LockToc
->GrantedListHead
))
425 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
426 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
430 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
433 return STATUS_SUCCESS
;
436 return STATUS_RANGE_NOT_LOCKED
;
439 /**********************************************************************
447 FsRtlFastUnlockAll
/*ByProcess*/ (
448 IN PFILE_LOCK FileLock
,
449 IN PFILE_OBJECT FileObject
,
450 IN PEPROCESS Process
,
451 IN PVOID Context OPTIONAL
454 return FsRtlpFastUnlockAllByKey( FileLock
,
457 0, /* Key is ignored */
458 FALSE
, /* Do NOT use Key */
463 /**********************************************************************
465 * FsRtlFastUnlockAllByKey
471 FsRtlFastUnlockAllByKey (
472 IN PFILE_LOCK FileLock
,
473 IN PFILE_OBJECT FileObject
,
474 IN PEPROCESS Process
,
476 IN PVOID Context OPTIONAL
479 return FsRtlpFastUnlockAllByKey( FileLock
,
489 /**********************************************************************
494 * Spinlock held at entry !!
499 IN PFILE_LOCK_TOC LockToc
,
500 IN PFILE_OBJECT FileObject
,
501 IN PLARGE_INTEGER FileOffset
,
502 IN PLARGE_INTEGER Length
,
503 IN PEPROCESS Process
,
505 IN BOOLEAN ExclusiveLock
,
509 PLIST_ENTRY EnumEntry
;
510 PFILE_LOCK_GRANTED Granted
;
511 LARGE_INTEGER EndOffset
;
513 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
515 //loop and try to find conflicking locks
516 LIST_FOR_EACH(EnumEntry
, &LockToc
->GrantedListHead
)
518 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
520 if (IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
522 //we found a locks that overlap with the new lock
524 //if both locks are shared, we might have a fast path outa here...
525 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
527 //if existing lock surround new lock, we know that no other exclusive lock
528 //may overlap with our new lock;-D
529 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
534 //else keep locking for conflicts
538 //we found a conflict:
539 //we want shared access to an excl. lock OR exlc. access to a shared lock
544 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
547 Granted
->Lock
.StartingByte
= *FileOffset
;
548 Granted
->Lock
.Length
= *Length
;
549 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
550 Granted
->Lock
.Key
= Key
;
551 Granted
->Lock
.FileObject
= FileObject
;
552 Granted
->Lock
.Process
= Process
;
554 Granted
->Lock
.EndingByte
= EndOffset
;
555 Granted
->UnlockContext
= Context
;
557 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
563 /**********************************************************************
565 * FsRtlpCompletePendingLocks
568 * Spinlock held at entry !!
572 FsRtlpCompletePendingLocks(
573 IN PFILE_LOCK FileLock
,
574 IN PFILE_LOCK_TOC LockToc
,
575 IN OUT PKIRQL oldirql
,
579 //walk pending list, FIFO order, try 2 complete locks
580 PLIST_ENTRY EnumEntry
;
582 PIO_STACK_LOCATION Stack
;
583 LIST_ENTRY CompletedListHead
;
585 InitializeListHead(&CompletedListHead
);
587 LIST_FOR_EACH_SAFE(EnumEntry
, &LockToc
->PendingListHead
, Irp
, IRP
, Tail
.Overlay
.ListEntry
)
589 Stack
= IoGetCurrentIrpStackLocation(Irp
);
590 if (FsRtlpAddLock(LockToc
,
592 &Stack
->Parameters
.LockControl
.ByteOffset
,
593 Stack
->Parameters
.LockControl
.Length
,
594 IoGetRequestorProcess(Irp
),
595 Stack
->Parameters
.LockControl
.Key
,
596 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
597 Irp
->Tail
.Overlay
.DriverContext
[2] //Context
600 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
602 if (!IoSetCancelRoutine(Irp
, NULL
))
604 //irp is canceled and cancelroutine will run when we release the lock
605 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
610 Put on completed list and complete them all afterwards.
611 This way we don't have to restart enum after each completion.
613 InsertHeadList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
617 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);
619 //complete irp's (if any)
620 while (!IsListEmpty(&CompletedListHead
))
622 EnumEntry
= RemoveTailList(&CompletedListHead
);
624 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
626 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
627 Irp
->IoStatus
.Information
= 0;
629 if (FileLock
->CompleteLockIrpRoutine
)
631 if (FileLock
->CompleteLockIrpRoutine(Context
, Irp
)!=STATUS_SUCCESS
)
633 Stack
= IoGetCurrentIrpStackLocation(Irp
);
636 FsRtlpUnlockSingle ( FileLock
,
638 &Stack
->Parameters
.LockControl
.ByteOffset
,
639 Stack
->Parameters
.LockControl
.Length
,
640 IoGetRequestorProcess(Irp
),
641 Stack
->Parameters
.LockControl
.Key
,
642 NULL
, /* unused context */
643 FALSE
/* don't call unlock copletion rout.*/
649 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
654 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
659 /**********************************************************************
667 IN PFILE_LOCK FileLock
,
668 IN PFILE_OBJECT FileObject
,
669 IN PLARGE_INTEGER FileOffset
,
670 IN PLARGE_INTEGER Length
,
671 IN PEPROCESS Process
,
673 IN PVOID Context OPTIONAL
,
674 IN BOOLEAN CallUnlockRoutine
678 PFILE_LOCK_TOC LockToc
;
679 PFILE_LOCK_GRANTED Granted
;
680 PLIST_ENTRY EnumEntry
;
683 LockToc
= FileLock
->LockInformation
;
687 return STATUS_RANGE_NOT_LOCKED
;
690 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
692 LIST_FOR_EACH_SAFE(EnumEntry
, &LockToc
->GrantedListHead
, Granted
,FILE_LOCK_GRANTED
,ListEntry
)
695 //must be exact match
696 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
697 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
698 Granted
->Lock
.Process
== Process
&&
699 Granted
->Lock
.FileObject
== FileObject
&&
700 Granted
->Lock
.Key
== Key
)
702 RemoveEntryList(&Granted
->ListEntry
);
703 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
705 if (IsListEmpty(&LockToc
->GrantedListHead
))
707 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
709 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
; //paged data
713 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
716 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
718 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
721 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
723 return STATUS_SUCCESS
;
727 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
729 return STATUS_RANGE_NOT_LOCKED
;
735 /**********************************************************************
737 * FsRtlFastUnlockSingle
743 FsRtlFastUnlockSingle (
744 IN PFILE_LOCK FileLock
,
745 IN PFILE_OBJECT FileObject
,
746 IN PLARGE_INTEGER FileOffset
,
747 IN PLARGE_INTEGER Length
,
748 IN PEPROCESS Process
,
750 IN PVOID Context OPTIONAL
,
751 IN BOOLEAN AlreadySynchronized
754 return FsRtlpUnlockSingle( FileLock
,
761 TRUE
/* call unlock copletion routine */
765 /**********************************************************************
767 * FsRtlpDumpFileLocks
769 * NOTE: used for testing and debugging
774 IN PFILE_LOCK FileLock
778 PFILE_LOCK_TOC LockToc
;
779 PFILE_LOCK_GRANTED Granted
;
781 PLIST_ENTRY EnumEntry
;
782 PIO_STACK_LOCATION Stack
;
785 LockToc
= FileLock
->LockInformation
;
789 DPRINT1("No file locks\n");
793 DPRINT1("Dumping granted file locks, FIFO order\n");
795 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
797 LIST_FOR_EACH(EnumEntry
, &LockToc
->GrantedListHead
)
799 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
801 DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
802 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
803 Granted
->Lock
.StartingByte
.QuadPart
,
804 Granted
->Lock
.Length
.QuadPart
,
805 Granted
->Lock
.EndingByte
.QuadPart
,
807 Granted
->Lock
.Process
,
808 Granted
->Lock
.FileObject
813 DPRINT1("Dumping pending file locks, FIFO order\n");
815 LIST_FOR_EACH(EnumEntry
, &LockToc
->PendingListHead
)
817 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
818 Stack
= IoGetCurrentIrpStackLocation(Irp
);
820 DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
821 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
822 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
823 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
824 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
825 Stack
->Parameters
.LockControl
.Key
,
826 IoGetRequestorProcess(Irp
),
832 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
837 /**********************************************************************
839 * FsRtlGetNextFileLock
842 * NULL if no more locks.
848 FsRtlGetNextFileLock (
849 IN PFILE_LOCK FileLock
,
854 Messy enumeration of granted locks.
855 What our last ptr. in LastReturnedLock points at, might have been freed between
856 calls, so we have to scan thru the list every time, searching for our last lock.
857 If it's not there anymore, restart the enumeration...
860 PLIST_ENTRY EnumEntry
;
861 PFILE_LOCK_GRANTED Granted
;
862 PFILE_LOCK_TOC LockToc
;
863 BOOLEAN FoundPrevious
= FALSE
;
864 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
865 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
866 PVOID LocalLastReturnedLock
;
869 LockToc
= FileLock
->LockInformation
;
875 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
877 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
881 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
885 if (EnumEntry
!= &LockToc
->GrantedListHead
)
887 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
888 LocalLastReturnedLockInfo
= Granted
->Lock
;
889 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
891 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
892 FileLock
->LastReturnedLock
= EnumEntry
;
893 return &FileLock
->LastReturnedLockInfo
;
897 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
902 //else: continue enum
903 while (EnumEntry
!= &LockToc
->GrantedListHead
)
905 //found previous lock?
906 if (EnumEntry
== LocalLastReturnedLock
)
908 FoundPrevious
= TRUE
;
910 EnumEntry
= EnumEntry
->Flink
;
911 if (EnumEntry
!= &LockToc
->GrantedListHead
)
913 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
914 LocalLastReturnedLockInfo
= Granted
->Lock
;
915 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
917 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
918 FileLock
->LastReturnedLock
= EnumEntry
;
919 return &FileLock
->LastReturnedLockInfo
;
923 EnumEntry
= EnumEntry
->Flink
;
928 //got here? uh no, didn't find our last lock..must have been freed...restart
933 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
935 return NULL
;//no (more) locks
939 /**********************************************************************
941 * FsRtlInitializeFileLock
944 * Called when creating/allocating/initializing FCB
950 FsRtlInitializeFileLock (
951 IN PFILE_LOCK FileLock
,
952 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
953 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
957 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
958 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
959 FileLock
->UnlockRoutine
= UnlockRoutine
;
960 FileLock
->LockInformation
= NULL
;
965 /**********************************************************************
974 IN PFILE_LOCK FileLock
,
975 IN PFILE_OBJECT FileObject
,
976 IN PLARGE_INTEGER FileOffset
,
977 IN PLARGE_INTEGER Length
,
978 IN PEPROCESS Process
,
980 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
981 IN BOOLEAN ExclusiveLock
,
982 OUT PIO_STATUS_BLOCK IoStatus
,
983 IN PIRP Irp OPTIONAL
,
984 IN PVOID Context OPTIONAL
,
985 IN BOOLEAN AlreadySynchronized
988 PFILE_LOCK_TOC LockToc
;
992 if (FileLock
->LockInformation
== NULL
)
994 ExAcquireFastMutex(&LockTocMutex
);
996 if (FileLock
->LockInformation
== NULL
)
998 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
999 LockToc
= FileLock
->LockInformation
;
1000 KeInitializeSpinLock(&LockToc
->SpinLock
);
1001 InitializeListHead(&LockToc
->GrantedListHead
);
1002 InitializeListHead(&LockToc
->PendingListHead
);
1004 ExReleaseFastMutex(&LockTocMutex
);
1007 LockToc
= FileLock
->LockInformation
;
1008 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1010 //try add new lock (while holding spin lock)
1011 if (FsRtlpAddLock(LockToc
,
1021 IoStatus
->Status
= STATUS_SUCCESS
;
1023 else if (Irp
&& !FailImmediately
)
1025 //failed + irp + no fail = make. pending
1027 Irp
->Tail
.Overlay
.DriverContext
[3] = &LockToc
->SpinLock
;
1028 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
1030 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
1031 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
1034 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1036 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1037 Irp
->IoStatus
.Information
= 0;
1038 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1043 IoMarkIrpPending(Irp
);
1044 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1045 Irp
->IoStatus
.Information
= 0;
1046 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1051 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1054 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1056 //never pending if no irp;-)
1057 ASSERT(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1059 if (IoStatus
->Status
!= STATUS_PENDING
)
1061 if (IoStatus
->Status
== STATUS_SUCCESS
)
1063 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1068 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1069 Irp
->IoStatus
.Information
= 0;
1070 if (FileLock
->CompleteLockIrpRoutine
)
1072 if (FileLock
->CompleteLockIrpRoutine(Context
,Irp
)!=STATUS_SUCCESS
)
1074 //CompleteLockIrpRoutine complain: revert changes
1075 FsRtlpUnlockSingle( FileLock
,
1082 FALSE
/* don't call unlock copletion routine */
1088 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1093 //NOTE: only fast io seems to care about this return value
1094 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1100 /**********************************************************************
1102 * FsRtlProcessFileLock
1108 FsRtlProcessFileLock (
1109 IN PFILE_LOCK FileLock
,
1111 IN PVOID Context OPTIONAL
1114 PIO_STACK_LOCATION Stack
;
1116 IO_STATUS_BLOCK LocalIoStatus
;
1119 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1120 Irp
->IoStatus
.Information
= 0;
1122 switch(Stack
->MinorFunction
)
1126 FsRtlPrivateLock( FileLock
,
1128 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1129 Stack
->Parameters
.LockControl
.Length
,
1130 IoGetRequestorProcess(Irp
),
1131 Stack
->Parameters
.LockControl
.Key
,
1132 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1133 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1139 return LocalIoStatus
.Status
;
1141 case IRP_MN_UNLOCK_SINGLE
:
1142 Status
= FsRtlFastUnlockSingle ( FileLock
,
1144 &Stack
->Parameters
.LockControl
.ByteOffset
,
1145 Stack
->Parameters
.LockControl
.Length
,
1146 IoGetRequestorProcess(Irp
),
1147 Stack
->Parameters
.LockControl
.Key
,
1152 case IRP_MN_UNLOCK_ALL
:
1153 Status
= FsRtlFastUnlockAll( FileLock
,
1155 IoGetRequestorProcess(Irp
),
1159 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1160 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1162 IoGetRequestorProcess(Irp
),
1163 Stack
->Parameters
.LockControl
.Key
,
1169 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1170 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1175 Irp
->IoStatus
.Status
= Status
;
1176 Irp
->IoStatus
.Information
= 0;
1178 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1184 /**********************************************************************
1186 * FsRtlUninitializeFileLock
1192 FsRtlUninitializeFileLock (
1193 IN PFILE_LOCK FileLock
1196 PFILE_LOCK_TOC LockToc
;
1198 PFILE_LOCK_GRANTED Granted
;
1199 PLIST_ENTRY EnumEntry
;
1203 if (FileLock
->LockInformation
== NULL
)
1208 LockToc
= FileLock
->LockInformation
;
1210 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1212 //remove and free granted locks
1213 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1215 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1216 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1217 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1220 //remove, complete and free all pending locks
1221 while (!IsListEmpty(&LockToc
->PendingListHead
))
1223 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1224 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1226 if (!IoSetCancelRoutine(Irp
, NULL
))
1228 //The cancel routine will be called. When we release the lock it will complete the irp.
1229 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1233 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1235 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1236 Irp
->IoStatus
.Information
= 0;
1237 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1239 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1243 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1245 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1247 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1248 FileLock
->LockInformation
= NULL
;
1253 /**********************************************************************
1255 * FsRtlAllocateFileLock
1258 * Only present in NT 5.0 or later.
1259 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1265 FsRtlAllocateFileLock(
1266 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1267 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1270 PFILE_LOCK FileLock
;
1272 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1274 FsRtlInitializeFileLock(FileLock
,
1275 CompleteLockIrpRoutine
,
1282 /**********************************************************************
1287 * Only present in NT 5.0 or later.
1288 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1295 IN PFILE_LOCK FileLock
1300 FsRtlUninitializeFileLock(FileLock
);
1301 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);
1309 FsRtlAcquireFileExclusive(
1310 IN PFILE_OBJECT FileObject
1313 PFAST_IO_DISPATCH FastDispatch
;
1314 PDEVICE_OBJECT DeviceObject
;
1315 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1317 /* Get the Device Object */
1318 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1320 /* Check if we have to do a Fast I/O Dispatch */
1321 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1323 /* Call the Fast I/O Routine */
1324 if (FastDispatch
->AcquireFileForNtCreateSection
) {
1325 FastDispatch
->AcquireFileForNtCreateSection(FileObject
);
1331 /* Do a normal acquire */
1332 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1334 /* Use a Resource Acquire */
1335 ExAcquireResourceExclusive(FcbHeader
->Resource
, TRUE
);
1340 /* Return...is there some kind of failure we should raise?? */
1350 IN PFILE_OBJECT FileObject
1353 PFAST_IO_DISPATCH FastDispatch
;
1354 PDEVICE_OBJECT DeviceObject
;
1355 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1357 /* Get the Device Object */
1358 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1360 /* Check if we have to do a Fast I/O Dispatch */
1361 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1364 if (FastDispatch
->ReleaseFileForNtCreateSection
) {
1365 FastDispatch
->ReleaseFileForNtCreateSection(FileObject
);
1371 /* Do a normal acquire */
1372 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1374 /* Use a Resource Release */
1375 ExReleaseResourceLite(FcbHeader
->Resource
);
1380 /* Return...is there some kind of failure we should raise?? */