Removed the 'special' mode, because it didn't connect a pipe.
[reactos.git] / reactos / drivers / fs / np / create.c
index 019af1a..34e44a9 100644 (file)
@@ -1,21 +1,18 @@
-/* $Id: create.c,v 1.27 2004/12/30 12:34:26 ekohl Exp $
- *
+/*
  * COPYRIGHT:  See COPYING in the top level directory
  * PROJECT:    ReactOS kernel
- * FILE:       services/fs/np/create.c
+ * FILE:       drivers/fs/np/create.c
  * PURPOSE:    Named pipe filesystem
  * PROGRAMMER: David Welch <welch@cwcom.net>
  */
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-
-#include "npfs.h"
-
 #define NDEBUG
 #include <debug.h>
 
+#include "npfs.h"
+
 /* FUNCTIONS *****************************************************************/
 
 static PNPFS_PIPE
@@ -48,17 +45,29 @@ static PNPFS_FCB
 NpfsFindListeningServerInstance(PNPFS_PIPE Pipe)
 {
   PLIST_ENTRY CurrentEntry;
-  PNPFS_FCB ServerFcb;
+  PNPFS_WAITER_ENTRY Waiter;
+  KIRQL oldIrql;
+  PIRP Irp;
 
-  CurrentEntry = Pipe->ServerFcbListHead.Flink;
-  while (CurrentEntry != &Pipe->ServerFcbListHead)
+  CurrentEntry = Pipe->WaiterListHead.Flink;
+  while (CurrentEntry != &Pipe->WaiterListHead)
     {
-      ServerFcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, FcbListEntry);
-      if (ServerFcb->PipeState == FILE_PIPE_LISTENING_STATE)
+      Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
+      Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
+      if (Waiter->Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
        {
-         DPRINT("Server found! Fcb %p\n", ServerFcb);
-         return ServerFcb;
+         DPRINT("Server found! Fcb %p\n", Waiter->Fcb);
+
+         IoAcquireCancelSpinLock(&oldIrql);
+          if (!Irp->Cancel)
+           {
+             IoSetCancelRoutine(Irp, NULL);
+              IoReleaseCancelSpinLock(oldIrql);
+              return Waiter->Fcb;
+            }
+          IoReleaseCancelSpinLock(oldIrql);
        }
+
       CurrentEntry = CurrentEntry->Flink;
     }
 
@@ -66,34 +75,55 @@ NpfsFindListeningServerInstance(PNPFS_PIPE Pipe)
 }
 
 
+static VOID
+NpfsSignalAndRemoveListeningServerInstance(PNPFS_PIPE Pipe,
+                                          PNPFS_FCB Fcb)
+{
+  PLIST_ENTRY CurrentEntry;
+  PNPFS_WAITER_ENTRY Waiter;
+  PIRP Irp;
+
+  CurrentEntry = Pipe->WaiterListHead.Flink;
+  while (CurrentEntry != &Pipe->WaiterListHead)
+    {
+      Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
+      if (Waiter->Fcb == Fcb)
+       {
+         DPRINT("Server found! Fcb %p\n", Waiter->Fcb);
+
+         RemoveEntryList(&Waiter->Entry);
+         Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
+         Irp->IoStatus.Status = STATUS_SUCCESS;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+         break;
+       }
+      CurrentEntry = CurrentEntry->Flink;
+    }
+}
+
+
 NTSTATUS STDCALL
 NpfsCreate(PDEVICE_OBJECT DeviceObject,
           PIRP Irp)
 {
-  PIO_STACK_LOCATION IoStack;
+  PEXTENDED_IO_STACK_LOCATION IoStack;
   PFILE_OBJECT FileObject;
   PNPFS_PIPE Pipe;
   PNPFS_FCB ClientFcb;
   PNPFS_FCB ServerFcb = NULL;
   PNPFS_DEVICE_EXTENSION DeviceExt;
-  ULONG Disposition;
 
   DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-  IoStack = IoGetCurrentIrpStackLocation(Irp);
+  IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
   FileObject = IoStack->FileObject;
-  Disposition = ((IoStack->Parameters.Create.Options >> 24) & 0xff);
   DPRINT("FileObject %p\n", FileObject);
   DPRINT("FileName %wZ\n", &FileObject->FileName);
 
   Irp->IoStatus.Information = 0;
 
-  if (Disposition & FILE_OPEN)
-    {
-      DPRINT("NpfsCreate() open client end for special use!\n");
-    }
-
   /*
    * Step 1. Find the pipe we're trying to open.
    */
@@ -112,40 +142,14 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
 
   KeUnlockMutex(&DeviceExt->PipeListLock);
 
-  /*
-   * Step 2. Search for listening server FCB.
-   */
-
   /*
    * Acquire the lock for FCB lists. From now on no modifications to the
    * FCB lists are allowed, because it can cause various misconsistencies.
    */
   KeLockMutex(&Pipe->FcbListLock);
 
-  if (!(Disposition & FILE_OPEN))
-    {
-      ServerFcb = NpfsFindListeningServerInstance(Pipe);
-      if (ServerFcb == NULL)
-        {
-          /* Not found, bail out with error for FILE_OPEN requests. */
-          DPRINT("No listening server fcb found!\n");
-          KeUnlockMutex(&Pipe->FcbListLock);
-          Irp->IoStatus.Status = STATUS_PIPE_BUSY;
-          IoCompleteRequest(Irp, IO_NO_INCREMENT);
-          return STATUS_PIPE_BUSY;
-        }
-    }
-  else if (IsListEmpty(&Pipe->ServerFcbListHead))
-    {
-      DPRINT("No server fcb found!\n");
-      KeUnlockMutex(&Pipe->FcbListLock);
-      Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-      IoCompleteRequest(Irp, IO_NO_INCREMENT);
-      return STATUS_UNSUCCESSFUL;
-    }
-
   /*
-   * Step 3. Create the client FCB.
+   * Step 2. Create the client FCB.
    */
   ClientFcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
   if (ClientFcb == NULL)
@@ -157,15 +161,19 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
       return STATUS_NO_MEMORY;
     }
 
+  ClientFcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
   ClientFcb->Pipe = Pipe;
   ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
   ClientFcb->OtherSide = NULL;
-  ClientFcb->PipeState = (Disposition & FILE_OPEN) ? 0 : FILE_PIPE_DISCONNECTED_STATE;
+  ClientFcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+  InitializeListHead(&ClientFcb->ReadRequestListHead);
+
+  DPRINT("Fcb: %x\n", ClientFcb);
 
   /* Initialize data list. */
-  if (Pipe->InboundQuota)
+  if (Pipe->OutboundQuota)
     {
-      ClientFcb->Data = ExAllocatePool(NonPagedPool, Pipe->InboundQuota);
+      ClientFcb->Data = ExAllocatePool(PagedPool, Pipe->OutboundQuota);
       if (ClientFcb->Data == NULL)
         {
           DPRINT("No memory!\n");
@@ -184,29 +192,84 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
   ClientFcb->ReadPtr = ClientFcb->Data;
   ClientFcb->WritePtr = ClientFcb->Data;
   ClientFcb->ReadDataAvailable = 0;
-  ClientFcb->WriteQuotaAvailable = Pipe->InboundQuota;
-  ClientFcb->MaxDataLength = Pipe->InboundQuota;
-  KeInitializeSpinLock(&ClientFcb->DataListLock);
+  ClientFcb->WriteQuotaAvailable = Pipe->OutboundQuota;
+  ClientFcb->MaxDataLength = Pipe->OutboundQuota;
+  ExInitializeFastMutex(&ClientFcb->DataListLock);
   KeInitializeEvent(&ClientFcb->ConnectEvent, SynchronizationEvent, FALSE);
-  KeInitializeEvent(&ClientFcb->Event, SynchronizationEvent, FALSE);
+  KeInitializeEvent(&ClientFcb->ReadEvent, SynchronizationEvent, FALSE);
+  KeInitializeEvent(&ClientFcb->WriteEvent, SynchronizationEvent, FALSE);
+
 
   /*
-   * Step 4. Add the client FCB to a list and connect it if necessary.
+   * Step 3. Search for listening server FCB.
+   */
+
+  /*
+   * WARNING: Point of no return! Once we get the server FCB it's
+   * possible that we completed a wait request and so we have to
+   * complete even this request.
+   */
+
+  ServerFcb = NpfsFindListeningServerInstance(Pipe);
+  if (ServerFcb == NULL)
+    {
+      PLIST_ENTRY CurrentEntry;
+      PNPFS_FCB Fcb;
+
+      /*
+       * If no waiting server FCB was found then try to pick
+       * one of the listing server FCB on the pipe.
+       */
+
+      CurrentEntry = Pipe->ServerFcbListHead.Flink;
+      while (CurrentEntry != &Pipe->ServerFcbListHead)
+        {
+          Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, FcbListEntry);
+          if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
+            {
+              ServerFcb = Fcb;
+              break;
+            }
+          CurrentEntry = CurrentEntry->Flink;
+        }
+
+      /*
+       * No one is listening to me?! I'm so lonely... :(
+       */
+
+      if (ServerFcb == NULL)
+        {
+          /* Not found, bail out with error for FILE_OPEN requests. */
+          DPRINT("No listening server fcb found!\n");
+          if (ClientFcb->Data)
+            ExFreePool(ClientFcb->Data);
+          KeUnlockMutex(&Pipe->FcbListLock);
+          Irp->IoStatus.Status = STATUS_PIPE_NOT_AVAILABLE;
+          IoCompleteRequest(Irp, IO_NO_INCREMENT);
+          return STATUS_PIPE_NOT_AVAILABLE;
+        }
+    }
+  else
+    {
+      /* Signal the server thread and remove it from the waiter list */
+      /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
+      NpfsSignalAndRemoveListeningServerInstance(Pipe, ServerFcb);
+    }
+
+  /*
+   * Step 4. Add the client FCB to a list and connect it if possible.
    */
 
   /* Add the client FCB to the pipe FCB list. */
   InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
 
+  /* Connect to listening server side */
   if (ServerFcb)
     {
       ClientFcb->OtherSide = ServerFcb;
       ServerFcb->OtherSide = ClientFcb;
       ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
       ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
-
-      /* Wake server thread */
-      DPRINT("Setting the ConnectEvent for %x\n", ServerFcb);
-      KeSetEvent(&ServerFcb->ConnectEvent, 0, FALSE);
     }
 
   KeUnlockMutex(&Pipe->FcbListLock);
@@ -226,7 +289,7 @@ NTSTATUS STDCALL
 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
                    PIRP Irp)
 {
-   PIO_STACK_LOCATION IoStack;
+   PEXTENDED_IO_STACK_LOCATION IoStack;
    PFILE_OBJECT FileObject;
    PNPFS_DEVICE_EXTENSION DeviceExt;
    PNPFS_PIPE Pipe;
@@ -237,7 +300,7 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
    DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-   IoStack = IoGetCurrentIrpStackLocation(Irp);
+   IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
    FileObject = IoStack->FileObject;
    DPRINT("FileObject %p\n", FileObject);
    DPRINT("Pipe name %wZ\n", &FileObject->FileName);
@@ -254,6 +317,7 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
        return STATUS_NO_MEMORY;
      }
 
+   Fcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
    KeLockMutex(&DeviceExt->PipeListLock);
 
    /*
@@ -264,7 +328,7 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
    if (Pipe != NULL)
      {
        /*
-        * Found Pipe with the same name. Check if we are 
+        * Found Pipe with the same name. Check if we are
         * allowed to use it.
         */
        KeUnlockMutex(&DeviceExt->PipeListLock);
@@ -302,7 +366,10 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
            return STATUS_NO_MEMORY;
          }
 
-       if (RtlCreateUnicodeString(&Pipe->PipeName, FileObject->FileName.Buffer) == FALSE)
+       Pipe->PipeName.Length = FileObject->FileName.Length;
+       Pipe->PipeName.MaximumLength = Pipe->PipeName.Length + sizeof(UNICODE_NULL);
+       Pipe->PipeName.Buffer = ExAllocatePool(NonPagedPool, Pipe->PipeName.MaximumLength);
+       if (Pipe->PipeName.Buffer == NULL)
          {
            KeUnlockMutex(&DeviceExt->PipeListLock);
            ExFreePool(Pipe);
@@ -313,20 +380,23 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
            return STATUS_NO_MEMORY;
          }
 
+       RtlCopyUnicodeString(&Pipe->PipeName, &FileObject->FileName);
+
        InitializeListHead(&Pipe->ServerFcbListHead);
        InitializeListHead(&Pipe->ClientFcbListHead);
+       InitializeListHead(&Pipe->WaiterListHead);
        KeInitializeMutex(&Pipe->FcbListLock, 0);
 
-       Pipe->PipeType = Buffer->NamedPipeType ? FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE;
-       Pipe->PipeWriteMode = Buffer->NamedPipeType ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
-       Pipe->PipeReadMode = Buffer->ReadMode ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
-       Pipe->PipeBlockMode = Buffer->CompletionMode;
-       Pipe->PipeConfiguration = IoStack->Parameters.Create.Options & 0x3;
+       Pipe->PipeType = Buffer->NamedPipeType;
+       Pipe->WriteMode = Buffer->ReadMode;
+       Pipe->ReadMode = Buffer->ReadMode;
+       Pipe->CompletionMode = Buffer->CompletionMode;
+       Pipe->PipeConfiguration = IoStack->Parameters.CreatePipe.Options & 0x3;
        Pipe->MaximumInstances = Buffer->MaximumInstances;
        Pipe->CurrentInstances = 0;
        Pipe->TimeOut = Buffer->DefaultTimeout;
-       if (!(IoStack->Parameters.Create.Options & FILE_PIPE_OUTBOUND) || 
-           IoStack->Parameters.Create.Options & FILE_PIPE_FULL_DUPLEX)
+       if (!(IoStack->Parameters.CreatePipe.Options & FILE_PIPE_OUTBOUND) ||
+           IoStack->Parameters.CreatePipe.Options & FILE_PIPE_FULL_DUPLEX)
          {
            if (Buffer->InboundQuota == 0)
              {
@@ -350,7 +420,7 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
            Pipe->InboundQuota = 0;
          }
 
-       if (IoStack->Parameters.Create.Options & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
+       if (IoStack->Parameters.CreatePipe.Options & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
          {
            if (Buffer->OutboundQuota == 0)
              {
@@ -378,15 +448,18 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
        KeUnlockMutex(&DeviceExt->PipeListLock);
      }
 
-   if (Pipe->OutboundQuota)
+   if (Pipe->InboundQuota)
      {
-       Fcb->Data = ExAllocatePool(NonPagedPool, Pipe->OutboundQuota);
+       Fcb->Data = ExAllocatePool(PagedPool, Pipe->InboundQuota);
        if (Fcb->Data == NULL)
          {
            ExFreePool(Fcb);
 
            if (NewPipe)
              {
+               KeLockMutex(&DeviceExt->PipeListLock);
+              RemoveEntryList(&Pipe->PipeListEntry);
+               KeUnlockMutex(&DeviceExt->PipeListLock);
                RtlFreeUnicodeString(&Pipe->PipeName);
                ExFreePool(Pipe);
              }
@@ -404,51 +477,51 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
    Fcb->ReadPtr = Fcb->Data;
    Fcb->WritePtr = Fcb->Data;
    Fcb->ReadDataAvailable = 0;
-   Fcb->WriteQuotaAvailable = Pipe->OutboundQuota;
-   Fcb->MaxDataLength = Pipe->OutboundQuota;
-   KeInitializeSpinLock(&Fcb->DataListLock);
+   Fcb->WriteQuotaAvailable = Pipe->InboundQuota;
+   Fcb->MaxDataLength = Pipe->InboundQuota;
+   InitializeListHead(&Fcb->ReadRequestListHead);
+   ExInitializeFastMutex(&Fcb->DataListLock);
 
    Pipe->CurrentInstances++;
 
-   KeLockMutex(&Pipe->FcbListLock);
-   InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
-   KeUnlockMutex(&Pipe->FcbListLock);
-
    Fcb->Pipe = Pipe;
    Fcb->PipeEnd = FILE_PIPE_SERVER_END;
    Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
    Fcb->OtherSide = NULL;
 
-   KeInitializeEvent(&Fcb->ConnectEvent,
-                    SynchronizationEvent,
-                    FALSE);
+   DPRINT("Fcb: %x\n", Fcb);
 
-   KeInitializeEvent(&Fcb->Event,
-                    SynchronizationEvent,
-                    FALSE);
+   KeInitializeEvent(&Fcb->ConnectEvent, SynchronizationEvent, FALSE);
+   KeInitializeEvent(&Fcb->ReadEvent, SynchronizationEvent, FALSE);
+   KeInitializeEvent(&Fcb->WriteEvent, SynchronizationEvent, FALSE);
+
+   KeLockMutex(&Pipe->FcbListLock);
+   InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
+   KeUnlockMutex(&Pipe->FcbListLock);
 
    FileObject->FsContext = Fcb;
 
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
+   DPRINT("Success!\n");
+
    return STATUS_SUCCESS;
 }
 
 
 NTSTATUS STDCALL
-NpfsClose(
-   PDEVICE_OBJECT DeviceObject,
-   PIRP Irp)
+NpfsCleanup(PDEVICE_OBJECT DeviceObject,
+           PIRP Irp)
 {
    PNPFS_DEVICE_EXTENSION DeviceExt;
    PIO_STACK_LOCATION IoStack;
    PFILE_OBJECT FileObject;
-   PNPFS_FCB Fcb;
+   PNPFS_FCB Fcb, OtherSide;
    PNPFS_PIPE Pipe;
-   BOOL Server;
+   BOOLEAN Server;
 
-   DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+   DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
    IoStack = IoGetCurrentIrpStackLocation(Irp);
    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
@@ -457,6 +530,7 @@ NpfsClose(
 
    if (Fcb == NULL)
    {
+      DPRINT("Success!\n");
       Irp->IoStatus.Status = STATUS_SUCCESS;
       Irp->IoStatus.Information = 0;
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -466,7 +540,7 @@ NpfsClose(
    DPRINT("Fcb %x\n", Fcb);
    Pipe = Fcb->Pipe;
 
-   DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
+   DPRINT("Cleaning pipe %wZ\n", &Pipe->PipeName);
 
    KeLockMutex(&Pipe->FcbListLock);
 
@@ -476,65 +550,160 @@ NpfsClose(
    {
       /* FIXME: Clean up existing connections here ?? */
       DPRINT("Server\n");
-      Pipe->CurrentInstances--;
    }
    else
    {
       DPRINT("Client\n");
    }
-
    if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
    {
-      if (Fcb->OtherSide)
+      OtherSide = Fcb->OtherSide;
+      /* Lock the server first */
+      if (Server)
+      {
+         ExAcquireFastMutex(&Fcb->DataListLock);
+        ExAcquireFastMutex(&OtherSide->DataListLock);
+      }
+      else
+      {
+        ExAcquireFastMutex(&OtherSide->DataListLock);
+         ExAcquireFastMutex(&Fcb->DataListLock);
+      }
+      OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+      OtherSide->OtherSide = NULL;
+      /*
+       * Signaling the write event. If is possible that an other
+       * thread waits for an empty buffer.
+       */
+      KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
+      KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
+      if (Server)
+      {
+         ExReleaseFastMutex(&Fcb->DataListLock);
+        ExReleaseFastMutex(&OtherSide->DataListLock);
+      }
+      else
+      {
+        ExReleaseFastMutex(&OtherSide->DataListLock);
+        ExReleaseFastMutex(&Fcb->DataListLock);
+      }
+   }
+   else if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
+   {
+      PLIST_ENTRY Entry;
+      PNPFS_WAITER_ENTRY WaitEntry = NULL;
+      BOOLEAN Complete = FALSE;
+      KIRQL oldIrql;
+      PIRP tmpIrp;
+
+      Entry = Fcb->Pipe->WaiterListHead.Flink;
+      while (Entry != &Fcb->Pipe->WaiterListHead)
       {
-#ifndef FIN_WORKAROUND_READCLOSE
-         Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
-         Fcb->OtherSide->OtherSide = NULL;
-#endif
-         /*
-          * Signaling the write event. If is possible that an other
-          * thread waits for an empty buffer.
-          */
-         KeSetEvent(&Fcb->OtherSide->Event, IO_NO_INCREMENT, FALSE);
+         WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
+        if (WaitEntry->Fcb == Fcb)
+        {
+            RemoveEntryList(Entry);
+           tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
+           IoAcquireCancelSpinLock(&oldIrql);
+           if (!tmpIrp->Cancel)
+           {
+               IoSetCancelRoutine(tmpIrp, NULL);
+              Complete = TRUE;
+           }
+           IoReleaseCancelSpinLock(oldIrql);
+            if (Complete)
+           {
+              tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
+               tmpIrp->IoStatus.Information = 0;
+               IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
+           }
+           break;
+        }
+        Entry = Entry->Flink;
       }
 
-#ifndef FIN_WORKAROUND_READCLOSE
-      Fcb->PipeState = 0;
-#endif
    }
+   Fcb->PipeState = FILE_PIPE_CLOSING_STATE;
 
-   FileObject->FsContext = NULL;
+   KeUnlockMutex(&Pipe->FcbListLock);
 
-#ifndef FIN_WORKAROUND_READCLOSE
-   RemoveEntryList(&Fcb->FcbListEntry);
+   ExAcquireFastMutex(&Fcb->DataListLock);
    if (Fcb->Data)
+   {
       ExFreePool(Fcb->Data);
-   ExFreePool(Fcb);
-#else
-   Fcb->PipeState = FILE_PIPE_CLOSING_STATE;
-   if (Fcb->OtherSide == NULL ||
-       Fcb->OtherSide->PipeState == FILE_PIPE_CLOSING_STATE)
+      Fcb->Data = NULL;
+      Fcb->ReadPtr = NULL;
+      Fcb->WritePtr = NULL;
+   }
+   ExReleaseFastMutex(&Fcb->DataListLock);
+
+   Irp->IoStatus.Status = STATUS_SUCCESS;
+   Irp->IoStatus.Information = 0;
+   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+   DPRINT("Success!\n");
+
+   return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+NpfsClose(PDEVICE_OBJECT DeviceObject,
+          PIRP Irp)
+{
+   PNPFS_DEVICE_EXTENSION DeviceExt;
+   PIO_STACK_LOCATION IoStack;
+   PFILE_OBJECT FileObject;
+   PNPFS_FCB Fcb;
+   PNPFS_PIPE Pipe;
+   BOOLEAN Server;
+
+   DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+
+   IoStack = IoGetCurrentIrpStackLocation(Irp);
+   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+   FileObject = IoStack->FileObject;
+   Fcb = FileObject->FsContext;
+
+   if (Fcb == NULL)
    {
-      if (Server && Fcb->OtherSide != NULL &&
-          Fcb->OtherSide->PipeState == FILE_PIPE_CLOSING_STATE)
-      {
-         RemoveEntryList(&Fcb->OtherSide->FcbListEntry);
-         if (Fcb->OtherSide->Data)
-            ExFreePool(Fcb->OtherSide->Data);
-        ExFreePool(Fcb->OtherSide);
-      }
+      DPRINT("Success!\n");
+      Irp->IoStatus.Status = STATUS_SUCCESS;
+      Irp->IoStatus.Information = 0;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_SUCCESS;
+   }
 
-      RemoveEntryList(&Fcb->FcbListEntry);
-      if (Fcb->Data)
-         ExFreePool(Fcb->Data);
+   DPRINT("Fcb %x\n", Fcb);
+   Pipe = Fcb->Pipe;
 
-      ExFreePool(Fcb);
+   DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
+
+   KeLockMutex(&Pipe->FcbListLock);
+
+   Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
+
+   if (Server)
+   {
+      DPRINT("Server\n");
+      Pipe->CurrentInstances--;
    }
-#endif
+   else
+   {
+      DPRINT("Client\n");
+   }
+
+   ASSERT (Fcb->PipeState == FILE_PIPE_CLOSING_STATE);
+
+   FileObject->FsContext = NULL;
+
+   RemoveEntryList(&Fcb->FcbListEntry);
+
+   ExFreePool(Fcb);
 
    KeUnlockMutex(&Pipe->FcbListLock);
 
-   if (Server && Pipe->CurrentInstances == 0)
+   if (IsListEmpty(&Pipe->ServerFcbListHead) &&
+       IsListEmpty(&Pipe->ClientFcbListHead))
    {
       RtlFreeUnicodeString(&Pipe->PipeName);
       KeLockMutex(&DeviceExt->PipeListLock);
@@ -547,6 +716,8 @@ NpfsClose(
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
+   DPRINT("Success!\n");
+
    return STATUS_SUCCESS;
 }