From 0440330ea68f6de151bce4b553f7e6b26deb6451 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Mon, 10 Nov 2014 22:11:36 +0000 Subject: [PATCH] [FASTFAT] - Implement VPB swapout in our FAT driver for dismout (see VfatCheckForDismount) - Dereference volume handles on close (not on cleanup) - Keep track of the VDO in our VCB - Let VfatCheckForDismount() do the actual dismount, instead of VfatDismountVolume() which just initiates it CORE-8732 #comment Can you retry? svn path=/trunk/; revision=65372 --- reactos/drivers/filesystems/fastfat/cleanup.c | 6 +- reactos/drivers/filesystems/fastfat/close.c | 6 ++ reactos/drivers/filesystems/fastfat/fsctl.c | 2 +- reactos/drivers/filesystems/fastfat/misc.c | 87 +++++++++++++++++++ reactos/drivers/filesystems/fastfat/vfat.h | 8 +- 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/reactos/drivers/filesystems/fastfat/cleanup.c b/reactos/drivers/filesystems/fastfat/cleanup.c index f9bde77d206..6d64ee15c6c 100644 --- a/reactos/drivers/filesystems/fastfat/cleanup.c +++ b/reactos/drivers/filesystems/fastfat/cleanup.c @@ -38,7 +38,6 @@ VfatCleanupFile( if (pFcb->Flags & FCB_IS_VOLUME) { pFcb->OpenHandleCount--; - DeviceExt->OpenHandleCount--; if (pFcb->OpenHandleCount != 0) { @@ -111,6 +110,11 @@ VfatCleanupFile( ExReleaseResourceLite(&pFcb->MainResource); } + if (DeviceExt->Flags & VCB_DISMOUNT_PENDING) + { + VfatCheckForDismount(DeviceExt, FALSE); + } + return STATUS_SUCCESS; } diff --git a/reactos/drivers/filesystems/fastfat/close.c b/reactos/drivers/filesystems/fastfat/close.c index b91b85b644b..54a1280f180 100644 --- a/reactos/drivers/filesystems/fastfat/close.c +++ b/reactos/drivers/filesystems/fastfat/close.c @@ -75,12 +75,18 @@ VfatCloseFile( FileObject->FsContext2 = NULL; FileObject->FsContext = NULL; FileObject->SectionObjectPointer = NULL; + DeviceExt->OpenHandleCount--; if (pCcb) { vfatDestroyCCB(pCcb); } + if (DeviceExt->OpenHandleCount == 0) + { + VfatCheckForDismount(DeviceExt, FALSE); + } + return Status; } diff --git a/reactos/drivers/filesystems/fastfat/fsctl.c b/reactos/drivers/filesystems/fastfat/fsctl.c index 43e582a0bfd..6798ea81cd3 100644 --- a/reactos/drivers/filesystems/fastfat/fsctl.c +++ b/reactos/drivers/filesystems/fastfat/fsctl.c @@ -447,6 +447,7 @@ VfatMount( RtlZeroMemory(DeviceExt, ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize); DeviceExt->FcbHashTable = (HASHENTRY**)((ULONG_PTR)DeviceExt + ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG))); DeviceExt->HashTableSize = HashTableSize; + DeviceExt->VolumeDevice = DeviceObject; /* use same vpb as device disk */ DeviceObject->Vpb = Vpb; @@ -962,7 +963,6 @@ VfatDismountVolume( /* Mark we're being dismounted */ DeviceExt->Flags |= VCB_DISMOUNT_PENDING; - IrpContext->DeviceObject->Vpb->Flags &= ~VPB_MOUNTED; ExReleaseResourceLite(&DeviceExt->FatResource); diff --git a/reactos/drivers/filesystems/fastfat/misc.c b/reactos/drivers/filesystems/fastfat/misc.c index ddd547ff8fe..751514d34f5 100644 --- a/reactos/drivers/filesystems/fastfat/misc.c +++ b/reactos/drivers/filesystems/fastfat/misc.c @@ -312,3 +312,90 @@ VfatLockUserBuffer( return STATUS_SUCCESS; } + +BOOLEAN +VfatCheckForDismount( + IN PDEVICE_EXTENSION DeviceExt, + IN BOOLEAN Create) +{ + KIRQL OldIrql; + PVPB Vpb; + BOOLEAN Delete; + + DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt, Create); + + /* Lock VPB */ + IoAcquireVpbSpinLock(&OldIrql); + + /* Reference it and check if a create is being done */ + Vpb = DeviceExt->IoVPB; + if (Vpb->ReferenceCount != Create) + { + /* Copy the VPB to our local own to prepare later dismount */ + if (DeviceExt->SpareVPB != NULL) + { + RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB)); + DeviceExt->SpareVPB->Type = IO_TYPE_VPB; + DeviceExt->SpareVPB->Size = sizeof(VPB); + DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice; + DeviceExt->SpareVPB->DeviceObject = NULL; + DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING; + DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB; + DeviceExt->SpareVPB = NULL; + DeviceExt->IoVPB->Flags |= VPB_PERSISTENT; + } + + /* Don't do anything */ + Delete = FALSE; + } + else + { + /* Otherwise, delete the volume */ + Delete = TRUE; + + /* Check if it has a VPB and unmount it */ + if (Vpb->RealDevice->Vpb == Vpb) + { + Vpb->DeviceObject = NULL; + Vpb->Flags &= ~VPB_MOUNTED; + } + } + + /* Release lock and return status */ + IoReleaseVpbSpinLock(OldIrql); + + /* If we were to delete, delete volume */ + if (Delete) + { + PVPB DelVpb; + + /* If we have a local VPB, we'll have to delete it + * but we won't dismount us - something went bad before + */ + if (DeviceExt->SpareVPB) + { + DelVpb = DeviceExt->SpareVPB; + } + /* Otherwise, dismount our device if possible */ + else + { + if (DeviceExt->IoVPB->ReferenceCount) + { + ObfDereferenceObject(DeviceExt->StorageDevice); + IoDeleteDevice(DeviceExt->VolumeDevice); + return Delete; + } + + DelVpb = DeviceExt->IoVPB; + } + + /* Delete any of the available VPB and dismount */ + ExFreePool(DelVpb); + ObfDereferenceObject(DeviceExt->StorageDevice); + IoDeleteDevice(DeviceExt->VolumeDevice); + + return Delete; + } + + return Delete; +} diff --git a/reactos/drivers/filesystems/fastfat/vfat.h b/reactos/drivers/filesystems/fastfat/vfat.h index b02d4b480f1..15a91f2b338 100644 --- a/reactos/drivers/filesystems/fastfat/vfat.h +++ b/reactos/drivers/filesystems/fastfat/vfat.h @@ -271,6 +271,7 @@ typedef struct DEVICE_EXTENSION ULONG HashTableSize; struct _HASHENTRY **FcbHashTable; + PDEVICE_OBJECT VolumeDevice; PDEVICE_OBJECT StorageDevice; PFILE_OBJECT FATFileObject; FATINFO FatInfo; @@ -297,7 +298,7 @@ typedef struct DEVICE_EXTENSION LIST_ENTRY NotifyList; PNOTIFY_SYNC NotifySync; - /* Incremented on IRP_MJ_CREATE, decremented on IRP_MJ_CLEANUP */ + /* Incremented on IRP_MJ_CREATE, decremented on IRP_MJ_CLOSE */ ULONG OpenHandleCount; /* VPBs for dismount */ @@ -928,6 +929,11 @@ VfatLockUserBuffer( IN ULONG, IN LOCK_OPERATION); +BOOLEAN +VfatCheckForDismount( + IN PDEVICE_EXTENSION DeviceExt, + IN BOOLEAN Create); + /* pnp.c */ NTSTATUS -- 2.17.1