Skip to content

Conversation

@behlendorf
Copy link
Contributor

@behlendorf behlendorf commented Nov 8, 2025

Motivation and Context

As final preparation for tagging v2.4.0 verify library version numbers accurately reflects the ABI changes from v2.3.4 -> v2.4.0.

Description

The libzfs_core.so, libnvpair.so and libuutil.so libraries all include additional symbols which were not in the last public release.

For libnvpair.so which adds the nvlist_snprintf() function but doesn't modify or remove any existing symbols I've bumped the -library-info current and age arguments to reflect this is a minor library in the SONAME.

For libzfs_core.so and libuutil.so I've instead hidden the zfs_tunable_* symbols which were added to the internal libspl library and bled through to the libraries. These libraries contain no other ABI changes so the library version no longer needs to be bumped. This also had the advantage that we can do whatever we need with these internal symbols as part of the user space library refactoring.

Marked as a draft, I'll be adding the libzfs and libzpool ABI changes next but I wanted to get feedback on symbol hiding which might be controversial.

Updated with the libzfs6 -> libzfs7 and libzpool6 -> libzpool7 version bump.

Note: For reviewers the checkstyle failure is expected because of the major version bump

How Has This Been Tested?

  • libnvpair: minor version bump
$ abidiff zfs-2.3/.libs/libnvpair.so.3.0.0 zfs-2.4/.libs/libnvpair.so.3.1.0 
Functions changes summary: 0 Removed, 0 Changed, 1 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

1 Added function:

  [A] 'function int nvlist_snprintf(char*, size_t, nvlist_t*, int)'    {nvlist_snprintf}
  • libuutil, libzfsbootenv, libzfs_core: no interface changes.
$ abidiff zfs-2.3/.libs/libuutil.so.3.0.0 zfs-2.4/.libs/libuutil.so.3.0.0 

$ abidiff zfs-2.3/.libs/libzfsbootenv.so.1.0.0 zfs-2.4/.libs/libzfsbootenv.so.1.0.0 

$ abidiff zfs-2.3/.libs/libzfs_core.so.3.0.0 zfs-2.4/.libs/libzfs_core.so.3.0.0 
Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
  • libzfs: significant changes, major version bump (not yet included in this PR)
abidiff v2.3.4 -> v2.4.0-rc3 $ abidiff zfs-2.3/.libs/libzfs.so.6.0.0 zfs-2.4/.libs/libzfs.so.6.0.0 Functions changes summary: 0 Removed, 4 Changed (37 filtered out), 6 Added functions Variables changes summary: 0 Removed, 2 Changed, 0 Added variables

6 Added functions:

[A] 'function size_t zfs_valstr_zio_type(int, char*, size_t)' {zfs_valstr_zio_type}
[A] 'function void zpool_collect_leaves(zpool_handle_t*, nvlist_t*, nvlist_t*)' {zpool_collect_leaves}
[A] 'function int zpool_initialize_one(zpool_handle_t*, void*)' {zpool_initialize_one}
[A] 'function void zpool_refresh_stats_from_handle(zpool_handle_t*, zpool_handle_t*)' {zpool_refresh_stats_from_handle}
[A] 'function int zpool_scan_range(zpool_handle_t*, pool_scan_func_t, pool_scrub_cmd_t, time_t, time_t)' {zpool_scan_range}
[A] 'function int zpool_trim_one(zpool_handle_t*, void*)' {zpool_trim_one}

4 functions with some indirect sub-type change:

[C] 'function uint64_t getprop_uint64(zfs_handle_t*, zfs_prop_t, const char**)' at libzfs_dataset.c:2092:1 has some indirect sub-type changes:
parameter 2 of type 'typedef zfs_prop_t' has sub-type changes:
underlying type 'enum zfs_prop_t' at zfs.h:96:1 changed:
type size hasn't changed
6 enumerator insertions:
'zfs_prop_t::ZFS_PROP_DEFAULTUSERQUOTA' value '100'
'zfs_prop_t::ZFS_PROP_DEFAULTGROUPQUOTA' value '101'
'zfs_prop_t::ZFS_PROP_DEFAULTPROJECTQUOTA' value '102'
'zfs_prop_t::ZFS_PROP_DEFAULTUSEROBJQUOTA' value '103'
'zfs_prop_t::ZFS_PROP_DEFAULTGROUPOBJQUOTA' value '104'
'zfs_prop_t::ZFS_PROP_DEFAULTPROJECTOBJQUOTA' value '105'
1 enumerator change:
'zfs_prop_t::ZFS_NUM_PROPS' from value '100' to '106' at zfs.h:96:1

[C] 'function vdev_prop_t vdev_name_to_prop(const char*)' at zpool_prop.c:490:1 has some indirect sub-type changes:
return type changed:
underlying type 'enum vdev_prop_t' at zfs.h:327:1 changed:
type size hasn't changed
2 enumerator insertions:
'vdev_prop_t::VDEV_PROP_SIT_OUT' value '52'
'vdev_prop_t::VDEV_PROP_AUTOSIT' value '53'
1 enumerator change:
'vdev_prop_t::VDEV_NUM_PROPS' from value '52' to '54' at zfs.h:333:1

[C] 'function boolean_t zfeature_depends_on(spa_feature_t, spa_feature_t)' at zfeature_common.c:149:1 has some indirect sub-type changes:
parameter 1 of type 'typedef spa_feature_t' has sub-type changes:
underlying type 'enum spa_feature' at zfeature_common.h:44:1 changed:
type size hasn't changed
3 enumerator insertions:
'spa_feature::SPA_FEATURE_DYNAMIC_GANG_HEADER' value '44'
'spa_feature::SPA_FEATURE_BLOCK_CLONING_ENDIAN' value '45'
'spa_feature::SPA_FEATURE_PHYSICAL_REWRITE' value '46'
1 enumerator change:
'spa_feature::SPA_FEATURES' from value '44' to '47' at zfeature_common.h:44:1

[C] 'function int zfs_userspace(zfs_handle_t*, zfs_userquota_prop_t, zfs_userspace_cb_t, void*)' at libzfs_dataset.c:4945:1 has some indirect sub-type changes:
parameter 3 of type 'typedef zfs_userspace_cb_t' changed:
underlying type 'int ()(void, const char*, uid_t, uint64_t)' changed:
in pointed to type 'function type int (void*, const char*, uid_t, uint64_t)':
parameter 5 of type 'typedef uint64_t' was added

1 variable with incompatible sub-type changes:

[C] 'zfeature_info_t spa_feature_table[44]' was changed to 'zfeature_info_t spa_feature_table[47]' at zfeature_common.c:54:1:
size of symbol changed from 2464 to 2632
type of variable changed:
array element type 'typedef zfeature_info_t' changed:
underlying type 'struct zfeature_info' at zfeature_common.h:115:1 changed:
type size hasn't changed
2 data member changes (1 filtered):
type of 'spa_feature_t fi_feature' changed, as reported earlier
type of 'const spa_feature_t* fi_depends' changed:
in pointed to type 'const spa_feature_t':
unqualified underlying type 'typedef spa_feature_t' changed at zfeature_common.h:91:1, as reported earlier
type name changed from 'zfeature_info_t[44]' to 'zfeature_info_t[47]'
array type size changed from 19712 to 21056
array type subrange 1 changed length from 44 to 47
array subrange changed:
upper bound of '[44]' change from '43' to '46'

1 Changed variable:

[C] 'const zfs_deleg_perm_tab_t zfs_deleg_perm_tab[]' was changed at zfs_deleg.c:46:1:
size of symbol changed from 528 to 544
type of variable changed:
array element type 'const zfs_deleg_perm_tab_t' changed:
in unqualified underlying type 'typedef zfs_deleg_perm_tab_t' at zfs_deleg.h:88:1:
underlying type 'struct zfs_deleg_perm_tab' at zfs_deleg.h:84:1 changed:
type size hasn't changed
1 data member change:
type of 'zfs_deleg_note_t z_note' changed:
underlying type 'enum zfs_deleg_note_t' at zfs_deleg.h:49:1 changed:
type size hasn't changed
1 enumerator insertion:
'zfs_deleg_note_t::ZFS_DELEG_NOTE_SEND_RAW' value '8'
24 enumerator changes:
'zfs_deleg_note_t::ZFS_DELEG_NOTE_RECEIVE' from value '8' to '9' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_ALLOW' from value '9' to '10' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_USERPROP' from value '10' to '11' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_MOUNT' from value '11' to '12' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_SHARE' from value '12' to '13' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_USERQUOTA' from value '13' to '14' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_GROUPQUOTA' from value '14' to '15' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_USERUSED' from value '15' to '16' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_GROUPUSED' from value '16' to '17' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_USEROBJQUOTA' from value '17' to '18' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_GROUPOBJQUOTA' from value '18' to '19' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_USEROBJUSED' from value '19' to '20' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_GROUPOBJUSED' from value '20' to '21' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_HOLD' from value '21' to '22' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_RELEASE' from value '22' to '23' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_DIFF' from value '23' to '24' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_BOOKMARK' from value '24' to '25' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_LOAD_KEY' from value '25' to '26' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_CHANGE_KEY' from value '26' to '27' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_PROJECTUSED' from value '27' to '28' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_PROJECTQUOTA' from value '28' to '29' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_PROJECTOBJUSED' from value '29' to '30' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_PROJECTOBJQUOTA' from value '30' to '31' at zfs_deleg.h:49:1
'zfs_deleg_note_t::ZFS_DELEG_NOTE_NONE' from value '31' to '32' at zfs_deleg.h:49:1
type size hasn't changed

  • libzpool: extensive changes, not a stable interface, major version bump (not yet included in this PR)

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)
  • Quality assurance (non-breaking change which makes the code more robust against bugs)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv)
  • Documentation (a change to man pages or other documentation)

Checklist:

@behlendorf behlendorf requested review from don-brady and robn November 8, 2025 01:19
@behlendorf behlendorf added Component: Packaging custom packages Status: Code Review Needed Ready for review and testing labels Nov 8, 2025
@github-actions github-actions bot added the Status: Work in Progress Not yet ready for general review label Nov 8, 2025
The nvlist_snprintf() function was added to the ABI of libnvpair.
No other symbols were modified or removed.  Bump the library-info
SONAME current and age args to reflect this is a minor library
version update.

Signed-off-by: Brian Behlendorf <[email protected]>
The zfs_tunable_* functions are a public interface which are
part of the internal libspl convenience library.  They should
be hidden to prevent an unnecessary ABI change in installed
libraries which link against libspl (e.g. libzfs_core, libuutil).

Signed-off-by: Brian Behlendorf <[email protected]>
The ABI of libzfs and libzpool have breaking changes since the
last major release.  Bump the SONAME for the upcoming 2.4 release
branch to libzfs7 and libzpool7.

Signed-off-by: Brian Behlendorf <[email protected]>
Closes openzfs#17911
@behlendorf
Copy link
Contributor Author

@Harry-Chen would you mind reviewing this PR so to make sure we get the version info right for the 2.4 release.

Copy link
Member

@robn robn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with the symbol hiding for zfs_tunable_*; they should and will be unavailable here as soon as they're moved exclusively to libzpool.so anyway.

The rationale for the rest sounds right, and the diff looks plausible, but I'm not up on the fine details of soname changes so call this a "soft" approval.

@behlendorf behlendorf marked this pull request as ready for review November 10, 2025 23:49
@github-actions github-actions bot removed the Status: Work in Progress Not yet ready for general review label Nov 10, 2025
@Harry-Chen
Copy link
Contributor

@behlendorf Thanks! Overall the changes LGTM, with only one minor comment: it is not common to define header guard macros (_SYS_TUNABLES_H) to somethinig conrete. Maybe use some other names would be better?

The hiding of zfs_tunable_* symbols, however, remind me of some existing facts: some symbols from statically-linked libraries are leaked into public interface libraries (e.g. libzfs, libzpool). For example, we have (not comprehensive):

  • atomic_* functions from libspl into libzfs, libzpool
  • avl_* funcitons from zcommon into libzfs, libzpool
  • many crypto-related functions and constants from avl, icp, zcommon to libzpool
  • ... any more

IHMO these symbols are only used internally, thus not meant to be exported to the rest of the userland. Hidding them will relieve more pressure from maintaining ABI stability, both for upstream (openzfs) and downstream (distros).

The common way to do this is to compile with -fvisibility=hidden, and to add explicit default visibility to all symbols that should be exported. This might require some work, but I think it is worthwhile for the future, and also appropriate for the time since we are having SONAME bumps anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component: Packaging custom packages Status: Code Review Needed Ready for review and testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants