mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 07:32:57 +00:00
-Added some file locking improvements. (Thanks to Gunnar Andr� Dalsnes)
svn path=/trunk/; revision=4064
This commit is contained in:
parent
1fb967f911
commit
ca34b94db6
2 changed files with 877 additions and 810 deletions
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue