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

View file

@ -1,6 +1,6 @@
#ifndef __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>
@ -11,12 +11,12 @@ VOID STDCALL
FsRtlpInitFileLockingImplementation(VOID);
VOID STDCALL
FsRtlpPendingFileLockCancelRoutine(
FsRtlpFileLockCancelRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
BOOLEAN STDCALL
BOOLEAN FASTCALL
FsRtlpCheckLockForReadOrWriteAccess(
IN PFILE_LOCK FileLock,
IN PLARGE_INTEGER FileOffset,
@ -27,7 +27,7 @@ FsRtlpCheckLockForReadOrWriteAccess(
IN BOOLEAN Read
);
NTSTATUS STDCALL
NTSTATUS FASTCALL
FsRtlpFastUnlockAllByKey(
IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject,
@ -37,7 +37,7 @@ FsRtlpFastUnlockAllByKey(
IN PVOID Context OPTIONAL
);
NTSTATUS STDCALL
NTSTATUS FASTCALL
FsRtlpAddLock(
IN PFILE_LOCK_TOC LockToc,
IN PFILE_OBJECT FileObject,
@ -48,14 +48,14 @@ FsRtlpAddLock(
IN BOOLEAN ExclusiveLock
);
VOID STDCALL
FsRtlpTryCompletePendingLocks(
VOID FASTCALL
FsRtlpCompletePendingLocks(
IN PFILE_LOCK FileLock,
IN PFILE_LOCK_TOC LockToc,
IN OUT PKIRQL oldirql
);
NTSTATUS STDCALL
NTSTATUS FASTCALL
FsRtlpUnlockSingle(
IN PFILE_LOCK FileLock,
IN PFILE_OBJECT FileObject,
@ -68,7 +68,7 @@ FsRtlpUnlockSingle(
IN BOOLEAN CallUnlockRoutine
);
VOID STDCALL
VOID FASTCALL
FsRtlpDumpFileLocks(
IN PFILE_LOCK FileLock
);