/* $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 <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
-inline BOOLEAN
+__inline BOOLEAN
IsOverlappingLock(
PFILE_LOCK_INFO Lock,
PLARGE_INTEGER StartOffset,
{
if ((ULONGLONG)StartOffset->QuadPart > (ULONGLONG)Lock->EndingByte.QuadPart)
{
- return FALSE;
+ return FALSE;
}
-
+
if ((ULONGLONG)EndOffset->QuadPart < (ULONGLONG)Lock->StartingByte.QuadPart)
{
- return FALSE;
+ return FALSE;
}
-
- return TRUE;
+
+ return TRUE;
}
-inline BOOLEAN
+__inline BOOLEAN
IsSurroundingLock(
PFILE_LOCK_INFO Lock,
PLARGE_INTEGER StartOffset,
PLARGE_INTEGER EndOffset
)
{
- if ((ULONGLONG)StartOffset->QuadPart >= (ULONGLONG)Lock->StartingByte.QuadPart &&
+ if ((ULONGLONG)StartOffset->QuadPart >= (ULONGLONG)Lock->StartingByte.QuadPart &&
(ULONGLONG)EndOffset->QuadPart <= (ULONGLONG)Lock->EndingByte.QuadPart)
{
- return TRUE;
+ return TRUE;
}
-
- return FALSE;
+
+ return FALSE;
}
);
ExInitializeFastMutex(&LockTocMutex);
-
+
}
/**********************************************************************
*
*/
VOID
-STDCALL
+STDCALL
FsRtlpFileLockCancelRoutine(
- IN PDEVICE_OBJECT DeviceObject,
+ IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PKSPIN_LOCK SpinLock;
//don't need this since we have our own sync. protecting irp cancellation
- IoReleaseCancelSpinLock(Irp->CancelIrql);
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
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);
-
+
}
/**********************************************************************
* NAME PRIVATE
* FsRtlpCheckLockForReadOrWriteAccess
*
- * Return:
+ * Return:
* TRUE: can read/write
* FALSE: can't read/write
*/
KIRQL oldirql;
PFILE_LOCK_TOC LockToc;
PFILE_LOCK_GRANTED Granted;
- PLIST_ENTRY EnumEntry;
LARGE_INTEGER EndOffset;
-
+
ASSERT(FileLock);
-
+
LockToc = FileLock->LockInformation;
- if (LockToc == NULL || Length->QuadPart == 0)
+ if (LockToc == NULL || Length->QuadPart == 0)
{
return TRUE;
}
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
+ LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry);
-
//if overlapping
- if(IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset))
+ 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 (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset) )
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
return TRUE;
}
-
+
//else continue searching for conflicts
continue;
}
{
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
BOOLEAN GotUnlockRoutine;
LIST_ENTRY UnlockedListHead;
+ PLIST_ENTRY EnumEntry;
ASSERT(FileLock);
LockToc = FileLock->LockInformation;
InitializeListHead(&UnlockedListHead);
GotUnlockRoutine = FileLock->UnlockRoutine != NULL;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
-
- LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->GrantedListHead, Granted, FILE_LOCK_GRANTED, ListEntry)
+
+ LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry)
{
-
+
if (Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject &&
(!UseKey || (UseKey && Granted->Lock.Key == Key)) )
RemoveEntryList(&Granted->ListEntry);
Unlock = TRUE;
- if (GotUnlockRoutine)
+ if (GotUnlockRoutine)
{
/*
Put on unlocked list and call unlock routine for them afterwards.
*/
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(&UnlockedListHead))
+ while (!IsListEmpty(&UnlockedListHead))
{
EnumEntry = RemoveTailList(&UnlockedListHead);
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
-
+
FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock);
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
}
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;
}
Process,
0, /* Key is ignored */
FALSE, /* Do NOT use Key */
- Context
+ Context
);
}
Process,
Key,
TRUE, /* Use Key */
- Context
+ Context
);
}
IN PVOID Context
)
{
- PLIST_ENTRY EnumEntry;
PFILE_LOCK_GRANTED Granted;
LARGE_INTEGER EndOffset;
-
+
EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
//loop and try to find conflicking locks
- LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
+ LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry)
{
- Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
-
if (IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset))
{
//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)
+ if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
{
//if existing lock surround new lock, we know that no other exclusive lock
//may overlap with our new lock;-D
{
break;
}
-
+
//else keep locking for conflicts
continue;
}
-
- //we found a conflict:
+
+ //we found a conflict:
//we want shared access to an excl. lock OR exlc. access to a shared lock
return FALSE;
}
{
//walk pending list, FIFO order, try 2 complete locks
PLIST_ENTRY EnumEntry;
- PIRP Irp;
+ PIRP Irp, tmp;
PIO_STACK_LOCATION Stack;
LIST_ENTRY CompletedListHead;
-
+
InitializeListHead(&CompletedListHead);
-
- LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->PendingListHead, Irp, IRP, Tail.Overlay.ListEntry)
+
+ LIST_FOR_EACH_SAFE(Irp, tmp, &LockToc->PendingListHead, IRP, Tail.Overlay.ListEntry)
{
Stack = IoGetCurrentIrpStackLocation(Irp);
if (FsRtlpAddLock(LockToc,
Stack->Parameters.LockControl.Key,
Stack->Flags & SL_EXCLUSIVE_LOCK,
Irp->Tail.Overlay.DriverContext[2] //Context
- ) )
+ ) )
{
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
}
KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);
-
+
//complete irp's (if any)
- while (!IsListEmpty(&CompletedListHead))
+ while (!IsListEmpty(&CompletedListHead))
{
EnumEntry = RemoveTailList(&CompletedListHead);
-
+
Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
Irp->IoStatus.Status = STATUS_SUCCESS;
if (FileLock->CompleteLockIrpRoutine(Context, Irp)!=STATUS_SUCCESS)
{
Stack = IoGetCurrentIrpStackLocation(Irp);
-
- //revert
+
+ //revert
FsRtlpUnlockSingle ( FileLock,
Stack->FileObject,
&Stack->Parameters.LockControl.ByteOffset,
{
KIRQL oldirql;
PFILE_LOCK_TOC LockToc;
- PFILE_LOCK_GRANTED Granted;
- PLIST_ENTRY EnumEntry;
+ PFILE_LOCK_GRANTED Granted, tmp;
ASSERT(FileLock);
LockToc = FileLock->LockInformation;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql );
- LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->GrantedListHead, Granted,FILE_LOCK_GRANTED,ListEntry)
+ LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, 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, Context);
if (IsListEmpty(&LockToc->GrantedListHead))
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
-
+
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; //paged data
}
else
PFILE_LOCK_TOC LockToc;
PFILE_LOCK_GRANTED Granted;
PIRP Irp;
- PLIST_ENTRY EnumEntry;
PIO_STACK_LOCATION Stack;
ASSERT(FileLock);
LockToc = FileLock->LockInformation;
- if (LockToc == NULL)
+ if (LockToc == NULL)
{
DPRINT1("No file locks\n");
return;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
- LIST_FOR_EACH(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,
DPRINT1("Dumping pending file locks, FIFO order\n");
- LIST_FOR_EACH(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,
{
/*
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...
*/
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;
KIRQL oldirql;
ASSERT(FileLock);
- if (FileLock->LockInformation == NULL)
+ if (FileLock->LockInformation == NULL)
{
ExAcquireFastMutex(&LockTocMutex);
//still NULL?
Process,
Key,
ExclusiveLock,
- Context
- ) )
+ Context
+ ) )
{
IoStatus->Status = STATUS_SUCCESS;
}
- else if (Irp && !FailImmediately)
- {
+ 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 && IoSetCancelRoutine(Irp, NULL))
- {
+ {
//irp was canceled
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
-
+
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
}
- else
+ else
{
IoStatus->Status = STATUS_LOCK_NOT_GRANTED;
}
//never pending if no 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)
+ if (FileLock->CompleteLockIrpRoutine)
{
- if (FileLock->CompleteLockIrpRoutine(Context,Irp)!=STATUS_SUCCESS)
+ if (FileLock->CompleteLockIrpRoutine(Context,Irp)!=STATUS_SUCCESS)
{
//CompleteLockIrpRoutine complain: revert changes
FsRtlpUnlockSingle( FileLock,
);
}
}
- else
+ else
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
Stack->Parameters.LockControl.Length,
IoGetRequestorProcess(Irp),
Stack->Parameters.LockControl.Key,
- Context,
+ Context,
FALSE);
break;
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
-
+
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return Status;
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;
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)) {
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;
}
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 */
- ExReleaseResource(FcbHeader->Resource);
-
+ ExReleaseResourceLite(FcbHeader->Resource);
+
return;
}
-
+
/* Return...is there some kind of failure we should raise?? */
return;
}