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 LARGE_INTEGER EndOffset
;
168 LockToc
= FileLock
->LockInformation
;
170 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
175 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
177 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
179 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
182 if(IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
184 //No read conflict if (shared lock) OR (exclusive + our lock)
185 //No write conflict if exclusive lock AND our lock
186 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
187 (Granted
->Lock
.ExclusiveLock
&&
188 Granted
->Lock
.Process
== Process
&&
189 Granted
->Lock
.FileObject
== FileObject
&&
190 Granted
->Lock
.Key
== Key
) )
192 //AND if lock surround request region, stop searching and grant
193 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
) )
195 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
199 //else continue searching for conflicts
204 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
211 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
216 /**********************************************************************
218 * FsRtlCheckLockForReadAccess
224 FsRtlCheckLockForReadAccess (
225 IN PFILE_LOCK FileLock
,
229 PIO_STACK_LOCATION Stack
;
230 LARGE_INTEGER LocalLength
;
232 Stack
= IoGetCurrentIrpStackLocation(Irp
);
234 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
235 LocalLength
.u
.HighPart
= 0;
237 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
238 &Stack
->Parameters
.Read
.ByteOffset
,
240 Stack
->Parameters
.Read
.Key
,
242 IoGetRequestorProcess(Irp
),
248 /**********************************************************************
250 * FsRtlCheckLockForWriteAccess
256 FsRtlCheckLockForWriteAccess (
257 IN PFILE_LOCK FileLock
,
261 PIO_STACK_LOCATION Stack
;
262 LARGE_INTEGER LocalLength
;
264 Stack
= IoGetCurrentIrpStackLocation(Irp
);
266 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
267 LocalLength
.u
.HighPart
= 0;
269 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
270 &Stack
->Parameters
.Write
.ByteOffset
,
272 Stack
->Parameters
.Write
.Key
,
274 IoGetRequestorProcess(Irp
),
283 /**********************************************************************
285 * FsRtlFastCheckLockForRead
291 FsRtlFastCheckLockForRead (
292 IN PFILE_LOCK FileLock
,
293 IN PLARGE_INTEGER FileOffset
,
294 IN PLARGE_INTEGER Length
,
296 IN PFILE_OBJECT FileObject
,
300 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
311 /**********************************************************************
313 * FsRtlFastCheckLockForWrite
319 FsRtlFastCheckLockForWrite (
320 IN PFILE_LOCK FileLock
,
321 IN PLARGE_INTEGER FileOffset
,
322 IN PLARGE_INTEGER Length
,
324 IN PFILE_OBJECT FileObject
,
328 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
340 /**********************************************************************
342 * FsRtlpFastUnlockAllByKey
347 FsRtlpFastUnlockAllByKey(
348 IN PFILE_LOCK FileLock
,
349 IN PFILE_OBJECT FileObject
,
350 IN PEPROCESS Process
,
353 IN PVOID Context OPTIONAL
357 PFILE_LOCK_TOC LockToc
;
358 PFILE_LOCK_GRANTED Granted
, tmp
;
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
;
363 PLIST_ENTRY EnumEntry
;
366 LockToc
= FileLock
->LockInformation
;
370 return STATUS_RANGE_NOT_LOCKED
;
373 InitializeListHead(&UnlockedListHead
);
374 GotUnlockRoutine
= FileLock
->UnlockRoutine
!= NULL
;
375 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
377 LIST_FOR_EACH_SAFE(Granted
, tmp
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
380 if (Granted
->Lock
.Process
== Process
&&
381 Granted
->Lock
.FileObject
== FileObject
&&
382 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
384 RemoveEntryList(&Granted
->ListEntry
);
387 if (GotUnlockRoutine
)
390 Put on unlocked list and call unlock routine for them afterwards.
391 This way we don't have to restart enum after each call
393 InsertHeadList(&UnlockedListHead
,&Granted
->ListEntry
);
397 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
402 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
406 //call unlock routine for each unlocked lock (if any)
407 while (!IsListEmpty(&UnlockedListHead
))
409 EnumEntry
= RemoveTailList(&UnlockedListHead
);
410 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
412 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
413 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
416 //NOTE: holding spinlock while calling this
417 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
418 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
420 if (IsListEmpty(&LockToc
->GrantedListHead
))
422 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
423 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
427 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
430 return STATUS_SUCCESS
;
433 return STATUS_RANGE_NOT_LOCKED
;
436 /**********************************************************************
444 FsRtlFastUnlockAll
/*ByProcess*/ (
445 IN PFILE_LOCK FileLock
,
446 IN PFILE_OBJECT FileObject
,
447 IN PEPROCESS Process
,
448 IN PVOID Context OPTIONAL
451 return FsRtlpFastUnlockAllByKey( FileLock
,
454 0, /* Key is ignored */
455 FALSE
, /* Do NOT use Key */
460 /**********************************************************************
462 * FsRtlFastUnlockAllByKey
468 FsRtlFastUnlockAllByKey (
469 IN PFILE_LOCK FileLock
,
470 IN PFILE_OBJECT FileObject
,
471 IN PEPROCESS Process
,
473 IN PVOID Context OPTIONAL
476 return FsRtlpFastUnlockAllByKey( FileLock
,
486 /**********************************************************************
491 * Spinlock held at entry !!
496 IN PFILE_LOCK_TOC LockToc
,
497 IN PFILE_OBJECT FileObject
,
498 IN PLARGE_INTEGER FileOffset
,
499 IN PLARGE_INTEGER Length
,
500 IN PEPROCESS Process
,
502 IN BOOLEAN ExclusiveLock
,
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(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
514 if (IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
516 //we found a locks that overlap with the new lock
518 //if both locks are shared, we might have a fast path outa here...
519 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
521 //if existing lock surround new lock, we know that no other exclusive lock
522 //may overlap with our new lock;-D
523 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
528 //else keep locking for conflicts
532 //we found a conflict:
533 //we want shared access to an excl. lock OR exlc. access to a shared lock
538 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
541 Granted
->Lock
.StartingByte
= *FileOffset
;
542 Granted
->Lock
.Length
= *Length
;
543 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
544 Granted
->Lock
.Key
= Key
;
545 Granted
->Lock
.FileObject
= FileObject
;
546 Granted
->Lock
.Process
= Process
;
548 Granted
->Lock
.EndingByte
= EndOffset
;
549 Granted
->UnlockContext
= Context
;
551 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
557 /**********************************************************************
559 * FsRtlpCompletePendingLocks
562 * Spinlock held at entry !!
566 FsRtlpCompletePendingLocks(
567 IN PFILE_LOCK FileLock
,
568 IN PFILE_LOCK_TOC LockToc
,
569 IN OUT PKIRQL oldirql
,
573 //walk pending list, FIFO order, try 2 complete locks
574 PLIST_ENTRY EnumEntry
;
576 PIO_STACK_LOCATION Stack
;
577 LIST_ENTRY CompletedListHead
;
579 InitializeListHead(&CompletedListHead
);
581 LIST_FOR_EACH_SAFE(Irp
, tmp
, &LockToc
->PendingListHead
, IRP
, Tail
.Overlay
.ListEntry
)
583 Stack
= IoGetCurrentIrpStackLocation(Irp
);
584 if (FsRtlpAddLock(LockToc
,
586 &Stack
->Parameters
.LockControl
.ByteOffset
,
587 Stack
->Parameters
.LockControl
.Length
,
588 IoGetRequestorProcess(Irp
),
589 Stack
->Parameters
.LockControl
.Key
,
590 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
591 Irp
->Tail
.Overlay
.DriverContext
[2] //Context
594 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
596 if (!IoSetCancelRoutine(Irp
, NULL
))
598 //irp is canceled and cancelroutine will run when we release the lock
599 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
604 Put on completed list and complete them all afterwards.
605 This way we don't have to restart enum after each completion.
607 InsertHeadList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
611 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);
613 //complete irp's (if any)
614 while (!IsListEmpty(&CompletedListHead
))
616 EnumEntry
= RemoveTailList(&CompletedListHead
);
618 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
620 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
621 Irp
->IoStatus
.Information
= 0;
623 if (FileLock
->CompleteLockIrpRoutine
)
625 if (FileLock
->CompleteLockIrpRoutine(Context
, Irp
)!=STATUS_SUCCESS
)
627 Stack
= IoGetCurrentIrpStackLocation(Irp
);
630 FsRtlpUnlockSingle ( FileLock
,
632 &Stack
->Parameters
.LockControl
.ByteOffset
,
633 Stack
->Parameters
.LockControl
.Length
,
634 IoGetRequestorProcess(Irp
),
635 Stack
->Parameters
.LockControl
.Key
,
636 NULL
, /* unused context */
637 FALSE
/* don't call unlock copletion rout.*/
643 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
648 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
653 /**********************************************************************
661 IN PFILE_LOCK FileLock
,
662 IN PFILE_OBJECT FileObject
,
663 IN PLARGE_INTEGER FileOffset
,
664 IN PLARGE_INTEGER Length
,
665 IN PEPROCESS Process
,
667 IN PVOID Context OPTIONAL
,
668 IN BOOLEAN CallUnlockRoutine
672 PFILE_LOCK_TOC LockToc
;
673 PFILE_LOCK_GRANTED Granted
, tmp
;
676 LockToc
= FileLock
->LockInformation
;
680 return STATUS_RANGE_NOT_LOCKED
;
683 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
685 LIST_FOR_EACH_SAFE(Granted
, tmp
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
,ListEntry
)
688 //must be exact match
689 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
690 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
691 Granted
->Lock
.Process
== Process
&&
692 Granted
->Lock
.FileObject
== FileObject
&&
693 Granted
->Lock
.Key
== Key
)
695 RemoveEntryList(&Granted
->ListEntry
);
696 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
698 if (IsListEmpty(&LockToc
->GrantedListHead
))
700 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
702 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
; //paged data
706 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
709 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
711 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
714 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
716 return STATUS_SUCCESS
;
720 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
722 return STATUS_RANGE_NOT_LOCKED
;
728 /**********************************************************************
730 * FsRtlFastUnlockSingle
736 FsRtlFastUnlockSingle (
737 IN PFILE_LOCK FileLock
,
738 IN PFILE_OBJECT FileObject
,
739 IN PLARGE_INTEGER FileOffset
,
740 IN PLARGE_INTEGER Length
,
741 IN PEPROCESS Process
,
743 IN PVOID Context OPTIONAL
,
744 IN BOOLEAN AlreadySynchronized
747 return FsRtlpUnlockSingle( FileLock
,
754 TRUE
/* call unlock copletion routine */
758 /**********************************************************************
760 * FsRtlpDumpFileLocks
762 * NOTE: used for testing and debugging
767 IN PFILE_LOCK FileLock
771 PFILE_LOCK_TOC LockToc
;
772 PFILE_LOCK_GRANTED Granted
;
774 PIO_STACK_LOCATION Stack
;
777 LockToc
= FileLock
->LockInformation
;
781 DPRINT1("No file locks\n");
785 DPRINT1("Dumping granted file locks, FIFO order\n");
787 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
789 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
791 DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
792 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
793 Granted
->Lock
.StartingByte
.QuadPart
,
794 Granted
->Lock
.Length
.QuadPart
,
795 Granted
->Lock
.EndingByte
.QuadPart
,
797 Granted
->Lock
.Process
,
798 Granted
->Lock
.FileObject
803 DPRINT1("Dumping pending file locks, FIFO order\n");
805 LIST_FOR_EACH(Irp
, &LockToc
->PendingListHead
, IRP
, Tail
.Overlay
.ListEntry
)
807 Stack
= IoGetCurrentIrpStackLocation(Irp
);
809 DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
810 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
811 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
812 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
813 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
814 Stack
->Parameters
.LockControl
.Key
,
815 IoGetRequestorProcess(Irp
),
821 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
826 /**********************************************************************
828 * FsRtlGetNextFileLock
831 * NULL if no more locks.
837 FsRtlGetNextFileLock (
838 IN PFILE_LOCK FileLock
,
843 Messy enumeration of granted locks.
844 What our last ptr. in LastReturnedLock points at, might have been freed between
845 calls, so we have to scan thru the list every time, searching for our last lock.
846 If it's not there anymore, restart the enumeration...
849 PLIST_ENTRY EnumEntry
;
850 PFILE_LOCK_GRANTED Granted
;
851 PFILE_LOCK_TOC LockToc
;
852 BOOLEAN FoundPrevious
= FALSE
;
853 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
854 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
855 PVOID LocalLastReturnedLock
;
858 LockToc
= FileLock
->LockInformation
;
864 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
866 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
870 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
874 if (EnumEntry
!= &LockToc
->GrantedListHead
)
876 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
877 LocalLastReturnedLockInfo
= Granted
->Lock
;
878 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
880 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
881 FileLock
->LastReturnedLock
= EnumEntry
;
882 return &FileLock
->LastReturnedLockInfo
;
886 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
891 //else: continue enum
892 while (EnumEntry
!= &LockToc
->GrantedListHead
)
894 //found previous lock?
895 if (EnumEntry
== LocalLastReturnedLock
)
897 FoundPrevious
= TRUE
;
899 EnumEntry
= EnumEntry
->Flink
;
900 if (EnumEntry
!= &LockToc
->GrantedListHead
)
902 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
903 LocalLastReturnedLockInfo
= Granted
->Lock
;
904 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
906 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
907 FileLock
->LastReturnedLock
= EnumEntry
;
908 return &FileLock
->LastReturnedLockInfo
;
912 EnumEntry
= EnumEntry
->Flink
;
917 //got here? uh no, didn't find our last lock..must have been freed...restart
922 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
924 return NULL
;//no (more) locks
928 /**********************************************************************
930 * FsRtlInitializeFileLock
933 * Called when creating/allocating/initializing FCB
939 FsRtlInitializeFileLock (
940 IN PFILE_LOCK FileLock
,
941 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
942 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
946 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
947 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
948 FileLock
->UnlockRoutine
= UnlockRoutine
;
949 FileLock
->LockInformation
= NULL
;
954 /**********************************************************************
963 IN PFILE_LOCK FileLock
,
964 IN PFILE_OBJECT FileObject
,
965 IN PLARGE_INTEGER FileOffset
,
966 IN PLARGE_INTEGER Length
,
967 IN PEPROCESS Process
,
969 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
970 IN BOOLEAN ExclusiveLock
,
971 OUT PIO_STATUS_BLOCK IoStatus
,
972 IN PIRP Irp OPTIONAL
,
973 IN PVOID Context OPTIONAL
,
974 IN BOOLEAN AlreadySynchronized
977 PFILE_LOCK_TOC LockToc
;
981 if (FileLock
->LockInformation
== NULL
)
983 ExAcquireFastMutex(&LockTocMutex
);
985 if (FileLock
->LockInformation
== NULL
)
987 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
988 LockToc
= FileLock
->LockInformation
;
989 KeInitializeSpinLock(&LockToc
->SpinLock
);
990 InitializeListHead(&LockToc
->GrantedListHead
);
991 InitializeListHead(&LockToc
->PendingListHead
);
993 ExReleaseFastMutex(&LockTocMutex
);
996 LockToc
= FileLock
->LockInformation
;
997 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
999 //try add new lock (while holding spin lock)
1000 if (FsRtlpAddLock(LockToc
,
1010 IoStatus
->Status
= STATUS_SUCCESS
;
1012 else if (Irp
&& !FailImmediately
)
1014 //failed + irp + no fail = make. pending
1016 Irp
->Tail
.Overlay
.DriverContext
[3] = &LockToc
->SpinLock
;
1017 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
1019 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
1020 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
1023 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1025 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1026 Irp
->IoStatus
.Information
= 0;
1027 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1032 IoMarkIrpPending(Irp
);
1033 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1034 Irp
->IoStatus
.Information
= 0;
1035 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1040 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1043 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1045 //never pending if no irp;-)
1046 ASSERT(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1048 if (IoStatus
->Status
!= STATUS_PENDING
)
1050 if (IoStatus
->Status
== STATUS_SUCCESS
)
1052 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1057 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1058 Irp
->IoStatus
.Information
= 0;
1059 if (FileLock
->CompleteLockIrpRoutine
)
1061 if (FileLock
->CompleteLockIrpRoutine(Context
,Irp
)!=STATUS_SUCCESS
)
1063 //CompleteLockIrpRoutine complain: revert changes
1064 FsRtlpUnlockSingle( FileLock
,
1071 FALSE
/* don't call unlock copletion routine */
1077 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1082 //NOTE: only fast io seems to care about this return value
1083 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1089 /**********************************************************************
1091 * FsRtlProcessFileLock
1097 FsRtlProcessFileLock (
1098 IN PFILE_LOCK FileLock
,
1100 IN PVOID Context OPTIONAL
1103 PIO_STACK_LOCATION Stack
;
1105 IO_STATUS_BLOCK LocalIoStatus
;
1108 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1109 Irp
->IoStatus
.Information
= 0;
1111 switch(Stack
->MinorFunction
)
1115 FsRtlPrivateLock( FileLock
,
1117 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1118 Stack
->Parameters
.LockControl
.Length
,
1119 IoGetRequestorProcess(Irp
),
1120 Stack
->Parameters
.LockControl
.Key
,
1121 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1122 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1128 return LocalIoStatus
.Status
;
1130 case IRP_MN_UNLOCK_SINGLE
:
1131 Status
= FsRtlFastUnlockSingle ( FileLock
,
1133 &Stack
->Parameters
.LockControl
.ByteOffset
,
1134 Stack
->Parameters
.LockControl
.Length
,
1135 IoGetRequestorProcess(Irp
),
1136 Stack
->Parameters
.LockControl
.Key
,
1141 case IRP_MN_UNLOCK_ALL
:
1142 Status
= FsRtlFastUnlockAll( FileLock
,
1144 IoGetRequestorProcess(Irp
),
1148 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1149 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1151 IoGetRequestorProcess(Irp
),
1152 Stack
->Parameters
.LockControl
.Key
,
1158 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1159 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1164 Irp
->IoStatus
.Status
= Status
;
1165 Irp
->IoStatus
.Information
= 0;
1167 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1173 /**********************************************************************
1175 * FsRtlUninitializeFileLock
1181 FsRtlUninitializeFileLock (
1182 IN PFILE_LOCK FileLock
1185 PFILE_LOCK_TOC LockToc
;
1187 PFILE_LOCK_GRANTED Granted
;
1188 PLIST_ENTRY EnumEntry
;
1192 if (FileLock
->LockInformation
== NULL
)
1197 LockToc
= FileLock
->LockInformation
;
1199 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1201 //remove and free granted locks
1202 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1204 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1205 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1206 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1209 //remove, complete and free all pending locks
1210 while (!IsListEmpty(&LockToc
->PendingListHead
))
1212 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1213 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1215 if (!IoSetCancelRoutine(Irp
, NULL
))
1217 //The cancel routine will be called. When we release the lock it will complete the irp.
1218 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1222 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1224 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1225 Irp
->IoStatus
.Information
= 0;
1226 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1228 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1232 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1234 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1236 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1237 FileLock
->LockInformation
= NULL
;
1242 /**********************************************************************
1244 * FsRtlAllocateFileLock
1247 * Only present in NT 5.0 or later.
1248 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1254 FsRtlAllocateFileLock(
1255 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1256 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1259 PFILE_LOCK FileLock
;
1261 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1263 FsRtlInitializeFileLock(FileLock
,
1264 CompleteLockIrpRoutine
,
1271 /**********************************************************************
1276 * Only present in NT 5.0 or later.
1277 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1284 IN PFILE_LOCK FileLock
1289 FsRtlUninitializeFileLock(FileLock
);
1290 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);
1298 FsRtlAcquireFileExclusive(
1299 IN PFILE_OBJECT FileObject
1302 PFAST_IO_DISPATCH FastDispatch
;
1303 PDEVICE_OBJECT DeviceObject
;
1304 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1306 /* Get the Device Object */
1307 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1309 /* Check if we have to do a Fast I/O Dispatch */
1310 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1312 /* Call the Fast I/O Routine */
1313 if (FastDispatch
->AcquireFileForNtCreateSection
) {
1314 FastDispatch
->AcquireFileForNtCreateSection(FileObject
);
1320 /* Do a normal acquire */
1321 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1323 /* Use a Resource Acquire */
1324 ExAcquireResourceExclusive(FcbHeader
->Resource
, TRUE
);
1329 /* Return...is there some kind of failure we should raise?? */
1339 IN PFILE_OBJECT FileObject
1342 PFAST_IO_DISPATCH FastDispatch
;
1343 PDEVICE_OBJECT DeviceObject
;
1344 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1346 /* Get the Device Object */
1347 DeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1349 /* Check if we have to do a Fast I/O Dispatch */
1350 if ((FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
)) {
1353 if (FastDispatch
->ReleaseFileForNtCreateSection
) {
1354 FastDispatch
->ReleaseFileForNtCreateSection(FileObject
);
1360 /* Do a normal acquire */
1361 if ((FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)) {
1363 /* Use a Resource Release */
1364 ExReleaseResourceLite(FcbHeader
->Resource
);
1369 /* Return...is there some kind of failure we should raise?? */