From bde195d8d5a547bb142d13af1fdbc22822221ffa Mon Sep 17 00:00:00 2001 From: Jorgen Lundman Date: Mon, 22 Jul 2024 09:50:07 +0900 Subject: [PATCH] mount code, sort of clean Signed-off-by: Jorgen Lundman --- .../windows/OpenZFS/OpenZFS/OpenZFS.vcxproj | 3 +- include/os/windows/spl/sys/mount.h | 16 +- include/os/windows/zfs/sys/zfs_context_os.h | 1 + include/os/windows/zfs/sys/zfs_windows.h | 9 + module/os/windows/OpenZFS.inf | 13 +- module/os/windows/driver.c | 118 +- module/os/windows/zfs/sysctl_os.c | 10 +- module/os/windows/zfs/zfs_ioctl_os.c | 275 +++-- module/os/windows/zfs/zfs_vnops_windows.c | 549 +++++++-- module/os/windows/zfs/zfs_vnops_windows_lib.c | 363 ++++-- .../os/windows/zfs/zfs_vnops_windows_mount.c | 1098 ++++++++++++++--- module/os/windows/zfs/zfs_windows_zvol_scsi.c | 6 +- module/zfs/dmu_recv.c | 5 + module/zfs/dnode.c | 10 +- 14 files changed, 2020 insertions(+), 456 deletions(-) diff --git a/contrib/windows/OpenZFS/OpenZFS/OpenZFS.vcxproj b/contrib/windows/OpenZFS/OpenZFS/OpenZFS.vcxproj index 1aa1c7ab3bd6..b1f865421dde 100644 --- a/contrib/windows/OpenZFS/OpenZFS/OpenZFS.vcxproj +++ b/contrib/windows/OpenZFS/OpenZFS/OpenZFS.vcxproj @@ -130,8 +130,7 @@ DbgengKernelDebugger true false - - + http://timestamp.digicert.com $(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH);../../../../include diff --git a/include/os/windows/spl/sys/mount.h b/include/os/windows/spl/sys/mount.h index 99f418749a6e..269868671d6b 100644 --- a/include/os/windows/spl/sys/mount.h +++ b/include/os/windows/spl/sys/mount.h @@ -81,7 +81,8 @@ struct vfsstatfs { }; typedef enum _FSD_IDENTIFIER_TYPE { - MOUNT_TYPE_DGL = ':DGL', // Dokan Global + MOUNT_TYPE_DGL = ':DGL', // Global + MOUNT_TYPE_BUS = ':BUS', // Bus Control MOUNT_TYPE_DCB = ':DCB', // Disk Control Block MOUNT_TYPE_VCB = ':VCB', // Volume Control Block MOUNT_TYPE_FCB = ':FCB', // File Control Block @@ -96,15 +97,24 @@ struct mount ULONG size; void *fsprivate; void *parent_device; // Only set so vcd can find dcb - PDEVICE_OBJECT deviceObject; - PDEVICE_OBJECT diskDeviceObject; + uuid_t rawuuid; + PDEVICE_OBJECT PhysicalDeviceObject; // From AddDevices + PDEVICE_OBJECT LowerDeviceObject; // Attaching PDO in AddDevices + PDEVICE_OBJECT FunctionalDeviceObject; // Created in AddDevices + PDEVICE_OBJECT VolumeDeviceObject; + PDEVICE_OBJECT AttachedDevice; UNICODE_STRING bus_name; UNICODE_STRING device_name; UNICODE_STRING symlink_name; + UNICODE_STRING arc_name; UNICODE_STRING fs_name; UNICODE_STRING name; UNICODE_STRING uuid; UNICODE_STRING mountpoint; + UNICODE_STRING deviceInterfaceName; + UNICODE_STRING fsInterfaceName; + UNICODE_STRING volumeInterfaceName; + PFILE_OBJECT root_file; boolean_t justDriveLetter; uint64_t volume_opens; PVPB vpb; diff --git a/include/os/windows/zfs/sys/zfs_context_os.h b/include/os/windows/zfs/sys/zfs_context_os.h index 0a26bc0dda5c..9911e637814f 100644 --- a/include/os/windows/zfs/sys/zfs_context_os.h +++ b/include/os/windows/zfs/sys/zfs_context_os.h @@ -68,6 +68,7 @@ typedef struct spa_iokit spa_iokit_t; extern boolean_t ml_set_interrupts_enabled(boolean_t); extern PDRIVER_OBJECT WIN_DriverObject; + /* * Ok this is pretty gross - until we can get rid of it from lua - * it works as long as it doesn't parse strings diff --git a/include/os/windows/zfs/sys/zfs_windows.h b/include/os/windows/zfs/sys/zfs_windows.h index 3800ee69a572..a958d9e04e64 100644 --- a/include/os/windows/zfs/sys/zfs_windows.h +++ b/include/os/windows/zfs/sys/zfs_windows.h @@ -71,6 +71,8 @@ typedef struct zfs_ccb zfs_ccb_t; extern uint64_t zfs_module_busy; +#define DIR_LINKS(zp) (S_ISDIR((zp)->z_mode) ? (zp)->z_links - 1 : (zp)->z_links) + extern CACHE_MANAGER_CALLBACKS CacheManagerCallbacks; @@ -143,6 +145,8 @@ extern size_t get_reparse_point_impl(znode_t *zp, char *buffer, size_t outlen); extern void fastio_init(FAST_IO_DISPATCH **fast); extern NTSTATUS pnp_query_di(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +extern NTSTATUS pnp_query_bus_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, + PIO_STACK_LOCATION IrpSp); extern NTSTATUS pnp_device_usage_notification(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); @@ -167,6 +171,8 @@ extern void acl_trivial_access_masks(mode_t mode, boolean_t isdir, extern void zfs_save_ntsecurity(struct vnode *vp); void zfs_load_ntsecurity(struct vnode *vp); struct vnode *zfs_parent(struct vnode *); +extern PVOID MapUserBuffer(IN OUT PIRP Irp); + /* IRP_MJ_SET_INFORMATION helpers */ extern NTSTATUS set_file_basic_information(PDEVICE_OBJECT, PIRP, @@ -234,6 +240,7 @@ extern NTSTATUS file_hard_link_information(PDEVICE_OBJECT, PIRP, /* IRP_MJ_DEVICE_CONTROL helpers */ extern NTSTATUS QueryCapabilities(PDEVICE_OBJECT, PIRP, PIO_STACK_LOCATION); +extern NTSTATUS QueryDeviceRelations(PDEVICE_OBJECT, PIRP, PIO_STACK_LOCATION); extern NTSTATUS ioctl_query_device_name(PDEVICE_OBJECT, PIRP, PIO_STACK_LOCATION); extern NTSTATUS ioctl_disk_get_drive_geometry(PDEVICE_OBJECT, PIRP, @@ -266,6 +273,8 @@ extern NTSTATUS fsctl_set_zero_data(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); extern NTSTATUS ioctl_get_gpt_attributes(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +extern NTSTATUS volume_read(PDEVICE_OBJECT DeviceObject, PIRP Irp, + PIO_STACK_LOCATION IrpSp); #endif diff --git a/module/os/windows/OpenZFS.inf b/module/os/windows/OpenZFS.inf index 531499fcdc46..9fbb366cfff1 100644 --- a/module/os/windows/OpenZFS.inf +++ b/module/os/windows/OpenZFS.inf @@ -37,15 +37,22 @@ OpenZFS.DllFiles = 11 ;%windir%\system32 [Standard.NTamd64] %VolumeName% = OpenZFS_Install, OpenZFSVolume +;%DriverName% = OpenZFS_Install, ROOT\OpenZFS %ControllerName% = OpenZFS_Install, ROOT\OpenZFS [Standard.NTx86] %VolumeName% = OpenZFS_Install, OpenZFSVolume +;%DriverName% = OpenZFS_Install, ROOT\OpenZFS %ControllerName% = OpenZFS_Install, ROOT\OpenZFS [OpenZFS_Install] OptionDesc = %ServiceDescription% CopyFiles = OpenZFS.DriverFiles +AddReg=Device_AddReg + +[Device_AddReg] +HKR,,DeviceType,0x00010001,1 + ;;,OpenZFS.DllFiles ;;RegisterDlls = shellopenzfs @@ -71,7 +78,7 @@ DelService = %ServiceName%,0x200 ;Ensure service is stopped before deleting [OpenZFS.Service] DisplayName = %ServiceName% Description = %ServiceDescription% -ServiceBinary = %12%\OpenZFS.sys ;%windir%\system32\drivers\ +ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\ ServiceType = 1 StartType = 1 ;SERVICE_SYSTEM_START ErrorControl = 1 @@ -85,8 +92,8 @@ LoadOrderGroup = "File System" ; [OpenZFS.DriverFiles] -OpenZFS.sys -OpenZFS.man +%DriverName%.sys +%DriverName%.man [OpenZFS.DllFiles] ;;zpool.exe diff --git a/module/os/windows/driver.c b/module/os/windows/driver.c index d153eb553ab3..bffd81503e9c 100644 --- a/module/os/windows/driver.c +++ b/module/os/windows/driver.c @@ -30,10 +30,13 @@ #include #include +#include #include #include #include +#include +#include #include "Trace.h" @@ -65,13 +68,103 @@ extern void sysctl_os_fini(void); PDRIVER_OBJECT WIN_DriverObject = NULL; PDRIVER_UNLOAD STOR_DriverUnload = NULL; PDRIVER_DISPATCH STOR_MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; - wzvolDriverInfo STOR_wzvolDriverInfo; extern _Function_class_(IO_WORKITEM_ROUTINE) void __stdcall sysctl_os_registry_change(DEVICE_OBJECT *DeviceObject, PVOID Parameter); +void +mount_add_device(PDEVICE_OBJECT DriverObject, + PDEVICE_OBJECT PhysicalDeviceObject, PDEVICE_OBJECT AddDeviceObject); + +NTSTATUS +OpenZFS_AddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject +) +{ + NTSTATUS status; + + if (PhysicalDeviceObject == NULL) { + DbgBreakPoint(); + return (STATUS_NO_MORE_ENTRIES); + } + + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(DriverObject, DriverObject); + + xprintf("%s called: PhysicalDeviceObject %p\n", __func__, PhysicalDeviceObject); + DbgBreakPoint(); + + if (DriverExtension == NULL) { + dprintf("No DriverExtension? Help!\n"); + return (STATUS_INVALID_PARAMETER); + } + + if (PhysicalDeviceObject->DeviceType == FILE_DEVICE_CONTROLLER) { + DriverExtension->PhysicalDeviceObject = PhysicalDeviceObject; + return (STATUS_SUCCESS); + } + + // This isnt needed, we set it in DriverLoad + if (DriverExtension->PhysicalDeviceObject == NULL) { + // Called when driver installs at load time. + DriverExtension->PhysicalDeviceObject = PhysicalDeviceObject; +#if 0 // chatgpt version + // I feel we don't really need this one? + status = IoCreateDevice( + DriverObject, + sizeof(mount_t), + NULL, + FILE_DEVICE_BUS_EXTENDER, + FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, + FALSE, + &DriverExtension->FunctionalDeviceObject // busfdo + ); + + if (NT_SUCCESS(status)) { + mount_t *zmo = DriverExtension->FunctionalDeviceObject->DeviceExtension; + zmo->size = sizeof(mount_t); + zmo->type = MOUNT_TYPE_BUS; + DriverExtension->FunctionalDeviceObject->Flags |= DO_POWER_PAGABLE; + DriverExtension->FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + // DriverExtension->ChildDeviceObject = DriverExtension->FunctionalDeviceObject; + zmo->PhysicalDeviceObject = PhysicalDeviceObject; + + DriverExtension->LowerDeviceObject = + IoAttachDeviceToDeviceStack(DriverExtension->FunctionalDeviceObject, + PhysicalDeviceObject); + + zmo->LowerDeviceObject = DriverExtension->LowerDeviceObject; + RtlInitUnicodeString(&zmo->bus_name, L"OpenZFS"); + + status = IoRegisterDeviceInterface(DriverExtension->FunctionalDeviceObject, + &BtrfsBusInterface, NULL, &zmo->bus_name); + + status = IoSetDeviceInterfaceState(&zmo->bus_name, TRUE); + + } +#else // btrfs + + +#endif + return (STATUS_SUCCESS); + } + +// DbgBreakPoint(); + + // OK, we created a new mount + if (DriverExtension->AddDeviceObject) { + PDEVICE_OBJECT AddDeviceObject = DriverExtension->AddDeviceObject; + DriverExtension->AddDeviceObject = NULL; // Yeah, we need better sync here + + mount_add_device(DriverObject, PhysicalDeviceObject, AddDeviceObject); + + } + + return (STATUS_SUCCESS); +} void OpenZFS_Fini(PDRIVER_OBJECT DriverObject) @@ -114,9 +207,25 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING pRegistryPath) { NTSTATUS status; + OpenZFS_Driver_Extension *DriverExtension; + KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "OpenZFS: DriverEntry\n")); + LARGE_INTEGER start, end, frequency; + LONGLONG elapsedTime; + frequency = KeQueryPerformanceCounter(NULL); + start = KeQueryPerformanceCounter(NULL); + + + status = IoAllocateDriverObjectExtension( + DriverObject, + DriverObject, // Identifying the extension + sizeof(OpenZFS_Driver_Extension), // Size of your custom structure + (PVOID*)&DriverExtension + ); + + ZFSWppInit(DriverObject, pRegistryPath); // Setup global so zfs_ioctl.c can setup devnode @@ -160,6 +269,7 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, /* Now set the Driver Callbacks to dispatcher and start ZFS */ WIN_DriverObject->DriverUnload = OpenZFS_Fini; + WIN_DriverObject->DriverExtension->AddDevice = OpenZFS_AddDevice; /* Start ZFS itself */ zfs_kmod_init(); @@ -172,5 +282,11 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "OpenZFS: Started\n")); + + end = KeQueryPerformanceCounter(NULL); + elapsedTime = ((end.QuadPart - start.QuadPart) * 1000000) / frequency.QuadPart; + xprintf("DriverEntry execution time: %lld microseconds\n", elapsedTime); + return (STATUS_SUCCESS); } + diff --git a/module/os/windows/zfs/sysctl_os.c b/module/os/windows/zfs/sysctl_os.c index 16a4fa58268b..e9d6f2dcc349 100644 --- a/module/os/windows/zfs/sysctl_os.c +++ b/module/os/windows/zfs/sysctl_os.c @@ -149,11 +149,11 @@ sysctl_os_process(PUNICODE_STRING pRegistryPath, ztunable_t *zt) { HANDLE regfd = NULL; - dprintf( - "tunable: '%s/%s' type %d at %p\n", - zt->zt_prefix, zt->zt_name, - zt->zt_type, - zt->zt_ptr); +// dprintf( +// "tunable: '%s/%s' type %d at %p\n", +// zt->zt_prefix, zt->zt_name, +// zt->zt_type, +// zt->zt_ptr); /* * tunable: 'zfs_prefetch_disable' type 0 at FFFFF80731A1B770 diff --git a/module/os/windows/zfs/zfs_ioctl_os.c b/module/os/windows/zfs/zfs_ioctl_os.c index 993e7bafd509..7040a71d885f 100644 --- a/module/os/windows/zfs/zfs_ioctl_os.c +++ b/module/os/windows/zfs/zfs_ioctl_os.c @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -969,16 +970,21 @@ zfs_ioc_unregister_fs(void) zfs_module_busy); return (zfs_module_busy); } - if (fsDiskDeviceObject != NULL) { + + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); + + if (DriverExtension->fsDiskDeviceObject != NULL) { IoUnregisterFsRegistrationChange(WIN_DriverObject, DriverNotificationRoutine); - IoUnregisterFileSystem(fsDiskDeviceObject); - ObDereferenceObject(fsDiskDeviceObject); + IoUnregisterFileSystem(DriverExtension->fsDiskDeviceObject); + // ObDereferenceObject(DriverExtension->fsDiskDeviceObject); UNICODE_STRING ntWin32NameString; RtlInitUnicodeString(&ntWin32NameString, ZFS_DEV_DOS); IoDeleteSymbolicLink(&ntWin32NameString); - IoDeleteDevice(fsDiskDeviceObject); - fsDiskDeviceObject = NULL; + IoDeleteDevice(DriverExtension->fsDiskDeviceObject); + DriverExtension->fsDiskDeviceObject = NULL; + DbgBreakPoint(); } #if 0 // Do not unload these, so that the zfsinstaller uninstall can @@ -1008,6 +1014,45 @@ openzfs_fini_os(void) { } +void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 = NULL; + +#ifdef _MSC_VER +#include +#include +#include +#undef INITGUID +#endif + +_Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) +NTSTATUS __stdcall +volume_notification(PVOID NotificationStructure, PVOID Context) +{ + DEVICE_INTERFACE_CHANGE_NOTIFICATION *dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION *)NotificationStructure; + xprintf("%s called.\n", __func__); + + if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) + xprintf("%s arrival: %wZ\n", __func__, dicn->SymbolicLinkName); + else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) + xprintf("%s removal: %wZ\n", __func__, dicn->SymbolicLinkName); + + return (STATUS_SUCCESS); +} + +_Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) +NTSTATUS __stdcall +pnp_notification(PVOID NotificationStructure, PVOID Context) +{ + DEVICE_INTERFACE_CHANGE_NOTIFICATION *dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION *)NotificationStructure; + dprintf("%s called.\n", __func__); + + if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) + xprintf("%s arrival: %wZ\n", __func__, dicn->SymbolicLinkName); + else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) + xprintf("%s removal: %wZ\n", __func__, dicn->SymbolicLinkName); + + return (STATUS_SUCCESS); +} + int zfsdev_attach(void) { @@ -1021,78 +1066,13 @@ zfsdev_attach(void) "(A;;GRGWGX;;;WD)(A;;GRGX;;;RC)"); // Or use &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R - RtlInitUnicodeString(&ntUnicodeString, ZFS_DEV_KERNEL); - ntStatus = IoCreateDeviceSecure( - WIN_DriverObject, - sizeof (mount_t), - &ntUnicodeString, // Device name "\Device\SIOCTL" - FILE_DEVICE_UNKNOWN, // Device type - /* FILE_DEVICE_SECURE_OPEN */ 0, // Device characteristics - FALSE, // Not an exclusive device - &sddl, - NULL, - &ioctlDeviceObject); // Returned ptr to Device Object - - if (!NT_SUCCESS(ntStatus)) { - dprintf("ZFS: Couldn't create the device object " - "/dev/zfs (%S)\n", ZFS_DEV_KERNEL); - return (ntStatus); - } - dprintf("ZFS: created kernel device node: %p: name %S\n", - ioctlDeviceObject, ZFS_DEV_KERNEL); - - UNICODE_STRING fsDiskDeviceName; - RtlInitUnicodeString(&fsDiskDeviceName, ZFS_GLOBAL_FS_DISK_DEVICE_NAME); - - ntStatus = IoCreateDeviceSecure(WIN_DriverObject, // DriverObject - sizeof (mount_t), // DeviceExtensionSize - &fsDiskDeviceName, // DeviceName - FILE_DEVICE_DISK_FILE_SYSTEM, // DeviceType - 0, - FALSE, - &sddl, - NULL, - &fsDiskDeviceObject); // DeviceObject - - ObReferenceObject(ioctlDeviceObject); - - mount_t *dgl; - dgl = ioctlDeviceObject->DeviceExtension; - dgl->type = MOUNT_TYPE_DGL; - dgl->size = sizeof (mount_t); - - mount_t *vcb; - vcb = fsDiskDeviceObject->DeviceExtension; - vcb->type = MOUNT_TYPE_VCB; - vcb->size = sizeof (mount_t); - - if (ntStatus == STATUS_SUCCESS) { - dprintf("DiskFileSystemDevice: 0x%0x %wZ created\n", - ntStatus, &fsDiskDeviceName); - } - - // Initialize a Unicode String containing the Win32 name - // for our device. - RtlInitUnicodeString(&ntWin32NameString, ZFS_DEV_DOS); - - // Create a symbolic link between our device name and the Win32 name - ntStatus = IoCreateSymbolicLink( - &ntWin32NameString, &ntUnicodeString); - - if (!NT_SUCCESS(ntStatus)) { - dprintf("ZFS: Couldn't create userland symbolic link to " - "/dev/zfs (%wZ)\n", ZFS_DEV); - ObDereferenceObject(ioctlDeviceObject); - IoDeleteDevice(ioctlDeviceObject); - return (-1); - } - dprintf("ZFS: created userland device symlink\n"); - - fsDiskDeviceObject->Flags |= DO_DIRECT_IO; - fsDiskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - IoRegisterFileSystem(fsDiskDeviceObject); - ObReferenceObject(fsDiskDeviceObject); + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); + if (DriverExtension == NULL) + return (STATUS_INVALID_DEVICE_REQUEST); + // ObReferenceObject(fsDiskDeviceObject); +#if 1 NTSTATUS pcwStatus = RegisterZFSinPerf(ZFSinPerfCallBack, NULL); if (!NT_SUCCESS(pcwStatus)) { TraceEvent(TRACE_ERROR, "ZFSin perf registration failed\n"); @@ -1107,7 +1087,7 @@ zfsdev_attach(void) TraceEvent(TRACE_ERROR, "ZFSin cache perf registration failed\n"); } - +#endif // Set all the callbacks to "dispatch()" WIN_DriverObject->MajorFunction[IRP_MJ_CREATE] = @@ -1156,6 +1136,94 @@ zfsdev_attach(void) (PDRIVER_DISPATCH)dispatcher; WIN_DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = (PDRIVER_DISPATCH)dispatcher; + WIN_DriverObject->MajorFunction[IRP_MJ_POWER] = + (PDRIVER_DISPATCH)dispatcher; + +#if 1 + RtlInitUnicodeString(&ntUnicodeString, ZFS_DEV_KERNEL); + // RtlInitUnicodeString(&ntUnicodeString, L"\\OpenZFS"); + ntStatus = IoCreateDeviceSecure( + WIN_DriverObject, + sizeof (mount_t), + &ntUnicodeString, // Device name "\Device\SIOCTL" + FILE_DEVICE_UNKNOWN, // Device type + FILE_DEVICE_SECURE_OPEN, // Device characteristics + FALSE, // Not an exclusive device + &sddl, + NULL, + &DriverExtension->ioctlDeviceObject); // Returned ptr to Device Object + + if (!NT_SUCCESS(ntStatus)) { + dprintf("ZFS: Couldn't create the device object " + "/dev/zfs (%S)\n", ZFS_DEV_KERNEL); + return (ntStatus); + } +// dprintf("ZFS: created kernel device node: %p: name %S\n", +// DriverExtension->ioctlDeviceObject, ZFS_DEV_KERNEL); + + // ObReferenceObject(ioctlDeviceObject); + + mount_t *dgl; + dgl = DriverExtension->ioctlDeviceObject->DeviceExtension; + dgl->type = MOUNT_TYPE_DGL; + dgl->size = sizeof (mount_t); + + // Initialize a Unicode String containing the Win32 name + // for our device. + RtlInitUnicodeString(&ntWin32NameString, ZFS_DEV_DOS); + //RtlInitUnicodeString(&ntWin32NameString, L"\\DosDevices\\OpenZFS"); + + // Create a symbolic link between our device name and the Win32 name + ntStatus = IoCreateSymbolicLink( + &ntWin32NameString, &ntUnicodeString); + + if (!NT_SUCCESS(ntStatus)) { + dprintf("ZFS: Couldn't create userland symbolic link to " + "/dev/zfs (%wZ)\n", ZFS_DEV); + // ObDereferenceObject(ioctlDeviceObject); + IoDeleteDevice(DriverExtension->ioctlDeviceObject); + return (-1); + } +// dprintf("ZFS: created userland device symlink\n"); + + DriverExtension->ioctlDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; +#endif + +#if 1 + UNICODE_STRING fsDiskDeviceName; + // RtlInitUnicodeString(&fsDiskDeviceName, ZFS_GLOBAL_FS_DISK_DEVICE_NAME); + RtlInitUnicodeString(&fsDiskDeviceName, L"\\OpenZFS"); + // DbgBreakPoint(); + ntStatus = IoCreateDeviceSecure(WIN_DriverObject, // DriverObject + sizeof (mount_t), // DeviceExtensionSize + &fsDiskDeviceName, // DeviceName + FILE_DEVICE_DISK_FILE_SYSTEM, // DeviceType + 0, + FALSE, + &sddl, + NULL, + &DriverExtension->fsDiskDeviceObject); // DeviceObject + + mount_t *vcb; + vcb = DriverExtension->fsDiskDeviceObject->DeviceExtension; + vcb->type = MOUNT_TYPE_VCB; + vcb->size = sizeof (mount_t); + + if (ntStatus == STATUS_SUCCESS) { + dprintf("DiskFileSystemDevice: 0x%0x %wZ created\n", + ntStatus, &fsDiskDeviceName); + } + + DriverExtension->fsDiskDeviceObject->Flags |= DO_DIRECT_IO; + DriverExtension->fsDiskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + RtlInitUnicodeString(&ntWin32NameString, L"\\DosDevices\\OpenZFS"); + ntStatus = IoCreateSymbolicLink( + &ntWin32NameString, &ntUnicodeString); + +// IoRegisterFileSystem(DriverExtension->fsDiskDeviceObject); +// ObReferenceObject(DriverExtension->fsDiskDeviceObject); +#endif fastio_init(&WIN_DriverObject->FastIoDispatch); @@ -1179,6 +1247,58 @@ zfsdev_attach(void) "ZFS pool version %s, ZFS filesystem version %s\n", ZFS_META_GITREV, SPA_VERSION_STRING, ZPL_VERSION_STRING); +#if 1 + // btrfs + NTSTATUS status; + + status = IoCreateDevice( + WIN_DriverObject, + sizeof(mount_t), + NULL, + FILE_DEVICE_UNKNOWN, + FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, + FALSE, + &DriverExtension->FunctionalDeviceObject // busfdo + ); + + mount_t *zmo_bus = DriverExtension->FunctionalDeviceObject->DeviceExtension; + zmo_bus->size = sizeof(mount_t); + zmo_bus->type = MOUNT_TYPE_BUS; + zmo_bus->FunctionalDeviceObject = DriverExtension->FunctionalDeviceObject; + + status = IoReportDetectedDevice(WIN_DriverObject, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, + NULL, NULL, 0, &zmo_bus->PhysicalDeviceObject); + xprintf("%s called: PhysicalDeviceObject %p\n", __func__, zmo_bus->PhysicalDeviceObject); + + status = IoRegisterDeviceInterface(zmo_bus->PhysicalDeviceObject, &BtrfsBusInterface, NULL, + &zmo_bus->deviceInterfaceName); + + zmo_bus->AttachedDevice = IoAttachDeviceToDeviceStack(DriverExtension->FunctionalDeviceObject, + zmo_bus->PhysicalDeviceObject); + + DriverExtension->FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + status = IoSetDeviceInterfaceState(&zmo_bus->deviceInterfaceName, TRUE); + + IoInvalidateDeviceRelations(zmo_bus->PhysicalDeviceObject, BusRelations); + + status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, + (PVOID)&GUID_DEVINTERFACE_VOLUME, WIN_DriverObject, volume_notification, NULL, ¬ification_entry2); + + status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, + (PVOID)&GUID_DEVINTERFACE_HIDDEN_VOLUME, WIN_DriverObject, volume_notification, NULL, ¬ification_entry3); + + status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, + (PVOID)&GUID_DEVINTERFACE_DISK, WIN_DriverObject, pnp_notification, WIN_DriverObject, ¬ification_entry); + + + // btrfs + +#endif + + IoRegisterFileSystem(DriverExtension->fsDiskDeviceObject); + ObReferenceObject(DriverExtension->fsDiskDeviceObject); + return (0); @@ -1189,6 +1309,7 @@ zfsdev_attach(void) icp_failed: zcommon_fini(); zcommon_failed: + DbgBreakPoint(); return (err); } diff --git a/module/os/windows/zfs/zfs_vnops_windows.c b/module/os/windows/zfs/zfs_vnops_windows.c index 0bc69e4a5b64..ac34ec8e0825 100644 --- a/module/os/windows/zfs/zfs_vnops_windows.c +++ b/module/os/windows/zfs/zfs_vnops_windows.c @@ -37,6 +37,7 @@ #include #include #include +#include // I have no idea what black magic is needed to get ntifs.h to define these @@ -78,14 +79,16 @@ #include #include -PDEVICE_OBJECT ioctlDeviceObject = NULL; -PDEVICE_OBJECT fsDiskDeviceObject = NULL; #ifdef DEBUG_IOCOUNT static kmutex_t GIANT_SERIAL_LOCK; #endif #ifdef _KERNEL +#ifndef STATUS_VOLUME_NOT_MOUNTED +#define STATUS_VOLUME_NOT_MOUNTED 0xC000001A +#endif + DRIVER_INITIALIZE DriverEntry; unsigned int debug_vnop_osx_printf = 0; @@ -2175,29 +2178,96 @@ dev_ioctl(PDEVICE_OBJECT DeviceObject, ULONG ControlCode, PVOID InputBuffer, return (Status); } +static WCHAR +hex_digit(uint8_t u) +{ + if (u >= 0xa && u <= 0xf) + return ((uint8_t)(u - 0xa + 'a')); + else + return ((uint8_t)(u + '0')); +} + // THIS IS THE PNP DEVICE ID NTSTATUS pnp_query_id(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { mount_t *zmo; + WCHAR *idString = NULL; + int idLen = 0; + NTSTATUS Status = STATUS_SUCCESS; + DECLARE_UNICODE_STRING_SIZE(mpt, 100); dprintf("%s: query id type %d\n", __func__, IrpSp->Parameters.QueryId.IdType); + Irp->IoStatus.Information = NULL; + zmo = (mount_t *)DeviceObject->DeviceExtension; + /* + * Hark. So BusQueryHardwareIDs and BusQueryCompatibleIDs do not + * take a single string, but a MULTI_SZ - list of strings. + * Each string is null-terminated, and the last string is + * double null-terminated. Oh the fun we had figuring that out. + */ + switch (IrpSp->Parameters.QueryId.IdType) { + case BusQueryDeviceID: + RtlUnicodeStringPrintf(&mpt, + L"OpenZFS\\%wZ%lc", &zmo->uuid, 0); + idString = mpt.Buffer; + idLen = mpt.Length; + break; + case BusQueryHardwareIDs: // IDs, plural + if (zmo->type == MOUNT_TYPE_BUS) + RtlUnicodeStringPrintf(&mpt, + L"ROOT\\OpenZFS%lc%lc", 0, 0); // double nulls + else + RtlUnicodeStringPrintf(&mpt, + L"OpenZFSVolume%lc%lc", 0, 0); + idString = mpt.Buffer; + idLen = mpt.Length; + break; +#if 0 + case BusQueryCompatibleIDs: + RtlUnicodeStringPrintf(&mpt, + L"OpenZFS\\Generic%lc%lc", 0, 0); + idString = mpt.Buffer; + idLen = mpt.Length; + break; + case BusQueryInstanceID: // Needs to be unique. + idString = zmo->uuid.Buffer; + idLen = zmo->uuid.Length; + break; + case BusQueryContainerID: + idString = zmo->device_name.Buffer; + idLen = zmo->device_name.Length; + break; +#endif + default: + // Status = Irp->IoStatus.Status; + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } - Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePoolWithTag(PagedPool, - zmo->bus_name.Length + sizeof (UNICODE_NULL), '!OIZ'); - if (Irp->IoStatus.Information == 0) - return (STATUS_NO_MEMORY); + if (idLen > 0) { + WCHAR *str; + str = (WCHAR *)ExAllocatePoolWithTag(PagedPool, + idLen /* + sizeof(WCHAR) */, '!OIZ'); + if (str == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); - RtlCopyMemory((void *)Irp->IoStatus.Information, zmo->bus_name.Buffer, - zmo->bus_name.Length); - dprintf("replying with '%.*S'\n", - (int)(zmo->uuid.Length/sizeof (WCHAR)), - (WCHAR *)Irp->IoStatus.Information); + RtlCopyMemory((void *)str, idString, + idLen); + // str[idLen / sizeof(WCHAR)] = UNICODE_NULL; - return (STATUS_SUCCESS); + Irp->IoStatus.Information = (ULONG_PTR)str; + + dprintf("replying with '%.*S'\n", + (int)(idLen/sizeof (WCHAR)), + (WCHAR *)str); + + } + + return (Status); } NTSTATUS @@ -2205,8 +2275,10 @@ pnp_device_state(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { dprintf("%s:\n", __func__); + PPNP_DEVICE_STATE pDeviceState = (PPNP_DEVICE_STATE)&Irp->IoStatus.Information; - Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; + pDeviceState = 0; + // Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; return (STATUS_SUCCESS); } @@ -2309,9 +2381,9 @@ query_volume_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName); UNICODE_STRING name; - if (zfsvfs->z_mimic == ZFS_MIMIC_OFF) - RtlInitUnicodeString(&name, L"ZFS"); - else + // if (zfsvfs->z_mimic == ZFS_MIMIC_OFF) + // RtlInitUnicodeString(&name, L"ZFS"); + // else RtlInitUnicodeString(&name, L"NTFS"); space = MIN(space, name.Length); @@ -2394,6 +2466,7 @@ query_volume_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, break; case FileFsVolumeInformation: + // Confirmed this call beha dprintf("* %s: FileFsVolumeInformation\n", __func__); if (IrpSp->Parameters.QueryVolume.Length < sizeof (FILE_FS_VOLUME_INFORMATION)) { @@ -3927,6 +4000,7 @@ user_fs_request(PDEVICE_OBJECT DeviceObject, PIRP *PIrp, break; case FSCTL_DISMOUNT_VOLUME: dprintf(" FSCTL_DISMOUNT_VOLUME\n"); + DbgBreakPoint(); break; case FSCTL_MARK_VOLUME_DIRTY: dprintf(" FSCTL_MARK_VOLUME_DIRTY\n"); @@ -3936,11 +4010,15 @@ user_fs_request(PDEVICE_OBJECT DeviceObject, PIRP *PIrp, dprintf(" FSCTL_IS_VOLUME_MOUNTED\n"); Status = STATUS_SUCCESS; { + Status = STATUS_VOLUME_NOT_MOUNTED; mount_t *zmo; zmo = DeviceObject->DeviceExtension; zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); - if (zfsvfs->z_unmounted) - Status = STATUS_VERIFY_REQUIRED; + if (zfsvfs) { + Status = STATUS_VOLUME_MOUNTED; + if (zfsvfs->z_unmounted) + Status = STATUS_VERIFY_REQUIRED; + } } break; case FSCTL_SET_COMPRESSION: @@ -4143,11 +4221,12 @@ user_fs_request(PDEVICE_OBJECT DeviceObject, PIRP *PIrp, return (STATUS_BUFFER_TOO_SMALL); Info = Buffer; +#if 0 if (1 != Info->Version || !FlagOn(Info->FlagMask, PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED)) return (STATUS_INVALID_PARAMETER); - +#endif RtlZeroMemory(Info, sizeof (FILE_FS_PERSISTENT_VOLUME_INFORMATION)); Info->VolumeFlags = @@ -5973,15 +6052,31 @@ ioctl_volume_get_volume_disk_extents(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { VOLUME_DISK_EXTENTS *vde = Irp->AssociatedIrp.SystemBuffer; + ULONG requiredSize = sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT); + mount_t *zmo = DeviceObject->DeviceExtension; + int error; - if (IrpSp->Parameters.QueryFile.Length < sizeof (VOLUME_DISK_EXTENTS)) { - Irp->IoStatus.Information = sizeof (VOLUME_DISK_EXTENTS); + if (IrpSp->Parameters.QueryFile.Length < requiredSize) { + Irp->IoStatus.Information = requiredSize; return (STATUS_BUFFER_TOO_SMALL); } - Irp->IoStatus.Information = sizeof (VOLUME_DISK_EXTENTS); - RtlZeroMemory(vde, sizeof (VOLUME_DISK_EXTENTS)); + Irp->IoStatus.Information = requiredSize; vde->NumberOfDiskExtents = 1; + vde->Extents[0].DiskNumber = 0; + vde->Extents[0].StartingOffset.QuadPart = 0ULL; + vde->Extents[0].ExtentLength.QuadPart = 1024 * 1024 * 1024ULL; + + zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); + if (zfsvfs != NULL) { + if ((error = zfs_enter(zfsvfs, FTAG)) == 0) { + uint64_t refdbytes, availbytes, usedobjs, availobjs; + dmu_objset_space(zfsvfs->z_os, + &refdbytes, &availbytes, &usedobjs, &availobjs); + vde->Extents[0].ExtentLength.QuadPart = refdbytes * availbytes; + zfs_exit(zfsvfs, FTAG); + } + } return (STATUS_SUCCESS); } @@ -5994,10 +6089,12 @@ volume_create(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) // This is also called from fsContext when IRP_MJ_CREATE // FileName is NULL /* VERIFY(zmo->type == MOUNT_TYPE_DCB); */ +#if 1 if (zmo->vpb != NULL) IrpSp->FileObject->Vpb = zmo->vpb; else IrpSp->FileObject->Vpb = DeviceObject->Vpb; +#endif // dprintf("Setting FileObject->Vpb to %p\n", IrpSp->FileObject->Vpb); // SetFileObjectForVCB(IrpSp->FileObject, zmo); @@ -6413,6 +6510,99 @@ zfsdev_async(PDEVICE_OBJECT DeviceObject, PIRP Irp) return (error); } +/* + * dispatcher for the "bus", so we can add pnp devices for mounting + */ +_Function_class_(DRIVER_DISPATCH) + static NTSTATUS + busDispatcher(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP *PIrp, + PIO_STACK_LOCATION IrpSp) +{ + NTSTATUS Status; + PIRP Irp = *PIrp; + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); + + PAGED_CODE(); + + dprintf(" %s: enter: major %d: minor %d: %s busDeviceObject\n", + __func__, IrpSp->MajorFunction, IrpSp->MinorFunction, + major2str(IrpSp->MajorFunction, IrpSp->MinorFunction)); + + Status = STATUS_INVALID_DEVICE_REQUEST; + + + + switch (IrpSp->MajorFunction) { + + case IRP_MJ_PNP: + switch(IrpSp->MinorFunction) { + case IRP_MN_START_DEVICE: + dprintf("IRP_MN_START_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + case IRP_MN_CANCEL_REMOVE_DEVICE: + dprintf("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + case IRP_MN_SURPRISE_REMOVAL: + dprintf("IRP_MN_SURPRISE_REMOVAL\n"); + Status = STATUS_SUCCESS; + break; + case IRP_MN_REMOVE_DEVICE: + dprintf("IRP_MN_REMOVE_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_DEVICE_RELATIONS: + Status = QueryDeviceRelations(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_QUERY_CAPABILITIES: + Status = QueryCapabilities(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_QUERY_PNP_DEVICE_STATE: + Status = pnp_device_state(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_QUERY_ID: + Status = pnp_query_id(DeviceObject, Irp, IrpSp); + break; + + // maybes + case IRP_MN_QUERY_INTERFACE: + Status = pnp_query_di(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_QUERY_BUS_INFORMATION: + dprintf("IRP_MN_QUERY_BUS_INFORMATION\n"); + Status = pnp_query_bus_information(DeviceObject, Irp, IrpSp); + break; + + // these are not handled in btrfs, pass down + case IRP_MN_DEVICE_ENUMERATED: + dprintf("IRP_MN_DEVICE_ENUMERATED\n"); + break; + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: + dprintf("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + // PIO_RESOURCE_REQUIREMENTS_LIST resList = + // (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information; + // Status = STATUS_SUCCESS; + break; + + default: + dprintf("**** unknown pnp IRP_MJ_PNP: 0x%lx\n", + IrpSp->MinorFunction); + DbgBreakPoint(); + break; + } + break; + + default: + dprintf("**** unknown pnp IRP_MJ_: 0x%lx\n", + IrpSp->MajorFunction); + DbgBreakPoint(); + } + + return (Status); +} + /* * This is the ioctl handler for ioctl done directly on /dev/zfs node. * This means all the internal ZFS ioctls, like ZFS_IOC_SEND etc. @@ -6427,6 +6617,8 @@ _Function_class_(DRIVER_DISPATCH) { NTSTATUS Status; PIRP Irp = *PIrp; + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); PAGED_CODE(); @@ -6450,12 +6642,12 @@ _Function_class_(DRIVER_DISPATCH) // uninstall extern kmutex_t zfsdev_state_lock; - if (fsDiskDeviceObject == NULL) { + if (DriverExtension->fsDiskDeviceObject == NULL) { mutex_enter(&zfsdev_state_lock); - if (ioctlDeviceObject != NULL) { - ObDereferenceObject(ioctlDeviceObject); - IoDeleteDevice(ioctlDeviceObject); - ioctlDeviceObject = NULL; + if (DriverExtension->ioctlDeviceObject != NULL) { +// ObDereferenceObject(ioctlDeviceObject); + IoDeleteDevice(DriverExtension->ioctlDeviceObject); + DriverExtension->ioctlDeviceObject = NULL; } mutex_exit(&zfsdev_state_lock); } @@ -6530,8 +6722,16 @@ _Function_class_(DRIVER_DISPATCH) Status = ioctl_query_stable_guid(DeviceObject, Irp, IrpSp); break; + case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED: + dprintf("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED\n"); + Status = STATUS_SUCCESS; + break; + case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED: + dprintf("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED\n"); + Status = STATUS_SUCCESS; + break; case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: - dprintf("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME\n"); + dprintf("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME\n"); break; case IOCTL_VOLUME_ONLINE: dprintf("IOCTL_VOLUME_ONLINE\n"); @@ -6578,6 +6778,7 @@ _Function_class_(DRIVER_DISPATCH) default: dprintf("**** unknown Windows IOCTL: 0x%lx\n", cmd); + DbgBreakPoint(); } } @@ -6623,6 +6824,17 @@ _Function_class_(DRIVER_DISPATCH) break; case IRP_MN_REMOVE_DEVICE: dprintf("IRP_MN_REMOVE_DEVICE\n"); +#if 0 + PVPB vpb = DeviceObject->Vpb; + KIRQL OldIrql; + IoAcquireVpbSpinLock(&OldIrql); + vpb->ReferenceCount--; + IoReleaseVpbSpinLock(&OldIrql); +#endif + Status = STATUS_SUCCESS; + break; + case IRP_MN_START_DEVICE: + dprintf("IRP_MN_START_DEVICE\n"); Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: @@ -6666,7 +6878,7 @@ _Function_class_(DRIVER_DISPATCH) __func__, IrpSp->MajorFunction, IrpSp->MinorFunction, major2str(IrpSp->MajorFunction, IrpSp->MinorFunction)); - Status = STATUS_NOT_IMPLEMENTED; + Status = STATUS_INVALID_DEVICE_REQUEST; switch (IrpSp->MajorFunction) { @@ -6713,6 +6925,18 @@ _Function_class_(DRIVER_DISPATCH) Status = ioctl_mountdev_query_suggested_link_name( DeviceObject, Irp, IrpSp); break; + case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED: + dprintf("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED\n"); + Status = STATUS_SUCCESS; + break; + case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED: + dprintf("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED\n"); + Status = STATUS_SUCCESS; + break; + case IOCTL_MOUNTMGR_DELETE_POINTS: + dprintf("IOCTL_MOUNTMGR_DELETE_POINTS\n"); + Status = STATUS_SUCCESS; + break; case IOCTL_VOLUME_ONLINE: dprintf("IOCTL_VOLUME_ONLINE\n"); Status = STATUS_SUCCESS; @@ -6720,7 +6944,7 @@ _Function_class_(DRIVER_DISPATCH) case IOCTL_VOLUME_OFFLINE: case IOCTL_VOLUME_IS_OFFLINE: dprintf("IOCTL_VOLUME_OFFLINE\n"); - Status = STATUS_SUCCESS; + Status = STATUS_VOLUME_MOUNTED; break; case IOCTL_DISK_IS_WRITABLE: dprintf("IOCTL_DISK_IS_WRITABLE\n"); @@ -6801,9 +7025,15 @@ _Function_class_(DRIVER_DISPATCH) Status = ioctl_disk_get_drive_geometry(DeviceObject, Irp, IrpSp); break; + case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: + dprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX\n"); + Status = ioctl_disk_get_drive_geometry_ex(DeviceObject, + Irp, IrpSp); + break; default: dprintf("**** unknown disk Windows IOCTL: 0x%lx\n", cmd); + // DbgBreakPoint(); } } @@ -6816,15 +7046,12 @@ _Function_class_(DRIVER_DISPATCH) // Technically we don't really let them read from the virtual // devices that hold the ZFS filesystem, so we just return all zeros. case IRP_MJ_READ: - dprintf("disk fake read\n"); - uint64_t bufferLength; - bufferLength = IrpSp->Parameters.Read.Length; - Irp->IoStatus.Information = bufferLength; - Status = STATUS_SUCCESS; + Status = volume_read(DeviceObject, Irp, IrpSp); break; case IRP_MJ_WRITE: dprintf("disk fake write\n"); + DbgBreakPoint(); Irp->IoStatus.Information = IrpSp->Parameters.Write.Length; Status = STATUS_SUCCESS; break; @@ -6851,16 +7078,12 @@ _Function_class_(DRIVER_DISPATCH) Status = query_information(DeviceObject, Irp, IrpSp); break; + case IRP_MJ_QUERY_VOLUME_INFORMATION: + Status = query_volume_information(DeviceObject, Irp, IrpSp); + break; + case IRP_MJ_PNP: switch (IrpSp->MinorFunction) { - case IRP_MN_QUERY_CAPABILITIES: - Status = QueryCapabilities(DeviceObject, Irp, IrpSp); - break; - case IRP_MN_QUERY_DEVICE_RELATIONS: - Status = STATUS_NOT_IMPLEMENTED; - dprintf("DeviceRelations.Type 0x%x\n", - IrpSp->Parameters.QueryDeviceRelations.Type); - break; case IRP_MN_QUERY_ID: Status = pnp_query_id(DeviceObject, Irp, IrpSp); break; @@ -6875,17 +7098,50 @@ _Function_class_(DRIVER_DISPATCH) dprintf("IRP_MN_SURPRISE_REMOVAL\n"); Status = STATUS_SUCCESS; break; + case IRP_MN_CANCEL_REMOVE_DEVICE: + dprintf("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Status = STATUS_SUCCESS; + break; case IRP_MN_REMOVE_DEVICE: dprintf("IRP_MN_REMOVE_DEVICE\n"); - Status = STATUS_SUCCESS; + Status = STATUS_UNSUCCESSFUL; break; - case IRP_MN_CANCEL_REMOVE_DEVICE: - dprintf("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + case IRP_MN_QUERY_DEVICE_RELATIONS: + Status = QueryDeviceRelations(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + dprintf("IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); Status = STATUS_SUCCESS; break; + // The rest btrfs does not have, pass down + case IRP_MN_QUERY_CAPABILITIES: + dprintf("IRP_MN_QUERY_CAPABILITIES\n"); + // Status = QueryCapabilities(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_QUERY_INTERFACE: + dprintf("IRP_MN_QUERY_INTERFACE\n"); + // Status = pnp_query_di(DeviceObject, Irp, IrpSp); + break; + case IRP_MN_QUERY_DEVICE_TEXT: + dprintf("IRP_MN_QUERY_DEVICE_TEXT\n"); + break; + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + dprintf("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + break; + case IRP_MN_QUERY_RESOURCES: + dprintf("IRP_MN_QUERY_RESOURCES\n"); + break; + case IRP_MN_QUERY_BUS_INFORMATION: + dprintf("IRP_MN_QUERY_BUS_INFORMATION\n"); + /* not in btrfs Status = pnp_query_bus_information(DeviceObject, Irp, IrpSp); */ + break; + case IRP_MN_DEVICE_ENUMERATED: + dprintf("IRP_MN_DEVICE_ENUMERATED\n"); + break; default: dprintf("Unknown IRP_MJ_PNP(disk): 0x%x\n", IrpSp->MinorFunction); + DbgBreakPoint(); break; } break; @@ -6906,7 +7162,7 @@ _Function_class_(DRIVER_DISPATCH) _Inout_ PIRP *PIrp, PIO_STACK_LOCATION IrpSp) { - NTSTATUS Status; + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; struct vnode *hold_vp = NULL; PIRP Irp = *PIrp; @@ -6974,8 +7230,6 @@ _Function_class_(DRIVER_DISPATCH) * style works out. */ - Status = STATUS_NOT_IMPLEMENTED; - switch (IrpSp->MajorFunction) { case IRP_MJ_CREATE: @@ -7072,6 +7326,22 @@ _Function_class_(DRIVER_DISPATCH) ulong_t cmd = IrpSp->Parameters.DeviceIoControl.IoControlCode; /* Not ZFS ioctl, handle Windows ones */ switch (cmd) { + + case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: + dprintf("IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n"); + Status = ioctl_query_stable_guid(DeviceObject, Irp, + IrpSp); + break; + case IOCTL_DISK_IS_WRITABLE: + dprintf("IOCTL_DISK_IS_WRITABLE\n"); + Status = STATUS_SUCCESS; + break; +#if 0 + case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: + dprintf("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n"); + Status = ioctl_query_device_name(DeviceObject, Irp, + IrpSp); + break; case IOCTL_VOLUME_GET_GPT_ATTRIBUTES: dprintf("IOCTL_VOLUME_GET_GPT_ATTRIBUTES\n"); Status = 0; @@ -7101,6 +7371,7 @@ _Function_class_(DRIVER_DISPATCH) Status = STATUS_SUCCESS; break; case IOCTL_VOLUME_OFFLINE: + case IOCTL_VOLUME_IS_OFFLINE: dprintf("IOCTL_VOLUME_OFFLINE\n"); Status = STATUS_SUCCESS; break; @@ -7175,16 +7446,24 @@ _Function_class_(DRIVER_DISPATCH) Status = ioctl_storage_query_property(DeviceObject, Irp, IrpSp); break; - +#endif case FSCTL_DISMOUNT_VOLUME: dprintf("FSCTL_DISMOUNT_VOLUME\n"); - Status = 0; + Status = STATUS_SUCCESS; break; case FSCTL_LOCK_VOLUME: dprintf("FSCTL_LOCK_VOLUME\n"); - Status = 0; + Status = STATUS_SUCCESS; + break; + case IOCTL_MOUNTDEV_LINK_DELETED: + dprintf("IOCTL_MOUNTDEV_LINK_DELETED\n"); + Status = STATUS_SUCCESS; + break; + case 0x4d0014: +// Same as IOCTL_MOUNTDEV_LINK_DELETED but bit 14,15 are 0 (access permissions) + dprintf("IOCTL_MOUNTDEV_LINK_DELETED v2\n"); + Status = STATUS_SUCCESS; break; - default: dprintf("**** unknown fsWindows IOCTL: 0x%lx\n", cmd); @@ -7202,6 +7481,9 @@ _Function_class_(DRIVER_DISPATCH) case IRP_MN_USER_FS_REQUEST: Status = user_fs_request(DeviceObject, PIrp, IrpSp); break; + case IRP_MN_VERIFY_VOLUME: + Status = STATUS_SUCCESS; + break; // FSCTL_QUERY_VOLUME_CONTAINER_STATE 0x90930 case IRP_MN_KERNEL_CALL: dprintf("IRP_MN_KERNEL_CALL: unknown 0x%lx\n", @@ -7214,48 +7496,42 @@ _Function_class_(DRIVER_DISPATCH) Status = STATUS_INVALID_DEVICE_REQUEST; } break; - case IRP_MJ_PNP: switch (IrpSp->MinorFunction) { - case IRP_MN_QUERY_CAPABILITIES: - Status = QueryCapabilities(DeviceObject, Irp, IrpSp); - break; case IRP_MN_QUERY_DEVICE_RELATIONS: - Status = STATUS_NOT_IMPLEMENTED; - - if (IrpSp->Parameters.QueryDeviceRelations.Type == - TargetDeviceRelation) { - PDEVICE_RELATIONS DeviceRelations; - DeviceRelations = - (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, - sizeof (DEVICE_RELATIONS)); - if (!DeviceRelations) { - dprintf("enomem DeviceRelations\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - break; - } - - dprintf("TargetDeviceRelations: returning %p\n", - DeviceObject); - -/* The PnP manager will remove this when it is done with device */ - ObReferenceObject(DeviceObject); - - DeviceRelations->Count = 1; - DeviceRelations->Objects[0] = DeviceObject; - Irp->IoStatus.Information = - (ULONG_PTR)DeviceRelations; - - Status = STATUS_SUCCESS; - break; - } - + Status = QueryDeviceRelations(DeviceObject, Irp, IrpSp); dprintf("DeviceRelations.Type 0x%x\n", IrpSp->Parameters.QueryDeviceRelations.Type); break; case IRP_MN_QUERY_ID: Status = pnp_query_id(DeviceObject, Irp, IrpSp); break; + // These are not implemented in btrfs, so pass down. + case IRP_MN_QUERY_INTERFACE: + dprintf("IRP_MN_QUERY_DEVICE_TEXT\n"); + break; + case IRP_MN_QUERY_DEVICE_TEXT: + dprintf("IRP_MN_QUERY_DEVICE_TEXT\n"); + break; + case IRP_MN_QUERY_BUS_INFORMATION: + dprintf("IRP_MN_QUERY_BUS_INFORMATION\n"); + break; + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + dprintf("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + break; + case IRP_MN_QUERY_RESOURCES: + dprintf("IRP_MN_QUERY_RESOURCES\n"); + break; + case IRP_MN_QUERY_CAPABILITIES: + dprintf("IRP_MN_QUERY_CAPABILITIES\n"); + break; + case IRP_MN_DEVICE_ENUMERATED: + dprintf("IRP_MN_DEVICE_ENUMERATED\n"); + break; +#if 0 + case IRP_MN_QUERY_CAPABILITIES: // x INTERFACE TEXT IRP_MN_QUERY_BUS_INFORMATION IRP_MN_QUERY_RESOURCE_REQUIREMENTS IRP_MN_QUERY_RESOURCES + Status = QueryCapabilities(DeviceObject, Irp, IrpSp); + break; case IRP_MN_QUERY_PNP_DEVICE_STATE: Status = pnp_device_state(DeviceObject, Irp, IrpSp); break; @@ -7279,17 +7555,20 @@ _Function_class_(DRIVER_DISPATCH) dprintf("IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); Status = pnp_device_usage_notification(DeviceObject, Irp, IrpSp); - break; + break; +#endif default: dprintf("Unknown IRP_MJ_PNP(fs): 0x%x\n", IrpSp->MinorFunction); + DbgBreakPoint(); break; } break; +#if 0 case IRP_MJ_QUERY_VOLUME_INFORMATION: Status = query_volume_information(DeviceObject, Irp, IrpSp); break; - +#endif case IRP_MJ_LOCK_CONTROL: xprintf("lockcontrol!\n"); Status = lock_control(DeviceObject, Irp, IrpSp); @@ -7349,6 +7628,9 @@ _Function_class_(DRIVER_DISPATCH) dprintf("IRP_MJ_SHUTDOWN\n"); Status = STATUS_SUCCESS; break; + default: + dprintf("**** unknown fsWindows IOCTL: 0x%lx\n", IrpSp->MajorFunction); + break; } /* If we held the vp above, release it now. */ @@ -7378,6 +7660,15 @@ _Function_class_(DRIVER_DISPATCH) * ALL ioctl requests come in here, and we do the Windows specific * work to handle IRPs then we sort out the type of request * (ioctl, volume, filesystem) and call each respective handler. + * Update + * Our fsDispatcher() (VDO) can get a request it would normally not + * handle, so it should pass it down using + * IoCallDriver(DeviceObject->AttachedDevice, Irp); + * This is probably our diskDispatcher() (PDO), but that is the + * standard Windows driver model. + * diskDispatcher() should also do the same. + * We use the ntstatus STATUS_INVALID_DEVICE_REQUEST to indicate + * we have not handled the request at this level. */ _Function_class_(DRIVER_DISPATCH) NTSTATUS @@ -7389,6 +7680,7 @@ _Function_class_(DRIVER_DISPATCH) BOOLEAN AtIrqlPassiveLevel = FALSE; PIO_STACK_LOCATION IrpSp; NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + mount_t *zmo = NULL; // Storport can call itself (and hence, ourselves) so this isn't // always true. @@ -7417,6 +7709,10 @@ _Function_class_(DRIVER_DISPATCH) KIRQL saveIRQL; saveIRQL = KeGetCurrentIrql(); + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); + if (DriverExtension == NULL) // Should never happen, but + return (STATUS_INVALID_DEVICE_REQUEST); AtIrqlPassiveLevel = (KeGetCurrentIrql() == PASSIVE_LEVEL); if (AtIrqlPassiveLevel) { @@ -7427,11 +7723,13 @@ _Function_class_(DRIVER_DISPATCH) TopLevel = TRUE; } - if (DeviceObject == ioctlDeviceObject) + if (DeviceObject == DriverExtension->ioctlDeviceObject) Status = ioctlDispatcher(DeviceObject, &Irp, IrpSp); else { - mount_t *zmo = DeviceObject->DeviceExtension; - if (zmo && zmo->type == MOUNT_TYPE_DCB) + zmo = DeviceObject->DeviceExtension; + if (zmo && zmo->type == MOUNT_TYPE_BUS) + Status = busDispatcher(DeviceObject, &Irp, IrpSp); + else if (zmo && zmo->type == MOUNT_TYPE_DCB) Status = diskDispatcher(DeviceObject, &Irp, IrpSp); else if (zmo && zmo->type == MOUNT_TYPE_VCB) Status = fsDispatcher(DeviceObject, &Irp, IrpSp); @@ -7453,6 +7751,7 @@ _Function_class_(DRIVER_DISPATCH) // Got a request we don't care about? Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; + zmo = NULL; } } @@ -7464,6 +7763,8 @@ _Function_class_(DRIVER_DISPATCH) } switch (Status) { + case STATUS_INVALID_DEVICE_REQUEST: + break; case STATUS_SUCCESS: case STATUS_BUFFER_OVERFLOW: break; @@ -7479,15 +7780,32 @@ _Function_class_(DRIVER_DISPATCH) // Complete the request if it isn't pending (ie, we // called zfsdev_async()) - if (Status != STATUS_PENDING && Irp != NULL) { + if ((Status == STATUS_INVALID_DEVICE_REQUEST) && + zmo != NULL && + zmo->AttachedDevice != NULL) { + dprintf("Passing request %s down\n", + major2str(IrpSp->MajorFunction, IrpSp->MinorFunction)); + + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(zmo->AttachedDevice, Irp); + dprintf("Lower Device said 0x%0x %s\n", Status, + common_status_str(Status)); + + } else if (Status != STATUS_PENDING && Irp != NULL) { // IOCTL_STORAGE_GET_HOTPLUG_INFO // IOCTL_DISK_CHECK_VERIFY // IOCTL_STORAGE_QUERY_PROPERTY + Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, Status == STATUS_SUCCESS ? IO_DISK_INCREMENT : IO_NO_INCREMENT); + } else if (Status == STATUS_PENDING && Irp == NULL) { + // If Irp is NULL, we are not to IoComplete the IRP + // as we are to wait, see FSCTL_REQUEST_OPLOCK. + } else { + DbgBreakPoint(); } VERIFY3U(saveIRQL, ==, KeGetCurrentIrql()); @@ -7607,6 +7925,7 @@ NTSTATUS pnp_query_di(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { NTSTATUS status; + if (IsEqualGUID(IrpSp->Parameters.QueryInterface.InterfaceType, &ZFSZVOLDI_GUID)) { if (IrpSp->Parameters.QueryInterface.Version < 1) @@ -7656,12 +7975,44 @@ pnp_query_di(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) else status = STATUS_NOT_FOUND; } - } + } else if (RtlCompareMemory(&IrpSp->Parameters.QueryInterface.InterfaceType, + &BtrfsBusInterface, sizeof(GUID)) == sizeof(GUID)) + status = STATUS_SUCCESS; else - status = STATUS_NOT_IMPLEMENTED; + status = STATUS_INVALID_DEVICE_REQUEST; return (status); } +DEFINE_GUID(GUID_BUS_TYPE_PCI, + 0xc8ebdfb0, 0xb510, 0x11d0, 0x80, 0xe5, 0x00, 0xa0, 0xc9, 0x25, 0x42, 0xe3); + + +NTSTATUS +pnp_query_bus_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PPNP_BUS_INFORMATION busInfo; + + // Allocate memory for the bus information structure + busInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag( + PagedPool, + sizeof(PNP_BUS_INFORMATION), + 'nIbQ' + ); + + if (busInfo == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + + // Fill in the bus information structure + busInfo->BusTypeGuid = GUID_BUS_TYPE_PCI; // Change as appropriate + busInfo->LegacyBusType = PNPBus; + busInfo->BusNumber = 0; // Change as appropriate + + // Set the bus information in the IRP + Irp->IoStatus.Information = (ULONG_PTR)busInfo; + + return (STATUS_SUCCESS); +} + NTSTATUS pnp_device_usage_notification(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) @@ -8358,8 +8709,8 @@ fastio_init(FAST_IO_DISPATCH **fast) fastio_release_file_for_ntsection; FastIoDispatch.FastIoDetachDevice = (PFAST_IO_DETACH_DEVICE) fastio_detach_device; - FastIoDispatch.FastIoQueryNetworkOpenInfo = - fastio_query_network_open_info; +// FastIoDispatch.FastIoQueryNetworkOpenInfo = +// fastio_query_network_open_info; FastIoDispatch.AcquireForModWrite = fastio_acquire_for_mod_write; FastIoDispatch.MdlRead = FsRtlMdlReadDev; FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev; @@ -8373,13 +8724,13 @@ fastio_init(FAST_IO_DISPATCH **fast) fastio_read_complete_compressed; FastIoDispatch.MdlWriteCompleteCompressed = fastio_write_complete_compressed; - FastIoDispatch.FastIoQueryOpen = fastio_query_open; +// FastIoDispatch.FastIoQueryOpen = fastio_query_open; FastIoDispatch.ReleaseForModWrite = fastio_release_for_mod_write; FastIoDispatch.AcquireForCcFlush = fastio_acquire_for_ccflush; FastIoDispatch.ReleaseForCcFlush = fastio_release_for_ccflush; *fast = &FastIoDispatch; - dprintf("Using FASTIO\n"); +// dprintf("Using FASTIO\n"); #endif // ZFS_HAVE_FASTIO } diff --git a/module/os/windows/zfs/zfs_vnops_windows_lib.c b/module/os/windows/zfs/zfs_vnops_windows_lib.c index e0259d12cd0d..ad4b25a8473f 100644 --- a/module/os/windows/zfs/zfs_vnops_windows_lib.c +++ b/module/os/windows/zfs/zfs_vnops_windows_lib.c @@ -54,7 +54,7 @@ #include #include - +#include #include #include @@ -322,6 +322,8 @@ major2str(int major, int minor) return ("IRP_MJ_PNP(IRP_MN_DEVICE_USAGE_NOTIFICATION)"); case IRP_MN_SURPRISE_REMOVAL: // SUPPLIES! return ("IRP_MJ_PNP(IRP_MN_SURPRISE_REMOVAL)"); + case 0x18: // No longer used + return ("IRP_MJ_PNP(IRP_MN_QUERY_LEGACY_BUS_INFORMATION)"); } return ("IRP_MJ_PNP"); default: @@ -380,6 +382,10 @@ common_status_str(NTSTATUS Status) return ("STATUS_DISK_QUOTA_EXCEEDED"); case STATUS_UNRECOGNIZED_VOLUME: return ("STATUS_UNRECOGNIZED_VOLUME"); + case STATUS_VOLUME_MOUNTED: + return ("STATUS_VOLUME_MOUNTED"); + case STATUS_VOLUME_DISMOUNTED: + return ("STATUS_VOLUME_DISMOUNTED"); default: return ("<*****>"); } @@ -4476,7 +4482,7 @@ file_standard_information_impl(PDEVICE_OBJECT DeviceObject, fsi->AllocationSize.QuadPart = allocationsize(zp); fsi->EndOfFile.QuadPart = vnode_isdir(vp) ? 0 : zp->z_size; - fsi->NumberOfLinks = zp->z_links; + fsi->NumberOfLinks = DIR_LINKS(zp); fsi->DeletePending = zccb && zccb->deleteonclose ? TRUE : FALSE; @@ -4694,8 +4700,8 @@ file_standard_link_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, znode_t *zp = VTOZ(vp); - fsli->NumberOfAccessibleLinks = zp->z_links; - fsli->TotalNumberOfLinks = zp->z_links; + fsli->NumberOfAccessibleLinks = DIR_LINKS(zp); + fsli->TotalNumberOfLinks = DIR_LINKS(zp); fsli->DeletePending = zccb && zccb->deleteonclose ? TRUE : FALSE; fsli->Directory = S_ISDIR(zp->z_mode); @@ -4811,7 +4817,7 @@ file_stat_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, fsi->FileAttributes = zfs_getwinflags(zp->z_pflags, vnode_isdir(vp)); fsi->ReparseTag = get_reparse_tag(zp); - fsi->NumberOfLinks = zp->z_links; + fsi->NumberOfLinks = DIR_LINKS(zp); fsi->EffectiveAccess = zccb->access; } @@ -4887,7 +4893,7 @@ file_stat_lx_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, fsli->FileAttributes = zfs_getwinflags(zp->z_pflags, vnode_isdir(vp)); fsli->ReparseTag = get_reparse_tag(zp); - fsli->NumberOfLinks = zp->z_links; + fsli->NumberOfLinks = DIR_LINKS(zp); fsli->EffectiveAccess = zccb->access; fsli->LxFlags = LX_FILE_METADATA_HAS_UID | @@ -5398,23 +5404,132 @@ NTSTATUS QueryCapabilities(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { - NTSTATUS Status; - PDEVICE_CAPABILITIES DeviceCapabilities; + NTSTATUS Status; + PDEVICE_CAPABILITIES DeviceCapabilities; DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities; + DeviceCapabilities->Version = 1; + DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES); + DeviceCapabilities->DeviceD1 = FALSE; + DeviceCapabilities->DeviceD2 = FALSE; DeviceCapabilities->SurpriseRemovalOK = TRUE; - DeviceCapabilities->LockSupported = TRUE; - DeviceCapabilities->EjectSupported = TRUE; - DeviceCapabilities->Removable = FALSE; // XX + DeviceCapabilities->LockSupported = FALSE; + DeviceCapabilities->EjectSupported = FALSE; + DeviceCapabilities->Removable = TRUE; DeviceCapabilities->DockDevice = FALSE; + DeviceCapabilities->UniqueID = FALSE; + DeviceCapabilities->SilentInstall = FALSE; + DeviceCapabilities->RawDeviceOK = FALSE; + DeviceCapabilities->SurpriseRemovalOK = FALSE; + DeviceCapabilities->WakeFromD0 = FALSE; + DeviceCapabilities->WakeFromD1 = FALSE; + DeviceCapabilities->WakeFromD2 = FALSE; + DeviceCapabilities->WakeFromD3 = FALSE; + DeviceCapabilities->HardwareDisabled = FALSE; + DeviceCapabilities->NonDynamic = FALSE; + DeviceCapabilities->WarmEjectSupported = FALSE; + DeviceCapabilities->NoDisplayInUI = FALSE; + DeviceCapabilities->Address = 0xffffffff; + DeviceCapabilities->UINumber = 0xffffffff; + DeviceCapabilities->D1Latency = DeviceCapabilities->D2Latency = DeviceCapabilities->D3Latency = 0; - DeviceCapabilities->NoDisplayInUI = 0; - Irp->IoStatus.Information = sizeof (DEVICE_CAPABILITIES); + DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; + DeviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; + DeviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; + DeviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + DeviceCapabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3; + DeviceCapabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3; + + // Irp->IoStatus.Information = sizeof (DEVICE_CAPABILITIES); return (STATUS_SUCCESS); } + +NTSTATUS +QueryDeviceRelations(PDEVICE_OBJECT DeviceObject, PIRP Irp, + PIO_STACK_LOCATION IrpSp) +{ + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + mount_t *zmo; + PDEVICE_OBJECT ReturnDevice = NULL; + PDEVICE_RELATIONS DeviceRelations; + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); + + zmo = (mount_t *)DeviceObject->DeviceExtension; + + dprintf("DeviceRelations.Type 0x%x\n", + IrpSp->Parameters.QueryDeviceRelations.Type); + + switch (IrpSp->Parameters.QueryDeviceRelations.Type) { + case TargetDeviceRelation: + { + DeviceRelations = + (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, + sizeof (DEVICE_RELATIONS)); + if (!DeviceRelations) { + dprintf("enomem DeviceRelations\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + + /* The PnP manager will remove this when it is done with device */ + mount_t *zmo_dcb = (mount_t *)zmo->parent_device; + + if (zmo->PhysicalDeviceObject != NULL) + ReturnDevice = zmo->PhysicalDeviceObject; + else if (zmo_dcb && zmo_dcb->PhysicalDeviceObject != NULL) + ReturnDevice = zmo_dcb->PhysicalDeviceObject; + else { + ReturnDevice = DeviceObject; // wrong + DbgBreakPoint(); + } + ObReferenceObject(ReturnDevice); + + DeviceRelations->Count = 1; + DeviceRelations->Objects[0] = ReturnDevice; + Irp->IoStatus.Information = + (ULONG_PTR)DeviceRelations; + + Status = STATUS_SUCCESS; + break; + } + case BusRelations: + { + DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag( + PagedPool, + sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT), + 'drvg' + ); + + DeviceRelations->Count = 0; + + ReturnDevice = DriverExtension->ChildDeviceObject; + if (ReturnDevice != NULL) { + ObReferenceObject(ReturnDevice); + DeviceRelations->Count = 1; + DeviceRelations->Objects[0] = ReturnDevice; + xprintf("Returning ChildDeviceObject %p\n", ReturnDevice); + } + Irp->IoStatus.Information = + (ULONG_PTR)DeviceRelations; + + Status = STATUS_SUCCESS; + break; + } + default: + DbgBreakPoint(); + } + +out: + dprintf("TargetDeviceRelations: returning %d: %p\n", + Status, ReturnDevice); + return (Status); +} + NTSTATUS ioctl_get_gpt_attributes(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) @@ -5467,16 +5582,16 @@ ioctl_query_device_name(PDEVICE_OBJECT DeviceObject, PIRP Irp, // Return name in MOUNTDEV_NAME PMOUNTDEV_NAME name; mount_t *zmo; - NTSTATUS Status; + ULONG OutputBufferLength; - if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < - sizeof (MOUNTDEV_NAME)) { + OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + if (OutputBufferLength < sizeof (MOUNTDEV_NAME)) { Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); return (STATUS_BUFFER_TOO_SMALL); } zmo = (mount_t *)DeviceObject->DeviceExtension; - +#if 1 /* If given a file, it must be root */ if (IrpSp->FileObject != NULL && IrpSp->FileObject->FsContext != NULL) { struct vnode *vp = IrpSp->FileObject->FsContext; @@ -5491,47 +5606,31 @@ ioctl_query_device_name(PDEVICE_OBJECT DeviceObject, PIRP Irp, } } } - +#endif name = Irp->AssociatedIrp.SystemBuffer; + ULONG requiredSize = sizeof(MOUNTDEV_NAME) + zmo->device_name.Length; - int space = IrpSp->Parameters.DeviceIoControl.OutputBufferLength - - sizeof (MOUNTDEV_NAME); -#if 1 - space = MIN(space, zmo->device_name.Length); - name->NameLength = zmo->device_name.Length; - RtlCopyMemory(name->Name, zmo->device_name.Buffer, - space + sizeof (name->Name)); - Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME) + space; - - if (space < zmo->device_name.Length - sizeof (name->Name)) - Status = STATUS_BUFFER_OVERFLOW; - else - Status = STATUS_SUCCESS; -#else - if (zmo->parent_device != NULL) { - DeviceObject = zmo->parent_device; - zmo = (mount_t *)DeviceObject->DeviceExtension; + // Check if the output buffer is large enough + if (OutputBufferLength < requiredSize) { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + Irp->IoStatus.Information = requiredSize; + return (STATUS_BUFFER_TOO_SMALL); } - space = MIN(space, zmo->device_name.Length); + // Set the length of the device name name->NameLength = zmo->device_name.Length; - RtlCopyMemory(name->Name, zmo->device_name.Buffer, - space + sizeof (name->Name)); - Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME) + space; - if (space < zmo->device_name.Length - sizeof (name->Name)) - Status = STATUS_BUFFER_OVERFLOW; - else - Status = STATUS_SUCCESS; -#endif + // Copy the device name into the buffer + RtlCopyMemory(name->Name, zmo->device_name.Buffer, zmo->device_name.Length); - ASSERT(Irp->IoStatus.Information <= - IrpSp->Parameters.DeviceIoControl.OutputBufferLength); + // Set the status and information fields + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = requiredSize; dprintf("replying with '%.*S'\n", - space + sizeof (name->Name) / sizeof (WCHAR), name->Name); + name->NameLength / sizeof (WCHAR), name->Name); - return (Status); + return (STATUS_SUCCESS); } NTSTATUS @@ -5591,6 +5690,7 @@ ioctl_disk_get_drive_geometry_ex(PDEVICE_OBJECT DeviceObject, PIRP Irp, { int error = 0; dprintf("%s: \n", __func__); + if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) { Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX); @@ -5604,23 +5704,33 @@ ioctl_disk_get_drive_geometry_ex(PDEVICE_OBJECT DeviceObject, PIRP Irp, return (STATUS_INVALID_PARAMETER); } - zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); - if (zfsvfs == NULL) - return (STATUS_INVALID_PARAMETER); - - if ((error = zfs_enter(zfsvfs, FTAG)) != 0) - return (error); // This returns EIO if fail + // DISK_GEOMETRY_EX_INTERNAL *geom = Irp->AssociatedIrp.SystemBuffer; + DISK_GEOMETRY_EX *geom = Irp->AssociatedIrp.SystemBuffer; - uint64_t refdbytes, availbytes, usedobjs, availobjs; - dmu_objset_space(zfsvfs->z_os, - &refdbytes, &availbytes, &usedobjs, &availobjs); + zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); + if (zfsvfs == NULL) { + geom->DiskSize.QuadPart = 1024 * 1024 * 1024; + geom->Geometry.BytesPerSector = 512; + geom->Geometry.MediaType = FixedMedia; + } else { + if ((error = zfs_enter(zfsvfs, FTAG)) != 0) + return (error); // This returns EIO if fail + uint64_t refdbytes, availbytes, usedobjs, availobjs; + dmu_objset_space(zfsvfs->z_os, + &refdbytes, &availbytes, &usedobjs, &availobjs); - DISK_GEOMETRY_EX_INTERNAL *geom = Irp->AssociatedIrp.SystemBuffer; - geom->DiskSize.QuadPart = availbytes + refdbytes; - geom->Geometry.BytesPerSector = 512; - geom->Geometry.MediaType = FixedMedia; + geom->DiskSize.QuadPart = availbytes + refdbytes; + geom->Geometry.BytesPerSector = 512; + geom->Geometry.MediaType = FixedMedia; // or RemovableMedia + zfs_exit(zfsvfs, FTAG); + } + geom->Geometry.Cylinders.QuadPart = 1024; + geom->Geometry.SectorsPerTrack = 63; + geom->Geometry.TracksPerCylinder = 255; + geom->Data[0] = 0; +#if 0 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= FIELD_OFFSET(DISK_GEOMETRY_EX_INTERNAL, Detection)) { geom->Partition.SizeOfPartitionInfo = sizeof (geom->Partition); @@ -5631,11 +5741,8 @@ ioctl_disk_get_drive_geometry_ex(PDEVICE_OBJECT DeviceObject, PIRP Irp, sizeof (DISK_GEOMETRY_EX_INTERNAL)) { geom->Detection.SizeOfDetectInfo = sizeof (geom->Detection); } - zfs_exit(zfsvfs, FTAG); - - Irp->IoStatus.Information = - MIN(IrpSp->Parameters.DeviceIoControl.OutputBufferLength, - sizeof (DISK_GEOMETRY_EX_INTERNAL)); +#endif + Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX); return (STATUS_SUCCESS); } @@ -5818,8 +5925,17 @@ ioctl_storage_query_property(PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG outputLength; dprintf("%s: \n", __func__); + return (STATUS_INVALID_DEVICE_REQUEST); outputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) { +// According to MSDN, an output buffer of size 0 can be used to determine if a property exists +// so this must be a success case with no data transferred + Irp->IoStatus.Information = 0; + return (STATUS_SUCCESS); + } + if (outputLength < sizeof (STORAGE_PROPERTY_QUERY)) { Irp->IoStatus.Information = sizeof (STORAGE_PROPERTY_QUERY); return (STATUS_BUFFER_TOO_SMALL); @@ -5842,7 +5958,7 @@ dprintf(" PropertyExistsQuery StorageDeviceUniqueIdProperty\n"); case StorageDeviceWriteCacheProperty: case StorageAdapterProperty: dprintf(" PropertyExistsQuery Not implemented 0x%x\n", spq->PropertyId); - status = STATUS_NOT_IMPLEMENTED; + status = STATUS_INVALID_DEVICE_REQUEST; break; case StorageDeviceAttributesProperty: dprintf(" PropertyExistsQuery StorageDeviceAttributesProperty\n"); @@ -5850,7 +5966,7 @@ dprintf(" PropertyExistsQuery StorageDeviceAttributesProperty\n"); break; default: dprintf(" PropertyExistsQuery unknown 0x%x\n", spq->PropertyId); - status = STATUS_NOT_IMPLEMENTED; + status = STATUS_INVALID_DEVICE_REQUEST; break; } // switch PropertyId break; @@ -5861,6 +5977,7 @@ dprintf(" PropertyExistsQuery unknown 0x%x\n", spq->PropertyId); switch (spq->PropertyId) { case StorageDeviceProperty: dprintf(" PropertyStandardQuery StorageDeviceProperty\n"); + Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR); if (outputLength < sizeof (STORAGE_DEVICE_DESCRIPTOR)) { @@ -5869,11 +5986,26 @@ dprintf(" PropertyStandardQuery StorageDeviceProperty\n"); } PSTORAGE_DEVICE_DESCRIPTOR storage; storage = Irp->AssociatedIrp.SystemBuffer; + storage->Version = sizeof (STORAGE_DEVICE_DESCRIPTOR); + storage->Size = sizeof (STORAGE_DEVICE_DESCRIPTOR) ; + storage->BusType = 0; + storage->CommandQueueing = 0; + storage->DeviceType = 0; + storage->DeviceTypeModifier = 0; + storage->ProductIdOffset = 0; + storage->ProductRevisionOffset = 0; + // storage->RawDeviceProperties = 0; + storage->RawPropertiesLength = 0; + storage->RemovableMedia = 0; + storage->SerialNumberOffset = 0; + storage->VendorIdOffset = 0; + Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR); + status = STATUS_SUCCESS; break; case StorageAdapterProperty: dprintf(" PropertyStandardQuery Not implemented 0x%x\n", spq->PropertyId); - status = STATUS_NOT_IMPLEMENTED; + status = STATUS_INVALID_DEVICE_REQUEST; break; case StorageDeviceAttributesProperty: dprintf(" PropertyStandardQuery StorageDeviceAttributesProperty\n"); @@ -5891,12 +6023,18 @@ dprintf(" PropertyStandardQuery StorageDeviceAttributesProperty\n"); sizeof (STORAGE_DEVICE_ATTRIBUTES_DESCRIPTOR); sdad->Attributes = STORAGE_ATTRIBUTE_BYTE_ADDRESSABLE_IO; + Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_ATTRIBUTES_DESCRIPTOR); status = STATUS_SUCCESS; break; + case StorageAccessAlignmentProperty: +dprintf(" StorageAccessAlignmentProperty Not implemented 0x%x\n", spq->PropertyId); + status = STATUS_INVALID_DEVICE_REQUEST; + break; + default: dprintf(" PropertyStandardQuery unknown 0x%x\n", spq->PropertyId); - status = STATUS_NOT_IMPLEMENTED; + status = STATUS_INVALID_DEVICE_REQUEST; break; } // switch propertyId break; @@ -5904,11 +6042,10 @@ dprintf(" PropertyStandardQuery StorageDeviceAttributesProperty\n"); default: dprintf("%s: unknown Querytype: 0x%x\n", __func__, spq->QueryType); - status = STATUS_NOT_IMPLEMENTED; + status = STATUS_INVALID_DEVICE_REQUEST; break; } - Irp->IoStatus.Information = sizeof (STORAGE_PROPERTY_QUERY); return (status); } @@ -5936,6 +6073,7 @@ ioctl_query_unique_id(PDEVICE_OBJECT DeviceObject, PIRP Irp, return (STATUS_BUFFER_TOO_SMALL); } +#if 0 RtlUnicodeToUTF8N(osname, MAXPATHLEN - 1, &len, zmo->name.Buffer, zmo->name.Length); osname[len] = 0; @@ -5959,6 +6097,34 @@ ioctl_query_unique_id(PDEVICE_OBJECT DeviceObject, PIRP Irp, Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); return (STATUS_BUFFER_OVERFLOW); } + +#else + +// RtlUnicodeToUTF8N(osname, MAXPATHLEN - 1, &len, zmo->uuid.Buffer, +// zmo->uuid.Length); +// osname[len] = 0; + + // uniqueId appears to be CHARS not WCHARS, + // so this might need correcting? + uniqueId = (PMOUNTDEV_UNIQUE_ID)Irp->AssociatedIrp.SystemBuffer; + + uniqueId->UniqueIdLength = sizeof (zmo->rawuuid); + + if (sizeof (USHORT) + uniqueId->UniqueIdLength <= bufferLength) { + RtlCopyMemory((PCHAR)uniqueId->UniqueId, zmo->rawuuid, + uniqueId->UniqueIdLength); + Irp->IoStatus.Information = + FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId[0]) + + uniqueId->UniqueIdLength; + //dprintf("replying with '%.*s'\n", + // uniqueId->UniqueIdLength, uniqueId->UniqueId); + return (STATUS_SUCCESS); + } else { + Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); + return (STATUS_BUFFER_OVERFLOW); + } +#endif + } NTSTATUS @@ -5978,13 +6144,14 @@ ioctl_query_stable_guid(PDEVICE_OBJECT DeviceObject, PIRP Irp, Irp->IoStatus.Information = sizeof (MOUNTDEV_STABLE_GUID); return (STATUS_BUFFER_TOO_SMALL); } + DbgBreakPoint(); mountGuid = (PMOUNTDEV_STABLE_GUID)Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(&mountGuid->StableGuid, sizeof (mountGuid->StableGuid)); zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); if (zfsvfs) { - uint64_t guid = dmu_objset_fsid_guid(zfsvfs->z_os); - RtlCopyMemory(&mountGuid->StableGuid, &guid, sizeof (guid)); +// uint64_t guid = dmu_objset_fsid_guid(zfsvfs->z_os); + RtlCopyMemory(&mountGuid->StableGuid, zmo->rawuuid, sizeof (zmo->rawuuid)); Irp->IoStatus.Information = sizeof (MOUNTDEV_STABLE_GUID); return (STATUS_SUCCESS); } @@ -6010,12 +6177,16 @@ ioctl_mountdev_query_suggested_link_name(PDEVICE_OBJECT DeviceObject, } // We only reply to strict driveletter mounts, not paths... - if (!zmo->justDriveLetter) - return (STATUS_NOT_FOUND); +// if (!zmo->justDriveLetter) +// return (STATUS_NOT_FOUND); + Irp->IoStatus.Information = 0; + + if (zmo->mountpoint.Buffer == NULL) + return (STATUS_OBJECT_NAME_NOT_FOUND); // If "?:" then just let windows pick drive letter if (zmo->mountpoint.Buffer[4] == L'?') - return (STATUS_NOT_FOUND); + return (STATUS_OBJECT_NAME_NOT_FOUND); // This code works, for driveletters. // The mountpoint string is "\\??\\f:" so change @@ -6044,7 +6215,7 @@ ioctl_mountdev_query_suggested_link_name(PDEVICE_OBJECT DeviceObject, return (STATUS_SUCCESS); } - Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME); + Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME) + MountPoint.Length; return (STATUS_BUFFER_OVERFLOW); } @@ -6064,7 +6235,7 @@ ioctl_mountdev_query_stable_guid(PDEVICE_OBJECT DeviceObject, PIRP Irp, Irp->IoStatus.Information = sizeof (MOUNTDEV_STABLE_GUID); return (STATUS_BUFFER_TOO_SMALL); } - +#if 0 zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); if (zfsvfs == NULL) return (STATUS_INVALID_PARAMETER); @@ -6074,7 +6245,9 @@ ioctl_mountdev_query_stable_guid(PDEVICE_OBJECT DeviceObject, PIRP Irp, // A bit naughty zfs_vfs_uuid_gen(spa_name(dmu_objset_spa(zfsvfs->z_os)), (char *)&guid->StableGuid); - +#else + memcpy(&guid->StableGuid, zmo->rawuuid, sizeof (guid->StableGuid)); +#endif Irp->IoStatus.Information = sizeof (MOUNTDEV_STABLE_GUID); return (STATUS_SUCCESS); } @@ -6196,3 +6369,33 @@ fsctl_set_zero_data(PDEVICE_OBJECT DeviceObject, PIRP Irp, return (Status); } + +NTSTATUS +volume_read(PDEVICE_OBJECT DeviceObject, PIRP Irp, + PIO_STACK_LOCATION IrpSp) +{ + dprintf("%s\n", __func__); + + uint64_t bufferLength; + void *buffer; + bufferLength = IrpSp->Parameters.Read.Length; + LARGE_INTEGER offset = IrpSp->Parameters.Read.ByteOffset; + + buffer = Irp->AssociatedIrp.SystemBuffer; + if (buffer == NULL) + buffer = MapUserBuffer(Irp); + if (buffer == NULL) { + Irp->IoStatus.Information = 0; + return (STATUS_INSUFFICIENT_RESOURCES); + } + + if (offset.QuadPart < 0 || bufferLength == 0) { + Irp->IoStatus.Information = 0; + return (STATUS_INVALID_PARAMETER); + } + + memset(buffer, 0, bufferLength); + + Irp->IoStatus.Information = bufferLength; + return (STATUS_SUCCESS); +} diff --git a/module/os/windows/zfs/zfs_vnops_windows_mount.c b/module/os/windows/zfs/zfs_vnops_windows_mount.c index b491c4ce2f6d..dbe2bfeac43d 100644 --- a/module/os/windows/zfs/zfs_vnops_windows_mount.c +++ b/module/os/windows/zfs/zfs_vnops_windows_mount.c @@ -49,6 +49,7 @@ #include #include +#include #undef _NTDDK_ @@ -62,6 +63,7 @@ uint64_t zfs_disable_removablemedia = 0; ZFS_MODULE_RAW(zfs, disable_removablemedia, zfs_disable_removablemedia, U64, ZMOD_RW, 0, "Disable Removable Media"); +extern kmem_cache_t *znode_cache; /* * Jump through the hoops needed to make a mount happen. @@ -222,6 +224,112 @@ mountmgr_get_mountpoint(PDEVICE_OBJECT mountmgr, return (STATUS_SUCCESS); } +#define MOUNTMGR_IS_DOSDEVICES(s, l) ( \ + (l) >= 26 && \ + (s)[0] == '\\' && \ + (s)[1] == 'D' && \ + (s)[2] == 'o' && \ + (s)[3] == 's' && \ + (s)[4] == 'D' && \ + (s)[5] == 'e' && \ + (s)[6] == 'v' && \ + (s)[7] == 'i' && \ + (s)[8] == 'c' && \ + (s)[9] == 'e' && \ + (s)[10] == 's' && \ + (s)[11] == '\\' && \ + (s)[12] >= 'A' && \ + (s)[12] <= 'Z' && \ + (s)[13] == ':') + +NTSTATUS +mountmgr_get_mountpoint2(PDEVICE_OBJECT mountmgr, + PUNICODE_STRING devpath, + PUNICODE_STRING symbolicname, + PUNICODE_STRING mountpoint, + BOOLEAN stop_when_found) +{ + MOUNTMGR_MOUNT_POINT point = { 0 }; + MOUNTMGR_MOUNT_POINTS points; + PMOUNTMGR_MOUNT_POINTS ppoints = NULL; + int len; + NTSTATUS Status; + int found = 0; + + ppoints = &points; + Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, + &point, sizeof (MOUNTMGR_MOUNT_POINT), ppoints, + sizeof (MOUNTMGR_MOUNT_POINTS), FALSE, NULL); + + if (Status == STATUS_BUFFER_OVERFLOW) { + len = points.Size; + ppoints = kmem_alloc(len, KM_SLEEP); + Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, + &point, sizeof (MOUNTMGR_MOUNT_POINT), + ppoints, len, FALSE, NULL); + + } + dprintf("IOCTL_MOUNTMGR_QUERY_POINTS return %lx - looking for '%wZ'\n", + Status, devpath); + if (Status == STATUS_SUCCESS) { + for (int Index = 0; + Index < ppoints->NumberOfMountPoints; + Index++) { + PMOUNTMGR_MOUNT_POINT ipoint = + ppoints->MountPoints + Index; + PWCHAR DeviceName = + (PWCHAR)((PUCHAR)ppoints + + ipoint->DeviceNameOffset); + PWCHAR SymbolicLinkName = + (PWCHAR)((PUCHAR)ppoints + + ipoint->SymbolicLinkNameOffset); + // UniqueId is a binary blob. + + // Why is this hackery needed, we should be able + // to lookup the drive letter from volume name + dprintf(" point %d: '%.*S' '%.*S'\n", Index, + (int)(ipoint->DeviceNameLength / sizeof (WCHAR)), + DeviceName, + (int)(ipoint->SymbolicLinkNameLength / + sizeof (WCHAR)), + SymbolicLinkName); + + if (wcsncmp(DeviceName, devpath->Buffer, + ipoint->DeviceNameLength / sizeof (WCHAR)) == 0) { + + if (mountpoint != NULL && + MOUNTMGR_IS_DOSDEVICES(SymbolicLinkName, ipoint->SymbolicLinkNameLength)) { + // Mountpoint + RtlUnicodeStringCbCopyStringN(mountpoint, + SymbolicLinkName, + ipoint->SymbolicLinkNameLength); + // Might as well null terminate. + mountpoint->Buffer[ + ipoint->SymbolicLinkNameLength / + sizeof (WCHAR)] = 0; + found++; + } else if (symbolicname != NULL) { + // SymbolicLinkName + RtlUnicodeStringCbCopyStringN(symbolicname, + SymbolicLinkName, + ipoint->SymbolicLinkNameLength); + // Might as well null terminate. + symbolicname->Buffer[ + ipoint->SymbolicLinkNameLength / + sizeof (WCHAR)] = 0; + found++; + } + + if (stop_when_found && found == 2) + break; + } // DeviceName match + } // for + } + + if (ppoints != NULL) kmem_free(ppoints, len); + return (STATUS_SUCCESS); +} + /* * Returns the last valid mountpoint of the device according * to MOUNTMGR_IS_DRIVE_LETTER() @@ -419,6 +527,7 @@ RegisterDeviceInterface(__in PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pnpDeviceObject = NULL; NTSTATUS status; + /* This creates the PDO - PhysicalDeviceObject */ status = IoReportDetectedDevice( DriverObject, InterfaceTypeUndefined, @@ -436,8 +545,12 @@ RegisterDeviceInterface(__in PDRIVER_OBJECT DriverObject, return (status); } - if (IoAttachDeviceToDeviceStack(pnpDeviceObject, - DeviceObject) != NULL) { + Dcb->PhysicalDeviceObject = pnpDeviceObject; + + Dcb->AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject, + pnpDeviceObject); + + if (Dcb->AttachedDevice != NULL) { dprintf(" IoAttachDeviceToDeviceStack success\n"); } else { dprintf(" IoAttachDeviceToDeviceStack failed\n"); @@ -445,19 +558,20 @@ RegisterDeviceInterface(__in PDRIVER_OBJECT DriverObject, status = IoRegisterDeviceInterface( pnpDeviceObject, - &GUID_DEVINTERFACE_DISK, +// &GUID_DEVINTERFACE_DISK, + &GUID_DEVINTERFACE_VOLUME, NULL, - &Dcb->device_name); // device_name checks out + &Dcb->deviceInterfaceName); // device_name checks out if (NT_SUCCESS(status)) { dprintf(" IoRegisterDeviceInterface success: %wZ\n", - &Dcb->device_name); + &Dcb->deviceInterfaceName); } else { dprintf(" IoRegisterDeviceInterface failed: 0x%lx\n", status); return (status); } - status = IoSetDeviceInterfaceState(&Dcb->device_name, TRUE); + status = IoSetDeviceInterfaceState(&Dcb->deviceInterfaceName, TRUE); if (NT_SUCCESS(status)) { dprintf(" IoSetDeviceInterfaceState success\n"); @@ -470,17 +584,17 @@ RegisterDeviceInterface(__in PDRIVER_OBJECT DriverObject, pnpDeviceObject, &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL, - &Dcb->fs_name); + &Dcb->fsInterfaceName); if (NT_SUCCESS(status)) { dprintf(" IoRegisterDeviceInterface success: %wZ\n", - &Dcb->fs_name); + &Dcb->fsInterfaceName); } else { dprintf(" IoRegisterDeviceInterface failed: 0x%lx\n", status); return (status); } - status = IoSetDeviceInterfaceState(&Dcb->fs_name, TRUE); + status = IoSetDeviceInterfaceState(&Dcb->fsInterfaceName, TRUE); if (NT_SUCCESS(status)) { dprintf(" IoSetDeviceInterfaceState success\n"); @@ -489,6 +603,25 @@ RegisterDeviceInterface(__in PDRIVER_OBJECT DriverObject, return (status); } +#if 0 + status = IoRegisterDeviceInterface( + pnpDeviceObject, + &GUID_DEVINTERFACE_VOLUME, + NULL, + &Dcb->volumeInterfaceName + ); + + if (!NT_SUCCESS(status)) { + dprintf("Failed to register GUID_DEVINTERFACE_VOLUME: %08x\n", status); + } + + // Enable the device interface + status = IoSetDeviceInterfaceState(&Dcb->volumeInterfaceName, TRUE); + if (!NT_SUCCESS(status)) { + KdPrint(("Failed to enable GUID_DEVINTERFACE_VOLUME: %08x\n", status)); + } +#endif + return (status); } @@ -679,6 +812,9 @@ zfs_release_mount(mount_t *zmo) FreeUnicodeString(&zmo->fs_name); FreeUnicodeString(&zmo->uuid); FreeUnicodeString(&zmo->mountpoint); + FreeUnicodeString(&zmo->deviceInterfaceName); + FreeUnicodeString(&zmo->fsInterfaceName); + FreeUnicodeString(&zmo->volumeInterfaceName); if (zmo->vpb) { zmo->vpb->DeviceObject = NULL; @@ -704,6 +840,8 @@ zfs_windows_mount(zfs_cmd_t *zc) // PDEVICE_OBJECT pdo = NULL; PDEVICE_OBJECT diskDeviceObject = NULL; // PDEVICE_OBJECT fsDeviceObject = NULL; + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); /* * We expect mountpath (zv_value) to be already sanitised, ie, Windows @@ -733,6 +871,7 @@ zfs_windows_mount(zfs_cmd_t *zc) UNICODE_STRING diskDeviceName; UNICODE_STRING fsDeviceName; UNICODE_STRING symbolicLinkTarget; + UNICODE_STRING arcLinkTarget; ANSI_STRING pants; ULONG deviceCharacteristics; @@ -742,18 +881,20 @@ zfs_windows_mount(zfs_cmd_t *zc) deviceCharacteristics |= FILE_REMOVABLE_MEDIA; snprintf(buf, sizeof (buf), "\\Device\\Volume{%s}", uuid_a); - // snprintf(buf, sizeof (buf), "\\Device\\ZFS_%s", zc->zc_name); + pants.Buffer = buf; pants.Length = strlen(buf); pants.MaximumLength = PATH_MAX; status = RtlAnsiStringToUnicodeString(&diskDeviceName, &pants, TRUE); dprintf("%s: new devstring '%wZ'\n", __func__, &diskDeviceName); +#if 1 + /* This creates the FDO - Functional Device Object */ status = IoCreateDeviceSecure(WIN_DriverObject, sizeof (mount_t), &diskDeviceName, FILE_DEVICE_DISK, - deviceCharacteristics, + deviceCharacteristics | FILE_DEVICE_IS_MOUNTED, FALSE, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R, NULL, @@ -764,11 +905,25 @@ zfs_windows_mount(zfs_cmd_t *zc) return (status); } - diskDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; +#else + status = IoCreateDevice(WIN_DriverObject, sizeof (mount_t), + NULL, FILE_DEVICE_DISK, + FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, + &diskDeviceObject); + xprintf("Created ChildDeviceObject %p\n", diskDeviceObject); +#endif + if (status != STATUS_SUCCESS) { + dprintf("IoCreateDeviceSecure returned %08lx\n", status); + return (status); + } mount_t *zmo_dcb = diskDeviceObject->DeviceExtension; + zmo_dcb->type = MOUNT_TYPE_DCB; zmo_dcb->size = sizeof (mount_t); + + zfs_vfs_uuid_gen(zc->zc_name, zmo_dcb->rawuuid); + vfs_setfsprivate(zmo_dcb, NULL); dprintf("%s: created dcb at %p asked for size %llu\n", __func__, zmo_dcb, sizeof (mount_t)); @@ -777,13 +932,20 @@ zfs_windows_mount(zfs_cmd_t *zc) // just "lower". Turns out the name in Explorer only // works for 4 chars or lower. Why? AsciiStringToUnicodeString(zc->zc_name, &zmo_dcb->name); - AsciiStringToUnicodeString(buf, &zmo_dcb->device_name); + RtlDuplicateUnicodeString(0, &diskDeviceName, &zmo_dcb->device_name); + // strlcpy(zc->zc_value, buf, sizeof (zc->zc_value)); - zmo_dcb->deviceObject = diskDeviceObject; + zmo_dcb->FunctionalDeviceObject = diskDeviceObject; + // So DeviceRelations can return it + DriverExtension->ChildDeviceObject = diskDeviceObject; + // So AddDevice can match us + DriverExtension->AddDeviceObject = diskDeviceObject; + dprintf("New device %p has extension %p\n", diskDeviceObject, zmo_dcb); snprintf(buf, sizeof (buf), "\\DosDevices\\Global\\Volume{%s}", uuid_a); + //snprintf(buf, sizeof (buf), "\\DosDevices\\Global\\E:", uuid_a); pants.Buffer = buf; pants.Length = strlen(buf); pants.MaximumLength = PATH_MAX; @@ -792,7 +954,18 @@ zfs_windows_mount(zfs_cmd_t *zc) dprintf("%s: new symlink '%wZ'\n", __func__, &symbolicLinkTarget); AsciiStringToUnicodeString(buf, &zmo_dcb->symlink_name); - snprintf(buf, sizeof (buf), "\\Device\\ZFS{%s}", uuid_a); + snprintf(buf, sizeof (buf), "\\ArcName\\OpenZFS(%s)", uuid_a); + //snprintf(buf, sizeof (buf), "\\DosDevices\\Global\\E:", uuid_a); + pants.Buffer = buf; + pants.Length = strlen(buf); + pants.MaximumLength = PATH_MAX; + status = RtlAnsiStringToUnicodeString(&arcLinkTarget, &pants, + TRUE); + dprintf("%s: new symlink '%wZ'\n", __func__, &arcLinkTarget); + AsciiStringToUnicodeString(buf, &zmo_dcb->arc_name); + + //snprintf(buf, sizeof (buf), "\\Device\\ZFS{%s}", uuid_a); + snprintf(buf, sizeof (buf), "\\??\\{%s}", uuid_a); pants.Buffer = buf; pants.Length = strlen(buf); pants.MaximumLength = PATH_MAX; @@ -801,16 +974,65 @@ zfs_windows_mount(zfs_cmd_t *zc) AsciiStringToUnicodeString(buf, &zmo_dcb->fs_name); diskDeviceObject->Flags |= DO_DIRECT_IO; + diskDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; + DbgBreakPoint(); - status = IoCreateSymbolicLink(&symbolicLinkTarget, &diskDeviceName); + // diskDeviceObject->Flags |= DO_POWER_PAGABLE; + diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - if (!NT_SUCCESS(status)) { - IoDeleteDevice(diskDeviceObject); - dprintf(" IoCreateSymbolicLink returned 0x%lx\n", status); - return (status); - } +#if 1 + // zmo_dcb->PhysicalDeviceObject = DriverExtension->PhysicalDeviceObject; +// zmo_dcb->PhysicalDeviceObject = diskDeviceObject; + // zmo_dcb->FunctionalDeviceObject = DriverExtension->FunctionalDeviceObject; + +// zmo_dcb->LowerDeviceObject = IoAttachDeviceToDeviceStack(diskDeviceObject, +// DriverExtension->PhysicalDeviceObject); + +// status = IoReportDetectedDevice( +// WIN_DriverObject, +// InterfaceTypeUndefined, +// -1, +// -1, +// NULL, +// NULL, +// FALSE, +// &WIN_PhysicalDeviceObject +// ); + +// status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, FileObject, +// drvobj, pnp_removal, pdode, &vc->notification_entry); +#if 0 + status = IoRegisterDeviceInterface( + diskDeviceObject, + &GUID_DEVINTERFACE_DISK, + NULL, + &zmo_dcb->deviceInterfaceName + ); + + status = IoSetDeviceInterfaceState(&zmo_dcb->deviceInterfaceName, TRUE); +#endif + + zmo_dcb->AttachedDevice = IoAttachDeviceToDeviceStack(diskDeviceObject, + DriverExtension->PhysicalDeviceObject); + // zmo_dcb->AttachedDevice = IoAttachDeviceToDeviceStack(diskDeviceObject, + // DriverExtension->FunctionalDeviceObject); + // zmo->VolumeDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + IoInvalidateDeviceRelations(DriverExtension->PhysicalDeviceObject, BusRelations); + +#else + status = IoReportDetectedDevice( + WIN_DriverObject, + InterfaceTypeUndefined, + -1, + -1, + NULL, + NULL, + FALSE, + &diskDeviceObject + ); +#endif // Call ZFS and have it setup a mount "zfsvfs" // we don't have the vcb yet, but we want to find out mount // problems early. @@ -824,6 +1046,13 @@ zfs_windows_mount(zfs_cmd_t *zc) if (zc->zc_cleanup_fd & MNT_RDONLY) vfs_setrdonly(zmo_dcb); +#if 0 + if (zc->zc_value[0] != 0) { + PUNICODE_STRING tmp; + tmp = &(zmo_dcb->mountpoint.Length); + AsciiStringToUnicodeString(zc->zc_value, tmp); + } +#endif // Mount will temporarily be pointing to "dcb" until the // zfs_vnop_mount() below corrects it to "vcb". status = zfs_vfs_mount(zmo_dcb, NULL, (user_addr_t)&mnt_args, NULL); @@ -834,6 +1063,27 @@ zfs_windows_mount(zfs_cmd_t *zc) return (status); } +#if 0 + status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, FileObject, + WIN_DriverObject, pnp_removal, pdode, &zmo_dcb->notification_entry); + if (!NT_SUCCESS(status)) + dprintf("IoRegisterPlugPlayNotification returned %08lx\n", status); +// #else + + status = RegisterDeviceInterface(WIN_DriverObject, + diskDeviceObject, zmo_dcb); + + status = IoCreateSymbolicLink(&symbolicLinkTarget, &diskDeviceName); + // status = IoCreateSymbolicLink(&zmo_dcb->deviceInterfaceName, &diskDeviceName); + + if (!NT_SUCCESS(status)) { + IoDeleteDevice(diskDeviceObject); + dprintf(" IoCreateSymbolicLink returned 0x%lx\n", status); + return (status); + } +#else + +#endif // Check if we are to mount with driveletter, or path // We already check that path is "\\??\\" above, and // at least 6 chars. Seventh char can be zero, or "/" @@ -847,6 +1097,9 @@ zfs_windows_mount(zfs_cmd_t *zc) } // Remember mountpoint path + // if (zmo_dcb->mountpoint.Buffer) + // FreeUnicodeString(&zmo_dcb->mountpoint); + AsciiStringToUnicodeString(zc->zc_value, &zmo_dcb->mountpoint); dprintf("%s: driveletter %d '%wZ'\n", @@ -857,8 +1110,8 @@ zfs_windows_mount(zfs_cmd_t *zc) "\\DosDevices\\Global\\Volume{%s}", uuid_a); // Mark devices as initialized - diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - ObReferenceObject(diskDeviceObject); + // diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + // ObReferenceObject(diskDeviceObject); /* * IoVerifyVolume() kicks off quite a large amount of work @@ -880,6 +1133,9 @@ zfs_windows_mount(zfs_cmd_t *zc) if (taskq_dispatch(system_taskq, io_verify_volume_impl, diskDeviceObject, TQ_SLEEP) == 0) IoVerifyVolume(diskDeviceObject, FALSE); + + // Free diskDeviceName + FreeUnicodeString(&diskDeviceName); status = STATUS_SUCCESS; return (status); @@ -1137,159 +1393,222 @@ generateVolumeNameMountpoint(wchar_t *vol_mpt) wchar_t wc_guid[50]; generateGUID(&GUID); mbstowcs(&wc_guid, GUID, 50); - _snwprintf(vol_mpt, 50, L"\\??\\Volume{%s}", wc_guid); + _snwprintf(vol_mpt, 50, L"\\??\\Volume{%s}\\", wc_guid); } - -int -zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) +NTSTATUS +CreateMountPoint(PUNICODE_STRING sourceVolumeName, PUNICODE_STRING targetVolumeName) { - PDRIVER_OBJECT DriverObject = DiskDevice->DriverObject; - PDEVICE_OBJECT volDeviceObject; NTSTATUS status; - PDEVICE_OBJECT DeviceToMount; - dprintf("%s\n", __func__); + // Calculate lengths including null terminators + ULONG sourceNameLength = sourceVolumeName->Length + sizeof(WCHAR); + ULONG targetNameLength = targetVolumeName->Length + sizeof(WCHAR); + ULONG totalLength = sizeof (MOUNTMGR_VOLUME_MOUNT_POINT) + sourceNameLength + targetNameLength; - if (IrpSp->Parameters.MountVolume.DeviceObject == NULL) { - dprintf("%s: MountVolume is NULL\n", __func__); - return (STATUS_UNRECOGNIZED_VOLUME); - } + // Allocate memory for the MOUNTMGR_VOLUME_MOUNT_POINT structure + PMOUNTMGR_VOLUME_MOUNT_POINT mountPoint = + (PMOUNTMGR_VOLUME_MOUNT_POINT)ExAllocatePoolWithTag(NonPagedPoolNx, totalLength, 'mntp'); - DeviceToMount = IoGetDeviceAttachmentBaseRef(IrpSp-> - Parameters.MountVolume.DeviceObject); - dprintf("*** mount request for %p : minor\n", DeviceToMount); + if (!mountPoint) + return (STATUS_INSUFFICIENT_RESOURCES); - if (DeviceToMount == NULL) { - dprintf("%s: DeviceToMount is NULL\n", __func__); - return (STATUS_UNRECOGNIZED_VOLUME); - } + RtlZeroMemory(mountPoint, totalLength); - // DeviceToMount must be released from here down + // Set the offsets and lengths + mountPoint->SourceVolumeNameOffset = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT); + mountPoint->SourceVolumeNameLength = sourceNameLength; + mountPoint->TargetVolumeNameOffset = mountPoint->SourceVolumeNameOffset + sourceNameLength; + mountPoint->TargetVolumeNameLength = targetNameLength; - if (DeviceToMount->DriverObject == WIN_DriverObject) { - dprintf("*** The device belong to us\n"); + // Copy the source volume name and add a null terminator + RtlCopyMemory(((PUCHAR)mountPoint) + mountPoint->SourceVolumeNameOffset, + sourceVolumeName->Buffer, sourceVolumeName->Length); + *((WCHAR*)(((PUCHAR)mountPoint) + mountPoint->SourceVolumeNameOffset + sourceVolumeName->Length)) = L'\0'; + + // Copy the target volume name and add a null terminator + RtlCopyMemory(((PUCHAR)mountPoint) + mountPoint->TargetVolumeNameOffset, + targetVolumeName->Buffer, targetVolumeName->Length); + *((WCHAR*)(((PUCHAR)mountPoint) + mountPoint->TargetVolumeNameOffset + targetVolumeName->Length)) = L'\0'; + + status = SendIoctlToMountManager( + IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED, + mountPoint, totalLength, NULL, 0); + + if (NT_SUCCESS(status)) { + dprintf(" IoCallDriver success\n"); } else { - dprintf("*** The device does NOT belong to us\n"); - status = STATUS_UNRECOGNIZED_VOLUME; - goto out; + dprintf(" IoCallDriver failed: 0x%lx\n", status); } + ExFreePoolWithTag(mountPoint, 'mntp'); + return (status); +} - mount_t *dcb = DeviceToMount->DeviceExtension; - if (dcb == NULL) { - dprintf("%s: Not a ZFS dataset -- ignoring\n", __func__); - status = STATUS_UNRECOGNIZED_VOLUME; - goto out; - } +typedef struct _MOUNTMGR_CREATE_POINT { + USHORT SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + USHORT DeviceNameOffset; + USHORT DeviceNameLength; +} MOUNTMGR_CREATE_POINT, *PMOUNTMGR_CREATE_POINT; - if ((dcb->type != MOUNT_TYPE_DCB) || - (dcb->size != sizeof (mount_t))) { - dprintf("%s: Not a ZFS dataset -- dcb %p ignoring: " - "type 0x%x != 0x%x, size %lu != %llu\n", - __func__, dcb, - dcb->type, MOUNT_TYPE_DCB, dcb->size, sizeof (mount_t)); - status = STATUS_UNRECOGNIZED_VOLUME; - goto out; - } +NTSTATUS +GPTCreateMountPoint(PUNICODE_STRING SymbolicLinkName, PUNICODE_STRING DeviceName) +{ + NTSTATUS status; + PMOUNTMGR_CREATE_POINT inputBuffer; + ULONG inputSize; - zfsvfs_t *xzfsvfs = vfs_fsprivate(dcb); + // Calculate the size of the input buffer + inputSize = sizeof(MOUNTMGR_CREATE_POINT) + + SymbolicLinkName->Length + sizeof(WCHAR) + // +sizeof(WCHAR) for NULL terminator + DeviceName->Length + sizeof(WCHAR); // +sizeof(WCHAR) for NULL terminator - if (xzfsvfs && xzfsvfs->z_unmounted) { - dprintf("%s: Is a ZFS dataset -- unmounted. dcb %p ignoring: " - "type 0x%x != 0x%x, size %lu != %llu\n", - __func__, dcb, - dcb->type, MOUNT_TYPE_DCB, dcb->size, sizeof (mount_t)); - status = STATUS_UNRECOGNIZED_VOLUME; - goto out; - } + // Allocate the input buffer + inputBuffer = (PMOUNTMGR_CREATE_POINT)ExAllocatePoolWithTag(NonPagedPoolNx, inputSize, 'mntp'); + if (!inputBuffer) + return (STATUS_INSUFFICIENT_RESOURCES); - // ZFS Dataset being mounted: - // dprintf("%s: mounting '%wZ'\n", __func__, dcb->name); + // Fill in the input buffer + inputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT); + inputBuffer->SymbolicLinkNameLength = SymbolicLinkName->Length; - // We created a DISK before, now we create a VOLUME - ULONG deviceCharacteristics; - deviceCharacteristics = 0; // FILE_DEVICE_IS_MOUNTED; - /* Allow $recycle.bin - don't set removable. */ - if (!zfs_disable_removablemedia) - deviceCharacteristics |= FILE_REMOVABLE_MEDIA; + inputBuffer->DeviceNameOffset = inputBuffer->SymbolicLinkNameOffset + SymbolicLinkName->Length + sizeof(WCHAR); + inputBuffer->DeviceNameLength = DeviceName->Length; - if (dcb->mountflags & MNT_RDONLY) - deviceCharacteristics |= FILE_READ_ONLY_DEVICE; + // Copy the symbolic link name and device name into the buffer + RtlCopyMemory(((UCHAR*)inputBuffer) + inputBuffer->SymbolicLinkNameOffset, SymbolicLinkName->Buffer, SymbolicLinkName->Length); + *((WCHAR*)(((UCHAR*)inputBuffer) + inputBuffer->SymbolicLinkNameOffset + SymbolicLinkName->Length)) = L'\0'; - status = IoCreateDevice(DriverObject, - sizeof (mount_t), - NULL, -// FILE_DEVICE_DISK, - FILE_DEVICE_DISK_FILE_SYSTEM, - deviceCharacteristics, - FALSE, - &volDeviceObject); + RtlCopyMemory(((UCHAR*)inputBuffer) + inputBuffer->DeviceNameOffset, + DeviceName->Buffer, DeviceName->Length); + *((WCHAR*)(((UCHAR*)inputBuffer) + inputBuffer->DeviceNameOffset + + DeviceName->Length)) = UNICODE_NULL; - if (!NT_SUCCESS(status)) { - dprintf("%s: IoCreateDevice failed: 0x%lx\n", __func__, status); - goto out; + status = SendIoctlToMountManager( + IOCTL_MOUNTMGR_CREATE_POINT, + inputBuffer, inputSize, NULL, 0); + + if (NT_SUCCESS(status)) { + dprintf(" IoCallDriver success\n"); + } else { + dprintf(" IoCallDriver failed: 0x%lx\n", status); } + ExFreePoolWithTag(inputBuffer, 'mntp'); + return (status); - mount_t *vcb = volDeviceObject->DeviceExtension; - vcb->type = MOUNT_TYPE_VCB; - vcb->size = sizeof (mount_t); +} - volDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; +typedef struct _MOUNTMGR_VOLUME_MOUNT_POINT_INPUT { + ULONG SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + ULONG UniqueIdOffset; + USHORT UniqueIdLength; + ULONG DeviceNameOffset; + USHORT DeviceNameLength; +} MOUNTMGR_VOLUME_MOUNT_POINT_INPUT, *PMOUNTMGR_VOLUME_MOUNT_POINT_INPUT; - zfsvfs_t *zfsvfs = vfs_fsprivate(dcb); - int giveup = 0; - while (zfsvfs == NULL) { - delay(hz / 10); - dprintf("zfsvfs not resolved yet\n"); - zfsvfs = vfs_fsprivate(dcb); - if (giveup++ > 50) - return (STATUS_UNRECOGNIZED_VOLUME); - } - zfsvfs->z_vfs = vcb; - vfs_setfsprivate(vcb, zfsvfs); - // a bit hacky this bit, but we created some vnodes under - // dcb during this mount hand over, make them be owned by - // vcb - vfs_changeowner(dcb, vcb); +NTSTATUS +MountVolumeMountPoint(PUNICODE_STRING sourceVolumeName, PUNICODE_STRING volumeMountPoint) +{ + NTSTATUS status; - // Remember the parent device, so during unmount we can free both. - vcb->parent_device = dcb; + PVOID inputBuffer = NULL; + ULONG inputBufferLength = 0; - // vcb is the ptr used in unmount, so set both devices here. - // vcb->diskDeviceObject = dcb->deviceObject; - vcb->deviceObject = volDeviceObject; + // Calculate required buffer length + inputBufferLength = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT_INPUT) + + sourceVolumeName->Length + + volumeMountPoint->Length; - RtlDuplicateUnicodeString(0, &dcb->fs_name, &vcb->fs_name); - RtlDuplicateUnicodeString(0, &dcb->name, &vcb->name); - RtlDuplicateUnicodeString(0, &dcb->device_name, &vcb->device_name); - RtlDuplicateUnicodeString(0, &dcb->symlink_name, &vcb->symlink_name); - RtlDuplicateUnicodeString(0, &dcb->uuid, &vcb->uuid); - RtlDuplicateUnicodeString(0, &dcb->mountpoint, &vcb->mountpoint); + // Allocate memory for input buffer + inputBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, inputBufferLength, 'volz'); + if (!inputBuffer) + return (STATUS_INSUFFICIENT_RESOURCES); - vcb->mountflags = dcb->mountflags; - if (vfs_isrdonly(dcb)) - vfs_setrdonly(vcb); + // Initialize input structure + PMOUNTMGR_VOLUME_MOUNT_POINT_INPUT input = (PMOUNTMGR_VOLUME_MOUNT_POINT_INPUT)inputBuffer; + RtlZeroMemory(input, sizeof(MOUNTMGR_VOLUME_MOUNT_POINT_INPUT)); - // Directory notification - InitializeListHead(&vcb->DirNotifyList); - FsRtlNotifyInitializeSync(&vcb->NotifySync); + // Setup input structure fields + input->SymbolicLinkNameLength = volumeMountPoint->Length; + input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT_INPUT); - PVPB vpb = NULL; - vpb = IrpSp->Parameters.MountVolume.Vpb; - InitVpb(vpb, volDeviceObject); - vcb->vpb = vpb; - dcb->vpb = vpb; + input->DeviceNameLength = sourceVolumeName->Length; + input->DeviceNameOffset = input->SymbolicLinkNameOffset + input->SymbolicLinkNameLength; - volDeviceObject->Flags |= DO_DIRECT_IO; - volDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - // SetLongFlag(vcb->Flags, VCB_MOUNTED); + // Copy the strings into the buffer + RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset, + volumeMountPoint->Buffer, + input->SymbolicLinkNameLength); - ObReferenceObject(volDeviceObject); + RtlCopyMemory((PCHAR)input + input->DeviceNameOffset, + sourceVolumeName->Buffer, + input->DeviceNameLength); - status = SendVolumeArrivalNotification(&dcb->device_name); - if (!NT_SUCCESS(status)) { - dprintf(" SendVolumeArrivalNotification failed: 0x%lx\n", - status); + + status = SendIoctlToMountManager( + IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED, + input, inputBufferLength, NULL, 0); + + if (NT_SUCCESS(status)) { + dprintf(" IoCallDriver success\n"); + } else { + dprintf(" IoCallDriver failed: 0x%lx\n", status); } + ExFreePoolWithTag(input, 'volz'); + return (status); +} + + +// Function to extract device name from symbolic link name +NTSTATUS +ExtractDeviceName( + PUNICODE_STRING SymbolicLinkName, + PUNICODE_STRING DeviceName +) +{ + USHORT length = 0; + USHORT i = 0; + + // Find the last backslash in the SymbolicLinkName + for (i = (SymbolicLinkName->Length / sizeof(WCHAR))-1; i >= 0; i--) { + if (SymbolicLinkName->Buffer[i] == L'\\') { + break; + } + } + + // Calculate the length of the DeviceName + length = (SymbolicLinkName->Length / sizeof(WCHAR)) - i; + + // Ensure the DeviceName buffer is large enough + if (length * sizeof(WCHAR) > DeviceName->MaximumLength) + return (STATUS_BUFFER_TOO_SMALL); + + // Copy the DeviceName from the SymbolicLinkName + RtlCopyMemory(DeviceName->Buffer, &SymbolicLinkName->Buffer[i], length * sizeof(WCHAR)); + + // Set the length and maximum length + DeviceName->Length = length * sizeof(WCHAR); + DeviceName->Buffer[length] = UNICODE_NULL; // Null-terminate the string + + return (STATUS_SUCCESS); +} + + +static void +mount_volume_impl(void *arg1) +{ + NTSTATUS status; + mount_t *vcb = (mount_t *)arg1; + mount_t *dcb = vcb->parent_device; + + DbgBreakPoint(); + + dprintf("MOUNT starts here\n"); +// status = SendVolumeArrivalNotification(&dcb->device_name); +// if (!NT_SUCCESS(status)) { +// dprintf(" SendVolumeArrivalNotification failed: 0x%lx\n", +// status); +// } UNICODE_STRING name; PFILE_OBJECT fileObject; @@ -1297,15 +1616,26 @@ zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) // Query MntMgr for points, just informative RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME); - status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, - &fileObject, &mountmgr); + DECLARE_UNICODE_STRING_SIZE(symbolicname, PATH_MAX); DECLARE_UNICODE_STRING_SIZE(mountpath, PATH_MAX); - status = mountmgr_get_drive_letter(mountmgr, &dcb->device_name, - &mountpath); + /* + * So MountMgr assigns a SymbolicLinkName for our device + * which we need to use when talking to MountMgr. We also + * want to know if it was already assigned a driverletter + */ +// mountmgr_get_mountpoint2(mountmgr, &dcb->device_name, +// &symbolicname, &mountpath, +// TRUE); // Check if we are to mount as path or just drive letter if (dcb->justDriveLetter) { + status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, + &fileObject, &mountmgr); + status = mountmgr_get_drive_letter(mountmgr, &dcb->device_name, + &mountpath); + ObDereferenceObject(fileObject); + // If SendVolumeArrival was executed successfully we should // have two mountpoints // point 1: \Device\Volumes{abc} \DosDevices\X: @@ -1317,8 +1647,13 @@ zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) if (!MOUNTMGR_IS_DRIVE_LETTER(&mountpath)) { DECLARE_UNICODE_STRING_SIZE(mountpoint, PATH_MAX); + status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, + &fileObject, &mountmgr); + status = mountmgr_get_volume_name_mountpoint(mountmgr, &dcb->device_name, &mountpoint); + ObDereferenceObject(fileObject); + if (!MOUNTMGR_IS_VOLUME_NAME(&mountpoint)) { // We have no volume name mountpoint for our // device, so generate a valid GUID and mount @@ -1338,16 +1673,23 @@ zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) dcb->mountpoint.Buffer[4] != '?') { // check if driveletter is unassigned BOOLEAN ret; + status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, + &fileObject, &mountmgr); + status = mountmgr_is_driveletter_assigned( mountmgr, dcb->mountpoint.Buffer[4], &ret); + ObDereferenceObject(fileObject); if (status == STATUS_SUCCESS && ret == 0) { // driveletter is unassigned, try to // add mountpoint + status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, + &fileObject, &mountmgr); status = mountmgr_assign_driveletter( &dcb->device_name, dcb->mountpoint.Buffer[4]); + ObDereferenceObject(fileObject); } else { // driveletter already assigned, // find another one @@ -1367,6 +1709,9 @@ zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) FreeUnicodeString(&dcb->mountpoint); RtlDuplicateUnicodeString(0, &mountpath, &dcb->mountpoint); + + + } } else { OBJECT_ATTRIBUTES poa; @@ -1374,16 +1719,48 @@ zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) DECLARE_UNICODE_STRING_SIZE(volStr, ZFS_MAX_DATASET_NAME_LEN); // "\??\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277}" + status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, + &fileObject, &mountmgr); + mountmgr_get_mountpoint2(mountmgr, &dcb->device_name, + &symbolicname, &mountpath, + TRUE); + ObDereferenceObject(fileObject); + + DECLARE_UNICODE_STRING_SIZE(mountmgr_device_name, + ZFS_MAX_DATASET_NAME_LEN); + // ExtractDeviceName(&symbolicname, &mountmgr_device_name); + ExtractDeviceName(&dcb->device_name, &mountmgr_device_name); + + + // We need to query the SymbolicName from MountMgr +// mountmgr_get_mountpoint(mountmgr, &dcb->device_name, &mountpath, +// FALSE, TRUE); + // mountpath="\??\Volume{df46d372-2857-11ef-82bd-58961d57db67}" + +// RtlUnicodeStringPrintf(&volStr, +// L"\\??\\Volume{%wZ}\\", +// vcb->uuid); + + // Annoyingly, the reparsepoints need trailing backslash RtlUnicodeStringPrintf(&volStr, - L"\\??\\Volume{%wZ}", - vcb->uuid); + L"%wZ\\", + &symbolicname); + UNICODE_STRING mountpoint; + RtlInitUnicodeString(&mountpoint, L"\\??\\E:\\dataset"); InitializeObjectAttributes(&poa, - &dcb->mountpoint, OBJ_KERNEL_HANDLE, NULL, NULL); + &mountpoint, OBJ_KERNEL_HANDLE, NULL, NULL); + // &dcb->mountpoint, OBJ_KERNEL_HANDLE, NULL, NULL); dprintf("Creating reparse mountpoint on '%wZ' for " "volume '%wZ'\n", &dcb->mountpoint, &volStr); // 3rd arg is visible in DOS box - CreateReparsePoint(&poa, &volStr, &vcb->name); + // if (taskq_dispatch(system_taskq, io_verify_volume_impl, + // diskDeviceObject, TQ_SLEEP) == 0) + //IoVerifyVolume(diskDeviceObject, FALSE); + + status = CreateReparsePoint(&poa, &volStr, + &volStr); + // &dcb->name); // Remove drive letter? // RtlUnicodeStringPrintf(&volStr, L"\\DosDevices\\E:"); @@ -1397,32 +1774,363 @@ zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) DECLARE_UNICODE_STRING_SIZE(mpoint, 128); status = RtlUnicodeStringPrintf( - &mpoint, L"\\DosDevices\\%ws", + &mpoint, L"\\DosDevices\\%ws", // name contains backslash &dcb->mountpoint.Buffer[4]); + UNICODE_STRING roger; + RtlInitUnicodeString(&roger, L"\\DosDevices\\E:\\dataset"); + DbgBreakPoint(); status = - SendVolumeCreatePointX( - &dcb->device_name, &mpoint); + GPTCreateMountPoint( + &roger, &dcb->device_name); + // &roger, &mountmgr_device_name); +// status = CreateMountPoint(&volStr, &roger); + //status = CreateMountPoint(&dcb->device_name, &roger); // mpoint + + // status = MountVolumeMountPoint(&volStr, &mpoint); + DECLARE_UNICODE_STRING_SIZE(withslash, 128); + status = RtlUnicodeStringPrintf( + &withslash, L"%wZ\\", // name contains backslash + &dcb->device_name); + // status = MountVolumeMountPoint(&withslash, &roger); + // status = MountVolumeMountPoint(&mountmgr_device_name, &roger); + status = MountVolumeMountPoint(&dcb->device_name, &roger); + + // = SendVolumeArrivalNotification(&dcb->device_name); + // status = SendVolumeArrivalNotification(&symbolicname); + // status = SendVolumeArrivalNotification(&roger); + + + status = STATUS_SUCCESS; } - // match IoGetDeviceAttachmentBaseRef() + RtlDuplicateUnicodeString(0, &dcb->mountpoint, &vcb->mountpoint); + + status = SendVolumeArrivalNotification(&dcb->device_name); + if (!NT_SUCCESS(status)) { + dprintf(" SendVolumeArrivalNotification failed: 0x%lx\n", + status); + } + + if (dcb->root_file) + status = FsRtlNotifyVolumeEvent(dcb->root_file, FSRTL_VOLUME_MOUNT); + + status = STATUS_SUCCESS; + + dprintf("Printing final result\n"); + status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, + &fileObject, &mountmgr); + mountmgr_get_mountpoint2(mountmgr, &dcb->device_name, + NULL, NULL, TRUE); ObDereferenceObject(fileObject); +} +NTSTATUS +matched_mount(PDEVICE_OBJECT DeviceObject, PDEVICE_OBJECT DeviceToMount, mount_t *dcb, PVPB vpb) +{ + zfsvfs_t *xzfsvfs = vfs_fsprivate(dcb); + NTSTATUS status; + PDEVICE_OBJECT volDeviceObject; - // It seems likely we should announce our new filesystem, but when - // we do it stops working in explorer with "invalid function". - // But if we can set this, we can't call - // FSRTL_VOLUME_MOUNT below it, and more importantly, - // FSRTL_VOLUME_DISMOUNT - // before we umount. Need to figure out why. + if (xzfsvfs && xzfsvfs->z_unmounted) { + dprintf("%s: Is a ZFS dataset -- unmounted. dcb %p ignoring: " + "type 0x%x != 0x%x, size %lu != %llu\n", + __func__, dcb, + dcb->type, MOUNT_TYPE_DCB, dcb->size, sizeof (mount_t)); + return (STATUS_UNRECOGNIZED_VOLUME); + } + + xprintf("%s\n", __func__); + + // ZFS Dataset being mounted: + // dprintf("%s: mounting '%wZ'\n", __func__, dcb->name); + + // We created a DISK before, now we create a VOLUME + ULONG deviceCharacteristics; + deviceCharacteristics = 0; // FILE_DEVICE_IS_MOUNTED; + /* Allow $recycle.bin - don't set removable. */ + if (!zfs_disable_removablemedia) + deviceCharacteristics |= FILE_REMOVABLE_MEDIA; + + if (dcb->mountflags & MNT_RDONLY) + deviceCharacteristics |= FILE_READ_ONLY_DEVICE; + DbgBreakPoint(); + /* This creates the VDO - VolumeDeviceObject */ + status = IoCreateDevice(WIN_DriverObject, + sizeof (mount_t), + NULL, +// FILE_DEVICE_DISK, + FILE_DEVICE_DISK_FILE_SYSTEM, + deviceCharacteristics|FILE_DEVICE_IS_MOUNTED, + FALSE, + &volDeviceObject); + + if (!NT_SUCCESS(status)) { + dprintf("%s: IoCreateDevice failed: 0x%lx\n", __func__, status); + } + + mount_t *vcb = volDeviceObject->DeviceExtension; + vcb->type = MOUNT_TYPE_VCB; + vcb->size = sizeof (mount_t); + + volDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; + + zfsvfs_t *zfsvfs = vfs_fsprivate(dcb); + int giveup = 0; + while (zfsvfs == NULL) { + delay(hz / 10); + dprintf("zfsvfs not resolved yet\n"); + zfsvfs = vfs_fsprivate(dcb); + if (giveup++ > 50) { + status = STATUS_UNRECOGNIZED_VOLUME; + goto out; + } + } + zfsvfs->z_vfs = vcb; + vfs_setfsprivate(vcb, zfsvfs); + // a bit hacky this bit, but we created some vnodes under + // dcb during this mount hand over, make them be owned by + // vcb + vfs_changeowner(dcb, vcb); + + // Remember the parent device, so during unmount we can free both. + vcb->parent_device = dcb; + + // vcb is the ptr used in unmount, so set both devices here. + // vcb->diskDeviceObject = dcb->deviceObject; + vcb->VolumeDeviceObject = volDeviceObject; + + RtlDuplicateUnicodeString(0, &dcb->fs_name, &vcb->fs_name); + RtlDuplicateUnicodeString(0, &dcb->name, &vcb->name); + RtlDuplicateUnicodeString(0, &dcb->device_name, &vcb->device_name); + RtlDuplicateUnicodeString(0, &dcb->symlink_name, &vcb->symlink_name); + RtlDuplicateUnicodeString(0, &dcb->uuid, &vcb->uuid); +// RtlDuplicateUnicodeString(0, &dcb->mountpoint, &vcb->mountpoint); + + vcb->mountflags = dcb->mountflags; + if (vfs_isrdonly(dcb)) + vfs_setrdonly(vcb); + + // Directory notification + InitializeListHead(&vcb->DirNotifyList); + FsRtlNotifyInitializeSync(&vcb->NotifySync); + + DbgBreakPoint(); + + dcb->root_file = IoCreateStreamFileObject(NULL, DeviceToMount); + if (dcb->root_file != NULL) { + struct vnode *vp; + struct znode *zp; + zfs_ccb_t *zccb; + + dcb->root_file->Vpb = vpb; + vnode_create(dcb, NULL, NULL, VDIR, VNODE_MARKROOT, &vp); + dcb->root_file->FsContext = vp; + vnode_ref(vp); + vnode_couplefileobject(vp, dcb->root_file, 0); + zp = kmem_cache_alloc(znode_cache, KM_SLEEP); + zp->z_vnode = vp; + vp->v_data = zp; + zccb = kmem_zalloc(sizeof (zfs_ccb_t), KM_SLEEP); + zccb->magic = ZFS_CCB_MAGIC; + dcb->root_file->FsContext2 = zccb; + zccb->z_name_len = 2; + zccb->z_name_cache = kmem_zalloc(zccb->z_name_len, KM_SLEEP); + zccb->z_name_cache[0] = '/'; + zccb->z_name_cache[1] = 0; + zccb->z_name_offset = 0; + } + + KIRQL OldIrql; + IoAcquireVpbSpinLock(&OldIrql); + InitVpb(vpb, volDeviceObject); + vcb->vpb = vpb; + vpb->ReferenceCount++; + vpb->ReferenceCount++; + vpb->ReferenceCount++; + vpb->ReferenceCount+=50; + xprintf("%p ReferenceCount is %d\n", vpb, vpb->ReferenceCount); + // dcb->vpb = vpb; +// vpb->ReferenceCount++; + IoReleaseVpbSpinLock(OldIrql); + + + volDeviceObject->Flags |= DO_DIRECT_IO; + volDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + // SetLongFlag(vcb->Flags, VCB_MOUNTED); + +#if 1 + PDEVICE_OBJECT attachedDevice; + attachedDevice = IoAttachDeviceToDeviceStack(volDeviceObject, + DeviceObject); // DeviceToMount); + if (attachedDevice == NULL) { + IoDeleteDevice(volDeviceObject); + status = STATUS_UNSUCCESSFUL; + goto out; + } + vcb->AttachedDevice = attachedDevice; + +#endif + + // ObReferenceObject(volDeviceObject); + + status = STATUS_SUCCESS; + +// if (NT_SUCCESS(status)) +// /* Sort out the mountpoint names */ +// taskq_dispatch(system_taskq, mount_volume_impl, +// vcb, TQ_SLEEP); + + out: + return (status); +} + +static void *fudgeptr = NULL; + +int +zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PDRIVER_OBJECT DriverObject = DiskDevice->DriverObject; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_OBJECT DeviceToMount; + + if (IrpSp->Parameters.MountVolume.DeviceObject == NULL) { + dprintf("%s: MountVolume is NULL\n", __func__); + return (STATUS_UNRECOGNIZED_VOLUME); + } + + DbgBreakPoint(); + + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); + if (DriverExtension == NULL) // Should never happen, but + return (STATUS_INVALID_DEVICE_REQUEST); + + // The "/OpenZFS" FILE_DEVICE_DISK_FILE_SYSTEM "masterobj" + if (DiskDevice != DriverExtension->fsDiskDeviceObject) + return (STATUS_INVALID_DEVICE_REQUEST); + + DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject; + if (DeviceToMount->DeviceType != FILE_DEVICE_DISK) { + // Not a disk device, pass it down + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceToMount, Irp); + } + + // DeviceToMount must be released from here down + mount_t *dcb = NULL; + dcb = DeviceToMount->DeviceExtension; + dcb = fudgeptr; + + PDEVICE_OBJECT d2m2; + d2m2 = IoGetDeviceAttachmentBaseRef(IrpSp-> + Parameters.MountVolume.DeviceObject); -out: ObDereferenceObject(DeviceToMount); + + if (dcb == NULL) + return (STATUS_UNRECOGNIZED_VOLUME); + + status = matched_mount(IrpSp->Parameters.MountVolume.DeviceObject, + DeviceToMount, + dcb, IrpSp->Parameters.MountVolume.Vpb); + return (status); + + + + DeviceToMount = IoGetDeviceAttachmentBaseRef(IrpSp-> + Parameters.MountVolume.DeviceObject); + dprintf("*** mount request for %p : minor\n", DeviceToMount); + + if (DeviceToMount == NULL) { + dprintf("%s: DeviceToMount is NULL\n", __func__); + return (STATUS_UNRECOGNIZED_VOLUME); + } + + if (DeviceToMount->DriverObject == WIN_DriverObject) { + dprintf("*** The device belong to us\n"); + dcb = DeviceToMount->DeviceExtension; + } else { + dprintf("*** The device does NOT belong to us\n"); + status = STATUS_UNRECOGNIZED_VOLUME; +// goto out; + } + + // If it comes from "\Driver\PnpManager" + if (DeviceToMount->AttachedDevice != NULL && + DeviceToMount->AttachedDevice->DriverObject == WIN_DriverObject) { + dprintf("*** The device belong to us after all\n"); + dcb = DeviceToMount->AttachedDevice->DeviceExtension; + status = 0; + } + + if (dcb == NULL) { + dprintf("%s: Not a ZFS dataset -- ignoring\n", __func__); + status = STATUS_UNRECOGNIZED_VOLUME; + goto out; + } + + if ((dcb->type != MOUNT_TYPE_DCB) || + (dcb->size != sizeof (mount_t))) { + dprintf("%s: Not a ZFS dataset -- dcb %p ignoring: " + "type 0x%x != 0x%x, size %lu != %llu\n", + __func__, dcb, + dcb->type, MOUNT_TYPE_DCB, dcb->size, sizeof (mount_t)); + status = STATUS_UNRECOGNIZED_VOLUME; + goto out; + } + + status = matched_mount(IrpSp->Parameters.MountVolume.DeviceObject, + DeviceToMount, + dcb, IrpSp->Parameters.MountVolume.Vpb); + + out: + // match IoGetDeviceAttachmentBaseRef() + ObDereferenceObject(DeviceToMount); + dprintf("%s: exit: 0x%lx\n", __func__, status); return (status); } +void +mount_add_device(PDEVICE_OBJECT DriverObject, + PDEVICE_OBJECT PhysicalDeviceObject, PDEVICE_OBJECT AddDeviceObject) +{ + NTSTATUS status; + mount_t *zmo = (mount_t *)AddDeviceObject->DeviceExtension; + + xprintf("%s\n", __func__); + DbgBreakPoint(); + + // status = IoCreateDevice(DriverObject, sizeof(mount_t), + // &zmo->device_name, FILE_DEVICE_DISK, + // 0, FALSE, &zmo->VolumeDeviceObject); + + zmo->PhysicalDeviceObject = PhysicalDeviceObject; + + status = IoCreateSymbolicLink(&zmo->symlink_name, &zmo->device_name); + status = IoCreateSymbolicLink(&zmo->arc_name, &zmo->device_name); + + status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, + &zmo->deviceInterfaceName); +// status = IoRegisterDeviceInterface( +// PhysicalDeviceObject, +// &MOUNTDEV_MOUNTED_DEVICE_GUID, +// NULL, +// &zmo->fsInterfaceName); + + zmo->AttachedDevice = IoAttachDeviceToDeviceStack(AddDeviceObject, PhysicalDeviceObject); + + // zmo->VolumeDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + // status = IoSetDeviceInterfaceState(&zmo->deviceInterfaceName, TRUE); + status = IoSetDeviceInterfaceState(&zmo->fsInterfaceName, TRUE); + xprintf("FILE_DEVICE_DISK PhysicalDeviceObject %p = zmo %p\n", + PhysicalDeviceObject, zmo); + fudgeptr = zmo; +} + int zfs_remove_driveletter(mount_t *zmo) { @@ -1521,12 +2229,12 @@ zfs_windows_unmount(zfs_cmd_t *zc) // Try issuing DISMOUNT ... this wont work unless // "attached" in RegisterDeviceInterface() - FILE_OBJECT *root_file; - root_file = IoCreateStreamFileObject(NULL, - zmo->deviceObject); - ntstatus = FsRtlNotifyVolumeEvent(root_file, +// FILE_OBJECT *root_file; +// root_file = IoCreateStreamFileObject(NULL, +// zmo->VolumeDeviceObject); + ntstatus = FsRtlNotifyVolumeEvent(zmo->root_file, FSRTL_VOLUME_DISMOUNT); - ObDereferenceObject(root_file); +// ObDereferenceObject(root_file); UNICODE_STRING name; PFILE_OBJECT fileObject; @@ -1582,7 +2290,7 @@ zfs_windows_unmount(zfs_cmd_t *zc) KIRQL irql; IoAcquireVpbSpinLock(&irql); zmo->vpb->Flags &= ~VPB_MOUNTED; - zmo_dcb->vpb->Flags &= ~VPB_MOUNTED; + // zmo_dcb->vpb->Flags &= ~VPB_MOUNTED; zmo->vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; zmo->vpb->DeviceObject = NULL; IoReleaseVpbSpinLock(irql); @@ -1609,27 +2317,59 @@ zfs_windows_unmount(zfs_cmd_t *zc) // Release devices IoDeleteSymbolicLink(&zmo->symlink_name); + RtlFreeUnicodeString(&zmo->symlink_name); - // fsDeviceObject - if (zmo->deviceObject) { - // For some reason IODetachDevice can cause BSOD - // IoDetachDevice(zmo->deviceObject); - IoDeleteDevice(zmo->deviceObject); + DbgBreakPoint(); + + if (zmo->root_file) { + struct vnode *vp = zmo->root_file->FsContext; + if (vp) { + kmem_cache_free(znode_cache, VTOZ(vp)); + vnode_rele(vp); + vnode_decouplefileobject(zmo->root_file->FsContext, zmo->root_file); + vnode_recycle(vp); + } + zfs_ccb_t *zccb = zmo->root_file->FsContext2; + if (zccb) { + if (zccb->z_name_cache != NULL) + kmem_free(zccb->z_name_cache, zccb->z_name_len); + kmem_free(zccb, sizeof (zfs_ccb_t)); + } + + ObDereferenceObject(zmo->root_file); + zmo->root_file = NULL; } - // diskDeviceObject - if (zmo->diskDeviceObject) - IoDeleteDevice(zmo->diskDeviceObject); + // zmo has Volume, and Attached + IoSetDeviceInterfaceState(&zmo_dcb->volumeInterfaceName, FALSE); + IoSetDeviceInterfaceState(&zmo_dcb->fsInterfaceName, FALSE); + IoSetDeviceInterfaceState(&zmo_dcb->deviceInterfaceName, FALSE); + IoDetachDevice(zmo->AttachedDevice); + zmo->AttachedDevice = NULL; + + // fsDeviceObject + if (zmo->VolumeDeviceObject) { + IoDeleteDevice(zmo->VolumeDeviceObject); + zmo->VolumeDeviceObject = NULL; + } zfs_release_mount(zmo); + zmo = NULL; + // dcb has physical and functional // There should also be a diskDevice above us to release. if (zmo_dcb != NULL) { - if (zmo_dcb->deviceObject) - IoDeleteDevice(zmo_dcb->deviceObject); - if (zmo_dcb->diskDeviceObject) - IoDeleteDevice(zmo_dcb->diskDeviceObject); + if (zmo_dcb->PhysicalDeviceObject) + IoDeleteDevice(zmo_dcb->PhysicalDeviceObject); + zmo_dcb->PhysicalDeviceObject = NULL; + + if (zmo_dcb->FunctionalDeviceObject) { + IoDetachDevice(zmo_dcb->AttachedDevice); + IoDeleteDevice(zmo_dcb->FunctionalDeviceObject); + } + zmo_dcb->FunctionalDeviceObject = NULL; zfs_release_mount(zmo_dcb); + zmo_dcb = NULL; } diff --git a/module/os/windows/zfs/zfs_windows_zvol_scsi.c b/module/os/windows/zfs/zfs_windows_zvol_scsi.c index 5c5fbfa8508c..8b306f89d183 100644 --- a/module/os/windows/zfs/zfs_windows_zvol_scsi.c +++ b/module/os/windows/zfs/zfs_windows_zvol_scsi.c @@ -57,6 +57,7 @@ #include #include #include +#include /* * We have a list of ZVOLs, and we receive incoming (Target, Lun) @@ -1104,10 +1105,11 @@ DiReadWriteSetup(zvol_state_t *zv, MpWkRtnAction action, zfsiodesc_t *pIo) * we do not want to slow down the caller so perform taskq queuing * always in the workitem. */ - extern PDEVICE_OBJECT ioctlDeviceObject; + OpenZFS_Driver_Extension *DriverExtension = + (OpenZFS_Driver_Extension *)IoGetDriverObjectExtension(WIN_DriverObject, WIN_DriverObject); PIO_WORKITEM pWI = (PIO_WORKITEM)ALIGN_UP_POINTER_BY( pWkRtnParms->pQueueWorkItem, 16); - IoInitializeWorkItem(ioctlDeviceObject, pWI); + IoInitializeWorkItem(DriverExtension->ioctlDeviceObject, pWI); IoQueueWorkItem(pWI, (PIO_WORKITEM_ROUTINE)bzvol_TaskQueuingWkRtn, DelayedWorkQueue, pWkRtnParms); return (STATUS_PENDING); // queued up. diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c index 54aa60259ea1..09f183d5fe39 100644 --- a/module/zfs/dmu_recv.c +++ b/module/zfs/dmu_recv.c @@ -2853,6 +2853,11 @@ receive_read_record(dmu_recv_cookie_t *drc) { struct drr_write *drrw = &drc->drc_rrd->header.drr_u.drr_write; int size = DRR_WRITE_PAYLOAD_SIZE(drrw); + if (size == 0) + return (SET_ERROR(EINVAL)); + if (size == 0) + return (receive_read_payload_and_next_header(drc, 0, + NULL)); abd_t *abd = abd_alloc_linear(size, B_FALSE); err = receive_read_payload_and_next_header(drc, size, abd_to_buf(abd)); diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c index ba28aa06a91f..d833bc6b640a 100644 --- a/module/zfs/dnode.c +++ b/module/zfs/dnode.c @@ -716,9 +716,9 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs, ibs = MIN(MAX(ibs, DN_MIN_INDBLKSHIFT), DN_MAX_INDBLKSHIFT); - dprintf("os=%p obj=%llu txg=%llu blocksize=%d ibs=%d dn_slots=%d\n", - dn->dn_objset, (u_longlong_t)dn->dn_object, - (u_longlong_t)tx->tx_txg, blocksize, ibs, dn_slots); + // dprintf("os=%p obj=%llu txg=%llu blocksize=%d ibs=%d dn_slots=%d\n", + // dn->dn_objset, (u_longlong_t)dn->dn_object, + // (u_longlong_t)tx->tx_txg, blocksize, ibs, dn_slots); DNODE_STAT_BUMP(dnode_allocate); ASSERT(dn->dn_type == DMU_OT_NONE); @@ -1856,8 +1856,8 @@ dnode_setdirty(dnode_t *dn, dmu_tx_t *tx) ASSERT0(dn->dn_next_blksz[txg & TXG_MASK]); ASSERT0(dn->dn_next_bonustype[txg & TXG_MASK]); - dprintf_ds(os->os_dsl_dataset, "obj=%llu txg=%llu\n", - (u_longlong_t)dn->dn_object, (u_longlong_t)txg); + //dprintf_ds(os->os_dsl_dataset, "obj=%llu txg=%llu\n", + // (u_longlong_t)dn->dn_object, (u_longlong_t)txg); multilist_sublist_insert_head(mls, dn);