openzfsonwindows/openzfs

Representing volume FS type as `ZFS` instead of `NTFS`

sskras opened this issue ยท 7 comments

Describe the feature would like to see added to OpenZFS

I would like an ability to switch FS type that the driver presents to the OS for the arbitrary volume to ZFS.
IIUC, now the type is being hardcoded to NTFS.

Maybe the interface for that could be registry / tunables-based.

How will this feature improve OpenZFS?

That would allow an operator to navigate in a set of different volumes more easily. Given that WinBTRFS already does that.

Also it could help to reuse some maintenance scripts/tools already written for Linux/FreeBSD/illumOS/Solaris.

Additional context

Influenced by #294 (comment) and #376 (comment)

Eg. WinBTRFS set FS type to Btrfs in my example, the B: drive letter, and MSYS2 environment recognizes it:

saukrs@DESKTOP-O7JE7JE MSYS ~
$ df -Th
Filesystem     Type   Size  Used Avail Use% Mounted on
C:/msys64      ntfs   238G  234G  4.1G  99% /
B:             btrfs  228G  624K  228G   1% /b
D:             ntfs   932G  924G  8.5G 100% /d
E:             ntfs    71G  5.6G   65G   8% /e

E: is my ZFS mount. I also checked the type using WMI:

saukrs@DESKTOP-O7JE7JE MSYS ~
$ wmic volume get caption,FileSystem
Caption                                            FileSystem
D:\                                                NTFS
C:\                                                NTFS
\\?\Volume{878041e1-48c2-484b-bcc1-507b0ff19c4c}\  NTFS
\\?\Volume{5feefb5c-468a-4da8-9fcc-0dfba19dcab8}\  FAT32
\\?\Volume{e24f4a77-14e4-3367-afa7-b538e0dd6bca}\  FAT32
B:\                                                Btrfs
E:\
\\?\Volume{00000000-0000-0000-0c00-0f00fa7f0000}\

Strangely enough the FileSystem is empty for the ZFS volume here (but not for BTRFS volume).

That is what the mimic property is for, but I wonder if I didn't plumb it yet, since it is saying ntfs by default.

OK. Found mimic declared in zfs_domount():

static int
zfs_domount(struct mount *vfsp, dev_t mount_dev, char *osname,
vfs_context_t ctx)
{
int error = 0;
zfsvfs_t *zfsvfs;
uint64_t mimic = 0;

... it's extracted from the "com.apple.mimic" property later to write "ntfs" into vfsstatfs->f_fstypename conditionally:

error = dsl_prop_get_integer(osname, "com.apple.mimic", &mimic, NULL);
/*
* If we are readonly (ie, waiting for rootmount) we need to reply
* honestly, so launchd runs fsck_zfs and mount_zfs
*/
if (mimic /* == ZFS_MIMIC_NTFS */) {
struct vfsstatfs *vfsstatfs;
vfsstatfs = vfs_statfs(vfsp);
strlcpy(vfsstatfs->f_fstypename, "ntfs", MFSTYPENAMELEN);
}

  1. Do mounted filesystems have such property by default? Will check later.

Now could this enum and the tables be related to code above?

typedef enum zfs_mimic {
ZFS_MIMIC_OFF = 0,
ZFS_MIMIC_HFS,
ZFS_MIMIC_APFS,
ZFS_MIMIC_NTFS
} zfs_mimic_t;

static zprop_index_t mimic_table[] = {
{ "off", ZFS_MIMIC_OFF },
{ "hfs", ZFS_MIMIC_HFS },
{ "apfs", ZFS_MIMIC_APFS },
{ "ntfs", ZFS_MIMIC_NTFS },
{ NULL }
};

IOW:

  1. I wonder why is "ntfs" harcoded in zfs_domount() instead of using mimic_table[ZFS_MIMIC_NTFS] or mimic_table[mimic] .

Also found mimic_changed_cb() fn, where both paths of the if-branch are commented out:

mimic_changed_cb(void *arg, uint64_t newval)
{
zfsvfs_t *zfsvfs = arg;
struct vfsstatfs *vfsstatfs;
vfsstatfs = vfs_statfs(zfsvfs->z_vfs);
if (newval == 0) {
// strlcpy(vfsstatfs->f_fstypename, "zfs", MFSTYPENAMELEN);
} else {
// strlcpy(vfsstatfs->f_fstypename, "hfs", MFSTYPENAMELEN);
}
}

  1. Any reason โ€“ maybe leftover from openzfsonosx ?

The fn is seemingly referenced in one place only:

zprop_register_index(ZFS_PROP_MIMIC, "com.apple.mimic", 0,
PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "off | ntfs",
"COM.APPLE.MIMIC_HFS", mimic_table, sfeatures);

  1. So mimic_table[] is related to "com.apple.mimic" property, but I don't get exactly how. IOW, when is mimic_changed_cb() invoked?

And anyways, semantically "com.apple.mimic" and "ntfs" feels a bit alien to me when paired.

  1. It would be fine to reuse an existing thing, but I'm much interested about origins of this property (where did it come from:)

Yep, right path. When we call zprop_register_index(..."com.apple.mimic"... there is also a callback registered for it:

	error = error ? error : dsl_prop_register(ds,
	    zfs_prop_to_name(ZFS_PROP_MIMIC), mimic_changed_cb, zfsvfs);

so that is called whenever it is changed. You can see from the commented out code where it should be changed, obviously no need for hfs in Windows version, so only need to look for MIMIC_NTFS.

We do not use the struct/enum/mimic_table, as it is static and not visible outside of that file. It's a shame, but a change too large to bother to get to pass with upstream.

Thanks!

so that is called whenever it is changed. You can see from the commented out code where it should be changed, obviously no need for hfs in Windows version, so only need to look for MIMIC_NTFS.

OK, I am going to wait for that change :)

We do not use the struct/enum/mimic_table, as it is static and not visible outside of that file. It's a shame, but a change too large to bother to get to pass with upstream.

Oh. If I got free time and other resources, I would take a try at that. Thank you for the details!

@sskras WinBtrfs+OpenZFS = problematic, at best. First, WinBtrfs will break your Btrfs at some point (Linux will detect errors first, then it wont be able to repair those at some further point). This happened to me ~ 6 weeks ago (again), after testing recent winbtrfs update with hopes of this being solved (again) - its not. WinBtrfs driver will break your Zfs dataset as well - if you shuffle data between those within Windows, i dont know what exactly caused zfs pool cripple, but both drivers dont play well WinBtrfs makes a pretty stable impression but resulted with major hickups.

After reading #384 (comment) by @lundman about MOUNTMGR I compared two related outputs from PowerShell.

The 1st one comes from Get-WMIObject and is related to output of wmic reported in the original comment:

C:\Users\saukrs> sudo powershell "Get-WMIObject -Query 'Select * from Win32_Volume' | Sort-Object -Property Capacity | Format-Table -Property DriveLetter, Name, Label, FileSystem, DriveType, Status, @{Name='FreeSpace'; Exp={$_.FreeSpace}; Align='right'}, @{Name='Capacity'; Exp={$_.Capacity}; Align='right'}"

DriveLetter Name                                              Label       FileSystem DriveType Status    FreeSpace      Capacity
----------- ----                                              -----       ---------- --------- ------    ---------      --------
            F:\
            \\?\Volume{5feefb5c-468a-4da8-9fcc-0dfba19dcab8}\             FAT32      3                    53580800     100663296
            \\?\Volume{e24f4a77-14e4-3367-afa7-b538e0dd6bca}\             FAT32      3                   219055616     264257536
            \\?\Volume{878041e1-48c2-484b-bcc1-507b0ff19c4c}\             NTFS       3                    86540288     529526784
E:          E:\                                                           Btrfs      3                244047036416  244047675392
C:          C:\                                               pagrindinis NTFS       3                  2043293696  255405891584
D:          D:\                                               New Volume  NTFS       3                  1797406720 1000186310656

As mentioned in the original comment, WinBrtfs reports FileSystem = Btrfs, while OpenZFS reports no type at all.

The 2nd output comes from Get-Volume:

C:\Users\saukrs> sudo powershell "Get-Volume | Sort-Object -Property Size | Format-Table -Property @{Name='DriveLetter'; Expression={$_.DriveLetter}; Align='left'}, FileSystemLabel, FileSystemType, DriveType, OperationalStatus, SizeRemaining, Size"

DriveLetter FileSystemLabel FileSystemType DriveType OperationalStatus SizeRemaining          Size
----------- --------------- -------------- --------- ----------------- -------------          ----
F                           Unknown        Removable Unknown                       0             0
                            FAT32          Fixed     OK                     53580800     100663296
                            FAT32          Fixed     OK                    219055616     264257536
                            NTFS           Fixed     OK                     86540288     529526784
E                           Unknown        Fixed     OK                 244047036416  244047675392
C           pagrindinis     NTFS           Fixed     OK                   2045136896  255405891584
D           New Volume      NTFS           Fixed     OK                   1797615616 1000186310656

And here both WinBTRFS and OpenZFS show FileSystemType = Unknown.

To me this means that there are at least two untouched places where the type needs to be reported at.

Some insights come from WinBTRFS code:
https://github.com/maharmstone/btrfs/blob/99c109ee3e63bb6317ee0afb31156c70ddc3b408/src/btrfs.c#L681-L685

// This function exists because we have to lie about our FS type in certain situations.
// MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match,
// it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
// The command mklink refuses to create hard links on anything other than NTFS, so we have to
// blacklist cmd.exe too.

static bool lie_about_fs_type() {