Modern guidance on ZFS casesensitivity, normalization, and utf8only properties

seanm

Guru
Joined
Jun 11, 2018
Messages
570
I've been reading about the 3 ZFS properties : casesensitivity, normalization, and utf8only. I want to get my choice right, since it's pretty permanent.

I'm quite sure I want to set utf8only=on, but I'm not sure what to choose for normalization. Must it be other than "none" if utf8only=on? If so, how to choose among NFC, NFD, etc?

I'm also confused about the "mixed" option for casesensitivity, I can't find a good explanation of what it means exactly...

My use case is SMB sharing. Clients are about 50% macOS, 40% Windows, and 10% Ubuntu. All are using recent versions of the OS.

Thanks.
 

seanm

Guru
Joined
Jun 11, 2018
Messages
570
The GUI doesn't support setting those properties, see:

https://redmine.ixsystems.com/issues/54180
https://redmine.ixsystems.com/issues/71029

So, I've tried to create my pool via the command line. The command succeeded, but even after a reboot, the GUI does not see the pool. I guess I have created it in an incompatibly way, perhaps missing a flag or something? I created it like so:

zpool create -O utf8only=on -O normalization=formD -O casesensitivity=insensitive mypool mirror /dev/ada0 /dev/ada1 mirror /dev/ada2 /dev/ada3

after which zpool status reports something that looks good to me:

Code:
  pool: mypool
 state: ONLINE
  scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    mypool      ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
        ada0    ONLINE       0     0     0
        ada1    ONLINE       0     0     0
      mirror-1  ONLINE       0     0     0
        ada2    ONLINE       0     0     0
        ada3    ONLINE       0     0     0


What command line incantation am I missing to create a pool compatible with the GUI?

Thanks.
 

seanm

Guru
Joined
Jun 11, 2018
Messages
570
So scouring the forums, I've leaned that FreeNAS also keeps pool information in its own database, which is why my manually created pool does not appear in the GUI.

I found a post by someone looking to do as I am: https://forums.freenas.org/index.ph...l-with-normalization-formd.21191/#post-330157 but there's no solution there.

I've grepped the FreeNAS code for 'zpool create' and found an instance in freenas/gui/middleware/notifier.py, is that indeed the code that's run when using Storage > Pools > Add? If so, perhaps my best bet is to hack that file to add in "-O utf8only=on -O normalization=formD -O casesensitivity=insensitive"?
 

Linkman

Patron
Joined
Feb 19, 2015
Messages
219
I believe you can just import your manually created pool into the GUI.
 

Mlovelace

Guru
Joined
Aug 19, 2014
Messages
1,111
One thing you could do, which I would recommend, would be to create the pool through the UI; then set the pool flags manually in the CLI. When you create a dataset check that the flags you're interested in were inherited, and if not set them manually. This way the pool is configured properly using the gptids for the drive partitions, the pool is setup with the proper swap partitions, you are setting up the correct flags for freenas such as (-o cachefile=/data/zfs/zpool.cache -o failmode=continue -o autoexpand=on -O compression=lz4 -O aclmode=passthrough -O aclinherit=passthrough -f -m /<pool name> -o altroot=/mnt <pool name>).

It's easy enough once the pool is created properly to run 'zfs set utf8only=on mypool' 'zfs set normalization=formD mypool' 'zfs set casesensitivity=insensitive mypool' in the CLI.

My two cents, for what it's worth.;)

Edit: Well, nevermind to all that above. I didn't realize those were readonly and could only be set at creation. So, if you are going the manual route then mimic the UI and create a 2G swap partition at the start of each drive then a 2nd partition for data and add that partition to the pool.
 
Last edited:

SweetAndLow

Sweet'NASty
Joined
Nov 6, 2013
Messages
6,421
You're not creating your pool correctly. You need to use gptid's and also partition some room for swap space. If you're going to create your own pool look into issuing freebsd or mimic how freenas excepts things to be created.
 

Mlovelace

Guru
Joined
Aug 19, 2014
Messages
1,111
So to build the pool manually and properly you'll need to setup the partitions in the CLI.
Code:
gpart destroy -F /dev/ada0
gpart destroy -F /dev/ada1
gpart destroy -F /dev/ada2
gpart destroy -F /dev/ada3


Next create labels and partition the disks.

gpart create -s gpt /dev/ada0
gpart add -a 4096 -i 1 -s 2g -t freebsd-swap /dev/ada0
gpart add -a 4096 -i 2 -t freebsd-zfs /dev/ada0
gpart create -s gpt /dev/ada1
gpart add -a 4096 -i 1 -s 2g -t freebsd-swap /dev/ada1
gpart add -a 4096 -i 2 -t freebsd-zfs /dev/ada1
gpart create -s gpt /dev/ada2
gpart add -a 4096 -i 1 -s 2g -t freebsd-swap /dev/ada2
gpart add -a 4096 -i 2 -t freebsd-zfs /dev/ada2
gpart create -s gpt /dev/ada3
gpart add -a 4096 -i 1 -s 2g -t freebsd-swap /dev/ada3
gpart add -a 4096 -i 2 -t freebsd-zfs /dev/ada3


Now get the gptid values for each disk. You'll use these when creating 'mypool'.


glabel status
Name  Status  Components
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada0p1
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada0p2
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada1p1
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada1p2
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada2p1
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada2p2
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada3p1
gptid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX     N/A  ada3p2

You'll need to use the p2 partitions when creating the pool.
So, cd into /dev/gptid then you can tab complete the gptids of the paritions you've identifited above.

Then create your pool.
zpool create -o cachefile=/data/zfs/zpool.cache -o failmode=continue -o autoexpand=on -O compression=lz4 -O aclmode=passthrough -O aclinherit=passthrough -O utf8only=on -O normalization=formD -O casesensitivity=insensitive -f -m /mypool -o altroot=/mnt mypool mirror /dev/gptid/<partition 2 gptid> /dev/gptid/<partition 2 gptid> mirror /dev/gptid/<partition 2 gptid> /dev/gptid/<partition 2 gptid>


Once you created the pool the 'freeNAS' way in the CLI export the pool 'zpool export mypool', then import the pool in the UI.
 

seanm

Guru
Joined
Jun 11, 2018
Messages
570
Thanks for your replies folks, they are appreciated!

After having the idea, I went ahead and added "-O utf8only=on -O normalization=formD -O casesensitivity=insensitive" to notifier.py, and it worked! I think it's less error prone to tweak that one existing command rather than to otherwise try to match what the GUI does.

But back to my original question... :) how does one choose between formC, formD, etc.? I'm inclined towards formD, since it's closer to the behaviour of Mac HFS, and most of my office uses Macs (though few of the Macs use HFS anymore). Still, I've not found a good explanation of how to choose or what the tradeoffs are.
 

Mlovelace

Guru
Joined
Aug 19, 2014
Messages
1,111
Thanks for your replies folks, they are appreciated!

After having the idea, I went ahead and added "-O utf8only=on -O normalization=formD -O casesensitivity=insensitive" to notifier.py, and it worked! I think it's less error prone to tweak that one existing command rather than to otherwise try to match what the GUI does.

But back to my original question... :) how does one choose between formC, formD, etc.? I'm inclined towards formD, since it's closer to the behaviour of Mac HFS, and most of my office uses Macs (though few of the Macs use HFS any more). Still, I've not found a good explanation of how to choose or what the tradeoffs are.
This is what I could find on some mailing lists...

Normalization value - none - normalization-sensitive, names are compared as byte sequences.

Normalization value - formD - normalization-insensitive, both names are normalized to NFD (fully decomposed), and then compared as byte sequences - should be used for interoperability between Windows (which doesn't do any normalization on filenames) and MacOS X (which does normalize filenames and lookups to NFD).

Normalization value - formC - normalization-insensitive, both names are normalized to NFC (NFD + fully composed), In terms of observable effects on the lookup, formC and formD should be functionally equivalent, formC requires an extra step, so it may be slightly slower.
 

seanm

Guru
Joined
Jun 11, 2018
Messages
570
Yeah, I searched the web quite a bit. If formC is functionally equivalent *and* slower, I wonder why it would ever be preferred...
 
Top