Author: arty
Date: Sat Mar 10 07:28:03 2012
New Revision: 56098

URL: http://svn.reactos.org/svn/reactos?rev=56098&view=rev
Log:
[FSRTL]
Handle cases where multiple ranges overlap a new lock, including either 
exclusive or shared
ranges.  We expand a shared range when an overlap occurs and add another shared 
range to
the shared ranges list.  Also make sure to complete an IRP along every 
non-pending case.
Reduces failures in kernel32_winetest except an expected successful unlock of 
~0,1, which
appears to contravene the documentation.


Modified:
    trunk/reactos/ntoskrnl/fsrtl/filelock.c

Modified: trunk/reactos/ntoskrnl/fsrtl/filelock.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/filelock.c?rev=56098&r1=56097&r2=56098&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/filelock.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/fsrtl/filelock.c [iso-8859-1] Sat Mar 10 07:28:03 
2012
@@ -9,7 +9,7 @@
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
-//#define NDEBUG
+#define NDEBUG
 #include <debug.h>
 
 /* GLOBALS *******************************************************************/
@@ -28,17 +28,27 @@
        };
        FILE_EXCLUSIVE_LOCK_ENTRY Exclusive;
 }
-COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT;
+    COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT;
 
 typedef struct _LOCK_INFORMATION
 {
-       RTL_GENERIC_TABLE RangeTable;
-       IO_CSQ Csq;
-       KSPIN_LOCK CsqLock;
+    RTL_GENERIC_TABLE RangeTable;
+    IO_CSQ Csq;
+    KSPIN_LOCK CsqLock;
     LIST_ENTRY CsqList;
-       PFILE_LOCK BelongsTo;
-}
-LOCK_INFORMATION, *PLOCK_INFORMATION;
+    PFILE_LOCK BelongsTo;
+    LIST_ENTRY SharedLocks;
+}
+    LOCK_INFORMATION, *PLOCK_INFORMATION;
+
+typedef struct _LOCK_SHARED_RANGE
+{
+    LIST_ENTRY Entry;
+    LARGE_INTEGER Start, End;
+    ULONG Key;
+    PVOID ProcessId;
+}
+    LOCK_SHARED_RANGE, *PLOCK_SHARED_RANGE;
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
@@ -72,13 +82,27 @@
 {
        PCOMBINED_LOCK_ELEMENT A = PtrA, B = PtrB;
        RTL_GENERIC_COMPARE_RESULTS Result;
-       DPRINT("Starting to compare element %x to element %x\n", PtrA, PtrB);
+#if 0
+    DPRINT("Starting to compare element %x to element %x\n", PtrA, PtrB);
+#endif
+    /* Match if we overlap */
+    if (((A->Exclusive.FileLock.StartingByte.QuadPart <
+          B->Exclusive.FileLock.EndingByte.QuadPart) &&
+         (A->Exclusive.FileLock.StartingByte.QuadPart >=
+          B->Exclusive.FileLock.StartingByte.QuadPart)) ||
+        ((B->Exclusive.FileLock.StartingByte.QuadPart <
+          A->Exclusive.FileLock.EndingByte.QuadPart) &&
+         (B->Exclusive.FileLock.StartingByte.QuadPart >=
+          A->Exclusive.FileLock.StartingByte.QuadPart)))
+        return GenericEqual;
+    /* Otherwise, key on the starting byte */
        Result =
                (A->Exclusive.FileLock.StartingByte.QuadPart < 
                 B->Exclusive.FileLock.StartingByte.QuadPart) ? GenericLessThan 
:
                (A->Exclusive.FileLock.StartingByte.QuadPart > 
                 B->Exclusive.FileLock.StartingByte.QuadPart) ? 
GenericGreaterThan :
                GenericEqual;
+#if 0
        DPRINT("Compare(%x:%x) %x-%x to %x-%x => %d\n",
                   A,B,
                   A->Exclusive.FileLock.StartingByte.LowPart, 
@@ -86,6 +110,7 @@
                   B->Exclusive.FileLock.StartingByte.LowPart, 
                   B->Exclusive.FileLock.EndingByte.LowPart,
                   Result);
+#endif
        return Result;
 }
 
@@ -115,24 +140,24 @@
     PCOMBINED_LOCK_ELEMENT WhereUnlock = PeekContext;
        PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, 
Csq);
     PLIST_ENTRY Following;
+    DPRINT("PeekNextIrp(IRP %p, Context %p)\n", Irp, PeekContext);
     if (!Irp)
     {
-        Irp = CONTAINING_RECORD
-            (LockInfo->CsqList.Flink,
-             IRP,
-             Tail.Overlay.ListEntry);
-        Following = &Irp->Tail.Overlay.ListEntry;
+        Following = LockInfo->CsqList.Flink;
     }
     else
         Following = Irp->Tail.Overlay.ListEntry.Flink;
-
+    
+    DPRINT("ListEntry %p Head %p\n", Following, &LockInfo->CsqList);
     for (;
          Following != &LockInfo->CsqList;
          Following = Following->Flink)
     {
-        PIRP Irp = CONTAINING_RECORD(Following, IRP, Tail.Overlay.ListEntry);
-        PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
+        PIO_STACK_LOCATION IoStack;
         BOOLEAN Matching;
+        Irp = CONTAINING_RECORD(Following, IRP, Tail.Overlay.ListEntry);
+        DPRINT("Irp %p\n", Irp);
+        IoStack = IoGetCurrentIrpStackLocation(Irp);
         LockElement.Exclusive.FileLock.StartingByte = 
             IoStack->Parameters.LockControl.ByteOffset;
         LockElement.Exclusive.FileLock.EndingByte.QuadPart = 
@@ -147,15 +172,16 @@
         /* Else get any completable IRP */
         else
         {
-            Matching = !!RtlLookupElementGenericTable
-                (&LockInfo->RangeTable, &LockElement);
+            Matching = FALSE;
         }
         if (!Matching)
         {
             // This IRP is fine...
+            DPRINT("Returning the IRP %p\n", Irp);
             return Irp;
         }
     }
+    DPRINT("Return NULL\n");
     return NULL;
 }
 
@@ -178,6 +204,7 @@
 {
        NTSTATUS Status;
        PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, 
Csq);
+       DPRINT("Complete cancelled IRP %p Status %x\n", Irp, STATUS_CANCELLED);
        FsRtlCompleteLockIrpReal
                (LockInfo->BelongsTo->CompleteLockIrpRoutine,
                 NULL,
@@ -201,14 +228,16 @@
     {
         /* Check if we have a file object */
         if (FileObject) FileObject->LastLock = NULL;
-
+        
         /* Set the I/O Status and do completion */
         Irp->IoStatus.Status = Status;
+        DPRINT("Calling completion routine %p Status %x\n", Irp, Status);
         *NewStatus = CompleteRoutine(Context, Irp);
     }
     else
     {
         /* Otherwise do a normal I/O complete request */
+        DPRINT("Completing IRP %p Status %x\n", Irp, Status);
         FsRtlCompleteRequest(Irp, Status);
         *NewStatus = Status;
     }
@@ -229,6 +258,58 @@
        Entry = RtlEnumerateGenericTable(FileLock->LockInformation, Restart);
        if (!Entry) return NULL;
        else return &Entry->Exclusive.FileLock;
+}
+
+/* This function expands the conflicting range Conflict by removing and 
reinserting it,
+   then adds a shared range of the same size */
+PCOMBINED_LOCK_ELEMENT
+NTAPI
+FsRtlpSubsumeSharedLock
+(PFILE_LOCK FileLock,
+ PLOCK_INFORMATION LockInfo,
+ PCOMBINED_LOCK_ELEMENT ToInsert,
+ PCOMBINED_LOCK_ELEMENT Conflict)
+{
+    BOOLEAN InsertedNew = FALSE, RemovedOld;
+    COMBINED_LOCK_ELEMENT NewElement;
+    PLOCK_SHARED_RANGE SharedRange = 
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*SharedRange), 'FSRA');
+
+    if (!SharedRange)
+        return NULL;
+    
+    ASSERT(!Conflict->Exclusive.FileLock.ExclusiveLock);
+    ASSERT(!ToInsert->Exclusive.FileLock.ExclusiveLock);
+    SharedRange->Start = ToInsert->Exclusive.FileLock.StartingByte;
+    SharedRange->End = ToInsert->Exclusive.FileLock.EndingByte;
+    SharedRange->Key = ToInsert->Exclusive.FileLock.Key;
+    SharedRange->ProcessId = ToInsert->Exclusive.FileLock.ProcessId;
+    InsertTailList(&LockInfo->SharedLocks, &SharedRange->Entry);
+    
+    NewElement = *Conflict;
+    if (ToInsert->Exclusive.FileLock.StartingByte.QuadPart >
+        Conflict->Exclusive.FileLock.StartingByte.QuadPart)
+    {
+        NewElement.Exclusive.FileLock.StartingByte = 
+            Conflict->Exclusive.FileLock.StartingByte;
+    }
+    if (ToInsert->Exclusive.FileLock.EndingByte.QuadPart <
+        Conflict->Exclusive.FileLock.EndingByte.QuadPart)
+    {
+        NewElement.Exclusive.FileLock.EndingByte =
+            Conflict->Exclusive.FileLock.EndingByte;
+    }
+    RemovedOld = RtlDeleteElementGenericTable
+        (&LockInfo->RangeTable,
+         Conflict);
+    ASSERT(RemovedOld);
+    Conflict = RtlInsertElementGenericTable
+        (&LockInfo->RangeTable,
+         ToInsert,
+         sizeof(*ToInsert),
+         &InsertedNew);
+    ASSERT(InsertedNew && Conflict);
+    return Conflict;
 }
 
 /*
@@ -254,32 +335,59 @@
        PCOMBINED_LOCK_ELEMENT Conflict;
        PLOCK_INFORMATION LockInfo;
        BOOLEAN InsertedNew;
-
-    DPRINT1("FsRtlPrivateLock() is stubplemented!\n");
-    /* Windows 2003 ignores that parameter
-    ASSERT(AlreadySynchronized);
-    */
-
+    
+    DPRINT("FsRtlPrivateLock(%wZ, Offset %08x%08x, Length %08x%08x, Key %x, 
FailImmediately %d, Exclusive %d)\n", 
+           &FileObject->FileName, 
+           FileOffset->HighPart,
+           FileOffset->LowPart, 
+           Length->HighPart,
+           Length->LowPart, 
+           Key,
+           FailImmediately, 
+           ExclusiveLock);
+    
+    if (FileOffset->QuadPart < 0ll || 
+        FileOffset->QuadPart + Length->QuadPart < FileOffset->QuadPart)
+    {
+        DPRINT("File offset out of range\n");
+        IoStatus->Status = STATUS_INVALID_PARAMETER;
+        if (Irp)
+        {
+            DPRINT("Complete lock %p Status %x\n", Irp, IoStatus->Status);
+            FsRtlCompleteLockIrpReal
+                (FileLock->CompleteLockIrpRoutine,
+                 Context,
+                 Irp,
+                 IoStatus->Status,
+                 &Status,
+                 FileObject);
+        }
+        return FALSE;
+    }
+    
     /* Initialize the lock, if necessary */
     if (!FileLock->LockInformation)
     {
                LockInfo = ExAllocatePoolWithTag(NonPagedPool, 
sizeof(LOCK_INFORMATION), 'FLCK');
                FileLock->LockInformation = LockInfo;
-               if (!FileLock)
+               if (!FileLock) {
+            IoStatus->Status = STATUS_NO_MEMORY;
                        return FALSE;
-
+        }
+        
                LockInfo->BelongsTo = FileLock;
-
+        InitializeListHead(&LockInfo->SharedLocks);
+        
                RtlInitializeGenericTable
                        (&LockInfo->RangeTable,
                         LockCompare,
                         LockAllocate,
                         LockFree,
                         NULL);
-
+        
                KeInitializeSpinLock(&LockInfo->CsqLock);
         InitializeListHead(&LockInfo->CsqList);
-
+        
                IoCsqInitializeEx
                        (&LockInfo->Csq, 
                         LockInsertIrpEx,
@@ -289,7 +397,7 @@
                         LockReleaseQueueLock,
                         LockCompleteCanceledIrp);
     }
-
+    
        LockInfo = FileLock->LockInformation;
        ToInsert.Exclusive.FileLock.FileObject = FileObject;
        ToInsert.Exclusive.FileLock.StartingByte = *FileOffset;
@@ -297,13 +405,13 @@
        ToInsert.Exclusive.FileLock.ProcessId = Process->UniqueProcessId;
        ToInsert.Exclusive.FileLock.Key = Key;
        ToInsert.Exclusive.FileLock.ExclusiveLock = ExclusiveLock;
-
+    
        Conflict = RtlInsertElementGenericTable
                (FileLock->LockInformation,
                 &ToInsert,
                 sizeof(ToInsert),
                 &InsertedNew);
-
+    
        if (Conflict && !InsertedNew)
        {
                if (Conflict->Exclusive.FileLock.ExclusiveLock || ExclusiveLock)
@@ -340,18 +448,112 @@
                }
                else
                {
-                       IoStatus->Status = STATUS_SUCCESS;
-                       if (Irp)
+            ULONG i;
+            /* We know of at least one lock in range that's shared.  We need to
+             * find out if any more exist and any are exclusive. */
+            for (i = 0; i < 
RtlNumberGenericTableElements(&LockInfo->RangeTable); i++)
+            {
+                Conflict = RtlGetElementGenericTable(&LockInfo->RangeTable, i);
+                /* The first argument will be inserted as a shared range */
+                if (LockCompare(&LockInfo->RangeTable, Conflict, &ToInsert) == 
GenericEqual)
+                {
+                    if (Conflict->Exclusive.FileLock.ExclusiveLock)
+                    {
+                        /* Found an exclusive match */
+                        if (FailImmediately)
+                        {
+                            IoStatus->Status = STATUS_FILE_LOCK_CONFLICT;
+                            if (Irp)
+                            {
+                                FsRtlCompleteLockIrpReal
+                                    (FileLock->CompleteLockIrpRoutine,
+                                     Context,
+                                     Irp,
+                                     IoStatus->Status,
+                                     &Status,
+                                     FileObject);
+                            }
+                        }
+                        else
+                        {
+                            IoStatus->Status = STATUS_PENDING;
+                            if (Irp)
+                            {
+                                IoMarkIrpPending(Irp);
+                                IoCsqInsertIrpEx
+                                    (&LockInfo->Csq,
+                                     Irp,
+                                     NULL,
+                                     NULL);
+                            }
+                        }
+                        return FALSE;
+                    }
+                    else
+                    {
+                        /* We've made all overlapping shared ranges into one 
big range
+                         * now we need to add a range entry for the new range 
*/
+                        DPRINT("Overlapping shared lock %wZ %08x%08x 
%08x%08x\n",
+                               &FileObject->FileName,
+                               
Conflict->Exclusive.FileLock.StartingByte.HighPart,
+                               
Conflict->Exclusive.FileLock.StartingByte.LowPart,
+                               
Conflict->Exclusive.FileLock.EndingByte.HighPart,
+                               
Conflict->Exclusive.FileLock.EndingByte.LowPart);
+                        Conflict = FsRtlpSubsumeSharedLock
+                            (FileLock, LockInfo, &ToInsert, Conflict);
+                        if (!Conflict)
+                        {
+                            IoStatus->Status = STATUS_NO_MEMORY;
+                            if (Irp)
+                            {
+                                FsRtlCompleteLockIrpReal
+                                    (FileLock->CompleteLockIrpRoutine,
+                                     Context,
+                                     Irp,
+                                     IoStatus->Status,
+                                     &Status,
+                                     FileObject);
+                            }
+                            return FALSE;
+                        }
+                    }
+                }
+            }
+
+            /* We got here because there were only overlapping shared locks */
+            DPRINT("Acquired shared lock %wZ %08x%08x %08x%08x\n",
+                   &FileObject->FileName,
+                   Conflict->Exclusive.FileLock.StartingByte.HighPart,
+                   Conflict->Exclusive.FileLock.StartingByte.LowPart,
+                   Conflict->Exclusive.FileLock.EndingByte.HighPart,
+                   Conflict->Exclusive.FileLock.EndingByte.LowPart);
+            if (!FsRtlpSubsumeSharedLock(FileLock, LockInfo, &ToInsert, 
Conflict))
                        {
-                               FsRtlCompleteLockIrpReal
-                                       (FileLock->CompleteLockIrpRoutine,
-                                        Context,
-                                        Irp,
-                                        IoStatus->Status,
-                                        &Status,
-                                        FileObject);
+                IoStatus->Status = STATUS_NO_MEMORY;
+                if (Irp)
+                {
+                    FsRtlCompleteLockIrpReal
+                        (FileLock->CompleteLockIrpRoutine,
+                         Context,
+                         Irp,
+                         IoStatus->Status,
+                         &Status,
+                         FileObject);
+                }
+                return FALSE;
                        }
-                       return FALSE;
+            IoStatus->Status = STATUS_SUCCESS;
+            if (Irp)
+            {
+                FsRtlCompleteLockIrpReal
+                    (FileLock->CompleteLockIrpRoutine,
+                     Context,
+                     Irp,
+                     IoStatus->Status,
+                     &Status,
+                     FileObject);
+            }
+                       return TRUE;
                }
        }
        else if (!Conflict)
@@ -359,13 +561,58 @@
                /* Conflict here is (or would be) the newly inserted element, 
but we ran
                 * out of space probably. */
                IoStatus->Status = STATUS_NO_MEMORY;
+               if (Irp)
+               {
+                       FsRtlCompleteLockIrpReal
+                               (FileLock->CompleteLockIrpRoutine,
+                                Context,
+                                Irp,
+                                IoStatus->Status,
+                                &Status,
+                                FileObject);
+               }
                return FALSE;
        }
        else
        {
+        DPRINT("Inserted new lock %wZ %08x%08x %08x%08x exclusive %d\n",
+               &FileObject->FileName,
+               Conflict->Exclusive.FileLock.StartingByte.HighPart,
+               Conflict->Exclusive.FileLock.StartingByte.LowPart,
+               Conflict->Exclusive.FileLock.StartingByte.HighPart,
+               Conflict->Exclusive.FileLock.StartingByte.LowPart,
+               Conflict->Exclusive.FileLock.ExclusiveLock);
+        if (!ExclusiveLock)
+        {
+            PLOCK_SHARED_RANGE NewSharedRange;
+            NewSharedRange = 
+                ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), 
'FSRA');
+            if (!NewSharedRange)
+            {
+                IoStatus->Status = STATUS_NO_MEMORY;
+                if (Irp)
+                {
+                    FsRtlCompleteLockIrpReal
+                        (FileLock->CompleteLockIrpRoutine,
+                         Context,
+                         Irp,
+                         IoStatus->Status,
+                         &Status,
+                         FileObject);
+                }
+                return FALSE;
+            }
+            DPRINT("Adding shared lock %wZ\n", &FileObject->FileName);
+            NewSharedRange->Start = ToInsert.Exclusive.FileLock.StartingByte;
+            NewSharedRange->End = ToInsert.Exclusive.FileLock.EndingByte;
+            NewSharedRange->Key = Key;
+            NewSharedRange->ProcessId = ToInsert.Exclusive.FileLock.ProcessId;
+            InsertTailList(&LockInfo->SharedLocks, &NewSharedRange->Entry);
+        }
+        
                /* Assume all is cool, and lock is set */
                IoStatus->Status = STATUS_SUCCESS;
-       
+        
                if (Irp)
                {
                        /* Complete the request */
@@ -375,12 +622,12 @@
                                                                         
IoStatus->Status,
                                                                         
&Status,
                                                                         
FileObject);
-                       
+            
                        /* Update the status */
                        IoStatus->Status = Status;
                }
        }
-
+    
     return TRUE;
 }
 
@@ -392,10 +639,19 @@
 FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock,
                             IN PIRP Irp)
 {
+    BOOLEAN Result;
        PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
        COMBINED_LOCK_ELEMENT ToFind;
        PCOMBINED_LOCK_ELEMENT Found;
-       if (!FileLock->LockInformation) return TRUE;
+    DPRINT("CheckLockForReadAccess(%wZ, Offset %08x%08x, Length %x)\n", 
+           &IoStack->FileObject->FileName,
+           IoStack->Parameters.Read.ByteOffset.HighPart,
+           IoStack->Parameters.Read.ByteOffset.LowPart,
+           IoStack->Parameters.Read.Length);
+       if (!FileLock->LockInformation) {
+        DPRINT("CheckLockForReadAccess(%wZ) => TRUE\n", 
&IoStack->FileObject->FileName);
+        return TRUE;
+    }
        ToFind.Exclusive.FileLock.StartingByte = 
IoStack->Parameters.Read.ByteOffset;
        ToFind.Exclusive.FileLock.EndingByte.QuadPart = 
                ToFind.Exclusive.FileLock.StartingByte.QuadPart + 
@@ -403,9 +659,14 @@
        Found = RtlLookupElementGenericTable
                (FileLock->LockInformation,
                 &ToFind);
-       if (!Found) return TRUE;
-       return !Found->Exclusive.FileLock.ExclusiveLock || 
+       if (!Found) {
+        DPRINT("CheckLockForReadAccess(%wZ) => TRUE\n", 
&IoStack->FileObject->FileName);
+        return TRUE;
+    }
+       Result = !Found->Exclusive.FileLock.ExclusiveLock || 
                IoStack->Parameters.Read.Key == Found->Exclusive.FileLock.Key;
+    DPRINT("CheckLockForReadAccess(%wZ) => %s\n", 
&IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE");
+    return Result;
 }
 
 /*
@@ -416,11 +677,20 @@
 FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock,
                              IN PIRP Irp)
 {
+    BOOLEAN Result;
        PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
        COMBINED_LOCK_ELEMENT ToFind;
        PCOMBINED_LOCK_ELEMENT Found;
        PEPROCESS Process = Irp->Tail.Overlay.Thread->ThreadsProcess;
-       if (!FileLock->LockInformation) return TRUE;
+    DPRINT("CheckLockForWriteAccess(%wZ, Offset %08x%08x, Length %x)\n", 
+           &IoStack->FileObject->FileName,
+           IoStack->Parameters.Write.ByteOffset.HighPart,
+           IoStack->Parameters.Write.ByteOffset.LowPart,
+           IoStack->Parameters.Write.Length);
+       if (!FileLock->LockInformation) {
+        DPRINT("CheckLockForWriteAccess(%wZ) => TRUE\n", 
&IoStack->FileObject->FileName);
+        return TRUE;
+    }
        ToFind.Exclusive.FileLock.StartingByte = 
IoStack->Parameters.Write.ByteOffset;
        ToFind.Exclusive.FileLock.EndingByte.QuadPart = 
                ToFind.Exclusive.FileLock.StartingByte.QuadPart + 
@@ -428,8 +698,13 @@
        Found = RtlLookupElementGenericTable
                (FileLock->LockInformation,
                 &ToFind);
-       if (!Found) return TRUE;
-       return Process->UniqueProcessId == Found->Exclusive.FileLock.ProcessId;
+       if (!Found) {
+        DPRINT("CheckLockForWriteAccess(%wZ) => TRUE\n", 
&IoStack->FileObject->FileName);
+        return TRUE;
+    }
+       Result = Process->UniqueProcessId == 
Found->Exclusive.FileLock.ProcessId;
+    DPRINT("CheckLockForWriteAccess(%wZ) => %s\n", 
&IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE");
+    return Result;
 }
 
 /*
@@ -447,6 +722,13 @@
        PEPROCESS EProcess = Process;
        COMBINED_LOCK_ELEMENT ToFind;
        PCOMBINED_LOCK_ELEMENT Found;
+    DPRINT("FsRtlFastCheckLockForRead(%wZ, Offset %08x%08x, Length %08x%08x, 
Key %x)\n", 
+           &FileObject->FileName, 
+           FileOffset->HighPart,
+           FileOffset->LowPart, 
+           Length->HighPart,
+           Length->LowPart,
+           Key);
        ToFind.Exclusive.FileLock.StartingByte = *FileOffset;
        ToFind.Exclusive.FileLock.EndingByte.QuadPart = 
                FileOffset->QuadPart + Length->QuadPart;
@@ -471,19 +753,35 @@
                            IN PFILE_OBJECT FileObject,
                            IN PVOID Process)
 {
+    BOOLEAN Result;
        PEPROCESS EProcess = Process;
        COMBINED_LOCK_ELEMENT ToFind;
        PCOMBINED_LOCK_ELEMENT Found;
+    DPRINT("FsRtlFastCheckLockForWrite(%wZ, Offset %08x%08x, Length %08x%08x, 
Key %x)\n", 
+           &FileObject->FileName, 
+           FileOffset->HighPart,
+           FileOffset->LowPart, 
+           Length->HighPart,
+           Length->LowPart,
+           Key);
        ToFind.Exclusive.FileLock.StartingByte = *FileOffset;
        ToFind.Exclusive.FileLock.EndingByte.QuadPart = 
                FileOffset->QuadPart + Length->QuadPart;
-       if (!FileLock->LockInformation) return TRUE;
+       if (!FileLock->LockInformation) {
+        DPRINT("CheckForWrite(%wZ) => TRUE\n", &FileObject->FileName);
+        return TRUE;
+    }
        Found = RtlLookupElementGenericTable
                (FileLock->LockInformation,
                 &ToFind);
-       if (!Found) return TRUE;
-       return Found->Exclusive.FileLock.Key == Key && 
+       if (!Found) {
+        DPRINT("CheckForWrite(%wZ) => TRUE\n", &FileObject->FileName);
+        return TRUE;
+    }
+       Result = Found->Exclusive.FileLock.Key == Key && 
                Found->Exclusive.FileLock.ProcessId == 
EProcess->UniqueProcessId;
+    DPRINT("CheckForWrite(%wZ) => %s\n", &FileObject->FileName, Result ? 
"TRUE" : "FALSE");
+    return Result;
 }
 
 /*
@@ -500,10 +798,20 @@
                       IN PVOID Context OPTIONAL,
                       IN BOOLEAN AlreadySynchronized)
 {
+    BOOLEAN FoundShared = FALSE;
+    PLIST_ENTRY SharedEntry;
+    PLOCK_SHARED_RANGE SharedRange = NULL;
        COMBINED_LOCK_ELEMENT Find;
        PCOMBINED_LOCK_ELEMENT Entry;
        PIRP NextMatchingLockIrp;
        PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
+    DPRINT("FsRtlFastUnlockSingle(%wZ, Offset %08x%08x, Length %08x%08x, Key 
%x)\n", 
+           &FileObject->FileName, 
+           FileOffset->HighPart,
+           FileOffset->LowPart, 
+           Length->HighPart,
+           Length->LowPart,
+           Key);
        // The region to unlock must correspond exactly to a previously locked 
region
        // -- msdn
        // But Windows 2003 doesn't assert on it and simply ignores that 
parameter
@@ -512,26 +820,101 @@
        Find.Exclusive.FileLock.EndingByte.QuadPart = 
                FileOffset->QuadPart + Length->QuadPart;
        Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find);
-       if (!Entry) return STATUS_RANGE_NOT_LOCKED;
-       if (Entry->Exclusive.FileLock.Key != Key || 
-               Entry->Exclusive.FileLock.ProcessId != Process->UniqueProcessId)
-               return STATUS_RANGE_NOT_LOCKED;
-       if (Entry->Exclusive.FileLock.StartingByte.QuadPart != 
FileOffset->QuadPart ||
-               Entry->Exclusive.FileLock.EndingByte.QuadPart != 
-               FileOffset->QuadPart + Length->QuadPart)
-               return STATUS_RANGE_NOT_LOCKED;
+       if (!Entry) {
+        DPRINT("Range not locked %wZ\n", &FileObject->FileName);
+        return STATUS_RANGE_NOT_LOCKED;
+    }
+    
+    if (Entry->Exclusive.FileLock.ExclusiveLock)
+    {
+        if (Entry->Exclusive.FileLock.Key != Key ||
+            Entry->Exclusive.FileLock.ProcessId != Process->UniqueProcessId ||
+            Entry->Exclusive.FileLock.StartingByte.QuadPart != 
FileOffset->QuadPart ||
+            Entry->Exclusive.FileLock.EndingByte.QuadPart != 
+            FileOffset->QuadPart + Length->QuadPart)
+        {
+            DPRINT("Range not locked %wZ\n", &FileObject->FileName);
+            return STATUS_RANGE_NOT_LOCKED;
+        }
+        RtlCopyMemory(&Find, Entry, sizeof(Find));
+    }
+    else
+    {
+        DPRINT("Shared lock %wZ Start %08x%08x End %08x%08x\n", 
+               &FileObject->FileName,
+               Entry->Exclusive.FileLock.StartingByte.HighPart,
+               Entry->Exclusive.FileLock.StartingByte.LowPart,
+               Entry->Exclusive.FileLock.EndingByte.HighPart,
+               Entry->Exclusive.FileLock.EndingByte.LowPart);
+        for (SharedEntry = InternalInfo->SharedLocks.Flink;
+             SharedEntry != &InternalInfo->SharedLocks;
+             SharedEntry = SharedEntry->Flink)
+        {
+            SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, 
Entry);
+            if (SharedRange->Start.QuadPart == FileOffset->QuadPart &&
+                SharedRange->End.QuadPart == FileOffset->QuadPart + 
Length->QuadPart &&
+                SharedRange->Key == Key &&
+                SharedRange->ProcessId == Process->UniqueProcessId)
+            {
+                FoundShared = TRUE;
+                DPRINT("Found shared element to delete %wZ Start %08x%08x End 
%08x%08x Key %x\n",
+                       &FileObject->FileName,
+                       SharedRange->Start.HighPart,
+                       SharedRange->Start.LowPart,
+                       SharedRange->End.HighPart,
+                       SharedRange->End.LowPart,
+                       SharedRange->Key);
+                break;
+            }
+        }
+        if (FoundShared)
+        {
+            Find.Exclusive.FileLock.StartingByte = SharedRange->Start;
+            Find.Exclusive.FileLock.EndingByte = SharedRange->End;
+            SharedEntry = SharedRange->Entry.Flink;
+            RemoveEntryList(&SharedRange->Entry);
+            ExFreePool(SharedRange);
+        }
+        else
+        {
+            return STATUS_RANGE_NOT_LOCKED;
+        }
+    }
+    
+    if (IsListEmpty(&InternalInfo->SharedLocks)) {
+        DPRINT("Removing the lock entry %wZ\n", &FileObject->FileName);
+        RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry);
+    } else {
+        DPRINT("Lock still has:\n");
+        for (SharedEntry = InternalInfo->SharedLocks.Flink;
+             SharedEntry != &InternalInfo->SharedLocks;
+             SharedEntry = SharedEntry->Flink)
+        {
+            SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, 
Entry);
+            DPRINT("Shared element %wZ Offset %08x%08x Length %08x%08x Key 
%x\n",
+                   &FileObject->FileName,
+                   SharedRange->Start.HighPart,
+                   SharedRange->Start.LowPart,
+                   SharedRange->End.HighPart,
+                   SharedRange->End.LowPart,
+                   SharedRange->Key);
+        }
+    }
+    
        // this is definitely the thing we want
-       RtlCopyMemory(&Find, Entry, sizeof(Find));
-       NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find);
-    RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry);
-       while (NextMatchingLockIrp)
-       {
-               // Got a new lock irp... try to do the new lock operation
-               // Note that we pick an operation that would succeed at the time
-               // we looked, but can't guarantee that it won't just be 
re-queued
-               // because somebody else snatched part of the range in a new 
thread.
-               FsRtlProcessFileLock(InternalInfo->BelongsTo, 
NextMatchingLockIrp, NULL);
-       }
+    NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find);
+    while (NextMatchingLockIrp)
+    {
+        // Got a new lock irp... try to do the new lock operation
+        // Note that we pick an operation that would succeed at the time
+        // we looked, but can't guarantee that it won't just be re-queued
+        // because somebody else snatched part of the range in a new thread.
+        DPRINT("Locking another IRP %p for %p %wZ\n", 
+               &FileObject->FileName, FileLock, NextMatchingLockIrp);
+        FsRtlProcessFileLock(InternalInfo->BelongsTo, NextMatchingLockIrp, 
NULL);
+    }
+    
+    DPRINT("Success %wZ\n", &FileObject->FileName);
        return STATUS_SUCCESS;
 }
 
@@ -547,11 +930,14 @@
 {
        PCOMBINED_LOCK_ELEMENT Entry;
        PRTL_GENERIC_TABLE InternalInfo = FileLock->LockInformation;
-
+    DPRINT("FsRtlFastUnlockAll(%wZ)\n", &FileObject->FileName);
        // XXX Synchronize somehow
-       if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no 
locks
+       if (!FileLock->LockInformation) {
+        DPRINT("Not locked %wZ\n", &FileObject->FileName);
+        return STATUS_RANGE_NOT_LOCKED; // no locks
+    }
        for (Entry = RtlEnumerateGenericTable(InternalInfo, TRUE);
-                        Entry;
+         Entry;
                 Entry = RtlEnumerateGenericTable(InternalInfo, FALSE))
        {
                LARGE_INTEGER Length;
@@ -569,7 +955,7 @@
                         Context,
                         TRUE);
        }
-
+    DPRINT("Done %wZ\n", &FileObject->FileName);
     return STATUS_SUCCESS;
 }
 
@@ -586,11 +972,13 @@
 {
        PCOMBINED_LOCK_ELEMENT Entry;
        PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
-
+    
+    DPRINT("FsRtlFastUnlockAllByKey(%wZ,Key %x)\n", &FileObject->FileName, 
Key);
+    
        // XXX Synchronize somehow
        if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no 
locks
        for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE);
-                        Entry;
+         Entry;
                 Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, 
FALSE))
        {
                LARGE_INTEGER Length;
@@ -612,7 +1000,7 @@
                                 TRUE);
                }
        }
-
+    
     return STATUS_SUCCESS;
 }
 
@@ -628,110 +1016,99 @@
     PIO_STACK_LOCATION IoStackLocation;
     NTSTATUS Status;
     IO_STATUS_BLOCK IoStatusBlock;
-
+    
     /* Get the I/O Stack location */
     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
     ASSERT(IoStackLocation->MajorFunction == IRP_MJ_LOCK_CONTROL);
-
+    
     /* Clear the I/O status block and check what function this is */
     IoStatusBlock.Information = 0;
+    
+    DPRINT("FsRtlProcessFileLock(%wZ, MinorFunction %x)\n", 
+           &IoStackLocation->FileObject->FileName,
+           IoStackLocation->MinorFunction);
+    
     switch(IoStackLocation->MinorFunction)
     {
         /* A lock */
-        case IRP_MN_LOCK:
-
-            /* Call the private lock routine */
-            FsRtlPrivateLock(FileLock,
-                             IoStackLocation->FileObject,
-                             &IoStackLocation->
-                             Parameters.LockControl.ByteOffset,
-                             IoStackLocation->Parameters.LockControl.Length,
-                             IoGetRequestorProcess(Irp),
-                             IoStackLocation->Parameters.LockControl.Key,
-                             IoStackLocation->Flags & SL_FAIL_IMMEDIATELY,
-                             IoStackLocation->Flags & SL_EXCLUSIVE_LOCK,
-                             &IoStatusBlock,
-                             Irp,
-                             Context,
-                             FALSE);
-            break;
-
+    case IRP_MN_LOCK:
+        
+        /* Call the private lock routine */
+        FsRtlPrivateLock(FileLock,
+                         IoStackLocation->FileObject,
+                         &IoStackLocation->
+                         Parameters.LockControl.ByteOffset,
+                         IoStackLocation->Parameters.LockControl.Length,
+                         IoGetRequestorProcess(Irp),
+                         IoStackLocation->Parameters.LockControl.Key,
+                         IoStackLocation->Flags & SL_FAIL_IMMEDIATELY,
+                         IoStackLocation->Flags & SL_EXCLUSIVE_LOCK,
+                         &IoStatusBlock,
+                         Irp,
+                         Context,
+                         FALSE);
+        return IoStatusBlock.Status;
+        
         /* A single unlock */
-        case IRP_MN_UNLOCK_SINGLE:
-
-            /* Call fast unlock */
-            IoStatusBlock.Status =
-                FsRtlFastUnlockSingle(FileLock,
-                                      IoStackLocation->FileObject,
-                                      &IoStackLocation->Parameters.LockControl.
-                                      ByteOffset,
-                                      IoStackLocation->Parameters.LockControl.
-                                      Length,
-                                      IoGetRequestorProcess(Irp),
-                                      IoStackLocation->Parameters.LockControl.
-                                      Key,
-                                      Context,
-                                      FALSE);
-
-            /* Complete the IRP */
-            FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
-                                     Context,
-                                     Irp,
-                                     IoStatusBlock.Status,
-                                     &Status,
-                                     NULL);
-            break;
-
+    case IRP_MN_UNLOCK_SINGLE:
+        
+        /* Call fast unlock */
+        IoStatusBlock.Status =
+            FsRtlFastUnlockSingle(FileLock,
+                                  IoStackLocation->FileObject,
+                                  &IoStackLocation->Parameters.LockControl.
+                                  ByteOffset,
+                                  IoStackLocation->Parameters.LockControl.
+                                  Length,
+                                  IoGetRequestorProcess(Irp),
+                                  IoStackLocation->Parameters.LockControl.
+                                  Key,
+                                  Context,
+                                  FALSE);
+        break;
+        
         /* Total unlock */
-        case IRP_MN_UNLOCK_ALL:
-
-            /* Do a fast unlock */
-            IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock,
-                                                      IoStackLocation->
-                                                      FileObject,
-                                                      
IoGetRequestorProcess(Irp),
-                                                      Context);
-
-            /* Complete the IRP */
-            FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
-                                     Context,
-                                     Irp,
-                                     IoStatusBlock.Status,
-                                     &Status,
-                                     NULL);
-            break;
-
+    case IRP_MN_UNLOCK_ALL:
+        
+        /* Do a fast unlock */
+        IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock,
+                                                  IoStackLocation->
+                                                  FileObject,
+                                                  IoGetRequestorProcess(Irp),
+                                                  Context);
+        break;
+        
         /* Unlock by key */
-        case IRP_MN_UNLOCK_ALL_BY_KEY:
-
-            /* Do it */
-            IoStatusBlock.Status =
-                FsRtlFastUnlockAllByKey(FileLock,
-                                        IoStackLocation->FileObject,
-                                        IoGetRequestorProcess(Irp),
-                                        IoStackLocation->Parameters.
-                                        LockControl.Key,
-                                        Context);
-
-            /* Complete the IRP */
-            FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
-                                     Context,
-                                     Irp,
-                                     IoStatusBlock.Status,
-                                     &Status,
-                                     NULL);
-            break;
-
+    case IRP_MN_UNLOCK_ALL_BY_KEY:
+        
+        /* Do it */
+        IoStatusBlock.Status =
+            FsRtlFastUnlockAllByKey(FileLock,
+                                    IoStackLocation->FileObject,
+                                    IoGetRequestorProcess(Irp),
+                                    IoStackLocation->Parameters.
+                                    LockControl.Key,
+                                    Context);
+        break;
+        
         /* Invalid request */
-        default:
-
-            /* Complete it */
-            FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST);
-            IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST;
-            break;
-    }
-
+    default:
+        
+        /* Complete it */
+        FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST);
+        IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST;
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+    
     /* Return the status */
+    DPRINT("Lock IRP %p %x\n", Irp, IoStatusBlock.Status);
+    FsRtlCompleteLockIrpReal
+        (FileLock->CompleteLockIrpRoutine,
+         Context,
+         Irp,
+         IoStatusBlock.Status,
+         &Status,
+         NULL);
     return IoStatusBlock.Status;
 }
 
@@ -764,7 +1141,17 @@
         PIRP Irp;
         PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
         PCOMBINED_LOCK_ELEMENT Entry;
+        PLIST_ENTRY SharedEntry;
+        PLOCK_SHARED_RANGE SharedRange;
         // MSDN: this completes any remaining lock IRPs
+        for (SharedEntry = InternalInfo->SharedLocks.Flink;
+             SharedEntry != &InternalInfo->SharedLocks;)
+        {
+            SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, 
Entry);
+            SharedEntry = SharedEntry->Flink;
+            RemoveEntryList(SharedEntry);
+            ExFreePool(SharedRange);
+        }
         while ((Entry = RtlGetElementGenericTable(&InternalInfo->RangeTable, 
0)) != NULL)
         {
             RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry);
@@ -787,7 +1174,7 @@
                       IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL)
 {
     PFILE_LOCK FileLock;
-
+    
     /* Try to allocate it */
     FileLock = ExAllocateFromPagedLookasideList(&FsRtlFileLockLookasideList);
     if (FileLock)
@@ -797,7 +1184,7 @@
                                 CompleteLockIrpRoutine,
                                 UnlockRoutine);
     }
-
+    
     /* Return the lock */
     return FileLock;
 }


Reply via email to