From e2d799f0806047af0d9612e09d10d6ad798290a9 Mon Sep 17 00:00:00 2001 From: Robert Dickenson Date: Wed, 13 Nov 2002 06:01:12 +0000 Subject: [PATCH] Commit of the rest of Gunnars file locking patch. svn path=/trunk/; revision=3751 --- reactos/lib/ntdll/rtl/heap.c | 2 +- reactos/ntoskrnl/fs/filelock.c | 1136 ++++++++++++++++++++--- reactos/ntoskrnl/include/internal/ifs.h | 70 +- reactos/ntoskrnl/io/lock.c | 257 ++++- reactos/ntoskrnl/ke/main.c | 4 +- 5 files changed, 1308 insertions(+), 161 deletions(-) diff --git a/reactos/lib/ntdll/rtl/heap.c b/reactos/lib/ntdll/rtl/heap.c index a2f5d36ea86..09ce908ab43 100644 --- a/reactos/lib/ntdll/rtl/heap.c +++ b/reactos/lib/ntdll/rtl/heap.c @@ -1001,8 +1001,8 @@ static BOOL HEAP_IsRealArena( HANDLE STDCALL RtlCreateHeap(ULONG flags, PVOID BaseAddress, - ULONG initialSize, ULONG maxSize, + ULONG initialSize, PVOID Unknown, PRTL_HEAP_DEFINITION Definition) { diff --git a/reactos/ntoskrnl/fs/filelock.c b/reactos/ntoskrnl/fs/filelock.c index 2d3d0fe0162..75f9ad80720 100644 --- a/reactos/ntoskrnl/fs/filelock.c +++ b/reactos/ntoskrnl/fs/filelock.c @@ -1,26 +1,210 @@ -/* $Id: filelock.c,v 1.5 2002/09/08 10:23:20 chorns Exp $ +/* $Id: filelock.c,v 1.6 2002/11/13 06:01:11 robd Exp $ * * reactos/ntoskrnl/fs/filelock.c * */ -#include +#include +#include #include +#define NDEBUG +#include + +//#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. +*/ + +#define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart) +#define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1) +#define REQUEST_START_OFF (FileOffset->QuadPart) +#define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1) + +FAST_MUTEX LockTocMutex; +NPAGED_LOOKASIDE_LIST PendingLookaside; +NPAGED_LOOKASIDE_LIST GrantedLookaside; +NPAGED_LOOKASIDE_LIST LockTocLookaside; + +/********************************************************************** + * NAME PRIVATE + * FsRtlpInitFileLockingImplementation + * + */ +VOID +STDCALL +FsRtlpInitFileLockingImplementation(VOID) +{ + ExInitializeNPagedLookasideList( &LockTocLookaside, + NULL, + NULL, + 0, + sizeof(FILE_LOCK_TOC), + IFS_POOL_TAG, + 0 + ); + + ExInitializeNPagedLookasideList( &GrantedLookaside, + NULL, + NULL, + 0, + sizeof(FILE_LOCK_GRANTED), + IFS_POOL_TAG, + 0 + ); + + ExInitializeNPagedLookasideList( &PendingLookaside, + NULL, + NULL, + 0, + sizeof(FILE_LOCK_PENDING), + IFS_POOL_TAG, + 0 + ); + + ExInitializeFastMutex(&LockTocMutex); +} + + +/********************************************************************** + * NAME PRIVATE + * FsRtlpPendingFileLockCancelRoutine + * + */ +VOID +STDCALL +FsRtlpPendingFileLockCancelRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + KIRQL oldIrql; + PFILE_LOCK FileLock; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_PENDING Pending; + PLIST_ENTRY EnumEntry; + + IoReleaseCancelSpinLock(Irp->CancelIrql); //don't need this for private queue cancelation + + FileLock = (PVOID)Irp->IoStatus.Information; + assert(FileLock); + LockToc = FileLock->LockInformation; + if (LockToc == NULL) + return; + + KeAcquireSpinLock(&LockToc->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); + 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 +FsRtlpCheckLockForReadOrWriteAccess( + IN PFILE_LOCK FileLock, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN BOOLEAN Read + ) +{ + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted; + PLIST_ENTRY EnumEntry; + + assert(FileLock); + LockToc = FileLock->LockInformation; + + if (LockToc == NULL || Length->QuadPart == 0) { + return TRUE; + } + + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + + EnumEntry = LockToc->GrantedListHead.Flink; + 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))) { + + //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 + if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && + REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)){ + + EnumEntry = &LockToc->GrantedListHead;//success + break; + } + //else continue searching for conflicts + } + else //conflict + break; + } + EnumEntry = EnumEntry->Flink; + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + + if (EnumEntry == &LockToc->GrantedListHead) { //no conflict + return TRUE; + } + + return FALSE; +} + /********************************************************************** * NAME EXPORTED - * FsRtlCheckLockForReadAccess@8 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * NOTE (Bo Branten) - * All this really does is pick out the lock parameters from - * the irp (io stack location?), get IoGetRequestorProcess, - * and pass values on to FsRtlFastCheckLockForRead. + * FsRtlCheckLockForReadAccess * */ BOOLEAN @@ -30,24 +214,29 @@ FsRtlCheckLockForReadAccess ( IN PIRP Irp ) { - return FALSE; + PIO_STACK_LOCATION Stack; + LARGE_INTEGER LocalLength; + + Stack = IoGetCurrentIrpStackLocation(Irp); + + LocalLength.u.LowPart = Stack->Parameters.Read.Length; + LocalLength.u.HighPart = 0; + + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + &Stack->Parameters.Read.ByteOffset, + &LocalLength, + Stack->Parameters.Read.Key, + Stack->FileObject, + IoGetRequestorProcess(Irp), + TRUE//Read? + ); } /********************************************************************** * NAME EXPORTED - * FsRtlCheckLockForWriteAccess@8 + * FsRtlCheckLockForWriteAccess * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * NOTE (Bo Branten) - * All this really does is pick out the lock parameters from - * the irp (io stack location?), get IoGetRequestorProcess, - * and pass values on to FsRtlFastCheckLockForWrite. */ BOOLEAN STDCALL @@ -56,19 +245,31 @@ FsRtlCheckLockForWriteAccess ( IN PIRP Irp ) { - return FALSE; + PIO_STACK_LOCATION Stack; + LARGE_INTEGER LocalLength; + + Stack = IoGetCurrentIrpStackLocation(Irp); + + LocalLength.u.LowPart = Stack->Parameters.Read.Length; + LocalLength.u.HighPart = 0; + + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + &Stack->Parameters.Write.ByteOffset, + &LocalLength, + Stack->Parameters.Write.Key, + Stack->FileObject, + IoGetRequestorProcess(Irp), + FALSE//Read? + ); + } + + /********************************************************************** * NAME EXPORTED - * FsRtlFastCheckLockForRead@24 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE + * FsRtlFastCheckLockForRead * */ BOOLEAN @@ -82,19 +283,20 @@ FsRtlFastCheckLockForRead ( IN PEPROCESS Process ) { - return FALSE; + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + FileOffset, + Length, + Key, + FileObject, + Process, + TRUE//Read? + ); } /********************************************************************** * NAME EXPORTED - * FsRtlFastCheckLockForWrite@24 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE + * FsRtlFastCheckLockForWrite * */ BOOLEAN @@ -108,26 +310,26 @@ FsRtlFastCheckLockForWrite ( IN PEPROCESS Process ) { - return FALSE; + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + FileOffset, + Length, + Key, + FileObject, + Process, + FALSE//Read? + ); } + /********************************************************************** - * NAME EXPORTED - * FsRtlFastUnlockAll@16 - * FsRtlFastUnlockAllByKey@20 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE + * NAME PRIVATE + * FsRtlpFastUnlockAllByKey * */ -static NTSTATUS STDCALL -FsRtlpFastUnlockAllByKey ( +FsRtlpFastUnlockAllByKey( IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, IN PEPROCESS Process, @@ -136,31 +338,93 @@ FsRtlpFastUnlockAllByKey ( IN PVOID Context OPTIONAL ) { - /* FIXME: */ - return (STATUS_RANGE_NOT_LOCKED); + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PLIST_ENTRY EnumEntry; + PFILE_LOCK_GRANTED Granted; + BOOLEAN Unlock = FALSE; + //must make local copy since FILE_LOCK struct is allowed to be paged + BOOLEAN GotUnlockRoutine; + + assert(FileLock); + LockToc = FileLock->LockInformation; + + if (LockToc == NULL) + return STATUS_RANGE_NOT_LOCKED; + + GotUnlockRoutine = FileLock->UnlockRoutine ? TRUE : FALSE; + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + + EnumEntry = LockToc->GrantedListHead.Flink; + 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)) ){ + + RemoveEntryList(&Granted->ListEntry); + Unlock = TRUE; + + if (GotUnlockRoutine) { + 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); + } + } + + if (Unlock){ + FsRtlpTryCompletePendingLocks(FileLock,LockToc,NULL); + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + + if (Unlock) { + if (IsListEmpty(&LockToc->GrantedListHead)) + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + + return STATUS_SUCCESS; + } + + return STATUS_RANGE_NOT_LOCKED; } - +/********************************************************************** + * NAME EXPORTED + * FsRtlFastUnlockAll + * + */ NTSTATUS STDCALL -FsRtlFastUnlockAll ( +FsRtlFastUnlockAll /*ByProcess*/ ( IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, IN PEPROCESS Process, IN PVOID Context OPTIONAL ) { - return FsRtlpFastUnlockAllByKey ( - FileLock, - FileObject, - Process, - 0, /* Key */ - FALSE, /* Do NOT use Key */ - Context - ); + return FsRtlpFastUnlockAllByKey ( FileLock, + FileObject, + Process, + 0, /* Key */ + FALSE, /* Do NOT use Key */ + Context + ); } - +/********************************************************************** + * NAME EXPORTED + * FsRtlFastUnlockAllByKey + * + */ NTSTATUS STDCALL FsRtlFastUnlockAllByKey ( @@ -171,26 +435,227 @@ FsRtlFastUnlockAllByKey ( IN PVOID Context OPTIONAL ) { - return FsRtlpFastUnlockAllByKey ( - FileLock, - FileObject, - Process, - Key, - TRUE, /* Use Key */ - Context - ); + return FsRtlpFastUnlockAllByKey(FileLock, + FileObject, + Process, + Key, + TRUE, /* Use Key */ + Context + ); } +/********************************************************************** + * NAME PRIVATE + * FsRtlpAddLock + * + * NOTE + * Spinlock held at entry !! + */ +NTSTATUS +STDCALL +FsRtlpAddLock( + IN PFILE_LOCK_TOC LockToc, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN BOOLEAN ExclusiveLock + ) +{ + PLIST_ENTRY EnumEntry; + PFILE_LOCK_GRANTED Granted; + + EnumEntry = LockToc->GrantedListHead.Flink; + 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))) { + + //never conflict if shared lock and we want to add a shared lock + 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)){ + + 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 + break;//FAIL + } + + EnumEntry = EnumEntry->Flink; + } + + if (EnumEntry == &LockToc->GrantedListHead) {//no conflict + + Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside); + + Granted->Lock.StartingByte = *FileOffset; + Granted->Lock.Length = *Length; + Granted->Lock.ExclusiveLock = ExclusiveLock; + Granted->Lock.Key = Key; + Granted->Lock.FileObject = FileObject; + Granted->Lock.Process = Process; + Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF; + + InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry); + return TRUE; + } + + return FALSE; + +} + + + +/********************************************************************** + * NAME PRIVATE + * FsRtlpTryCompletePendingLocks + * + * NOTE + * Spinlock held at entry !! + */ +VOID +STDCALL +FsRtlpTryCompletePendingLocks( + IN PFILE_LOCK FileLock, + IN PFILE_LOCK_TOC LockToc, + IN OUT PKIRQL oldirql + ) +{ + //walk pending list, FIFO order, try 2 complete locks + PLIST_ENTRY EnumEntry; + PFILE_LOCK_PENDING Pending; + PIO_STACK_LOCATION Stack; + + EnumEntry = LockToc->PendingListHead.Blink; + while (EnumEntry != &LockToc->PendingListHead) { + + Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING,ListEntry); + + Stack = IoGetCurrentIrpStackLocation(Pending->Irp); + + if (FsRtlpAddLock( LockToc, + Stack->FileObject,//correct? + &Stack->Parameters.LockControl.ByteOffset, + Stack->Parameters.LockControl.Length, + IoGetRequestorProcess(Pending->Irp), + Stack->Parameters.LockControl.Key, + Stack->Flags & SL_EXCLUSIVE_LOCK + ) ) { + + RemoveEntryList(&Pending->ListEntry); + + IoSetCancelRoutine(Pending->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. + */ + KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine + Pending->Irp->IoStatus.Status = STATUS_SUCCESS; + + if (FileLock->CompleteLockIrpRoutine) + FileLock->CompleteLockIrpRoutine(Pending->Context,Pending->Irp); + else + IofCompleteRequest(Pending->Irp, IO_NO_INCREMENT); + + ExFreeToNPagedLookasideList(&PendingLookaside,Pending); + KeAcquireSpinLock(&LockToc->SpinLock, oldirql); + //restart, something migth have happend to our list + EnumEntry = LockToc->PendingListHead.Blink; + continue; + } + EnumEntry = EnumEntry->Blink; + } +} + + + +/********************************************************************** + * NAME PRIVATE + * FsRtlpUnlockSingle + * + */ +NTSTATUS +STDCALL +FsRtlpUnlockSingle( + IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN PVOID Context OPTIONAL, + IN BOOLEAN AlreadySynchronized, + IN BOOLEAN CallUnlockRoutine + ) +{ + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted; + PLIST_ENTRY EnumEntry; + + assert(FileLock); + LockToc = FileLock->LockInformation; + + if (LockToc == NULL) + return STATUS_RANGE_NOT_LOCKED; + + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); + + EnumEntry = LockToc->GrantedListHead.Flink; + while (EnumEntry != &LockToc->GrantedListHead) { + + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + + //must be exact match + if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart && + Length->QuadPart == Granted->Lock.Length.QuadPart && + Granted->Lock.Process == Process && + Granted->Lock.FileObject == FileObject && + Granted->Lock.Key == Key) { + + RemoveEntryList(&Granted->ListEntry); + + FsRtlpTryCompletePendingLocks(FileLock, LockToc,NULL); + + 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; + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + + return STATUS_RANGE_NOT_LOCKED; + +} + + + /********************************************************************** * NAME EXPORTED - * FsRtlFastUnlockSingle@32 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE + * FsRtlFastUnlockSingle * */ NTSTATUS @@ -206,27 +671,101 @@ FsRtlFastUnlockSingle ( IN BOOLEAN AlreadySynchronized ) { - return (STATUS_RANGE_NOT_LOCKED); + return FsRtlpUnlockSingle( FileLock, + FileObject, + FileOffset, + Length, + Process, + Key, + Context, + AlreadySynchronized, + TRUE//CallUnlockRoutine + ); } +/********************************************************************** + * NAME EXPORTED + * FsRtlpDumpFileLocks + * + */ +VOID +STDCALL +FsRtlpDumpFileLocks( + IN PFILE_LOCK FileLock + ) +{ + //100% OK + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted; + PFILE_LOCK_PENDING Pending; + PLIST_ENTRY EnumEntry; + PIO_STACK_LOCATION Stack; + + assert(FileLock); + LockToc = FileLock->LockInformation; + + if (LockToc == NULL) { + DPRINT1("No file locks\n"); + return; + } + + DPRINT1("Dumping granted file locks, FIFO order\n"); + + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + + EnumEntry = LockToc->GrantedListHead.Blink; + 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", + Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD", + Granted->Lock.StartingByte.QuadPart, + Granted->Lock.Length.QuadPart, + Granted->Lock.EndingByte.QuadPart, + Granted->Lock.Key, + Granted->Lock.Process, + Granted->Lock.FileObject + ); + + EnumEntry = EnumEntry->Blink; + } + + DPRINT1("Dumping pending file locks, FIFO order\n"); + + EnumEntry = LockToc->PendingListHead.Blink; + while ( EnumEntry != &LockToc->PendingListHead){ + + Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING , ListEntry ); + + Stack = IoGetCurrentIrpStackLocation(Pending->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", + Stack->Parameters.LockControl.ByteOffset.QuadPart, + Stack->Parameters.LockControl.Length->QuadPart, + Stack->Parameters.LockControl.ByteOffset.QuadPart + Stack->Parameters.LockControl.Length->QuadPart - 1, + Stack->Parameters.LockControl.Key, + IoGetRequestorProcess(Pending->Irp), + Stack->FileObject + ); + + EnumEntry = EnumEntry->Blink; + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); +} + + /********************************************************************** * NAME EXPORTED - * FsRtlGetNextFileLock@8 - * - * DESCRIPTION - * - * ARGUMENTS + * FsRtlGetNextFileLock * * RETURN VALUE * NULL if no more locks. * - * NOTE (Bo Branten) - * Internals: FsRtlGetNextFileLock uses - * FileLock->LastReturnedLockInfo and FileLock->LastReturnedLock - * as storage. LastReturnedLock is a pointer to the 'raw' lock - * inkl. double linked list, and FsRtlGetNextFileLock needs this - * to get next lock on subsequent calls with Restart = FALSE. */ PFILE_LOCK_INFO STDCALL @@ -234,20 +773,91 @@ FsRtlGetNextFileLock ( IN PFILE_LOCK FileLock, IN BOOLEAN Restart ) -{ - return (NULL); +{ + /* + Messy enumeration of granted locks. + What our last ptr. in LastReturnedLock points at, might have been free 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... + */ + KIRQL oldirql; + PLIST_ENTRY EnumEntry; + PFILE_LOCK_GRANTED Granted; + PFILE_LOCK_TOC LockToc; + BOOLEAN FoundPrevious = FALSE; + //must make local copy since FILE_LOCK struct is allowed to be in paged mem + FILE_LOCK_INFO LocalLastReturnedLockInfo; + PVOID LocalLastReturnedLock; + + assert(FileLock); + LockToc = FileLock->LockInformation; + if (LockToc == NULL) + return NULL; + + LocalLastReturnedLock = FileLock->LastReturnedLock; + + KeAcquireSpinLock(&LockToc->SpinLock,&oldirql); + +restart:; + + EnumEntry = LockToc->GrantedListHead.Flink; + + if (Restart){ + if (EnumEntry != &LockToc->GrantedListHead){ + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + LocalLastReturnedLockInfo = Granted->Lock; + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + + FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; + FileLock->LastReturnedLock = EnumEntry; + return &FileLock->LastReturnedLockInfo; + } + else { + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + return NULL; + } + } + + //else: continue enum + while (EnumEntry != &LockToc->GrantedListHead) { + + //found previous lock? + if (EnumEntry == LocalLastReturnedLock) { + FoundPrevious = TRUE; + //get next + EnumEntry = EnumEntry->Flink; + if (EnumEntry != &LockToc->GrantedListHead){ + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + LocalLastReturnedLockInfo = Granted->Lock; + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + + FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; + FileLock->LastReturnedLock = EnumEntry; + return &FileLock->LastReturnedLockInfo; + } + break; + } + EnumEntry = EnumEntry->Flink; + } + + if (!FoundPrevious) { + //got here? uh no, didn't find our last lock..must have been freed...restart + Restart = TRUE; + goto restart; + } + + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + + return NULL;//no (more) locks } /********************************************************************** * NAME EXPORTED - * FsRtlInitializeFileLock@12 + * FsRtlInitializeFileLock * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE + * NOTE + * Called when creating/allocating/initializing FCB * */ VOID @@ -258,24 +868,19 @@ FsRtlInitializeFileLock ( IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL ) { + + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine; + FileLock->UnlockRoutine = UnlockRoutine; + FileLock->LockInformation = NULL; + } /********************************************************************** * NAME EXPORTED - * FsRtlPrivateLock@48 + * FsRtlPrivateLock * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * IoStatus->Status: STATUS_PENDING, STATUS_LOCK_NOT_GRANTED - * - * NOTE (Bo Branten) - * -Calls IoCompleteRequest if Irp - * -Uses exception handling / ExRaiseStatus with - * STATUS_INSUFFICIENT_RESOURCES */ BOOLEAN STDCALL @@ -286,43 +891,121 @@ FsRtlPrivateLock ( IN PLARGE_INTEGER Length, IN PEPROCESS Process, IN ULONG Key, - IN BOOLEAN FailImmediately, + IN BOOLEAN FailImmediately, //meaningless for fast io IN BOOLEAN ExclusiveLock, - OUT PIO_STATUS_BLOCK IoStatus, + OUT PIO_STATUS_BLOCK IoStatus, IN PIRP Irp OPTIONAL, IN PVOID Context, IN BOOLEAN AlreadySynchronized ) { + PFILE_LOCK_TOC LockToc; + KIRQL oldirql; + PFILE_LOCK_PENDING Pending; + + assert(FileLock); + if (FileLock->LockInformation == NULL) { + ExAcquireFastMutex(&LockTocMutex); + //still NULL? + if (FileLock->LockInformation == NULL){ + FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside); + LockToc = FileLock->LockInformation; + KeInitializeSpinLock(&LockToc->SpinLock); + InitializeListHead(&LockToc->PendingListHead); + InitializeListHead(&LockToc->GrantedListHead); + } + ExReleaseFastMutex(&LockTocMutex); + } + + LockToc = FileLock->LockInformation; + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + + //try add new lock + if (FsRtlpAddLock( LockToc, + FileObject, + FileOffset, + Length, + Process, + Key, + ExclusiveLock + ) ) { + + IoStatus->Status = STATUS_SUCCESS; + } + else if (Irp && !FailImmediately) { //failed + irp + no fail = mk. pending + + Irp->IoStatus.Information = (DWORD)FileLock;//for our cancel routine + IoSetCancelRoutine(Irp, FsRtlpPendingFileLockCancelRoutine); + + 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. + */ + 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 { + IoStatus->Status = STATUS_LOCK_NOT_GRANTED; + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine + + assert(!(IoStatus->Status == STATUS_PENDING && !Irp)); + + if (IoStatus->Status == STATUS_SUCCESS) + FsRtlAreThereCurrentFileLocks(FileLock) = TRUE; + + Irp->IoStatus.Status = IoStatus->Status; + + if (Irp && (IoStatus->Status != STATUS_PENDING)) { + + if (FileLock->CompleteLockIrpRoutine) { //complete irp routine + + if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp))) { + //CompleteLockIrpRoutine complain: revert changes + FsRtlpUnlockSingle( FileLock, + FileObject, + FileOffset, + Length, + Process, + Key, + Context, + AlreadySynchronized, + FALSE//CallUnlockRoutine + ); + } + } + 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; + } + /********************************************************************** * NAME EXPORTED - * FsRtlProcessFileLock@12 + * FsRtlProcessFileLock * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * -STATUS_INVALID_DEVICE_REQUEST - * -STATUS_RANGE_NOT_LOCKED from unlock routines. - * -STATUS_PENDING, STATUS_LOCK_NOT_GRANTED from FsRtlPrivateLock - * (redirected IoStatus->Status). - * - * NOTE (Bo Branten) - * -switch ( Irp->CurrentStackLocation->MinorFunction ) - * lock: return FsRtlPrivateLock; - * unlocksingle: return FsRtlFastUnlockSingle; - * unlockall: return FsRtlFastUnlockAll; - * unlockallbykey: return FsRtlFastUnlockAllByKey; - * default: IofCompleteRequest with STATUS_INVALID_DEVICE_REQUEST; - * return STATUS_INVALID_DEVICE_REQUEST; - * - * -'AllwaysZero' is passed thru as 'AllwaysZero' to lock / unlock routines. - * -'Irp' is passet thru as 'Irp' to FsRtlPrivateLock. */ NTSTATUS STDCALL @@ -332,19 +1015,79 @@ FsRtlProcessFileLock ( IN PVOID Context OPTIONAL ) { - return (STATUS_NOT_IMPLEMENTED); + PIO_STACK_LOCATION Stack; + NTSTATUS Status; + IO_STATUS_BLOCK LocalIoStatus; + + assert(FileLock); + Stack = IoGetCurrentIrpStackLocation(Irp); + + switch(Stack->MinorFunction){ + + case IRP_MN_LOCK: + //ret: BOOLEAN + FsRtlPrivateLock( FileLock, + Stack->FileObject, + &Stack->Parameters.LockControl.ByteOffset, //not pointer! + Stack->Parameters.LockControl.Length, + IoGetRequestorProcess(Irp), + Stack->Parameters.LockControl.Key, + Stack->Flags & SL_FAIL_IMMEDIATELY, + Stack->Flags & SL_EXCLUSIVE_LOCK, + &LocalIoStatus, + Irp, + Context, + FALSE); + + return LocalIoStatus.Status; + + case IRP_MN_UNLOCK_SINGLE: + Status = FsRtlFastUnlockSingle (FileLock, + Stack->FileObject, + &Stack->Parameters.LockControl.ByteOffset, + Stack->Parameters.LockControl.Length, + IoGetRequestorProcess(Irp), + Stack->Parameters.LockControl.Key, + Context, + FALSE); + break; + + case IRP_MN_UNLOCK_ALL: + Status = FsRtlFastUnlockAll(FileLock, + Stack->FileObject, + IoGetRequestorProcess(Irp), + Context); + break; + + case IRP_MN_UNLOCK_ALL_BY_KEY: + Status = FsRtlFastUnlockAllByKey ( FileLock, + Stack->FileObject, + IoGetRequestorProcess(Irp), + Stack->Parameters.LockControl.Key, + Context); + + break; + + default: + Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; + IofCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + Irp->IoStatus.Status = Status; + + if (FileLock->CompleteLockIrpRoutine ) + FileLock->CompleteLockIrpRoutine(Context,Irp); + else + IofCompleteRequest(Irp,IO_NO_INCREMENT); + + return Status; } /********************************************************************** * NAME EXPORTED - * FsRtlUninitializeFileLock@4 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE + * FsRtlUninitializeFileLock * */ VOID @@ -353,19 +1096,77 @@ FsRtlUninitializeFileLock ( IN PFILE_LOCK FileLock ) { + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_PENDING Pending; + 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) { + + 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) { + + Pending = CONTAINING_RECORD(EnumEntry,FILE_LOCK_PENDING, ListEntry); + RemoveEntryList(&Pending->ListEntry); + + IoSetCancelRoutine(Pending->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. + */ + KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine + + Pending->Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED; + + if (FileLock->CompleteLockIrpRoutine) + FileLock->CompleteLockIrpRoutine(Pending->Context,Pending->Irp); + else + IofCompleteRequest(Pending->Irp, IO_NO_INCREMENT); + + ExFreeToNPagedLookasideList(&PendingLookaside,Pending); + + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + //restart, something migth have happend to our list + EnumEntry = LockToc->PendingListHead.Flink; + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql) ; + + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + FileLock->LockInformation = NULL; + + ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc); + } /********************************************************************** * NAME EXPORTED - * FsRtlAllocateFileLock@8 + * FsRtlAllocateFileLock * - * DESCRIPTION + * NOTE * Only present in NT 5.0 or later. - * - * ARGUMENTS - * - * RETURN VALUE + * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool! * */ PFILE_LOCK @@ -375,7 +1176,36 @@ FsRtlAllocateFileLock ( IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL ) { - return NULL; + PFILE_LOCK FileLock; + + FileLock = ExAllocatePoolWithTag(PagedPool,sizeof(FILE_LOCK),IFS_POOL_TAG); + + FsRtlInitializeFileLock( FileLock, + CompleteLockIrpRoutine, + UnlockRoutine + ); + + return FileLock; +} + +/********************************************************************** + * NAME EXPORTED + * FsRtlFreeFileLock + * + * NOTE + * Only present in NT 5.0 or later. + * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool! + * + */ +VOID +STDCALL +FsRtlFreeFileLock( + IN PFILE_LOCK FileLock + ) +{ + assert(FileLock); + FsRtlUninitializeFileLock(FileLock); + ExFreePool(FileLock); } /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ifs.h b/reactos/ntoskrnl/include/internal/ifs.h index 10a06ca5725..6bb12dafe1f 100644 --- a/reactos/ntoskrnl/include/internal/ifs.h +++ b/reactos/ntoskrnl/include/internal/ifs.h @@ -1,8 +1,76 @@ #ifndef __INCLUDE_INTERNAL_IFS_H #define __INCLUDE_INTERNAL_IFS_H -/* $Id: ifs.h,v 1.3 2002/09/08 10:23:21 chorns Exp $ */ +/* $Id: ifs.h,v 1.4 2002/11/13 06:01:11 robd Exp $ */ + +#include /* Look for "FSrt" in mem view */ #define IFS_POOL_TAG 0x74725346 +VOID STDCALL +FsRtlpInitFileLockingImplementation(VOID); + +VOID STDCALL +FsRtlpPendingFileLockCancelRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +BOOLEAN STDCALL +FsRtlpCheckLockForReadOrWriteAccess( + IN PFILE_LOCK FileLock, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN BOOLEAN Read + ); + +NTSTATUS STDCALL +FsRtlpFastUnlockAllByKey( + IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN DWORD Key, /* FIXME: guess */ + IN BOOLEAN UseKey, /* FIXME: guess */ + IN PVOID Context OPTIONAL + ); + +NTSTATUS STDCALL +FsRtlpAddLock( + IN PFILE_LOCK_TOC LockToc, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN BOOLEAN ExclusiveLock + ); + +VOID STDCALL +FsRtlpTryCompletePendingLocks( + IN PFILE_LOCK FileLock, + IN PFILE_LOCK_TOC LockToc, + IN OUT PKIRQL oldirql + ); + +NTSTATUS STDCALL +FsRtlpUnlockSingle( + IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN PVOID Context OPTIONAL, + IN BOOLEAN AlreadySynchronized, + IN BOOLEAN CallUnlockRoutine + ); + +VOID STDCALL +FsRtlpDumpFileLocks( + IN PFILE_LOCK FileLock + ); + #endif diff --git a/reactos/ntoskrnl/io/lock.c b/reactos/ntoskrnl/io/lock.c index f27ca8dd691..38cdd61b53c 100644 --- a/reactos/ntoskrnl/io/lock.c +++ b/reactos/ntoskrnl/io/lock.c @@ -10,20 +10,38 @@ /* INCLUDES *****************************************************************/ + #include +#define NDEBUG #include + +#define TAG_LOCK TAG('F','l','c','k') + /* FUNCTIONS *****************************************************************/ +NTSTATUS +STDCALL + NtLockFileCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +{ + ExFreePool(Context); + return STATUS_SUCCESS; + //FIXME: should I call IoFreeIrp and return STATUS_MORE_PROCESSING_REQUIRED? +} + NTSTATUS STDCALL NtLockFile ( IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, + IN HANDLE EventHandle OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, IN PLARGE_INTEGER ByteOffset, IN PLARGE_INTEGER Length, IN PULONG Key, @@ -31,19 +49,248 @@ NtLockFile ( IN BOOLEAN ExclusiveLock ) { - UNIMPLEMENTED; + NTSTATUS Status; + PFILE_OBJECT FileObject = NULL; + PLARGE_INTEGER LocalLength = NULL; + PKEVENT Event = NULL; + PIRP Irp = NULL; + PIO_STACK_LOCATION StackPtr; + IO_STATUS_BLOCK LocalIoStatusBlock; + PIO_STATUS_BLOCK IoStatusBlock; + PDEVICE_OBJECT DeviceObject; + + //FIXME: instead of this, use SEH when available? + if (!Length || !ByteOffset) { + Status = STATUS_INVALID_PARAMETER; + goto fail; + } + + /* + BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode! + It should ONLY fail if we desire an access that conflict with granted access! + */ + Status = ObReferenceObjectByHandle( + FileHandle, + FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to! + IoFileObjectType, + ExGetPreviousMode(), + (PVOID*)&FileObject, + NULL); + + if (!NT_SUCCESS(Status)){ + goto fail; + } + + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + Irp = IoAllocateIrp( + DeviceObject->StackSize, + TRUE + ); + + if (Irp == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto fail; + } + + if (EventHandle != NULL && !FailImmediatedly) { + Status = ObReferenceObjectByHandle( + EventHandle, + SYNCHRONIZE, + ExEventObjectType, + ExGetPreviousMode(), + (PVOID*)&Event, + NULL); + + if (!NT_SUCCESS(Status)) { + goto fail; + } + + } + else { + Event = &FileObject->Event; + KeResetEvent(Event); + } + + if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || FailImmediatedly) + IoStatusBlock = &LocalIoStatusBlock; + else + IoStatusBlock = UserIoStatusBlock; + + Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; + Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; + + Irp->UserEvent = Event; + Irp->UserIosb = IoStatusBlock; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; + StackPtr->MinorFunction = IRP_MN_LOCK; + StackPtr->DeviceObject = DeviceObject; + StackPtr->FileObject = FileObject; + + if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK; + if (FailImmediatedly) StackPtr->Flags |= SL_FAIL_IMMEDIATELY; + + LocalLength = ExAllocatePoolWithTag( + NonPagedPool, + sizeof(LARGE_INTEGER), + TAG_LOCK + ); + if (!LocalLength){ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto fail; + } + + *LocalLength = *Length; + + StackPtr->Parameters.LockControl.Length = LocalLength; + StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset; + StackPtr->Parameters.LockControl.Key = Key ? *Key : 0; + + IoSetCompletionRoutine( + Irp, + NtLockFileCompletionRoutine, + LocalLength, + TRUE, + TRUE, + TRUE ); + + Status = IofCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO)) { + + Status = KeWaitForSingleObject( + Event, + Executive, + ExGetPreviousMode() , + (FileObject->Flags & FO_ALERTABLE_IO) ? TRUE : FALSE, + NULL + ); + + if (Status != STATUS_WAIT_0) { + DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n"); + /* + FIXME: should do some special processing here if alertable wait + was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC) + */ + return Status; //set status to something else? + } + + Status = LocalIoStatusBlock.Status; + } + + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + *UserIoStatusBlock = LocalIoStatusBlock; + + return Status; + + fail:; + + if (LocalLength) ExFreePool(LocalLength); + if (Irp) IoFreeIrp(Irp); + if (Event) ObDereferenceObject(Event); + if (FileObject) ObDereferenceObject(FileObject); + + return Status; + } + + NTSTATUS STDCALL NtUnlockFile ( IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, IN PLARGE_INTEGER ByteOffset, IN PLARGE_INTEGER Length, OUT PULONG Key OPTIONAL ) { - UNIMPLEMENTED; + NTSTATUS Status; + PFILE_OBJECT FileObject = NULL; + PLARGE_INTEGER LocalLength = NULL; + PIRP Irp = NULL; + PIO_STACK_LOCATION StackPtr; + IO_STATUS_BLOCK LocalIoStatusBlock; + PDEVICE_OBJECT DeviceObject; + + //FIXME: instead of this, use SEH when available + if (!Length || !ByteOffset) { + Status = STATUS_INVALID_PARAMETER; + goto fail; + } + + /* + BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode + It should ONLY fail if we desire an access that conflict with granted access! + */ + Status = ObReferenceObjectByHandle( + FileHandle, + FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to! + IoFileObjectType, + ExGetPreviousMode(), + (PVOID*)&FileObject, + NULL); + + if (!NT_SUCCESS(Status)){ + goto fail; + } + + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + Irp = IoAllocateIrp( + DeviceObject->StackSize, + TRUE + ); + + if (Irp == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto fail; + } + + Irp->UserIosb = &LocalIoStatusBlock; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; + StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE; + StackPtr->DeviceObject = DeviceObject; + StackPtr->FileObject = FileObject; + + LocalLength = ExAllocatePoolWithTag( + NonPagedPool, + sizeof(LARGE_INTEGER), + TAG_LOCK + ); + if (!LocalLength){ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto fail; + } + + *LocalLength = *Length; + + StackPtr->Parameters.LockControl.Length = LocalLength; + StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset; + StackPtr->Parameters.LockControl.Key = Key ? *Key : 0; + + //allways syncronious + Status = IofCallDriver(DeviceObject, Irp); + + *UserIoStatusBlock = LocalIoStatusBlock; + + ExFreePool(LocalLength); + + return Status; + + fail:; + + if (LocalLength) ExFreePool(LocalLength); + if (Irp) IoFreeIrp(Irp); + if (FileObject) ObDereferenceObject(FileObject); + + return Status; } diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index 048785fd206..ed34f7ee7c0 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: main.c,v 1.140 2002/11/12 19:12:13 ekohl Exp $ +/* $Id: main.c,v 1.141 2002/11/13 06:01:12 robd Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -424,6 +425,7 @@ ExpInitializeExecutive(VOID) MmInit3(); CcInit(); KdInit2(); + FsRtlpInitFileLockingImplementation(); /* Report all resources used by hal */ HalReportResourceUsage();