[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [win-pv-devel] [PATCH 3/3] Add XenDisk device upper filter
> -----Original Message----- > From: win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx [mailto:win-pv-devel- > bounces@xxxxxxxxxxxxxxxxxxxx] On Behalf Of Owen smith > Sent: 22 September 2014 12:00 > To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx > Cc: Owen Smith > Subject: [win-pv-devel] [PATCH 3/3] Add XenDisk device upper filter > > XenDisk intercepts and translates > IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES > into SCSIOP_UNMAP SRBs. Storport will pass on these SCSIOP_UNMAP > requests > to XenVbd, which will create the appropriate BLKIF_OP_DISCARD requests. > XenDisk is only neccessary because Storport does not do the translation > to SCSIOP_UNMAP SRBs. > > Signed-off-by: Owen smith <owen.smith@xxxxxxxxxx> > --- [snip] > diff --git a/src/xendisk/pdo.c b/src/xendisk/pdo.c > new file mode 100644 > index 0000000..c815a1e > --- /dev/null > +++ b/src/xendisk/pdo.c > @@ -0,0 +1,2126 @@ > +/* Copyright (c) Citrix Systems Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, > + * with or without modification, are permitted provided > + * that the following conditions are met: > + * > + * * Redistributions of source code must retain the above > + * copyright notice, this list of conditions and the > + * following disclaimer. > + * * Redistributions in binary form must reproduce the above > + * copyright notice, this list of conditions and the > + * following disclaimer in the documentation and/or other > + * materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, > + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, > + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, > + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING > + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#define INITGUID 1 > + > +#include <ntddk.h> > +#include <wdmguid.h> > +#include <ntstrsafe.h> > +#include <stdlib.h> > +#include <storport.h> > +#include <Ntddstor.h> > +#include <Ntddscsi.h> > +#include <names.h> > + > +#include "fdo.h" > +#include "pdo.h" > +#include "driver.h" > +#include "thread.h" > +#include "debug.h" > +#include "assert.h" > +#include "util.h" > + > +#define PDO_TAG 'ODP' > + > +struct _XENDISK_PDO { > + PXENDISK_DX Dx; > + PDEVICE_OBJECT LowerDeviceObject; > + PDEVICE_OBJECT PhysicalDeviceObject; > + > + PXENDISK_THREAD SystemPowerThread; > + PIRP SystemPowerIrp; > + PXENDISK_THREAD DevicePowerThread; > + PIRP DevicePowerIrp; > + > + PXENDISK_FDO Fdo; > + BOOLEAN Missing; > + const CHAR *Reason; > + > + ULONG SectorSize; > +}; > + > +static FORCEINLINE PVOID > +__PdoAllocate( > + IN ULONG Length > + ) > +{ > + return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, > Length, PDO_TAG); > +} > + > +static FORCEINLINE VOID > +__PdoFree( > + IN PVOID Buffer > + ) > +{ > + __FreePoolWithTag(Buffer, PDO_TAG); > +} > + > +static FORCEINLINE VOID > +__PdoSetDevicePnpState( > + IN PXENDISK_PDO Pdo, > + IN DEVICE_PNP_STATE State > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + // We can never transition out of the deleted state > + ASSERT(Dx->DevicePnpState != Deleted || State == Deleted); > + > + Dx->PreviousDevicePnpState = Dx->DevicePnpState; > + Dx->DevicePnpState = State; > +} > + > +VOID > +PdoSetDevicePnpState( > + IN PXENDISK_PDO Pdo, > + IN DEVICE_PNP_STATE State > + ) > +{ > + __PdoSetDevicePnpState(Pdo, State); > +} > + > +static FORCEINLINE VOID > +__PdoRestoreDevicePnpState( > + IN PXENDISK_PDO Pdo, > + IN DEVICE_PNP_STATE State > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + if (Dx->DevicePnpState == State) > + Dx->DevicePnpState = Dx->PreviousDevicePnpState; > +} > + > +static FORCEINLINE DEVICE_PNP_STATE > +__PdoGetDevicePnpState( > + IN PXENDISK_PDO Pdo > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + return Dx->DevicePnpState; > +} > + > +DEVICE_PNP_STATE > +PdoGetDevicePnpState( > + IN PXENDISK_PDO Pdo > + ) > +{ > + return __PdoGetDevicePnpState(Pdo); > +} > + > +static FORCEINLINE VOID > +__PdoSetDevicePowerState( > + IN PXENDISK_PDO Pdo, > + IN DEVICE_POWER_STATE State > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + Dx->DevicePowerState = State; > +} > + > +static FORCEINLINE DEVICE_POWER_STATE > +__PdoGetDevicePowerState( > + IN PXENDISK_PDO Pdo > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + return Dx->DevicePowerState; > +} > + > +static FORCEINLINE VOID > +__PdoSetSystemPowerState( > + IN PXENDISK_PDO Pdo, > + IN SYSTEM_POWER_STATE State > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + Dx->SystemPowerState = State; > +} > + > +static FORCEINLINE SYSTEM_POWER_STATE > +__PdoGetSystemPowerState( > + IN PXENDISK_PDO Pdo > + ) > +{ > + PXENDISK_DX Dx = Pdo->Dx; > + > + return Dx->SystemPowerState; > +} > + > +PDEVICE_OBJECT > +PdoGetPhysicalDeviceObject( > + IN PXENDISK_PDO Pdo > + ) > +{ > + return Pdo->PhysicalDeviceObject; > +} > + > +static FORCEINLINE VOID > +__PdoSetMissing( > + IN PXENDISK_PDO Pdo, > + IN const CHAR *Reason > + ) > +{ > + Pdo->Reason = Reason; > + Pdo->Missing = TRUE; > +} > + > +VOID > +PdoSetMissing( > + IN PXENDISK_PDO Pdo, > + IN const CHAR *Reason > + ) > +{ > + __PdoSetMissing(Pdo, Reason); > +} > + > +static FORCEINLINE BOOLEAN > +__PdoIsMissing( > + IN PXENDISK_PDO Pdo > + ) > +{ > + return Pdo->Missing; > +} > + > +BOOLEAN > +PdoIsMissing( > + IN PXENDISK_PDO Pdo > + ) > +{ > + return __PdoIsMissing(Pdo); > +} > + > +static FORCEINLINE VOID > +__PdoLink( > + IN PXENDISK_PDO Pdo, > + IN PXENDISK_FDO Fdo > + ) > +{ > + Pdo->Fdo = Fdo; > + FdoAddPhysicalDeviceObject(Fdo, Pdo->Dx->DeviceObject); > +} > + > +static FORCEINLINE VOID > +__PdoUnlink( > + IN PXENDISK_PDO Pdo > + ) > +{ > + PXENDISK_FDO Fdo = Pdo->Fdo; > + > + ASSERT(Fdo != NULL); > + > + FdoRemovePhysicalDeviceObject(Fdo, Pdo->Dx->DeviceObject); > + > + Pdo->Fdo = NULL; > +} > + > +static FORCEINLINE PXENDISK_FDO > +__PdoGetFdo( > + IN PXENDISK_PDO Pdo > + ) > +{ > + return Pdo->Fdo; > +} > + > +__drv_functionClass(IO_COMPLETION_ROUTINE) > +__drv_sameIRQL > +static NTSTATUS > +__PdoForwardIrpSynchronously( > + IN PDEVICE_OBJECT DeviceObject, > + IN PIRP Irp, > + IN PVOID Context > + ) > +{ > + PKEVENT Event = Context; > + > + UNREFERENCED_PARAMETER(DeviceObject); > + UNREFERENCED_PARAMETER(Irp); > + > + KeSetEvent(Event, IO_NO_INCREMENT, FALSE); > + > + return STATUS_MORE_PROCESSING_REQUIRED; > +} > + > +static NTSTATUS > +PdoForwardIrpSynchronously( > + IN PXENDISK_PDO Pdo, > + IN PIRP Irp > + ) > +{ > + KEVENT Event; > + NTSTATUS status; > + > + ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL); > + > + KeInitializeEvent(&Event, NotificationEvent, FALSE); > + > + IoCopyCurrentIrpStackLocationToNext(Irp); > + IoSetCompletionRoutine(Irp, > + __PdoForwardIrpSynchronously, > + &Event, > + TRUE, > + TRUE, > + TRUE); > + > + status = IoCallDriver(Pdo->LowerDeviceObject, Irp); > + if (status == STATUS_PENDING) { > + (VOID) KeWaitForSingleObject(&Event, > + Executive, > + KernelMode, > + FALSE, > + NULL); > + status = Irp->IoStatus.Status; > + } else { > + ASSERT3U(status, ==, Irp->IoStatus.Status); > + } > + > + return status; > +} > + > +__drv_functionClass(IO_COMPLETION_ROUTINE) > +__drv_sameIRQL > +static NTSTATUS > +__PdoForwardIrpAndForget( > + IN PDEVICE_OBJECT DeviceObject, > + IN PIRP Irp, > + IN PVOID Context > + ) > +{ > + PXENDISK_PDO Pdo = Context; > + > + UNREFERENCED_PARAMETER(DeviceObject); > + > + if (Irp->PendingReturned) > + IoMarkIrpPending(Irp); > + > + IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp); > + > + return STATUS_SUCCESS; > +} > + > +static NTSTATUS > +PdoForwardIrpAndForget( > + IN PXENDISK_PDO Pdo, > + IN PIRP Irp > + ) > +{ > + IoCopyCurrentIrpStackLocationToNext(Irp); > + IoSetCompletionRoutine(Irp, > + __PdoForwardIrpAndForget, > + Pdo, > + TRUE, > + TRUE, > + TRUE); > + > + return IoCallDriver(Pdo->LowerDeviceObject, Irp); > +} > + > +static NTSTATUS > +PdoCompleteIrp( > + IN PXENDISK_PDO Pdo, > + IN PIRP Irp, > + IN NTSTATUS Status > + ) > +{ > + Irp->IoStatus.Status = Status; > + IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp); > + IoCompleteRequest(Irp, IO_NO_INCREMENT); > + return Status; > +} > + > +__drv_functionClass(IO_COMPLETION_ROUTINE) > +__drv_sameIRQL > +static NTSTATUS > +__PdoQueryProperty( > + IN PDEVICE_OBJECT DeviceObject, > + IN PIRP Irp, > + IN PVOID Context > + ) > +{ > + PXENDISK_PDO Pdo = Context; > + PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR Descriptor = Irp- > >UserBuffer; > + > + UNREFERENCED_PARAMETER(DeviceObject); > + > + if (Irp->PendingReturned) > + IoMarkIrpPending(Irp); > + > + if (!NT_SUCCESS(Irp->IoStatus.Status)) > + goto done; > + > + Descriptor = Irp->UserBuffer; > + Pdo->SectorSize = Descriptor->BytesPerLogicalSector; > + Verbose("%p : %u bytes per sector\n", Pdo->Dx->DeviceObject, Pdo- > >SectorSize); > + > +done: > + IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp); > + > + return STATUS_SUCCESS; > +} > + > +static DECLSPEC_NOINLINE NTSTATUS > +PdoQueryProperty( > + IN PXENDISK_PDO Pdo, > + IN PIRP Irp > + ) > +{ > + PSTORAGE_PROPERTY_QUERY Query; > + PDEVICE_TRIM_DESCRIPTOR Trim; > + NTSTATUS status; > + > + Query = Irp->AssociatedIrp.SystemBuffer; > + > + switch (Query->PropertyId) { > + case StorageAccessAlignmentProperty: > + IoCopyCurrentIrpStackLocationToNext(Irp); > + IoSetCompletionRoutine(Irp, > + __PdoQueryProperty, > + Pdo, > + TRUE, > + TRUE, > + TRUE); > + > + status = IoCallDriver(Pdo->LowerDeviceObject, Irp); > + break; > + > + case StorageDeviceTrimProperty: > + Trim = Irp->AssociatedIrp.SystemBuffer; > + > + Trim->Version = 0; > + Trim->Size = sizeof(DEVICE_TRIM_DESCRIPTOR); > + Trim->TrimEnabled = TRUE; > + > + Irp->IoStatus.Information = > (ULONG_PTR)sizeof(DEVICE_TRIM_DESCRIPTOR); > + status = PdoCompleteIrp(Pdo, Irp, STATUS_SUCCESS); > + break; > + > + default: > + status = PdoForwardIrpAndForget(Pdo, Irp); > + break; > + } > + > + return status; > +} > + > +__drv_functionClass(IO_COMPLETION_ROUTINE) > +__drv_sameIRQL > +static NTSTATUS > +__PdoSendAwaitSrb( > + IN PDEVICE_OBJECT DeviceObject, > + IN PIRP Irp, > + IN PVOID Context > + ) > +{ > + UNREFERENCED_PARAMETER(DeviceObject); > + UNREFERENCED_PARAMETER(Context); > + > + *(Irp->UserIosb) = Irp->IoStatus; > + > + if (Irp->MdlAddress) { > + MmUnlockPages(Irp->MdlAddress); > + IoFreeMdl(Irp->MdlAddress); > + } > + > + KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); > + > + IoFreeIrp(Irp); > + return STATUS_MORE_PROCESSING_REQUIRED; > +} > + > +static NTSTATUS > +PdoSendAwaitSrb( > + IN PXENDISK_PDO Pdo, > + IN PSCSI_REQUEST_BLOCK Srb > + ) > +{ > + PIRP Irp; > + IO_STATUS_BLOCK IoStatus; > + KEVENT Event; > + PIO_STACK_LOCATION Stack; > + NTSTATUS status; > + > + KeInitializeEvent(&Event, NotificationEvent, FALSE); > + > + status = STATUS_NO_MEMORY; > + Irp = IoAllocateIrp((CCHAR)(Pdo->LowerDeviceObject->StackSize + 1), > FALSE); > + if (Irp == NULL) > + goto fail1; > + > + Stack = IoGetNextIrpStackLocation(Irp); > + Stack->MajorFunction = IRP_MJ_SCSI; > + Stack->Parameters.Scsi.Srb = Srb; > + > + IoSetCompletionRoutine(Irp, > + __PdoSendAwaitSrb, > + Srb, > + TRUE, > + TRUE, > + TRUE); > + Irp->UserIosb = &IoStatus; > + Irp->UserEvent = &Event; > + > + Irp->MdlAddress = IoAllocateMdl(Srb->DataBuffer, > + Srb->DataTransferLength, > + FALSE, > + FALSE, > + Irp); > + if (Irp->MdlAddress == NULL) > + goto fail2; > + > +#pragma warning(disable:6320) > + try { > + MmProbeAndLockPages(Irp->MdlAddress, KernelMode, > IoReadAccess); > + } except (EXCEPTION_EXECUTE_HANDLER) { > + status = GetExceptionCode(); > + > + goto fail3; > + } > +#pragma warning(default:6320) > + > + Srb->OriginalRequest = Irp; > + > + status = IoCallDriver(Pdo->LowerDeviceObject, Irp); > + if (status == STATUS_PENDING) { > + (VOID) KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, > NULL); > + status = IoStatus.Status; > + } > + > + return status; > + > +fail3: > + Error("fail3\n"); > + > + IoFreeMdl(Irp->MdlAddress); > + > +fail2: > + Error("fail2\n"); > + > + IoFreeIrp(Irp); > + > +fail1: > + Error("fail1 (%08x)\n", status); > + > + return status; > +} > + > +static FORCEINLINE VOID > +__Set8Bytes( > + IN PUCHAR Bytes, > + IN ULONGLONG Value > + ) > +{ > + Bytes[0] = (UCHAR)(Value >> 56); > + Bytes[1] = (UCHAR)(Value >> 48); > + Bytes[2] = (UCHAR)(Value >> 40); > + Bytes[3] = (UCHAR)(Value >> 32); > + Bytes[4] = (UCHAR)(Value >> 24); > + Bytes[5] = (UCHAR)(Value >> 16); > + Bytes[6] = (UCHAR)(Value >> 8); > + Bytes[7] = (UCHAR)(Value); > +} > + > +static FORCEINLINE VOID > +__Set4Bytes( > + IN PUCHAR Bytes, > + IN ULONG Value > + ) > +{ > + Bytes[0] = (UCHAR)(Value >> 24); > + Bytes[1] = (UCHAR)(Value >> 16); > + Bytes[2] = (UCHAR)(Value >> 8); > + Bytes[3] = (UCHAR)(Value); > +} > + > +static FORCEINLINE VOID > +__Set2Bytes( > + IN PUCHAR Bytes, > + IN USHORT Value > + ) > +{ > + Bytes[0] = (UCHAR)(Value << 8); > + Bytes[1] = (UCHAR)(Value); > +} > + I think you should use intrinsics for the above 3 functions. > +static FORCEINLINE VOID > +__SetUnmap( > + IN PUNMAP_LIST_HEADER Unmap, > + IN ULONG Length, > + IN PDEVICE_DATA_SET_RANGE Ranges, > + IN ULONG Count, > + IN ULONG SectorSize > + ) > +{ > + ULONG Index; > + > + __Set2Bytes(Unmap->DataLength, (USHORT)Length); > + __Set2Bytes(Unmap->BlockDescrDataLength, > (USHORT)sizeof(UNMAP_BLOCK_DESCRIPTOR)); > + > + for (Index = 0; Index < Count; ++Index) { > + Trace("TRIM[%x] %x @ %llx\n", > + Index, > + (ULONG)(Ranges[Index].LengthInBytes / SectorSize), > + (ULONG64)(Ranges[Index].StartingOffset / > SectorSize)); > + > + __Set8Bytes(Unmap->Descriptors[Index].StartingLba, > + (ULONG64)(Ranges[Index].StartingOffset / > SectorSize)); > + __Set4Bytes(Unmap->Descriptors[Index].LbaCount, > + (ULONG)(Ranges[Index].LengthInBytes / SectorSize)); > + } > +} > + > +static NTSTATUS > +PdoSendTrimSynchronous( > + IN PXENDISK_PDO Pdo, > + IN PDEVICE_DATA_SET_RANGE Ranges, > + IN ULONG Count > + ) > +{ > + SCSI_REQUEST_BLOCK Srb; > + PCDB Cdb; > + PUNMAP_LIST_HEADER Unmap; > + ULONG Length; > + NTSTATUS status; > + > + Length = sizeof(UNMAP_LIST_HEADER) + Count * > sizeof(UNMAP_BLOCK_DESCRIPTOR); I know they are not necessary, but could we have brackets around the multiplication? > + > + status = STATUS_NO_MEMORY; > + Unmap = __PdoAllocate(Length); > + if (Unmap == NULL) > + goto fail1; > + > + RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK)); > + Srb.Length = sizeof(SCSI_REQUEST_BLOCK); > + Srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | > SRB_FLAGS_NO_QUEUE_FREEZE; Do we want to bypass a frozen queue here? Paul > + Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; > + Srb.DataBuffer = Unmap; > + Srb.DataTransferLength = Length; > + Srb.TimeOutValue = (ULONG)-1; > + Srb.CdbLength = 10; > + > + Cdb = (PCDB)&Srb.Cdb[0]; > + Cdb->UNMAP.OperationCode = SCSIOP_UNMAP; > + __Set2Bytes(Cdb->UNMAP.AllocationLength, (USHORT)Length); > + > + __SetUnmap(Unmap, Length, Ranges, Count, Pdo->SectorSize); > + > + status = PdoSendAwaitSrb(Pdo, &Srb); > + if (!NT_SUCCESS(status)) > + goto fail2; > + > + __PdoFree(Unmap); > + return status; > + > +fail2: > + Error("fail2\n"); > + > + __PdoFree(Unmap); > + > +fail1: > + Error("fail1 (%08x)\n", status); > + > + return status; > +} > + > +static DECLSPEC_NOINLINE NTSTATUS > +PdoManageDataSetAttributes( > + IN PXENDISK_PDO Pdo, > + IN PIRP Irp > + ) > +{ > + PDEVICE_MANAGE_DATA_SET_ATTRIBUTES Attributes; > + PDEVICE_DATA_SET_RANGE Ranges; > + ULONG NumRanges; > + NTSTATUS status; > + > + Attributes = Irp->AssociatedIrp.SystemBuffer; > + > + switch (Attributes->Action) { > + case DeviceDsmAction_Trim: > + Ranges = (PDEVICE_DATA_SET_RANGE)((PUCHAR)Attributes + > Attributes->DataSetRangesOffset); > + NumRanges = Attributes->DataSetRangesLength / > sizeof(DEVICE_DATA_SET_RANGE); > + > + status = PdoSendTrimSynchronous(Pdo, Ranges, NumRanges); > + > + status = PdoCompleteIrp(Pdo, Irp, status); > + break; > + > + default: > + status = PdoForwardIrpAndForget(Pdo, Irp); > + break; > + } > + > + return status; > +} > + [snip] > > > _______________________________________________ > win-pv-devel mailing list > win-pv-devel@xxxxxxxxxxxxxxxxxxxx > http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |