1 /* $Id: filelock.c,v 1.8 2003/07/10 06:27:13 royce Exp $
3 * reactos/ntoskrnl/fs/filelock.c
7 #include <internal/ifs.h>
11 #include <internal/debug.h>
15 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
16 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
20 #define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
21 #define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1)
22 #define REQUEST_START_OFF (FileOffset->QuadPart)
23 #define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
25 FAST_MUTEX LockTocMutex
;
26 NPAGED_LOOKASIDE_LIST GrantedLookaside
;
27 NPAGED_LOOKASIDE_LIST LockTocLookaside
;
28 PAGED_LOOKASIDE_LIST LockLookaside
;
30 /**********************************************************************
32 * FsRtlpInitFileLockingImplementation
37 FsRtlpInitFileLockingImplementation(VOID
)
39 ExInitializeNPagedLookasideList( &LockTocLookaside
,
43 sizeof(FILE_LOCK_TOC
),
48 ExInitializeNPagedLookasideList( &GrantedLookaside
,
52 sizeof(FILE_LOCK_GRANTED
),
57 ExInitializePagedLookasideList( &LockLookaside
,
66 ExInitializeFastMutex(&LockTocMutex
);
69 /**********************************************************************
71 * FsRtlpFileLockCancelRoutine
76 FsRtlpFileLockCancelRoutine(
77 IN PDEVICE_OBJECT DeviceObject
,
83 PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine
;
85 //don't need this since we have our own sync. protecting irp cancellation
86 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
88 SpinLock
= &((PFILE_LOCK_TOC
)Irp
->Tail
.Overlay
.DriverContext
[1])->SpinLock
;
90 KeAcquireSpinLock(SpinLock
, &oldIrql
);
91 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
92 KeReleaseSpinLock(SpinLock
, oldIrql
);
94 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
96 CompleteLockIrpRoutine
= ((PFILE_LOCK
)Irp
->Tail
.Overlay
.DriverContext
[0])->CompleteLockIrpRoutine
;
97 if (CompleteLockIrpRoutine
)
99 CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
103 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
108 /**********************************************************************
110 * FsRtlpCheckLockForReadOrWriteAccess
115 FsRtlpCheckLockForReadOrWriteAccess(
116 IN PFILE_LOCK FileLock
,
117 IN PLARGE_INTEGER FileOffset
,
118 IN PLARGE_INTEGER Length
,
120 IN PFILE_OBJECT FileObject
,
121 IN PEPROCESS Process
,
126 PFILE_LOCK_TOC LockToc
;
127 PFILE_LOCK_GRANTED Granted
;
128 PLIST_ENTRY EnumEntry
;
131 LockToc
= FileLock
->LockInformation
;
133 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
138 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
140 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
141 while ( EnumEntry
!= &LockToc
->GrantedListHead
)
143 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
145 if(!(REQUEST_START_OFF
> LOCK_END_OFF(Granted
->Lock
) ||
146 REQUEST_END_OFF
< LOCK_START_OFF(Granted
->Lock
)))
148 //No read conflict if (shared lock) OR (exclusive + our lock)
149 //No write conflict if exclusive lock AND our lock
150 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
151 (Granted
->Lock
.ExclusiveLock
&&
152 Granted
->Lock
.Process
== Process
&&
153 Granted
->Lock
.FileObject
== FileObject
&&
154 Granted
->Lock
.Key
== Key
) )
156 //AND if lock surround request region, stop searching and grant
157 if (REQUEST_START_OFF
>= LOCK_START_OFF(Granted
->Lock
) &&
158 REQUEST_END_OFF
<= LOCK_END_OFF(Granted
->Lock
))
160 EnumEntry
= &LockToc
->GrantedListHead
;//indicate no conflict
163 //else continue searching for conflicts
170 EnumEntry
= EnumEntry
->Flink
;
173 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
175 if (EnumEntry
== &LockToc
->GrantedListHead
)
184 /**********************************************************************
186 * FsRtlCheckLockForReadAccess
192 FsRtlCheckLockForReadAccess (
193 IN PFILE_LOCK FileLock
,
197 PIO_STACK_LOCATION Stack
;
198 LARGE_INTEGER LocalLength
;
200 Stack
= IoGetCurrentIrpStackLocation(Irp
);
202 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
203 LocalLength
.u
.HighPart
= 0;
205 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
206 &Stack
->Parameters
.Read
.ByteOffset
,
208 Stack
->Parameters
.Read
.Key
,
210 IoGetRequestorProcess(Irp
),
216 /**********************************************************************
218 * FsRtlCheckLockForWriteAccess
224 FsRtlCheckLockForWriteAccess (
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
.Write
.ByteOffset
,
240 Stack
->Parameters
.Write
.Key
,
242 IoGetRequestorProcess(Irp
),
251 /**********************************************************************
253 * FsRtlFastCheckLockForRead
259 FsRtlFastCheckLockForRead (
260 IN PFILE_LOCK FileLock
,
261 IN PLARGE_INTEGER FileOffset
,
262 IN PLARGE_INTEGER Length
,
264 IN PFILE_OBJECT FileObject
,
268 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
279 /**********************************************************************
281 * FsRtlFastCheckLockForWrite
287 FsRtlFastCheckLockForWrite (
288 IN PFILE_LOCK FileLock
,
289 IN PLARGE_INTEGER FileOffset
,
290 IN PLARGE_INTEGER Length
,
292 IN PFILE_OBJECT FileObject
,
296 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
308 /**********************************************************************
310 * FsRtlpFastUnlockAllByKey
315 FsRtlpFastUnlockAllByKey(
316 IN PFILE_LOCK FileLock
,
317 IN PFILE_OBJECT FileObject
,
318 IN PEPROCESS Process
,
319 IN DWORD Key
, /* FIXME: guess */
320 IN BOOLEAN UseKey
, /* FIXME: guess */
321 IN PVOID Context OPTIONAL
325 PFILE_LOCK_TOC LockToc
;
326 PLIST_ENTRY EnumEntry
;
327 PFILE_LOCK_GRANTED Granted
;
328 BOOLEAN Unlock
= FALSE
;
329 //must make local copy since FILE_LOCK struct is allowed to be paged
330 PUNLOCK_ROUTINE GotUnlockRoutine
;
333 LockToc
= FileLock
->LockInformation
;
337 return STATUS_RANGE_NOT_LOCKED
;
340 GotUnlockRoutine
= FileLock
->UnlockRoutine
;
341 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
343 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
344 while (EnumEntry
!= &LockToc
->GrantedListHead
)
346 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
347 EnumEntry
= EnumEntry
->Flink
;
349 if (Granted
->Lock
.Process
== Process
&&
350 Granted
->Lock
.FileObject
== FileObject
&&
351 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
353 RemoveEntryList(&Granted
->ListEntry
);
356 if (GotUnlockRoutine
)
359 Put on unlocked list and call unlock routine for them afterwards.
360 This way we don't have to restart enum after each call
362 InsertHeadList(&LockToc
->UnlockedListHead
,&Granted
->ListEntry
);
366 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
373 //call unlock routine for each unlocked lock (if any)
374 while (!IsListEmpty(&LockToc
->UnlockedListHead
))
376 EnumEntry
= RemoveTailList(&LockToc
->UnlockedListHead
);
377 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
378 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
379 FileLock
->UnlockRoutine(Context
,&Granted
->Lock
);
380 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
381 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
384 //NOTE: holding spinlock while calling this
385 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
);
387 if (IsListEmpty(&LockToc
->GrantedListHead
))
389 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
390 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
394 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
396 return STATUS_SUCCESS
;
399 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
400 return STATUS_RANGE_NOT_LOCKED
;
403 /**********************************************************************
411 FsRtlFastUnlockAll
/*ByProcess*/ (
412 IN PFILE_LOCK FileLock
,
413 IN PFILE_OBJECT FileObject
,
414 IN PEPROCESS Process
,
415 IN PVOID Context OPTIONAL
418 return FsRtlpFastUnlockAllByKey( FileLock
,
422 FALSE
, /* Do NOT use Key */
427 /**********************************************************************
429 * FsRtlFastUnlockAllByKey
435 FsRtlFastUnlockAllByKey (
436 IN PFILE_LOCK FileLock
,
437 IN PFILE_OBJECT FileObject
,
438 IN PEPROCESS Process
,
440 IN PVOID Context OPTIONAL
443 return FsRtlpFastUnlockAllByKey( FileLock
,
453 /**********************************************************************
458 * Spinlock held at entry !!
463 IN PFILE_LOCK_TOC LockToc
,
464 IN PFILE_OBJECT FileObject
,
465 IN PLARGE_INTEGER FileOffset
,
466 IN PLARGE_INTEGER Length
,
467 IN PEPROCESS Process
,
469 IN BOOLEAN ExclusiveLock
472 PLIST_ENTRY EnumEntry
;
473 PFILE_LOCK_GRANTED Granted
;
475 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
476 while (EnumEntry
!= &LockToc
->GrantedListHead
)
478 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
480 if(!(REQUEST_START_OFF
> LOCK_END_OFF(Granted
->Lock
) ||
481 REQUEST_END_OFF
< LOCK_START_OFF(Granted
->Lock
)))
483 //never conflict if shared lock and we want to add a shared lock
484 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
486 //AND if lock surround region, stop searching and insert lock
487 if (REQUEST_START_OFF
>= LOCK_START_OFF(Granted
->Lock
) &&
488 REQUEST_END_OFF
<= LOCK_END_OFF(Granted
->Lock
))
490 EnumEntry
= &LockToc
->GrantedListHead
;
493 //else keep locking for conflicts
496 {//conflict if we want share access to excl. lock OR exlc. access to shared lock
500 EnumEntry
= EnumEntry
->Flink
;
503 if (EnumEntry
== &LockToc
->GrantedListHead
)
505 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
507 Granted
->Lock
.StartingByte
= *FileOffset
;
508 Granted
->Lock
.Length
= *Length
;
509 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
510 Granted
->Lock
.Key
= Key
;
511 Granted
->Lock
.FileObject
= FileObject
;
512 Granted
->Lock
.Process
= Process
;
513 Granted
->Lock
.EndingByte
.QuadPart
= REQUEST_END_OFF
;
515 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
525 /**********************************************************************
527 * FsRtlpCompletePendingLocks
530 * Spinlock held at entry !!
534 FsRtlpCompletePendingLocks(
535 IN PFILE_LOCK FileLock
,
536 IN PFILE_LOCK_TOC LockToc
,
537 IN OUT PKIRQL oldirql
540 //walk pending list, FIFO order, try 2 complete locks
541 PLIST_ENTRY EnumEntry
;
543 PIO_STACK_LOCATION Stack
;
545 EnumEntry
= LockToc
->PendingListHead
.Blink
;
546 while (EnumEntry
!= &LockToc
->PendingListHead
)
548 Irp
= CONTAINING_RECORD(EnumEntry
,IRP
, Tail
.Overlay
.ListEntry
);
550 Stack
= IoGetCurrentIrpStackLocation(Irp
);
551 if (FsRtlpAddLock(LockToc
,
553 &Stack
->Parameters
.LockControl
.ByteOffset
,
554 Stack
->Parameters
.LockControl
.Length
,
555 IoGetRequestorProcess(Irp
),
556 Stack
->Parameters
.LockControl
.Key
,
557 Stack
->Flags
& SL_EXCLUSIVE_LOCK
560 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
562 if (!IoSetCancelRoutine(Irp
, NULL
))
565 Cancel routine WILL be called after we release the spinlock. It will try to remove
566 the irp from the list and cancel/complete this irp. Since we allready removed it,
567 make its ListEntry point to itself.
569 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
574 Cancel routine will NOT be called, canceled or not.
576 Put on completed list and complete them all afterwards.
577 This way we don't have to restart enum after each completion.
579 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
580 Irp
->IoStatus
.Information
= 0;
581 InsertHeadList(&LockToc
->CompletedListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
584 EnumEntry
= EnumEntry
->Blink
;
587 //complete irp's (if any)
588 while (!IsListEmpty(&LockToc
->CompletedListHead
))
590 EnumEntry
= RemoveTailList(&LockToc
->CompletedListHead
);
591 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);//fires cancel routine
592 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
594 if (FileLock
->CompleteLockIrpRoutine
)
596 FileLock
->CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
600 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
603 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
610 /**********************************************************************
618 IN PFILE_LOCK FileLock
,
619 IN PFILE_OBJECT FileObject
,
620 IN PLARGE_INTEGER FileOffset
,
621 IN PLARGE_INTEGER Length
,
622 IN PEPROCESS Process
,
624 IN PVOID Context OPTIONAL
,
625 IN BOOLEAN AlreadySynchronized
,
626 IN BOOLEAN CallUnlockRoutine
630 PFILE_LOCK_TOC LockToc
;
631 PFILE_LOCK_GRANTED Granted
;
632 PLIST_ENTRY EnumEntry
;
635 LockToc
= FileLock
->LockInformation
;
637 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
639 return STATUS_RANGE_NOT_LOCKED
;
642 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
644 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
645 while (EnumEntry
!= &LockToc
->GrantedListHead
)
647 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
649 //must be exact match
650 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
651 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
652 Granted
->Lock
.Process
== Process
&&
653 Granted
->Lock
.FileObject
== FileObject
&&
654 Granted
->Lock
.Key
== Key
)
656 RemoveEntryList(&Granted
->ListEntry
);
657 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
);
659 if (IsListEmpty(&LockToc
->GrantedListHead
))
661 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
662 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
666 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
669 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
671 FileLock
->UnlockRoutine(Context
,&Granted
->Lock
);
674 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
676 return STATUS_SUCCESS
;
678 EnumEntry
= EnumEntry
->Flink
;
681 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
683 return STATUS_RANGE_NOT_LOCKED
;
689 /**********************************************************************
691 * FsRtlFastUnlockSingle
697 FsRtlFastUnlockSingle (
698 IN PFILE_LOCK FileLock
,
699 IN PFILE_OBJECT FileObject
,
700 IN PLARGE_INTEGER FileOffset
,
701 IN PLARGE_INTEGER Length
,
702 IN PEPROCESS Process
,
704 IN PVOID Context OPTIONAL
,
705 IN BOOLEAN AlreadySynchronized
708 return FsRtlpUnlockSingle( FileLock
,
716 TRUE
//CallUnlockRoutine
720 /**********************************************************************
722 * FsRtlpDumpFileLocks
724 * NOTE: used for testing and debugging
731 IN PFILE_LOCK FileLock
735 PFILE_LOCK_TOC LockToc
;
736 PFILE_LOCK_GRANTED Granted
;
738 PLIST_ENTRY EnumEntry
;
739 PIO_STACK_LOCATION Stack
;
742 LockToc
= FileLock
->LockInformation
;
746 DPRINT1("No file locks\n");
750 DPRINT1("Dumping granted file locks, FIFO order\n");
752 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
754 EnumEntry
= LockToc
->GrantedListHead
.Blink
;
755 while ( EnumEntry
!= &LockToc
->GrantedListHead
)
757 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
759 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
760 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
761 Granted
->Lock
.StartingByte
.QuadPart
,
762 Granted
->Lock
.Length
.QuadPart
,
763 Granted
->Lock
.EndingByte
.QuadPart
,
765 Granted
->Lock
.Process
,
766 Granted
->Lock
.FileObject
769 EnumEntry
= EnumEntry
->Blink
;
772 DPRINT1("Dumping pending file locks, FIFO order\n");
774 EnumEntry
= LockToc
->PendingListHead
.Blink
;
775 while ( EnumEntry
!= &LockToc
->PendingListHead
)
777 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
779 Stack
= IoGetCurrentIrpStackLocation(Irp
);
781 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
782 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
783 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
784 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
785 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
786 Stack
->Parameters
.LockControl
.Key
,
787 IoGetRequestorProcess(Irp
),
791 EnumEntry
= EnumEntry
->Blink
;
794 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
799 /**********************************************************************
801 * FsRtlGetNextFileLock
804 * NULL if no more locks.
810 FsRtlGetNextFileLock (
811 IN PFILE_LOCK FileLock
,
816 Messy enumeration of granted locks.
817 What our last ptr. in LastReturnedLock points at, might have been freed between
818 calls, so we have to scan thru the list every time, searching for our last lock.
819 If it's not there anymore, restart the enumeration...
822 PLIST_ENTRY EnumEntry
;
823 PFILE_LOCK_GRANTED Granted
;
824 PFILE_LOCK_TOC LockToc
;
825 BOOLEAN FoundPrevious
= FALSE
;
826 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
827 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
828 PVOID LocalLastReturnedLock
;
831 LockToc
= FileLock
->LockInformation
;
837 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
839 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
843 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
847 if (EnumEntry
!= &LockToc
->GrantedListHead
)
849 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
850 LocalLastReturnedLockInfo
= Granted
->Lock
;
851 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
853 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
854 FileLock
->LastReturnedLock
= EnumEntry
;
855 return &FileLock
->LastReturnedLockInfo
;
859 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
864 //else: continue enum
865 while (EnumEntry
!= &LockToc
->GrantedListHead
)
867 //found previous lock?
868 if (EnumEntry
== LocalLastReturnedLock
)
870 FoundPrevious
= TRUE
;
872 EnumEntry
= EnumEntry
->Flink
;
873 if (EnumEntry
!= &LockToc
->GrantedListHead
)
875 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
876 LocalLastReturnedLockInfo
= Granted
->Lock
;
877 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
879 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
880 FileLock
->LastReturnedLock
= EnumEntry
;
881 return &FileLock
->LastReturnedLockInfo
;
885 EnumEntry
= EnumEntry
->Flink
;
890 //got here? uh no, didn't find our last lock..must have been freed...restart
895 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
897 return NULL
;//no (more) locks
901 /**********************************************************************
903 * FsRtlInitializeFileLock
906 * Called when creating/allocating/initializing FCB
912 FsRtlInitializeFileLock (
913 IN PFILE_LOCK FileLock
,
914 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
915 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
919 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
920 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
921 FileLock
->UnlockRoutine
= UnlockRoutine
;
922 FileLock
->LockInformation
= NULL
;
927 /**********************************************************************
936 IN PFILE_LOCK FileLock
,
937 IN PFILE_OBJECT FileObject
,
938 IN PLARGE_INTEGER FileOffset
,
939 IN PLARGE_INTEGER Length
,
940 IN PEPROCESS Process
,
942 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
943 IN BOOLEAN ExclusiveLock
,
944 OUT PIO_STATUS_BLOCK IoStatus
,
945 IN PIRP Irp OPTIONAL
,
947 IN BOOLEAN AlreadySynchronized
950 PFILE_LOCK_TOC LockToc
;
954 if (FileLock
->LockInformation
== NULL
)
956 ExAcquireFastMutex(&LockTocMutex
);
958 if (FileLock
->LockInformation
== NULL
)
960 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
961 LockToc
= FileLock
->LockInformation
;
962 KeInitializeSpinLock(&LockToc
->SpinLock
);
963 InitializeListHead(&LockToc
->GrantedListHead
);
964 InitializeListHead(&LockToc
->PendingListHead
);
965 InitializeListHead(&LockToc
->CompletedListHead
);
966 InitializeListHead(&LockToc
->UnlockedListHead
);
968 ExReleaseFastMutex(&LockTocMutex
);
971 LockToc
= FileLock
->LockInformation
;
972 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
974 //try add new lock (while holding spin lock)
975 if (FsRtlpAddLock(LockToc
,
984 IoStatus
->Status
= STATUS_SUCCESS
;
986 else if (Irp
&& !FailImmediately
)
987 { //failed + irp + no fail = mk. pending
988 //for our cancel routine
989 Irp
->Tail
.Overlay
.DriverContext
[0] = (PVOID
)FileLock
;
990 Irp
->Tail
.Overlay
.DriverContext
[1] = (PVOID
)LockToc
;
991 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
993 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
997 //irp canceled even before we got to queue it
998 if (IoSetCancelRoutine(Irp
, NULL
))
999 { //Cancel routine will NOT be called: cancel it here
1000 IoStatus
->Status
= STATUS_CANCELLED
;
1003 { //Cancel routine WILL be called. When we release the lock it will complete the irp
1004 //Return pending since we are not completing the irp here
1005 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1006 Irp
->IoStatus
.Information
= 0;
1007 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1012 { //not cancelled: queue irp
1013 IoMarkIrpPending(Irp
);
1014 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1015 Irp
->IoStatus
.Information
= 0;
1016 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1022 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1025 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1027 //never pending if no irp;-)
1028 assert(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1030 if (IoStatus
->Status
!= STATUS_PENDING
)
1032 if (IoStatus
->Status
== STATUS_SUCCESS
)
1034 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1039 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1040 Irp
->IoStatus
.Information
= 0;
1042 if (FileLock
->CompleteLockIrpRoutine
)
1043 { //complete irp routine
1045 if (!NT_SUCCESS(FileLock
->CompleteLockIrpRoutine(Context
,Irp
)))
1047 //CompleteLockIrpRoutine complain: revert changes
1048 FsRtlpUnlockSingle( FileLock
,
1055 AlreadySynchronized
,
1056 FALSE
//CallUnlockRoutine
1061 {//std irp completion
1062 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1067 //NOTE: only fast io seems to care about this return value
1068 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1074 /**********************************************************************
1076 * FsRtlProcessFileLock
1082 FsRtlProcessFileLock (
1083 IN PFILE_LOCK FileLock
,
1085 IN PVOID Context OPTIONAL
1088 PIO_STACK_LOCATION Stack
;
1090 IO_STATUS_BLOCK LocalIoStatus
;
1093 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1094 Irp
->IoStatus
.Information
= 0;
1096 switch(Stack
->MinorFunction
)
1100 FsRtlPrivateLock( FileLock
,
1102 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1103 Stack
->Parameters
.LockControl
.Length
,
1104 IoGetRequestorProcess(Irp
),
1105 Stack
->Parameters
.LockControl
.Key
,
1106 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1107 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1113 return LocalIoStatus
.Status
;
1115 case IRP_MN_UNLOCK_SINGLE
:
1116 Status
= FsRtlFastUnlockSingle ( FileLock
,
1118 &Stack
->Parameters
.LockControl
.ByteOffset
,
1119 Stack
->Parameters
.LockControl
.Length
,
1120 IoGetRequestorProcess(Irp
),
1121 Stack
->Parameters
.LockControl
.Key
,
1126 case IRP_MN_UNLOCK_ALL
:
1127 Status
= FsRtlFastUnlockAll( FileLock
,
1129 IoGetRequestorProcess(Irp
),
1133 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1134 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1136 IoGetRequestorProcess(Irp
),
1137 Stack
->Parameters
.LockControl
.Key
,
1143 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1144 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1148 Irp
->IoStatus
.Status
= Status
;
1150 if (FileLock
->CompleteLockIrpRoutine
)
1152 FileLock
->CompleteLockIrpRoutine(Context
,Irp
);
1156 IofCompleteRequest(Irp
,IO_NO_INCREMENT
);
1163 /**********************************************************************
1165 * FsRtlUninitializeFileLock
1171 FsRtlUninitializeFileLock (
1172 IN PFILE_LOCK FileLock
1175 PFILE_LOCK_TOC LockToc
;
1177 PFILE_LOCK_GRANTED Granted
;
1178 PLIST_ENTRY EnumEntry
;
1182 if (FileLock
->LockInformation
== NULL
)
1187 LockToc
= FileLock
->LockInformation
;
1189 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1191 //remove and free granted locks
1192 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1194 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1195 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1196 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1199 //remove, complete and free all pending locks
1200 while (!IsListEmpty(&LockToc
->PendingListHead
))
1202 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1203 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1205 if (!IoSetCancelRoutine(Irp
, NULL
))
1207 //The cancel routine will be called. When we release the lock it will complete the irp.
1208 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1213 Cancel routine will NOT be called, even though the irp might have been canceled.
1214 Don't care since we'l complete it faster than the cancel routine would have.
1216 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);//fires cancel routine
1218 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1220 if (FileLock
->CompleteLockIrpRoutine
)
1222 FileLock
->CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
1226 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1229 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1233 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1235 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1237 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1238 FileLock
->LockInformation
= NULL
;
1243 /**********************************************************************
1245 * FsRtlAllocateFileLock
1248 * Only present in NT 5.0 or later.
1249 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1255 FsRtlAllocateFileLock(
1256 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1257 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1260 PFILE_LOCK FileLock
;
1262 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1264 FsRtlInitializeFileLock(FileLock
,
1265 CompleteLockIrpRoutine
,
1272 /**********************************************************************
1277 * Only present in NT 5.0 or later.
1278 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1285 IN PFILE_LOCK FileLock
1290 FsRtlUninitializeFileLock(FileLock
);
1291 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);