[NTOSKRNL]
authorPierre Schweitzer <pierre@reactos.org>
Fri, 31 Oct 2014 11:17:43 +0000 (11:17 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Fri, 31 Oct 2014 11:17:43 +0000 (11:17 +0000)
Some fixes and missing implementations in RawFS:
- Remove some magic values for VCB state
- Add a local VPB in our VCB. This will allow diverting the IO VPB with ours in case of dismount (and thus, will fix dismount)
- Implement support for said VPB in both RawCheckForDismount() and RawInitializeVcb()
- Now, dismount is handled in RawCheckForDismount() directly, and not in functions calling it
- Handle streams in RawClose
- Handle VCB being dismounted in RawCreate()
- Handle dismount also in RawCleanup() (not only in RawClose())

This fixes volume locking and dismounting in RawFS. And thus, allows FS swap in case of raw volume formating in first stage :-).
More to follow!

svn path=/trunk/; revision=65141

reactos/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);