-Added some file locking improvements. (Thanks to Gunnar Andr� Dalsnes)

svn path=/trunk/; revision=4064
This commit is contained in:
Hartmut Birr 2003-01-25 15:52:43 +00:00
parent 1fb967f911
commit ca34b94db6
2 changed files with 877 additions and 810 deletions

View file

@ -1,4 +1,4 @@
/* $Id: filelock.c,v 1.6 2002/11/13 06:01:11 robd Exp $ /* $Id: filelock.c,v 1.7 2003/01/25 15:52:43 hbirr Exp $
* *
* reactos/ntoskrnl/fs/filelock.c * reactos/ntoskrnl/fs/filelock.c
* *
@ -10,14 +10,11 @@
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
//#define TAG_LOCK TAG('F','l','c','k')
/* /*
NOTE: NOTE:
I'm not using resource syncronization here, since I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write
FsRtlFastCheckLockForRead/FsRtlFastCheckLockForWrite are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for
can be running at any IRQL. Therefore I also have used the lists.
nonpaged memory for the lists.
*/ */
#define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart) #define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart)
@ -26,9 +23,9 @@ nonpaged memory for the lists.
#define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1) #define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1)
FAST_MUTEX LockTocMutex; FAST_MUTEX LockTocMutex;
NPAGED_LOOKASIDE_LIST PendingLookaside;
NPAGED_LOOKASIDE_LIST GrantedLookaside; NPAGED_LOOKASIDE_LIST GrantedLookaside;
NPAGED_LOOKASIDE_LIST LockTocLookaside; NPAGED_LOOKASIDE_LIST LockTocLookaside;
PAGED_LOOKASIDE_LIST LockLookaside;
/********************************************************************** /**********************************************************************
* NAME PRIVATE * NAME PRIVATE
@ -57,11 +54,11 @@ FsRtlpInitFileLockingImplementation(VOID)
0 0
); );
ExInitializeNPagedLookasideList( &PendingLookaside, ExInitializePagedLookasideList( &LockLookaside,
NULL, NULL,
NULL, NULL,
0, 0,
sizeof(FILE_LOCK_PENDING), sizeof(FILE_LOCK),
IFS_POOL_TAG, IFS_POOL_TAG,
0 0
); );
@ -69,74 +66,52 @@ FsRtlpInitFileLockingImplementation(VOID)
ExInitializeFastMutex(&LockTocMutex); ExInitializeFastMutex(&LockTocMutex);
} }
/********************************************************************** /**********************************************************************
* NAME PRIVATE * NAME PRIVATE
* FsRtlpPendingFileLockCancelRoutine * FsRtlpFileLockCancelRoutine
* *
*/ */
VOID VOID
STDCALL STDCALL
FsRtlpPendingFileLockCancelRoutine( FsRtlpFileLockCancelRoutine(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp IN PIRP Irp
) )
{ {
KIRQL oldIrql; KIRQL oldIrql;
PFILE_LOCK FileLock; PKSPIN_LOCK SpinLock;
PFILE_LOCK_TOC LockToc; PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine;
PFILE_LOCK_PENDING Pending;
PLIST_ENTRY EnumEntry;
IoReleaseCancelSpinLock(Irp->CancelIrql); //don't need this for private queue cancelation //don't need this since we have our own sync. protecting irp cancellation
IoReleaseCancelSpinLock(Irp->CancelIrql);
FileLock = (PVOID)Irp->IoStatus.Information; SpinLock = &((PFILE_LOCK_TOC)Irp->Tail.Overlay.DriverContext[1])->SpinLock;
assert(FileLock);
LockToc = FileLock->LockInformation;
if (LockToc == NULL)
return;
KeAcquireSpinLock(&LockToc->SpinLock, &oldIrql); KeAcquireSpinLock(SpinLock, &oldIrql);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(SpinLock, oldIrql);
EnumEntry = LockToc->PendingListHead.Flink;
while (EnumEntry != &LockToc->PendingListHead) {
Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING , ListEntry );
if (Pending->Irp == Irp){
RemoveEntryList(&Pending->ListEntry);
KeReleaseSpinLock(&LockToc->SpinLock, oldIrql);
Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Status = STATUS_CANCELLED;
if (FileLock->CompleteLockIrpRoutine ) CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine;
FileLock->CompleteLockIrpRoutine(Pending->Context,Irp); if (CompleteLockIrpRoutine)
{
CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
}
else else
{
IofCompleteRequest(Irp, IO_NO_INCREMENT); IofCompleteRequest(Irp, IO_NO_INCREMENT);
ExFreeToNPagedLookasideList(&PendingLookaside,Pending);
return;
}
EnumEntry = EnumEntry->Flink;
} }
/*
didn't find irp in list, so someone else must have completed it
while we were waiting for the spinlock
*/
KeReleaseSpinLock(&LockToc->SpinLock, oldIrql);
} }
/********************************************************************** /**********************************************************************
* NAME PRIVATE * NAME PRIVATE
* FsRtlpCheckLockForReadOrWriteAccess * FsRtlpCheckLockForReadOrWriteAccess
* *
*/ */
BOOLEAN BOOLEAN
STDCALL FASTCALL
FsRtlpCheckLockForReadOrWriteAccess( FsRtlpCheckLockForReadOrWriteAccess(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER FileOffset,
@ -155,46 +130,50 @@ FsRtlpCheckLockForReadOrWriteAccess(
assert(FileLock); assert(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL || Length->QuadPart == 0) { if (LockToc == NULL || Length->QuadPart == 0)
{
return TRUE; return TRUE;
} }
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Flink; EnumEntry = LockToc->GrantedListHead.Flink;
while ( 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(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock))) { 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
if ((Read && !Granted->Lock.ExclusiveLock) || if ((Read && !Granted->Lock.ExclusiveLock) ||
(Granted->Lock.ExclusiveLock && (Granted->Lock.ExclusiveLock &&
Granted->Lock.Process == Process && Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject && Granted->Lock.FileObject == FileObject &&
Granted->Lock.Key == Key ) ) { Granted->Lock.Key == Key ) )
{
//AND if lock surround read 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 (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)){ REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
{
EnumEntry = &LockToc->GrantedListHead;//success EnumEntry = &LockToc->GrantedListHead;//indicate no conflict
break; break;
} }
//else continue searching for conflicts //else continue searching for conflicts
} }
else //conflict else //conflict
{
break; break;
} }
}
EnumEntry = EnumEntry->Flink; EnumEntry = EnumEntry->Flink;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
if (EnumEntry == &LockToc->GrantedListHead) { //no conflict if (EnumEntry == &LockToc->GrantedListHead)
{ //no conflict
return TRUE; return TRUE;
} }
@ -328,7 +307,7 @@ FsRtlFastCheckLockForWrite (
* *
*/ */
NTSTATUS NTSTATUS
STDCALL FASTCALL
FsRtlpFastUnlockAllByKey( FsRtlpFastUnlockAllByKey(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -344,56 +323,76 @@ 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
BOOLEAN GotUnlockRoutine; PUNLOCK_ROUTINE GotUnlockRoutine;
assert(FileLock); assert(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL) if (LockToc == NULL)
{
return STATUS_RANGE_NOT_LOCKED; return STATUS_RANGE_NOT_LOCKED;
}
GotUnlockRoutine = FileLock->UnlockRoutine ? TRUE : FALSE; GotUnlockRoutine = FileLock->UnlockRoutine;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Flink; EnumEntry = LockToc->GrantedListHead.Flink;
while ( EnumEntry != &LockToc->GrantedListHead ) { while (EnumEntry != &LockToc->GrantedListHead )
{
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
EnumEntry = EnumEntry->Flink; EnumEntry = EnumEntry->Flink;
if (Granted->Lock.Process == Process && if (Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject && Granted->Lock.FileObject == FileObject &&
(!UseKey || (UseKey && Granted->Lock.Key == Key)) ){ (!UseKey || (UseKey && Granted->Lock.Key == Key)) )
{
RemoveEntryList(&Granted->ListEntry); RemoveEntryList(&Granted->ListEntry);
Unlock = TRUE; 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);
}
else
{
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
}
}
}
if (Unlock)
{
//call unlock routine for each unlocked lock (if any)
while (!IsListEmpty(&LockToc->UnlockedListHead))
{
EnumEntry = RemoveTailList(&LockToc->UnlockedListHead);
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry);
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
FileLock->UnlockRoutine(Context,&Granted->Lock); FileLock->UnlockRoutine(Context,&Granted->Lock);
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Flink; //restart
continue;
} }
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); //NOTE: holding spinlock while calling this
} FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
}
if (Unlock){
FsRtlpTryCompletePendingLocks(FileLock,LockToc,NULL);
}
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
if (Unlock) {
if (IsListEmpty(&LockToc->GrantedListHead)) if (IsListEmpty(&LockToc->GrantedListHead))
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
}
else
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
return STATUS_RANGE_NOT_LOCKED; return STATUS_RANGE_NOT_LOCKED;
} }
@ -453,7 +452,7 @@ FsRtlFastUnlockAllByKey (
* Spinlock held at entry !! * Spinlock held at entry !!
*/ */
NTSTATUS NTSTATUS
STDCALL FASTCALL
FsRtlpAddLock( FsRtlpAddLock(
IN PFILE_LOCK_TOC LockToc, IN PFILE_LOCK_TOC LockToc,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -468,35 +467,35 @@ FsRtlpAddLock(
PFILE_LOCK_GRANTED Granted; PFILE_LOCK_GRANTED Granted;
EnumEntry = LockToc->GrantedListHead.Flink; EnumEntry = LockToc->GrantedListHead.Flink;
while (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(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) ||
REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock))) { REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock)))
{
//never conflict if shared lock and we want to add a shared lock //never conflict if shared lock and we want to add a shared lock
if (!Granted->Lock.ExclusiveLock && if (!Granted->Lock.ExclusiveLock && !ExclusiveLock)
!ExclusiveLock) { {
//AND if lock surround region, stop searching and insert lock //AND if lock surround region, stop searching and insert lock
if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) &&
REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)){ REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock))
{
EnumEntry = &LockToc->GrantedListHead; EnumEntry = &LockToc->GrantedListHead;
break; break;
} }
//else keep locking for conflicts //else keep locking for conflicts
} }
else //conflict if we want share access to excl. lock OR exlc. access to shared lock else
{//conflict if we want share access to excl. lock OR exlc. access to shared lock
break;//FAIL break;//FAIL
} }
}
EnumEntry = EnumEntry->Flink; EnumEntry = EnumEntry->Flink;
} }
if (EnumEntry == &LockToc->GrantedListHead) {//no conflict if (EnumEntry == &LockToc->GrantedListHead)
{//no conflict
Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside); Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside);
Granted->Lock.StartingByte = *FileOffset; Granted->Lock.StartingByte = *FileOffset;
@ -519,14 +518,14 @@ FsRtlpAddLock(
/********************************************************************** /**********************************************************************
* NAME PRIVATE * NAME PRIVATE
* FsRtlpTryCompletePendingLocks * FsRtlpCompletePendingLocks
* *
* NOTE * NOTE
* Spinlock held at entry !! * Spinlock held at entry !!
*/ */
VOID VOID
STDCALL FASTCALL
FsRtlpTryCompletePendingLocks( 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
@ -534,49 +533,70 @@ FsRtlpTryCompletePendingLocks(
{ {
//walk pending list, FIFO order, try 2 complete locks //walk pending list, FIFO order, try 2 complete locks
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
PFILE_LOCK_PENDING Pending; PIRP Irp;
PIO_STACK_LOCATION Stack; PIO_STACK_LOCATION Stack;
EnumEntry = LockToc->PendingListHead.Blink; EnumEntry = LockToc->PendingListHead.Blink;
while (EnumEntry != &LockToc->PendingListHead) { while (EnumEntry != &LockToc->PendingListHead)
{
Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING,ListEntry); Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry);
Stack = IoGetCurrentIrpStackLocation(Pending->Irp);
Stack = IoGetCurrentIrpStackLocation(Irp);
if (FsRtlpAddLock(LockToc, if (FsRtlpAddLock(LockToc,
Stack->FileObject,//correct? Stack->FileObject,
&Stack->Parameters.LockControl.ByteOffset, &Stack->Parameters.LockControl.ByteOffset,
Stack->Parameters.LockControl.Length, Stack->Parameters.LockControl.Length,
IoGetRequestorProcess(Pending->Irp), IoGetRequestorProcess(Irp),
Stack->Parameters.LockControl.Key, Stack->Parameters.LockControl.Key,
Stack->Flags & SL_EXCLUSIVE_LOCK Stack->Flags & SL_EXCLUSIVE_LOCK
) ) { ) )
{
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
RemoveEntryList(&Pending->ListEntry); if (!IoSetCancelRoutine(Irp, NULL))
{
IoSetCancelRoutine(Pending->Irp, NULL);
/* /*
Irp could be cancelled and the cancel routine may or may not have been called, Cancel routine WILL be called after we release the spinlock. It will try to remove
waiting there for our spinlock. the irp from the list and cancel/complete this irp. Since we allready removed it,
But it doesn't matter because it will not find the IRP in the list. make its ListEntry point to itself.
*/ */
KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine InitializeListHead(&Irp->Tail.Overlay.ListEntry);
Pending->Irp->IoStatus.Status = STATUS_SUCCESS; }
if (FileLock->CompleteLockIrpRoutine)
FileLock->CompleteLockIrpRoutine(Pending->Context,Pending->Irp);
else else
IofCompleteRequest(Pending->Irp, IO_NO_INCREMENT); {
/*
Cancel routine will NOT be called, canceled or not.
ExFreeToNPagedLookasideList(&PendingLookaside,Pending); Put on completed list and complete them all afterwards.
KeAcquireSpinLock(&LockToc->SpinLock, oldirql); This way we don't have to restart enum after each completion.
//restart, something migth have happend to our list */
EnumEntry = LockToc->PendingListHead.Blink; Irp->IoStatus.Status = STATUS_SUCCESS;
continue; Irp->IoStatus.Information = 0;
InsertHeadList(&LockToc->CompletedListHead,&Irp->Tail.Overlay.ListEntry);
}
} }
EnumEntry = EnumEntry->Blink; EnumEntry = EnumEntry->Blink;
} }
//complete irp's (if any)
while (!IsListEmpty(&LockToc->CompletedListHead))
{
EnumEntry = RemoveTailList(&LockToc->CompletedListHead);
KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine
Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
if (FileLock->CompleteLockIrpRoutine)
{
FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
}
else
{
IofCompleteRequest(Irp, IO_NO_INCREMENT);
}
KeAcquireSpinLock(&LockToc->SpinLock, oldirql);
}
} }
@ -587,7 +607,7 @@ FsRtlpTryCompletePendingLocks(
* *
*/ */
NTSTATUS NTSTATUS
STDCALL FASTCALL
FsRtlpUnlockSingle( FsRtlpUnlockSingle(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -608,14 +628,16 @@ FsRtlpUnlockSingle(
assert(FileLock); assert(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL) if (LockToc == NULL || Length->QuadPart == 0)
{
return STATUS_RANGE_NOT_LOCKED; return STATUS_RANGE_NOT_LOCKED;
}
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql );
EnumEntry = LockToc->GrantedListHead.Flink; EnumEntry = LockToc->GrantedListHead.Flink;
while (EnumEntry != &LockToc->GrantedListHead) { while (EnumEntry != &LockToc->GrantedListHead)
{
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
//must be exact match //must be exact match
@ -623,24 +645,29 @@ FsRtlpUnlockSingle(
Length->QuadPart == Granted->Lock.Length.QuadPart && Length->QuadPart == Granted->Lock.Length.QuadPart &&
Granted->Lock.Process == Process && Granted->Lock.Process == Process &&
Granted->Lock.FileObject == FileObject && Granted->Lock.FileObject == FileObject &&
Granted->Lock.Key == Key) { Granted->Lock.Key == Key)
{
RemoveEntryList(&Granted->ListEntry); RemoveEntryList(&Granted->ListEntry);
FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql);
FsRtlpTryCompletePendingLocks(FileLock, LockToc,NULL); if (IsListEmpty(&LockToc->GrantedListHead))
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
}
else
{
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
}
if (FileLock->UnlockRoutine && CallUnlockRoutine) if (FileLock->UnlockRoutine && CallUnlockRoutine)
{
FileLock->UnlockRoutine(Context,&Granted->Lock); FileLock->UnlockRoutine(Context,&Granted->Lock);
}
ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); ExFreeToNPagedLookasideList(&GrantedLookaside,Granted);
if (IsListEmpty(&LockToc->GrantedListHead))
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
EnumEntry = EnumEntry->Flink; EnumEntry = EnumEntry->Flink;
} }
@ -687,25 +714,26 @@ FsRtlFastUnlockSingle (
* NAME EXPORTED * NAME EXPORTED
* FsRtlpDumpFileLocks * FsRtlpDumpFileLocks
* *
* NOTE: used for testing and debugging
*/ */
VOID VOID
STDCALL FASTCALL
FsRtlpDumpFileLocks( FsRtlpDumpFileLocks(
IN PFILE_LOCK FileLock IN PFILE_LOCK FileLock
) )
{ {
//100% OK
KIRQL oldirql; KIRQL oldirql;
PFILE_LOCK_TOC LockToc; PFILE_LOCK_TOC LockToc;
PFILE_LOCK_GRANTED Granted; PFILE_LOCK_GRANTED Granted;
PFILE_LOCK_PENDING Pending; PIRP Irp;
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
PIO_STACK_LOCATION Stack; PIO_STACK_LOCATION Stack;
assert(FileLock); assert(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL) { if (LockToc == NULL)
{
DPRINT1("No file locks\n"); DPRINT1("No file locks\n");
return; return;
} }
@ -715,8 +743,8 @@ FsRtlpDumpFileLocks(
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
EnumEntry = LockToc->GrantedListHead.Blink; EnumEntry = LockToc->GrantedListHead.Blink;
while ( 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",
@ -735,11 +763,11 @@ FsRtlpDumpFileLocks(
DPRINT1("Dumping pending file locks, FIFO order\n"); DPRINT1("Dumping pending file locks, FIFO order\n");
EnumEntry = LockToc->PendingListHead.Blink; EnumEntry = LockToc->PendingListHead.Blink;
while ( EnumEntry != &LockToc->PendingListHead){ while ( EnumEntry != &LockToc->PendingListHead)
{
Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry );
Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING , ListEntry ); Stack = IoGetCurrentIrpStackLocation(Irp);
Stack = IoGetCurrentIrpStackLocation(Pending->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",
(Stack->Flags & SL_EXCLUSIVE_LOCK) ? "EXCL" : "SHRD", (Stack->Flags & SL_EXCLUSIVE_LOCK) ? "EXCL" : "SHRD",
@ -747,7 +775,7 @@ FsRtlpDumpFileLocks(
Stack->Parameters.LockControl.Length->QuadPart, Stack->Parameters.LockControl.Length->QuadPart,
Stack->Parameters.LockControl.ByteOffset.QuadPart + Stack->Parameters.LockControl.Length->QuadPart - 1, Stack->Parameters.LockControl.ByteOffset.QuadPart + Stack->Parameters.LockControl.Length->QuadPart - 1,
Stack->Parameters.LockControl.Key, Stack->Parameters.LockControl.Key,
IoGetRequestorProcess(Pending->Irp), IoGetRequestorProcess(Irp),
Stack->FileObject Stack->FileObject
); );
@ -776,7 +804,7 @@ FsRtlGetNextFileLock (
{ {
/* /*
Messy enumeration of granted locks. Messy enumeration of granted locks.
What our last ptr. in LastReturnedLock points at, might have been free 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. 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... If it's not there anymore, restart the enumeration...
*/ */
@ -792,7 +820,9 @@ FsRtlGetNextFileLock (
assert(FileLock); assert(FileLock);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
if (LockToc == NULL) if (LockToc == NULL)
{
return NULL; return NULL;
}
LocalLastReturnedLock = FileLock->LastReturnedLock; LocalLastReturnedLock = FileLock->LastReturnedLock;
@ -802,8 +832,10 @@ restart:;
EnumEntry = LockToc->GrantedListHead.Flink; EnumEntry = LockToc->GrantedListHead.Flink;
if (Restart){ if (Restart)
if (EnumEntry != &LockToc->GrantedListHead){ {
if (EnumEntry != &LockToc->GrantedListHead)
{
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
LocalLastReturnedLockInfo = Granted->Lock; LocalLastReturnedLockInfo = Granted->Lock;
KeReleaseSpinLock(&LockToc->SpinLock,oldirql); KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
@ -812,21 +844,24 @@ restart:;
FileLock->LastReturnedLock = EnumEntry; FileLock->LastReturnedLock = EnumEntry;
return &FileLock->LastReturnedLockInfo; return &FileLock->LastReturnedLockInfo;
} }
else { else
{
KeReleaseSpinLock(&LockToc->SpinLock,oldirql); KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
return NULL; return NULL;
} }
} }
//else: continue enum //else: continue enum
while (EnumEntry != &LockToc->GrantedListHead) { while (EnumEntry != &LockToc->GrantedListHead)
{
//found previous lock? //found previous lock?
if (EnumEntry == LocalLastReturnedLock) { if (EnumEntry == LocalLastReturnedLock)
{
FoundPrevious = TRUE; FoundPrevious = TRUE;
//get next //get next
EnumEntry = EnumEntry->Flink; EnumEntry = EnumEntry->Flink;
if (EnumEntry != &LockToc->GrantedListHead){ if (EnumEntry != &LockToc->GrantedListHead)
{
Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry);
LocalLastReturnedLockInfo = Granted->Lock; LocalLastReturnedLockInfo = Granted->Lock;
KeReleaseSpinLock(&LockToc->SpinLock,oldirql); KeReleaseSpinLock(&LockToc->SpinLock,oldirql);
@ -840,7 +875,8 @@ restart:;
EnumEntry = EnumEntry->Flink; EnumEntry = EnumEntry->Flink;
} }
if (!FoundPrevious) { if (!FoundPrevious)
{
//got here? uh no, didn't find our last lock..must have been freed...restart //got here? uh no, didn't find our last lock..must have been freed...restart
Restart = TRUE; Restart = TRUE;
goto restart; goto restart;
@ -891,7 +927,7 @@ FsRtlPrivateLock (
IN PLARGE_INTEGER Length, IN PLARGE_INTEGER Length,
IN PEPROCESS Process, IN PEPROCESS Process,
IN ULONG Key, IN ULONG Key,
IN BOOLEAN FailImmediately, //meaningless for fast io IN BOOLEAN FailImmediately, //seems meaningless for fast io
IN BOOLEAN ExclusiveLock, IN BOOLEAN ExclusiveLock,
OUT PIO_STATUS_BLOCK IoStatus, OUT PIO_STATUS_BLOCK IoStatus,
IN PIRP Irp OPTIONAL, IN PIRP Irp OPTIONAL,
@ -901,18 +937,21 @@ FsRtlPrivateLock (
{ {
PFILE_LOCK_TOC LockToc; PFILE_LOCK_TOC LockToc;
KIRQL oldirql; KIRQL oldirql;
PFILE_LOCK_PENDING Pending;
assert(FileLock); assert(FileLock);
if (FileLock->LockInformation == NULL) { if (FileLock->LockInformation == NULL)
{
ExAcquireFastMutex(&LockTocMutex); ExAcquireFastMutex(&LockTocMutex);
//still NULL? //still NULL?
if (FileLock->LockInformation == NULL){ if (FileLock->LockInformation == NULL)
{
FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside); FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside);
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
KeInitializeSpinLock(&LockToc->SpinLock); KeInitializeSpinLock(&LockToc->SpinLock);
InitializeListHead(&LockToc->PendingListHead);
InitializeListHead(&LockToc->GrantedListHead); InitializeListHead(&LockToc->GrantedListHead);
InitializeListHead(&LockToc->PendingListHead);
InitializeListHead(&LockToc->CompletedListHead);
InitializeListHead(&LockToc->UnlockedListHead);
} }
ExReleaseFastMutex(&LockTocMutex); ExReleaseFastMutex(&LockTocMutex);
} }
@ -920,7 +959,7 @@ FsRtlPrivateLock (
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
//try add new lock //try add new lock (while holding spin lock)
if (FsRtlpAddLock(LockToc, if (FsRtlpAddLock(LockToc,
FileObject, FileObject,
FileOffset, FileOffset,
@ -928,52 +967,71 @@ FsRtlPrivateLock (
Process, Process,
Key, Key,
ExclusiveLock ExclusiveLock
) ) { ) )
{
IoStatus->Status = STATUS_SUCCESS; IoStatus->Status = STATUS_SUCCESS;
} }
else if (Irp && !FailImmediately) { //failed + irp + no fail = mk. pending 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;
Irp->Tail.Overlay.DriverContext[2] = Context;
Irp->IoStatus.Information = (DWORD)FileLock;//for our cancel routine IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine);
IoSetCancelRoutine(Irp, FsRtlpPendingFileLockCancelRoutine);
if (Irp->Cancel) { if (Irp->Cancel)
IoSetCancelRoutine(Irp, NULL); {
/* //irp canceled even before we got to queue it
Irp was canceled and the cancel routine may or may not have been called, if (IoSetCancelRoutine(Irp, NULL))
waiting there for our spinlock. { //Cancel routine will NOT be called: cancel it here
But it doesn't matter since it will not find the IRP in the list.
*/
IoStatus->Status = STATUS_CANCELLED; IoStatus->Status = STATUS_CANCELLED;
} }
else { //not cancelled: queue irp else
IoMarkIrpPending(Irp); { //Cancel routine WILL be called. When we release the lock it will complete the irp
Pending = ExAllocateFromNPagedLookasideList(&PendingLookaside); //Return pending since we are not completing the irp here
Pending->Context = Context; Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
Pending->Irp = Irp; Irp->IoStatus.Information = 0;
IoStatus->Status = STATUS_PENDING; InitializeListHead(&Irp->Tail.Overlay.ListEntry);
InsertHeadList(&LockToc->PendingListHead,&Pending->ListEntry);
} }
} }
else { else
{ //not cancelled: queue irp
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING;
Irp->IoStatus.Information = 0;
InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry);
}
}
else
{
IoStatus->Status = STATUS_LOCK_NOT_GRANTED; IoStatus->Status = STATUS_LOCK_NOT_GRANTED;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine 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_SUCCESS) if (IoStatus->Status == STATUS_SUCCESS)
{
FsRtlAreThereCurrentFileLocks(FileLock) = TRUE; FsRtlAreThereCurrentFileLocks(FileLock) = TRUE;
}
if (Irp)
{
Irp->IoStatus.Status = IoStatus->Status; Irp->IoStatus.Status = IoStatus->Status;
Irp->IoStatus.Information = 0;
if (Irp && (IoStatus->Status != STATUS_PENDING)) { if (FileLock->CompleteLockIrpRoutine)
{ //complete irp routine
if (FileLock->CompleteLockIrpRoutine) { //complete irp routine if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp)))
{
if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp))) {
//CompleteLockIrpRoutine complain: revert changes //CompleteLockIrpRoutine complain: revert changes
FsRtlpUnlockSingle( FileLock, FsRtlpUnlockSingle( FileLock,
FileObject, FileObject,
@ -987,16 +1045,15 @@ FsRtlPrivateLock (
); );
} }
} }
else {//std irp completion else
{//std irp completion
IofCompleteRequest(Irp, IO_NO_INCREMENT); IofCompleteRequest(Irp, IO_NO_INCREMENT);
} }
} }
}
//NOTE: only fast io care about this return value //NOTE: only fast io seems to care about this return value
if (IoStatus->Status == STATUS_SUCCESS || FailImmediately) return (IoStatus->Status == STATUS_SUCCESS || FailImmediately);
return TRUE;
return FALSE;
} }
@ -1021,9 +1078,10 @@ FsRtlProcessFileLock (
assert(FileLock); assert(FileLock);
Stack = IoGetCurrentIrpStackLocation(Irp); Stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
switch(Stack->MinorFunction){ switch(Stack->MinorFunction)
{
case IRP_MN_LOCK: case IRP_MN_LOCK:
//ret: BOOLEAN //ret: BOOLEAN
FsRtlPrivateLock( FileLock, FsRtlPrivateLock( FileLock,
@ -1077,9 +1135,13 @@ FsRtlProcessFileLock (
Irp->IoStatus.Status = Status; Irp->IoStatus.Status = Status;
if (FileLock->CompleteLockIrpRoutine ) if (FileLock->CompleteLockIrpRoutine )
{
FileLock->CompleteLockIrpRoutine(Context,Irp); FileLock->CompleteLockIrpRoutine(Context,Irp);
}
else else
{
IofCompleteRequest(Irp,IO_NO_INCREMENT); IofCompleteRequest(Irp,IO_NO_INCREMENT);
}
return Status; return Status;
} }
@ -1097,66 +1159,70 @@ FsRtlUninitializeFileLock (
) )
{ {
PFILE_LOCK_TOC LockToc; PFILE_LOCK_TOC LockToc;
PFILE_LOCK_PENDING Pending; PIRP Irp;
PFILE_LOCK_GRANTED Granted; PFILE_LOCK_GRANTED Granted;
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
KIRQL oldirql; KIRQL oldirql;
assert(FileLock); assert(FileLock);
if (FileLock->LockInformation == NULL) if (FileLock->LockInformation == NULL)
{
return; return;
}
LockToc = FileLock->LockInformation; LockToc = FileLock->LockInformation;
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
//unlock and free granted locks //remove and free granted locks
EnumEntry = LockToc->GrantedListHead.Flink; while (!IsListEmpty(&LockToc->GrantedListHead))
while (EnumEntry != &LockToc->GrantedListHead) { {
EnumEntry = RemoveTailList(&LockToc->GrantedListHead);
Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry); Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry);
EnumEntry = EnumEntry->Flink;
RemoveEntryList(&Granted->ListEntry);
ExFreeToNPagedLookasideList(&GrantedLookaside, Granted); ExFreeToNPagedLookasideList(&GrantedLookaside, Granted);
} }
//complete pending locks //remove, complete and free all pending locks
EnumEntry = LockToc->PendingListHead.Flink; while (!IsListEmpty(&LockToc->PendingListHead))
while (EnumEntry != &LockToc->PendingListHead) { {
EnumEntry = RemoveTailList(&LockToc->PendingListHead);
Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry);
Pending = CONTAINING_RECORD(EnumEntry,FILE_LOCK_PENDING, ListEntry); if (!IoSetCancelRoutine(Irp, NULL))
RemoveEntryList(&Pending->ListEntry); {
//The cancel routine will be called. When we release the lock it will complete the irp.
IoSetCancelRoutine(Pending->Irp, NULL); InitializeListHead(&Irp->Tail.Overlay.ListEntry);
}
else
{
/* /*
Irp could be cancelled and the cancel routine may or may not have been called, Cancel routine will NOT be called, even though the irp might have been canceled.
waiting there for our spinlock. Don't care since we'l complete it faster than the cancel routine would have.
But it doesn't matter because it will not find the IRP in the list.
*/ */
KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine
Pending->Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED; Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED;
if (FileLock->CompleteLockIrpRoutine) if (FileLock->CompleteLockIrpRoutine)
FileLock->CompleteLockIrpRoutine(Pending->Context,Pending->Irp); {
FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp);
}
else else
IofCompleteRequest(Pending->Irp, IO_NO_INCREMENT); {
IofCompleteRequest(Irp, IO_NO_INCREMENT);
ExFreeToNPagedLookasideList(&PendingLookaside,Pending); }
KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); KeAcquireSpinLock(&LockToc->SpinLock, &oldirql);
//restart, something migth have happend to our list }
EnumEntry = LockToc->PendingListHead.Flink;
} }
KeReleaseSpinLock(&LockToc->SpinLock, oldirql); KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc);
FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; FsRtlAreThereCurrentFileLocks(FileLock) = FALSE;
FileLock->LockInformation = NULL; FileLock->LockInformation = NULL;
ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc);
} }
@ -1178,7 +1244,7 @@ FsRtlAllocateFileLock (
{ {
PFILE_LOCK FileLock; PFILE_LOCK FileLock;
FileLock = ExAllocatePoolWithTag(PagedPool,sizeof(FILE_LOCK),IFS_POOL_TAG); FileLock = ExAllocateFromPagedLookasideList(&LockLookaside);
FsRtlInitializeFileLock(FileLock, FsRtlInitializeFileLock(FileLock,
CompleteLockIrpRoutine, CompleteLockIrpRoutine,
@ -1204,8 +1270,9 @@ FsRtlFreeFileLock(
) )
{ {
assert(FileLock); assert(FileLock);
FsRtlUninitializeFileLock(FileLock); FsRtlUninitializeFileLock(FileLock);
ExFreePool(FileLock); ExFreeToPagedLookasideList(&LockLookaside, FileLock);
} }
/* 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.4 2002/11/13 06:01:11 robd Exp $ */ /* $Id: ifs.h,v 1.5 2003/01/25 15:52:43 hbirr Exp $ */
#include <ddk/ntifs.h> #include <ddk/ntifs.h>
@ -11,12 +11,12 @@ VOID STDCALL
FsRtlpInitFileLockingImplementation(VOID); FsRtlpInitFileLockingImplementation(VOID);
VOID STDCALL VOID STDCALL
FsRtlpPendingFileLockCancelRoutine( FsRtlpFileLockCancelRoutine(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp IN PIRP Irp
); );
BOOLEAN STDCALL BOOLEAN FASTCALL
FsRtlpCheckLockForReadOrWriteAccess( FsRtlpCheckLockForReadOrWriteAccess(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER FileOffset,
@ -27,7 +27,7 @@ FsRtlpCheckLockForReadOrWriteAccess(
IN BOOLEAN Read IN BOOLEAN Read
); );
NTSTATUS STDCALL NTSTATUS FASTCALL
FsRtlpFastUnlockAllByKey( FsRtlpFastUnlockAllByKey(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -37,7 +37,7 @@ FsRtlpFastUnlockAllByKey(
IN PVOID Context OPTIONAL IN PVOID Context OPTIONAL
); );
NTSTATUS STDCALL NTSTATUS FASTCALL
FsRtlpAddLock( FsRtlpAddLock(
IN PFILE_LOCK_TOC LockToc, IN PFILE_LOCK_TOC LockToc,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -48,14 +48,14 @@ FsRtlpAddLock(
IN BOOLEAN ExclusiveLock IN BOOLEAN ExclusiveLock
); );
VOID STDCALL VOID FASTCALL
FsRtlpTryCompletePendingLocks( 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
); );
NTSTATUS STDCALL NTSTATUS FASTCALL
FsRtlpUnlockSingle( FsRtlpUnlockSingle(
IN PFILE_LOCK FileLock, IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject, IN PFILE_OBJECT FileObject,
@ -68,7 +68,7 @@ FsRtlpUnlockSingle(
IN BOOLEAN CallUnlockRoutine IN BOOLEAN CallUnlockRoutine
); );
VOID STDCALL VOID FASTCALL
FsRtlpDumpFileLocks( FsRtlpDumpFileLocks(
IN PFILE_LOCK FileLock IN PFILE_LOCK FileLock
); );