3 * reactos/ntoskrnl/fs/filelock.c
7 #include <internal/ifs.h>
12 #include <internal/debug.h>
16 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
17 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
21 #define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
22 #define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1)
23 #define REQUEST_START_OFF (FileOffset->QuadPart)
24 #define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
26 FAST_MUTEX LockTocMutex;
27 NPAGED_LOOKASIDE_LIST GrantedLookaside;
28 NPAGED_LOOKASIDE_LIST LockTocLookaside;
29 PAGED_LOOKASIDE_LIST LockLookaside;
31 /**********************************************************************
33 * FsRtlpInitFileLockingImplementation
38 FsRtlpInitFileLockingImplementation(VOID)
40 ExInitializeNPagedLookasideList( &LockTocLookaside,
44 sizeof(FILE_LOCK_TOC),
49 ExInitializeNPagedLookasideList( &GrantedLookaside,
53 sizeof(FILE_LOCK_GRANTED),
58 ExInitializePagedLookasideList( &LockLookaside,
67 ExInitializeFastMutex(&LockTocMutex);
70 /**********************************************************************
72 * FsRtlpFileLockCancelRoutine
77 FsRtlpFileLockCancelRoutine(
78 IN PDEVICE_OBJECT DeviceObject,
84 PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine;
86 //don't need this since we have our own sync. protecting irp cancellation
87 IoReleaseCancelSpinLock(Irp->CancelIrql);
89 SpinLock = &((PFILE_LOCK_TOC)Irp->Tail.Overlay.DriverContext[1])->SpinLock;
91 KeAcquireSpinLock(SpinLock, &oldIrql);
92 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
93 KeReleaseSpinLock(SpinLock, oldIrql);
95 Irp->IoStatus.Status = STATUS_CANCELLED;
97 CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine;
98 if (CompleteLockIrpRoutine)
100 CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
104 IofCompleteRequest(Irp, IO_NO_INCREMENT);
109 /**********************************************************************
111 * FsRtlpCheckLockForReadOrWriteAccess
116 FsRtlpCheckLockForReadOrWriteAccess(
117 IN PFILE_LOCK FileLock,
118 IN PLARGE_INTEGER FileOffset,
119 IN PLARGE_INTEGER Length,
121 IN PFILE_OBJECT FileObject,
122 IN PEPROCESS Process,
127 PFILE_LOCK_TOC LockToc;
128 PFILE_LOCK_GRANTED Granted;
129 PLIST_ENTRY EnumEntry;
132 LockToc = FileLock->LockInformation;
134 if (LockToc == NULL || Length->QuadPart == 0)
139 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
141 EnumEntry = LockToc->GrantedListHead.Flink;
142 while ( EnumEntry != &LockToc->GrantedListHead)
144 Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry );
146 if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
147 REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
149 //No read conflict if (shared lock) OR (exclusive + our lock)
150 //No write conflict if exclusive lock AND our lock
151 if ((Read && !Granted->Lock.ExclusiveLock) ||
152 (Granted->Lock.ExclusiveLock &&
153 Granted->Lock.Process == Process &&
154 Granted->Lock.FileObject == FileObject &&
155 Granted->Lock.Key == Key ) )
157 //AND if lock surround request region, stop searching and grant
158 if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
159 REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
161 EnumEntry = &LockToc->GrantedListHead;//indicate no conflict
164 //else continue searching for conflicts
171 EnumEntry = EnumEntry->Flink;
174 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
176 if (EnumEntry == &LockToc->GrantedListHead)
185 /**********************************************************************
187 * FsRtlCheckLockForReadAccess
193 FsRtlCheckLockForReadAccess (
194 IN PFILE_LOCK FileLock,
198 PIO_STACK_LOCATION Stack;
199 LARGE_INTEGER LocalLength;
201 Stack = IoGetCurrentIrpStackLocation(Irp);
203 LocalLength.u.LowPart = Stack->Parameters.Read.Length;
204 LocalLength.u.HighPart = 0;
206 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
207 &Stack->Parameters.Read.ByteOffset,
209 Stack->Parameters.Read.Key,
211 IoGetRequestorProcess(Irp),
217 /**********************************************************************
219 * FsRtlCheckLockForWriteAccess
225 FsRtlCheckLockForWriteAccess (
226 IN PFILE_LOCK FileLock,
230 PIO_STACK_LOCATION Stack;
231 LARGE_INTEGER LocalLength;
233 Stack = IoGetCurrentIrpStackLocation(Irp);
235 LocalLength.u.LowPart = Stack->Parameters.Read.Length;
236 LocalLength.u.HighPart = 0;
238 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
239 &Stack->Parameters.Write.ByteOffset,
241 Stack->Parameters.Write.Key,
243 IoGetRequestorProcess(Irp),
252 /**********************************************************************
254 * FsRtlFastCheckLockForRead
260 FsRtlFastCheckLockForRead (
261 IN PFILE_LOCK FileLock,
262 IN PLARGE_INTEGER FileOffset,
263 IN PLARGE_INTEGER Length,
265 IN PFILE_OBJECT FileObject,
269 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
280 /**********************************************************************
282 * FsRtlFastCheckLockForWrite
288 FsRtlFastCheckLockForWrite (
289 IN PFILE_LOCK FileLock,
290 IN PLARGE_INTEGER FileOffset,
291 IN PLARGE_INTEGER Length,
293 IN PFILE_OBJECT FileObject,
297 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
309 /**********************************************************************
311 * FsRtlpFastUnlockAllByKey
316 FsRtlpFastUnlockAllByKey(
317 IN PFILE_LOCK FileLock,
318 IN PFILE_OBJECT FileObject,
319 IN PEPROCESS Process,
320 IN DWORD Key, /* FIXME: guess */
321 IN BOOLEAN UseKey, /* FIXME: guess */
322 IN PVOID Context OPTIONAL
326 PFILE_LOCK_TOC LockToc;
327 PLIST_ENTRY EnumEntry;
328 PFILE_LOCK_GRANTED Granted;
329 BOOLEAN Unlock = FALSE;
330 //must make local copy since FILE_LOCK struct is allowed to be paged
331 PUNLOCK_ROUTINE GotUnlockRoutine;
334 LockToc = FileLock->LockInformation;
338 return STATUS_RANGE_NOT_LOCKED;
341 GotUnlockRoutine = FileLock->UnlockRoutine;
342 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
344 EnumEntry = LockToc->GrantedListHead.Flink;
345 while (EnumEntry != &LockToc->GrantedListHead )
347 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
348 EnumEntry = EnumEntry->Flink;
350 if (Granted->Lock.Process == Process &&
351 Granted->Lock.FileObject == FileObject &&
352 (!UseKey || (UseKey && Granted->Lock.Key == Key)) )
354 RemoveEntryList(&Granted->ListEntry);
357 if (GotUnlockRoutine)
360 Put on unlocked list and call unlock routine for them afterwards.
361 This way we don't have to restart enum after each call
363 InsertHeadList(&LockToc->UnlockedListHead,&Granted->ListEntry);
367 ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
374 //call unlock routine for each unlocked lock (if any)
375 while (!IsListEmpty(&LockToc->UnlockedListHead))
377 EnumEntry = RemoveTailList(&LockToc->UnlockedListHead);
378 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
379 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
380 FileLock->UnlockRoutine(Context,&Granted->Lock);
381 ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
382 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
385 //NOTE: holding spinlock while calling this
386 FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
388 if (IsListEmpty(&LockToc->GrantedListHead))
390 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
391 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
395 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
397 return STATUS_SUCCESS;
400 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
401 return STATUS_RANGE_NOT_LOCKED;
404 /**********************************************************************
412 FsRtlFastUnlockAll /*ByProcess*/ (
413 IN PFILE_LOCK FileLock,
414 IN PFILE_OBJECT FileObject,
415 IN PEPROCESS Process,
416 IN PVOID Context OPTIONAL
419 return FsRtlpFastUnlockAllByKey( FileLock,
423 FALSE, /* Do NOT use Key */
428 /**********************************************************************
430 * FsRtlFastUnlockAllByKey
436 FsRtlFastUnlockAllByKey (
437 IN PFILE_LOCK FileLock,
438 IN PFILE_OBJECT FileObject,
439 IN PEPROCESS Process,
441 IN PVOID Context OPTIONAL
444 return FsRtlpFastUnlockAllByKey( FileLock,
454 /**********************************************************************
459 * Spinlock held at entry !!
464 IN PFILE_LOCK_TOC LockToc,
465 IN PFILE_OBJECT FileObject,
466 IN PLARGE_INTEGER FileOffset,
467 IN PLARGE_INTEGER Length,
468 IN PEPROCESS Process,
470 IN BOOLEAN ExclusiveLock
473 PLIST_ENTRY EnumEntry;
474 PFILE_LOCK_GRANTED Granted;
476 EnumEntry = LockToc->GrantedListHead.Flink;
477 while (EnumEntry != &LockToc->GrantedListHead)
479 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
481 if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
482 REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
484 //never conflict if shared lock and we want to add a shared lock
485 if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
487 //AND if lock surround region, stop searching and insert lock
488 if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
489 REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
491 EnumEntry = &LockToc->GrantedListHead;
494 //else keep locking for conflicts
497 {//conflict if we want share access to excl. lock OR exlc. access to shared lock
501 EnumEntry = EnumEntry->Flink;
504 if (EnumEntry == &LockToc->GrantedListHead)
506 Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside);
508 Granted->Lock.StartingByte = *FileOffset;
509 Granted->Lock.Length = *Length;
510 Granted->Lock.ExclusiveLock = ExclusiveLock;
511 Granted->Lock.Key = Key;
512 Granted->Lock.FileObject = FileObject;
513 Granted->Lock.Process = Process;
514 Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF;
516 InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry);
526 /**********************************************************************
528 * FsRtlpCompletePendingLocks
531 * Spinlock held at entry !!
535 FsRtlpCompletePendingLocks(
536 IN PFILE_LOCK FileLock,
537 IN PFILE_LOCK_TOC LockToc,
538 IN OUT PKIRQL oldirql
541 //walk pending list, FIFO order, try 2 complete locks
542 PLIST_ENTRY EnumEntry;
544 PEXTENDED_IO_STACK_LOCATION Stack;
546 EnumEntry = LockToc->PendingListHead.Blink;
547 while (EnumEntry != &LockToc->PendingListHead)
549 Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry);
551 Stack = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation(Irp);
552 if (FsRtlpAddLock(LockToc,
554 &Stack->Parameters.LockControl.ByteOffset,
555 Stack->Parameters.LockControl.Length,
556 IoGetRequestorProcess(Irp),
557 Stack->Parameters.LockControl.Key,
558 Stack->Flags & SL_EXCLUSIVE_LOCK
561 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
563 if (!IoSetCancelRoutine(Irp, NULL))
566 Cancel routine WILL be called after we release the spinlock. It will try to remove
567 the irp from the list and cancel/complete this irp. Since we allready removed it,
568 make its ListEntry point to itself.
570 InitializeListHead(&Irp->Tail.Overlay.ListEntry);
575 Cancel routine will NOT be called, canceled or not.
577 Put on completed list and complete them all afterwards.
578 This way we don't have to restart enum after each completion.
580 Irp->IoStatus.Status = STATUS_SUCCESS;
581 Irp->IoStatus.Information = 0;
582 InsertHeadList(&LockToc->CompletedListHead,&Irp->Tail.Overlay.ListEntry);
585 EnumEntry = EnumEntry->Blink;
588 //complete irp's (if any)
589 while (!IsListEmpty(&LockToc->CompletedListHead))
591 EnumEntry = RemoveTailList(&LockToc->CompletedListHead);
592 KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine
593 Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
595 if (FileLock->CompleteLockIrpRoutine)
597 FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
601 IofCompleteRequest(Irp, IO_NO_INCREMENT);
604 KeAcquireSpinLock(&LockToc->SpinLock, oldirql);
611 /**********************************************************************
619 IN PFILE_LOCK FileLock,
620 IN PFILE_OBJECT FileObject,
621 IN PLARGE_INTEGER FileOffset,
622 IN PLARGE_INTEGER Length,
623 IN PEPROCESS Process,
625 IN PVOID Context OPTIONAL,
626 IN BOOLEAN AlreadySynchronized,
627 IN BOOLEAN CallUnlockRoutine
631 PFILE_LOCK_TOC LockToc;
632 PFILE_LOCK_GRANTED Granted;
633 PLIST_ENTRY EnumEntry;
636 LockToc = FileLock->LockInformation;
638 if (LockToc == NULL || Length->QuadPart == 0)
640 return STATUS_RANGE_NOT_LOCKED;
643 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql );
645 EnumEntry = LockToc->GrantedListHead.Flink;
646 while (EnumEntry != &LockToc->GrantedListHead)
648 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
650 //must be exact match
651 if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart &&
652 Length->QuadPart == Granted->Lock.Length.QuadPart &&
653 Granted->Lock.Process == Process &&
654 Granted->Lock.FileObject == FileObject &&
655 Granted->Lock.Key == Key)
657 RemoveEntryList(&Granted->ListEntry);
658 FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
660 if (IsListEmpty(&LockToc->GrantedListHead))
662 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
663 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
667 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
670 if (FileLock->UnlockRoutine && CallUnlockRoutine)
672 FileLock->UnlockRoutine(Context,&Granted->Lock);
675 ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
677 return STATUS_SUCCESS;
679 EnumEntry = EnumEntry->Flink;
682 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
684 return STATUS_RANGE_NOT_LOCKED;
690 /**********************************************************************
692 * FsRtlFastUnlockSingle
698 FsRtlFastUnlockSingle (
699 IN PFILE_LOCK FileLock,
700 IN PFILE_OBJECT FileObject,
701 IN PLARGE_INTEGER FileOffset,
702 IN PLARGE_INTEGER Length,
703 IN PEPROCESS Process,
705 IN PVOID Context OPTIONAL,
706 IN BOOLEAN AlreadySynchronized
709 return FsRtlpUnlockSingle( FileLock,
717 TRUE//CallUnlockRoutine
721 /**********************************************************************
723 * FsRtlpDumpFileLocks
725 * NOTE: used for testing and debugging
730 IN PFILE_LOCK FileLock
734 PFILE_LOCK_TOC LockToc;
735 PFILE_LOCK_GRANTED Granted;
737 PLIST_ENTRY EnumEntry;
738 PEXTENDED_IO_STACK_LOCATION Stack;
741 LockToc = FileLock->LockInformation;
745 DPRINT1("No file locks\n");
749 DPRINT1("Dumping granted file locks, FIFO order\n");
751 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
753 EnumEntry = LockToc->GrantedListHead.Blink;
754 while ( EnumEntry != &LockToc->GrantedListHead)
756 Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry );
758 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
759 Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD",
760 Granted->Lock.StartingByte.QuadPart,
761 Granted->Lock.Length.QuadPart,
762 Granted->Lock.EndingByte.QuadPart,
764 Granted->Lock.Process,
765 Granted->Lock.FileObject
768 EnumEntry = EnumEntry->Blink;
771 DPRINT1("Dumping pending file locks, FIFO order\n");
773 EnumEntry = LockToc->PendingListHead.Blink;
774 while ( EnumEntry != &LockToc->PendingListHead)
776 Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry );
778 Stack = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation(Irp);
780 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
781 (Stack->Flags & SL_EXCLUSIVE_LOCK) ? "EXCL" : "SHRD",
782 Stack->Parameters.LockControl.ByteOffset.QuadPart,
783 Stack->Parameters.LockControl.Length->QuadPart,
784 Stack->Parameters.LockControl.ByteOffset.QuadPart + Stack->Parameters.LockControl.Length->QuadPart - 1,
785 Stack->Parameters.LockControl.Key,
786 IoGetRequestorProcess(Irp),
790 EnumEntry = EnumEntry->Blink;
793 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
798 /**********************************************************************
800 * FsRtlGetNextFileLock
803 * NULL if no more locks.
809 FsRtlGetNextFileLock (
810 IN PFILE_LOCK FileLock,
815 Messy enumeration of granted locks.
816 What our last ptr. in LastReturnedLock points at, might have been freed between
817 calls, so we have to scan thru the list every time, searching for our last lock.
818 If it's not there anymore, restart the enumeration...
821 PLIST_ENTRY EnumEntry;
822 PFILE_LOCK_GRANTED Granted;
823 PFILE_LOCK_TOC LockToc;
824 BOOLEAN FoundPrevious = FALSE;
825 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
826 FILE_LOCK_INFO LocalLastReturnedLockInfo;
827 PVOID LocalLastReturnedLock;
830 LockToc = FileLock->LockInformation;
836 LocalLastReturnedLock = FileLock->LastReturnedLock;
838 KeAcquireSpinLock(&LockToc->SpinLock,&oldirql);
842 EnumEntry = LockToc->GrantedListHead.Flink;
846 if (EnumEntry != &LockToc->GrantedListHead)
848 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
849 LocalLastReturnedLockInfo = Granted->Lock;
850 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
852 FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo;
853 FileLock->LastReturnedLock = EnumEntry;
854 return &FileLock->LastReturnedLockInfo;
858 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
863 //else: continue enum
864 while (EnumEntry != &LockToc->GrantedListHead)
866 //found previous lock?
867 if (EnumEntry == LocalLastReturnedLock)
869 FoundPrevious = TRUE;
871 EnumEntry = EnumEntry->Flink;
872 if (EnumEntry != &LockToc->GrantedListHead)
874 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
875 LocalLastReturnedLockInfo = Granted->Lock;
876 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
878 FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo;
879 FileLock->LastReturnedLock = EnumEntry;
880 return &FileLock->LastReturnedLockInfo;
884 EnumEntry = EnumEntry->Flink;
889 //got here? uh no, didn't find our last lock..must have been freed...restart
894 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
896 return NULL;//no (more) locks
900 /**********************************************************************
902 * FsRtlInitializeFileLock
905 * Called when creating/allocating/initializing FCB
911 FsRtlInitializeFileLock (
912 IN PFILE_LOCK FileLock,
913 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL,
914 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
918 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
919 FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine;
920 FileLock->UnlockRoutine = UnlockRoutine;
921 FileLock->LockInformation = NULL;
926 /**********************************************************************
935 IN PFILE_LOCK FileLock,
936 IN PFILE_OBJECT FileObject,
937 IN PLARGE_INTEGER FileOffset,
938 IN PLARGE_INTEGER Length,
939 IN PEPROCESS Process,
941 IN BOOLEAN FailImmediately, //seems meaningless for fast io
942 IN BOOLEAN ExclusiveLock,
943 OUT PIO_STATUS_BLOCK IoStatus,
944 IN PIRP Irp OPTIONAL,
946 IN BOOLEAN AlreadySynchronized
949 PFILE_LOCK_TOC LockToc;
953 if (FileLock->LockInformation == NULL)
955 ExAcquireFastMutex(&LockTocMutex);
957 if (FileLock->LockInformation == NULL)
959 FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside);
960 LockToc = FileLock->LockInformation;
961 KeInitializeSpinLock(&LockToc->SpinLock);
962 InitializeListHead(&LockToc->GrantedListHead);
963 InitializeListHead(&LockToc->PendingListHead);
964 InitializeListHead(&LockToc->CompletedListHead);
965 InitializeListHead(&LockToc->UnlockedListHead);
967 ExReleaseFastMutex(&LockTocMutex);
970 LockToc = FileLock->LockInformation;
971 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
973 //try add new lock (while holding spin lock)
974 if (FsRtlpAddLock(LockToc,
983 IoStatus->Status = STATUS_SUCCESS;
985 else if (Irp && !FailImmediately)
986 { //failed + irp + no fail = mk. pending
987 //for our cancel routine
988 Irp->Tail.Overlay.DriverContext[0] = (PVOID)FileLock;
989 Irp->Tail.Overlay.DriverContext[1] = (PVOID)LockToc;
990 Irp->Tail.Overlay.DriverContext[2] = Context;
992 IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine);
996 //irp canceled even before we got to queue it
997 if (IoSetCancelRoutine(Irp, NULL))
998 { //Cancel routine will NOT be called: cancel it here
999 IoStatus->Status = STATUS_CANCELLED;
1002 { //Cancel routine WILL be called. When we release the lock it will complete the irp
1003 //Return pending since we are not completing the irp here
1004 Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
1005 Irp->IoStatus.Information = 0;
1006 InitializeListHead(&Irp->Tail.Overlay.ListEntry);
1011 { //not cancelled: queue irp
1012 IoMarkIrpPending(Irp);
1013 Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
1014 Irp->IoStatus.Information = 0;
1015 InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
1021 IoStatus->Status = STATUS_LOCK_NOT_GRANTED;
1024 KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine
1026 //never pending if no irp;-)
1027 assert(!(IoStatus->Status == STATUS_PENDING && !Irp));
1029 if (IoStatus->Status != STATUS_PENDING)
1031 if (IoStatus->Status == STATUS_SUCCESS)
1033 FsRtlAreThereCurrentFileLocks(FileLock) = TRUE;
1038 Irp->IoStatus.Status = IoStatus->Status;
1039 Irp->IoStatus.Information = 0;
1041 if (FileLock->CompleteLockIrpRoutine)
1042 { //complete irp routine
1044 if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp)))
1046 //CompleteLockIrpRoutine complain: revert changes
1047 FsRtlpUnlockSingle( FileLock,
1054 AlreadySynchronized,
1055 FALSE//CallUnlockRoutine
1060 {//std irp completion
1061 IofCompleteRequest(Irp, IO_NO_INCREMENT);
1066 //NOTE: only fast io seems to care about this return value
1067 return (IoStatus->Status == STATUS_SUCCESS || FailImmediately);
1073 /**********************************************************************
1075 * FsRtlProcessFileLock
1081 FsRtlProcessFileLock (
1082 IN PFILE_LOCK FileLock,
1084 IN PVOID Context OPTIONAL
1087 PEXTENDED_IO_STACK_LOCATION Stack;
1089 IO_STATUS_BLOCK LocalIoStatus;
1092 Stack = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation(Irp);
1093 Irp->IoStatus.Information = 0;
1095 switch(Stack->MinorFunction)
1099 FsRtlPrivateLock( FileLock,
1101 &Stack->Parameters.LockControl.ByteOffset, //not pointer!
1102 Stack->Parameters.LockControl.Length,
1103 IoGetRequestorProcess(Irp),
1104 Stack->Parameters.LockControl.Key,
1105 Stack->Flags & SL_FAIL_IMMEDIATELY,
1106 Stack->Flags & SL_EXCLUSIVE_LOCK,
1112 return LocalIoStatus.Status;
1114 case IRP_MN_UNLOCK_SINGLE:
1115 Status = FsRtlFastUnlockSingle ( FileLock,
1117 &Stack->Parameters.LockControl.ByteOffset,
1118 Stack->Parameters.LockControl.Length,
1119 IoGetRequestorProcess(Irp),
1120 Stack->Parameters.LockControl.Key,
1125 case IRP_MN_UNLOCK_ALL:
1126 Status = FsRtlFastUnlockAll( FileLock,
1128 IoGetRequestorProcess(Irp),
1132 case IRP_MN_UNLOCK_ALL_BY_KEY:
1133 Status = FsRtlFastUnlockAllByKey ( FileLock,
1135 IoGetRequestorProcess(Irp),
1136 Stack->Parameters.LockControl.Key,
1142 Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
1143 IofCompleteRequest(Irp, IO_NO_INCREMENT);
1147 Irp->IoStatus.Status = Status;
1149 if (FileLock->CompleteLockIrpRoutine )
1151 FileLock->CompleteLockIrpRoutine(Context,Irp);
1155 IofCompleteRequest(Irp,IO_NO_INCREMENT);
1162 /**********************************************************************
1164 * FsRtlUninitializeFileLock
1170 FsRtlUninitializeFileLock (
1171 IN PFILE_LOCK FileLock
1174 PFILE_LOCK_TOC LockToc;
1176 PFILE_LOCK_GRANTED Granted;
1177 PLIST_ENTRY EnumEntry;
1181 if (FileLock->LockInformation == NULL)
1186 LockToc = FileLock->LockInformation;
1188 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
1190 //remove and free granted locks
1191 while (!IsListEmpty(&LockToc->GrantedListHead))
1193 EnumEntry = RemoveTailList(&LockToc->GrantedListHead);
1194 Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry);
1195 ExFreeToNPagedLookasideList(&GrantedLookaside, Granted);
1198 //remove, complete and free all pending locks
1199 while (!IsListEmpty(&LockToc->PendingListHead))
1201 EnumEntry = RemoveTailList(&LockToc->PendingListHead);
1202 Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
1204 if (!IoSetCancelRoutine(Irp, NULL))
1206 //The cancel routine will be called. When we release the lock it will complete the irp.
1207 InitializeListHead(&Irp->Tail.Overlay.ListEntry);
1212 Cancel routine will NOT be called, even though the irp might have been canceled.
1213 Don't care since we'l complete it faster than the cancel routine would have.
1215 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine
1217 Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED;
1219 if (FileLock->CompleteLockIrpRoutine)
1221 FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
1225 IofCompleteRequest(Irp, IO_NO_INCREMENT);
1228 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
1232 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
1234 ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc);
1236 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
1237 FileLock->LockInformation = NULL;
1242 /**********************************************************************
1244 * FsRtlAllocateFileLock
1247 * Only present in NT 5.0 or later.
1248 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1254 FsRtlAllocateFileLock(
1255 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL,
1256 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1259 PFILE_LOCK FileLock;
1261 FileLock = ExAllocateFromPagedLookasideList(&LockLookaside);
1263 FsRtlInitializeFileLock(FileLock,
1264 CompleteLockIrpRoutine,
1271 /**********************************************************************
1276 * Only present in NT 5.0 or later.
1277 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1284 IN PFILE_LOCK FileLock
1289 FsRtlUninitializeFileLock(FileLock);
1290 ExFreeToPagedLookasideList(&LockLookaside, FileLock);