[NPFS]
[reactos.git] / reactos / drivers / filesystems / npfs / rw.c
index 7b14449..3c54bd7 100644 (file)
@@ -48,46 +48,70 @@ NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
                            IN PIRP Irp)
 {
     PNPFS_CONTEXT Context;
-    PNPFS_DEVICE_EXTENSION DeviceExt;
     PIO_STACK_LOCATION IoStack;
+    PNPFS_VCB Vcb;
     PNPFS_CCB Ccb;
-    BOOLEAN Complete = FALSE;
+    PLIST_ENTRY ListEntry;
+    PNPFS_THREAD_CONTEXT ThreadContext;
+    ULONG i;
 
     DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
 
     IoReleaseCancelSpinLock(Irp->CancelIrql);
 
     Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
-    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
     IoStack = IoGetCurrentIrpStackLocation(Irp);
     Ccb = IoStack->FileObject->FsContext2;
 
-    KeLockMutex(&DeviceExt->PipeListLock);
+    KeLockMutex(&Vcb->PipeListLock);
     ExAcquireFastMutex(&Ccb->DataListLock);
     switch(IoStack->MajorFunction)
     {
     case IRP_MJ_READ:
-        if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
-        {
-            /* we are not the first in the list, remove an complete us */
-            RemoveEntryList(&Context->ListEntry);
-            Complete = TRUE;
-        }
-        else
+        ListEntry = Vcb->ThreadListHead.Flink;
+        while (ListEntry != &Vcb->ThreadListHead)
         {
-            KeSetEvent(&Ccb->ReadEvent, IO_NO_INCREMENT, FALSE);
+            ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
+            /* Real events start at index 1 */
+            for (i = 1; i < ThreadContext->Count; i++)
+            {
+                if (ThreadContext->WaitIrpArray[i] == Irp)
+                {
+                    ASSERT(ThreadContext->WaitObjectArray[i] == Context->WaitEvent);
+
+                    ThreadContext->WaitIrpArray[i] = NULL;
+
+                    RemoveEntryList(&Context->ListEntry);
+
+                    Irp->IoStatus.Status = STATUS_CANCELLED;
+                    Irp->IoStatus.Information = 0;
+
+                    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+                    KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
+
+                    ExReleaseFastMutex(&Ccb->DataListLock);
+                    KeUnlockMutex(&Vcb->PipeListLock);
+
+                    return;
+                }
+            }
+            ListEntry = ListEntry->Flink;
         }
-        break;
-    default:
-        ASSERT(FALSE);
-    }
-    ExReleaseFastMutex(&Ccb->DataListLock);
-    KeUnlockMutex(&DeviceExt->PipeListLock);
-    if (Complete)
-    {
+
+        RemoveEntryList(&Context->ListEntry);
+
+        ExReleaseFastMutex(&Ccb->DataListLock);
+        KeUnlockMutex(&Vcb->PipeListLock);
+
         Irp->IoStatus.Status = STATUS_CANCELLED;
         Irp->IoStatus.Information = 0;
+
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        break;
+    default:
+        ASSERT(FALSE);
     }
 }
 
@@ -96,46 +120,35 @@ NpfsWaiterThread(PVOID InitContext)
 {
     PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
     ULONG CurrentCount;
-    ULONG Count = 0;
+    ULONG Count = 0, i;
     PIRP Irp = NULL;
-    PIRP NextIrp;
     NTSTATUS Status;
-    BOOLEAN Terminate = FALSE;
-    BOOLEAN Cancel = FALSE;
     PIO_STACK_LOCATION IoStack = NULL;
-    PNPFS_CONTEXT Context;
-    PNPFS_CONTEXT NextContext;
-    PNPFS_CCB Ccb;
+    KIRQL OldIrql;
 
-    KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
+    KeLockMutex(&ThreadContext->Vcb->PipeListLock);
 
     while (1)
     {
         CurrentCount = ThreadContext->Count;
-        KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
-        if (Irp)
+        KeUnlockMutex(&ThreadContext->Vcb->PipeListLock);
+        IoAcquireCancelSpinLock(&OldIrql);
+        if (Irp && IoSetCancelRoutine(Irp, NULL) != NULL)
         {
-            if (Cancel)
-            {
-                Irp->IoStatus.Status = STATUS_CANCELLED;
-                Irp->IoStatus.Information = 0;
-                IoCompleteRequest(Irp, IO_NO_INCREMENT);
-            }
-            else
+            IoReleaseCancelSpinLock(OldIrql);
+            IoStack = IoGetCurrentIrpStackLocation(Irp);
+            switch (IoStack->MajorFunction)
             {
-                switch (IoStack->MajorFunction)
-                {
                 case IRP_MJ_READ:
                     NpfsRead(IoStack->DeviceObject, Irp);
                     break;
                 default:
                     ASSERT(FALSE);
-                }
             }
         }
-        if (Terminate)
+        else
         {
-            break;
+            IoReleaseCancelSpinLock(OldIrql);
         }
         Status = KeWaitForMultipleObjects(CurrentCount,
             ThreadContext->WaitObjectArray,
@@ -149,57 +162,41 @@ NpfsWaiterThread(PVOID InitContext)
         {
             ASSERT(FALSE);
         }
-        KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
-        Count = Status - STATUS_SUCCESS;
+        KeLockMutex(&ThreadContext->Vcb->PipeListLock);
+        Count = Status - STATUS_WAIT_0;
         ASSERT (Count < CurrentCount);
         if (Count > 0)
         {
             Irp = ThreadContext->WaitIrpArray[Count];
             ThreadContext->Count--;
-            ThreadContext->DeviceExt->EmptyWaiterCount++;
+            ThreadContext->Vcb->EmptyWaiterCount++;
             ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
             ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
+        }
+        else
+        {
+            /* someone has add a new wait request or cancelled an old one */
+            Irp = NULL;
 
-            Cancel = (NULL == IoSetCancelRoutine(Irp, NULL));
-            Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
-            IoStack = IoGetCurrentIrpStackLocation(Irp);
-
-            if (Cancel)
+            /* Look for cancelled requests */
+            for (i = 1; i < ThreadContext->Count; i++)
             {
-                Ccb = IoStack->FileObject->FsContext2;
-                ExAcquireFastMutex(&Ccb->DataListLock);
-                RemoveEntryList(&Context->ListEntry);
-                switch (IoStack->MajorFunction)
+                if (ThreadContext->WaitIrpArray[i] == NULL)
                 {
-                case IRP_MJ_READ:
-                    if (!IsListEmpty(&Ccb->ReadRequestListHead))
-                    {
-                        /* put the next request on the wait list */
-                        NextContext = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
-                        ThreadContext->WaitObjectArray[ThreadContext->Count] = NextContext->WaitEvent;
-                        NextIrp = CONTAINING_RECORD(NextContext, IRP, Tail.Overlay.DriverContext);
-                        ThreadContext->WaitIrpArray[ThreadContext->Count] = NextIrp;
-                        ThreadContext->Count++;
-                        ThreadContext->DeviceExt->EmptyWaiterCount--;
-                    }
-                    break;
-                default:
-                    ASSERT(FALSE);
+                   ThreadContext->Count--;
+                   ThreadContext->Vcb->EmptyWaiterCount++;
+                   ThreadContext->WaitObjectArray[i] = ThreadContext->WaitObjectArray[ThreadContext->Count];
+                   ThreadContext->WaitIrpArray[i] = ThreadContext->WaitIrpArray[ThreadContext->Count];
                 }
-                ExReleaseFastMutex(&Ccb->DataListLock);
             }
         }
-        else
-        {
-            /* someone has add a new wait request */
-            Irp = NULL;
-        }
-        if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
+        if (ThreadContext->Count == 1 && ThreadContext->Vcb->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
         {
             /* it exist an other thread with empty wait slots, we can remove our thread from the list */
             RemoveEntryList(&ThreadContext->ListEntry);
-            ThreadContext->DeviceExt->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
-            Terminate = TRUE;
+            ThreadContext->Vcb->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
+            KeUnlockMutex(&ThreadContext->Vcb->PipeListLock);
+            break;
         }
     }
     ExFreePool(ThreadContext);
@@ -211,19 +208,21 @@ NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
 {
     PLIST_ENTRY ListEntry;
     PNPFS_THREAD_CONTEXT ThreadContext = NULL;
-    NTSTATUS Status;
+    PNPFS_CONTEXT Context;
     HANDLE hThread;
+    PNPFS_VCB Vcb;
     KIRQL oldIrql;
+    NTSTATUS Status;
 
-    PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
-    PNPFS_DEVICE_EXTENSION DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
+    Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
 
     DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
 
-    KeLockMutex(&DeviceExt->PipeListLock);
+    KeLockMutex(&Vcb->PipeListLock);
 
-    ListEntry = DeviceExt->ThreadListHead.Flink;
-    while (ListEntry != &DeviceExt->ThreadListHead)
+    ListEntry = Vcb->ThreadListHead.Flink;
+    while (ListEntry != &Vcb->ThreadListHead)
     {
         ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
         if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
@@ -232,20 +231,21 @@ NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
         }
         ListEntry = ListEntry->Flink;
     }
-    if (ListEntry == &DeviceExt->ThreadListHead)
+
+    if (ListEntry == &Vcb->ThreadListHead)
     {
         ThreadContext = ExAllocatePool(NonPagedPool, sizeof(NPFS_THREAD_CONTEXT));
         if (ThreadContext == NULL)
         {
-            KeUnlockMutex(&DeviceExt->PipeListLock);
+            KeUnlockMutex(&Vcb->PipeListLock);
             return STATUS_NO_MEMORY;
         }
-        ThreadContext->DeviceExt = DeviceExt;
+
+        ThreadContext->Vcb = Vcb;
         KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
         ThreadContext->Count = 1;
         ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
 
-
         DPRINT("Creating a new system thread for waiting read/write requests\n");
 
         Status = PsCreateSystemThread(&hThread,
@@ -258,11 +258,12 @@ NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
         if (!NT_SUCCESS(Status))
         {
             ExFreePool(ThreadContext);
-            KeUnlockMutex(&DeviceExt->PipeListLock);
+            KeUnlockMutex(&Vcb->PipeListLock);
             return Status;
         }
-        InsertHeadList(&DeviceExt->ThreadListHead, &ThreadContext->ListEntry);
-        DeviceExt->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
+
+        InsertHeadList(&Vcb->ThreadListHead, &ThreadContext->ListEntry);
+        Vcb->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
     }
     IoMarkIrpPending(Irp);
 
@@ -279,11 +280,11 @@ NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
         ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
         ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
         ThreadContext->Count++;
-        DeviceExt->EmptyWaiterCount--;
+        Vcb->EmptyWaiterCount--;
         KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
         Status = STATUS_SUCCESS;
     }
-    KeUnlockMutex(&DeviceExt->PipeListLock);
+    KeUnlockMutex(&Vcb->PipeListLock);
     return Status;
 }
 
@@ -332,10 +333,7 @@ NpfsRead(IN PDEVICE_OBJECT DeviceObject,
     if ((Ccb->OtherSide == NULL) && (Ccb->ReadDataAvailable == 0))
     {
         if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
-        {
-            DPRINT("File pipe broken\n");
             Status = STATUS_PIPE_BROKEN;
-        }
         else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
             Status = STATUS_PIPE_LISTENING;
         else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
@@ -443,7 +441,7 @@ NpfsRead(IN PDEVICE_OBJECT DeviceObject,
                 {
                     break;
                 }
-                if ((Ccb->PipeState != FILE_PIPE_CONNECTED_STATE) && (Ccb->ReadDataAvailable == 0))
+                if (((Ccb->PipeState != FILE_PIPE_CONNECTED_STATE) || (!Ccb->OtherSide)) && (Ccb->ReadDataAvailable == 0))
                 {
                     DPRINT("PipeState: %x\n", Ccb->PipeState);
                     Status = STATUS_PIPE_BROKEN;
@@ -787,7 +785,16 @@ NpfsWrite(PDEVICE_OBJECT DeviceObject,
     }
 
     Status = STATUS_SUCCESS;
-    Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
+    Buffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, NormalPagePriority);
+
+    if (!Buffer)
+    {
+        DPRINT("MmGetSystemAddressForMdlSafe failed\n");
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        Length = 0;
+        goto done;
+
+    }
 
     ExAcquireFastMutex(&ReaderCcb->DataListLock);
 
@@ -800,13 +807,13 @@ NpfsWrite(PDEVICE_OBJECT DeviceObject,
     {
         if ((ReaderCcb->WriteQuotaAvailable == 0))
         {
-            KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
-            if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
+            if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE || !Ccb->OtherSide)
             {
                 Status = STATUS_PIPE_BROKEN;
                 ExReleaseFastMutex(&ReaderCcb->DataListLock);
                 goto done;
             }
+            KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
             ExReleaseFastMutex(&ReaderCcb->DataListLock);
 
             DPRINT("Write Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer);
@@ -830,20 +837,15 @@ NpfsWrite(PDEVICE_OBJECT DeviceObject,
             * It's possible that the event was signaled because the
             * other side of pipe was closed.
             */
-            if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
+            if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE || !Ccb->OtherSide)
             {
                 DPRINT("PipeState: %x\n", Ccb->PipeState);
                 Status = STATUS_PIPE_BROKEN;
                 goto done;
             }
             /* Check that the pipe has not been closed */
-            if (ReaderCcb->PipeState != FILE_PIPE_CONNECTED_STATE)
+            if (ReaderCcb->PipeState != FILE_PIPE_CONNECTED_STATE || !ReaderCcb->OtherSide)
             {
-                /* If the other side is valid, fire event */
-                if (Ccb)
-                {
-                    KeResetEvent(&Ccb->WriteEvent);
-                }
                 Status = STATUS_PIPE_BROKEN;
                 goto done;
             }