Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "features" property for zpool feature sets. #10980

Closed
wants to merge 1 commit into from
Closed

Add "features" property for zpool feature sets. #10980

wants to merge 1 commit into from

Conversation

colmbuckley
Copy link
Contributor

@colmbuckley colmbuckley commented Sep 25, 2020

Motivation and Context

With the advent of zpool features, it is sometimes desirable to specify 'sets' of features to be applied to a zpool - for example, "all features supported by the current version of grub" and to limit the features applied by (eg) zpool create or zpool upgrade to not inadvertently enable unwanted features (in the case of grub incompatibility, this might result in an unbootable system).

Ubuntu have addressed this by hard-coding the pool name bpool to be immune to zpool upgrade and suppressing the warning about disabled features in zpool status when this pool name is encountered. Obviously, this is a very limited way of solving the problem.

After a discussion with @rlaager on the Debian ZFS package maintainers mailing list, I became aware of the "default features" proposal discussed at the OpenZFS leadership team meeting of 2019-03-26. This PR is an attempt to implement the necessary functionality.

Description

An on-disk zpool property "features" is added, with the enum value ZPOOL_PROP_FEATURES.
This property may be unset, take one of the special values all or none, or be set to a "feature set" name.
Feature sets refer to files in the current filesystem, either absolute pathnames, or relative to /etc/zfs/features.d (as currently implemented).
If the referenced file exists, the desired features are loaded from it; it is expected to contain the user-facing feature names, whitespace or comma-separated. Comments are allowed.
If a valid feature set is read, zpool create modifies its behavior to only apply features present in the set. (the -d flag inhibits automatic feature creation as usual), and zpool upgrade modifies its behavior likewise. zpool status will not print warnings about disabled features unless they are present in the set. The intention is that, when a feature set is specified, only those features are considered to be "all features" for the zpool command.

Example:

# cat /etc/zfs/features.d/grub
# Only features which are supported by GRUB2
async_destroy
bookmarks
embedded_data
empty_bpobj
enabled_txg
extensible_dataset
filesystem_limits
hole_birth
large_blocks
lz4_compress
spacemap_histogram
userobj_accounting
# zpool create -o ashift=12 -o features=grub -O mountpoint=/ -R /mnt bootpool /dev/disk/bootdisk

Key Implementation Details

In zpool_main.c, watch out for the features property and populate a boolean array of desired features when it is seen. When this occurs, modify the behavior of the zpool_do_create() function. In upgrade_enable_all(), explicitly look up this property and only apply features which are present in the set.

In libzfs_pool.c add the function zpool_load_features() which, given a feature property value, locates and reads the specified file, matching keywords against feature unames, and populating a boolean array with TRUE/FALSE accordingly. This function is called in zpool_valid_proplist() to validate that the property file is present and correct.

In libzfs_status.c, the check_status() function is modified to likewise read the features property, load the relevant feature sets, and only flag missing features if they are present in the set. Note that I needed to pass the features property explicitly in to this function, as I could find no way to retrieve it using just the config nvlist which was passed in. Someone more familiar with the data structures might be able to suggest a cleaner approach here.

Things I'm unsure about...

The features property is always shown as default source in zpool get for pools where it is set; I couldn't determine exactly how this happens (vs. local which is what I'd expect).

I have not had time to understand the test infrastructure for this project, so there are no unit tests for this specific functionality.

The interaction between the features property and the -d flag in zpool create is not quite as was previously discussed; after a little back and forth, I feel that my implementation is most consistent.

How Has This Been Tested?

This only affects the operation of the command-line zpool create, zpool upgrade and zpool status commands (with a smaller influence on zpool import). I created various pools with suitable combinations of the -d flag, the -o features property, features files containing valid and invalid feature names, and verified that correct behavior resulted in all cases. Similarly, the behavior of zpool upgrade was observed to work as designed.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation (a change to man pages or other documentation)

Checklist:

@ahrens
Copy link
Member

ahrens commented Sep 25, 2020

@colmbuckley Thanks for getting started on this! I know @jpaetzel is hoping to work on this at the OpenZFS Developer Summit hackathon on October 7. Will you be able to coordinate with him then?

@colmbuckley
Copy link
Contributor Author

@colmbuckley Thanks for getting started on this! I know @jpaetzel is hoping to work on this at the OpenZFS Developer Summit hackathon on October 7. Will you be able to coordinate with him then?

I don't know to be honest what my schedule looks like that week, but I'd of course be perfectly happy to chat with him before then to see whether this PR can be the basis for a final version. I am happy with the functionality at the moment, although my unfamiliarity with the code base and data structures might have led to some inelegance in how things can best be achieved.

I of course encourage him and anyone else to give the function a test drive; it wasn't as difficult in the end as I'd feared.

@colmbuckley
Copy link
Contributor Author

@colmbuckley Thanks for getting started on this! I know @jpaetzel is hoping to work on this at the OpenZFS Developer Summit hackathon on October 7. Will you be able to coordinate with him then?

Oh; I'm sorry I hadn't seen the proposed agenda; I certainly didn't intend to step on Josh's toes by charging ahead with a full implementation before discussion. If this implementation is useful as the basis of work at the hackathon, I'd be delighted (it especially needs a good test suite), or if it's thought to be a dead-end, that's also fine.

I think the main innovation in my implementation is the concept of storing each feature set in a separate file; allowing for greater flexibility in comments and explanatory text, and also allowing packaged software like grub to supply and maintain its own compatible feature lists without treading on the toes of other packages.

@colmbuckley
Copy link
Contributor Author

Quick sample use:

# dd if=/dev/zero of=loopdev bs=1M count=256
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 0.458312 s, 586 MB/s
# losetup -f --show loopdev
/dev/loop0
# cat /etc/zfs/features.d/grub
# Features compatible with grub
async_destroy
bookmarks
embedded_data
empty_bpobj
enabled_txg
extensible_dataset
filesystem_limits
hole_birth
large_blocks
lz4_compress
spacemap_histogram
userobj_accounting
resilver_defer
# zpool create -o features=grub tpool loop0
# zpool get all tpool | grep feature
tpool  features                       grub                           default
tpool  feature@async_destroy          enabled                        local
tpool  feature@empty_bpobj            enabled                        local
tpool  feature@lz4_compress           active                         local
tpool  feature@multi_vdev_crash_dump  disabled                       local
tpool  feature@spacemap_histogram     active                         local
tpool  feature@enabled_txg            active                         local
tpool  feature@hole_birth             active                         local
tpool  feature@extensible_dataset     active                         local
tpool  feature@embedded_data          active                         local
tpool  feature@bookmarks              enabled                        local
tpool  feature@filesystem_limits      enabled                        local
tpool  feature@large_blocks           enabled                        local
tpool  feature@large_dnode            disabled                       local
tpool  feature@sha512                 disabled                       local
tpool  feature@skein                  disabled                       local
tpool  feature@edonr                  disabled                       local
tpool  feature@userobj_accounting     active                         local
tpool  feature@encryption             disabled                       local
tpool  feature@project_quota          disabled                       local
tpool  feature@device_removal         disabled                       local
tpool  feature@obsolete_counts        disabled                       local
tpool  feature@zpool_checkpoint       disabled                       local
tpool  feature@spacemap_v2            disabled                       local
tpool  feature@allocation_classes     disabled                       local
tpool  feature@resilver_defer         enabled                        local
tpool  feature@bookmark_v2            disabled                       local
tpool  feature@redaction_bookmarks    disabled                       local
tpool  feature@redacted_datasets      disabled                       local
tpool  feature@bookmark_written       disabled                       local
tpool  feature@log_spacemap           disabled                       local
tpool  feature@livelist               disabled                       local
tpool  feature@device_rebuild         disabled                       local
tpool  feature@zstd_compress          disabled                       local
# zpool upgrade tpool
This system supports ZFS pool feature flags.

Pool 'tpool' already has all supported/requested features enabled.
# zpool status tpool
  pool: tpool
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        tpool       ONLINE       0     0     0
          loop0     ONLINE       0     0     0

errors: No known data errors
# zpool set feature@zstd_compress=enabled tpool
# zpool set features=all tpool
# zpool upgrade tpool
This system supports ZFS pool feature flags.

Enabled the following features on 'tpool':
  multi_vdev_crash_dump
  large_dnode
  sha512
  skein
  edonr
  encryption
  project_quota
  device_removal
  obsolete_counts
  zpool_checkpoint
  spacemap_v2
  allocation_classes
  bookmark_v2
  redaction_bookmarks
  redacted_datasets
  bookmark_written
  log_spacemap
  livelist
  device_rebuild

# zpool status tpool
  pool: tpool
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        tpool       ONLINE       0     0     0
          loop0     ONLINE       0     0     0

errors: No known data errors

Another using -d; same loop device setup:

# zpool create -d -o features=grub tpool loop0
# zpool get all tpool | grep feature
tpool  features                       grub                           default
tpool  feature@async_destroy          disabled                       local
tpool  feature@empty_bpobj            disabled                       local
tpool  feature@lz4_compress           disabled                       local
tpool  feature@multi_vdev_crash_dump  disabled                       local
tpool  feature@spacemap_histogram     disabled                       local
tpool  feature@enabled_txg            disabled                       local
tpool  feature@hole_birth             disabled                       local
tpool  feature@extensible_dataset     disabled                       local
tpool  feature@embedded_data          disabled                       local
tpool  feature@bookmarks              disabled                       local
tpool  feature@filesystem_limits      disabled                       local
tpool  feature@large_blocks           disabled                       local
tpool  feature@large_dnode            disabled                       local
tpool  feature@sha512                 disabled                       local
tpool  feature@skein                  disabled                       local
tpool  feature@edonr                  disabled                       local
tpool  feature@userobj_accounting     disabled                       local
tpool  feature@encryption             disabled                       local
tpool  feature@project_quota          disabled                       local
tpool  feature@device_removal         disabled                       local
tpool  feature@obsolete_counts        disabled                       local
tpool  feature@zpool_checkpoint       disabled                       local
tpool  feature@spacemap_v2            disabled                       local
tpool  feature@allocation_classes     disabled                       local
tpool  feature@resilver_defer         disabled                       local
tpool  feature@bookmark_v2            disabled                       local
tpool  feature@redaction_bookmarks    disabled                       local
tpool  feature@redacted_datasets      disabled                       local
tpool  feature@bookmark_written       disabled                       local
tpool  feature@log_spacemap           disabled                       local
tpool  feature@livelist               disabled                       local
tpool  feature@device_rebuild         disabled                       local
tpool  feature@zstd_compress          disabled                       local
# zpool status tpool
  pool: tpool
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
        still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
        the pool may no longer be accessible by software that does not support
        the features. See zpool-features(5) for details.
config:

        NAME        STATE     READ WRITE CKSUM
        tpool       ONLINE       0     0     0
          loop0     ONLINE       0     0     0

errors: No known data errors
# zpool set feature@zstd_compress=enabled tpool
# zpool upgrade tpool
This system supports ZFS pool feature flags.

Enabled the following features on 'tpool':
  async_destroy
  empty_bpobj
  lz4_compress
  spacemap_histogram
  enabled_txg
  hole_birth
  embedded_data
  bookmarks
  filesystem_limits
  large_blocks
  userobj_accounting
  resilver_defer

# zpool status tpool
  pool: tpool
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        tpool       ONLINE       0     0     0
          loop0     ONLINE       0     0     0

errors: No known data errors

Adding a feature by adding it to the file:

# echo zpool_checkpoint >> /etc/zfs/features.d/grub 
# zpool status tpool
  pool: tpool
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
        still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
        the pool may no longer be accessible by software that does not support
        the features. See zpool-features(5) for details.
config:

        NAME        STATE     READ WRITE CKSUM
        tpool       ONLINE       0     0     0
          loop0     ONLINE       0     0     0

errors: No known data errors
# zpool upgrade tpool
This system supports ZFS pool feature flags.

Enabled the following features on 'tpool':
  zpool_checkpoint

man/man8/zpoolprops.8 Outdated Show resolved Hide resolved
@colmbuckley
Copy link
Contributor Author

It's not clear to me why zimport.sh is failing in some of the tests. Will see if I can replicate locally next week.

@colmbuckley
Copy link
Contributor Author

It's not clear to me why zimport.sh is failing in some of the tests. Will see if I can replicate locally next week.

... found a strcmp before a NULL check. Hopefully that's the issue; will take another look on Monday.

@behlendorf behlendorf added the Status: Code Review Needed Ready for review and testing label Sep 25, 2020
@colmbuckley
Copy link
Contributor Author

The test failures don't seem related to any of the code in this PR; can anyone confirm that?

@behlendorf One thing I do need help with; I couldn't fully grasp the relationship between zpool properties as added to the zpool_prop_t enum and registered with zprop_register_string, and properties added as ZPOOL_CONFIG_* #defines and manipulated in spa_config_generate, spa_prop_get_config etc. - there does not seem to be a 1:1 correspondence. I haven't touched the spa config stuff in this PR, but I suspect something does need to be done there. Is this related to the "source" of this property always showing as default even when explicitly set on a pool?

@codecov
Copy link

codecov bot commented Sep 28, 2020

Codecov Report

Merging #10980 into master will decrease coverage by 0.02%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #10980      +/-   ##
==========================================
- Coverage   79.56%   79.54%   -0.03%     
==========================================
  Files         398      398              
  Lines      125754   125754              
==========================================
- Hits       100060   100025      -35     
- Misses      25694    25729      +35     
Flag Coverage Δ
kernel 80.41% <ø> (-0.08%) ⬇️
user 64.27% <ø> (-0.75%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
cmd/zpool/zpool_main.c 80.97% <ø> (+0.02%) ⬆️
lib/libzfs/libzfs_pool.c 73.12% <ø> (ø)
lib/libzfs/libzfs_status.c 96.18% <ø> (ø)
module/zfs/spa.c 87.31% <ø> (+0.10%) ⬆️
cmd/zvol_id/zvol_id_main.c 76.31% <0.00%> (-5.27%) ⬇️
module/zfs/bpobj.c 86.86% <0.00%> (-3.76%) ⬇️
module/zfs/vdev_removal.c 93.66% <0.00%> (-3.06%) ⬇️
module/zfs/vdev_indirect_mapping.c 96.61% <0.00%> (-1.94%) ⬇️
module/zfs/zap_micro.c 85.35% <0.00%> (-1.26%) ⬇️
module/zfs/vdev_indirect.c 72.25% <0.00%> (-1.17%) ⬇️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3928ec5...9a3ec8b. Read the comment docs.

@ahrens
Copy link
Member

ahrens commented Sep 28, 2020

Thanks for coding this up!

I think we'll want to also add some feature-set files and an explanation of them. Here's a link to my proposal from December 2018. That said, this is kind of orthogonal to the implementation, so we can keep those discussions separate if you like. Perhaps we should open another PR to add the feature-set files and documentation related to the rules around them.

@colmbuckley
Copy link
Contributor Author

Would you please add this to the 2.0 series too?

That's up to the release maintainers. I suspect we don't want to hold up 2.0.0 for this feature, but I'd hope that it'd be able to merge fairly soon. There's a few things I'm still slightly unsure about, and I'd like to see better tests etc. but hopefully it's not in terrible shape.

@colmbuckley
Copy link
Contributor Author

Thanks for coding this up!

I think we'll want to also add some feature-set files and an explanation of them. Here's a link to my proposal from December 2018. That said, this is kind of orthogonal to the implementation, so we can keep those discussions separate if you like. Perhaps we should open another PR to add the feature-set files and documentation related to the rules around them.

Yes, I'd like to see a nice suite of feature sets supplied with the standard distribution; and this can proceed, I think, largely independently of the code support.

Your proposal does suggest modifying the default behavior of zpool create to start with a conservative feature set; this would be fairly easy to achieve (the relevant logic in zpool_main.c is not complex). We could default to "none", hard-code a specific set (there's a boolean array which indicates which ones are chosen), or trust that a suitable default feature file be supplied with the distribution.

@ahrens
Copy link
Member

ahrens commented Sep 28, 2020

@colmbuckley I'm not sure we would want to change the default immediately, but when we do change it, I'd propose features=portable (i.e. features that are supported by the current release of all tier-1 platforms)

@colmbuckley
Copy link
Contributor Author

I'd like to hear from @jpaetzel regarding whether this is in any way in line with his thoughts in the lead-up to the Developer Summit. I regret that I wasn't aware of his existing effort before coding this up, but if it's useful to the broader picture, it's given with a glad heart.

Josh?

@jpaetzel
Copy link

I'm getting slammed at work, I'll take a look at all this over the weekend.

@behlendorf behlendorf added Status: Work in Progress Not yet ready for general review and removed Status: Code Review Needed Ready for review and testing labels Oct 3, 2020
@adilger
Copy link
Contributor

adilger commented Oct 7, 2020

One thing to consider here is that "features supported by grub" is itself not going to be static over time. It would be better, IMHO, to make this feature list for a specific version of grub from the beginning (e.g. "grub-2.0"), so that as newer versions are added (presumably with more features) there doesn't need to be an "either/or" situation in the single "grub" feature list.

@ghfields
Copy link
Contributor

ghfields commented Oct 7, 2020

Would it be possible to allow something like "-o feature=freenas11.2+ubuntu18.04" and it determines commonality for you (as long as there was a profile for each in the directory)?

@ghfields
Copy link
Contributor

ghfields commented Oct 7, 2020

One thing to consider here is that "features supported by grub" is itself not going to be static over time. It would be better, IMHO, to make this feature list for a specific version of grub from the beginning (e.g. "grub-2.0"), so that as newer versions are added (presumably with more features) there doesn't need to be an "either/or" situation in the single "grub" feature list.

I agree. Minimally, it should be called "grub2" and if grub ever adds more feature flags (its been May 2015 since last addition) we can add another profile.

@rlaager
Copy link
Member

rlaager commented Oct 7, 2020

One thing to consider here is that "features supported by grub" is itself not going to be static over time.

Agreed.

It would be better, IMHO, to make this feature list for a specific version of grub from the beginning (e.g. "grub-2.0"), so that as newer versions are added (presumably with more features) there doesn't need to be an "either/or" situation in the single "grub" feature list.

I disagree, at least to some extent.

To me, having the generic "grub" (or to be more correct, you can substitute "grub2") is an important feature. The idea is that "grub" means "whatever GRUB supports on my system". This is accomplished by having the feature definition of "grub" be a separate file which is installed by the GRUB package (initially e.g. the grub2 distro package on Ubuntu, but ideally GRUB upstream). That way, it is updated independent of the OpenZFS package (and release cycle) and always matches GRUB. Then if I upgrade my system from GRUB 2.0x to 2.0y and the feature list changes, zpool status and zpool upgrade will start offering me the new features on my bpool. But I should not be required to go manually run zpool set features=grub-2.0y. That halfway defeats the point.

One might argue that we should have both grub-2 and grub-2.0x. I see a few problems with that, though. First off, unless we introduce some alias mechanism (which might be a good idea anyway), this would lead to a lot of duplication of feature definitions (and files; see below). But setting that aside, what is the use case? Even if you are dual booting, you're still only going to have one copy of GRUB, which more-or-less has to be managed by one boot environment.

Also, right now, it sounds like the feature definitions are single files. I wonder if we should support multiple feature definitions per file.

@ericloewe
Copy link

Just going through major versions of relevant platforms/distributions there are easily over 30 lists of features, if they were all included. I think that declaring multiple strings for the same list (e.g. FreeNAS 11.0, FreeNAS 11.1, FreeBSD 11.0 and FreeBSD 11.1 support the same feature flags) might be useful to cut down on the spam a bit.

@ghfields
Copy link
Contributor

ghfields commented Oct 8, 2020

@rlaager This is intended to ensure compatibility with other systems following the creation of pools. To do this, one would target certain OS/distro/zfs release or a compatibility year. For this to be successful there has to be an extensive profile library on the system that is creating the pool. Grub is the only "application", beyond ZFS itself, I can recall that cares about feature flags. Also, there may be people would want to create a pool while on a non-grub system, yet would want to limit flags so it could be compatible with grub in the future. Since ZFS upstream would need to keep track of all the other cases, a grub2 profile wouldn't be difficult to also keep (it hasn't changed in 5 years).

While I can see the advantage of upgrading to an improved version of grub and having its install package automatically change the available grub feature flags and allowing a zpool upgrade, I don't see this being useful in any other scenarios. Automatic actions when past explicit protective actions were taken could lead to problems. Even with a distro upgrade, the running operating system cannot ascertain why the current restriction is in place. Was it because of a multi-boot situation? Was it to allow mounting in a different OS? Having the user explicitly do a "zpool set features=" seems to be little burden and allows the user to confirm that lesser restrictions are appropriate.

@rlaager
Copy link
Member

rlaager commented Oct 8, 2020

@rlaager This is intended to ensure compatibility with other systems following the creation of pools. To do this, one would target certain OS/distro/zfs release or a compatibility year. For this to be successful there has to be an extensive profile library on the system that is creating the pool.

features=grub is a very different use case than the "main" use of this for things like features=portable. My previous comments were strictly for the "grub" case. I'm not against ZFS shipping e.g. various portable-YYYY definitions as was proposed.

Also, there may be people would want to create a pool while on a non-grub system, yet would want to limit flags so it could be compatible with grub in the future.

GRUB's feature set is very limited (and as you noted, not changing much), so modern practice is to use a separate bpool for /boot so that GRUB can access it. This allows the root pool to use all features (including notably things like encryption). It is extremely unlikely that anyone would care to "future-proof" a general purpose pool or even a root pool to allow access by GRUB. Nor would anyone create an otherwise unnecessary bpool. If you want to future proof for the possibility of a future bpool, you can do that by creating the partition and putting nothing on it.

@colmbuckley
Copy link
Contributor Author

To me, having the generic "grub" (or to be more correct, you can substitute "grub2") is an important feature. The idea is that "grub" means "whatever GRUB supports on my system". This is accomplished by having the feature definition of "grub" be a separate file which is installed by the GRUB package (initially e.g. the grub2 distro package on Ubuntu, but ideally GRUB upstream). That way, it is updated independent of the OpenZFS package (and release cycle) and always matches GRUB. Then if I upgrade my system from GRUB 2.0x to 2.0y and the feature list changes, zpool status and zpool upgrade will start offering me the new features on my bpool. But I should not be required to go manually run zpool set features=grub-2.0y. That halfway defeats the point.

Yes, this is pretty much what I had in mind also; a situation whereby some feature files (eg: "portable") are maintained and distributed by core OpenZFS, and some (eg: "grub2") which are maintained by those packages (or by their per-distro packaging teams). Note of course that individual installations are able (trivially) to edit or add their own feature files, or simply to add or remove specific features to their zpools as needed; feature files are largely a convenience feature.

Also, right now, it sounds like the feature definitions are single files. I wonder if we should support multiple feature definitions per file.

I chose the current implementation largely for simplicity; it keeps the parsing logic extremely straightforward, allows for very rapid sanity-checking and error detection, while satisfying all the use cases I could easily think of. I can imagine several potential extensions, such as allowing #include-like functionality, or a more complex file format based on a "setX = foo, bar, baz" syntax, but this comes with a substantial step-increase in complexity of the parsing function, and associated faff around accurate reporting of errors etc.

What would be gained, do you think, by having multiple feature definitions per file?

@colmbuckley
Copy link
Contributor Author

Would it be possible to allow something like "-o feature=freenas11.2+ubuntu18.04" and it determines commonality for you (as long as there was a profile for each in the directory)?

Yes, this would certainly be possible; again at the slight expense of code complexity. The actual parsing is easy, the main difficulty is in coherent error reporting. I'd be slightly concerned about the distinction between AND and OR combinations; and the possibility of getting this wrong either in the code, or as an admin.

@colmbuckley
Copy link
Contributor Author

Just going through major versions of relevant platforms/distributions there are easily over 30 lists of features, if they were all included. I think that declaring multiple strings for the same list (e.g. FreeNAS 11.0, FreeNAS 11.1, FreeBSD 11.0 and FreeBSD 11.1 support the same feature flags) might be useful to cut down on the spam a bit.

ln -s FreeBSD-11 FreeBSD-11.1 feels like a fairly elegant way to address this? "Real" files in /etc/zfs/features.d refer to base OS features, with symlinks to those files referring to fully-compatible derived distributions.

@colmbuckley
Copy link
Contributor Author

Aside from the great discussion about the UI; has anyone got any comments on the code? In particular, I have to say I still don't really know whether this property needs to be added as a ZPOOL_CONFIG #define and the spa data structure or logic; the narrative there eludes me. I also suspect I'm missing something as the property always shows as "default" instead of "local" in zpool get; if anyone groks the logic there you could save me a great deal of code-scrutinizing time...

@ericloewe
Copy link

I'd be slightly concerned about the distinction between AND and OR combinations; and the possibility of getting this wrong either in the code, or as an admin.

Would OR ever be useful? Realistically, users might say "I want to run on A, B and C" and it feels at least somewhat weird to me to say "I want to run on something else but don't particularly care if it's B or C". Supporting just AND simplifies things a bit.

Another concern I have is that relying on these files being present on all systems might confuse users. If I'm reading this right, the current behavior is to error out of zpool upgrade if the file can't be read. Is the intent then that the user set the property to a file which does exist on the new system (or clear it entirely) in order to proceed?

@adilger
Copy link
Contributor

adilger commented Oct 8, 2020

Would OR ever be useful? Realistically, users might say "I want to run on A, B and C"
and it feels at least somewhat weird to me to say "I want to run on something else but
don't particularly care if it's B or C". Supporting just AND simplifies things a bit.

Agreed, I don't see a sensible use for OR here. You'd always want the common subset.

Another concern I have is that relying on these files being present on all systems might
confuse users. If I'm reading this right, the current behavior is to error out of zpool
upgrade if the file can't be read. Is the intent then that the user set the property to a file
which does exist on the new system (or clear it entirely) in order to proceed?

These files only need to exist on the system where the pool create or upgrade is done.
It would be useful for the ZFS package to include them from different distros, on the
assumption that the feature set supported by freenas11.2 or ubuntu18.04 does
not change over time, only when a new release like ubuntu20.04 is made. Distro
updates and users can add files in /etc/zfs/features.d/ until it is available via ZFS.

@rlaager
Copy link
Member

rlaager commented Oct 8, 2020

If I'm reading this right, the current behavior is to error out of zpool upgrade if the file can't be read. Is the intent then that the user set the property to a file which does exist on the new system (or clear it entirely) in order to proceed?

That seems reasonable to me. If the file does not exist, the features mask cannot be enforced. At that point, zpool upgrade can either do the upgrade or refuse. If it does the upgrade, that could easily violate the features mask that the user asked for.

A corollary is that feature definitions are not expected to go away. So we should be somewhat judicious in the features groups we create.

@colmbuckley
Copy link
Contributor Author

Added the relevant bits to the spa_t structure, with suitable copying / freeing and validation logic (largely by copying the code and workflow for spa_comment).

Note that it's not possible in spa_prop_validate() to fully validate whether we have a functioning features flag, so we just test for a plausible pathname by checking that it's made of printable characters. A better test might be possible here, not sure whether it's necessary.

@colmbuckley
Copy link
Contributor Author

Would OR ever be useful? Realistically, users might say "I want to run on A, B and C" and it feels at least somewhat weird to me to say "I want to run on something else but don't particularly care if it's B or C". Supporting just AND simplifies things a bit.

Agreed, ok. Working on this feature; it'll be something like -o features=grub,FreeBSD-11 - ie: multiple featuresets, comma-separated.

@colmbuckley colmbuckley marked this pull request as ready for review October 16, 2020 16:25
@colmbuckley
Copy link
Contributor Author

Ok; I think this is where it needs to be for review.

Note to reviewers: the bulk of the additional logic is the zpool_load_features function at the end of libzfs_zpool.c - this splits the features property into filenames (after checking for special cases), parses each file, combines the results, and fills a boolean array to indicate which features are requested. Logic in zpool-upgrade, zpool-create and zpool-status checks this array to modify behavior accordingly.

Let me know what you think.

@colmbuckley
Copy link
Contributor Author

@behlendorf One thing I do need help with; I couldn't fully grasp the relationship between zpool properties as added to the zpool_prop_t enum and registered with zprop_register_string, and properties added as ZPOOL_CONFIG_* #defines and manipulated in spa_config_generate, spa_prop_get_config etc. - there does not seem to be a 1:1 correspondence. I haven't touched the spa config stuff in this PR, but I suspect something does need to be done there. Is this related to the "source" of this property always showing as default even when explicitly set on a pool?

Much code spelunking later, I think I grok this, and all looks good now.

@behlendorf behlendorf self-requested a review October 20, 2020 16:14
Signed-off-by: Colm Buckley <colm@tuatha.org>
@colmbuckley
Copy link
Contributor Author

(A little confused by the test failures; it seems that the new tests are being run with the old code?)

@colmbuckley
Copy link
Contributor Author

Apologies to anyone who may have been watching this in anticipation; I hit some personal roadblocks preventing work through much of Q4/2020. I will be able to resume work on this shortly, although it might take some time to rebase cleanly against current head.

@colmbuckley
Copy link
Contributor Author

New version of this PR is #11468

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Work in Progress Not yet ready for general review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants