1 /* $Id: filelock.c,v 1.10 2003/08/07 11:47:33 silverblade 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 PEXTENDED_IO_STACK_LOCATION Stack
;
545 EnumEntry
= LockToc
->PendingListHead
.Blink
;
546 while (EnumEntry
!= &LockToc
->PendingListHead
)
548 Irp
= CONTAINING_RECORD(EnumEntry
,IRP
, Tail
.Overlay
.ListEntry
);
550 Stack
= (PEXTENDED_IO_STACK_LOCATION
) 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
729 IN PFILE_LOCK FileLock
733 PFILE_LOCK_TOC LockToc
;
734 PFILE_LOCK_GRANTED Granted
;
736 PLIST_ENTRY EnumEntry
;
737 PEXTENDED_IO_STACK_LOCATION Stack
;
740 LockToc
= FileLock
->LockInformation
;
744 DPRINT1("No file locks\n");
748 DPRINT1("Dumping granted file locks, FIFO order\n");
750 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
752 EnumEntry
= LockToc
->GrantedListHead
.Blink
;
753 while ( EnumEntry
!= &LockToc
->GrantedListHead
)
755 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
757 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
758 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
759 Granted
->Lock
.StartingByte
.QuadPart
,
760 Granted
->Lock
.Length
.QuadPart
,
761 Granted
->Lock
.EndingByte
.QuadPart
,
763 Granted
->Lock
.Process
,
764 Granted
->Lock
.FileObject
767 EnumEntry
= EnumEntry
->Blink
;
770 DPRINT1("Dumping pending file locks, FIFO order\n");
772 EnumEntry
= LockToc
->PendingListHead
.Blink
;
773 while ( EnumEntry
!= &LockToc
->PendingListHead
)
775 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
777 Stack
= (PEXTENDED_IO_STACK_LOCATION
) IoGetCurrentIrpStackLocation(Irp
);
779 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
780 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
781 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
782 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
783 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
784 Stack
->Parameters
.LockControl
.Key
,
785 IoGetRequestorProcess(Irp
),
789 EnumEntry
= EnumEntry
->Blink
;
792 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
797 /**********************************************************************
799 * FsRtlGetNextFileLock
802 * NULL if no more locks.
808 FsRtlGetNextFileLock (
809 IN PFILE_LOCK FileLock
,
814 Messy enumeration of granted locks.
815 What our last ptr. in LastReturnedLock points at, might have been freed between
816 calls, so we have to scan thru the list every time, searching for our last lock.
817 If it's not there anymore, restart the enumeration...
820 PLIST_ENTRY EnumEntry
;
821 PFILE_LOCK_GRANTED Granted
;
822 PFILE_LOCK_TOC LockToc
;
823 BOOLEAN FoundPrevious
= FALSE
;
824 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
825 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
826 PVOID LocalLastReturnedLock
;
829 LockToc
= FileLock
->LockInformation
;
835 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
837 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
841 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
845 if (EnumEntry
!= &LockToc
->GrantedListHead
)
847 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
848 LocalLastReturnedLockInfo
= Granted
->Lock
;
849 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
851 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
852 FileLock
->LastReturnedLock
= EnumEntry
;
853 return &FileLock
->LastReturnedLockInfo
;
857 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
862 //else: continue enum
863 while (EnumEntry
!= &LockToc
->GrantedListHead
)
865 //found previous lock?
866 if (EnumEntry
== LocalLastReturnedLock
)
868 FoundPrevious
= TRUE
;
870 EnumEntry
= EnumEntry
->Flink
;
871 if (EnumEntry
!= &LockToc
->GrantedListHead
)
873 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
874 LocalLastReturnedLockInfo
= Granted
->Lock
;
875 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
877 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
878 FileLock
->LastReturnedLock
= EnumEntry
;
879 return &FileLock
->LastReturnedLockInfo
;
883 EnumEntry
= EnumEntry
->Flink
;
888 //got here? uh no, didn't find our last lock..must have been freed...restart
893 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
895 return NULL
;//no (more) locks
899 /**********************************************************************
901 * FsRtlInitializeFileLock
904 * Called when creating/allocating/initializing FCB
910 FsRtlInitializeFileLock (
911 IN PFILE_LOCK FileLock
,
912 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
913 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
917 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
918 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
919 FileLock
->UnlockRoutine
= UnlockRoutine
;
920 FileLock
->LockInformation
= NULL
;
925 /**********************************************************************
934 IN PFILE_LOCK FileLock
,
935 IN PFILE_OBJECT FileObject
,
936 IN PLARGE_INTEGER FileOffset
,
937 IN PLARGE_INTEGER Length
,
938 IN PEPROCESS Process
,
940 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
941 IN BOOLEAN ExclusiveLock
,
942 OUT PIO_STATUS_BLOCK IoStatus
,
943 IN PIRP Irp OPTIONAL
,
945 IN BOOLEAN AlreadySynchronized
948 PFILE_LOCK_TOC LockToc
;
952 if (FileLock
->LockInformation
== NULL
)
954 ExAcquireFastMutex(&LockTocMutex
);
956 if (FileLock
->LockInformation
== NULL
)
958 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
959 LockToc
= FileLock
->LockInformation
;
960 KeInitializeSpinLock(&LockToc
->SpinLock
);
961 InitializeListHead(&LockToc
->GrantedListHead
);
962 InitializeListHead(&LockToc
->PendingListHead
);
963 InitializeListHead(&LockToc
->CompletedListHead
);
964 InitializeListHead(&LockToc
->UnlockedListHead
);
966 ExReleaseFastMutex(&LockTocMutex
);
969 LockToc
= FileLock
->LockInformation
;
970 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
972 //try add new lock (while holding spin lock)
973 if (FsRtlpAddLock(LockToc
,
982 IoStatus
->Status
= STATUS_SUCCESS
;
984 else if (Irp
&& !FailImmediately
)
985 { //failed + irp + no fail = mk. pending
986 //for our cancel routine
987 Irp
->Tail
.Overlay
.DriverContext
[0] = (PVOID
)FileLock
;
988 Irp
->Tail
.Overlay
.DriverContext
[1] = (PVOID
)LockToc
;
989 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
991 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
995 //irp canceled even before we got to queue it
996 if (IoSetCancelRoutine(Irp
, NULL
))
997 { //Cancel routine will NOT be called: cancel it here
998 IoStatus
->Status
= STATUS_CANCELLED
;
1001 { //Cancel routine WILL be called. When we release the lock it will complete the irp
1002 //Return pending since we are not completing the irp here
1003 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1004 Irp
->IoStatus
.Information
= 0;
1005 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1010 { //not cancelled: queue irp
1011 IoMarkIrpPending(Irp
);
1012 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1013 Irp
->IoStatus
.Information
= 0;
1014 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1020 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1023 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1025 //never pending if no irp;-)
1026 assert(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1028 if (IoStatus
->Status
!= STATUS_PENDING
)
1030 if (IoStatus
->Status
== STATUS_SUCCESS
)
1032 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1037 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1038 Irp
->IoStatus
.Information
= 0;
1040 if (FileLock
->CompleteLockIrpRoutine
)
1041 { //complete irp routine
1043 if (!NT_SUCCESS(FileLock
->CompleteLockIrpRoutine(Context
,Irp
)))
1045 //CompleteLockIrpRoutine complain: revert changes
1046 FsRtlpUnlockSingle( FileLock
,
1053 AlreadySynchronized
,
1054 FALSE
//CallUnlockRoutine
1059 {//std irp completion
1060 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1065 //NOTE: only fast io seems to care about this return value
1066 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1072 /**********************************************************************
1074 * FsRtlProcessFileLock
1080 FsRtlProcessFileLock (
1081 IN PFILE_LOCK FileLock
,
1083 IN PVOID Context OPTIONAL
1086 PEXTENDED_IO_STACK_LOCATION Stack
;
1088 IO_STATUS_BLOCK LocalIoStatus
;
1091 Stack
= (PEXTENDED_IO_STACK_LOCATION
) IoGetCurrentIrpStackLocation(Irp
);
1092 Irp
->IoStatus
.Information
= 0;
1094 switch(Stack
->MinorFunction
)
1098 FsRtlPrivateLock( FileLock
,
1100 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1101 Stack
->Parameters
.LockControl
.Length
,
1102 IoGetRequestorProcess(Irp
),
1103 Stack
->Parameters
.LockControl
.Key
,
1104 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1105 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1111 return LocalIoStatus
.Status
;
1113 case IRP_MN_UNLOCK_SINGLE
:
1114 Status
= FsRtlFastUnlockSingle ( FileLock
,
1116 &Stack
->Parameters
.LockControl
.ByteOffset
,
1117 Stack
->Parameters
.LockControl
.Length
,
1118 IoGetRequestorProcess(Irp
),
1119 Stack
->Parameters
.LockControl
.Key
,
1124 case IRP_MN_UNLOCK_ALL
:
1125 Status
= FsRtlFastUnlockAll( FileLock
,
1127 IoGetRequestorProcess(Irp
),
1131 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1132 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1134 IoGetRequestorProcess(Irp
),
1135 Stack
->Parameters
.LockControl
.Key
,
1141 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1142 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1146 Irp
->IoStatus
.Status
= Status
;
1148 if (FileLock
->CompleteLockIrpRoutine
)
1150 FileLock
->CompleteLockIrpRoutine(Context
,Irp
);
1154 IofCompleteRequest(Irp
,IO_NO_INCREMENT
);
1161 /**********************************************************************
1163 * FsRtlUninitializeFileLock
1169 FsRtlUninitializeFileLock (
1170 IN PFILE_LOCK FileLock
1173 PFILE_LOCK_TOC LockToc
;
1175 PFILE_LOCK_GRANTED Granted
;
1176 PLIST_ENTRY EnumEntry
;
1180 if (FileLock
->LockInformation
== NULL
)
1185 LockToc
= FileLock
->LockInformation
;
1187 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1189 //remove and free granted locks
1190 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1192 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1193 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1194 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1197 //remove, complete and free all pending locks
1198 while (!IsListEmpty(&LockToc
->PendingListHead
))
1200 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1201 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1203 if (!IoSetCancelRoutine(Irp
, NULL
))
1205 //The cancel routine will be called. When we release the lock it will complete the irp.
1206 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1211 Cancel routine will NOT be called, even though the irp might have been canceled.
1212 Don't care since we'l complete it faster than the cancel routine would have.
1214 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);//fires cancel routine
1216 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1218 if (FileLock
->CompleteLockIrpRoutine
)
1220 FileLock
->CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
1224 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1227 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1231 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1233 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1235 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1236 FileLock
->LockInformation
= NULL
;
1241 /**********************************************************************
1243 * FsRtlAllocateFileLock
1246 * Only present in NT 5.0 or later.
1247 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1253 FsRtlAllocateFileLock(
1254 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1255 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1258 PFILE_LOCK FileLock
;
1260 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1262 FsRtlInitializeFileLock(FileLock
,
1263 CompleteLockIrpRoutine
,
1270 /**********************************************************************
1275 * Only present in NT 5.0 or later.
1276 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1283 IN PFILE_LOCK FileLock
1288 FsRtlUninitializeFileLock(FileLock
);
1289 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);