1 /* $Id: filelock.c,v 1.15 2004/10/22 20:19:58 ekohl Exp $
3 * reactos/ntoskrnl/fs/filelock.c
9 #include <internal/debug.h>
13 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
14 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
18 #define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
19 #define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1)
20 #define REQUEST_START_OFF (FileOffset->QuadPart)
21 #define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
23 FAST_MUTEX LockTocMutex
;
24 NPAGED_LOOKASIDE_LIST GrantedLookaside
;
25 NPAGED_LOOKASIDE_LIST LockTocLookaside
;
26 PAGED_LOOKASIDE_LIST LockLookaside
;
28 /**********************************************************************
30 * FsRtlpInitFileLockingImplementation
35 FsRtlpInitFileLockingImplementation(VOID
)
37 ExInitializeNPagedLookasideList( &LockTocLookaside
,
41 sizeof(FILE_LOCK_TOC
),
46 ExInitializeNPagedLookasideList( &GrantedLookaside
,
50 sizeof(FILE_LOCK_GRANTED
),
55 ExInitializePagedLookasideList( &LockLookaside
,
64 ExInitializeFastMutex(&LockTocMutex
);
67 /**********************************************************************
69 * FsRtlpFileLockCancelRoutine
74 FsRtlpFileLockCancelRoutine(
75 IN PDEVICE_OBJECT DeviceObject
,
81 PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine
;
83 //don't need this since we have our own sync. protecting irp cancellation
84 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
86 SpinLock
= &((PFILE_LOCK_TOC
)Irp
->Tail
.Overlay
.DriverContext
[1])->SpinLock
;
88 KeAcquireSpinLock(SpinLock
, &oldIrql
);
89 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
90 KeReleaseSpinLock(SpinLock
, oldIrql
);
92 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
94 CompleteLockIrpRoutine
= ((PFILE_LOCK
)Irp
->Tail
.Overlay
.DriverContext
[0])->CompleteLockIrpRoutine
;
95 if (CompleteLockIrpRoutine
)
97 CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
101 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
106 /**********************************************************************
108 * FsRtlpCheckLockForReadOrWriteAccess
113 FsRtlpCheckLockForReadOrWriteAccess(
114 IN PFILE_LOCK FileLock
,
115 IN PLARGE_INTEGER FileOffset
,
116 IN PLARGE_INTEGER Length
,
118 IN PFILE_OBJECT FileObject
,
119 IN PEPROCESS Process
,
124 PFILE_LOCK_TOC LockToc
;
125 PFILE_LOCK_GRANTED Granted
;
126 PLIST_ENTRY EnumEntry
;
129 LockToc
= FileLock
->LockInformation
;
131 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
136 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
138 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
139 while ( EnumEntry
!= &LockToc
->GrantedListHead
)
141 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
143 if(!(REQUEST_START_OFF
> LOCK_END_OFF(Granted
->Lock
) ||
144 REQUEST_END_OFF
< LOCK_START_OFF(Granted
->Lock
)))
146 //No read conflict if (shared lock) OR (exclusive + our lock)
147 //No write conflict if exclusive lock AND our lock
148 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
149 (Granted
->Lock
.ExclusiveLock
&&
150 Granted
->Lock
.Process
== Process
&&
151 Granted
->Lock
.FileObject
== FileObject
&&
152 Granted
->Lock
.Key
== Key
) )
154 //AND if lock surround request region, stop searching and grant
155 if (REQUEST_START_OFF
>= LOCK_START_OFF(Granted
->Lock
) &&
156 REQUEST_END_OFF
<= LOCK_END_OFF(Granted
->Lock
))
158 EnumEntry
= &LockToc
->GrantedListHead
;//indicate no conflict
161 //else continue searching for conflicts
168 EnumEntry
= EnumEntry
->Flink
;
171 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
173 if (EnumEntry
== &LockToc
->GrantedListHead
)
182 /**********************************************************************
184 * FsRtlCheckLockForReadAccess
190 FsRtlCheckLockForReadAccess (
191 IN PFILE_LOCK FileLock
,
195 PIO_STACK_LOCATION Stack
;
196 LARGE_INTEGER LocalLength
;
198 Stack
= IoGetCurrentIrpStackLocation(Irp
);
200 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
201 LocalLength
.u
.HighPart
= 0;
203 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
204 &Stack
->Parameters
.Read
.ByteOffset
,
206 Stack
->Parameters
.Read
.Key
,
208 IoGetRequestorProcess(Irp
),
214 /**********************************************************************
216 * FsRtlCheckLockForWriteAccess
222 FsRtlCheckLockForWriteAccess (
223 IN PFILE_LOCK FileLock
,
227 PIO_STACK_LOCATION Stack
;
228 LARGE_INTEGER LocalLength
;
230 Stack
= IoGetCurrentIrpStackLocation(Irp
);
232 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
233 LocalLength
.u
.HighPart
= 0;
235 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
236 &Stack
->Parameters
.Write
.ByteOffset
,
238 Stack
->Parameters
.Write
.Key
,
240 IoGetRequestorProcess(Irp
),
249 /**********************************************************************
251 * FsRtlFastCheckLockForRead
257 FsRtlFastCheckLockForRead (
258 IN PFILE_LOCK FileLock
,
259 IN PLARGE_INTEGER FileOffset
,
260 IN PLARGE_INTEGER Length
,
262 IN PFILE_OBJECT FileObject
,
266 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
277 /**********************************************************************
279 * FsRtlFastCheckLockForWrite
285 FsRtlFastCheckLockForWrite (
286 IN PFILE_LOCK FileLock
,
287 IN PLARGE_INTEGER FileOffset
,
288 IN PLARGE_INTEGER Length
,
290 IN PFILE_OBJECT FileObject
,
294 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
306 /**********************************************************************
308 * FsRtlpFastUnlockAllByKey
313 FsRtlpFastUnlockAllByKey(
314 IN PFILE_LOCK FileLock
,
315 IN PFILE_OBJECT FileObject
,
316 IN PEPROCESS Process
,
317 IN DWORD Key
, /* FIXME: guess */
318 IN BOOLEAN UseKey
, /* FIXME: guess */
319 IN PVOID Context OPTIONAL
323 PFILE_LOCK_TOC LockToc
;
324 PLIST_ENTRY EnumEntry
;
325 PFILE_LOCK_GRANTED Granted
;
326 BOOLEAN Unlock
= FALSE
;
327 //must make local copy since FILE_LOCK struct is allowed to be paged
328 PUNLOCK_ROUTINE GotUnlockRoutine
;
331 LockToc
= FileLock
->LockInformation
;
335 return STATUS_RANGE_NOT_LOCKED
;
338 GotUnlockRoutine
= FileLock
->UnlockRoutine
;
339 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
341 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
342 while (EnumEntry
!= &LockToc
->GrantedListHead
)
344 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
345 EnumEntry
= EnumEntry
->Flink
;
347 if (Granted
->Lock
.Process
== Process
&&
348 Granted
->Lock
.FileObject
== FileObject
&&
349 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
351 RemoveEntryList(&Granted
->ListEntry
);
354 if (GotUnlockRoutine
)
357 Put on unlocked list and call unlock routine for them afterwards.
358 This way we don't have to restart enum after each call
360 InsertHeadList(&LockToc
->UnlockedListHead
,&Granted
->ListEntry
);
364 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
371 //call unlock routine for each unlocked lock (if any)
372 while (!IsListEmpty(&LockToc
->UnlockedListHead
))
374 EnumEntry
= RemoveTailList(&LockToc
->UnlockedListHead
);
375 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
376 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
377 FileLock
->UnlockRoutine(Context
,&Granted
->Lock
);
378 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
379 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
382 //NOTE: holding spinlock while calling this
383 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
);
385 if (IsListEmpty(&LockToc
->GrantedListHead
))
387 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
388 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
392 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
394 return STATUS_SUCCESS
;
397 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
398 return STATUS_RANGE_NOT_LOCKED
;
401 /**********************************************************************
409 FsRtlFastUnlockAll
/*ByProcess*/ (
410 IN PFILE_LOCK FileLock
,
411 IN PFILE_OBJECT FileObject
,
412 IN PEPROCESS Process
,
413 IN PVOID Context OPTIONAL
416 return FsRtlpFastUnlockAllByKey( FileLock
,
420 FALSE
, /* Do NOT use Key */
425 /**********************************************************************
427 * FsRtlFastUnlockAllByKey
433 FsRtlFastUnlockAllByKey (
434 IN PFILE_LOCK FileLock
,
435 IN PFILE_OBJECT FileObject
,
436 IN PEPROCESS Process
,
438 IN PVOID Context OPTIONAL
441 return FsRtlpFastUnlockAllByKey( FileLock
,
451 /**********************************************************************
456 * Spinlock held at entry !!
461 IN PFILE_LOCK_TOC LockToc
,
462 IN PFILE_OBJECT FileObject
,
463 IN PLARGE_INTEGER FileOffset
,
464 IN PLARGE_INTEGER Length
,
465 IN PEPROCESS Process
,
467 IN BOOLEAN ExclusiveLock
470 PLIST_ENTRY EnumEntry
;
471 PFILE_LOCK_GRANTED Granted
;
473 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
474 while (EnumEntry
!= &LockToc
->GrantedListHead
)
476 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
478 if(!(REQUEST_START_OFF
> LOCK_END_OFF(Granted
->Lock
) ||
479 REQUEST_END_OFF
< LOCK_START_OFF(Granted
->Lock
)))
481 //never conflict if shared lock and we want to add a shared lock
482 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
484 //AND if lock surround region, stop searching and insert lock
485 if (REQUEST_START_OFF
>= LOCK_START_OFF(Granted
->Lock
) &&
486 REQUEST_END_OFF
<= LOCK_END_OFF(Granted
->Lock
))
488 EnumEntry
= &LockToc
->GrantedListHead
;
491 //else keep locking for conflicts
494 {//conflict if we want share access to excl. lock OR exlc. access to shared lock
498 EnumEntry
= EnumEntry
->Flink
;
501 if (EnumEntry
== &LockToc
->GrantedListHead
)
503 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
505 Granted
->Lock
.StartingByte
= *FileOffset
;
506 Granted
->Lock
.Length
= *Length
;
507 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
508 Granted
->Lock
.Key
= Key
;
509 Granted
->Lock
.FileObject
= FileObject
;
510 Granted
->Lock
.Process
= Process
;
511 Granted
->Lock
.EndingByte
.QuadPart
= REQUEST_END_OFF
;
513 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
523 /**********************************************************************
525 * FsRtlpCompletePendingLocks
528 * Spinlock held at entry !!
532 FsRtlpCompletePendingLocks(
533 IN PFILE_LOCK FileLock
,
534 IN PFILE_LOCK_TOC LockToc
,
535 IN OUT PKIRQL oldirql
538 //walk pending list, FIFO order, try 2 complete locks
539 PLIST_ENTRY EnumEntry
;
541 PEXTENDED_IO_STACK_LOCATION Stack
;
543 EnumEntry
= LockToc
->PendingListHead
.Blink
;
544 while (EnumEntry
!= &LockToc
->PendingListHead
)
546 Irp
= CONTAINING_RECORD(EnumEntry
,IRP
, Tail
.Overlay
.ListEntry
);
548 Stack
= (PEXTENDED_IO_STACK_LOCATION
) IoGetCurrentIrpStackLocation(Irp
);
549 if (FsRtlpAddLock(LockToc
,
551 &Stack
->Parameters
.LockControl
.ByteOffset
,
552 Stack
->Parameters
.LockControl
.Length
,
553 IoGetRequestorProcess(Irp
),
554 Stack
->Parameters
.LockControl
.Key
,
555 Stack
->Flags
& SL_EXCLUSIVE_LOCK
558 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
560 if (!IoSetCancelRoutine(Irp
, NULL
))
563 Cancel routine WILL be called after we release the spinlock. It will try to remove
564 the irp from the list and cancel/complete this irp. Since we allready removed it,
565 make its ListEntry point to itself.
567 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
572 Cancel routine will NOT be called, canceled or not.
574 Put on completed list and complete them all afterwards.
575 This way we don't have to restart enum after each completion.
577 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
578 Irp
->IoStatus
.Information
= 0;
579 InsertHeadList(&LockToc
->CompletedListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
582 EnumEntry
= EnumEntry
->Blink
;
585 //complete irp's (if any)
586 while (!IsListEmpty(&LockToc
->CompletedListHead
))
588 EnumEntry
= RemoveTailList(&LockToc
->CompletedListHead
);
589 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);//fires cancel routine
590 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
592 if (FileLock
->CompleteLockIrpRoutine
)
594 FileLock
->CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
598 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
601 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
608 /**********************************************************************
616 IN PFILE_LOCK FileLock
,
617 IN PFILE_OBJECT FileObject
,
618 IN PLARGE_INTEGER FileOffset
,
619 IN PLARGE_INTEGER Length
,
620 IN PEPROCESS Process
,
622 IN PVOID Context OPTIONAL
,
623 IN BOOLEAN AlreadySynchronized
,
624 IN BOOLEAN CallUnlockRoutine
628 PFILE_LOCK_TOC LockToc
;
629 PFILE_LOCK_GRANTED Granted
;
630 PLIST_ENTRY EnumEntry
;
633 LockToc
= FileLock
->LockInformation
;
635 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
637 return STATUS_RANGE_NOT_LOCKED
;
640 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
642 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
643 while (EnumEntry
!= &LockToc
->GrantedListHead
)
645 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
647 //must be exact match
648 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
649 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
650 Granted
->Lock
.Process
== Process
&&
651 Granted
->Lock
.FileObject
== FileObject
&&
652 Granted
->Lock
.Key
== Key
)
654 RemoveEntryList(&Granted
->ListEntry
);
655 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
);
657 if (IsListEmpty(&LockToc
->GrantedListHead
))
659 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
660 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
664 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
667 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
669 FileLock
->UnlockRoutine(Context
,&Granted
->Lock
);
672 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
674 return STATUS_SUCCESS
;
676 EnumEntry
= EnumEntry
->Flink
;
679 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
681 return STATUS_RANGE_NOT_LOCKED
;
687 /**********************************************************************
689 * FsRtlFastUnlockSingle
695 FsRtlFastUnlockSingle (
696 IN PFILE_LOCK FileLock
,
697 IN PFILE_OBJECT FileObject
,
698 IN PLARGE_INTEGER FileOffset
,
699 IN PLARGE_INTEGER Length
,
700 IN PEPROCESS Process
,
702 IN PVOID Context OPTIONAL
,
703 IN BOOLEAN AlreadySynchronized
706 return FsRtlpUnlockSingle( FileLock
,
714 TRUE
//CallUnlockRoutine
718 /**********************************************************************
720 * FsRtlpDumpFileLocks
722 * NOTE: used for testing and debugging
727 IN PFILE_LOCK FileLock
731 PFILE_LOCK_TOC LockToc
;
732 PFILE_LOCK_GRANTED Granted
;
734 PLIST_ENTRY EnumEntry
;
735 PEXTENDED_IO_STACK_LOCATION Stack
;
738 LockToc
= FileLock
->LockInformation
;
742 DPRINT1("No file locks\n");
746 DPRINT1("Dumping granted file locks, FIFO order\n");
748 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
750 EnumEntry
= LockToc
->GrantedListHead
.Blink
;
751 while ( EnumEntry
!= &LockToc
->GrantedListHead
)
753 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
755 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
756 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
757 Granted
->Lock
.StartingByte
.QuadPart
,
758 Granted
->Lock
.Length
.QuadPart
,
759 Granted
->Lock
.EndingByte
.QuadPart
,
761 Granted
->Lock
.Process
,
762 Granted
->Lock
.FileObject
765 EnumEntry
= EnumEntry
->Blink
;
768 DPRINT1("Dumping pending file locks, FIFO order\n");
770 EnumEntry
= LockToc
->PendingListHead
.Blink
;
771 while ( EnumEntry
!= &LockToc
->PendingListHead
)
773 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
775 Stack
= (PEXTENDED_IO_STACK_LOCATION
) IoGetCurrentIrpStackLocation(Irp
);
777 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
778 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
779 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
780 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
781 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
782 Stack
->Parameters
.LockControl
.Key
,
783 IoGetRequestorProcess(Irp
),
787 EnumEntry
= EnumEntry
->Blink
;
790 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
795 /**********************************************************************
797 * FsRtlGetNextFileLock
800 * NULL if no more locks.
806 FsRtlGetNextFileLock (
807 IN PFILE_LOCK FileLock
,
812 Messy enumeration of granted locks.
813 What our last ptr. in LastReturnedLock points at, might have been freed between
814 calls, so we have to scan thru the list every time, searching for our last lock.
815 If it's not there anymore, restart the enumeration...
818 PLIST_ENTRY EnumEntry
;
819 PFILE_LOCK_GRANTED Granted
;
820 PFILE_LOCK_TOC LockToc
;
821 BOOLEAN FoundPrevious
= FALSE
;
822 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
823 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
824 PVOID LocalLastReturnedLock
;
827 LockToc
= FileLock
->LockInformation
;
833 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
835 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
839 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
843 if (EnumEntry
!= &LockToc
->GrantedListHead
)
845 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
846 LocalLastReturnedLockInfo
= Granted
->Lock
;
847 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
849 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
850 FileLock
->LastReturnedLock
= EnumEntry
;
851 return &FileLock
->LastReturnedLockInfo
;
855 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
860 //else: continue enum
861 while (EnumEntry
!= &LockToc
->GrantedListHead
)
863 //found previous lock?
864 if (EnumEntry
== LocalLastReturnedLock
)
866 FoundPrevious
= TRUE
;
868 EnumEntry
= EnumEntry
->Flink
;
869 if (EnumEntry
!= &LockToc
->GrantedListHead
)
871 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
872 LocalLastReturnedLockInfo
= Granted
->Lock
;
873 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
875 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
876 FileLock
->LastReturnedLock
= EnumEntry
;
877 return &FileLock
->LastReturnedLockInfo
;
881 EnumEntry
= EnumEntry
->Flink
;
886 //got here? uh no, didn't find our last lock..must have been freed...restart
891 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
893 return NULL
;//no (more) locks
897 /**********************************************************************
899 * FsRtlInitializeFileLock
902 * Called when creating/allocating/initializing FCB
908 FsRtlInitializeFileLock (
909 IN PFILE_LOCK FileLock
,
910 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
911 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
915 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
916 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
917 FileLock
->UnlockRoutine
= UnlockRoutine
;
918 FileLock
->LockInformation
= NULL
;
923 /**********************************************************************
932 IN PFILE_LOCK FileLock
,
933 IN PFILE_OBJECT FileObject
,
934 IN PLARGE_INTEGER FileOffset
,
935 IN PLARGE_INTEGER Length
,
936 IN PEPROCESS Process
,
938 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
939 IN BOOLEAN ExclusiveLock
,
940 OUT PIO_STATUS_BLOCK IoStatus
,
941 IN PIRP Irp OPTIONAL
,
943 IN BOOLEAN AlreadySynchronized
946 PFILE_LOCK_TOC LockToc
;
950 if (FileLock
->LockInformation
== NULL
)
952 ExAcquireFastMutex(&LockTocMutex
);
954 if (FileLock
->LockInformation
== NULL
)
956 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
957 LockToc
= FileLock
->LockInformation
;
958 KeInitializeSpinLock(&LockToc
->SpinLock
);
959 InitializeListHead(&LockToc
->GrantedListHead
);
960 InitializeListHead(&LockToc
->PendingListHead
);
961 InitializeListHead(&LockToc
->CompletedListHead
);
962 InitializeListHead(&LockToc
->UnlockedListHead
);
964 ExReleaseFastMutex(&LockTocMutex
);
967 LockToc
= FileLock
->LockInformation
;
968 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
970 //try add new lock (while holding spin lock)
971 if (FsRtlpAddLock(LockToc
,
980 IoStatus
->Status
= STATUS_SUCCESS
;
982 else if (Irp
&& !FailImmediately
)
983 { //failed + irp + no fail = mk. pending
984 //for our cancel routine
985 Irp
->Tail
.Overlay
.DriverContext
[0] = (PVOID
)FileLock
;
986 Irp
->Tail
.Overlay
.DriverContext
[1] = (PVOID
)LockToc
;
987 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
989 IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
993 //irp canceled even before we got to queue it
994 if (IoSetCancelRoutine(Irp
, NULL
))
995 { //Cancel routine will NOT be called: cancel it here
996 IoStatus
->Status
= STATUS_CANCELLED
;
999 { //Cancel routine WILL be called. When we release the lock it will complete the irp
1000 //Return pending since we are not completing the irp here
1001 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1002 Irp
->IoStatus
.Information
= 0;
1003 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1008 { //not cancelled: queue irp
1009 IoMarkIrpPending(Irp
);
1010 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
1011 Irp
->IoStatus
.Information
= 0;
1012 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
1018 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
1021 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
1023 //never pending if no irp;-)
1024 ASSERT(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
1026 if (IoStatus
->Status
!= STATUS_PENDING
)
1028 if (IoStatus
->Status
== STATUS_SUCCESS
)
1030 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
1035 Irp
->IoStatus
.Status
= IoStatus
->Status
;
1036 Irp
->IoStatus
.Information
= 0;
1038 if (FileLock
->CompleteLockIrpRoutine
)
1039 { //complete irp routine
1041 if (!NT_SUCCESS(FileLock
->CompleteLockIrpRoutine(Context
,Irp
)))
1043 //CompleteLockIrpRoutine complain: revert changes
1044 FsRtlpUnlockSingle( FileLock
,
1051 AlreadySynchronized
,
1052 FALSE
//CallUnlockRoutine
1057 {//std irp completion
1058 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1063 //NOTE: only fast io seems to care about this return value
1064 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
1070 /**********************************************************************
1072 * FsRtlProcessFileLock
1078 FsRtlProcessFileLock (
1079 IN PFILE_LOCK FileLock
,
1081 IN PVOID Context OPTIONAL
1084 PEXTENDED_IO_STACK_LOCATION Stack
;
1086 IO_STATUS_BLOCK LocalIoStatus
;
1089 Stack
= (PEXTENDED_IO_STACK_LOCATION
) IoGetCurrentIrpStackLocation(Irp
);
1090 Irp
->IoStatus
.Information
= 0;
1092 switch(Stack
->MinorFunction
)
1096 FsRtlPrivateLock( FileLock
,
1098 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1099 Stack
->Parameters
.LockControl
.Length
,
1100 IoGetRequestorProcess(Irp
),
1101 Stack
->Parameters
.LockControl
.Key
,
1102 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1103 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1109 return LocalIoStatus
.Status
;
1111 case IRP_MN_UNLOCK_SINGLE
:
1112 Status
= FsRtlFastUnlockSingle ( FileLock
,
1114 &Stack
->Parameters
.LockControl
.ByteOffset
,
1115 Stack
->Parameters
.LockControl
.Length
,
1116 IoGetRequestorProcess(Irp
),
1117 Stack
->Parameters
.LockControl
.Key
,
1122 case IRP_MN_UNLOCK_ALL
:
1123 Status
= FsRtlFastUnlockAll( FileLock
,
1125 IoGetRequestorProcess(Irp
),
1129 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1130 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1132 IoGetRequestorProcess(Irp
),
1133 Stack
->Parameters
.LockControl
.Key
,
1139 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1140 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1144 Irp
->IoStatus
.Status
= Status
;
1146 if (FileLock
->CompleteLockIrpRoutine
)
1148 FileLock
->CompleteLockIrpRoutine(Context
,Irp
);
1152 IofCompleteRequest(Irp
,IO_NO_INCREMENT
);
1159 /**********************************************************************
1161 * FsRtlUninitializeFileLock
1167 FsRtlUninitializeFileLock (
1168 IN PFILE_LOCK FileLock
1171 PFILE_LOCK_TOC LockToc
;
1173 PFILE_LOCK_GRANTED Granted
;
1174 PLIST_ENTRY EnumEntry
;
1178 if (FileLock
->LockInformation
== NULL
)
1183 LockToc
= FileLock
->LockInformation
;
1185 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1187 //remove and free granted locks
1188 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1190 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1191 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1192 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1195 //remove, complete and free all pending locks
1196 while (!IsListEmpty(&LockToc
->PendingListHead
))
1198 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1199 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1201 if (!IoSetCancelRoutine(Irp
, NULL
))
1203 //The cancel routine will be called. When we release the lock it will complete the irp.
1204 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
1209 Cancel routine will NOT be called, even though the irp might have been canceled.
1210 Don't care since we'l complete it faster than the cancel routine would have.
1212 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);//fires cancel routine
1214 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1216 if (FileLock
->CompleteLockIrpRoutine
)
1218 FileLock
->CompleteLockIrpRoutine(Irp
->Tail
.Overlay
.DriverContext
[2], Irp
);
1222 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1225 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1229 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
1231 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1233 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1234 FileLock
->LockInformation
= NULL
;
1239 /**********************************************************************
1241 * FsRtlAllocateFileLock
1244 * Only present in NT 5.0 or later.
1245 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1251 FsRtlAllocateFileLock(
1252 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1253 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1256 PFILE_LOCK FileLock
;
1258 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1260 FsRtlInitializeFileLock(FileLock
,
1261 CompleteLockIrpRoutine
,
1268 /**********************************************************************
1273 * Only present in NT 5.0 or later.
1274 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1281 IN PFILE_LOCK FileLock
1286 FsRtlUninitializeFileLock(FileLock
);
1287 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);
1295 FsRtlAcquireFileExclusive(
1296 IN PFILE_OBJECT FileObject
1308 IN PFILE_OBJECT FileObject