mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 09:16:17 +00:00
filelock.c:
-general cleanup -fix signed -> unsigned comparsion -allow zero length unlocks to complete with success -makes some more wine reg. tests pass ntdef.h: add macros LIST_FOR_EACH and LIST_FOR_EACH_SAFE svn path=/trunk/; revision=12391
This commit is contained in:
parent
f5e28a77d1
commit
c97559f3c5
5 changed files with 258 additions and 233 deletions
|
@ -113,12 +113,5 @@
|
|||
|
||||
#endif /* !__USE_W32API */
|
||||
|
||||
typedef struct _FILE_LOCK_TOC {
|
||||
KSPIN_LOCK SpinLock;
|
||||
LIST_ENTRY GrantedListHead;
|
||||
LIST_ENTRY PendingListHead;
|
||||
LIST_ENTRY CompletedListHead;
|
||||
LIST_ENTRY UnlockedListHead;
|
||||
} FILE_LOCK_TOC, *PFILE_LOCK_TOC;
|
||||
|
||||
#endif /* __INCLUDE_FILE_H */
|
||||
|
|
|
@ -27,9 +27,15 @@ typedef struct _MCB {
|
|||
|
||||
typedef struct _FILE_LOCK_GRANTED {
|
||||
LIST_ENTRY ListEntry;
|
||||
FILE_LOCK_INFO Lock;
|
||||
FILE_LOCK_INFO Lock;
|
||||
PVOID UnlockContext;
|
||||
} FILE_LOCK_GRANTED, *PFILE_LOCK_GRANTED;
|
||||
|
||||
|
||||
typedef struct _FILE_LOCK_TOC {
|
||||
KSPIN_LOCK SpinLock;
|
||||
LIST_ENTRY GrantedListHead;
|
||||
LIST_ENTRY PendingListHead;
|
||||
} FILE_LOCK_TOC, *PFILE_LOCK_TOC;
|
||||
|
||||
#endif /* __INCLUDE_DDK_FSTYPES_H */
|
||||
|
|
|
@ -39,6 +39,20 @@
|
|||
#define SECONDS_TO_100NS(seconds) (((LONGLONG)(seconds)) * MILLIS_TO_100NS(1000L))
|
||||
|
||||
|
||||
/* Helpers for enumarating lists */
|
||||
#define LIST_FOR_EACH(entry, head) \
|
||||
for(entry = (head)->Flink; entry != (head); entry = entry->Flink)
|
||||
|
||||
/*
|
||||
Safe version which saves pointer to the next entry so the current ptr->field entry
|
||||
can be unlinked without corrupting the list. NOTE: Never unlink tmp_entry!!!!!!!!!
|
||||
*/
|
||||
#define LIST_FOR_EACH_SAFE(tmp_entry, head, ptr, type, field) \
|
||||
for ((tmp_entry)=(head)->Flink; (tmp_entry)!=(head) && \
|
||||
((ptr) = CONTAINING_RECORD(tmp_entry,type,field)) && \
|
||||
((tmp_entry) = (tmp_entry)->Flink); )
|
||||
|
||||
|
||||
#ifndef __USE_W32API
|
||||
|
||||
#define ANYSIZE_ARRAY (1)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: filelock.c,v 1.16 2004/12/23 12:30:48 ekohl Exp $
|
||||
/* $Id: filelock.c,v 1.17 2004/12/30 02:30:40 gdalsnes Exp $
|
||||
*
|
||||
* reactos/ntoskrnl/fs/filelock.c
|
||||
*
|
||||
|
@ -13,18 +13,54 @@ 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
|
||||
|
@ -62,6 +98,7 @@ FsRtlpInitFileLockingImplementation(VOID)
|
|||
);
|
||||
|
||||
ExInitializeFastMutex(&LockTocMutex);
|
||||
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -78,28 +115,22 @@ FsRtlpFileLockCancelRoutine(
|
|||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine;
|
||||
if (CompleteLockIrpRoutine)
|
||||
{
|
||||
CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
|
||||
}
|
||||
else
|
||||
{
|
||||
IofCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
}
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
}
|
||||
|
||||
|
@ -107,6 +138,9 @@ FsRtlpFileLockCancelRoutine(
|
|||
* NAME PRIVATE
|
||||
* FsRtlpCheckLockForReadOrWriteAccess
|
||||
*
|
||||
* Return:
|
||||
* TRUE: can read/write
|
||||
* FALSE: can't read/write
|
||||
*/
|
||||
BOOLEAN
|
||||
FASTCALL
|
||||
|
@ -124,8 +158,10 @@ FsRtlpCheckLockForReadOrWriteAccess(
|
|||
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)
|
||||
|
@ -133,15 +169,16 @@ FsRtlpCheckLockForReadOrWriteAccess(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
|
||||
|
||||
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
|
||||
|
||||
EnumEntry = LockToc->GrantedListHead.Flink;
|
||||
while ( EnumEntry != &LockToc->GrantedListHead)
|
||||
LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
|
||||
{
|
||||
Granted = CONTAINING_RECORD(EnumEntry, 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
|
||||
|
@ -152,30 +189,26 @@ FsRtlpCheckLockForReadOrWriteAccess(
|
|||
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;
|
||||
}
|
||||
|
||||
//found conflict
|
||||
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
|
||||
return FALSE;
|
||||
}
|
||||
EnumEntry = EnumEntry->Flink;
|
||||
|
||||
}
|
||||
|
||||
//no conflict
|
||||
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
|
||||
|
||||
if (EnumEntry == &LockToc->GrantedListHead)
|
||||
{ //no conflict
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -206,7 +239,7 @@ FsRtlCheckLockForReadAccess (
|
|||
Stack->Parameters.Read.Key,
|
||||
Stack->FileObject,
|
||||
IoGetRequestorProcess(Irp),
|
||||
TRUE//Read?
|
||||
TRUE /* Read */
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -238,7 +271,7 @@ FsRtlCheckLockForWriteAccess (
|
|||
Stack->Parameters.Write.Key,
|
||||
Stack->FileObject,
|
||||
IoGetRequestorProcess(Irp),
|
||||
FALSE//Read?
|
||||
FALSE /* Read */
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -269,7 +302,7 @@ FsRtlFastCheckLockForRead (
|
|||
Key,
|
||||
FileObject,
|
||||
Process,
|
||||
TRUE//Read?
|
||||
TRUE /* Read */
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -297,7 +330,7 @@ FsRtlFastCheckLockForWrite (
|
|||
Key,
|
||||
FileObject,
|
||||
Process,
|
||||
FALSE//Read?
|
||||
FALSE /* Read */
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -314,8 +347,8 @@ FsRtlpFastUnlockAllByKey(
|
|||
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
|
||||
)
|
||||
{
|
||||
|
@ -325,7 +358,8 @@ FsRtlpFastUnlockAllByKey(
|
|||
PFILE_LOCK_GRANTED Granted;
|
||||
BOOLEAN Unlock = FALSE;
|
||||
//must make local copy since FILE_LOCK struct is allowed to be paged
|
||||
PUNLOCK_ROUTINE GotUnlockRoutine;
|
||||
BOOLEAN GotUnlockRoutine;
|
||||
LIST_ENTRY UnlockedListHead;
|
||||
|
||||
ASSERT(FileLock);
|
||||
LockToc = FileLock->LockInformation;
|
||||
|
@ -335,15 +369,13 @@ FsRtlpFastUnlockAllByKey(
|
|||
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(EnumEntry, &LockToc->GrantedListHead, Granted, FILE_LOCK_GRANTED, ListEntry)
|
||||
{
|
||||
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
|
||||
EnumEntry = EnumEntry->Flink;
|
||||
|
||||
|
||||
if (Granted->Lock.Process == Process &&
|
||||
Granted->Lock.FileObject == FileObject &&
|
||||
(!UseKey || (UseKey && Granted->Lock.Key == Key)) )
|
||||
|
@ -357,7 +389,7 @@ FsRtlpFastUnlockAllByKey(
|
|||
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
|
||||
{
|
||||
|
@ -366,21 +398,23 @@ FsRtlpFastUnlockAllByKey(
|
|||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
|
@ -391,10 +425,10 @@ FsRtlpFastUnlockAllByKey(
|
|||
{
|
||||
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
|
||||
return STATUS_RANGE_NOT_LOCKED;
|
||||
}
|
||||
|
||||
|
@ -416,9 +450,9 @@ FsRtlFastUnlockAll /*ByProcess*/ (
|
|||
return FsRtlpFastUnlockAllByKey( FileLock,
|
||||
FileObject,
|
||||
Process,
|
||||
0, /* Key */
|
||||
0, /* Key is ignored */
|
||||
FALSE, /* Do NOT use Key */
|
||||
Context
|
||||
Context
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -443,7 +477,7 @@ FsRtlFastUnlockAllByKey (
|
|||
Process,
|
||||
Key,
|
||||
TRUE, /* Use Key */
|
||||
Context
|
||||
Context
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -455,7 +489,7 @@ FsRtlFastUnlockAllByKey (
|
|||
* NOTE
|
||||
* Spinlock held at entry !!
|
||||
*/
|
||||
NTSTATUS
|
||||
BOOLEAN
|
||||
FASTCALL
|
||||
FsRtlpAddLock(
|
||||
IN PFILE_LOCK_TOC LockToc,
|
||||
|
@ -464,58 +498,60 @@ FsRtlpAddLock(
|
|||
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;
|
||||
|
||||
EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
|
||||
|
||||
EnumEntry = LockToc->GrantedListHead.Flink;
|
||||
while (EnumEntry != &LockToc->GrantedListHead)
|
||||
//loop and try to find conflicking locks
|
||||
LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
|
||||
{
|
||||
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
|
||||
//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
|
||||
}
|
||||
|
||||
//we found a conflict:
|
||||
//we want shared access to an excl. lock OR exlc. access to a shared lock
|
||||
return FALSE;
|
||||
}
|
||||
EnumEntry = EnumEntry->Flink;
|
||||
}
|
||||
|
||||
if (EnumEntry == &LockToc->GrantedListHead)
|
||||
{//no conflict
|
||||
Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside);
|
||||
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;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -532,19 +568,20 @@ FASTCALL
|
|||
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;
|
||||
PIO_STACK_LOCATION Stack;
|
||||
|
||||
EnumEntry = LockToc->PendingListHead.Blink;
|
||||
while (EnumEntry != &LockToc->PendingListHead)
|
||||
LIST_ENTRY CompletedListHead;
|
||||
|
||||
InitializeListHead(&CompletedListHead);
|
||||
|
||||
LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->PendingListHead, Irp, IRP, Tail.Overlay.ListEntry)
|
||||
{
|
||||
Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry);
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
if (FsRtlpAddLock(LockToc,
|
||||
Stack->FileObject,
|
||||
|
@ -552,55 +589,65 @@ FsRtlpCompletePendingLocks(
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -620,7 +667,6 @@ FsRtlpUnlockSingle(
|
|||
IN PEPROCESS Process,
|
||||
IN ULONG Key,
|
||||
IN PVOID Context OPTIONAL,
|
||||
IN BOOLEAN AlreadySynchronized,
|
||||
IN BOOLEAN CallUnlockRoutine
|
||||
)
|
||||
{
|
||||
|
@ -632,18 +678,16 @@ FsRtlpUnlockSingle(
|
|||
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(EnumEntry, &LockToc->GrantedListHead, Granted,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 &&
|
||||
|
@ -652,12 +696,13 @@ FsRtlpUnlockSingle(
|
|||
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
|
||||
{
|
||||
|
@ -666,14 +711,13 @@ FsRtlpUnlockSingle(
|
|||
|
||||
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);
|
||||
|
@ -710,8 +754,7 @@ FsRtlFastUnlockSingle (
|
|||
Process,
|
||||
Key,
|
||||
Context,
|
||||
AlreadySynchronized,
|
||||
TRUE//CallUnlockRoutine
|
||||
TRUE /* call unlock copletion routine */
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -747,11 +790,10 @@ FsRtlpDumpFileLocks(
|
|||
|
||||
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
|
||||
|
||||
EnumEntry = LockToc->GrantedListHead.Blink;
|
||||
while ( EnumEntry != &LockToc->GrantedListHead)
|
||||
LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
|
||||
{
|
||||
Granted = CONTAINING_RECORD(EnumEntry, 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",
|
||||
Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD",
|
||||
Granted->Lock.StartingByte.QuadPart,
|
||||
|
@ -762,16 +804,13 @@ FsRtlpDumpFileLocks(
|
|||
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(EnumEntry, &LockToc->PendingListHead)
|
||||
{
|
||||
Irp = CONTAINING_RECORD(EnumEntry, 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",
|
||||
|
@ -784,7 +823,6 @@ FsRtlpDumpFileLocks(
|
|||
Stack->FileObject
|
||||
);
|
||||
|
||||
EnumEntry = EnumEntry->Blink;
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
|
||||
|
@ -939,7 +977,7 @@ FsRtlPrivateLock (
|
|||
IN BOOLEAN ExclusiveLock,
|
||||
OUT PIO_STATUS_BLOCK IoStatus,
|
||||
IN PIRP Irp OPTIONAL,
|
||||
IN PVOID Context,
|
||||
IN PVOID Context OPTIONAL,
|
||||
IN BOOLEAN AlreadySynchronized
|
||||
)
|
||||
{
|
||||
|
@ -958,8 +996,6 @@ FsRtlPrivateLock (
|
|||
KeInitializeSpinLock(&LockToc->SpinLock);
|
||||
InitializeListHead(&LockToc->GrantedListHead);
|
||||
InitializeListHead(&LockToc->PendingListHead);
|
||||
InitializeListHead(&LockToc->CompletedListHead);
|
||||
InitializeListHead(&LockToc->UnlockedListHead);
|
||||
}
|
||||
ExReleaseFastMutex(&LockTocMutex);
|
||||
}
|
||||
|
@ -974,43 +1010,36 @@ FsRtlPrivateLock (
|
|||
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;
|
||||
{
|
||||
//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)
|
||||
{
|
||||
//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);
|
||||
}
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -1034,11 +1063,9 @@ FsRtlPrivateLock (
|
|||
{
|
||||
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(Context,Irp)!=STATUS_SUCCESS)
|
||||
{
|
||||
//CompleteLockIrpRoutine complain: revert changes
|
||||
FsRtlpUnlockSingle( FileLock,
|
||||
|
@ -1047,15 +1074,14 @@ FsRtlPrivateLock (
|
|||
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);
|
||||
{
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1115,7 +1141,7 @@ FsRtlProcessFileLock (
|
|||
Stack->Parameters.LockControl.Length,
|
||||
IoGetRequestorProcess(Irp),
|
||||
Stack->Parameters.LockControl.Key,
|
||||
Context,
|
||||
Context,
|
||||
FALSE);
|
||||
break;
|
||||
|
||||
|
@ -1123,7 +1149,7 @@ FsRtlProcessFileLock (
|
|||
Status = FsRtlFastUnlockAll( FileLock,
|
||||
Stack->FileObject,
|
||||
IoGetRequestorProcess(Irp),
|
||||
Context);
|
||||
Context );
|
||||
break;
|
||||
|
||||
case IRP_MN_UNLOCK_ALL_BY_KEY:
|
||||
|
@ -1131,26 +1157,21 @@ FsRtlProcessFileLock (
|
|||
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;
|
||||
|
||||
if (FileLock->CompleteLockIrpRoutine )
|
||||
{
|
||||
FileLock->CompleteLockIrpRoutine(Context,Irp);
|
||||
}
|
||||
else
|
||||
{
|
||||
IofCompleteRequest(Irp,IO_NO_INCREMENT);
|
||||
}
|
||||
Irp->IoStatus.Status = Status;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -1202,28 +1223,17 @@ FsRtlUninitializeFileLock (
|
|||
{
|
||||
//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);
|
||||
|
@ -1311,4 +1321,5 @@ FsRtlReleaseFile(
|
|||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef __INCLUDE_INTERNAL_IFS_H
|
||||
#define __INCLUDE_INTERNAL_IFS_H
|
||||
/* $Id: ifs.h,v 1.6 2003/08/14 18:30:28 silverblade Exp $ */
|
||||
/* $Id: ifs.h,v 1.7 2004/12/30 02:30:40 gdalsnes Exp $ */
|
||||
|
||||
#include <ddk/ntifs.h>
|
||||
#include <ntos.h>
|
||||
|
@ -38,7 +38,7 @@ FsRtlpFastUnlockAllByKey(
|
|||
IN PVOID Context OPTIONAL
|
||||
);
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
BOOLEAN FASTCALL
|
||||
FsRtlpAddLock(
|
||||
IN PFILE_LOCK_TOC LockToc,
|
||||
IN PFILE_OBJECT FileObject,
|
||||
|
@ -46,14 +46,16 @@ FsRtlpAddLock(
|
|||
IN PLARGE_INTEGER Length,
|
||||
IN PEPROCESS Process,
|
||||
IN ULONG Key,
|
||||
IN BOOLEAN ExclusiveLock
|
||||
IN BOOLEAN ExclusiveLock,
|
||||
IN PVOID UnlockContext
|
||||
);
|
||||
|
||||
VOID FASTCALL
|
||||
FsRtlpCompletePendingLocks(
|
||||
IN PFILE_LOCK FileLock,
|
||||
IN PFILE_LOCK_TOC LockToc,
|
||||
IN OUT PKIRQL oldirql
|
||||
IN OUT PKIRQL oldirql,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
|
@ -65,7 +67,6 @@ FsRtlpUnlockSingle(
|
|||
IN PEPROCESS Process,
|
||||
IN ULONG Key,
|
||||
IN PVOID Context OPTIONAL,
|
||||
IN BOOLEAN AlreadySynchronized,
|
||||
IN BOOLEAN CallUnlockRoutine
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue