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:
Gunnar Dalsnes 2004-12-30 02:30:40 +00:00
parent f5e28a77d1
commit c97559f3c5
5 changed files with 258 additions and 233 deletions

View file

@ -113,12 +113,5 @@
#endif /* !__USE_W32API */ #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 */ #endif /* __INCLUDE_FILE_H */

View file

@ -28,8 +28,14 @@ typedef struct _MCB {
typedef struct _FILE_LOCK_GRANTED { typedef struct _FILE_LOCK_GRANTED {
LIST_ENTRY ListEntry; LIST_ENTRY ListEntry;
FILE_LOCK_INFO Lock; FILE_LOCK_INFO Lock;
PVOID UnlockContext;
} FILE_LOCK_GRANTED, *PFILE_LOCK_GRANTED; } 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 */ #endif /* __INCLUDE_DDK_FSTYPES_H */

View file

@ -39,6 +39,20 @@
#define SECONDS_TO_100NS(seconds) (((LONGLONG)(seconds)) * MILLIS_TO_100NS(1000L)) #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 #ifndef __USE_W32API
#define ANYSIZE_ARRAY (1) #define ANYSIZE_ARRAY (1)

View file

@ -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 * reactos/ntoskrnl/fs/filelock.c
* *
@ -13,18 +13,54 @@ NOTE:
I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
the lists. 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; FAST_MUTEX LockTocMutex;
NPAGED_LOOKASIDE_LIST GrantedLookaside; NPAGED_LOOKASIDE_LIST GrantedLookaside;
NPAGED_LOOKASIDE_LIST LockTocLookaside; NPAGED_LOOKASIDE_LIST LockTocLookaside;
PAGED_LOOKASIDE_LIST LockLookaside; 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 * NAME PRIVATE
* FsRtlpInitFileLockingImplementation * FsRtlpInitFileLockingImplementation
@ -62,6 +98,7 @@ FsRtlpInitFileLockingImplementation(VOID)
); );
ExInitializeFastMutex(&LockTocMutex); ExInitializeFastMutex(&LockTocMutex);
} }
/********************************************************************** /**********************************************************************
@ -78,28 +115,22 @@ FsRtlpFileLockCancelRoutine(
{ {
KIRQL oldIrql; KIRQL oldIrql;
PKSPIN_LOCK SpinLock; PKSPIN_LOCK SpinLock;
PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine;
//don't need this since we have our own sync. protecting irp cancellation //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); KeAcquireSpinLock(SpinLock, &oldIrql);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry); RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(SpinLock, oldIrql); KeReleaseSpinLock(SpinLock, oldIrql);
Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine; IoCompleteRequest(Irp, IO_NO_INCREMENT);
if (CompleteLockIrpRoutine)
{
CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
}
else
{
IofCompleteRequest(Irp, IO_NO_INCREMENT);
}
} }
@ -107,6 +138,9 @@ FsRtlpFileLockCancelRoutine(
* NAME PRIVATE * NAME PRIVATE
* FsRtlpCheckLockForReadOrWriteAccess * FsRtlpCheckLockForReadOrWriteAccess
* *
* Return:
* TRUE: can read/write
* FALSE: can't read/write
*/ */
BOOLEAN BOOLEAN
FASTCALL FASTCALL
@ -124,8 +158,10 @@ FsRtlpCheckLockForReadOrWriteAccess(
PFILE_LOCK_TOC LockToc; PFILE_LOCK_TOC LockToc;
PFILE_LOCK_GRANTED Granted; PFILE_LOCK_GRANTED Granted;
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
LARGE_INTEGER EndOffset;
ASSERT(FileLock); ASSERT(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL || Length->QuadPart == 0) if (LockToc == NULL || Length->QuadPart == 0)
@ -133,15 +169,16 @@ FsRtlpCheckLockForReadOrWriteAccess(
return TRUE; return TRUE;
} }
EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Flink; LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
while ( EnumEntry != &LockToc->GrantedListHead)
{ {
Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry ); Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry);
//if overlapping //if overlapping
if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) || if(IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset))
REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
{ {
//No read conflict if (shared lock) OR (exclusive + our lock) //No read conflict if (shared lock) OR (exclusive + our lock)
//No write conflict if exclusive lock AND our lock //No write conflict if exclusive lock AND our lock
@ -152,30 +189,26 @@ FsRtlpCheckLockForReadOrWriteAccess(
Granted->Lock.Key == Key ) ) Granted->Lock.Key == Key ) )
{ {
//AND if lock surround request region, stop searching and grant //AND if lock surround request region, stop searching and grant
if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && if (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset) )
REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
{ {
EnumEntry = &LockToc->GrantedListHead;//indicate no conflict
break;
}
//else continue searching for conflicts
}
else //conflict
{
break;
}
}
EnumEntry = EnumEntry->Flink;
}
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
if (EnumEntry == &LockToc->GrantedListHead)
{ //no conflict
return TRUE; return TRUE;
} }
//else continue searching for conflicts
continue;
}
//found conflict
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
return FALSE; return FALSE;
}
}
//no conflict
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
return TRUE;
} }
@ -206,7 +239,7 @@ FsRtlCheckLockForReadAccess (
Stack->Parameters.Read.Key, Stack->Parameters.Read.Key,
Stack->FileObject, Stack->FileObject,
IoGetRequestorProcess(Irp), IoGetRequestorProcess(Irp),
TRUE//Read? TRUE /* Read */
); );
} }
@ -238,7 +271,7 @@ FsRtlCheckLockForWriteAccess (
Stack->Parameters.Write.Key, Stack->Parameters.Write.Key,
Stack->FileObject, Stack->FileObject,
IoGetRequestorProcess(Irp), IoGetRequestorProcess(Irp),
FALSE//Read? FALSE /* Read */
); );
} }
@ -269,7 +302,7 @@ FsRtlFastCheckLockForRead (
Key, Key,
FileObject, FileObject,
Process, Process,
TRUE//Read? TRUE /* Read */
); );
} }
@ -297,7 +330,7 @@ FsRtlFastCheckLockForWrite (
Key, Key,
FileObject, FileObject,
Process, Process,
FALSE//Read? FALSE /* Read */
); );
} }
@ -314,8 +347,8 @@ FsRtlpFastUnlockAllByKey(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
IN PEPROCESS Process, IN PEPROCESS Process,
IN DWORD Key, /* FIXME: guess */ IN DWORD Key,
IN BOOLEAN UseKey, /* FIXME: guess */ IN BOOLEAN UseKey,
IN PVOID Context OPTIONAL IN PVOID Context OPTIONAL
) )
{ {
@ -325,7 +358,8 @@ FsRtlpFastUnlockAllByKey(
PFILE_LOCK_GRANTED Granted; PFILE_LOCK_GRANTED Granted;
BOOLEAN Unlock = FALSE; BOOLEAN Unlock = FALSE;
//must make local copy since FILE_LOCK struct is allowed to be paged //must make local copy since FILE_LOCK struct is allowed to be paged
PUNLOCK_ROUTINE GotUnlockRoutine; BOOLEAN GotUnlockRoutine;
LIST_ENTRY UnlockedListHead;
ASSERT(FileLock); ASSERT(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
@ -335,14 +369,12 @@ FsRtlpFastUnlockAllByKey(
return STATUS_RANGE_NOT_LOCKED; return STATUS_RANGE_NOT_LOCKED;
} }
GotUnlockRoutine = FileLock->UnlockRoutine; InitializeListHead(&UnlockedListHead);
GotUnlockRoutine = FileLock->UnlockRoutine != NULL;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Flink; LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->GrantedListHead, Granted, FILE_LOCK_GRANTED, ListEntry)
while (EnumEntry != &LockToc->GrantedListHead )
{ {
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
EnumEntry = EnumEntry->Flink;
if (Granted->Lock.Process == Process && if (Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject && Granted->Lock.FileObject == FileObject &&
@ -357,7 +389,7 @@ FsRtlpFastUnlockAllByKey(
Put on unlocked list and call unlock routine for them afterwards. Put on unlocked list and call unlock routine for them afterwards.
This way we don't have to restart enum after each call This way we don't have to restart enum after each call
*/ */
InsertHeadList(&LockToc->UnlockedListHead,&Granted->ListEntry); InsertHeadList(&UnlockedListHead,&Granted->ListEntry);
} }
else else
{ {
@ -366,21 +398,23 @@ FsRtlpFastUnlockAllByKey(
} }
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
if (Unlock) if (Unlock)
{ {
//call unlock routine for each unlocked lock (if any) //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); 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); ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
} }
//NOTE: holding spinlock while calling this //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))
{ {
@ -391,10 +425,10 @@ FsRtlpFastUnlockAllByKey(
{ {
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
return STATUS_RANGE_NOT_LOCKED; return STATUS_RANGE_NOT_LOCKED;
} }
@ -416,7 +450,7 @@ FsRtlFastUnlockAll /*ByProcess*/ (
return FsRtlpFastUnlockAllByKey( FileLock, return FsRtlpFastUnlockAllByKey( FileLock,
FileObject, FileObject,
Process, Process,
0, /* Key */ 0, /* Key is ignored */
FALSE, /* Do NOT use Key */ FALSE, /* Do NOT use Key */
Context Context
); );
@ -455,7 +489,7 @@ FsRtlFastUnlockAllByKey (
* NOTE * NOTE
* Spinlock held at entry !! * Spinlock held at entry !!
*/ */
NTSTATUS BOOLEAN
FASTCALL FASTCALL
FsRtlpAddLock( FsRtlpAddLock(
IN PFILE_LOCK_TOC LockToc, IN PFILE_LOCK_TOC LockToc,
@ -464,58 +498,60 @@ FsRtlpAddLock(
IN PLARGE_INTEGER Length, IN PLARGE_INTEGER Length,
IN PEPROCESS Process, IN PEPROCESS Process,
IN ULONG Key, IN ULONG Key,
IN BOOLEAN ExclusiveLock IN BOOLEAN ExclusiveLock,
IN PVOID Context
) )
{ {
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
PFILE_LOCK_GRANTED Granted; PFILE_LOCK_GRANTED Granted;
LARGE_INTEGER EndOffset;
EnumEntry = LockToc->GrantedListHead.Flink; EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1;
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); Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
//if overlapping
if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) || if (IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset))
REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
{ {
//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) if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
{ {
//AND if lock surround region, stop searching and insert lock //if existing lock surround new lock, we know that no other exclusive lock
if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && //may overlap with our new lock;-D
REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)) if (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset))
{ {
EnumEntry = &LockToc->GrantedListHead;
break; break;
} }
//else keep locking for conflicts //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);
//starting offset
Granted->Lock.StartingByte = *FileOffset; Granted->Lock.StartingByte = *FileOffset;
Granted->Lock.Length = *Length; Granted->Lock.Length = *Length;
Granted->Lock.ExclusiveLock = ExclusiveLock; Granted->Lock.ExclusiveLock = ExclusiveLock;
Granted->Lock.Key = Key; Granted->Lock.Key = Key;
Granted->Lock.FileObject = FileObject; Granted->Lock.FileObject = FileObject;
Granted->Lock.Process = Process; Granted->Lock.Process = Process;
Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF; //ending offset
Granted->Lock.EndingByte = EndOffset;
Granted->UnlockContext = Context;
InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry); InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry);
return TRUE; return TRUE;
}
return FALSE;
} }
@ -532,19 +568,20 @@ FASTCALL
FsRtlpCompletePendingLocks( FsRtlpCompletePendingLocks(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_LOCK_TOC LockToc, 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 //walk pending list, FIFO order, try 2 complete locks
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
PIRP Irp; PIRP Irp;
PIO_STACK_LOCATION Stack; PIO_STACK_LOCATION Stack;
LIST_ENTRY CompletedListHead;
EnumEntry = LockToc->PendingListHead.Blink; InitializeListHead(&CompletedListHead);
while (EnumEntry != &LockToc->PendingListHead)
LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->PendingListHead, Irp, IRP, Tail.Overlay.ListEntry)
{ {
Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry);
Stack = IoGetCurrentIrpStackLocation(Irp); Stack = IoGetCurrentIrpStackLocation(Irp);
if (FsRtlpAddLock(LockToc, if (FsRtlpAddLock(LockToc,
Stack->FileObject, Stack->FileObject,
@ -552,55 +589,65 @@ FsRtlpCompletePendingLocks(
Stack->Parameters.LockControl.Length, Stack->Parameters.LockControl.Length,
IoGetRequestorProcess(Irp), IoGetRequestorProcess(Irp),
Stack->Parameters.LockControl.Key, 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); RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
if (!IoSetCancelRoutine(Irp, NULL)) if (!IoSetCancelRoutine(Irp, NULL))
{ {
/* //irp is canceled and cancelroutine will run when we release the lock
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.
*/
InitializeListHead(&Irp->Tail.Overlay.ListEntry); 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. Put on completed list and complete them all afterwards.
This way we don't have to restart enum after each completion. This way we don't have to restart enum after each completion.
*/ */
Irp->IoStatus.Status = STATUS_SUCCESS; InsertHeadList(&CompletedListHead, &Irp->Tail.Overlay.ListEntry);
Irp->IoStatus.Information = 0;
InsertHeadList(&LockToc->CompletedListHead,&Irp->Tail.Overlay.ListEntry);
} }
} }
EnumEntry = EnumEntry->Blink;
} KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);
//complete irp's (if any) //complete irp's (if any)
while (!IsListEmpty(&LockToc->CompletedListHead)) while (!IsListEmpty(&CompletedListHead))
{ {
EnumEntry = RemoveTailList(&LockToc->CompletedListHead); EnumEntry = RemoveTailList(&CompletedListHead);
KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine
Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
if (FileLock->CompleteLockIrpRoutine) 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 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 PEPROCESS Process,
IN ULONG Key, IN ULONG Key,
IN PVOID Context OPTIONAL, IN PVOID Context OPTIONAL,
IN BOOLEAN AlreadySynchronized,
IN BOOLEAN CallUnlockRoutine IN BOOLEAN CallUnlockRoutine
) )
{ {
@ -632,17 +678,15 @@ FsRtlpUnlockSingle(
ASSERT(FileLock); ASSERT(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL || Length->QuadPart == 0) if (LockToc == NULL)
{ {
return STATUS_RANGE_NOT_LOCKED; return STATUS_RANGE_NOT_LOCKED;
} }
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql );
EnumEntry = LockToc->GrantedListHead.Flink; LIST_FOR_EACH_SAFE(EnumEntry, &LockToc->GrantedListHead, Granted,FILE_LOCK_GRANTED,ListEntry)
while (EnumEntry != &LockToc->GrantedListHead)
{ {
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
//must be exact match //must be exact match
if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart && if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart &&
@ -652,12 +696,13 @@ FsRtlpUnlockSingle(
Granted->Lock.Key == Key) Granted->Lock.Key == Key)
{ {
RemoveEntryList(&Granted->ListEntry); RemoveEntryList(&Granted->ListEntry);
FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql); FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context);
if (IsListEmpty(&LockToc->GrantedListHead)) if (IsListEmpty(&LockToc->GrantedListHead))
{ {
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; //paged data
} }
else else
{ {
@ -666,14 +711,13 @@ FsRtlpUnlockSingle(
if (FileLock->UnlockRoutine && CallUnlockRoutine) if (FileLock->UnlockRoutine && CallUnlockRoutine)
{ {
FileLock->UnlockRoutine(Context,&Granted->Lock); FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock);
} }
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); ExFreeToNPagedLookasideList(&GrantedLookaside, Granted);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
EnumEntry = EnumEntry->Flink;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
@ -710,8 +754,7 @@ FsRtlFastUnlockSingle (
Process, Process,
Key, Key,
Context, Context,
AlreadySynchronized, TRUE /* call unlock copletion routine */
TRUE//CallUnlockRoutine
); );
} }
@ -747,10 +790,9 @@ FsRtlpDumpFileLocks(
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Blink; LIST_FOR_EACH(EnumEntry, &LockToc->GrantedListHead)
while ( 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", DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD", Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD",
@ -762,16 +804,13 @@ FsRtlpDumpFileLocks(
Granted->Lock.FileObject Granted->Lock.FileObject
); );
EnumEntry = EnumEntry->Blink;
} }
DPRINT1("Dumping pending file locks, FIFO order\n"); DPRINT1("Dumping pending file locks, FIFO order\n");
EnumEntry = LockToc->PendingListHead.Blink; LIST_FOR_EACH(EnumEntry, &LockToc->PendingListHead)
while ( EnumEntry != &LockToc->PendingListHead)
{ {
Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry ); Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry);
Stack = IoGetCurrentIrpStackLocation(Irp); Stack = IoGetCurrentIrpStackLocation(Irp);
DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n", DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n",
@ -784,7 +823,6 @@ FsRtlpDumpFileLocks(
Stack->FileObject Stack->FileObject
); );
EnumEntry = EnumEntry->Blink;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
@ -939,7 +977,7 @@ FsRtlPrivateLock (
IN BOOLEAN ExclusiveLock, IN BOOLEAN ExclusiveLock,
OUT PIO_STATUS_BLOCK IoStatus, OUT PIO_STATUS_BLOCK IoStatus,
IN PIRP Irp OPTIONAL, IN PIRP Irp OPTIONAL,
IN PVOID Context, IN PVOID Context OPTIONAL,
IN BOOLEAN AlreadySynchronized IN BOOLEAN AlreadySynchronized
) )
{ {
@ -958,8 +996,6 @@ FsRtlPrivateLock (
KeInitializeSpinLock(&LockToc->SpinLock); KeInitializeSpinLock(&LockToc->SpinLock);
InitializeListHead(&LockToc->GrantedListHead); InitializeListHead(&LockToc->GrantedListHead);
InitializeListHead(&LockToc->PendingListHead); InitializeListHead(&LockToc->PendingListHead);
InitializeListHead(&LockToc->CompletedListHead);
InitializeListHead(&LockToc->UnlockedListHead);
} }
ExReleaseFastMutex(&LockTocMutex); ExReleaseFastMutex(&LockTocMutex);
} }
@ -974,43 +1010,36 @@ FsRtlPrivateLock (
Length, Length,
Process, Process,
Key, Key,
ExclusiveLock ExclusiveLock,
Context
) ) ) )
{ {
IoStatus->Status = STATUS_SUCCESS; IoStatus->Status = STATUS_SUCCESS;
} }
else if (Irp && !FailImmediately) else if (Irp && !FailImmediately)
{ //failed + irp + no fail = mk. pending {
//for our cancel routine //failed + irp + no fail = make. pending
Irp->Tail.Overlay.DriverContext[0] = (PVOID)FileLock;
Irp->Tail.Overlay.DriverContext[1] = (PVOID)LockToc; Irp->Tail.Overlay.DriverContext[3] = &LockToc->SpinLock;
Irp->Tail.Overlay.DriverContext[2] = Context; Irp->Tail.Overlay.DriverContext[2] = Context;
IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine); IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine);
if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
if (Irp->Cancel)
{ {
//irp canceled even before we got to queue it //irp was canceled
if (IoSetCancelRoutine(Irp, NULL)) KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
{ //Cancel routine will NOT be called: cancel it here
IoStatus->Status = STATUS_CANCELLED; Irp->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; Irp->IoStatus.Information = 0;
InitializeListHead(&Irp->Tail.Overlay.ListEntry); 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.Status = IoStatus->Status = STATUS_PENDING;
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry); InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
}
} }
else else
@ -1034,11 +1063,9 @@ FsRtlPrivateLock (
{ {
Irp->IoStatus.Status = IoStatus->Status; Irp->IoStatus.Status = IoStatus->Status;
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
if (FileLock->CompleteLockIrpRoutine) if (FileLock->CompleteLockIrpRoutine)
{ //complete irp routine {
if (FileLock->CompleteLockIrpRoutine(Context,Irp)!=STATUS_SUCCESS)
if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp)))
{ {
//CompleteLockIrpRoutine complain: revert changes //CompleteLockIrpRoutine complain: revert changes
FsRtlpUnlockSingle( FileLock, FsRtlpUnlockSingle( FileLock,
@ -1047,15 +1074,14 @@ FsRtlPrivateLock (
Length, Length,
Process, Process,
Key, Key,
Context, NULL, /* context */
AlreadySynchronized, FALSE /* don't call unlock copletion routine */
FALSE//CallUnlockRoutine
); );
} }
} }
else else
{//std irp completion {
IofCompleteRequest(Irp, IO_NO_INCREMENT); IoCompleteRequest(Irp, IO_NO_INCREMENT);
} }
} }
} }
@ -1123,7 +1149,7 @@ FsRtlProcessFileLock (
Status = FsRtlFastUnlockAll( FileLock, Status = FsRtlFastUnlockAll( FileLock,
Stack->FileObject, Stack->FileObject,
IoGetRequestorProcess(Irp), IoGetRequestorProcess(Irp),
Context); Context );
break; break;
case IRP_MN_UNLOCK_ALL_BY_KEY: case IRP_MN_UNLOCK_ALL_BY_KEY:
@ -1131,26 +1157,21 @@ FsRtlProcessFileLock (
Stack->FileObject, Stack->FileObject,
IoGetRequestorProcess(Irp), IoGetRequestorProcess(Irp),
Stack->Parameters.LockControl.Key, Stack->Parameters.LockControl.Key,
Context); Context );
break; break;
default: default:
Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
IofCompleteRequest(Irp, IO_NO_INCREMENT); IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status; return Status;
} }
Irp->IoStatus.Status = Status;
if (FileLock->CompleteLockIrpRoutine ) Irp->IoStatus.Status = Status;
{ Irp->IoStatus.Information = 0;
FileLock->CompleteLockIrpRoutine(Context,Irp);
} IoCompleteRequest(Irp,IO_NO_INCREMENT);
else
{
IofCompleteRequest(Irp,IO_NO_INCREMENT);
}
return Status; return Status;
} }
@ -1202,28 +1223,17 @@ FsRtlUninitializeFileLock (
{ {
//The cancel routine will be called. When we release the lock it will complete the irp. //The cancel routine will be called. When we release the lock it will complete the irp.
InitializeListHead(&Irp->Tail.Overlay.ListEntry); InitializeListHead(&Irp->Tail.Overlay.ListEntry);
continue;
} }
else
{ KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
/*
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; Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED;
Irp->IoStatus.Information = 0;
if (FileLock->CompleteLockIrpRoutine) IoCompleteRequest(Irp, IO_NO_INCREMENT);
{
FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
}
else
{
IofCompleteRequest(Irp, IO_NO_INCREMENT);
}
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
}
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
@ -1311,4 +1321,5 @@ FsRtlReleaseFile(
UNIMPLEMENTED; UNIMPLEMENTED;
} }
/* EOF */ /* EOF */

View file

@ -1,6 +1,6 @@
#ifndef __INCLUDE_INTERNAL_IFS_H #ifndef __INCLUDE_INTERNAL_IFS_H
#define __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 <ddk/ntifs.h>
#include <ntos.h> #include <ntos.h>
@ -38,7 +38,7 @@ FsRtlpFastUnlockAllByKey(
IN PVOID Context OPTIONAL IN PVOID Context OPTIONAL
); );
NTSTATUS FASTCALL BOOLEAN FASTCALL
FsRtlpAddLock( FsRtlpAddLock(
IN PFILE_LOCK_TOC LockToc, IN PFILE_LOCK_TOC LockToc,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -46,14 +46,16 @@ FsRtlpAddLock(
IN PLARGE_INTEGER Length, IN PLARGE_INTEGER Length,
IN PEPROCESS Process, IN PEPROCESS Process,
IN ULONG Key, IN ULONG Key,
IN BOOLEAN ExclusiveLock IN BOOLEAN ExclusiveLock,
IN PVOID UnlockContext
); );
VOID FASTCALL VOID FASTCALL
FsRtlpCompletePendingLocks( FsRtlpCompletePendingLocks(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_LOCK_TOC LockToc, IN PFILE_LOCK_TOC LockToc,
IN OUT PKIRQL oldirql IN OUT PKIRQL oldirql,
IN PVOID Context
); );
NTSTATUS FASTCALL NTSTATUS FASTCALL
@ -65,7 +67,6 @@ FsRtlpUnlockSingle(
IN PEPROCESS Process, IN PEPROCESS Process,
IN ULONG Key, IN ULONG Key,
IN PVOID Context OPTIONAL, IN PVOID Context OPTIONAL,
IN BOOLEAN AlreadySynchronized,
IN BOOLEAN CallUnlockRoutine IN BOOLEAN CallUnlockRoutine
); );