* Sync up to trunk head (r65147).
[reactos.git] / ntoskrnl / io / iomgr / rawfs.c
index 143f486..99f4c73 100644 (file)
@@ -20,6 +20,7 @@ typedef struct _VCB
     USHORT NodeByteSize;
     PDEVICE_OBJECT TargetDeviceObject;
     PVPB Vpb;
+    PVPB LocalVpb;
     ULONG VcbState;
     KMUTEX Mutex;
     CLONG OpenCount;
@@ -34,20 +35,27 @@ typedef struct _VOLUME_DEVICE_OBJECT
     VCB Vcb;
 } VOLUME_DEVICE_OBJECT, *PVOLUME_DEVICE_OBJECT;
 
+#define VCB_STATE_LOCKED     0x00000001
+#define VCB_STATE_DISMOUNTED 0x00000002
+
 /* GLOBALS *******************************************************************/
 
 PDEVICE_OBJECT RawDiskDeviceObject, RawCdromDeviceObject, RawTapeDeviceObject;
 
 /* FUNCTIONS *****************************************************************/
 
-VOID
+NTSTATUS
 NTAPI
 RawInitializeVcb(IN OUT PVCB Vcb,
                  IN PDEVICE_OBJECT TargetDeviceObject,
                  IN PVPB Vpb)
 {
+    NTSTATUS Status = STATUS_SUCCESS;
+
     PAGED_CODE();
 
+    DPRINT("RawInitializeVcb(%p, %p, %p)\n", Vcb, TargetDeviceObject, Vpb);
+
     /* Clear it */
     RtlZeroMemory(Vcb, sizeof(VCB));
 
@@ -57,6 +65,14 @@ RawInitializeVcb(IN OUT PVCB Vcb,
 
     /* Initialize the lock */
     KeInitializeMutex(&Vcb->Mutex, 0);
+
+    Vcb->LocalVpb = ExAllocatePoolWithTag(NonPagedPool, sizeof(VPB), ' waR');
+    if (Vcb->LocalVpb == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    return Status;
 }
 
 BOOLEAN
@@ -68,6 +84,10 @@ RawCheckForDismount(IN PVCB Vcb,
     PVPB Vpb;
     BOOLEAN Delete;
 
+    DPRINT("RawCheckForDismount(%p, %lu)\n", Vcb, CreateOperation);
+
+    ASSERT(KeReadStateMutant(&Vcb->Mutex) == 0);
+
     /* Lock VPB */
     IoAcquireVpbSpinLock(&OldIrql);
 
@@ -75,6 +95,19 @@ RawCheckForDismount(IN PVCB Vcb,
     Vpb = Vcb->Vpb;
     if (Vcb->Vpb->ReferenceCount != CreateOperation)
     {
+        /* Copy the VPB to our local own to prepare later dismount */
+        if (Vcb->LocalVpb != NULL)
+        {
+            RtlZeroMemory(Vcb->LocalVpb, sizeof(VPB));
+            Vcb->LocalVpb->Type = IO_TYPE_VPB;
+            Vcb->LocalVpb->Size = sizeof(VPB);
+            Vcb->LocalVpb->RealDevice = Vcb->Vpb->RealDevice;
+            Vcb->LocalVpb->DeviceObject = NULL;
+            Vcb->LocalVpb->Flags = Vcb->Vpb->Flags & VPB_REMOVE_PENDING;
+            Vcb->Vpb->RealDevice->Vpb = Vcb->LocalVpb;
+            Vcb->LocalVpb = NULL;
+            Vcb->Vpb->Flags |= VPB_PERSISTENT;
+        }
         /* Don't do anything */
         Delete = FALSE;
     }
@@ -93,6 +126,47 @@ RawCheckForDismount(IN PVCB Vcb,
 
     /* Release lock and return status */
     IoReleaseVpbSpinLock(OldIrql);
+
+    /* If we were to delete, delete volume */
+    if (Delete)
+    {
+        PVPB DelVpb;
+
+        /* Release our Vcb lock to be able delete us */
+        KeReleaseMutex(&Vcb->Mutex, 0);
+
+        /* If we have a local VPB, we'll have to delete it
+         * but we won't dismount us - something went bad before
+         */
+        if (Vcb->LocalVpb)
+        {
+            DelVpb = Vcb->LocalVpb;
+        }
+        /* Otherwise, dismount our device if possible */
+        else
+        {
+            if (Vcb->Vpb->ReferenceCount)
+            {
+                ObfDereferenceObject(Vcb->TargetDeviceObject);
+                IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
+                                                                 VOLUME_DEVICE_OBJECT,
+                                                                 Vcb));
+                return Delete;
+            }
+
+            DelVpb = Vcb->Vpb;
+        }
+
+        /* Delete any of the available VPB and dismount */
+        ExFreePool(DelVpb);
+        ObfDereferenceObject(Vcb->TargetDeviceObject);
+        IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
+                                                         VOLUME_DEVICE_OBJECT,
+                                                         Vcb));
+
+        return Delete;
+    }
+
     return Delete;
 }
 
@@ -104,6 +178,8 @@ RawCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
 {
     PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
 
+    DPRINT("RawCompletionRoutine(%p, %p, %p)\n", DeviceObject, Irp, Context);
+
     /* Check if this was a valid sync R/W request */
     if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
          (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
@@ -128,9 +204,18 @@ RawClose(IN PVCB Vcb,
          IN PIO_STACK_LOCATION IoStackLocation)
 {
     NTSTATUS Status;
-    BOOLEAN Deleted = FALSE;
     PAGED_CODE();
 
+    DPRINT("RawClose(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
+    /* If its a stream, not much to do */
+    if (IoStackLocation->FileObject->Flags & FO_STREAM_FILE)
+    {
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
     /* Make sure we can clean up */
     Status = KeWaitForSingleObject(&Vcb->Mutex,
                                    Executive,
@@ -141,16 +226,9 @@ RawClose(IN PVCB Vcb,
 
     /* Decrease the open count and check if this is a dismount */
     Vcb->OpenCount--;
-    if (!Vcb->OpenCount) Deleted = RawCheckForDismount(Vcb, FALSE);
-
-    /* Check if we should delete the device */
-    KeReleaseMutex(&Vcb->Mutex, FALSE);
-    if (Deleted)
+    if (!Vcb->OpenCount || !RawCheckForDismount(Vcb, FALSE))
     {
-        /* Delete it */
-        IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
-                                                         VOLUME_DEVICE_OBJECT,
-                                                         Vcb));
+        KeReleaseMutex(&Vcb->Mutex, FALSE);
     }
 
     /* Complete the request */
@@ -166,11 +244,13 @@ RawCreate(IN PVCB Vcb,
           IN PIO_STACK_LOCATION IoStackLocation)
 {
     NTSTATUS Status;
-    BOOLEAN Deleted = FALSE;
     USHORT ShareAccess;
     ACCESS_MASK DesiredAccess;
+    BOOLEAN Deleted = FALSE;
     PAGED_CODE();
 
+    DPRINT("RawCreate(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Make sure we can clean up */
     Status = KeWaitForSingleObject(&Vcb->Mutex,
                                    Executive,
@@ -186,12 +266,18 @@ RawCreate(IN PVCB Vcb,
          (!(IoStackLocation->Parameters.Create.Options & FILE_DIRECTORY_FILE)))
     {
         /* Make sure the VCB isn't locked */
-        if (Vcb->VcbState & 1)
+        if (Vcb->VcbState & VCB_STATE_LOCKED)
         {
             /* Refuse the operation */
             Status = STATUS_ACCESS_DENIED;
             Irp->IoStatus.Information = 0;
         }
+        else if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
+        {
+            /* Refuse the operation */
+            Status = STATUS_VOLUME_DISMOUNTED;
+            Irp->IoStatus.Information = 0;
+        }
         else
         {
             /* Setup share access */
@@ -247,23 +333,19 @@ RawCreate(IN PVCB Vcb,
     if (!(NT_SUCCESS(Status)) && !(Vcb->OpenCount))
     {
         /* Check if we can dismount the device */
-        Deleted = RawCheckForDismount(Vcb, FALSE);
+        Deleted = RawCheckForDismount(Vcb, TRUE);   
     }
 
-    /* Check if we should delete the device */
-    KeReleaseMutex(&Vcb->Mutex, FALSE);
-    if (Deleted)
+    /* In case of deletion, the mutex is already released */
+    if (!Deleted)
     {
-        /* Delete it */
-        IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
-                                                         VOLUME_DEVICE_OBJECT,
-                                                         Vcb));
+        KeReleaseMutex(&Vcb->Mutex, FALSE);
     }
 
     /* Complete the request */
-    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Status = Status;
     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 NTSTATUS
@@ -275,6 +357,8 @@ RawReadWriteDeviceControl(IN PVCB Vcb,
     NTSTATUS Status;
     PAGED_CODE();
 
+    DPRINT("RawReadWriteDeviceControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Don't do anything if the request was 0 bytes */
     if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
          (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
@@ -315,6 +399,8 @@ RawMountVolume(IN PIO_STACK_LOCATION IoStackLocation)
     PFILE_OBJECT FileObject = NULL;
     PAGED_CODE();
 
+    DPRINT("RawMountVolume(%p)\n", IoStackLocation);
+
     /* Remember our owner */
     DeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject;
 
@@ -336,9 +422,14 @@ RawMountVolume(IN PIO_STACK_LOCATION IoStackLocation)
                                                     AlignmentRequirement);
 
     /* Setup the VCB */
-    RawInitializeVcb(&Volume->Vcb,
-                     IoStackLocation->Parameters.MountVolume.DeviceObject,
-                     IoStackLocation->Parameters.MountVolume.Vpb);
+    Status = RawInitializeVcb(&Volume->Vcb,
+                              IoStackLocation->Parameters.MountVolume.DeviceObject,
+                              IoStackLocation->Parameters.MountVolume.Vpb);
+    if (!NT_SUCCESS(Status))
+    {
+        IoDeleteDevice((PDEVICE_OBJECT)Volume);
+        return Status;
+    }
 
     /* Set dummy label and serial number */
     Volume->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
@@ -391,6 +482,8 @@ RawUserFsCtrl(IN PIO_STACK_LOCATION IoStackLocation,
     NTSTATUS Status;
     PAGED_CODE();
 
+    DPRINT("RawUserFsCtrl(%p, %p)\n", IoStackLocation, Vcb);
+
     /* Lock the device */
     Status = KeWaitForSingleObject(&Vcb->Mutex,
                                    Executive,
@@ -502,6 +595,8 @@ RawFileSystemControl(IN PVCB Vcb,
     NTSTATUS Status;
     PAGED_CODE();
 
+    DPRINT("RawFileSystemControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Check the kinds of FSCTLs that we support */
     switch (IoStackLocation->MinorFunction)
     {
@@ -563,6 +658,8 @@ RawQueryInformation(IN PVCB Vcb,
     PFILE_POSITION_INFORMATION Buffer;
     PAGED_CODE();
 
+    DPRINT("RawQueryInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Get information from the IRP */
     Length = &IoStackLocation->Parameters.QueryFile.Length;
     Buffer = Irp->AssociatedIrp.SystemBuffer;
@@ -608,6 +705,8 @@ RawSetInformation(IN PVCB Vcb,
     PDEVICE_OBJECT DeviceObject;
     PAGED_CODE();
 
+    DPRINT("RawSetInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Get information from the IRP */
     Buffer = Irp->AssociatedIrp.SystemBuffer;
 
@@ -650,6 +749,8 @@ RawQueryFsVolumeInfo(IN PVCB Vcb,
 {
     PAGED_CODE();
 
+    DPRINT("RawQueryFsVolumeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
     /* Clear the buffer and stub it out */
     RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION));
     Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
@@ -677,6 +778,8 @@ RawQueryFsSizeInfo(IN PVCB Vcb,
     BOOLEAN DiskHasPartitions;
     PAGED_CODE();
 
+    DPRINT("RawQueryFsSizeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
     /* Validate the buffer */
     if (*Length < sizeof(FILE_FS_SIZE_INFORMATION))
     {
@@ -806,6 +909,8 @@ RawQueryFsDeviceInfo(IN PVCB Vcb,
 {
     PAGED_CODE();
 
+    DPRINT("RawQueryFsDeviceInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
     /* Validate buffer */
     if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION))
     {
@@ -833,6 +938,8 @@ RawQueryFsAttributeInfo(IN PVCB Vcb,
     ULONG ReturnLength;
     PAGED_CODE();
 
+    DPRINT("RawQueryFsAttributeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
     /* Check if the buffer is large enough for our name ("RAW") */
     ReturnLength = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,
                                 FileSystemName[sizeof(szRawFSName) / sizeof(szRawFSName[0])]);
@@ -860,6 +967,8 @@ RawQueryVolumeInformation(IN PVCB Vcb,
     PVOID Buffer;
     PAGED_CODE();
 
+    DPRINT("RawQueryVolumeInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Get IRP Data */
     Length = IoStackLocation->Parameters.QueryVolume.Length;
     Buffer = Irp->AssociatedIrp.SystemBuffer;
@@ -916,6 +1025,8 @@ RawCleanup(IN PVCB Vcb,
     NTSTATUS Status;
     PAGED_CODE();
 
+    DPRINT("RawCleanup(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
     /* Make sure we can clean up */
     Status = KeWaitForSingleObject(&Vcb->Mutex,
                                    Executive,
@@ -924,8 +1035,16 @@ RawCleanup(IN PVCB Vcb,
                                    NULL);
     ASSERT(NT_SUCCESS(Status));
 
-    /* Remove shared access and complete the request */
+    /* Remove shared access */
     IoRemoveShareAccess(IoStackLocation->FileObject, &Vcb->ShareAccess);
+
+    /* Check if we're to dismount */
+    if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
+    {
+        ASSERT(Vcb->OpenCount == 1);
+        RawCheckForDismount(Vcb, FALSE);
+    }
+
     KeReleaseMutex(&Vcb->Mutex, FALSE);
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
@@ -942,6 +1061,8 @@ RawDispatch(IN PVOLUME_DEVICE_OBJECT DeviceObject,
     PVCB Vcb;
     PAGED_CODE();
 
+    DPRINT("RawDispatch(%p, %p)\n", DeviceObject, Irp);
+
     /* Get the stack location */
     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);