-/* $Id: filelock.c,v 1.8 2003/07/10 06:27:13 royce Exp $
+/* $Id$
*
- * reactos/ntoskrnl/fs/filelock.c
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/fs/filelock.c
+ * PURPOSE: No purpose listed.
*
+ * PROGRAMMERS: No programmer listed.
*/
-#include <ddk/ntddk.h>
-#include <internal/ifs.h>
-#include <ddk/ntifs.h>
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, FsRtlpInitFileLockingImplementation)
+#endif
+
+
/*
NOTE:
I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
the lists.
+UPDATE: I'm not sure about this! -Gunnar
*/
-#define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
-#define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1)
-#define REQUEST_START_OFF (FileOffset->QuadPart)
-#define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
-
FAST_MUTEX LockTocMutex;
NPAGED_LOOKASIDE_LIST GrantedLookaside;
NPAGED_LOOKASIDE_LIST LockTocLookaside;
PAGED_LOOKASIDE_LIST LockLookaside;
+
+
+__inline BOOLEAN
+IsOverlappingLock(
+ PFILE_LOCK_INFO Lock,
+ PLARGE_INTEGER StartOffset,
+ PLARGE_INTEGER EndOffset
+ )
+{
+ if ((ULONGLONG)StartOffset->QuadPart > (ULONGLONG)Lock->EndingByte.QuadPart)
+ {
+ return FALSE;
+ }
+
+ if ((ULONGLONG)EndOffset->QuadPart < (ULONGLONG)Lock->StartingByte.QuadPart)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+__inline BOOLEAN
+IsSurroundingLock(
+ PFILE_LOCK_INFO Lock,
+ PLARGE_INTEGER StartOffset,
+ PLARGE_INTEGER EndOffset
+ )
+{
+ if ((ULONGLONG)StartOffset->QuadPart >= (ULONGLONG)Lock->StartingByte.QuadPart &&
+ (ULONGLONG)EndOffset->QuadPart <= (ULONGLONG)Lock->EndingByte.QuadPart)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/**********************************************************************
* NAME PRIVATE
* FsRtlpInitFileLockingImplementation
*
*/
VOID
-STDCALL
+STDCALL INIT_FUNCTION
FsRtlpInitFileLockingImplementation(VOID)
{
ExInitializeNPagedLookasideList( &LockTocLookaside,
);
ExInitializeFastMutex(&LockTocMutex);
+
}
/**********************************************************************
*
*/
VOID
-STDCALL
+STDCALL
FsRtlpFileLockCancelRoutine(
- IN PDEVICE_OBJECT DeviceObject,
+ IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KIRQL oldIrql;
PKSPIN_LOCK SpinLock;
- PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine;
//don't need this since we have our own sync. protecting irp cancellation
- IoReleaseCancelSpinLock(Irp->CancelIrql);
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
- SpinLock = &((PFILE_LOCK_TOC)Irp->Tail.Overlay.DriverContext[1])->SpinLock;
+ SpinLock = Irp->Tail.Overlay.DriverContext[3];
KeAcquireSpinLock(SpinLock, &oldIrql);
+
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
KeReleaseSpinLock(SpinLock, oldIrql);
Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
- CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine;
- if (CompleteLockIrpRoutine)
- {
- CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
- }
- else
- {
- IofCompleteRequest(Irp, IO_NO_INCREMENT);
- }
-
}
/**********************************************************************
* NAME PRIVATE
* FsRtlpCheckLockForReadOrWriteAccess
*
+ * Return:
+ * TRUE: can read/write
+ * FALSE: can't read/write
*/
BOOLEAN
FASTCALL
KIRQL oldirql;
PFILE_LOCK_TOC LockToc;
PFILE_LOCK_GRANTED Granted;
- PLIST_ENTRY EnumEntry;
+ LARGE_INTEGER EndOffset;
+
+ ASSERT(FileLock);
- assert(FileLock);
LockToc = FileLock->LockInformation;
- if (LockToc == NULL || Length->QuadPart == 0)
+ if (LockToc == NULL || Length->QuadPart == 0)
{
return TRUE;
}
+ EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
+
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- EnumEntry = LockToc->GrantedListHead.Flink;
- while ( EnumEntry != &LockToc->GrantedListHead)
+ LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry );
//if overlapping
- if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
- REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
+ if(IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset))
{
//No read conflict if (shared lock) OR (exclusive + our lock)
//No write conflict if exclusive lock AND our lock
if ((Read && !Granted->Lock.ExclusiveLock) ||
- (Granted->Lock.ExclusiveLock &&
+ (Granted->Lock.ExclusiveLock &&
Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject &&
- Granted->Lock.Key == Key ) )
+ Granted->Lock.Key == Key ) )
{
//AND if lock surround request region, stop searching and grant
- if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
- REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
+ if (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset) )
{
- EnumEntry = &LockToc->GrantedListHead;//indicate no conflict
- break;
+ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+ return TRUE;
}
+
//else continue searching for conflicts
+ continue;
}
- else //conflict
- {
- break;
- }
- }
- EnumEntry = EnumEntry->Flink;
- }
- KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+ //found conflict
+ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+ return FALSE;
+ }
- if (EnumEntry == &LockToc->GrantedListHead)
- { //no conflict
- return TRUE;
}
- return FALSE;
+ //no conflict
+ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+ return TRUE;
}
Stack->Parameters.Read.Key,
Stack->FileObject,
IoGetRequestorProcess(Irp),
- TRUE//Read?
+ TRUE /* Read */
);
}
Stack->Parameters.Write.Key,
Stack->FileObject,
IoGetRequestorProcess(Irp),
- FALSE//Read?
+ FALSE /* Read */
);
}
Key,
FileObject,
Process,
- TRUE//Read?
+ TRUE /* Read */
);
}
Key,
FileObject,
Process,
- FALSE//Read?
+ FALSE /* Read */
);
}
IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject,
IN PEPROCESS Process,
- IN DWORD Key, /* FIXME: guess */
- IN BOOLEAN UseKey, /* FIXME: guess */
+ IN DWORD Key,
+ IN BOOLEAN UseKey,
IN PVOID Context OPTIONAL
)
{
KIRQL oldirql;
PFILE_LOCK_TOC LockToc;
- PLIST_ENTRY EnumEntry;
- PFILE_LOCK_GRANTED Granted;
+ PFILE_LOCK_GRANTED Granted, tmp;
BOOLEAN Unlock = FALSE;
//must make local copy since FILE_LOCK struct is allowed to be paged
- PUNLOCK_ROUTINE GotUnlockRoutine;
+ BOOLEAN GotUnlockRoutine;
+ LIST_ENTRY UnlockedListHead;
+ PLIST_ENTRY EnumEntry;
- assert(FileLock);
+ ASSERT(FileLock);
LockToc = FileLock->LockInformation;
if (LockToc == NULL)
return STATUS_RANGE_NOT_LOCKED;
}
- GotUnlockRoutine = FileLock->UnlockRoutine;
+ InitializeListHead(&UnlockedListHead);
+ GotUnlockRoutine = FileLock->UnlockRoutine != NULL;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- EnumEntry = LockToc->GrantedListHead.Flink;
- while (EnumEntry != &LockToc->GrantedListHead )
+ LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
- EnumEntry = EnumEntry->Flink;
if (Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject &&
RemoveEntryList(&Granted->ListEntry);
Unlock = TRUE;
- if (GotUnlockRoutine)
+ if (GotUnlockRoutine)
{
/*
Put on unlocked list and call unlock routine for them afterwards.
This way we don't have to restart enum after each call
*/
- InsertHeadList(&LockToc->UnlockedListHead,&Granted->ListEntry);
+ InsertHeadList(&UnlockedListHead,&Granted->ListEntry);
}
- else
+ else
{
- ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
+ ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
}
}
}
+ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+
if (Unlock)
{
//call unlock routine for each unlocked lock (if any)
- while (!IsListEmpty(&LockToc->UnlockedListHead))
+ while (!IsListEmpty(&UnlockedListHead))
{
- EnumEntry = RemoveTailList(&LockToc->UnlockedListHead);
+ EnumEntry = RemoveTailList(&UnlockedListHead);
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
- KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
- FileLock->UnlockRoutine(Context,&Granted->Lock);
+
+ FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock);
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
- KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
}
//NOTE: holding spinlock while calling this
- FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
+ KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
+ FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context);
- if (IsListEmpty(&LockToc->GrantedListHead))
+ if (IsListEmpty(&LockToc->GrantedListHead))
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
}
+
return STATUS_SUCCESS;
}
- KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
return STATUS_RANGE_NOT_LOCKED;
}
return FsRtlpFastUnlockAllByKey( FileLock,
FileObject,
Process,
- 0, /* Key */
+ 0, /* Key is ignored */
FALSE, /* Do NOT use Key */
Context
);
* NOTE
* Spinlock held at entry !!
*/
-NTSTATUS
+BOOLEAN
FASTCALL
FsRtlpAddLock(
IN PFILE_LOCK_TOC LockToc,
IN PLARGE_INTEGER Length,
IN PEPROCESS Process,
IN ULONG Key,
- IN BOOLEAN ExclusiveLock
+ IN BOOLEAN ExclusiveLock,
+ IN PVOID Context
)
{
- PLIST_ENTRY EnumEntry;
PFILE_LOCK_GRANTED Granted;
+ LARGE_INTEGER EndOffset;
- EnumEntry = LockToc->GrantedListHead.Flink;
- while (EnumEntry != &LockToc->GrantedListHead)
+ EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
+
+ //loop and try to find conflicking locks
+ LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
- //if overlapping
- if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
- REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
+ if (IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset))
{
- //never conflict if shared lock and we want to add a shared lock
- if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
+ //we found a locks that overlap with the new lock
+
+ //if both locks are shared, we might have a fast path outa here...
+ if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
{
- //AND if lock surround region, stop searching and insert lock
- if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
- REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
+ //if existing lock surround new lock, we know that no other exclusive lock
+ //may overlap with our new lock;-D
+ if (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset))
{
- EnumEntry = &LockToc->GrantedListHead;
break;
}
+
//else keep locking for conflicts
+ continue;
}
- else
- {//conflict if we want share access to excl. lock OR exlc. access to shared lock
- break;//FAIL
- }
- }
- EnumEntry = EnumEntry->Flink;
- }
- if (EnumEntry == &LockToc->GrantedListHead)
- {//no conflict
- Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside);
-
- Granted->Lock.StartingByte = *FileOffset;
- Granted->Lock.Length = *Length;
- Granted->Lock.ExclusiveLock = ExclusiveLock;
- Granted->Lock.Key = Key;
- Granted->Lock.FileObject = FileObject;
- Granted->Lock.Process = Process;
- Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF;
-
- InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry);
- return TRUE;
+ //we found a conflict:
+ //we want shared access to an excl. lock OR exlc. access to a shared lock
+ return FALSE;
+ }
}
- return FALSE;
-
+ Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside);
+
+ //starting offset
+ Granted->Lock.StartingByte = *FileOffset;
+ Granted->Lock.Length = *Length;
+ Granted->Lock.ExclusiveLock = ExclusiveLock;
+ Granted->Lock.Key = Key;
+ Granted->Lock.FileObject = FileObject;
+ Granted->Lock.Process = Process;
+ //ending offset
+ Granted->Lock.EndingByte = EndOffset;
+ Granted->UnlockContext = Context;
+
+ InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry);
+ return TRUE;
}
FsRtlpCompletePendingLocks(
IN PFILE_LOCK FileLock,
IN PFILE_LOCK_TOC LockToc,
- IN OUT PKIRQL oldirql
+ IN OUT PKIRQL oldirql,
+ IN PVOID Context
)
{
//walk pending list, FIFO order, try 2 complete locks
PLIST_ENTRY EnumEntry;
- PIRP Irp;
+ PIRP Irp, tmp;
PIO_STACK_LOCATION Stack;
+ LIST_ENTRY CompletedListHead;
- EnumEntry = LockToc->PendingListHead.Blink;
- while (EnumEntry != &LockToc->PendingListHead)
- {
- Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry);
+ InitializeListHead(&CompletedListHead);
+ LIST_FOR_EACH_SAFE(Irp, tmp, &LockToc->PendingListHead, IRP, Tail.Overlay.ListEntry)
+ {
Stack = IoGetCurrentIrpStackLocation(Irp);
if (FsRtlpAddLock(LockToc,
Stack->FileObject,
Stack->Parameters.LockControl.Length,
IoGetRequestorProcess(Irp),
Stack->Parameters.LockControl.Key,
- Stack->Flags & SL_EXCLUSIVE_LOCK
- ) )
+ Stack->Flags & SL_EXCLUSIVE_LOCK,
+ Irp->Tail.Overlay.DriverContext[2] //Context
+ ) )
{
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
if (!IoSetCancelRoutine(Irp, NULL))
{
- /*
- Cancel routine WILL be called after we release the spinlock. It will try to remove
- the irp from the list and cancel/complete this irp. Since we allready removed it,
- make its ListEntry point to itself.
- */
+ //irp is canceled and cancelroutine will run when we release the lock
InitializeListHead(&Irp->Tail.Overlay.ListEntry);
+ continue;
}
- else
- {
- /*
- Cancel routine will NOT be called, canceled or not.
- Put on completed list and complete them all afterwards.
- This way we don't have to restart enum after each completion.
- */
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- InsertHeadList(&LockToc->CompletedListHead,&Irp->Tail.Overlay.ListEntry);
- }
+ /*
+ Put on completed list and complete them all afterwards.
+ This way we don't have to restart enum after each completion.
+ */
+ InsertHeadList(&CompletedListHead, &Irp->Tail.Overlay.ListEntry);
}
- EnumEntry = EnumEntry->Blink;
}
+ KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);
+
//complete irp's (if any)
- while (!IsListEmpty(&LockToc->CompletedListHead))
+ while (!IsListEmpty(&CompletedListHead))
{
- EnumEntry = RemoveTailList(&LockToc->CompletedListHead);
- KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine
+ EnumEntry = RemoveTailList(&CompletedListHead);
+
Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
if (FileLock->CompleteLockIrpRoutine)
{
- FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
+ if (FileLock->CompleteLockIrpRoutine(Context, Irp)!=STATUS_SUCCESS)
+ {
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ //revert
+ FsRtlpUnlockSingle ( FileLock,
+ Stack->FileObject,
+ &Stack->Parameters.LockControl.ByteOffset,
+ Stack->Parameters.LockControl.Length,
+ IoGetRequestorProcess(Irp),
+ Stack->Parameters.LockControl.Key,
+ NULL, /* unused context */
+ FALSE /* don't call unlock copletion rout.*/
+ );
+ }
}
else
{
- IofCompleteRequest(Irp, IO_NO_INCREMENT);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
- KeAcquireSpinLock(&LockToc->SpinLock, oldirql);
}
+ KeAcquireSpinLock(&LockToc->SpinLock, oldirql);
}
IN PEPROCESS Process,
IN ULONG Key,
IN PVOID Context OPTIONAL,
- IN BOOLEAN AlreadySynchronized,
IN BOOLEAN CallUnlockRoutine
)
{
KIRQL oldirql;
PFILE_LOCK_TOC LockToc;
- PFILE_LOCK_GRANTED Granted;
- PLIST_ENTRY EnumEntry;
+ PFILE_LOCK_GRANTED Granted, tmp;
- assert(FileLock);
+ ASSERT(FileLock);
LockToc = FileLock->LockInformation;
- if (LockToc == NULL || Length->QuadPart == 0)
+ if (LockToc == NULL)
{
return STATUS_RANGE_NOT_LOCKED;
}
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql );
- EnumEntry = LockToc->GrantedListHead.Flink;
- while (EnumEntry != &LockToc->GrantedListHead)
+ LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED,ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
//must be exact match
if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart &&
Length->QuadPart == Granted->Lock.Length.QuadPart &&
Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject &&
- Granted->Lock.Key == Key)
+ Granted->Lock.Key == Key)
{
RemoveEntryList(&Granted->ListEntry);
- FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
+ FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context);
if (IsListEmpty(&LockToc->GrantedListHead))
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
- FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
+
+ FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; //paged data
}
else
{
if (FileLock->UnlockRoutine && CallUnlockRoutine)
{
- FileLock->UnlockRoutine(Context,&Granted->Lock);
+ FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock);
}
- ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
+ ExFreeToNPagedLookasideList(&GrantedLookaside, Granted);
return STATUS_SUCCESS;
}
- EnumEntry = EnumEntry->Flink;
}
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
Process,
Key,
Context,
- AlreadySynchronized,
- TRUE//CallUnlockRoutine
+ TRUE /* call unlock copletion routine */
);
}
* FsRtlpDumpFileLocks
*
* NOTE: used for testing and debugging
- *
- * @implemented
*/
VOID
FASTCALL
PFILE_LOCK_TOC LockToc;
PFILE_LOCK_GRANTED Granted;
PIRP Irp;
- PLIST_ENTRY EnumEntry;
PIO_STACK_LOCATION Stack;
- assert(FileLock);
+ ASSERT(FileLock);
LockToc = FileLock->LockInformation;
- if (LockToc == NULL)
+ if (LockToc == NULL)
{
DPRINT1("No file locks\n");
return;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- EnumEntry = LockToc->GrantedListHead.Blink;
- while ( EnumEntry != &LockToc->GrantedListHead)
+ LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED , ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry );
-
- DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
+ DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD",
Granted->Lock.StartingByte.QuadPart,
Granted->Lock.Length.QuadPart,
Granted->Lock.FileObject
);
- EnumEntry = EnumEntry->Blink;
}
DPRINT1("Dumping pending file locks, FIFO order\n");
- EnumEntry = LockToc->PendingListHead.Blink;
- while ( EnumEntry != &LockToc->PendingListHead)
+ LIST_FOR_EACH(Irp, &LockToc->PendingListHead, IRP , Tail.Overlay.ListEntry)
{
- Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry );
-
Stack = IoGetCurrentIrpStackLocation(Irp);
- DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
+ DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n",
(Stack->Flags & SL_EXCLUSIVE_LOCK) ? "EXCL" : "SHRD",
Stack->Parameters.LockControl.ByteOffset.QuadPart,
Stack->Parameters.LockControl.Length->QuadPart,
Stack->FileObject
);
- EnumEntry = EnumEntry->Blink;
}
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
{
/*
Messy enumeration of granted locks.
- What our last ptr. in LastReturnedLock points at, might have been freed between
+ What our last ptr. in LastReturnedLock points at, might have been freed between
calls, so we have to scan thru the list every time, searching for our last lock.
If it's not there anymore, restart the enumeration...
*/
FILE_LOCK_INFO LocalLastReturnedLockInfo;
PVOID LocalLastReturnedLock;
- assert(FileLock);
+ ASSERT(FileLock);
LockToc = FileLock->LockInformation;
if (LockToc == NULL)
{
FileLock->LastReturnedLock = EnumEntry;
return &FileLock->LastReturnedLockInfo;
}
- else
+ else
{
KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
return NULL;
}
//else: continue enum
- while (EnumEntry != &LockToc->GrantedListHead)
+ while (EnumEntry != &LockToc->GrantedListHead)
{
//found previous lock?
- if (EnumEntry == LocalLastReturnedLock)
+ if (EnumEntry == LocalLastReturnedLock)
{
FoundPrevious = TRUE;
//get next
EnumEntry = EnumEntry->Flink;
}
- if (!FoundPrevious)
+ if (!FoundPrevious)
{
//got here? uh no, didn't find our last lock..must have been freed...restart
Restart = TRUE;
IN BOOLEAN ExclusiveLock,
OUT PIO_STATUS_BLOCK IoStatus,
IN PIRP Irp OPTIONAL,
- IN PVOID Context,
+ IN PVOID Context OPTIONAL,
IN BOOLEAN AlreadySynchronized
)
{
PFILE_LOCK_TOC LockToc;
KIRQL oldirql;
- assert(FileLock);
- if (FileLock->LockInformation == NULL)
+ ASSERT(FileLock);
+ if (FileLock->LockInformation == NULL)
{
ExAcquireFastMutex(&LockTocMutex);
//still NULL?
KeInitializeSpinLock(&LockToc->SpinLock);
InitializeListHead(&LockToc->GrantedListHead);
InitializeListHead(&LockToc->PendingListHead);
- InitializeListHead(&LockToc->CompletedListHead);
- InitializeListHead(&LockToc->UnlockedListHead);
}
ExReleaseFastMutex(&LockTocMutex);
}
Length,
Process,
Key,
- ExclusiveLock
- ) )
+ ExclusiveLock,
+ Context
+ ) )
{
IoStatus->Status = STATUS_SUCCESS;
}
- else if (Irp && !FailImmediately)
- { //failed + irp + no fail = mk. pending
- //for our cancel routine
- Irp->Tail.Overlay.DriverContext[0] = (PVOID)FileLock;
- Irp->Tail.Overlay.DriverContext[1] = (PVOID)LockToc;
+ else if (Irp && !FailImmediately)
+ {
+ //failed + irp + no fail = make. pending
+
+ Irp->Tail.Overlay.DriverContext[3] = &LockToc->SpinLock;
Irp->Tail.Overlay.DriverContext[2] = Context;
IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine);
-
- if (Irp->Cancel)
+ if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
{
- //irp canceled even before we got to queue it
- if (IoSetCancelRoutine(Irp, NULL))
- { //Cancel routine will NOT be called: cancel it here
- IoStatus->Status = STATUS_CANCELLED;
- }
- else
- { //Cancel routine WILL be called. When we release the lock it will complete the irp
- //Return pending since we are not completing the irp here
- Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
- Irp->IoStatus.Information = 0;
- InitializeListHead(&Irp->Tail.Overlay.ListEntry);
- }
-
+ //irp was canceled
+ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return TRUE;
}
- else
- { //not cancelled: queue irp
- IoMarkIrpPending(Irp);
+
+ IoMarkIrpPending(Irp);
Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
Irp->IoStatus.Information = 0;
- InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
- }
+ InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
}
- else
+ else
{
IoStatus->Status = STATUS_LOCK_NOT_GRANTED;
}
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine
//never pending if no irp;-)
- assert(!(IoStatus->Status == STATUS_PENDING && !Irp));
+ ASSERT(!(IoStatus->Status == STATUS_PENDING && !Irp));
- if (IoStatus->Status != STATUS_PENDING)
+ if (IoStatus->Status != STATUS_PENDING)
{
- if (IoStatus->Status == STATUS_SUCCESS)
+ if (IoStatus->Status == STATUS_SUCCESS)
{
FsRtlAreThereCurrentFileLocks(FileLock) = TRUE;
}
- if (Irp)
+ if (Irp)
{
Irp->IoStatus.Status = IoStatus->Status;
Irp->IoStatus.Information = 0;
-
- if (FileLock->CompleteLockIrpRoutine)
- { //complete irp routine
-
- if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp)))
+ if (FileLock->CompleteLockIrpRoutine)
+ {
+ if (FileLock->CompleteLockIrpRoutine(Context,Irp)!=STATUS_SUCCESS)
{
//CompleteLockIrpRoutine complain: revert changes
FsRtlpUnlockSingle( FileLock,
Length,
Process,
Key,
- Context,
- AlreadySynchronized,
- FALSE//CallUnlockRoutine
+ NULL, /* context */
+ FALSE /* don't call unlock copletion routine */
);
}
}
- else
- {//std irp completion
- IofCompleteRequest(Irp, IO_NO_INCREMENT);
+ else
+ {
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
}
NTSTATUS Status;
IO_STATUS_BLOCK LocalIoStatus;
- assert(FileLock);
+ ASSERT(FileLock);
Stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
Status = FsRtlFastUnlockAll( FileLock,
Stack->FileObject,
IoGetRequestorProcess(Irp),
- Context);
+ Context );
break;
case IRP_MN_UNLOCK_ALL_BY_KEY:
Stack->FileObject,
IoGetRequestorProcess(Irp),
Stack->Parameters.LockControl.Key,
- Context);
+ Context );
break;
default:
Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
- IofCompleteRequest(Irp, IO_NO_INCREMENT);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
+
Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
- if (FileLock->CompleteLockIrpRoutine )
- {
- FileLock->CompleteLockIrpRoutine(Context,Irp);
- }
- else
- {
- IofCompleteRequest(Irp,IO_NO_INCREMENT);
- }
+ IoCompleteRequest(Irp,IO_NO_INCREMENT);
return Status;
}
PLIST_ENTRY EnumEntry;
KIRQL oldirql;
- assert(FileLock);
+ ASSERT(FileLock);
if (FileLock->LockInformation == NULL)
{
return;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
//remove and free granted locks
- while (!IsListEmpty(&LockToc->GrantedListHead))
+ while (!IsListEmpty(&LockToc->GrantedListHead))
{
EnumEntry = RemoveTailList(&LockToc->GrantedListHead);
Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry);
}
//remove, complete and free all pending locks
- while (!IsListEmpty(&LockToc->PendingListHead))
+ while (!IsListEmpty(&LockToc->PendingListHead))
{
EnumEntry = RemoveTailList(&LockToc->PendingListHead);
Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
if (!IoSetCancelRoutine(Irp, NULL))
- {
+ {
//The cancel routine will be called. When we release the lock it will complete the irp.
InitializeListHead(&Irp->Tail.Overlay.ListEntry);
+ continue;
}
- else
- {
- /*
- Cancel routine will NOT be called, even though the irp might have been canceled.
- Don't care since we'l complete it faster than the cancel routine would have.
- */
- KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine
- Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED;
-
- if (FileLock->CompleteLockIrpRoutine)
- {
- FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
- }
- else
- {
- IofCompleteRequest(Irp, IO_NO_INCREMENT);
- }
+ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
+
+ Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- }
}
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
IN PFILE_LOCK FileLock
)
{
- assert(FileLock);
+ ASSERT(FileLock);
FsRtlUninitializeFileLock(FileLock);
ExFreeToPagedLookasideList(&LockLookaside, FileLock);
}
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+FsRtlAcquireFileExclusive(
+ IN PFILE_OBJECT FileObject
+ )
+{
+ PFAST_IO_DISPATCH FastDispatch;
+ PDEVICE_OBJECT DeviceObject;
+ PFSRTL_COMMON_FCB_HEADER FcbHeader;
+
+ /* Get the Device Object */
+ DeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
+
+ /* Check if we have to do a Fast I/O Dispatch */
+ if ((FastDispatch = DeviceObject->DriverObject->FastIoDispatch)) {
+
+ /* Call the Fast I/O Routine */
+ if (FastDispatch->AcquireFileForNtCreateSection) {
+ FastDispatch->AcquireFileForNtCreateSection(FileObject);
+ }
+
+ return;
+ }
+
+ /* Do a normal acquire */
+ if ((FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)) {
+
+ /* Use a Resource Acquire */
+ ExAcquireResourceExclusive(FcbHeader->Resource, TRUE);
+
+ return;
+ }
+
+ /* Return...is there some kind of failure we should raise?? */
+ return;
+}
+
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+FsRtlReleaseFile(
+ IN PFILE_OBJECT FileObject
+ )
+{
+ PFAST_IO_DISPATCH FastDispatch;
+ PDEVICE_OBJECT DeviceObject;
+ PFSRTL_COMMON_FCB_HEADER FcbHeader;
+
+ /* Get the Device Object */
+ DeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
+
+ /* Check if we have to do a Fast I/O Dispatch */
+ if ((FastDispatch = DeviceObject->DriverObject->FastIoDispatch)) {
+
+ /* Use Fast I/O */
+ if (FastDispatch->ReleaseFileForNtCreateSection) {
+ FastDispatch->ReleaseFileForNtCreateSection(FileObject);
+ }
+
+ return;
+ }
+
+ /* Do a normal acquire */
+ if ((FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)) {
+
+ /* Use a Resource Release */
+ ExReleaseResourceLite(FcbHeader->Resource);
+
+ return;
+ }
+
+ /* Return...is there some kind of failure we should raise?? */
+ return;
+}
+
+
/* EOF */