Reworking the mount and unmount code.
lundman opened this issue · 29 comments
Re-writing the mount/unmount code, both to try to get it more correct, and further understanding.
Now when we start a mount request, we go through the steps:
Create my new (sub)device; called PDO - PhysicalDeviceObject.
"\Device\Volume{3fe4a1af-988f-3c6a-93c0-6c75d96902db}"
status = IoCreateDeviceSecure(WIN_DriverObject,
sizeof (mount_t),
&diskDeviceName,
FILE_DEVICE_DISK,
deviceCharacteristics,
FALSE,
&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R,
NULL,
&diskDeviceObject);
status = IoReportDetectedDevice(
DriverObject,
InterfaceTypeUndefined,
0xFFFFFFFF, // 0
0xFFFFFFFF, // 0
NULL,
NULL,
FALSE,
&pnpDeviceObject);
IoAttachDeviceToDeviceStack(DeviceObject,
pnpDeviceObject);
status = IoRegisterDeviceInterface(
pnpDeviceObject,
&GUID_DEVINTERFACE_DISK,
NULL,
&deviceInterfaceName);
status = IoSetDeviceInterfaceState(&deviceInterfaceName, TRUE);
status = IoRegisterDeviceInterface(
pnpDeviceObject,
&MOUNTDEV_MOUNTED_DEVICE_GUID,
NULL,
&fsInterfaceName);
status = IoSetDeviceInterfaceState(&fsInterfaceName, TRUE);
status = IoCreateSymbolicLink(&symbolicLinkTarget, &diskDeviceName);
IoVerifyVolume(diskDeviceObject, FALSE);
Next up, we wait to receive the IRP_MN_MOUNT_VOLUME
when we get it:
Create the VDO - Volume Device Object.
status = IoCreateDevice(DriverObject,
sizeof (mount_t),
NULL,
FILE_DEVICE_DISK_FILE_SYSTEM,
deviceCharacteristics,
FALSE,
&volDeviceObject);
attachedDevice = IoAttachDeviceToDeviceStack(volDeviceObject, DeviceToMount);
Vpb work, set MOUNTED, set DeviceObject, ReferenceCount++.
At this point we can start talking to mountmgr to arrange the Volume driveletter, or the reparsepoint.
I have rewritten the code so that PDO and VDO are more separated, ie, the diskDispatcher() and fsDispatcher() code. When a IRP_MJ is not handled, we now pass it "down" with:
IoCallDriver(DeviceObject->AttachedDevice, Irp);
So an IRP received by the VDO, if not recognised, will pass it down which for us is the PDO. If that does not recognise it, it will pass it further down. (pnpmanager it seems). This appears to be the model that Windows uses. Not everyone bothers, but I am in too deep, so let's explore it fully.
Testing against vhd mounted on F:
(NTFS) and a second mounted on F:\dataset
,
regedit
of MountedDevices
will show F:
, but not F:\dataset
. So we can ignore that.
The output of mountvol
however, should show both:
\\?\Volume{6323d61f-4014-11e7-b722-806e6f6e6963}\
F:\
\\?\Volume{6323d63a-4014-11e7-b722-806e6f6e6963}\
F:\dataset
whereas for ZFS, we only get E:\
, no E:\dataset
. Less than ideal.
\\?\Volume{3fe4a1af-988f-3c6a-93c0-6c75d96902db}\
E:\
Using the command mountvol E:\dataset \\?\Volume{3fe4a1af-988f-3c6a-93c0-6c75d96902db}
I was initially getting Directory is not empty
.
Now we return NumberOfLinks = zp->z_links;
like Unix, but with Unix empty directories has 2 links. Windows expects to see 1.
So we correct it to return 1.
Now I get Access Denied
. So I use an elevated CMD prompt, and the mountvol
command completes successfully. But, still does not show in mountvol
.
The need for elevated permissions is wrong, need to figure out why that is.
Congrats with the steps forward. To my eyes that's more than impressive!
Now I get
Access Denied
. So I use an elevated CMD prompt, and themountvol
command completes successfully. But, still does not show inmountvol
.The need for elevated permissions is wrong, need to figure out why that is.
I am not sure I can agree. Without elevation mountvol
is only able to read the volume status on my w10 Pro:
C:\Users\saukrs> ver
Microsoft Windows [Version 10.0.19044.3086]
C:\Users\saukrs> mountvol
<...>
\\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}\
*** NO MOUNT POINTS ***
\\?\Volume{5feefb5c-468a-4da8-9fcc-0dfba19dcab8}\
*** NO MOUNT POINTS ***
\\?\Volume{0869fa25-bd66-7074-6498-7f4d08d64db0}\
E:\
But to mount a volume it needs the elevated permissions:
C:\Users\saukrs> mountvol D:\Another-volume \\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}
Access is denied.
C:\Users\saukrs> gsudo mountvol D:\Another-volume \\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}
C:\Users\saukrs> mountvol
<...>
\\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}\
D:\Another-volume\
\\?\Volume{5feefb5c-468a-4da8-9fcc-0dfba19dcab8}\
*** NO MOUNT POINTS ***
\\?\Volume{0869fa25-bd66-7074-6498-7f4d08d64db0}\
E:\
The elevation is also needed for unmounting:
C:\Users\saukrs> mountvol D:\Another-volume /P
Access is denied.
That was ant EXT4
volume, but the same is valid for NTFS
– just checked that.
Volumes can be managed from Ext2 Volume Manager which also requires the elevation.
The only way I can assign drive letter without getting an UAC prompt is via diskmgmt.msc
, the Disk Management consolse, handled by mmc.exe
. This difference made me curious, so I made a diff.
Security properties for an unelevated cmd.exe
and the mmc.exe
in Process Explorer:
At least judging by the BUILTIN\Administrators
and NT AUTHORITY\Local account and member of Administrators group
entries I guess MMC gets some automatic elevation. At least on my OS setup.
PS. Mounting / unmounting VHDs also requires the elevation on my OS.
An SO thread Allow non-administrators to use diskpart to mount VHDs? says:
The official word from Microsoft (I don't have a reference to provide, but I used to work there and this was the message I got) is that mounting and unmounting VHDs can only be performed by administrators. ISOs, on the other hand, can be mounted and unmounted by regular users.
I found a tool VHDAttach: http://www.jmedved.com/vhdattach/ Which adds a Windows Service that runs as a privileged account, that recieves messages from a little exe, and add shell extensions so that non-priv users can attach/detach VHDs.
This also reminds me about Ext2Srv
, the Ext2Fsd Service Manager running in the background and doing things.
Now I noticed that VHDX files can be mounted and dismounted just from File Explorer. Still no luck from unelevated mountvol
.
Haven't investigated yet about what the explorer.exe
does. It's clearly unelevated:
I haven't investigated yet into exactly what does it do when I click the .vhdx
file.
EDIT: Looks like I will need to trace the explorer.exe
itself. Maybe using ProcMon for a start.
C:\Users\saukrs> reg query HKCR\Windows.VhdFile\Shell /s
HKEY_CLASSES_ROOT\Windows.VhdFile\Shell\mount
CommandStateSync REG_SZ
ExplorerCommandHandler REG_SZ {9ab3b1c9-3225-4bb4-93b6-bfb3c0d93743}
HasLUAShield REG_SZ true
MultiSelectModel REG_SZ Document
HKEY_CLASSES_ROOT\Windows.VhdFile\Shell\mount\command
(Default) REG_EXPAND_SZ %SystemRoot%\Explorer.exe
DelegateExecute REG_SZ {9ab3b1c9-3225-4bb4-93b6-bfb3c0d93743}
A quick shot revealed me nothing, except maybe the suspicious registry paths like these:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\Volume
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\Volume\{3001e1ae-97fa-4722-a80d-79ac3549257b}
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\{3001e1ae-97fa-4722-a80d-79ac3549257b}
... with the UUID matching output of mountvol
:
C:\Users\saukrs> mountvol
<...>
\\?\Volume{3001e1ae-97fa-4722-a80d-79ac3549257b}\
X:\
\\?\Volume{5feefb5c-468a-4da8-9fcc-0dfba19dcab8}\
*** NO MOUNT POINTS ***
\\?\Volume{0869fa25-bd66-7074-6498-7f4d08d64db0}\
E:\
... where X:
is the drive I get after I double-click my .vhdx
file (without having to interact with any UAC boxes):
I suppose it has something to do with AttachVirtualDisk function (virtdisk.h). MSDN writes:
This function will fail if a provider cannot be found, if the VHD or ISO image file is not valid, if the VHD image is already attached, or if the caller does not have SE_MANAGE_VOLUME_PRIVILEGE access rights.
Now I noticed: as soon as I launch "C:\Windows\explorer.exe" D:\antras.vhdx
, two processes are spawned under this system process:
One of them uses the same image of Explorer:
Command line: C:\Windows\explorer.exe /factory,{75dff2b7-6936-4c06-a8bb-676a7b00b24b} -Embedding
Current directory: C:\Windows\System32\
Autostart Location: n/a
Started: 19:18:20 10/07/2024
And another is some COM Surrogate:
Command line: C:\Windows\system32\DllHost.exe /Processid:{51A1467F-96A2-4B1C-9632-4B4D950FE216}
Current directory: C:\Windows\System32\
Autostart Location: HKLM\System\CurrentControlSet\Services\COMSysApp
Started: 19:18:21 10/07/2024
COM Surrogate process exits soon after that.
Clearly this indicates to me about some IPC/RPC going on behind the courtain via COM technology. And reversing that will require the skillset that I currently lack, I think.
Awesome, I would like to ignore the Access Denied, and sounds like I can.
So mounting NTFS F: and F:\dataset, will also not show in mountmgr QUERY_MOUNT_POINTS
FFFF9784A6EEE040: dprintf: zfs_vnops_windows_mount.c:293:mountmgr_get_mountpoint2(): point 4: '\Device\HarddiskVolume7' '\DosDevices\F:'
FFFF9784A6EEE040: dprintf: zfs_vnops_windows_mount.c:293:mountmgr_get_mountpoint2(): point 5: '\Device\HarddiskVolume8' '\??\Volume{77687f19-37c9-4b70-b4
90-532ac3c49538}'
so that was a couple of days of debugging lost trying to get that to work.
Now using mountvol
to make a dataset2
for NTFS on ZFS E:\dataset2, and the inverse
ZFS on NTFS F:\dataset2.
It is interesting to note that both E:\dataset, and E:\dataset2 are "Folders" in explorer. But with
F:\dataset, and F:\dataset2 they are presented as "Mounted Volumes". Which makes me think we present reparsepoints incorrectly.
Clearly the initial mount of E:\dataset is done with wrong target name.
Directory of E:\
07/11/2024 10:28 AM <DIR> .
07/11/2024 10:28 AM <DIR> ..
07/11/2024 10:28 AM <JUNCTION> dataset2 [\??\Volume{cbce18b4-e707-472f-8408-14938d234438}\]
07/11/2024 10:18 AM <JUNCTION> dataset [\]
Directory of F:\
07/11/2024 10:14 AM <JUNCTION> dataset [\??\Volume{77687f19-37c9-4b70-b490-532ac3c49538}\]
07/11/2024 10:29 AM <JUNCTION> dataset2 [\??\Volume{5605728c-3a86-11ef-82be-58961d57db67}\]
Ah no unrelated, shows as "Mounted Volume" after I corrected something.
I'm confused by all the missing information here, between F: (NTFS) and E: (ZFS).
True, a lot is missing. Can you share both outputs here + the command that generated them, please?
I would like to make a comparison using my own way :P
I used PowerShell Get-WmiObject -Query "SELECT * FROM Win32_Volume"
Thanks. This seems to be equal to Get-WmiObject Win32_Volume
.
Meanwhile I constructed a bit different PowerShell composite for easier reading:
C:\Users\saukrs> powershell "get-wmiobject Win32_Volume | ft @{Label = 'Mount'; Expression = {$_.Name -replace '^\\.+', ''}}, Capacity, FileSystem, Label, DeviceID"
Mount Capacity FileSystem Label DeviceID
----- -------- ---------- ----- --------
...
F:\ 4320129024 NTFS NTFS Volume \\?\Volume{c27eb7f0-3284-43ef-9f12-c3405d3bcd64}\
F:\dataset\ 1073741824 EXT4 An EXT4 Vol \\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}\
1073737728 NTFS Inner NTFS Volume \\?\Volume{fa93785d-d1f8-4ff7-b562-f2f2cbd7665a}\
...
B:\ 41527803904 Btrfs A Btrfs Vol \\?\Volume{0869fa25-bd66-7074-6498-7f4d08d64db0}\
Just noticed that Windows sees my EXT4 volume as mounted only if I mount it under NTFS folder: #389 (comment)
If I mount EXT4 by default (as a drive letter), the location/mount info is lost:
C:\Users\saukrs> powershell "get-wmiobject Win32_Volume | ft @{Label = 'Mount'; Expression = {$_.Name -replace '^\\.+', ''}}, Capacity, FileSystem, Label, DeviceID"
Mount Capacity FileSystem Label DeviceID
----- -------- ---------- ----- --------
...
F:\ 4320129024 NTFS NTFS Volume \\?\Volume{c27eb7f0-3284-43ef-9f12-c3405d3bcd64}\
1073741824 EXT4 An EXT4 Vol \\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}\
F:\dataset\ 1073737728 NTFS Inner NTFS Volume \\?\Volume{fa93785d-d1f8-4ff7-b562-f2f2cbd7665a}\
...
B:\ 41527803904 Btrfs A Btrfs Vol \\?\Volume{0869fa25-bd66-7074-6498-7f4d08d64db0}\
(It's replaced with \\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}\
, but I clear this out from Name
for the brevity)
So in that regard Ext4FSD project is broken – it registers only directory-based mountpoints.
But it's broken in a different way from Btrfs which registers only drive letters (and no directory mountpoints).
It would be nice to combine both partial mechanics into one :)
EDIT: I stand corrected – EXT4 drive letter is omitted from the mount list only when assigned using the Ext2 Volume Manager tool.
When I assign it the Windows way, via Disk Management console, the mounted EXT4 drive letter appears as expected:
C:\Users\saukrs> powershell "get-wmiobject Win32_Volume | ft @{Label = 'Mount'; Expression = {$_.Name -replace '^\\.+', ''}}, Capacity, FileSystem, Label, DeviceID"
Mount Capacity FileSystem Label DeviceID
----- -------- ---------- ----- --------
...
F:\ 4320129024 NTFS NTFS Volume \\?\Volume{c27eb7f0-3284-43ef-9f12-c3405d3bcd64}\
E:\ 1073741824 EXT4 An EXT4 Vol \\?\Volume{776c48ee-fe39-4fa4-8e7c-9d07a3a0d176}\
F:\dataset\ 1073737728 NTFS Inner NTFS Volume \\?\Volume{fa93785d-d1f8-4ff7-b562-f2f2cbd7665a}\
...
B:\ 41527803904 Btrfs A Btrfs Vol \\?\Volume{0869fa25-bd66-7074-6498-7f4d08d64db0}\
This probably means that Ext2 Volume Manager (its' mounting operation sequence) is also incomplete.
Sorry for the noise, digging further.
FWIW, found a tool which assigns a drive letter for my EXT4 volume correctly, it's ChangeLetter.
With it, the letter is seen by WMI (via PowerShell).
But the tool doesn't handle directory mounts.
It's written in C# and seems to be only using SetVolumeMountPoint()
:
https://github.com/medo64/ChangeLetter/blob/d198f3c/Source/ChangeLetter/Volume.cs#L52-L60
According to Creating Mounted Folders, this is enough:
It is not necessary to manipulate reparse points to use mounted folders; functions such as SetVolumeMountPoint handle all the reparse point details for you.
Then I found an Inside Mountvol.exe article and its' tool that does only directory mount for volumes.
The code aims at older Windows versions (circa 2008). Maybe because of that it also describes two additional things:
- creating a reparse point by hand
- registering it via MountMgr (
IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED
)
Anyway, it mounts my EXT4 volume on an empty NTFS dir just fine.
Registering MountMgr
Creating a reparse point is enought to build a mount point. But this mount point doesn't appear using MOUNTVOL.EXE. It semms to mean that the mount is not registered with the mount manager. I found the information in the DDK. The mount manager is responsible for managing volume names. For each volume, it stores a name that is unique and is permanently identified with the volume.
OpenZFS already seems to be sending that IOCTL, but I guess it's done in kernel mode:
https://github.com/openzfsonwindows/openzfs/blob/bab1d06/module/os/windows/zfs/zfs_vnops_windows_mount.c#L581-L583
I am guessing if the userland-vs-kernel mode difference is insignificant for registration.
I probably should stop flooding the ticket and migrate to discussions. Anyways, putting my findings here for now.
Last two items:
-
The OSR thread led me to the 22y old article:
Maybe I Should Drive - Drive Letter Assignment & The Mount Manager -
A piece of an old, circa VC6 Platform SDK showing that at least earlier Windows required even more tinkering to make driver letters permanent (surviving a reboot).
No need to survive reboots, at least not that the moment. I have noticed that VHD mounts do create DISK and PARTITION types, so perhaps it is time to add PARTITION to the testing. Everyone says you don't need it, but might as well try everything. I am concerned my E: doesn't have "driveletter" assigned, so potentially perhaps I have 2 broken things, and I should work on one at a time
OK so chatgpt suggests:
To use PnPUtil, open a Command Prompt with administrative privileges and use the following command:
pnputil /enum-devices /connected
OK having just created my first volume to attempt to mount, and pnputil says:
Instance ID: ROOT\OpenZFS\0000
Device Description: Unknown
Class Name: Unknown
Class GUID: Unknown
Manufacturer Name: Unknown
Status: Problem
Problem Code: 28 (0x1C) [CM_PROB_FAILED_INSTALL]
Check the Event Viewer for any error messages or warnings related to your driver or device installation.
The EventViewer has:
Driver Name: oem3.inf
Class Guid: {71a27cdd-812a-11d0-bec7-08002be2092f}
Service: OpenZFS
Lower Filters:
Upper Filters:
Problem: 0x0
Problem Status: 0xC00000E5
The 0xC00000E5 status code is STATUS_IO_TIMEOUT, indicating that a time-out occurred while attempting to install
the driver. This suggests that there might be an issue during the initialization or setup of the device,
particularly when creating the DeviceObject and preparing it for use as a volume.
@lundman , thank you very much for such a useful masterpiece!
Just wanted to ask, because it means so much,
- will it be possible to mount, umount and remount without an OS restart? It would be so great!
That is the goal :) Actually, unmouting is working much better with the new work. It's just that the mounts are only half recognised.
Hah ok, so today I found out BusQueryHardwareIDs does not return a string. Only once you point that out, does chatgpt happily point out you need to handle it. Thanks. </Sarcasm>
Yes, for the BusQueryHardwareIDs type in the IRP_MN_QUERY_ID request,
you need to return a MULTI_SZ string, which is a double-null-terminated
list of null-terminated strings.
I have finally had some small progress, I can load the Driver without pnputil complaining, so we can start moving forwards. There have been many small little bugs to tweaks.
I wonder if there are any book written that could help.
(Not that I am sure @lundman likes reading books at all, just a thought)
OK going to jot down what I have learned while I still remember.
Using WinObj.exe to inspect the objects created, in the
"\" category, we have
\Ntfs
\Fat
\Btrfs
So naturally, we also create \OpenZFS
. As a separate an unrelated note, we do create \Device\ZFSCTL
and \DosDevices\ZFS
for userland to ioctl()
with the kernel. Old name kept for compatibility with old tools. This may change.
Problem 1.
I noticed that in WinObj
you can right-click \Ntfs
and select Properties
(for some rather pointless properties), but with \OpenZFS
it would say The system cannot find the specified path.
Turns out the dispatcher()
handler for the \OpenZFS
device needs to handle IRP_MJ_CREATE
, IRP_MJ_CLOSE
and IRP_MJ_CLEANUP
. Does not need to do anything more that return STATUS_SUCCESS
that I can see. I do not assign FsContext
etc, nor are we given FileObject->FileName
. Now it works the same.
After that, I can confirm the symlink:
\DosDevices\OpenZFS
works the same as \DosDevices\Ntfs
. (Path in WinObj is \GLOBAL??\OpenZFS
and \GLOBAL??\Ntfs
.
Problem 2.
We should also get an entry
\FileSystem\Ntfs
but we do not.
This turns out to be automatically created by calling IoRegisterFileSystem()
, if your DeviceType is that of FILE_SYSTEM_DRIVER
. iomgr internally checks that against your HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OpenZFS\Type
. Which is automatically created when you install your driver based on OpenZFS.inf
.
For the longest time we had:
ServiceType = 1
which needs to be ServiceType = 2
for FILE_SYSTEM_DRIVER
.
Now we get a \FileSystem\OpenZFS
just like Ntfs.
It could very well be we need to do two .INF files, like Btrfs does. Presumably they do that for a reason. We can follow their example eventually. (Second INF appears to be for the Volumes, ie our ZVOLs)
After creating the \OpenZFS
DeviceObject, the Driver's AddDevice()
function is called, ie, DriverObject->DriverExtension->AddDevice = MyAddDevice;
.
In here, you are given the PhysicalDeviceObject
that applies to your \OpenZFS
DeviceObject
. You should attach DeviceObject
to the PhysicalDeviceObject
by calling IoAttachDeviceToDeviceStack()
.
This completes the DriverLoad work, and we are up and humming.
You can run things like pnputil /enum-devices /problem
and OpenZFS should not show, and also pnputil /enum-devices /connected
should show something like
Instance ID: ROOT\VOLUME\0000
Device Description: OpenZFS
Class Name: Volume
Class GUID: {71a27cdd-812a-11d0-bec7-08002be2092f}
Manufacturer Name: Jorgen Lundman
Status: Started
Driver Name: oem3.inf
The VOLUME in ROOT\VOLUME\0000
appears to be because OpenZFS.inf
has Class=Volume
in it, and Registry is created with HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OpenZFS\Enum\0
as ROOT\VOLUME\0000
. It is probably as expected.
However, using Event Viewer
and traversing down to Application and Services / Microsoft / Windows / Kernel-PnP / Device Configuration
when OpenZFS
is loaded, we get one Infromation
entry which looks good, then a Error
entry with Status 0xc00000e5
. Is this fixable? Do other drivers like Btrfs
also get this?
Problem 3
Mounting a OpenZFS dataset. Gets a bit vague, murky and hand wavey now.
Create a new DeviceObject
of type FILE_DEVICE_DISK
, often called DCB.
Call IoInvalidateDeviceRelations(pdo, BusRelations);
to buzz the bus. AddDevice()
is called, and for some weird reason has the same PhysicalDeviceObject
- hope that doesn't matter,
IoRegisterDeviceInterface(GUID_DEVINTERFACE_VOLUME ..., &volumeInterfaceName)
to make it also be a Volume
type. This returns a new string, which you have to enable by calling IoSetDeviceInterfaceState(&volumeInterfaceName, TRUE);
I guess VCB then too? If I call IoAttachDeviceToDeviceStack()
here I create a loop, so don't do that. I guess because it is the same PhysicalDeviceObject
.
Update: If diskDeviceObject
is the FILE_DEVICE_DISK
object created, then in AddDevice()
is called with PhysicalDeviceObject == diskDeviceObject
. Which you can obviously not attach to. Possibly the original PDO is what is needed here.
Next up, IRP_MN_MOUNT_VOLUME
is called. First make sure it is our FILE_DEVICE_DISK
DeviceObject
which generally means finding the lowest device. Most drivers loop down, or you can call IoGetDeviceAttachmentBaseRef()
and don't forget to call ObDereferenceObject()
when done with it.
Now create a new DeviceObject
type FILE_DEVICE_DISK_FILE_SYSTEM
, called a FCB. Attach this to the FILE_DEVICE_DISK
DeviceObject
. I believe they mean the DeviceObject
given in IRP_MN_MOUNT_VOLUME
, as opposed to the DeviceToMount
lowest DeviceObject
you found - but maybe not, lets try all combinations.
Setup the VPB passed along with the request, to point Vpb->DeviceObject
to FILE_DEVICE_DISK_FILE_SYSTEM
device, have a reference count, and set VPB_MOUNTED
. Interestingly, iomgr does this after the call to IRP_MN_MOUNT_VOLUME
so it feels redundant, but perhaps it didn't used to with older Windows. The Vpb->DeviceObject
is what is used to know the relationship to your disk DeviceObject
.
Now we can talk to MountMgr
about where to stick it. We should also announce the volume by calling MountMgr
with IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION
, or so says chatgpt.
But even then, our volume does seem "mostly created". I am uncertain if the differences are just that we are a Volume
, compared to if you create a VHD, format as NTFS. There VHD creates a DISK
, attaches PARTITION
, then .. somethingsomething, mounts.
<PowersHell> Get-Volume
DriveLetter FriendlyName FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining Size
----------- ------------ -------------- --------- ------------ ----------------- ------------- ----
E BOOM NTFS Removable Healthy OK 9.2 GB 9.2 GB
F New Volume NTFS Fixed Healthy OK 991.41 MB 1006 MB
Comparing the Objects in WinObj after a ZFS E:
mount, versus a NTFS F:
mount.
WinObj
\Device\HarddiskVolume8 Device
\Device\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277} Device
\Device\Harddisk2\Partition2 SymbolicLink \Device\HarddiskVolume8
\GLOBAL??\E: SymbolicLink \Device\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277}
\GLOBAL??\F: SymbolicLink \Device\HarddiskVolume8
\GLOBAL??\Harddisk2Partition2 SymbolicLink \Device\HarddiskVolume8
\GLOBAL??\HarddiskVolume8 SymbolicLink \Device\HarddiskVolume8
\GLOBAL??\OpenZFS#0b1bb601-af0b-32e8-a1d2-54c167af6277#1&112354b5&0&0000#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b} SymbolicLink \Device\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277}
\GLOBAL??\STORAGE#Volume#{56057687-3a86-11ef-82be-58961d57db67}#0000000001000000#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b} SymbolicLink \Device\HarddiskVolume8
\GLOBAL??\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277} SymbolicLink \Device\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277}
\GLOBAL??\Volume{c97506b9-126b-4c61-8dfd-92f72a5567eb} SymbolicLink \Device\HarddiskVolume8
\ArcName\OpenZFS(0b1bb601-af0b-32e8-a1d2-54c167af6277) SymbolicLink \Device\Volume{0b1bb601-af0b-32e8-a1d2-54c167af6277}
So it looks like we have all required entries and symboliclinks, at least if we remember we do not attach partitions. The ArcName seems to be related to boot support for later.
Here is where it looks a bit wrong:
$ wmic volume list brief
Capacity DriveType FileSystem FreeSpace Label Name
85103472640 3 NTFS 19006451712 C:\
E:\
5 D:\
Mostly empty? Just like CDrom.
BSOD on import on 2.2.6rc4, was fine on 2.2.3-rc6
Any clues as to why? cbuf? stack?
READ_ADDRESS: fffff80242b01390: Unable to get MiVisibleState
Unable to get NonPagedPoolStart
Unable to get NonPagedPoolEnd
Unable to get PagedPoolStart
Unable to get PagedPoolEnd
fffff80242a15400: Unable to get Flags value from nt!KdVersionBlock
fffff80242a15400: Unable to get Flags value from nt!KdVersionBlock
unable to get nt!MmSpecialPagesInUse
0000002938dde0f0
ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p 0x%p %s
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 0000000000000000
EXCEPTION_PARAMETER2: 0000002938dde0f0
EXCEPTION_STR: 0xc0000005
STACK_TEXT:
fffffd0b`4a9570c0 fffff80d`f817640d : ffff8782`faed6d60 00000000`00000000 fffff802`427d2840 00000000`00000000 : nt!IofCallDriver+0x48
fffffd0b`4a957100 ffff8783`0244dab0 : ffff8782`fa9d6820 ffff8783`347b3a20 ffff8783`347b3a20 ffff8783`347b3a20 : OpenZFS!zfsctl_vnode_alloc+0x2cd [C:\src\openzfs\module\os\windows\zfs\zfs_ctldir.c @ 203]
fffffd0b`4a957200 ffff8782`fa9d6820 : ffff8783`347b3a20 ffff8783`347b3a20 ffff8783`347b3a20 ffff3ade`2f8611a7 : 0xffff8783`0244dab0
fffffd0b`4a957208 ffff8783`347b3a20 : ffff8783`347b3a20 ffff8783`347b3a20 ffff3ade`2f8611a7 fffff802`42050d55 : 0xffff8782`fa9d6820
fffffd0b`4a957210 ffff8783`347b3a20 : ffff8783`347b3a20 ffff3ade`2f8611a7 fffff802`42050d55 ffff8783`22668050 : 0xffff8783`347b3a20
fffffd0b`4a957218 ffff8783`347b3a20 : ffff3ade`2f8611a7 fffff802`42050d55 ffff8783`22668050 00000000`00000000 : 0xffff8783`347b3a20
fffffd0b`4a957220 ffff3ade`2f8611a7 : fffff802`42050d55 ffff8783`22668050 00000000`00000000 00000000`00000000 : 0xffff8783`347b3a20
fffffd0b`4a957228 fffff802`42050d55 : ffff8783`22668050 00000000`00000000 00000000`00000000 ffffffff`ffffffff : 0xffff3ade`2f8611a7
fffffd0b`4a957230 fffff802`41bf4a76 : ffff8782`faed6d60 ffff8783`0244dab0 ffff8783`347b3a20 00000000`00000000 : nt!IofCallDriver+0x55
fffffd0b`4a957270 fffff802`42050d55 : ffff8783`24e27d20 00000000`00000000 00000000`00000000 ffffffff`ffffffff : FLTMGR!FltpDispatch+0xd6
fffffd0b`4a9572d0 fffff802`41bf4a76 : ffff8783`24e27d20 ffff8783`0244dab0 ffff8783`347b3a20 00000000`00000000 : nt!IofCallDriver+0x55
fffffd0b`4a957310 fffff802`42050d55 : ffff8783`24e27d20 fffff802`42060b8e 00000000`00000000 fffffd0b`4a957400 : FLTMGR!FltpDispatch+0xd6
fffffd0b`4a957370 fffff802`427b437e : ffff8783`0244db00 fffffd0b`4a9574a0 00000000`00000000 fffff802`00000000 : nt!IofCallDriver+0x55
fffffd0b`4a9573b0 fffff802`427b40ae : 00000000`00000001 ffff8782`f3b4f520 fffff802`42a27020 00000000`00000001 : nt!IopShutdownBaseFileSystems+0xca
fffffd0b`4a957430 fffff802`427ba31a : 00000000`00000002 00000000`00000002 fffff802`42a27020 ffff8783`32805b40 : nt!IoShutdownSystem+0x156
fffffd0b`4a9574b0 fffff802`42028525 : ffff8783`3837d0c0 fffff802`4207b4a0 ffff8782`f3b4f520 ffff8782`00000000 : nt!PopGracefulShutdown+0x23a
fffffd0b`4a9574f0 fffff802`4212f9a5 : ffff8783`3837d0c0 00000000`00000080 ffff8782`f3b44080 001fe067`bcbbbdff : nt!ExpWorkerThread+0x105
fffffd0b`4a957590 fffff802`4220d2a8 : fffff802`3fb65180 ffff8783`3837d0c0 fffff802`4212f950 00000000`00000246 : nt!PspSystemThreadStartup+0x55
fffffd0b`4a9575e0 00000000`00000000 : fffffd0b`4a958000 fffffd0b`4a951000 00000000`00000000 00000000`00000000 : nt!KiStartSystemThread+0x28
FAULTING_SOURCE_LINE: C:\src\openzfs\module\os\windows\zfs\zfs_ctldir.c
FAULTING_SOURCE_FILE: C:\src\openzfs\module\os\windows\zfs\zfs_ctldir.c
FAULTING_SOURCE_LINE_NUMBER: 203
SYMBOL_NAME: OpenZFS!zfsctl_vnode_alloc+2cd
MODULE_NAME: OpenZFS
IMAGE_NAME: OpenZFS.sys
STACK_COMMAND: .cxr 0xfffffd0b4a9566c0 ; kb
BUCKET_ID_FUNC_OFFSET: 2cd
FAILURE_BUCKET_ID: AV_OpenZFS!zfsctl_vnode_alloc
OSPLATFORM_TYPE: x64
OSNAME: Windows 10```
Why would IopShutdownBaseFileSystems
be called on your system? This is during import?
Why would
IopShutdownBaseFileSystems
be called on your system? This is during import?
Yes this is when I do zpool import ZFS
I can certainly fix the IRP_SHUTDOWN
we receive, and look at why the snapshot code is crashing - but it is peculiar it starts a shutdown processes.
Might be a trigger on my system, still need to be confirmed.