3 * reactos/ntoskrnl/fs/filelock.c
7 #include <internal/ifs.h>
11 #include <internal/debug.h>
15 I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
16 are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
20 #define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
21 #define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1)
22 #define REQUEST_START_OFF (FileOffset->QuadPart)
23 #define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
25 FAST_MUTEX LockTocMutex;
26 NPAGED_LOOKASIDE_LIST GrantedLookaside;
27 NPAGED_LOOKASIDE_LIST LockTocLookaside;
28 PAGED_LOOKASIDE_LIST LockLookaside;
30 /**********************************************************************
32 * FsRtlpInitFileLockingImplementation
37 FsRtlpInitFileLockingImplementation(VOID)
39 ExInitializeNPagedLookasideList( &LockTocLookaside,
43 sizeof(FILE_LOCK_TOC),
48 ExInitializeNPagedLookasideList( &GrantedLookaside,
52 sizeof(FILE_LOCK_GRANTED),
57 ExInitializePagedLookasideList( &LockLookaside,
66 ExInitializeFastMutex(&LockTocMutex);
69 /**********************************************************************
71 * FsRtlpFileLockCancelRoutine
76 FsRtlpFileLockCancelRoutine(
77 IN PDEVICE_OBJECT DeviceObject,
83 PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine;
85 //don't need this since we have our own sync. protecting irp cancellation
86 IoReleaseCancelSpinLock(Irp->CancelIrql);
88 SpinLock = &((PFILE_LOCK_TOC)Irp->Tail.Overlay.DriverContext[1])->SpinLock;
90 KeAcquireSpinLock(SpinLock, &oldIrql);
91 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
92 KeReleaseSpinLock(SpinLock, oldIrql);
94 Irp->IoStatus.Status = STATUS_CANCELLED;
96 CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine;
97 if (CompleteLockIrpRoutine)
99 CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
103 IofCompleteRequest(Irp, IO_NO_INCREMENT);
108 /**********************************************************************
110 * FsRtlpCheckLockForReadOrWriteAccess
115 FsRtlpCheckLockForReadOrWriteAccess(
116 IN PFILE_LOCK FileLock,
117 IN PLARGE_INTEGER FileOffset,
118 IN PLARGE_INTEGER Length,
120 IN PFILE_OBJECT FileObject,
121 IN PEPROCESS Process,
126 PFILE_LOCK_TOC LockToc;
127 PFILE_LOCK_GRANTED Granted;
128 PLIST_ENTRY EnumEntry;
131 LockToc = FileLock->LockInformation;
133 if (LockToc == NULL || Length->QuadPart == 0)
138 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
140 EnumEntry = LockToc->GrantedListHead.Flink;
141 while ( EnumEntry != &LockToc->GrantedListHead)
143 Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry );
145 if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
146 REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
148 //No read conflict if (shared lock) OR (exclusive + our lock)
149 //No write conflict if exclusive lock AND our lock
150 if ((Read && !Granted->Lock.ExclusiveLock) ||
151 (Granted->Lock.ExclusiveLock &&
152 Granted->Lock.Process == Process &&
153 Granted->Lock.FileObject == FileObject &&
154 Granted->Lock.Key == Key ) )
156 //AND if lock surround request region, stop searching and grant
157 if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
158 REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
160 EnumEntry = &LockToc->GrantedListHead;//indicate no conflict
163 //else continue searching for conflicts
170 EnumEntry = EnumEntry->Flink;
173 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
175 if (EnumEntry == &LockToc->GrantedListHead)
184 /**********************************************************************
186 * FsRtlCheckLockForReadAccess
191 FsRtlCheckLockForReadAccess (
192 IN PFILE_LOCK FileLock,
196 PIO_STACK_LOCATION Stack;
197 LARGE_INTEGER LocalLength;
199 Stack = IoGetCurrentIrpStackLocation(Irp);
201 LocalLength.u.LowPart = Stack->Parameters.Read.Length;
202 LocalLength.u.HighPart = 0;
204 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
205 &Stack->Parameters.Read.ByteOffset,
207 Stack->Parameters.Read.Key,
209 IoGetRequestorProcess(Irp),
215 /**********************************************************************
217 * 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
256 FsRtlFastCheckLockForRead (
257 IN PFILE_LOCK FileLock,
258 IN PLARGE_INTEGER FileOffset,
259 IN PLARGE_INTEGER Length,
261 IN PFILE_OBJECT FileObject,
265 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
276 /**********************************************************************
278 * FsRtlFastCheckLockForWrite
283 FsRtlFastCheckLockForWrite (
284 IN PFILE_LOCK FileLock,
285 IN PLARGE_INTEGER FileOffset,
286 IN PLARGE_INTEGER Length,
288 IN PFILE_OBJECT FileObject,
292 return FsRtlpCheckLockForReadOrWriteAccess( FileLock,
304 /**********************************************************************
306 * FsRtlpFastUnlockAllByKey
311 FsRtlpFastUnlockAllByKey(
312 IN PFILE_LOCK FileLock,
313 IN PFILE_OBJECT FileObject,
314 IN PEPROCESS Process,
315 IN DWORD Key, /* FIXME: guess */
316 IN BOOLEAN UseKey, /* FIXME: guess */
317 IN PVOID Context OPTIONAL
321 PFILE_LOCK_TOC LockToc;
322 PLIST_ENTRY EnumEntry;
323 PFILE_LOCK_GRANTED Granted;
324 BOOLEAN Unlock = FALSE;
325 //must make local copy since FILE_LOCK struct is allowed to be paged
326 PUNLOCK_ROUTINE GotUnlockRoutine;
329 LockToc = FileLock->LockInformation;
333 return STATUS_RANGE_NOT_LOCKED;
336 GotUnlockRoutine = FileLock->UnlockRoutine;
337 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
339 EnumEntry = LockToc->GrantedListHead.Flink;
340 while (EnumEntry != &LockToc->GrantedListHead )
342 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
343 EnumEntry = EnumEntry->Flink;
345 if (Granted->Lock.Process == Process &&
346 Granted->Lock.FileObject == FileObject &&
347 (!UseKey || (UseKey && Granted->Lock.Key == Key)) )
349 RemoveEntryList(&Granted->ListEntry);
352 if (GotUnlockRoutine)
355 Put on unlocked list and call unlock routine for them afterwards.
356 This way we don't have to restart enum after each call
358 InsertHeadList(&LockToc->UnlockedListHead,&Granted->ListEntry);
362 ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
369 //call unlock routine for each unlocked lock (if any)
370 while (!IsListEmpty(&LockToc->UnlockedListHead))
372 EnumEntry = RemoveTailList(&LockToc->UnlockedListHead);
373 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
374 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
375 FileLock->UnlockRoutine(Context,&Granted->Lock);
376 ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
377 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
380 //NOTE: holding spinlock while calling this
381 FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
383 if (IsListEmpty(&LockToc->GrantedListHead))
385 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
386 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
390 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
392 return STATUS_SUCCESS;
395 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
396 return STATUS_RANGE_NOT_LOCKED;
399 /**********************************************************************
406 FsRtlFastUnlockAll /*ByProcess*/ (
407 IN PFILE_LOCK FileLock,
408 IN PFILE_OBJECT FileObject,
409 IN PEPROCESS Process,
410 IN PVOID Context OPTIONAL
413 return FsRtlpFastUnlockAllByKey( FileLock,
417 FALSE, /* Do NOT use Key */
422 /**********************************************************************
424 * FsRtlFastUnlockAllByKey
429 FsRtlFastUnlockAllByKey (
430 IN PFILE_LOCK FileLock,
431 IN PFILE_OBJECT FileObject,
432 IN PEPROCESS Process,
434 IN PVOID Context OPTIONAL
437 return FsRtlpFastUnlockAllByKey( FileLock,
447 /**********************************************************************
452 * Spinlock held at entry !!
457 IN PFILE_LOCK_TOC LockToc,
458 IN PFILE_OBJECT FileObject,
459 IN PLARGE_INTEGER FileOffset,
460 IN PLARGE_INTEGER Length,
461 IN PEPROCESS Process,
463 IN BOOLEAN ExclusiveLock
466 PLIST_ENTRY EnumEntry;
467 PFILE_LOCK_GRANTED Granted;
469 EnumEntry = LockToc->GrantedListHead.Flink;
470 while (EnumEntry != &LockToc->GrantedListHead)
472 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
474 if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
475 REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
477 //never conflict if shared lock and we want to add a shared lock
478 if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
480 //AND if lock surround region, stop searching and insert lock
481 if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
482 REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
484 EnumEntry = &LockToc->GrantedListHead;
487 //else keep locking for conflicts
490 {//conflict if we want share access to excl. lock OR exlc. access to shared lock
494 EnumEntry = EnumEntry->Flink;
497 if (EnumEntry == &LockToc->GrantedListHead)
499 Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside);
501 Granted->Lock.StartingByte = *FileOffset;
502 Granted->Lock.Length = *Length;
503 Granted->Lock.ExclusiveLock = ExclusiveLock;
504 Granted->Lock.Key = Key;
505 Granted->Lock.FileObject = FileObject;
506 Granted->Lock.Process = Process;
507 Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF;
509 InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry);
519 /**********************************************************************
521 * FsRtlpCompletePendingLocks
524 * Spinlock held at entry !!
528 FsRtlpCompletePendingLocks(
529 IN PFILE_LOCK FileLock,
530 IN PFILE_LOCK_TOC LockToc,
531 IN OUT PKIRQL oldirql
534 //walk pending list, FIFO order, try 2 complete locks
535 PLIST_ENTRY EnumEntry;
537 PIO_STACK_LOCATION Stack;
539 EnumEntry = LockToc->PendingListHead.Blink;
540 while (EnumEntry != &LockToc->PendingListHead)
542 Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry);
544 Stack = IoGetCurrentIrpStackLocation(Irp);
545 if (FsRtlpAddLock(LockToc,
547 &Stack->Parameters.LockControl.ByteOffset,
548 Stack->Parameters.LockControl.Length,
549 IoGetRequestorProcess(Irp),
550 Stack->Parameters.LockControl.Key,
551 Stack->Flags & SL_EXCLUSIVE_LOCK
554 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
556 if (!IoSetCancelRoutine(Irp, NULL))
559 Cancel routine WILL be called after we release the spinlock. It will try to remove
560 the irp from the list and cancel/complete this irp. Since we allready removed it,
561 make its ListEntry point to itself.
563 InitializeListHead(&Irp->Tail.Overlay.ListEntry);
568 Cancel routine will NOT be called, canceled or not.
570 Put on completed list and complete them all afterwards.
571 This way we don't have to restart enum after each completion.
573 Irp->IoStatus.Status = STATUS_SUCCESS;
574 Irp->IoStatus.Information = 0;
575 InsertHeadList(&LockToc->CompletedListHead,&Irp->Tail.Overlay.ListEntry);
578 EnumEntry = EnumEntry->Blink;
581 //complete irp's (if any)
582 while (!IsListEmpty(&LockToc->CompletedListHead))
584 EnumEntry = RemoveTailList(&LockToc->CompletedListHead);
585 KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine
586 Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
588 if (FileLock->CompleteLockIrpRoutine)
590 FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
594 IofCompleteRequest(Irp, IO_NO_INCREMENT);
597 KeAcquireSpinLock(&LockToc->SpinLock, oldirql);
604 /**********************************************************************
612 IN PFILE_LOCK FileLock,
613 IN PFILE_OBJECT FileObject,
614 IN PLARGE_INTEGER FileOffset,
615 IN PLARGE_INTEGER Length,
616 IN PEPROCESS Process,
618 IN PVOID Context OPTIONAL,
619 IN BOOLEAN AlreadySynchronized,
620 IN BOOLEAN CallUnlockRoutine
624 PFILE_LOCK_TOC LockToc;
625 PFILE_LOCK_GRANTED Granted;
626 PLIST_ENTRY EnumEntry;
629 LockToc = FileLock->LockInformation;
631 if (LockToc == NULL || Length->QuadPart == 0)
633 return STATUS_RANGE_NOT_LOCKED;
636 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql );
638 EnumEntry = LockToc->GrantedListHead.Flink;
639 while (EnumEntry != &LockToc->GrantedListHead)
641 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
643 //must be exact match
644 if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart &&
645 Length->QuadPart == Granted->Lock.Length.QuadPart &&
646 Granted->Lock.Process == Process &&
647 Granted->Lock.FileObject == FileObject &&
648 Granted->Lock.Key == Key)
650 RemoveEntryList(&Granted->ListEntry);
651 FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
653 if (IsListEmpty(&LockToc->GrantedListHead))
655 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
656 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
660 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
663 if (FileLock->UnlockRoutine && CallUnlockRoutine)
665 FileLock->UnlockRoutine(Context,&Granted->Lock);
668 ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
670 return STATUS_SUCCESS;
672 EnumEntry = EnumEntry->Flink;
675 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
677 return STATUS_RANGE_NOT_LOCKED;
683 /**********************************************************************
685 * FsRtlFastUnlockSingle
690 FsRtlFastUnlockSingle (
691 IN PFILE_LOCK FileLock,
692 IN PFILE_OBJECT FileObject,
693 IN PLARGE_INTEGER FileOffset,
694 IN PLARGE_INTEGER Length,
695 IN PEPROCESS Process,
697 IN PVOID Context OPTIONAL,
698 IN BOOLEAN AlreadySynchronized
701 return FsRtlpUnlockSingle( FileLock,
709 TRUE//CallUnlockRoutine
713 /**********************************************************************
715 * FsRtlpDumpFileLocks
717 * NOTE: used for testing and debugging
722 IN PFILE_LOCK FileLock
726 PFILE_LOCK_TOC LockToc;
727 PFILE_LOCK_GRANTED Granted;
729 PLIST_ENTRY EnumEntry;
730 PIO_STACK_LOCATION Stack;
733 LockToc = FileLock->LockInformation;
737 DPRINT1("No file locks\n");
741 DPRINT1("Dumping granted file locks, FIFO order\n");
743 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
745 EnumEntry = LockToc->GrantedListHead.Blink;
746 while ( EnumEntry != &LockToc->GrantedListHead)
748 Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry );
750 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
751 Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD",
752 Granted->Lock.StartingByte.QuadPart,
753 Granted->Lock.Length.QuadPart,
754 Granted->Lock.EndingByte.QuadPart,
756 Granted->Lock.Process,
757 Granted->Lock.FileObject
760 EnumEntry = EnumEntry->Blink;
763 DPRINT1("Dumping pending file locks, FIFO order\n");
765 EnumEntry = LockToc->PendingListHead.Blink;
766 while ( EnumEntry != &LockToc->PendingListHead)
768 Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry );
770 Stack = IoGetCurrentIrpStackLocation(Irp);
772 DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
773 (Stack->Flags & SL_EXCLUSIVE_LOCK) ? "EXCL" : "SHRD",
774 Stack->Parameters.LockControl.ByteOffset.QuadPart,
775 Stack->Parameters.LockControl.Length->QuadPart,
776 Stack->Parameters.LockControl.ByteOffset.QuadPart + Stack->Parameters.LockControl.Length->QuadPart - 1,
777 Stack->Parameters.LockControl.Key,
778 IoGetRequestorProcess(Irp),
782 EnumEntry = EnumEntry->Blink;
785 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
790 /**********************************************************************
792 * FsRtlGetNextFileLock
795 * NULL if no more locks.
800 FsRtlGetNextFileLock (
801 IN PFILE_LOCK FileLock,
806 Messy enumeration of granted locks.
807 What our last ptr. in LastReturnedLock points at, might have been freed between
808 calls, so we have to scan thru the list every time, searching for our last lock.
809 If it's not there anymore, restart the enumeration...
812 PLIST_ENTRY EnumEntry;
813 PFILE_LOCK_GRANTED Granted;
814 PFILE_LOCK_TOC LockToc;
815 BOOLEAN FoundPrevious = FALSE;
816 //must make local copy since FILE_LOCK struct is allowed to be in paged mem
817 FILE_LOCK_INFO LocalLastReturnedLockInfo;
818 PVOID LocalLastReturnedLock;
821 LockToc = FileLock->LockInformation;
827 LocalLastReturnedLock = FileLock->LastReturnedLock;
829 KeAcquireSpinLock(&LockToc->SpinLock,&oldirql);
833 EnumEntry = LockToc->GrantedListHead.Flink;
837 if (EnumEntry != &LockToc->GrantedListHead)
839 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
840 LocalLastReturnedLockInfo = Granted->Lock;
841 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
843 FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo;
844 FileLock->LastReturnedLock = EnumEntry;
845 return &FileLock->LastReturnedLockInfo;
849 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
854 //else: continue enum
855 while (EnumEntry != &LockToc->GrantedListHead)
857 //found previous lock?
858 if (EnumEntry == LocalLastReturnedLock)
860 FoundPrevious = TRUE;
862 EnumEntry = EnumEntry->Flink;
863 if (EnumEntry != &LockToc->GrantedListHead)
865 Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
866 LocalLastReturnedLockInfo = Granted->Lock;
867 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
869 FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo;
870 FileLock->LastReturnedLock = EnumEntry;
871 return &FileLock->LastReturnedLockInfo;
875 EnumEntry = EnumEntry->Flink;
880 //got here? uh no, didn't find our last lock..must have been freed...restart
885 KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
887 return NULL;//no (more) locks
891 /**********************************************************************
893 * FsRtlInitializeFileLock
896 * Called when creating/allocating/initializing FCB
901 FsRtlInitializeFileLock (
902 IN PFILE_LOCK FileLock,
903 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL,
904 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
908 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
909 FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine;
910 FileLock->UnlockRoutine = UnlockRoutine;
911 FileLock->LockInformation = NULL;
916 /**********************************************************************
924 IN PFILE_LOCK FileLock,
925 IN PFILE_OBJECT FileObject,
926 IN PLARGE_INTEGER FileOffset,
927 IN PLARGE_INTEGER Length,
928 IN PEPROCESS Process,
930 IN BOOLEAN FailImmediately, //seems meaningless for fast io
931 IN BOOLEAN ExclusiveLock,
932 OUT PIO_STATUS_BLOCK IoStatus,
933 IN PIRP Irp OPTIONAL,
935 IN BOOLEAN AlreadySynchronized
938 PFILE_LOCK_TOC LockToc;
942 if (FileLock->LockInformation == NULL)
944 ExAcquireFastMutex(&LockTocMutex);
946 if (FileLock->LockInformation == NULL)
948 FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside);
949 LockToc = FileLock->LockInformation;
950 KeInitializeSpinLock(&LockToc->SpinLock);
951 InitializeListHead(&LockToc->GrantedListHead);
952 InitializeListHead(&LockToc->PendingListHead);
953 InitializeListHead(&LockToc->CompletedListHead);
954 InitializeListHead(&LockToc->UnlockedListHead);
956 ExReleaseFastMutex(&LockTocMutex);
959 LockToc = FileLock->LockInformation;
960 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
962 //try add new lock (while holding spin lock)
963 if (FsRtlpAddLock(LockToc,
972 IoStatus->Status = STATUS_SUCCESS;
974 else if (Irp && !FailImmediately)
975 { //failed + irp + no fail = mk. pending
976 //for our cancel routine
977 Irp->Tail.Overlay.DriverContext[0] = (PVOID)FileLock;
978 Irp->Tail.Overlay.DriverContext[1] = (PVOID)LockToc;
979 Irp->Tail.Overlay.DriverContext[2] = Context;
981 IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine);
985 //irp canceled even before we got to queue it
986 if (IoSetCancelRoutine(Irp, NULL))
987 { //Cancel routine will NOT be called: cancel it here
988 IoStatus->Status = STATUS_CANCELLED;
991 { //Cancel routine WILL be called. When we release the lock it will complete the irp
992 //Return pending since we are not completing the irp here
993 Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
994 Irp->IoStatus.Information = 0;
995 InitializeListHead(&Irp->Tail.Overlay.ListEntry);
1000 { //not cancelled: queue irp
1001 IoMarkIrpPending(Irp);
1002 Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
1003 Irp->IoStatus.Information = 0;
1004 InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
1010 IoStatus->Status = STATUS_LOCK_NOT_GRANTED;
1013 KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine
1015 //never pending if no irp;-)
1016 assert(!(IoStatus->Status == STATUS_PENDING && !Irp));
1018 if (IoStatus->Status != STATUS_PENDING)
1020 if (IoStatus->Status == STATUS_SUCCESS)
1022 FsRtlAreThereCurrentFileLocks(FileLock) = TRUE;
1027 Irp->IoStatus.Status = IoStatus->Status;
1028 Irp->IoStatus.Information = 0;
1030 if (FileLock->CompleteLockIrpRoutine)
1031 { //complete irp routine
1033 if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp)))
1035 //CompleteLockIrpRoutine complain: revert changes
1036 FsRtlpUnlockSingle( FileLock,
1043 AlreadySynchronized,
1044 FALSE//CallUnlockRoutine
1049 {//std irp completion
1050 IofCompleteRequest(Irp, IO_NO_INCREMENT);
1055 //NOTE: only fast io seems to care about this return value
1056 return (IoStatus->Status == STATUS_SUCCESS || FailImmediately);
1062 /**********************************************************************
1064 * FsRtlProcessFileLock
1069 FsRtlProcessFileLock (
1070 IN PFILE_LOCK FileLock,
1072 IN PVOID Context OPTIONAL
1075 PIO_STACK_LOCATION Stack;
1077 IO_STATUS_BLOCK LocalIoStatus;
1080 Stack = IoGetCurrentIrpStackLocation(Irp);
1081 Irp->IoStatus.Information = 0;
1083 switch(Stack->MinorFunction)
1087 FsRtlPrivateLock( FileLock,
1089 &Stack->Parameters.LockControl.ByteOffset, //not pointer!
1090 Stack->Parameters.LockControl.Length,
1091 IoGetRequestorProcess(Irp),
1092 Stack->Parameters.LockControl.Key,
1093 Stack->Flags & SL_FAIL_IMMEDIATELY,
1094 Stack->Flags & SL_EXCLUSIVE_LOCK,
1100 return LocalIoStatus.Status;
1102 case IRP_MN_UNLOCK_SINGLE:
1103 Status = FsRtlFastUnlockSingle ( FileLock,
1105 &Stack->Parameters.LockControl.ByteOffset,
1106 Stack->Parameters.LockControl.Length,
1107 IoGetRequestorProcess(Irp),
1108 Stack->Parameters.LockControl.Key,
1113 case IRP_MN_UNLOCK_ALL:
1114 Status = FsRtlFastUnlockAll( FileLock,
1116 IoGetRequestorProcess(Irp),
1120 case IRP_MN_UNLOCK_ALL_BY_KEY:
1121 Status = FsRtlFastUnlockAllByKey ( FileLock,
1123 IoGetRequestorProcess(Irp),
1124 Stack->Parameters.LockControl.Key,
1130 Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
1131 IofCompleteRequest(Irp, IO_NO_INCREMENT);
1135 Irp->IoStatus.Status = Status;
1137 if (FileLock->CompleteLockIrpRoutine )
1139 FileLock->CompleteLockIrpRoutine(Context,Irp);
1143 IofCompleteRequest(Irp,IO_NO_INCREMENT);
1150 /**********************************************************************
1152 * FsRtlUninitializeFileLock
1157 FsRtlUninitializeFileLock (
1158 IN PFILE_LOCK FileLock
1161 PFILE_LOCK_TOC LockToc;
1163 PFILE_LOCK_GRANTED Granted;
1164 PLIST_ENTRY EnumEntry;
1168 if (FileLock->LockInformation == NULL)
1173 LockToc = FileLock->LockInformation;
1175 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
1177 //remove and free granted locks
1178 while (!IsListEmpty(&LockToc->GrantedListHead))
1180 EnumEntry = RemoveTailList(&LockToc->GrantedListHead);
1181 Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry);
1182 ExFreeToNPagedLookasideList(&GrantedLookaside, Granted);
1185 //remove, complete and free all pending locks
1186 while (!IsListEmpty(&LockToc->PendingListHead))
1188 EnumEntry = RemoveTailList(&LockToc->PendingListHead);
1189 Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
1191 if (!IoSetCancelRoutine(Irp, NULL))
1193 //The cancel routine will be called. When we release the lock it will complete the irp.
1194 InitializeListHead(&Irp->Tail.Overlay.ListEntry);
1199 Cancel routine will NOT be called, even though the irp might have been canceled.
1200 Don't care since we'l complete it faster than the cancel routine would have.
1202 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine
1204 Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED;
1206 if (FileLock->CompleteLockIrpRoutine)
1208 FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
1212 IofCompleteRequest(Irp, IO_NO_INCREMENT);
1215 KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
1219 KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
1221 ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc);
1223 FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
1224 FileLock->LockInformation = NULL;
1229 /**********************************************************************
1231 * FsRtlAllocateFileLock
1234 * Only present in NT 5.0 or later.
1235 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1240 FsRtlAllocateFileLock(
1241 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL,
1242 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL
1245 PFILE_LOCK FileLock;
1247 FileLock = ExAllocateFromPagedLookasideList(&LockLookaside);
1249 FsRtlInitializeFileLock(FileLock,
1250 CompleteLockIrpRoutine,
1257 /**********************************************************************
1262 * Only present in NT 5.0 or later.
1263 * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool!
1269 IN PFILE_LOCK FileLock
1274 FsRtlUninitializeFileLock(FileLock);
1275 ExFreeToPagedLookasideList(&LockLookaside, FileLock);