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
;
29 IsOverlappingLock(PFILE_LOCK_INFO Lock
,
30 PLARGE_INTEGER StartOffset
,
31 PLARGE_INTEGER EndOffset
)
33 if ((ULONGLONG
)StartOffset
->QuadPart
> (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
38 if ((ULONGLONG
)EndOffset
->QuadPart
< (ULONGLONG
)Lock
->StartingByte
.QuadPart
)
47 IsSurroundingLock(PFILE_LOCK_INFO Lock
,
48 PLARGE_INTEGER StartOffset
,
49 PLARGE_INTEGER EndOffset
)
51 if ((ULONGLONG
)StartOffset
->QuadPart
>= (ULONGLONG
)Lock
->StartingByte
.QuadPart
&&
52 (ULONGLONG
)EndOffset
->QuadPart
<= (ULONGLONG
)Lock
->EndingByte
.QuadPart
)
64 /* Initialize the list for all lock information structures */
65 ExInitializeNPagedLookasideList(&LockTocLookaside
,
69 sizeof(FILE_LOCK_TOC
),
73 /* Initialize the list for granted locks */
74 ExInitializeNPagedLookasideList(&GrantedLookaside
,
78 sizeof(FILE_LOCK_GRANTED
),
82 /* Initialize the list for lock allocations */
83 ExInitializePagedLookasideList(&LockLookaside
,
91 /* Initialize the lock information mutex */
92 ExInitializeFastMutex(&LockTocMutex
);
97 FsRtlCompleteLockIrpReal(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteRoutine
,
101 OUT PNTSTATUS NewStatus
,
102 IN PFILE_OBJECT FileObject OPTIONAL
)
104 /* Check if we have a complete routine */
107 /* Check if we have a file object */
108 if (FileObject
) FileObject
->LastLock
= NULL
;
110 /* Set the I/O Status and do completion */
111 Irp
->IoStatus
.Status
= Status
;
112 *NewStatus
= CompleteRoutine(Context
, Irp
);
116 /* Otherwise do a normal I/O complete request */
117 FsRtlCompleteRequest(Irp
, Status
);
124 FsRtlpFileLockCancelRoutine(IN PDEVICE_OBJECT DeviceObject
,
128 PKSPIN_LOCK SpinLock
;
130 //don't need this since we have our own sync. protecting irp cancellation
131 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
133 SpinLock
= Irp
->Tail
.Overlay
.DriverContext
[3];
135 KeAcquireSpinLock(SpinLock
, &oldIrql
);
137 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
139 KeReleaseSpinLock(SpinLock
, oldIrql
);
141 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
142 Irp
->IoStatus
.Information
= 0;
144 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
149 FsRtlpCheckLockForReadOrWriteAccess(IN PFILE_LOCK FileLock
,
150 IN PLARGE_INTEGER FileOffset
,
151 IN PLARGE_INTEGER Length
,
153 IN PFILE_OBJECT FileObject
,
154 IN PEPROCESS Process
,
158 PFILE_LOCK_TOC LockToc
;
159 PFILE_LOCK_GRANTED Granted
;
160 LARGE_INTEGER EndOffset
;
164 LockToc
= FileLock
->LockInformation
;
166 if (LockToc
== NULL
|| Length
->QuadPart
== 0)
171 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
173 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
175 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
178 if(IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
180 //No read conflict if (shared lock) OR (exclusive + our lock)
181 //No write conflict if exclusive lock AND our lock
182 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
183 (Granted
->Lock
.ExclusiveLock
&&
184 Granted
->Lock
.ProcessId
== Process
&&
185 Granted
->Lock
.FileObject
== FileObject
&&
186 Granted
->Lock
.Key
== Key
) )
188 //AND if lock surround request region, stop searching and grant
189 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
) )
191 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
195 //else continue searching for conflicts
200 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
207 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
213 FsRtlpFastUnlockAllByKey(IN PFILE_LOCK FileLock
,
214 IN PFILE_OBJECT FileObject
,
215 IN PEPROCESS Process
,
218 IN PVOID Context OPTIONAL
)
221 PFILE_LOCK_TOC LockToc
;
222 PFILE_LOCK_GRANTED Granted
, tmp
;
223 BOOLEAN Unlock
= FALSE
;
224 //must make local copy since FILE_LOCK struct is allowed to be paged
225 BOOLEAN GotUnlockRoutine
;
226 LIST_ENTRY UnlockedListHead
;
227 PLIST_ENTRY EnumEntry
;
230 LockToc
= FileLock
->LockInformation
;
234 return STATUS_RANGE_NOT_LOCKED
;
237 InitializeListHead(&UnlockedListHead
);
238 GotUnlockRoutine
= FileLock
->UnlockRoutine
!= NULL
;
239 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
241 LIST_FOR_EACH_SAFE(Granted
, tmp
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
244 if (Granted
->Lock
.ProcessId
== Process
&&
245 Granted
->Lock
.FileObject
== FileObject
&&
246 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) )
248 RemoveEntryList(&Granted
->ListEntry
);
251 if (GotUnlockRoutine
)
254 Put on unlocked list and call unlock routine for them afterwards.
255 This way we don't have to restart enum after each call
257 InsertHeadList(&UnlockedListHead
,&Granted
->ListEntry
);
261 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
266 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
270 //call unlock routine for each unlocked lock (if any)
271 while (!IsListEmpty(&UnlockedListHead
))
273 EnumEntry
= RemoveTailList(&UnlockedListHead
);
274 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
276 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
277 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
280 //NOTE: holding spinlock while calling this
281 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
282 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
284 if (IsListEmpty(&LockToc
->GrantedListHead
))
286 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
287 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
291 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
294 return STATUS_SUCCESS
;
297 return STATUS_RANGE_NOT_LOCKED
;
302 FsRtlpAddLock(IN PFILE_LOCK_TOC LockToc
,
303 IN PFILE_OBJECT FileObject
,
304 IN PLARGE_INTEGER FileOffset
,
305 IN PLARGE_INTEGER Length
,
306 IN PEPROCESS Process
,
308 IN BOOLEAN ExclusiveLock
,
311 PFILE_LOCK_GRANTED Granted
;
312 LARGE_INTEGER EndOffset
;
314 EndOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
->QuadPart
- 1;
316 //loop and try to find conflicking locks
317 LIST_FOR_EACH(Granted
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
, ListEntry
)
319 if (IsOverlappingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
321 //we found a locks that overlap with the new lock
323 //if both locks are shared, we might have a fast path outa here...
324 if (!Granted
->Lock
.ExclusiveLock
&& !ExclusiveLock
)
326 //if existing lock surround new lock, we know that no other exclusive lock
327 //may overlap with our new lock;-D
328 if (IsSurroundingLock(&Granted
->Lock
, FileOffset
, &EndOffset
))
333 //else keep locking for conflicts
337 //we found a conflict:
338 //we want shared access to an excl. lock OR exlc. access to a shared lock
343 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
346 Granted
->Lock
.StartingByte
= *FileOffset
;
347 Granted
->Lock
.Length
= *Length
;
348 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
349 Granted
->Lock
.Key
= Key
;
350 Granted
->Lock
.FileObject
= FileObject
;
351 Granted
->Lock
.ProcessId
= Process
;
353 Granted
->Lock
.EndingByte
= EndOffset
;
354 Granted
->UnlockContext
= Context
;
356 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
362 FsRtlpCompletePendingLocks(IN PFILE_LOCK FileLock
,
363 IN PFILE_LOCK_TOC LockToc
,
364 IN OUT PKIRQL oldirql
,
367 //walk pending list, FIFO order, try 2 complete locks
368 PLIST_ENTRY EnumEntry
;
370 PIO_STACK_LOCATION Stack
;
371 LIST_ENTRY CompletedListHead
;
373 InitializeListHead(&CompletedListHead
);
375 LIST_FOR_EACH_SAFE(Irp
, tmp
, &LockToc
->PendingListHead
, IRP
, Tail
.Overlay
.ListEntry
)
377 Stack
= IoGetCurrentIrpStackLocation(Irp
);
378 if (FsRtlpAddLock(LockToc
,
380 &Stack
->Parameters
.LockControl
.ByteOffset
,
381 Stack
->Parameters
.LockControl
.Length
,
382 IoGetRequestorProcess(Irp
),
383 Stack
->Parameters
.LockControl
.Key
,
384 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
385 Irp
->Tail
.Overlay
.DriverContext
[2] //Context
388 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
390 if (!IoSetCancelRoutine(Irp
, NULL
))
392 //irp is canceled and cancelroutine will run when we release the lock
393 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
398 Put on completed list and complete them all afterwards.
399 This way we don't have to restart enum after each completion.
401 InsertHeadList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
405 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);
407 //complete irp's (if any)
408 while (!IsListEmpty(&CompletedListHead
))
410 EnumEntry
= RemoveTailList(&CompletedListHead
);
412 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
414 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
415 Irp
->IoStatus
.Information
= 0;
417 if (FileLock
->CompleteLockIrpRoutine
)
419 if (FileLock
->CompleteLockIrpRoutine(Context
, Irp
)!=STATUS_SUCCESS
)
421 Stack
= IoGetCurrentIrpStackLocation(Irp
);
424 FsRtlpUnlockSingle ( FileLock
,
426 &Stack
->Parameters
.LockControl
.ByteOffset
,
427 Stack
->Parameters
.LockControl
.Length
,
428 IoGetRequestorProcess(Irp
),
429 Stack
->Parameters
.LockControl
.Key
,
430 NULL
, /* unused context */
431 FALSE
/* don't call unlock copletion rout.*/
437 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
442 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
447 FsRtlpUnlockSingle(IN PFILE_LOCK FileLock
,
448 IN PFILE_OBJECT FileObject
,
449 IN PLARGE_INTEGER FileOffset
,
450 IN PLARGE_INTEGER Length
,
451 IN PEPROCESS Process
,
453 IN PVOID Context OPTIONAL
,
454 IN BOOLEAN CallUnlockRoutine
)
457 PFILE_LOCK_TOC LockToc
;
458 PFILE_LOCK_GRANTED Granted
, tmp
;
461 LockToc
= FileLock
->LockInformation
;
465 return STATUS_RANGE_NOT_LOCKED
;
468 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
470 LIST_FOR_EACH_SAFE(Granted
, tmp
, &LockToc
->GrantedListHead
, FILE_LOCK_GRANTED
,ListEntry
)
473 //must be exact match
474 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
475 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
476 Granted
->Lock
.ProcessId
== Process
&&
477 Granted
->Lock
.FileObject
== FileObject
&&
478 Granted
->Lock
.Key
== Key
)
480 RemoveEntryList(&Granted
->ListEntry
);
481 FsRtlpCompletePendingLocks(FileLock
, LockToc
, &oldirql
, Context
);
483 if (IsListEmpty(&LockToc
->GrantedListHead
))
485 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
487 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
; //paged data
491 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
494 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
496 FileLock
->UnlockRoutine(Granted
->UnlockContext
, &Granted
->Lock
);
499 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
501 return STATUS_SUCCESS
;
505 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
507 return STATUS_RANGE_NOT_LOCKED
;
511 /* PUBLIC FUNCTIONS **********************************************************/
518 FsRtlGetNextFileLock(IN PFILE_LOCK FileLock
,
522 Messy enumeration of granted locks.
523 What our last ptr. in LastReturnedLock points at, might have been freed between
524 calls, so we have to scan thru the list every time, searching for our last lock.
525 If it's not there anymore, restart the enumeration...
528 PLIST_ENTRY EnumEntry
;
529 PFILE_LOCK_GRANTED Granted
;
530 PFILE_LOCK_TOC LockToc
;
531 BOOLEAN FoundPrevious
= FALSE
;
532 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
533 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
534 PVOID LocalLastReturnedLock
;
537 LockToc
= FileLock
->LockInformation
;
543 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
545 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
549 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
553 if (EnumEntry
!= &LockToc
->GrantedListHead
)
555 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
556 LocalLastReturnedLockInfo
= Granted
->Lock
;
557 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
559 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
560 FileLock
->LastReturnedLock
= EnumEntry
;
561 return &FileLock
->LastReturnedLockInfo
;
565 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
570 //else: continue enum
571 while (EnumEntry
!= &LockToc
->GrantedListHead
)
573 //found previous lock?
574 if (EnumEntry
== LocalLastReturnedLock
)
576 FoundPrevious
= TRUE
;
578 EnumEntry
= EnumEntry
->Flink
;
579 if (EnumEntry
!= &LockToc
->GrantedListHead
)
581 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
582 LocalLastReturnedLockInfo
= Granted
->Lock
;
583 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
585 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
586 FileLock
->LastReturnedLock
= EnumEntry
;
587 return &FileLock
->LastReturnedLockInfo
;
591 EnumEntry
= EnumEntry
->Flink
;
596 //got here? uh no, didn't find our last lock..must have been freed...restart
601 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
603 return NULL
;//no (more) locks
611 FsRtlPrivateLock(IN PFILE_LOCK FileLock
,
612 IN PFILE_OBJECT FileObject
,
613 IN PLARGE_INTEGER FileOffset
,
614 IN PLARGE_INTEGER Length
,
615 IN PEPROCESS Process
,
617 IN BOOLEAN FailImmediately
, //seems meaningless for fast io
618 IN BOOLEAN ExclusiveLock
,
619 OUT PIO_STATUS_BLOCK IoStatus
,
620 IN PIRP Irp OPTIONAL
,
621 IN PVOID Context OPTIONAL
,
622 IN BOOLEAN AlreadySynchronized
)
624 PFILE_LOCK_TOC LockToc
;
628 if (FileLock
->LockInformation
== NULL
)
630 ExAcquireFastMutex(&LockTocMutex
);
632 if (FileLock
->LockInformation
== NULL
)
634 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
635 LockToc
= FileLock
->LockInformation
;
636 KeInitializeSpinLock(&LockToc
->SpinLock
);
637 InitializeListHead(&LockToc
->GrantedListHead
);
638 InitializeListHead(&LockToc
->PendingListHead
);
640 ExReleaseFastMutex(&LockTocMutex
);
643 LockToc
= FileLock
->LockInformation
;
644 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
646 //try add new lock (while holding spin lock)
647 if (FsRtlpAddLock(LockToc
,
657 IoStatus
->Status
= STATUS_SUCCESS
;
659 else if (Irp
&& !FailImmediately
)
661 //failed + irp + no fail = make. pending
663 Irp
->Tail
.Overlay
.DriverContext
[3] = &LockToc
->SpinLock
;
664 Irp
->Tail
.Overlay
.DriverContext
[2] = Context
;
666 (void)IoSetCancelRoutine(Irp
, FsRtlpFileLockCancelRoutine
);
667 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
670 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
672 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
673 Irp
->IoStatus
.Information
= 0;
674 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
679 IoMarkIrpPending(Irp
);
680 Irp
->IoStatus
.Status
= IoStatus
->Status
= STATUS_PENDING
;
681 Irp
->IoStatus
.Information
= 0;
682 InsertHeadList(&LockToc
->PendingListHead
,&Irp
->Tail
.Overlay
.ListEntry
);
687 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
690 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
692 //never pending if no irp;-)
693 ASSERT(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
695 if (IoStatus
->Status
!= STATUS_PENDING
)
697 if (IoStatus
->Status
== STATUS_SUCCESS
)
699 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
704 Irp
->IoStatus
.Status
= IoStatus
->Status
;
705 Irp
->IoStatus
.Information
= 0;
706 if (FileLock
->CompleteLockIrpRoutine
)
708 if (FileLock
->CompleteLockIrpRoutine(Context
,Irp
)!=STATUS_SUCCESS
)
710 //CompleteLockIrpRoutine complain: revert changes
711 FsRtlpUnlockSingle( FileLock
,
718 FALSE
/* don't call unlock copletion routine */
724 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
729 //NOTE: only fast io seems to care about this return value
730 return (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
);
738 FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock
,
741 PIO_STACK_LOCATION Stack
;
742 LARGE_INTEGER LocalLength
;
744 /* Get the I/O Stack location and length */
745 Stack
= IoGetCurrentIrpStackLocation(Irp
);
746 LocalLength
.QuadPart
= Stack
->Parameters
.Read
.Length
;
748 /* Call the internal API */
749 return FsRtlpCheckLockForReadOrWriteAccess(FileLock
,
753 Stack
->Parameters
.Read
.Key
,
755 IoGetRequestorProcess(Irp
),
764 FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock
,
767 PIO_STACK_LOCATION Stack
;
768 LARGE_INTEGER LocalLength
;
770 /* Get the I/O Stack location and length */
771 Stack
= IoGetCurrentIrpStackLocation(Irp
);
772 LocalLength
.QuadPart
= Stack
->Parameters
.Read
.Length
;
774 /* Call the internal API */
775 return FsRtlpCheckLockForReadOrWriteAccess(FileLock
,
779 Stack
->Parameters
.Read
.Key
,
781 IoGetRequestorProcess(Irp
),
790 FsRtlFastCheckLockForRead(IN PFILE_LOCK FileLock
,
791 IN PLARGE_INTEGER FileOffset
,
792 IN PLARGE_INTEGER Length
,
794 IN PFILE_OBJECT FileObject
,
795 IN PEPROCESS Process
)
797 /* Call the internal API */
798 return FsRtlpCheckLockForReadOrWriteAccess(FileLock
,
812 FsRtlFastCheckLockForWrite(IN PFILE_LOCK FileLock
,
813 IN PLARGE_INTEGER FileOffset
,
814 IN PLARGE_INTEGER Length
,
816 IN PFILE_OBJECT FileObject
,
817 IN PEPROCESS Process
)
819 /* Call the internal API */
820 return FsRtlpCheckLockForReadOrWriteAccess(FileLock
,
834 FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock
,
835 IN PFILE_OBJECT FileObject
,
836 IN PLARGE_INTEGER FileOffset
,
837 IN PLARGE_INTEGER Length
,
838 IN PEPROCESS Process
,
840 IN PVOID Context OPTIONAL
,
841 IN BOOLEAN AlreadySynchronized
)
843 /* Call the internal API */
844 return FsRtlpUnlockSingle(FileLock
,
859 FsRtlFastUnlockAll(IN PFILE_LOCK FileLock
,
860 IN PFILE_OBJECT FileObject
,
861 IN PEPROCESS Process
,
862 IN PVOID Context OPTIONAL
)
864 /* Call the generic function by process */
865 return FsRtlpFastUnlockAllByKey(FileLock
,
878 FsRtlFastUnlockAllByKey(IN PFILE_LOCK FileLock
,
879 IN PFILE_OBJECT FileObject
,
880 IN PEPROCESS Process
,
882 IN PVOID Context OPTIONAL
)
884 /* Call the generic function by key */
885 return FsRtlpFastUnlockAllByKey(FileLock
,
898 FsRtlProcessFileLock(IN PFILE_LOCK FileLock
,
900 IN PVOID Context OPTIONAL
)
902 PIO_STACK_LOCATION IoStackLocation
;
904 IO_STATUS_BLOCK IoStatusBlock
;
906 /* Get the I/O Stack location */
907 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
908 ASSERT(IoStackLocation
->MajorFunction
== IRP_MJ_LOCK_CONTROL
);
910 /* Clear the I/O status block and check what function this is */
911 IoStatusBlock
.Information
= 0;
912 switch(IoStackLocation
->MinorFunction
)
917 /* Call the private lock routine */
918 FsRtlPrivateLock(FileLock
,
919 IoStackLocation
->FileObject
,
921 Parameters
.LockControl
.ByteOffset
,
922 IoStackLocation
->Parameters
.LockControl
.Length
,
923 IoGetRequestorProcess(Irp
),
924 IoStackLocation
->Parameters
.LockControl
.Key
,
925 IoStackLocation
->Flags
& SL_FAIL_IMMEDIATELY
,
926 IoStackLocation
->Flags
& SL_EXCLUSIVE_LOCK
,
933 /* A single unlock */
934 case IRP_MN_UNLOCK_SINGLE
:
936 /* Call fast unlock */
937 IoStatusBlock
.Status
=
938 FsRtlFastUnlockSingle(FileLock
,
939 IoStackLocation
->FileObject
,
940 &IoStackLocation
->Parameters
.LockControl
.
942 IoStackLocation
->Parameters
.LockControl
.
944 IoGetRequestorProcess(Irp
),
945 IoStackLocation
->Parameters
.LockControl
.
950 /* Complete the IRP */
951 FsRtlCompleteLockIrpReal(FileLock
->CompleteLockIrpRoutine
,
954 IoStatusBlock
.Status
,
960 case IRP_MN_UNLOCK_ALL
:
962 /* Do a fast unlock */
963 IoStatusBlock
.Status
= FsRtlFastUnlockAll(FileLock
,
966 IoGetRequestorProcess(Irp
),
969 /* Complete the IRP */
970 FsRtlCompleteLockIrpReal(FileLock
->CompleteLockIrpRoutine
,
973 IoStatusBlock
.Status
,
979 case IRP_MN_UNLOCK_ALL_BY_KEY
:
982 IoStatusBlock
.Status
=
983 FsRtlFastUnlockAllByKey(FileLock
,
984 IoStackLocation
->FileObject
,
985 IoGetRequestorProcess(Irp
),
986 IoStackLocation
->Parameters
.
990 /* Complete the IRP */
991 FsRtlCompleteLockIrpReal(FileLock
->CompleteLockIrpRoutine
,
994 IoStatusBlock
.Status
,
999 /* Invalid request */
1003 FsRtlCompleteRequest(Irp
, STATUS_INVALID_DEVICE_REQUEST
);
1004 IoStatusBlock
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1008 /* Return the status */
1009 return IoStatusBlock
.Status
;
1017 FsRtlInitializeFileLock (IN PFILE_LOCK FileLock
,
1018 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1019 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
)
1021 /* Setup the lock */
1022 FileLock
->FastIoIsQuestionable
= FALSE
;
1023 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
1024 FileLock
->UnlockRoutine
= UnlockRoutine
;
1025 FileLock
->LockInformation
= NULL
;
1033 FsRtlUninitializeFileLock(IN PFILE_LOCK FileLock
)
1035 PFILE_LOCK_TOC LockToc
;
1037 PFILE_LOCK_GRANTED Granted
;
1038 PLIST_ENTRY EnumEntry
;
1041 /* Get the lock information */
1042 LockToc
= FileLock
->LockInformation
;
1043 if (!FileLock
->LockInformation
) return;
1045 /* Acquire the lock queue */
1046 KeAcquireSpinLock(&LockToc
->SpinLock
, &OldIrql
);
1048 /* Loop the lock tree */
1049 while (!IsListEmpty(&LockToc
->GrantedListHead
))
1052 EnumEntry
= RemoveTailList(&LockToc
->GrantedListHead
);
1054 /* Get the granted lock and free it */
1055 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
1056 ExFreeToNPagedLookasideList(&GrantedLookaside
, Granted
);
1059 /* Loop the waiting locks */
1060 while (!IsListEmpty(&LockToc
->PendingListHead
))
1062 /* Get the entry and IRP */
1063 EnumEntry
= RemoveTailList(&LockToc
->PendingListHead
);
1064 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1066 /* Release the lock */
1067 KeReleaseSpinLock(&LockToc
->SpinLock
, OldIrql
);
1069 /* Acquire cancel spinlock and clear the cancel routine */
1070 IoAcquireCancelSpinLock(&Irp
->CancelIrql
);
1071 (void)IoSetCancelRoutine(Irp
, NULL
);
1072 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1074 /* Complete the IRP */
1075 Irp
->IoStatus
.Information
= 0;
1076 Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1077 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1079 /* Acquire the lock again */
1080 KeAcquireSpinLock(&LockToc
->SpinLock
, &OldIrql
);
1083 /* Release the lock and free it */
1084 KeReleaseSpinLock(&LockToc
->SpinLock
, OldIrql
);
1085 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1087 /* Remove the lock information pointer */
1088 FileLock
->LockInformation
= NULL
;
1096 FsRtlAllocateFileLock(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1097 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
)
1099 PFILE_LOCK FileLock
;
1101 /* Try to allocate it */
1102 FileLock
= ExAllocateFromPagedLookasideList(&LockLookaside
);
1106 FsRtlInitializeFileLock(FileLock
,
1107 CompleteLockIrpRoutine
,
1111 /* Return the lock */
1120 FsRtlFreeFileLock(IN PFILE_LOCK FileLock
)
1122 /* Uninitialize and free the lock */
1123 FsRtlUninitializeFileLock(FileLock
);
1124 ExFreeToPagedLookasideList(&LockLookaside
, FileLock
);