1 /* $Id: filelock.c,v 1.6 2002/11/13 06:01:11 robd Exp $
3 * reactos/ntoskrnl/fs/filelock.c
7 #include <internal/ifs.h>
11 #include <internal/debug.h>
13 //#define TAG_LOCK TAG('F','l','c','k')
17 I'm not using resource syncronization here, since
18 FsRtlFastCheckLockForRead/FsRtlFastCheckLockForWrite
19 can be running at any IRQL. Therefore I also have used
20 nonpaged memory for the lists.
23 #define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
24 #define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1)
25 #define REQUEST_START_OFF (FileOffset->QuadPart)
26 #define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
28 FAST_MUTEX LockTocMutex
;
29 NPAGED_LOOKASIDE_LIST PendingLookaside
;
30 NPAGED_LOOKASIDE_LIST GrantedLookaside
;
31 NPAGED_LOOKASIDE_LIST LockTocLookaside
;
33 /**********************************************************************
35 * FsRtlpInitFileLockingImplementation
40 FsRtlpInitFileLockingImplementation(VOID
)
42 ExInitializeNPagedLookasideList( &LockTocLookaside
,
46 sizeof(FILE_LOCK_TOC
),
51 ExInitializeNPagedLookasideList( &GrantedLookaside
,
55 sizeof(FILE_LOCK_GRANTED
),
60 ExInitializeNPagedLookasideList( &PendingLookaside
,
64 sizeof(FILE_LOCK_PENDING
),
69 ExInitializeFastMutex(&LockTocMutex
);
73 /**********************************************************************
75 * FsRtlpPendingFileLockCancelRoutine
80 FsRtlpPendingFileLockCancelRoutine(
81 IN PDEVICE_OBJECT DeviceObject
,
87 PFILE_LOCK_TOC LockToc
;
88 PFILE_LOCK_PENDING Pending
;
89 PLIST_ENTRY EnumEntry
;
91 IoReleaseCancelSpinLock(Irp
->CancelIrql
); //don't need this for private queue cancelation
93 FileLock
= (PVOID
)Irp
->IoStatus
.Information
;
95 LockToc
= FileLock
->LockInformation
;
99 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldIrql
);
101 EnumEntry
= LockToc
->PendingListHead
.Flink
;
102 while (EnumEntry
!= &LockToc
->PendingListHead
) {
103 Pending
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_PENDING
, ListEntry
);
105 if (Pending
->Irp
== Irp
){
106 RemoveEntryList(&Pending
->ListEntry
);
107 KeReleaseSpinLock(&LockToc
->SpinLock
, oldIrql
);
108 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
110 if (FileLock
->CompleteLockIrpRoutine
)
111 FileLock
->CompleteLockIrpRoutine(Pending
->Context
,Irp
);
113 IofCompleteRequest(Irp
,IO_NO_INCREMENT
);
115 ExFreeToNPagedLookasideList(&PendingLookaside
,Pending
);
118 EnumEntry
= EnumEntry
->Flink
;
122 didn't find irp in list, so someone else must have completed it
123 while we were waiting for the spinlock
125 KeReleaseSpinLock(&LockToc
->SpinLock
, oldIrql
);
133 /**********************************************************************
135 * FsRtlpCheckLockForReadOrWriteAccess
140 FsRtlpCheckLockForReadOrWriteAccess(
141 IN PFILE_LOCK FileLock
,
142 IN PLARGE_INTEGER FileOffset
,
143 IN PLARGE_INTEGER Length
,
145 IN PFILE_OBJECT FileObject
,
146 IN PEPROCESS Process
,
151 PFILE_LOCK_TOC LockToc
;
152 PFILE_LOCK_GRANTED Granted
;
153 PLIST_ENTRY EnumEntry
;
156 LockToc
= FileLock
->LockInformation
;
158 if (LockToc
== NULL
|| Length
->QuadPart
== 0) {
162 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
164 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
165 while ( EnumEntry
!= &LockToc
->GrantedListHead
){
167 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
169 if(!(REQUEST_START_OFF
> LOCK_END_OFF(Granted
->Lock
) ||
170 REQUEST_END_OFF
< LOCK_START_OFF(Granted
->Lock
))) {
172 //No read conflict if (shared lock) OR (exclusive + our lock)
173 //No write conflict if exclusive lock AND our lock
174 if ((Read
&& !Granted
->Lock
.ExclusiveLock
) ||
175 (Granted
->Lock
.ExclusiveLock
&&
176 Granted
->Lock
.Process
== Process
&&
177 Granted
->Lock
.FileObject
== FileObject
&&
178 Granted
->Lock
.Key
== Key
) ) {
180 //AND if lock surround read region, stop searching and grant
181 if (REQUEST_START_OFF
>= LOCK_START_OFF(Granted
->Lock
) &&
182 REQUEST_END_OFF
<= LOCK_END_OFF(Granted
->Lock
)){
184 EnumEntry
= &LockToc
->GrantedListHead
;//success
187 //else continue searching for conflicts
192 EnumEntry
= EnumEntry
->Flink
;
195 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
197 if (EnumEntry
== &LockToc
->GrantedListHead
) { //no conflict
205 /**********************************************************************
207 * FsRtlCheckLockForReadAccess
212 FsRtlCheckLockForReadAccess (
213 IN PFILE_LOCK FileLock
,
217 PIO_STACK_LOCATION Stack
;
218 LARGE_INTEGER LocalLength
;
220 Stack
= IoGetCurrentIrpStackLocation(Irp
);
222 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
223 LocalLength
.u
.HighPart
= 0;
225 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
226 &Stack
->Parameters
.Read
.ByteOffset
,
228 Stack
->Parameters
.Read
.Key
,
230 IoGetRequestorProcess(Irp
),
236 /**********************************************************************
238 * FsRtlCheckLockForWriteAccess
243 FsRtlCheckLockForWriteAccess (
244 IN PFILE_LOCK FileLock
,
248 PIO_STACK_LOCATION Stack
;
249 LARGE_INTEGER LocalLength
;
251 Stack
= IoGetCurrentIrpStackLocation(Irp
);
253 LocalLength
.u
.LowPart
= Stack
->Parameters
.Read
.Length
;
254 LocalLength
.u
.HighPart
= 0;
256 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
257 &Stack
->Parameters
.Write
.ByteOffset
,
259 Stack
->Parameters
.Write
.Key
,
261 IoGetRequestorProcess(Irp
),
270 /**********************************************************************
272 * FsRtlFastCheckLockForRead
277 FsRtlFastCheckLockForRead (
278 IN PFILE_LOCK FileLock
,
279 IN PLARGE_INTEGER FileOffset
,
280 IN PLARGE_INTEGER Length
,
282 IN PFILE_OBJECT FileObject
,
286 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
297 /**********************************************************************
299 * FsRtlFastCheckLockForWrite
304 FsRtlFastCheckLockForWrite (
305 IN PFILE_LOCK FileLock
,
306 IN PLARGE_INTEGER FileOffset
,
307 IN PLARGE_INTEGER Length
,
309 IN PFILE_OBJECT FileObject
,
313 return FsRtlpCheckLockForReadOrWriteAccess( FileLock
,
325 /**********************************************************************
327 * FsRtlpFastUnlockAllByKey
332 FsRtlpFastUnlockAllByKey(
333 IN PFILE_LOCK FileLock
,
334 IN PFILE_OBJECT FileObject
,
335 IN PEPROCESS Process
,
336 IN DWORD Key
, /* FIXME: guess */
337 IN BOOLEAN UseKey
, /* FIXME: guess */
338 IN PVOID Context OPTIONAL
342 PFILE_LOCK_TOC LockToc
;
343 PLIST_ENTRY EnumEntry
;
344 PFILE_LOCK_GRANTED Granted
;
345 BOOLEAN Unlock
= FALSE
;
346 //must make local copy since FILE_LOCK struct is allowed to be paged
347 BOOLEAN GotUnlockRoutine
;
350 LockToc
= FileLock
->LockInformation
;
353 return STATUS_RANGE_NOT_LOCKED
;
355 GotUnlockRoutine
= FileLock
->UnlockRoutine
? TRUE
: FALSE
;
356 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
358 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
359 while ( EnumEntry
!= &LockToc
->GrantedListHead
) {
361 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
362 EnumEntry
= EnumEntry
->Flink
;
364 if (Granted
->Lock
.Process
== Process
&&
365 Granted
->Lock
.FileObject
== FileObject
&&
366 (!UseKey
|| (UseKey
&& Granted
->Lock
.Key
== Key
)) ){
368 RemoveEntryList(&Granted
->ListEntry
);
371 if (GotUnlockRoutine
) {
372 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
373 FileLock
->UnlockRoutine(Context
,&Granted
->Lock
);
374 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
375 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
376 EnumEntry
= LockToc
->GrantedListHead
.Flink
; //restart
380 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
385 FsRtlpTryCompletePendingLocks(FileLock
,LockToc
,NULL
);
388 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
391 if (IsListEmpty(&LockToc
->GrantedListHead
))
392 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
394 return STATUS_SUCCESS
;
397 return STATUS_RANGE_NOT_LOCKED
;
400 /**********************************************************************
407 FsRtlFastUnlockAll
/*ByProcess*/ (
408 IN PFILE_LOCK FileLock
,
409 IN PFILE_OBJECT FileObject
,
410 IN PEPROCESS Process
,
411 IN PVOID Context OPTIONAL
414 return FsRtlpFastUnlockAllByKey ( FileLock
,
418 FALSE
, /* Do NOT use Key */
423 /**********************************************************************
425 * FsRtlFastUnlockAllByKey
430 FsRtlFastUnlockAllByKey (
431 IN PFILE_LOCK FileLock
,
432 IN PFILE_OBJECT FileObject
,
433 IN PEPROCESS Process
,
435 IN PVOID Context OPTIONAL
438 return FsRtlpFastUnlockAllByKey(FileLock
,
448 /**********************************************************************
453 * Spinlock held at entry !!
458 IN PFILE_LOCK_TOC LockToc
,
459 IN PFILE_OBJECT FileObject
,
460 IN PLARGE_INTEGER FileOffset
,
461 IN PLARGE_INTEGER Length
,
462 IN PEPROCESS Process
,
464 IN BOOLEAN ExclusiveLock
467 PLIST_ENTRY EnumEntry
;
468 PFILE_LOCK_GRANTED Granted
;
470 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
471 while (EnumEntry
!= &LockToc
->GrantedListHead
) {
473 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
475 if(!(REQUEST_START_OFF
> LOCK_END_OFF(Granted
->Lock
) ||
476 REQUEST_END_OFF
< LOCK_START_OFF(Granted
->Lock
))) {
478 //never conflict if shared lock and we want to add a shared lock
479 if (!Granted
->Lock
.ExclusiveLock
&&
482 //AND if lock surround region, stop searching and insert lock
483 if (REQUEST_START_OFF
>= LOCK_START_OFF(Granted
->Lock
) &&
484 REQUEST_END_OFF
<= LOCK_END_OFF(Granted
->Lock
)){
486 EnumEntry
= &LockToc
->GrantedListHead
;
489 //else keep locking for conflicts
491 else //conflict if we want share access to excl. lock OR exlc. access to shared lock
495 EnumEntry
= EnumEntry
->Flink
;
498 if (EnumEntry
== &LockToc
->GrantedListHead
) {//no conflict
500 Granted
= ExAllocateFromNPagedLookasideList(&GrantedLookaside
);
502 Granted
->Lock
.StartingByte
= *FileOffset
;
503 Granted
->Lock
.Length
= *Length
;
504 Granted
->Lock
.ExclusiveLock
= ExclusiveLock
;
505 Granted
->Lock
.Key
= Key
;
506 Granted
->Lock
.FileObject
= FileObject
;
507 Granted
->Lock
.Process
= Process
;
508 Granted
->Lock
.EndingByte
.QuadPart
= REQUEST_END_OFF
;
510 InsertHeadList(&LockToc
->GrantedListHead
,&Granted
->ListEntry
);
520 /**********************************************************************
522 * FsRtlpTryCompletePendingLocks
525 * Spinlock held at entry !!
529 FsRtlpTryCompletePendingLocks(
530 IN PFILE_LOCK FileLock
,
531 IN PFILE_LOCK_TOC LockToc
,
532 IN OUT PKIRQL oldirql
535 //walk pending list, FIFO order, try 2 complete locks
536 PLIST_ENTRY EnumEntry
;
537 PFILE_LOCK_PENDING Pending
;
538 PIO_STACK_LOCATION Stack
;
540 EnumEntry
= LockToc
->PendingListHead
.Blink
;
541 while (EnumEntry
!= &LockToc
->PendingListHead
) {
543 Pending
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_PENDING
,ListEntry
);
545 Stack
= IoGetCurrentIrpStackLocation(Pending
->Irp
);
547 if (FsRtlpAddLock( LockToc
,
548 Stack
->FileObject
,//correct?
549 &Stack
->Parameters
.LockControl
.ByteOffset
,
550 Stack
->Parameters
.LockControl
.Length
,
551 IoGetRequestorProcess(Pending
->Irp
),
552 Stack
->Parameters
.LockControl
.Key
,
553 Stack
->Flags
& SL_EXCLUSIVE_LOCK
556 RemoveEntryList(&Pending
->ListEntry
);
558 IoSetCancelRoutine(Pending
->Irp
, NULL
);
560 Irp could be cancelled and the cancel routine may or may not have been called,
561 waiting there for our spinlock.
562 But it doesn't matter because it will not find the IRP in the list.
564 KeReleaseSpinLock(&LockToc
->SpinLock
, *oldirql
);//fires cancel routine
565 Pending
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
567 if (FileLock
->CompleteLockIrpRoutine
)
568 FileLock
->CompleteLockIrpRoutine(Pending
->Context
,Pending
->Irp
);
570 IofCompleteRequest(Pending
->Irp
, IO_NO_INCREMENT
);
572 ExFreeToNPagedLookasideList(&PendingLookaside
,Pending
);
573 KeAcquireSpinLock(&LockToc
->SpinLock
, oldirql
);
574 //restart, something migth have happend to our list
575 EnumEntry
= LockToc
->PendingListHead
.Blink
;
578 EnumEntry
= EnumEntry
->Blink
;
584 /**********************************************************************
592 IN PFILE_LOCK FileLock
,
593 IN PFILE_OBJECT FileObject
,
594 IN PLARGE_INTEGER FileOffset
,
595 IN PLARGE_INTEGER Length
,
596 IN PEPROCESS Process
,
598 IN PVOID Context OPTIONAL
,
599 IN BOOLEAN AlreadySynchronized
,
600 IN BOOLEAN CallUnlockRoutine
604 PFILE_LOCK_TOC LockToc
;
605 PFILE_LOCK_GRANTED Granted
;
606 PLIST_ENTRY EnumEntry
;
609 LockToc
= FileLock
->LockInformation
;
612 return STATUS_RANGE_NOT_LOCKED
;
614 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
616 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
617 while (EnumEntry
!= &LockToc
->GrantedListHead
) {
619 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
621 //must be exact match
622 if (FileOffset
->QuadPart
== Granted
->Lock
.StartingByte
.QuadPart
&&
623 Length
->QuadPart
== Granted
->Lock
.Length
.QuadPart
&&
624 Granted
->Lock
.Process
== Process
&&
625 Granted
->Lock
.FileObject
== FileObject
&&
626 Granted
->Lock
.Key
== Key
) {
628 RemoveEntryList(&Granted
->ListEntry
);
630 FsRtlpTryCompletePendingLocks(FileLock
, LockToc
,NULL
);
632 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
634 if (FileLock
->UnlockRoutine
&& CallUnlockRoutine
)
635 FileLock
->UnlockRoutine(Context
,&Granted
->Lock
);
637 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
639 if (IsListEmpty(&LockToc
->GrantedListHead
))
640 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
642 return STATUS_SUCCESS
;
645 EnumEntry
= EnumEntry
->Flink
;
648 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
650 return STATUS_RANGE_NOT_LOCKED
;
656 /**********************************************************************
658 * FsRtlFastUnlockSingle
663 FsRtlFastUnlockSingle (
664 IN PFILE_LOCK FileLock
,
665 IN PFILE_OBJECT FileObject
,
666 IN PLARGE_INTEGER FileOffset
,
667 IN PLARGE_INTEGER Length
,
668 IN PEPROCESS Process
,
670 IN PVOID Context OPTIONAL
,
671 IN BOOLEAN AlreadySynchronized
674 return FsRtlpUnlockSingle( FileLock
,
682 TRUE
//CallUnlockRoutine
686 /**********************************************************************
688 * FsRtlpDumpFileLocks
694 IN PFILE_LOCK FileLock
699 PFILE_LOCK_TOC LockToc
;
700 PFILE_LOCK_GRANTED Granted
;
701 PFILE_LOCK_PENDING Pending
;
702 PLIST_ENTRY EnumEntry
;
703 PIO_STACK_LOCATION Stack
;
706 LockToc
= FileLock
->LockInformation
;
708 if (LockToc
== NULL
) {
709 DPRINT1("No file locks\n");
713 DPRINT1("Dumping granted file locks, FIFO order\n");
715 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
717 EnumEntry
= LockToc
->GrantedListHead
.Blink
;
718 while ( EnumEntry
!= &LockToc
->GrantedListHead
){
720 Granted
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_GRANTED
, ListEntry
);
722 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
723 Granted
->Lock
.ExclusiveLock
? "EXCL" : "SHRD",
724 Granted
->Lock
.StartingByte
.QuadPart
,
725 Granted
->Lock
.Length
.QuadPart
,
726 Granted
->Lock
.EndingByte
.QuadPart
,
728 Granted
->Lock
.Process
,
729 Granted
->Lock
.FileObject
732 EnumEntry
= EnumEntry
->Blink
;
735 DPRINT1("Dumping pending file locks, FIFO order\n");
737 EnumEntry
= LockToc
->PendingListHead
.Blink
;
738 while ( EnumEntry
!= &LockToc
->PendingListHead
){
740 Pending
= CONTAINING_RECORD(EnumEntry
, FILE_LOCK_PENDING
, ListEntry
);
742 Stack
= IoGetCurrentIrpStackLocation(Pending
->Irp
);
744 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
745 (Stack
->Flags
& SL_EXCLUSIVE_LOCK
) ? "EXCL" : "SHRD",
746 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
,
747 Stack
->Parameters
.LockControl
.Length
->QuadPart
,
748 Stack
->Parameters
.LockControl
.ByteOffset
.QuadPart
+ Stack
->Parameters
.LockControl
.Length
->QuadPart
- 1,
749 Stack
->Parameters
.LockControl
.Key
,
750 IoGetRequestorProcess(Pending
->Irp
),
754 EnumEntry
= EnumEntry
->Blink
;
757 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);
762 /**********************************************************************
764 * FsRtlGetNextFileLock
767 * NULL if no more locks.
772 FsRtlGetNextFileLock (
773 IN PFILE_LOCK FileLock
,
778 Messy enumeration of granted locks.
779 What our last ptr. in LastReturnedLock points at, might have been free between
780 calls, so we have to scan thru the list every time, searching for our last lock.
781 If it's not there anymore, restart the enumeration...
784 PLIST_ENTRY EnumEntry
;
785 PFILE_LOCK_GRANTED Granted
;
786 PFILE_LOCK_TOC LockToc
;
787 BOOLEAN FoundPrevious
= FALSE
;
788 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
789 FILE_LOCK_INFO LocalLastReturnedLockInfo
;
790 PVOID LocalLastReturnedLock
;
793 LockToc
= FileLock
->LockInformation
;
797 LocalLastReturnedLock
= FileLock
->LastReturnedLock
;
799 KeAcquireSpinLock(&LockToc
->SpinLock
,&oldirql
);
803 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
806 if (EnumEntry
!= &LockToc
->GrantedListHead
){
807 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
808 LocalLastReturnedLockInfo
= Granted
->Lock
;
809 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
811 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
812 FileLock
->LastReturnedLock
= EnumEntry
;
813 return &FileLock
->LastReturnedLockInfo
;
816 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
821 //else: continue enum
822 while (EnumEntry
!= &LockToc
->GrantedListHead
) {
824 //found previous lock?
825 if (EnumEntry
== LocalLastReturnedLock
) {
826 FoundPrevious
= TRUE
;
828 EnumEntry
= EnumEntry
->Flink
;
829 if (EnumEntry
!= &LockToc
->GrantedListHead
){
830 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
,ListEntry
);
831 LocalLastReturnedLockInfo
= Granted
->Lock
;
832 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
834 FileLock
->LastReturnedLockInfo
= LocalLastReturnedLockInfo
;
835 FileLock
->LastReturnedLock
= EnumEntry
;
836 return &FileLock
->LastReturnedLockInfo
;
840 EnumEntry
= EnumEntry
->Flink
;
843 if (!FoundPrevious
) {
844 //got here? uh no, didn't find our last lock..must have been freed...restart
849 KeReleaseSpinLock(&LockToc
->SpinLock
,oldirql
);
851 return NULL
;//no (more) locks
855 /**********************************************************************
857 * FsRtlInitializeFileLock
860 * Called when creating/allocating/initializing FCB
865 FsRtlInitializeFileLock (
866 IN PFILE_LOCK FileLock
,
867 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
868 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
872 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
873 FileLock
->CompleteLockIrpRoutine
= CompleteLockIrpRoutine
;
874 FileLock
->UnlockRoutine
= UnlockRoutine
;
875 FileLock
->LockInformation
= NULL
;
880 /**********************************************************************
888 IN PFILE_LOCK FileLock
,
889 IN PFILE_OBJECT FileObject
,
890 IN PLARGE_INTEGER FileOffset
,
891 IN PLARGE_INTEGER Length
,
892 IN PEPROCESS Process
,
894 IN BOOLEAN FailImmediately
, //meaningless for fast io
895 IN BOOLEAN ExclusiveLock
,
896 OUT PIO_STATUS_BLOCK IoStatus
,
897 IN PIRP Irp OPTIONAL
,
899 IN BOOLEAN AlreadySynchronized
902 PFILE_LOCK_TOC LockToc
;
904 PFILE_LOCK_PENDING Pending
;
907 if (FileLock
->LockInformation
== NULL
) {
908 ExAcquireFastMutex(&LockTocMutex
);
910 if (FileLock
->LockInformation
== NULL
){
911 FileLock
->LockInformation
= ExAllocateFromNPagedLookasideList(&LockTocLookaside
);
912 LockToc
= FileLock
->LockInformation
;
913 KeInitializeSpinLock(&LockToc
->SpinLock
);
914 InitializeListHead(&LockToc
->PendingListHead
);
915 InitializeListHead(&LockToc
->GrantedListHead
);
917 ExReleaseFastMutex(&LockTocMutex
);
920 LockToc
= FileLock
->LockInformation
;
921 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
924 if (FsRtlpAddLock( LockToc
,
933 IoStatus
->Status
= STATUS_SUCCESS
;
935 else if (Irp
&& !FailImmediately
) { //failed + irp + no fail = mk. pending
937 Irp
->IoStatus
.Information
= (DWORD
)FileLock
;//for our cancel routine
938 IoSetCancelRoutine(Irp
, FsRtlpPendingFileLockCancelRoutine
);
941 IoSetCancelRoutine(Irp
, NULL
);
943 Irp was canceled and the cancel routine may or may not have been called,
944 waiting there for our spinlock.
945 But it doesn't matter since it will not find the IRP in the list.
947 IoStatus
->Status
= STATUS_CANCELLED
;
949 else { //not cancelled: queue irp
950 IoMarkIrpPending(Irp
);
951 Pending
= ExAllocateFromNPagedLookasideList(&PendingLookaside
);
952 Pending
->Context
= Context
;
954 IoStatus
->Status
= STATUS_PENDING
;
955 InsertHeadList(&LockToc
->PendingListHead
,&Pending
->ListEntry
);
960 IoStatus
->Status
= STATUS_LOCK_NOT_GRANTED
;
963 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
); //fires cancel routine
965 assert(!(IoStatus
->Status
== STATUS_PENDING
&& !Irp
));
967 if (IoStatus
->Status
== STATUS_SUCCESS
)
968 FsRtlAreThereCurrentFileLocks(FileLock
) = TRUE
;
970 Irp
->IoStatus
.Status
= IoStatus
->Status
;
972 if (Irp
&& (IoStatus
->Status
!= STATUS_PENDING
)) {
974 if (FileLock
->CompleteLockIrpRoutine
) { //complete irp routine
976 if (!NT_SUCCESS(FileLock
->CompleteLockIrpRoutine(Context
,Irp
))) {
977 //CompleteLockIrpRoutine complain: revert changes
978 FsRtlpUnlockSingle( FileLock
,
986 FALSE
//CallUnlockRoutine
990 else {//std irp completion
991 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
995 //NOTE: only fast io care about this return value
996 if (IoStatus
->Status
== STATUS_SUCCESS
|| FailImmediately
)
1005 /**********************************************************************
1007 * FsRtlProcessFileLock
1012 FsRtlProcessFileLock (
1013 IN PFILE_LOCK FileLock
,
1015 IN PVOID Context OPTIONAL
1018 PIO_STACK_LOCATION Stack
;
1020 IO_STATUS_BLOCK LocalIoStatus
;
1023 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1025 switch(Stack
->MinorFunction
){
1029 FsRtlPrivateLock( FileLock
,
1031 &Stack
->Parameters
.LockControl
.ByteOffset
, //not pointer!
1032 Stack
->Parameters
.LockControl
.Length
,
1033 IoGetRequestorProcess(Irp
),
1034 Stack
->Parameters
.LockControl
.Key
,
1035 Stack
->Flags
& SL_FAIL_IMMEDIATELY
,
1036 Stack
->Flags
& SL_EXCLUSIVE_LOCK
,
1042 return LocalIoStatus
.Status
;
1044 case IRP_MN_UNLOCK_SINGLE
:
1045 Status
= FsRtlFastUnlockSingle (FileLock
,
1047 &Stack
->Parameters
.LockControl
.ByteOffset
,
1048 Stack
->Parameters
.LockControl
.Length
,
1049 IoGetRequestorProcess(Irp
),
1050 Stack
->Parameters
.LockControl
.Key
,
1055 case IRP_MN_UNLOCK_ALL
:
1056 Status
= FsRtlFastUnlockAll(FileLock
,
1058 IoGetRequestorProcess(Irp
),
1062 case IRP_MN_UNLOCK_ALL_BY_KEY
:
1063 Status
= FsRtlFastUnlockAllByKey ( FileLock
,
1065 IoGetRequestorProcess(Irp
),
1066 Stack
->Parameters
.LockControl
.Key
,
1072 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
1073 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
1077 Irp
->IoStatus
.Status
= Status
;
1079 if (FileLock
->CompleteLockIrpRoutine
)
1080 FileLock
->CompleteLockIrpRoutine(Context
,Irp
);
1082 IofCompleteRequest(Irp
,IO_NO_INCREMENT
);
1088 /**********************************************************************
1090 * FsRtlUninitializeFileLock
1095 FsRtlUninitializeFileLock (
1096 IN PFILE_LOCK FileLock
1099 PFILE_LOCK_TOC LockToc
;
1100 PFILE_LOCK_PENDING Pending
;
1101 PFILE_LOCK_GRANTED Granted
;
1102 PLIST_ENTRY EnumEntry
;
1106 if (FileLock
->LockInformation
== NULL
)
1109 LockToc
= FileLock
->LockInformation
;
1111 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1113 //unlock and free granted locks
1114 EnumEntry
= LockToc
->GrantedListHead
.Flink
;
1115 while (EnumEntry
!= &LockToc
->GrantedListHead
) {
1117 Granted
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_GRANTED
, ListEntry
);
1118 EnumEntry
= EnumEntry
->Flink
;
1120 RemoveEntryList(&Granted
->ListEntry
);
1121 ExFreeToNPagedLookasideList(&GrantedLookaside
,Granted
);
1124 //complete pending locks
1125 EnumEntry
= LockToc
->PendingListHead
.Flink
;
1126 while (EnumEntry
!= &LockToc
->PendingListHead
) {
1128 Pending
= CONTAINING_RECORD(EnumEntry
,FILE_LOCK_PENDING
, ListEntry
);
1129 RemoveEntryList(&Pending
->ListEntry
);
1131 IoSetCancelRoutine(Pending
->Irp
, NULL
);
1133 Irp could be cancelled and the cancel routine may or may not have been called,
1134 waiting there for our spinlock.
1135 But it doesn't matter because it will not find the IRP in the list.
1137 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
);//fires cancel routine
1139 Pending
->Irp
->IoStatus
.Status
= STATUS_RANGE_NOT_LOCKED
;
1141 if (FileLock
->CompleteLockIrpRoutine
)
1142 FileLock
->CompleteLockIrpRoutine(Pending
->Context
,Pending
->Irp
);
1144 IofCompleteRequest(Pending
->Irp
, IO_NO_INCREMENT
);
1146 ExFreeToNPagedLookasideList(&PendingLookaside
,Pending
);
1148 KeAcquireSpinLock(&LockToc
->SpinLock
, &oldirql
);
1149 //restart, something migth have happend to our list
1150 EnumEntry
= LockToc
->PendingListHead
.Flink
;
1153 KeReleaseSpinLock(&LockToc
->SpinLock
, oldirql
) ;
1155 FsRtlAreThereCurrentFileLocks(FileLock
) = FALSE
;
1156 FileLock
->LockInformation
= NULL
;
1158 ExFreeToNPagedLookasideList(&LockTocLookaside
, LockToc
);
1163 /**********************************************************************
1165 * FsRtlAllocateFileLock
1168 * Only present in NT 5.0 or later.
1169 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1174 FsRtlAllocateFileLock (
1175 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL
,
1176 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1179 PFILE_LOCK FileLock
;
1181 FileLock
= ExAllocatePoolWithTag(PagedPool
,sizeof(FILE_LOCK
),IFS_POOL_TAG
);
1183 FsRtlInitializeFileLock( FileLock
,
1184 CompleteLockIrpRoutine
,
1191 /**********************************************************************
1196 * Only present in NT 5.0 or later.
1197 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1203 IN PFILE_LOCK FileLock
1207 FsRtlUninitializeFileLock(FileLock
);
1208 ExFreePool(FileLock
);