]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Support for longnames for files/directories (Linux part)
authorSanjeev Bagewadi <sanjeev.bagewadi@nutanix.com>
Fri, 18 Jun 2021 08:55:01 +0000 (08:55 +0000)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 1 Oct 2024 20:40:27 +0000 (13:40 -0700)
This patch adds the ability for zfs to support file/dir name up to 1023
bytes. This number is chosen so we can support up to 255 4-byte
characters. This new feature is represented by the new feature flag
feature@longname.

A new dataset property "longname" is also introduced to toggle longname
support for each dataset individually. This property can be disabled,
even if it contains longname files. In such case, new file cannot be
created with longname but existing longname files can still be looked
up.

Note that, to my knowledge native Linux filesystems don't support name
longer than 255 bytes. So there might be programs not able to work with
longname.

Note that NFS server may needs to use exportfs_get_name to reconnect
dentries, and the buffer being passed is limit to NAME_MAX+1 (256). So
NFS may not work when longname is enabled.

Note, FreeBSD vfs layer imposes a limit of 255 name lengh, so even
though we add code to support it here, it won't actually work.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Chunwei Chen <david.chen@nutanix.com>
Closes #15921

41 files changed:
cmd/zdb/zdb.c
cmd/zhack.c
include/os/freebsd/zfs/sys/zfs_vfsops_os.h
include/os/freebsd/zfs/sys/zfs_znode_impl.h
include/os/linux/zfs/sys/zfs_vfsops_os.h
include/os/linux/zfs/sys/zfs_vnops_os.h
include/sys/fs/zfs.h
include/sys/zap.h
include/sys/zfs_ioctl.h
include/zfeature_common.h
lib/libzfs/libzfs.abi
man/man7/zpool-features.7
module/os/freebsd/zfs/zfs_dir.c
module/os/freebsd/zfs/zfs_vfsops.c
module/os/freebsd/zfs/zfs_vnops_os.c
module/os/freebsd/zfs/zfs_znode_os.c
module/os/linux/zfs/zfs_dir.c
module/os/linux/zfs/zfs_vfsops.c
module/os/linux/zfs/zfs_vnops_os.c
module/os/linux/zfs/zpl_export.c
module/os/linux/zfs/zpl_inode.c
module/zcommon/zfeature_common.c
module/zcommon/zfs_prop.c
module/zfs/dmu_recv.c
module/zfs/dmu_send.c
module/zfs/dsl_dataset.c
module/zfs/dsl_dir.c
module/zfs/zap.c
module/zfs/zap_micro.c
module/zfs/zfs_ioctl.c
module/zfs/zfs_znode.c
tests/runfiles/linux.run
tests/zfs-tests/tests/Makefile.am
tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
tests/zfs-tests/tests/functional/longname/cleanup.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/longname/longname_001_pos.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/longname/longname_002_pos.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/longname/longname_003_pos.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/longname/setup.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/rsend/rsend.kshlib
tests/zfs-tests/tests/functional/rsend/send-c_longname.ksh [new file with mode: 0755]

index 83f79ad65613c79ea339bd2dbd244d9f1eb5d210..f185e24601cb4c1a163f07a122028ca90e0e9d85 100644 (file)
@@ -1117,7 +1117,7 @@ dump_zap(objset_t *os, uint64_t object, void *data, size_t size)
 {
        (void) data, (void) size;
        zap_cursor_t zc;
-       zap_attribute_t *attrp = zap_attribute_alloc();
+       zap_attribute_t *attrp = zap_attribute_long_alloc();
        void *prop;
        unsigned i;
 
@@ -1365,7 +1365,7 @@ dump_zpldir(objset_t *os, uint64_t object, void *data, size_t size)
 {
        (void) data, (void) size;
        zap_cursor_t zc;
-       zap_attribute_t *attrp = zap_attribute_alloc();
+       zap_attribute_t *attrp = zap_attribute_long_alloc();
        const char *typenames[] = {
                /* 0 */ "not specified",
                /* 1 */ "FIFO",
index 77284b8955ed4858ac4d5d31d577e527d97fea81..f297afb65d47a38ffad6324818ee78e64d0435d5 100644 (file)
@@ -203,7 +203,7 @@ static void
 dump_obj(objset_t *os, uint64_t obj, const char *name)
 {
        zap_cursor_t zc;
-       zap_attribute_t *za = zap_attribute_alloc();
+       zap_attribute_t *za = zap_attribute_long_alloc();
 
        (void) printf("%s_obj:\n", name);
 
index 3e54f3e846f78affae98cbbec76983770afebbe6..9fbca35cde8c5d21b77698bc17b13a0a29599fc2 100644 (file)
@@ -83,6 +83,7 @@ struct zfsvfs {
        boolean_t       z_use_sa;       /* version allow system attributes */
        boolean_t       z_xattr_sa;     /* allow xattrs to be stores as SA */
        boolean_t       z_use_namecache; /* make use of FreeBSD name cache */
+       boolean_t       z_longname;     /* Dataset supports long names */
        uint8_t         z_xattr;        /* xattr type in use */
        uint64_t        z_version;      /* ZPL version */
        uint64_t        z_shares_dir;   /* hidden shares dir */
index 050fc3036f87b4995ba298456c4b2df72b1c2b10..3727dca0f8d7d022bd074c3cb65a33536e3ba4a1 100644 (file)
@@ -179,7 +179,7 @@ extern void zfs_znode_free(struct znode *);
 extern zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE];
 
 extern int zfs_znode_parent_and_name(struct znode *zp, struct znode **dzpp,
-    char *buf);
+    char *buf, uint64_t buflen);
 
 extern int zfs_rlimit_fsize(off_t fsize);
 #ifdef __cplusplus
index b4d5db21f5e59e6daf52aed422df4d743bafeb05..e742e8dc392ee1cc7fec068b03e8e30dccddd09b 100644 (file)
@@ -118,6 +118,7 @@ struct zfsvfs {
        boolean_t       z_xattr_sa;     /* allow xattrs to be stores as SA */
        boolean_t       z_draining;     /* is true when drain is active */
        boolean_t       z_drain_cancel; /* signal the unlinked drain to stop */
+       boolean_t       z_longname;     /* Dataset supports long names */
        uint64_t        z_version;      /* ZPL version */
        uint64_t        z_shares_dir;   /* hidden shares dir */
        dataset_kstats_t        z_kstat;        /* fs kstats */
index f34eb153f546541412f768a7195ac05571c7cb7c..db33eda577053e724f3808528727cb06b04c7118 100644 (file)
@@ -44,6 +44,7 @@ extern int zfs_write_simple(znode_t *zp, const void *data, size_t len,
     loff_t pos, size_t *resid);
 extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags,
     cred_t *cr, int *direntflags, pathname_t *realpnp);
+extern int zfs_get_name(znode_t *dzp, char *name, znode_t *zp);
 extern int zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl,
     int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp,
     zidmap_t *mnt_ns);
index 3852fa03173c4c476c953a1500d6f24e2acb7819..cd2496bf7e95d4f7b4a1ee4f1af75fd625ae78b0 100644 (file)
@@ -81,6 +81,7 @@ typedef enum dmu_objset_type {
  * All of these include the terminating NUL byte.
  */
 #define        ZAP_MAXNAMELEN 256
+#define        ZAP_MAXNAMELEN_NEW 1024
 #define        ZAP_MAXVALUELEN (1024 * 8)
 #define        ZAP_OLDMAXVALUELEN 1024
 #define        ZFS_MAX_DATASET_NAME_LEN 256
@@ -194,6 +195,7 @@ typedef enum {
        ZFS_PROP_PREFETCH,
        ZFS_PROP_VOLTHREADING,
        ZFS_PROP_DIRECT,
+       ZFS_PROP_LONGNAME,
        ZFS_NUM_PROPS
 } zfs_prop_t;
 
index ec37c3447182eccbd609e72b1f999cae5c942318..43e8bbea1991e584331cb217e612d61123bbe997 100644 (file)
@@ -315,7 +315,7 @@ int zap_count(objset_t *ds, uint64_t zapobj, uint64_t *count);
  * match must be exact (ie, same as mask=-1ULL).
  */
 int zap_value_search(objset_t *os, uint64_t zapobj,
-    uint64_t value, uint64_t mask, char *name);
+    uint64_t value, uint64_t mask, char *name, uint64_t namelen);
 
 /*
  * Transfer all the entries from fromobj into intoobj.  Only works on
@@ -387,6 +387,7 @@ void zap_fini(void);
  * Alloc and free zap_attribute_t.
  */
 zap_attribute_t *zap_attribute_alloc(void);
+zap_attribute_t *zap_attribute_long_alloc(void);
 void zap_attribute_free(zap_attribute_t *attrp);
 
 /*
index 8b50168cfa0e12fc9180a13abb475213fae7d953..9e3d8150f5069c22dd98e27c9c6f80c4f743cc08 100644 (file)
@@ -143,7 +143,7 @@ typedef enum drr_headertype {
  * default use of "zfs send" won't encounter the bug mentioned above.
  */
 #define        DMU_BACKUP_FEATURE_SWITCH_TO_LARGE_BLOCKS (1 << 27)
-/* flag #28 is reserved for a Nutanix feature */
+#define        DMU_BACKUP_FEATURE_LONGNAME             (1 << 28)
 
 /*
  * Mask of all supported backup features
@@ -154,7 +154,7 @@ typedef enum drr_headertype {
     DMU_BACKUP_FEATURE_COMPRESSED | DMU_BACKUP_FEATURE_LARGE_DNODE | \
     DMU_BACKUP_FEATURE_RAW | DMU_BACKUP_FEATURE_HOLDS | \
     DMU_BACKUP_FEATURE_REDACTED | DMU_BACKUP_FEATURE_SWITCH_TO_LARGE_BLOCKS | \
-    DMU_BACKUP_FEATURE_ZSTD)
+    DMU_BACKUP_FEATURE_ZSTD | DMU_BACKUP_FEATURE_LONGNAME)
 
 /* Are all features in the given flag word currently supported? */
 #define        DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK))
index 5733a8187a95664ec8c2c805595b76042c6f06f6..1ca122d30ef5e40bb331247a595ab75a82b95d25 100644 (file)
@@ -83,6 +83,7 @@ typedef enum spa_feature {
        SPA_FEATURE_REDACTION_LIST_SPILL,
        SPA_FEATURE_RAIDZ_EXPANSION,
        SPA_FEATURE_FAST_DEDUP,
+       SPA_FEATURE_LONGNAME,
        SPA_FEATURES
 } spa_feature_t;
 
index 1f1f2fdffb15a25ed0baef496663909c9b0b7435..1bbbc5dd547c9caa0e7dc355e0e6b87d440bc224 100644 (file)
@@ -2,7 +2,6 @@
   <elf-needed>
     <dependency name='libzfs_core.so.3'/>
     <dependency name='libnvpair.so.3'/>
-    <dependency name='libtirpc.so.3'/>
     <dependency name='libuuid.so.1'/>
     <dependency name='libblkid.so.1'/>
     <dependency name='libudev.so.1'/>
     <elf-symbol name='fletcher_4_superscalar_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
-    <elf-symbol name='spa_feature_table' size='2352' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='spa_feature_table' size='2408' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zfs_deleg_perm_tab' size='512' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
       <parameter type-id='80f4b756'/>
       <return type-id='48b5725f'/>
     </function-decl>
-    <function-decl name='bsearch' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='b59d7dce'/>
-      <parameter type-id='b59d7dce'/>
-      <parameter type-id='aba7edd8'/>
-      <return type-id='eaa32e2f'/>
-    </function-decl>
-    <function-decl name='memmove' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='b59d7dce'/>
-      <return type-id='eaa32e2f'/>
-    </function-decl>
-    <function-decl name='strcat' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='26a90f95'/>
-      <parameter type-id='80f4b756'/>
-      <return type-id='26a90f95'/>
-    </function-decl>
     <function-type size-in-bits='64' id='276427e1'>
       <return type-id='95e97e5e'/>
     </function-type>
   </abi-instr>
   <abi-instr address-size='64' path='lib/libshare/os/linux/smb.c' language='LANG_C99'>
     <var-decl name='libshare_smb_type' type-id='d19dbca9' visibility='default'/>
-    <function-decl name='fgets' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__fgets_chk' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='266fe297'/>
+      <parameter type-id='b59d7dce'/>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='e75a27e9'/>
       <return type-id='26a90f95'/>
     <function-decl name='gettid' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='3629bad8'/>
     </function-decl>
-    <function-decl name='vfprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='e75a27e9'/>
-      <parameter type-id='9d26089a'/>
-      <parameter type-id='b7f2d5e6'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='prctl' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
       <parameter is-variadic='yes'/>
     <qualified-type-def type-id='f077d3f8' restrict='yes' id='598aab80'/>
     <pointer-type-def type-id='928221d2' size-in-bits='64' id='323d93c1'/>
     <qualified-type-def type-id='323d93c1' restrict='yes' id='f1358bc3'/>
-    <function-decl name='mbstowcs' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__mbstowcs_chk' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='f1358bc3'/>
       <parameter type-id='9d26089a'/>
       <parameter type-id='b59d7dce'/>
+      <parameter type-id='b59d7dce'/>
       <return type-id='b59d7dce'/>
     </function-decl>
-    <function-decl name='wcstombs' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__wcstombs_chk' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='266fe297'/>
       <parameter type-id='598aab80'/>
       <parameter type-id='b59d7dce'/>
+      <parameter type-id='b59d7dce'/>
       <return type-id='b59d7dce'/>
     </function-decl>
   </abi-instr>
       <parameter type-id='822cd80b'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='gnu_dev_major' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='35ed8932'/>
-      <return type-id='f0981eeb'/>
-    </function-decl>
-    <function-decl name='gnu_dev_minor' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='35ed8932'/>
-      <return type-id='f0981eeb'/>
-    </function-decl>
-    <function-decl name='gnu_dev_makedev' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='f0981eeb'/>
-      <parameter type-id='f0981eeb'/>
-      <return type-id='35ed8932'/>
-    </function-decl>
   </abi-instr>
   <abi-instr address-size='64' path='lib/libspl/timestamp.c' language='LANG_C99'>
     <typedef-decl name='nl_item' type-id='95e97e5e' id='03b79a94'/>
     <pointer-type-def type-id='6fcda10e' size-in-bits='64' id='ad33e5e7'/>
     <pointer-type-def type-id='66a0afc9' size-in-bits='64' id='f32b30e4'/>
     <qualified-type-def type-id='63e171df' restrict='yes' id='9e7a3a7d'/>
-    <function-decl name='__sysconf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='95e97e5e'/>
-      <return type-id='bd54fe1a'/>
-    </function-decl>
     <function-decl name='pthread_self' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='4051f5e7'/>
     </function-decl>
       <parameter type-id='0be2e71c'/>
       <return type-id='95e97e5e'/>
     </function-decl>
+    <function-decl name='__sysconf' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='95e97e5e'/>
+      <return type-id='bd54fe1a'/>
+    </function-decl>
     <function-decl name='tpool_abandon' mangled-name='tpool_abandon' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='tpool_abandon'>
       <parameter type-id='9cf59a50' name='tpool'/>
       <return type-id='48b5725f'/>
     <type-decl name='unsigned char' size-in-bits='8' id='002ac4a6'/>
     <type-decl name='unsigned int' size-in-bits='32' id='f0981eeb'/>
     <type-decl name='unsigned long int' size-in-bits='64' id='7359adad'/>
-    <type-decl name='variadic parameter type' id='2c1145c5'/>
     <type-decl name='void' id='48b5725f'/>
     <typedef-decl name='uu_compare_fn_t' type-id='add6e811' id='40f93560'/>
     <typedef-decl name='uu_avl_pool_t' type-id='12a530a8' id='7f84e390'/>
       <enumerator name='ZFS_PROP_PREFETCH' value='96'/>
       <enumerator name='ZFS_PROP_VOLTHREADING' value='97'/>
       <enumerator name='ZFS_PROP_DIRECT' value='98'/>
-      <enumerator name='ZFS_NUM_PROPS' value='99'/>
+      <enumerator name='ZFS_PROP_LONGNAME' value='99'/>
+      <enumerator name='ZFS_NUM_PROPS' value='100'/>
     </enum-decl>
     <typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/>
     <enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'>
     <typedef-decl name='longlong_t' type-id='1eb56b1e' id='9b3ff54f'/>
     <typedef-decl name='diskaddr_t' type-id='9b3ff54f' id='804dc465'/>
     <typedef-decl name='zoneid_t' type-id='3502e3ff' id='4da03624'/>
+    <typedef-decl name='__re_long_size_t' type-id='7359adad' id='ba516949'/>
+    <typedef-decl name='reg_syntax_t' type-id='7359adad' id='1b72c3b3'/>
+    <class-decl name='re_pattern_buffer' size-in-bits='512' is-struct='yes' visibility='default' id='19fc9a8c'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='buffer' type-id='33976309' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='64'>
+        <var-decl name='allocated' type-id='ba516949' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='128'>
+        <var-decl name='used' type-id='ba516949' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='192'>
+        <var-decl name='syntax' type-id='1b72c3b3' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='256'>
+        <var-decl name='fastmap' type-id='26a90f95' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='320'>
+        <var-decl name='translate' type-id='cf536864' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='384'>
+        <var-decl name='re_nsub' type-id='b59d7dce' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='448'>
+        <var-decl name='can_be_null' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='449'>
+        <var-decl name='regs_allocated' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='451'>
+        <var-decl name='fastmap_accurate' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='452'>
+        <var-decl name='no_sub' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='453'>
+        <var-decl name='not_bol' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='454'>
+        <var-decl name='not_eol' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='455'>
+        <var-decl name='newline_anchor' type-id='f0981eeb' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='regex_t' type-id='19fc9a8c' id='aca3bac8'/>
+    <typedef-decl name='uintptr_t' type-id='7359adad' id='e475ab95'/>
     <union-decl name='pthread_mutex_t' size-in-bits='320' naming-typedef-id='7a6844eb' visibility='default' id='70681f9b'>
       <data-member access='public'>
         <var-decl name='__data' type-id='4c734837' visibility='default'/>
     <typedef-decl name='__int32_t' type-id='95e97e5e' id='33f57a65'/>
     <typedef-decl name='__uint32_t' type-id='f0981eeb' id='62f1140c'/>
     <typedef-decl name='__uint64_t' type-id='7359adad' id='8910171f'/>
-    <typedef-decl name='__re_long_size_t' type-id='7359adad' id='ba516949'/>
-    <typedef-decl name='reg_syntax_t' type-id='7359adad' id='1b72c3b3'/>
-    <class-decl name='re_pattern_buffer' size-in-bits='512' is-struct='yes' visibility='default' id='19fc9a8c'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='buffer' type-id='33976309' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='allocated' type-id='ba516949' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='128'>
-        <var-decl name='used' type-id='ba516949' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='192'>
-        <var-decl name='syntax' type-id='1b72c3b3' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='256'>
-        <var-decl name='fastmap' type-id='26a90f95' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='320'>
-        <var-decl name='translate' type-id='cf536864' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='384'>
-        <var-decl name='re_nsub' type-id='b59d7dce' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='448'>
-        <var-decl name='can_be_null' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='449'>
-        <var-decl name='regs_allocated' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='451'>
-        <var-decl name='fastmap_accurate' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='452'>
-        <var-decl name='no_sub' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='453'>
-        <var-decl name='not_bol' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='454'>
-        <var-decl name='not_eol' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='455'>
-        <var-decl name='newline_anchor' type-id='f0981eeb' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <typedef-decl name='regex_t' type-id='19fc9a8c' id='aca3bac8'/>
-    <typedef-decl name='uintptr_t' type-id='7359adad' id='e475ab95'/>
     <typedef-decl name='size_t' type-id='7359adad' id='b59d7dce'/>
     <class-decl name='libzfs_handle' size-in-bits='18240' is-struct='yes' visibility='default' id='c8a9d9d8'>
       <data-member access='public' layout-offset-in-bits='0'>
     <class-decl name='uu_avl' is-struct='yes' visibility='default' is-declaration-only='yes' id='4af029d1'/>
     <class-decl name='uu_avl_pool' is-struct='yes' visibility='default' is-declaration-only='yes' id='12a530a8'/>
     <class-decl name='uu_avl_walk' is-struct='yes' visibility='default' is-declaration-only='yes' id='e70a39e3'/>
-    <function-decl name='uu_error' visibility='default' binding='global' size-in-bits='64'>
-      <return type-id='8f92235e'/>
-    </function-decl>
     <function-decl name='uu_avl_pool_create' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <parameter type-id='b59d7dce'/>
     <function-decl name='getzoneid' mangled-name='getzoneid' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='getzoneid'>
       <return type-id='4da03624'/>
     </function-decl>
-    <function-decl name='libspl_assertf' mangled-name='libspl_assertf' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_assertf'>
-      <parameter type-id='80f4b756'/>
-      <parameter type-id='80f4b756'/>
-      <parameter type-id='95e97e5e'/>
-      <parameter type-id='80f4b756'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='48b5725f'/>
-    </function-decl>
     <function-decl name='sa_commit_shares' mangled-name='sa_commit_shares' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_commit_shares'>
       <parameter type-id='9155d4b5'/>
       <return type-id='48b5725f'/>
       <parameter type-id='b59d7dce'/>
       <return type-id='b59d7dce'/>
     </function-decl>
-    <function-decl name='__assert_fail' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='80f4b756'/>
-      <parameter type-id='80f4b756'/>
-      <parameter type-id='f0981eeb'/>
-      <parameter type-id='80f4b756'/>
-      <return type-id='48b5725f'/>
-    </function-decl>
     <function-decl name='free' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='eaa32e2f'/>
       <return type-id='48b5725f'/>
     <array-type-def dimensions='1' type-id='b96825af' size-in-bits='24' id='d3490169'>
       <subrange length='3' type-id='7359adad' id='56f209d2'/>
     </array-type-def>
+    <type-decl name='variadic parameter type' id='2c1145c5'/>
     <typedef-decl name='zpool_iter_f' type-id='3aebb66f' id='fa476e62'/>
     <enum-decl name='data_type_t' naming-typedef-id='8d0687d2' id='aeeae136'>
       <underlying-type type-id='9cac1fee'/>
       <parameter type-id='3fa542f0'/>
       <return type-id='5ce45b60'/>
     </function-decl>
+    <function-decl name='libspl_assertf' mangled-name='libspl_assertf' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_assertf'>
+      <parameter type-id='80f4b756'/>
+      <parameter type-id='80f4b756'/>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='80f4b756'/>
+      <parameter is-variadic='yes'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
     <function-decl name='__errno_location' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='7292109c'/>
     </function-decl>
       <parameter type-id='80f4b756'/>
       <return type-id='26a90f95'/>
     </function-decl>
-    <function-decl name='strcpy' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='26a90f95'/>
-      <parameter type-id='80f4b756'/>
-      <return type-id='26a90f95'/>
-    </function-decl>
     <function-decl name='strchr' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <parameter type-id='95e97e5e'/>
       <enumerator name='ZPOOL_NUM_PROPS' value='39'/>
     </enum-decl>
     <typedef-decl name='zpool_prop_t' type-id='af1ba157' id='5d0c23fb'/>
+    <typedef-decl name='regoff_t' type-id='95e97e5e' id='54a2a2a8'/>
+    <class-decl name='regmatch_t' size-in-bits='64' is-struct='yes' naming-typedef-id='1b941664' visibility='default' id='4f932615'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='rm_so' type-id='54a2a2a8' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='32'>
+        <var-decl name='rm_eo' type-id='54a2a2a8' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='regmatch_t' type-id='4f932615' id='1b941664'/>
+    <typedef-decl name='__sighandler_t' type-id='03347643' id='8cdd9566'/>
+    <typedef-decl name='ssize_t' type-id='41060289' id='79a0948f'/>
     <class-decl name='sigaction' size-in-bits='1216' is-struct='yes' visibility='default' id='fe391c48'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='__sigaction_handler' type-id='ac5ab595' visibility='default'/>
         <var-decl name='_unused2' type-id='664ac0b7' visibility='default'/>
       </data-member>
     </class-decl>
-    <typedef-decl name='regoff_t' type-id='95e97e5e' id='54a2a2a8'/>
-    <class-decl name='regmatch_t' size-in-bits='64' is-struct='yes' naming-typedef-id='1b941664' visibility='default' id='4f932615'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='rm_so' type-id='54a2a2a8' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='rm_eo' type-id='54a2a2a8' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <typedef-decl name='regmatch_t' type-id='4f932615' id='1b941664'/>
-    <typedef-decl name='__sighandler_t' type-id='03347643' id='8cdd9566'/>
-    <typedef-decl name='ssize_t' type-id='41060289' id='79a0948f'/>
     <pointer-type-def type-id='aa12d1ba' size-in-bits='64' id='822cd80b'/>
     <qualified-type-def type-id='822cd80b' restrict='yes' id='e75a27e9'/>
     <pointer-type-def type-id='ec1ed955' size-in-bits='64' id='dca988a5'/>
       <parameter type-id='80f4b756'/>
       <return type-id='822cd80b'/>
     </function-decl>
-    <function-decl name='printf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='80f4b756'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='snprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='26a90f95'/>
-      <parameter type-id='b59d7dce'/>
-      <parameter type-id='80f4b756'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='asprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='8c85230f'/>
-      <parameter type-id='9d26089a'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='fputc' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='822cd80b'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='getline' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__getdelim' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='8c85230f'/>
       <parameter type-id='d19b2c25'/>
+      <parameter type-id='95e97e5e'/>
       <parameter type-id='e75a27e9'/>
       <return type-id='41060289'/>
     </function-decl>
-    <function-decl name='fread' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='1b7446cd'/>
-      <parameter type-id='b59d7dce'/>
-      <parameter type-id='b59d7dce'/>
-      <parameter type-id='e75a27e9'/>
-      <return type-id='b59d7dce'/>
-    </function-decl>
     <function-decl name='rewind' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='822cd80b'/>
       <return type-id='48b5725f'/>
       <parameter type-id='b59d7dce'/>
       <return type-id='eaa32e2f'/>
     </function-decl>
-    <function-decl name='memcpy' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='b59d7dce'/>
-      <return type-id='eaa32e2f'/>
-    </function-decl>
     <function-decl name='strdup' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <return type-id='26a90f95'/>
       <parameter type-id='95e97e5e'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='read' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='95e97e5e'/>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='b59d7dce'/>
-      <return type-id='79a0948f'/>
-    </function-decl>
     <function-decl name='getpid' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='3629bad8'/>
     </function-decl>
       <parameter type-id='80f4b756'/>
       <return type-id='95e97e5e'/>
     </function-decl>
+    <function-decl name='__open_too_many_args' visibility='default' binding='global' size-in-bits='64'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='__open_missing_mode' visibility='default' binding='global' size-in-bits='64'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='__printf_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='80f4b756'/>
+      <parameter is-variadic='yes'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='__asprintf_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='8c85230f'/>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='9d26089a'/>
+      <parameter is-variadic='yes'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='__fread_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='1b7446cd'/>
+      <parameter type-id='b59d7dce'/>
+      <parameter type-id='b59d7dce'/>
+      <parameter type-id='b59d7dce'/>
+      <parameter type-id='e75a27e9'/>
+      <return type-id='b59d7dce'/>
+    </function-decl>
+    <function-decl name='__read_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='eaa32e2f'/>
+      <parameter type-id='b59d7dce'/>
+      <parameter type-id='b59d7dce'/>
+      <return type-id='79a0948f'/>
+    </function-decl>
     <function-decl name='zfs_crypto_get_encryption_root' mangled-name='zfs_crypto_get_encryption_root' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_crypto_get_encryption_root'>
       <parameter type-id='9200a744' name='zhp'/>
       <parameter type-id='37e3bd22' name='is_encroot'/>
         <var-decl name='mnt_mntopts' type-id='26a90f95' visibility='default'/>
       </data-member>
     </class-decl>
-    <union-decl name='pthread_mutexattr_t' size-in-bits='32' naming-typedef-id='8afd6070' visibility='default' id='7300eb00'>
-      <data-member access='public'>
-        <var-decl name='__size' type-id='8e0573fd' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='__align' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-    </union-decl>
-    <typedef-decl name='pthread_mutexattr_t' type-id='7300eb00' id='8afd6070'/>
-    <typedef-decl name='int64_t' type-id='0c9942d2' id='9da381c4'/>
-    <typedef-decl name='__int64_t' type-id='bd54fe1a' id='0c9942d2'/>
-    <typedef-decl name='__gid_t' type-id='f0981eeb' id='d94ec6d9'/>
-    <typedef-decl name='__time_t' type-id='bd54fe1a' id='65eda9c0'/>
-    <class-decl name='tm' size-in-bits='448' is-struct='yes' visibility='default' id='dddf6ca2'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='tm_sec' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='tm_min' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='tm_hour' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='96'>
-        <var-decl name='tm_mday' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='128'>
-        <var-decl name='tm_mon' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='160'>
-        <var-decl name='tm_year' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='192'>
-        <var-decl name='tm_wday' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='224'>
-        <var-decl name='tm_yday' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='256'>
-        <var-decl name='tm_isdst' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='320'>
-        <var-decl name='tm_gmtoff' type-id='bd54fe1a' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='384'>
-        <var-decl name='tm_zone' type-id='80f4b756' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <typedef-decl name='time_t' type-id='65eda9c0' id='c9d12d66'/>
     <class-decl name='group' size-in-bits='256' is-struct='yes' visibility='default' id='01a1b934'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='gr_name' type-id='26a90f95' visibility='default'/>
     </class-decl>
     <class-decl name='passwd' size-in-bits='384' is-struct='yes' visibility='default' id='a63d15a3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='pw_name' type-id='26a90f95' visibility='default'/>
+        <var-decl name='pw_name' type-id='26a90f95' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='64'>
+        <var-decl name='pw_passwd' type-id='26a90f95' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='128'>
+        <var-decl name='pw_uid' type-id='cc5fcceb' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='160'>
+        <var-decl name='pw_gid' type-id='d94ec6d9' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='192'>
+        <var-decl name='pw_gecos' type-id='26a90f95' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='256'>
+        <var-decl name='pw_dir' type-id='26a90f95' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='320'>
+        <var-decl name='pw_shell' type-id='26a90f95' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <union-decl name='pthread_mutexattr_t' size-in-bits='32' naming-typedef-id='8afd6070' visibility='default' id='7300eb00'>
+      <data-member access='public'>
+        <var-decl name='__size' type-id='8e0573fd' visibility='default'/>
+      </data-member>
+      <data-member access='public'>
+        <var-decl name='__align' type-id='95e97e5e' visibility='default'/>
+      </data-member>
+    </union-decl>
+    <typedef-decl name='pthread_mutexattr_t' type-id='7300eb00' id='8afd6070'/>
+    <typedef-decl name='int64_t' type-id='0c9942d2' id='9da381c4'/>
+    <typedef-decl name='__int64_t' type-id='bd54fe1a' id='0c9942d2'/>
+    <typedef-decl name='__gid_t' type-id='f0981eeb' id='d94ec6d9'/>
+    <typedef-decl name='__time_t' type-id='bd54fe1a' id='65eda9c0'/>
+    <class-decl name='tm' size-in-bits='448' is-struct='yes' visibility='default' id='dddf6ca2'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='tm_sec' type-id='95e97e5e' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='32'>
+        <var-decl name='tm_min' type-id='95e97e5e' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='pw_passwd' type-id='26a90f95' visibility='default'/>
+        <var-decl name='tm_hour' type-id='95e97e5e' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='96'>
+        <var-decl name='tm_mday' type-id='95e97e5e' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='128'>
-        <var-decl name='pw_uid' type-id='cc5fcceb' visibility='default'/>
+        <var-decl name='tm_mon' type-id='95e97e5e' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='160'>
-        <var-decl name='pw_gid' type-id='d94ec6d9' visibility='default'/>
+        <var-decl name='tm_year' type-id='95e97e5e' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='192'>
-        <var-decl name='pw_gecos' type-id='26a90f95' visibility='default'/>
+        <var-decl name='tm_wday' type-id='95e97e5e' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='224'>
+        <var-decl name='tm_yday' type-id='95e97e5e' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='256'>
-        <var-decl name='pw_dir' type-id='26a90f95' visibility='default'/>
+        <var-decl name='tm_isdst' type-id='95e97e5e' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='320'>
-        <var-decl name='pw_shell' type-id='26a90f95' visibility='default'/>
+        <var-decl name='tm_gmtoff' type-id='bd54fe1a' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='384'>
+        <var-decl name='tm_zone' type-id='80f4b756' visibility='default'/>
       </data-member>
     </class-decl>
+    <typedef-decl name='time_t' type-id='65eda9c0' id='c9d12d66'/>
     <typedef-decl name='uid_t' type-id='cc5fcceb' id='354978ed'/>
     <typedef-decl name='prop_changelist_t' type-id='d86edc51' id='eae6431d'/>
     <pointer-type-def type-id='fba6cb51' size-in-bits='64' id='32adbf30'/>
       <parameter type-id='8f2c7109'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='fprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='e75a27e9'/>
+    <function-decl name='strtol' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='9d26089a'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='atoi' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='80f4b756'/>
-      <return type-id='95e97e5e'/>
+      <parameter type-id='8c85230f'/>
+      <parameter type-id='95e97e5e'/>
+      <return type-id='bd54fe1a'/>
     </function-decl>
     <function-decl name='strtoul' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='9d26089a'/>
       <parameter type-id='9d26089a'/>
       <return type-id='26a90f95'/>
     </function-decl>
-    <function-decl name='ioctl' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='95e97e5e'/>
-      <parameter type-id='7359adad'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='strftime' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='266fe297'/>
       <parameter type-id='b59d7dce'/>
       <parameter type-id='f099ad08'/>
       <return type-id='d915a820'/>
     </function-decl>
+    <function-decl name='__fprintf_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='e75a27e9'/>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='9d26089a'/>
+      <parameter is-variadic='yes'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='ioctl' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='7359adad'/>
+      <parameter is-variadic='yes'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
     <function-decl name='zfs_type_to_name' mangled-name='zfs_type_to_name' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_type_to_name'>
       <parameter type-id='2e45de5d' name='type'/>
       <return type-id='80f4b756'/>
       <parameter type-id='7292109c'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='memset' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='eaa32e2f'/>
-      <parameter type-id='95e97e5e'/>
-      <parameter type-id='b59d7dce'/>
-      <return type-id='eaa32e2f'/>
-    </function-decl>
-    <function-decl name='fstat64' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='95e97e5e'/>
-      <parameter type-id='62f7a03d'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='pread64' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='pwrite64' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='eaa32e2f'/>
       <parameter type-id='b59d7dce'/>
       <parameter type-id='724e4de6'/>
       <return type-id='79a0948f'/>
     </function-decl>
-    <function-decl name='pwrite64' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__pread64_chk' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='eaa32e2f'/>
       <parameter type-id='b59d7dce'/>
       <parameter type-id='724e4de6'/>
+      <parameter type-id='b59d7dce'/>
       <return type-id='79a0948f'/>
     </function-decl>
+    <function-decl name='fstat64' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='62f7a03d'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
     <function-decl name='zcmd_write_conf_nvlist' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='b0382bb3'/>
       <parameter type-id='e4ec4540'/>
     </class-decl>
     <typedef-decl name='get_all_cb_t' type-id='803dac95' id='9b293607'/>
     <typedef-decl name='tpool_t' type-id='88d1b7f9' id='b1bbf10d'/>
+    <typedef-decl name='DIR' type-id='20cd73f2' id='54a5d683'/>
+    <typedef-decl name='mode_t' type-id='e1c52942' id='d50d396c'/>
+    <typedef-decl name='__compar_fn_t' type-id='585e1de9' id='aba7edd8'/>
     <class-decl name='dirent64' size-in-bits='2240' is-struct='yes' visibility='default' id='5725d813'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='d_ino' type-id='71288a47' visibility='default'/>
     <typedef-decl name='__fsblkcnt64_t' type-id='7359adad' id='95fe1a02'/>
     <typedef-decl name='__fsfilcnt64_t' type-id='7359adad' id='0c3a4dde'/>
     <typedef-decl name='__fsword_t' type-id='bd54fe1a' id='6028cbfe'/>
-    <typedef-decl name='DIR' type-id='20cd73f2' id='54a5d683'/>
-    <typedef-decl name='mode_t' type-id='e1c52942' id='d50d396c'/>
-    <typedef-decl name='__compar_fn_t' type-id='585e1de9' id='aba7edd8'/>
     <pointer-type-def type-id='54a5d683' size-in-bits='64' id='f09217ba'/>
     <pointer-type-def type-id='5725d813' size-in-bits='64' id='07b96073'/>
     <pointer-type-def type-id='9b293607' size-in-bits='64' id='77bf1784'/>
       <parameter type-id='9155d4b5'/>
       <return type-id='48b5725f'/>
     </function-decl>
-    <function-decl name='closedir' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='f09217ba'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='fdopendir' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
       <return type-id='f09217ba'/>
     </function-decl>
+    <function-decl name='closedir' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='f09217ba'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
     <function-decl name='readdir64' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='f09217ba'/>
       <return type-id='07b96073'/>
       <parameter type-id='aba7edd8'/>
       <return type-id='48b5725f'/>
     </function-decl>
-    <function-decl name='statfs64' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='rmdir' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
-      <parameter type-id='7fd094c8'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='rmdir' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__openat_too_many_args' visibility='default' binding='global' size-in-bits='64'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='__openat_missing_mode' visibility='default' binding='global' size-in-bits='64'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='statfs64' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
+      <parameter type-id='7fd094c8'/>
       <return type-id='95e97e5e'/>
     </function-decl>
     <function-decl name='zfs_realloc' visibility='default' binding='global' size-in-bits='64'>
       <enumerator name='SPA_FEATURE_REDACTION_LIST_SPILL' value='39'/>
       <enumerator name='SPA_FEATURE_RAIDZ_EXPANSION' value='40'/>
       <enumerator name='SPA_FEATURE_FAST_DEDUP' value='41'/>
-      <enumerator name='SPA_FEATURES' value='42'/>
+      <enumerator name='SPA_FEATURE_LONGNAME' value='42'/>
+      <enumerator name='SPA_FEATURES' value='43'/>
     </enum-decl>
     <typedef-decl name='spa_feature_t' type-id='33ecb627' id='d6618c78'/>
     <qualified-type-def type-id='80f4b756' const='yes' id='b99c00c9'/>
       <parameter type-id='80f4b756'/>
       <return type-id='c19b74c3'/>
     </function-decl>
-    <function-decl name='zpool_prop_unsupported' mangled-name='zpool_prop_unsupported' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_unsupported'>
-      <parameter type-id='80f4b756'/>
-      <return type-id='c19b74c3'/>
-    </function-decl>
     <function-decl name='zpool_prop_index_to_string' mangled-name='zpool_prop_index_to_string' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_index_to_string'>
       <parameter type-id='5d0c23fb'/>
       <parameter type-id='9c313c2d'/>
       <parameter type-id='95e97e5e'/>
       <return type-id='3a47d82b'/>
     </function-decl>
-    <function-decl name='realpath' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='9d26089a'/>
-      <parameter type-id='266fe297'/>
-      <return type-id='26a90f95'/>
-    </function-decl>
     <function-decl name='memcmp' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='eaa32e2f'/>
       <parameter type-id='eaa32e2f'/>
       <parameter type-id='8c85230f'/>
       <return type-id='26a90f95'/>
     </function-decl>
+    <function-decl name='ctime_r' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='d6e2847c'/>
+      <parameter type-id='266fe297'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
+    <function-decl name='__realpath_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='b59d7dce'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
     <function-decl name='munmap' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='eaa32e2f'/>
       <parameter type-id='b59d7dce'/>
       <parameter type-id='f1cadedf'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='ctime_r' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='d6e2847c'/>
-      <parameter type-id='266fe297'/>
-      <return type-id='26a90f95'/>
-    </function-decl>
     <function-decl name='zpool_standard_error' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='b0382bb3'/>
       <parameter type-id='95e97e5e'/>
         <var-decl name='drr_checksum' type-id='39730d0b' visibility='default'/>
       </data-member>
     </class-decl>
+    <class-decl name='__cancel_jmp_buf_tag' size-in-bits='576' is-struct='yes' visibility='default' id='8901473c'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='__cancel_jmp_buf' type-id='379a1ab7' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='512'>
+        <var-decl name='__mask_was_saved' type-id='95e97e5e' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <class-decl name='__pthread_unwind_buf_t' size-in-bits='832' is-struct='yes' naming-typedef-id='4423cf7f' visibility='default' id='a0abc656'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='__cancel_jmp_buf' type-id='f5da478b' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='576'>
+        <var-decl name='__pad' type-id='209ef23f' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='__pthread_unwind_buf_t' type-id='a0abc656' id='4423cf7f'/>
     <typedef-decl name='__jmp_buf' type-id='5d4efd44' id='379a1ab7'/>
     <typedef-decl name='__clockid_t' type-id='95e97e5e' id='08f9a87a'/>
     <typedef-decl name='__timer_t' type-id='eaa32e2f' id='df209b60'/>
       </data-member>
     </class-decl>
     <typedef-decl name='timer_t' type-id='df209b60' id='b07ae406'/>
-    <class-decl name='__cancel_jmp_buf_tag' size-in-bits='576' is-struct='yes' visibility='default' id='8901473c'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='__cancel_jmp_buf' type-id='379a1ab7' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='512'>
-        <var-decl name='__mask_was_saved' type-id='95e97e5e' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <class-decl name='__pthread_unwind_buf_t' size-in-bits='832' is-struct='yes' naming-typedef-id='4423cf7f' visibility='default' id='a0abc656'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='__cancel_jmp_buf' type-id='f5da478b' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='576'>
-        <var-decl name='__pad' type-id='209ef23f' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <typedef-decl name='__pthread_unwind_buf_t' type-id='a0abc656' id='4423cf7f'/>
     <typedef-decl name='Byte' type-id='002ac4a6' id='efb9ba06'/>
     <typedef-decl name='uLong' type-id='7359adad' id='5bbcce85'/>
     <typedef-decl name='Bytef' type-id='efb9ba06' id='c1606520'/>
       <parameter type-id='eaa32e2f'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='pthread_sigmask' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='95e97e5e'/>
-      <parameter type-id='5a8729d0'/>
-      <parameter type-id='65e6ec45'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='pthread_exit' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='eaa32e2f'/>
       <return type-id='48b5725f'/>
       <parameter type-id='95e97e5e'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='sprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='26a90f95'/>
-      <parameter type-id='80f4b756'/>
-      <parameter is-variadic='yes'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='perror' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <return type-id='48b5725f'/>
     <function-decl name='pause' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='95e97e5e'/>
     </function-decl>
+    <function-decl name='pthread_sigmask' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='5a8729d0'/>
+      <parameter type-id='65e6ec45'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
     <function-decl name='uncompress' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='4c667223'/>
       <parameter type-id='60db3356'/>
       <parameter type-id='80f4b756'/>
       <return type-id='26a90f95'/>
     </function-decl>
+    <function-decl name='zpool_prop_unsupported' mangled-name='zpool_prop_unsupported' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_unsupported'>
+      <parameter type-id='80f4b756'/>
+      <return type-id='c19b74c3'/>
+    </function-decl>
     <function-decl name='zpool_feature_init' mangled-name='zpool_feature_init' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_feature_init'>
       <return type-id='48b5725f'/>
     </function-decl>
       <parameter type-id='62f7a03d'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='pow' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='a0eb0f08'/>
-      <parameter type-id='a0eb0f08'/>
-      <return type-id='a0eb0f08'/>
-    </function-decl>
     <function-decl name='__ctype_toupper_loc' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='24f95ba5'/>
     </function-decl>
       <parameter type-id='d33f11cb'/>
       <return type-id='48b5725f'/>
     </function-decl>
-    <function-decl name='vprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='80f4b756'/>
-      <parameter type-id='b7f2d5e6'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='vsnprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='26a90f95'/>
-      <parameter type-id='b59d7dce'/>
-      <parameter type-id='80f4b756'/>
-      <parameter type-id='b7f2d5e6'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='vasprintf' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='8c85230f'/>
-      <parameter type-id='9d26089a'/>
-      <parameter type-id='b7f2d5e6'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
-    <function-decl name='putchar' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='putc' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
+      <parameter type-id='822cd80b'/>
       <return type-id='95e97e5e'/>
     </function-decl>
     <function-decl name='puts' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='b59d7dce'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='waitpid' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='3629bad8'/>
-      <parameter type-id='7292109c'/>
-      <parameter type-id='95e97e5e'/>
-      <return type-id='3629bad8'/>
-    </function-decl>
     <function-decl name='access' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <parameter type-id='95e97e5e'/>
     <function-decl name='fork' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='3629bad8'/>
     </function-decl>
+    <function-decl name='pow' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='a0eb0f08'/>
+      <parameter type-id='a0eb0f08'/>
+      <return type-id='a0eb0f08'/>
+    </function-decl>
+    <function-decl name='__vfprintf_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='e75a27e9'/>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='b7f2d5e6'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='__vasprintf_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='8c85230f'/>
+      <parameter type-id='95e97e5e'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='b7f2d5e6'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='waitpid' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='3629bad8'/>
+      <parameter type-id='7292109c'/>
+      <parameter type-id='95e97e5e'/>
+      <return type-id='3629bad8'/>
+    </function-decl>
     <function-decl name='namespace_clear' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='b0382bb3'/>
       <return type-id='48b5725f'/>
   </abi-instr>
   <abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_mount_os.c' language='LANG_C99'>
     <pointer-type-def type-id='7359adad' size-in-bits='64' id='1d2c2b85'/>
+    <function-decl name='geteuid' visibility='default' binding='global' size-in-bits='64'>
+      <return type-id='cc5fcceb'/>
+    </function-decl>
     <function-decl name='mount' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <parameter type-id='80f4b756'/>
       <parameter type-id='95e97e5e'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='geteuid' visibility='default' binding='global' size-in-bits='64'>
-      <return type-id='cc5fcceb'/>
-    </function-decl>
     <function-decl name='zfs_parse_mount_options' mangled-name='zfs_parse_mount_options' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_parse_mount_options'>
       <parameter type-id='80f4b756' name='mntopts'/>
       <parameter type-id='1d2c2b85' name='mntflags'/>
       </data-member>
     </class-decl>
     <pointer-type-def type-id='b440e872' size-in-bits='64' id='3ac36db0'/>
-    <function-decl name='strtol' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='9d26089a'/>
-      <parameter type-id='8c85230f'/>
+    <function-decl name='__poll_chk' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='3ac36db0'/>
+      <parameter type-id='555eef66'/>
       <parameter type-id='95e97e5e'/>
-      <return type-id='bd54fe1a'/>
+      <parameter type-id='7359adad'/>
+      <return type-id='95e97e5e'/>
     </function-decl>
     <function-decl name='inotify_init1' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='8f92235e'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='poll' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='3ac36db0'/>
-      <parameter type-id='555eef66'/>
-      <parameter type-id='95e97e5e'/>
-      <return type-id='95e97e5e'/>
-    </function-decl>
     <function-decl name='timerfd_create' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='08f9a87a'/>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='80f4b756'/>
       <return type-id='80f4b756'/>
     </function-decl>
-    <function-decl name='readlink' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='__readlink_chk' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='9d26089a'/>
       <parameter type-id='266fe297'/>
       <parameter type-id='b59d7dce'/>
+      <parameter type-id='b59d7dce'/>
       <return type-id='79a0948f'/>
     </function-decl>
     <function-decl name='zfs_get_enclosure_sysfs_path' mangled-name='zfs_get_enclosure_sysfs_path' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_get_enclosure_sysfs_path'>
     <class-decl name='blkid_struct_dev_iterate' is-struct='yes' visibility='default' is-declaration-only='yes' id='d88420d6'/>
     <class-decl name='udev_list_entry' is-struct='yes' visibility='default' is-declaration-only='yes' id='e7dbdca3'/>
     <typedef-decl name='pool_vdev_iter_f' type-id='6c16a6c8' id='dff793e0'/>
-    <typedef-decl name='__useconds_t' type-id='f0981eeb' id='4e80d4b1'/>
     <typedef-decl name='blkid_dev' type-id='8433f053' id='f47b023a'/>
     <typedef-decl name='blkid_cache' type-id='940e3afc' id='0882dfdf'/>
     <typedef-decl name='blkid_dev_iterate' type-id='b8fa2efc' id='f4760fa7'/>
+    <typedef-decl name='__useconds_t' type-id='f0981eeb' id='4e80d4b1'/>
     <pointer-type-def type-id='0882dfdf' size-in-bits='64' id='2e3e7caa'/>
     <pointer-type-def type-id='f47b023a' size-in-bits='64' id='d87f9b75'/>
     <pointer-type-def type-id='09286066' size-in-bits='64' id='940e3afc'/>
     </function-decl>
   </abi-instr>
   <abi-instr address-size='64' path='module/zcommon/zfeature_common.c' language='LANG_C99'>
-    <array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='18816' id='b937914f'>
-      <subrange length='42' type-id='7359adad' id='cb7c937f'/>
+    <array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='19264' id='bd39d632'>
+      <subrange length='43' type-id='7359adad' id='8f7e73a2'/>
     </array-type-def>
     <enum-decl name='zfeature_flags' id='6db816a4'>
       <underlying-type type-id='9cac1fee'/>
       </data-member>
     </class-decl>
     <typedef-decl name='zfeature_info_t' type-id='1178d146' id='83f29ca2'/>
+    <typedef-decl name='__free_fn_t' type-id='b7f9d8e6' id='3ff5e51e'/>
     <class-decl name='dirent' size-in-bits='2240' is-struct='yes' visibility='default' id='611586a1'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='d_ino' type-id='71288a47' visibility='default'/>
         <var-decl name='d_name' type-id='d1617432' visibility='default'/>
       </data-member>
     </class-decl>
-    <typedef-decl name='__free_fn_t' type-id='b7f9d8e6' id='3ff5e51e'/>
     <class-decl name='zfs_mod_supported_features' size-in-bits='128' is-struct='yes' visibility='default' id='3eee3342'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='tree' type-id='eaa32e2f' visibility='default'/>
     <pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
     <qualified-type-def type-id='eaa32e2f' const='yes' id='83be723c'/>
     <pointer-type-def type-id='83be723c' size-in-bits='64' id='7acd98a2'/>
-    <var-decl name='spa_feature_table' type-id='b937914f' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
+    <var-decl name='spa_feature_table' type-id='bd39d632' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
     <var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
     <function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
index fe7715496eadaa31b6684e3f38aa2809711b77aa..ad9755ba50a472ad50cc9f0daad336736c3b9d99 100644 (file)
@@ -723,6 +723,23 @@ instead of scattering multiple writes to all the metaslab spacemaps.
 .Pp
 \*[instant-never]
 .
+.feature org.zfsonlinux longname no extensible_dataset
+This feature allows creating files and directories with name up to 1023 bytes
+in length.
+A new dataset property
+.Sy longname
+is also introduced to toggle longname support for each dataset individually.
+This property can be disabled even if it contains longname files.
+In such case, new file cannot be created with longname but existing longname
+files can still be looked up.
+.Pp
+This feature becomes
+.Sy active
+when a file name greater than 255 is created in a dataset, and returns to
+being
+.Sy enabled
+when all such datasets are destroyed.
+.
 .feature org.illumos lz4_compress no
 .Sy lz4
 is a high-performance real-time compression algorithm that
index 1ac0ab1ed384d51bca622e0097732768c3ce5e8c..1358c048619c746f8459c3b4b1b51047c183c27f 100644 (file)
@@ -627,6 +627,15 @@ zfs_link_create(znode_t *dzp, const char *name, znode_t *zp, dmu_tx_t *tx,
                return (error);
        }
 
+       /*
+        * If we added a longname activate the SPA_FEATURE_LONGNAME.
+        */
+       if (strlen(name) >= ZAP_MAXNAMELEN) {
+               dsl_dataset_t *ds = dmu_objset_ds(zfsvfs->z_os);
+               ds->ds_feature_activation[SPA_FEATURE_LONGNAME] =
+                   (void *)B_TRUE;
+       }
+
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL,
            &dzp->z_id, sizeof (dzp->z_id));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
index b96393df4626af0496b0ff38c7a2b0b089578135..a3fac1636981aa7db9015d0480b0f604c983913c 100644 (file)
@@ -614,6 +614,14 @@ acl_type_changed_cb(void *arg, uint64_t newval)
        zfsvfs->z_acl_type = newval;
 }
 
+static void
+longname_changed_cb(void *arg, uint64_t newval)
+{
+       zfsvfs_t *zfsvfs = arg;
+
+       zfsvfs->z_longname = newval;
+}
+
 static int
 zfs_register_callbacks(vfs_t *vfsp)
 {
@@ -751,6 +759,8 @@ zfs_register_callbacks(vfs_t *vfsp)
        error = error ? error : dsl_prop_register(ds,
            zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb,
            zfsvfs);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_LONGNAME), longname_changed_cb, zfsvfs);
        dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
        if (error)
                goto unregister;
@@ -1489,7 +1499,8 @@ zfs_statfs(vfs_t *vfsp, struct statfs *statp)
        strlcpy(statp->f_mntonname, vfsp->mnt_stat.f_mntonname,
            sizeof (statp->f_mntonname));
 
-       statp->f_namemax = MAXNAMELEN - 1;
+       statp->f_namemax =
+           zfsvfs->z_longname ? (ZAP_MAXNAMELEN_NEW - 1) : (MAXNAMELEN - 1);
 
        zfs_exit(zfsvfs, FTAG);
        return (0);
index 9df1fef60a13f3132afd987237a9aeee0a926781..60deab1f5ce98b63a93a8d261f2659b11ba54f27 100644 (file)
@@ -892,6 +892,14 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
        return (error);
 }
 
+static inline bool
+is_nametoolong(zfsvfs_t *zfsvfs, const char *name)
+{
+       size_t dlen = strlen(name);
+       return ((!zfsvfs->z_longname && dlen >= ZAP_MAXNAMELEN) ||
+           dlen >= ZAP_MAXNAMELEN_NEW);
+}
+
 /*
  * Attempt to create a new entry in a directory.  If the entry
  * already exists, truncate the file if permissible, else return
@@ -937,6 +945,9 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
        vnode_t *dvp = ZTOV(dzp);
 #endif
 
+       if (is_nametoolong(zfsvfs, name))
+               return (SET_ERROR(ENAMETOOLONG));
+
        /*
         * If we have an ephemeral id, ACL, or XVATTR then
         * make sure file system is at proper version
@@ -1301,6 +1312,9 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
 
        ASSERT3U(vap->va_type, ==, VDIR);
 
+       if (is_nametoolong(zfsvfs, dirname))
+               return (SET_ERROR(ENAMETOOLONG));
+
        /*
         * If we have an ephemeral id, ACL, or XVATTR then
         * make sure file system is at proper version
@@ -1616,7 +1630,7 @@ zfs_readdir(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, int *eofp,
        os = zfsvfs->z_os;
        offset = zfs_uio_offset(uio);
        prefetch = zp->z_zn_prefetch;
-       zap = zap_attribute_alloc();
+       zap = zap_attribute_long_alloc();
 
        /*
         * Initialize the iterator cursor.
@@ -3294,6 +3308,9 @@ zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname,
        int error;
        svp = tvp = NULL;
 
+       if (is_nametoolong(tdzp->z_zfsvfs, tname))
+               return (SET_ERROR(ENAMETOOLONG));
+
        if (rflags != 0 || wo_vap != NULL)
                return (SET_ERROR(EINVAL));
 
@@ -3358,6 +3375,9 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
 
        ASSERT3S(vap->va_type, ==, VLNK);
 
+       if (is_nametoolong(zfsvfs, name))
+               return (SET_ERROR(ENAMETOOLONG));
+
        if ((error = zfs_enter_verify_zp(zfsvfs, dzp, FTAG)) != 0)
                return (error);
        zilog = zfsvfs->z_log;
@@ -3540,6 +3560,9 @@ zfs_link(znode_t *tdzp, znode_t *szp, const char *name, cred_t *cr,
 
        ASSERT3S(ZTOV(tdzp)->v_type, ==, VDIR);
 
+       if (is_nametoolong(zfsvfs, name))
+               return (SET_ERROR(ENAMETOOLONG));
+
        if ((error = zfs_enter_verify_zp(zfsvfs, tdzp, FTAG)) != 0)
                return (error);
        zilog = zfsvfs->z_log;
@@ -5996,7 +6019,8 @@ zfs_vptocnp(struct vop_vptocnp_args *ap)
                znode_t *dzp;
                size_t len;
 
-               error = zfs_znode_parent_and_name(zp, &dzp, name);
+               error = zfs_znode_parent_and_name(zp, &dzp, name,
+                   sizeof (name));
                if (error == 0) {
                        len = strlen(name);
                        if (*ap->a_buflen < len)
index fea34273baef1c547e5f2bdefa350ef86385f036..a31ecc367414f2caecc889ce5855ae0a845f3b58 100644 (file)
@@ -1792,7 +1792,8 @@ zfs_znode_update_vfs(znode_t *zp)
 }
 
 int
-zfs_znode_parent_and_name(znode_t *zp, znode_t **dzpp, char *buf)
+zfs_znode_parent_and_name(znode_t *zp, znode_t **dzpp, char *buf,
+    uint64_t buflen)
 {
        zfsvfs_t *zfsvfs = zp->z_zfsvfs;
        uint64_t parent;
@@ -1814,7 +1815,7 @@ zfs_znode_parent_and_name(znode_t *zp, znode_t **dzpp, char *buf)
                return (SET_ERROR(EINVAL));
 
        err = zap_value_search(zfsvfs->z_os, parent, zp->z_id,
-           ZFS_DIRENT_OBJ(-1ULL), buf);
+           ZFS_DIRENT_OBJ(-1ULL), buf, buflen);
        if (err != 0)
                return (err);
        err = zfs_zget(zfsvfs, parent, dzpp);
index ad2ca15e297a72e6b2b1947b88f8bbfa17f230fc..f59281f06caba3183f433c640fd22faad9280069 100644 (file)
@@ -847,6 +847,15 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
                return (error);
        }
 
+       /*
+        * If we added a longname activate the SPA_FEATURE_LONGNAME.
+        */
+       if (strlen(dl->dl_name) >= ZAP_MAXNAMELEN) {
+               dsl_dataset_t *ds = dmu_objset_ds(zfsvfs->z_os);
+               ds->ds_feature_activation[SPA_FEATURE_LONGNAME] =
+                   (void *)B_TRUE;
+       }
+
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL,
            &dzp->z_id, sizeof (dzp->z_id));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
index a6d1202e424f39223a90c4784b775aa68c5b73f0..a24f504129d78b2a3606faf3276bd0ee33720e50 100644 (file)
@@ -57,6 +57,7 @@
 #include <sys/dmu_objset.h>
 #include <sys/dsl_dir.h>
 #include <sys/objlist.h>
+#include <sys/zfeature.h>
 #include <sys/zpl.h>
 #include <linux/vfs_compat.h>
 #include <linux/fs.h>
@@ -449,6 +450,12 @@ acl_inherit_changed_cb(void *arg, uint64_t newval)
        ((zfsvfs_t *)arg)->z_acl_inherit = newval;
 }
 
+static void
+longname_changed_cb(void *arg, uint64_t newval)
+{
+       ((zfsvfs_t *)arg)->z_longname = newval;
+}
+
 static int
 zfs_register_callbacks(vfs_t *vfsp)
 {
@@ -509,6 +516,8 @@ zfs_register_callbacks(vfs_t *vfsp)
            zfsvfs);
        error = error ? error : dsl_prop_register(ds,
            zfs_prop_to_name(ZFS_PROP_NBMAND), nbmand_changed_cb, zfsvfs);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_LONGNAME), longname_changed_cb, zfsvfs);
        dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
        if (error)
                goto unregister;
@@ -1140,7 +1149,8 @@ zfs_statvfs(struct inode *ip, struct kstatfs *statp)
        statp->f_fsid.val[0] = (uint32_t)fsid;
        statp->f_fsid.val[1] = (uint32_t)(fsid >> 32);
        statp->f_type = ZFS_SUPER_MAGIC;
-       statp->f_namelen = MAXNAMELEN - 1;
+       statp->f_namelen =
+           zfsvfs->z_longname ? (ZAP_MAXNAMELEN_NEW - 1) : (MAXNAMELEN - 1);
 
        /*
         * We have all of 40 characters to stuff a string here.
index 503b0d1317fa6927f3a3b72f4039ce38148173ec..4691972208598286506ba175181fdd4cde337f1e 100644 (file)
@@ -542,6 +542,46 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr,
        return (error);
 }
 
+/*
+ * Perform a linear search in directory for the name of specific inode.
+ * Note we don't pass in the buffer size of name because it's hardcoded to
+ * NAME_MAX+1(256) in Linux.
+ *
+ *     IN:     dzp     - znode of directory to search.
+ *             zp      - znode of the target
+ *
+ *     OUT:    name    - dentry name of the target
+ *
+ *     RETURN: 0 on success, error code on failure.
+ */
+int
+zfs_get_name(znode_t *dzp, char *name, znode_t *zp)
+{
+       zfsvfs_t *zfsvfs = ZTOZSB(dzp);
+       int error = 0;
+
+       if ((error = zfs_enter_verify_zp(zfsvfs, dzp, FTAG)) != 0)
+               return (error);
+
+       if ((error = zfs_verify_zp(zp)) != 0) {
+               zfs_exit(zfsvfs, FTAG);
+               return (error);
+       }
+
+       /* ctldir should have got their name in zfs_vget */
+       if (dzp->z_is_ctldir || zp->z_is_ctldir) {
+               zfs_exit(zfsvfs, FTAG);
+               return (ENOENT);
+       }
+
+       /* buffer len is hardcoded to 256 in Linux kernel */
+       error = zap_value_search(zfsvfs->z_os, dzp->z_id, zp->z_id,
+           ZFS_DIRENT_OBJ(-1ULL), name, ZAP_MAXNAMELEN);
+
+       zfs_exit(zfsvfs, FTAG);
+       return (error);
+}
+
 /*
  * Attempt to create a new entry in a directory.  If the entry
  * already exists, truncate the file if permissible, else return
@@ -1548,7 +1588,7 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
        os = zfsvfs->z_os;
        offset = ctx->pos;
        prefetch = zp->z_zn_prefetch;
-       zap = zap_attribute_alloc();
+       zap = zap_attribute_long_alloc();
 
        /*
         * Initialize the iterator cursor.
index b6b9e27540559559de86f07649bc4a9fa9df0f83..ff865d1299544b72f894cc9e1ff48c3c6685ca81 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 
+#include <sys/file.h>
 #include <sys/zfs_znode.h>
 #include <sys/zfs_vnops.h>
 #include <sys/zfs_ctldir.h>
@@ -102,6 +103,35 @@ zpl_fh_to_dentry(struct super_block *sb, struct fid *fh,
        return (d_obtain_alias(ip));
 }
 
+/*
+ * In case the filesystem contains name longer than 255, we need to override
+ * the default get_name so we don't get buffer overflow. Unfortunately, since
+ * the buffer size is hardcoded in Linux, we will get ESTALE error in this
+ * case.
+ */
+static int
+zpl_get_name(struct dentry *parent, char *name, struct dentry *child)
+{
+       cred_t *cr = CRED();
+       fstrans_cookie_t cookie;
+       struct inode *dir = parent->d_inode;
+       struct inode *ip = child->d_inode;
+       int error;
+
+       if (!dir || !S_ISDIR(dir->i_mode))
+               return (-ENOTDIR);
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       spl_inode_lock_shared(dir);
+       error = -zfs_get_name(ITOZ(dir), name, ITOZ(ip));
+       spl_inode_unlock_shared(dir);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       return (error);
+}
+
 static struct dentry *
 zpl_get_parent(struct dentry *child)
 {
@@ -146,6 +176,7 @@ zpl_commit_metadata(struct inode *inode)
 const struct export_operations zpl_export_operations = {
        .encode_fh              = zpl_encode_fh,
        .fh_to_dentry           = zpl_fh_to_dentry,
+       .get_name               = zpl_get_name,
        .get_parent             = zpl_get_parent,
        .commit_metadata        = zpl_commit_metadata,
 };
index 8386fc2ae0ce43c188bc73199f62dfdb72f6275c..c4b5087ca5e7ed3113b862ffce7c579d489cdedd 100644 (file)
@@ -46,9 +46,29 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
        pathname_t pn;
        int zfs_flags = 0;
        zfsvfs_t *zfsvfs = dentry->d_sb->s_fs_info;
+       dsl_dataset_t *ds = dmu_objset_ds(zfsvfs->z_os);
+       size_t dlen = dlen(dentry);
 
-       if (dlen(dentry) >= ZAP_MAXNAMELEN)
+       /*
+        * If z_longname is disabled, disallow create or rename of names
+        * longer than ZAP_MAXNAMELEN.
+        *
+        * This is needed in cases where longname was enabled first and some
+        * files/dirs with names > ZAP_MAXNAMELEN were created. And later
+        * longname was disabled. In such a case allow access to existing
+        * longnames. But disallow creation newer longnamed entities.
+        */
+       if (!zfsvfs->z_longname && (dlen >= ZAP_MAXNAMELEN)) {
+               /*
+                * If this is for create or rename fail it.
+                */
+               if (!dsl_dataset_feature_is_active(ds, SPA_FEATURE_LONGNAME) ||
+                   (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)))
+                       return (ERR_PTR(-ENAMETOOLONG));
+       }
+       if (dlen >= ZAP_MAXNAMELEN_NEW) {
                return (ERR_PTR(-ENAMETOOLONG));
+       }
 
        crhold(cr);
        cookie = spl_fstrans_mark();
@@ -131,6 +151,16 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr,
        }
 }
 
+static inline bool
+is_nametoolong(struct dentry *dentry)
+{
+       zfsvfs_t *zfsvfs = dentry->d_sb->s_fs_info;
+       size_t dlen = dlen(dentry);
+
+       return ((!zfsvfs->z_longname && dlen >= ZAP_MAXNAMELEN) ||
+           dlen >= ZAP_MAXNAMELEN_NEW);
+}
+
 static int
 #ifdef HAVE_IOPS_CREATE_USERNS
 zpl_create(struct user_namespace *user_ns, struct inode *dir,
@@ -151,6 +181,10 @@ zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag)
        zidmap_t *user_ns = kcred->user_ns;
 #endif
 
+       if (is_nametoolong(dentry)) {
+               return (-ENAMETOOLONG);
+       }
+
        crhold(cr);
        vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
        zpl_vap_init(vap, dir, mode, cr, user_ns);
@@ -201,6 +235,10 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
        zidmap_t *user_ns = kcred->user_ns;
 #endif
 
+       if (is_nametoolong(dentry)) {
+               return (-ENAMETOOLONG);
+       }
+
        /*
         * We currently expect Linux to supply rdev=0 for all sockets
         * and fifos, but we want to know if this behavior ever changes.
@@ -353,6 +391,10 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        zidmap_t *user_ns = kcred->user_ns;
 #endif
 
+       if (is_nametoolong(dentry)) {
+               return (-ENAMETOOLONG);
+       }
+
        crhold(cr);
        vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
        zpl_vap_init(vap, dir, mode | S_IFDIR, cr, user_ns);
@@ -568,6 +610,10 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry,
        zidmap_t *user_ns = kcred->user_ns;
 #endif
 
+       if (is_nametoolong(tdentry)) {
+               return (-ENAMETOOLONG);
+       }
+
        crhold(cr);
        if (rflags & RENAME_WHITEOUT) {
                wo_vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
@@ -618,6 +664,10 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name)
        zidmap_t *user_ns = kcred->user_ns;
 #endif
 
+       if (is_nametoolong(dentry)) {
+               return (-ENAMETOOLONG);
+       }
+
        crhold(cr);
        vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
        zpl_vap_init(vap, dir, S_IFLNK | S_IRWXUGO, cr, user_ns);
@@ -707,6 +757,10 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
        int error;
        fstrans_cookie_t cookie;
 
+       if (is_nametoolong(dentry)) {
+               return (-ENAMETOOLONG);
+       }
+
        if (ip->i_nlink >= ZFS_LINK_MAX)
                return (-EMLINK);
 
index 8dec5f27b0af0d021ee8f8c907529aa8354244a5..881deb5bf666c7c26a87341a9f68950cd30e7756 100644 (file)
@@ -760,6 +760,18 @@ zpool_feature_init(void)
            ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
            sfeatures);
 
+       {
+               static const spa_feature_t longname_deps[] = {
+                       SPA_FEATURE_EXTENSIBLE_DATASET,
+                       SPA_FEATURE_NONE
+               };
+               zfeature_register(SPA_FEATURE_LONGNAME,
+                   "org.zfsonlinux:longname", "longname",
+                   "support filename up to 1024 bytes",
+                   ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+                   longname_deps, sfeatures);
+       }
+
        zfs_mod_list_supported_free(sfeatures);
 }
 
index 20cc0dffc27e3e1516c498e701fb852bdd545885..8179a1a8c39d9d131e269382f96f5819bc2cc8f3 100644 (file)
@@ -772,6 +772,10 @@ zfs_prop_init(void)
            ZFS_TYPE_VOLUME, "<date>", "SNAPSHOTS_CHANGED", B_FALSE, B_TRUE,
            B_TRUE, NULL, sfeatures);
 
+       zprop_register_index(ZFS_PROP_LONGNAME, "longname", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "on | off", "LONGNAME", boolean_table,
+           sfeatures);
+
        zfs_mod_list_supported_free(sfeatures);
 }
 
index 9b3da032f35458d98ab82752f9ff861accfeb42c..4877eb7e62f80710afb9a10f9a2b3f87ac7876e9 100644 (file)
@@ -602,6 +602,13 @@ recv_begin_check_feature_flags_impl(uint64_t featureflags, spa_t *spa)
            !spa_feature_is_enabled(spa, SPA_FEATURE_REDACTED_DATASETS))
                return (SET_ERROR(ENOTSUP));
 
+       /*
+        * If the LONGNAME is not enabled on the target, fail that request.
+        */
+       if ((featureflags & DMU_BACKUP_FEATURE_LONGNAME) &&
+           !spa_feature_is_enabled(spa, SPA_FEATURE_LONGNAME))
+               return (SET_ERROR(ENOTSUP));
+
        return (0);
 }
 
@@ -990,6 +997,16 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
        dmu_buf_will_dirty(newds->ds_dbuf, tx);
        dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
 
+       /*
+        * Activate longname feature if received
+        */
+       if (featureflags & DMU_BACKUP_FEATURE_LONGNAME &&
+           !dsl_dataset_feature_is_active(newds, SPA_FEATURE_LONGNAME)) {
+               dsl_dataset_activate_feature(newds->ds_object,
+                   SPA_FEATURE_LONGNAME, (void *)B_TRUE, tx);
+               newds->ds_feature[SPA_FEATURE_LONGNAME] = (void *)B_TRUE;
+       }
+
        /*
         * If we actually created a non-clone, we need to create the objset
         * in our new dataset. If this is a raw send we postpone this until
index cb2b62fed3139daecf45534cd0910e3373af496e..c7d3a5cb6e7fca329df1f822d3376344fdc6e333 100644 (file)
@@ -2011,6 +2011,10 @@ setup_featureflags(struct dmu_send_params *dspp, objset_t *os,
        if (dsl_dataset_feature_is_active(to_ds, SPA_FEATURE_LARGE_DNODE)) {
                *featureflags |= DMU_BACKUP_FEATURE_LARGE_DNODE;
        }
+
+       if (dsl_dataset_feature_is_active(to_ds, SPA_FEATURE_LONGNAME)) {
+               *featureflags |= DMU_BACKUP_FEATURE_LONGNAME;
+       }
        return (0);
 }
 
index aa02af55722d13801add149325b41395dc0421cf..6a9ed891093bc83feca2a4de34685c8b7668fde8 100644 (file)
@@ -494,7 +494,8 @@ dsl_dataset_get_snapname(dsl_dataset_t *ds)
                return (err);
        headphys = headdbuf->db_data;
        err = zap_value_search(dp->dp_meta_objset,
-           headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname);
+           headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname,
+           sizeof (ds->ds_snapname));
        if (err != 0 && zfs_recover == B_TRUE) {
                err = 0;
                (void) snprintf(ds->ds_snapname, sizeof (ds->ds_snapname),
index 5aeff86b948ff968365d5f9a575ac2fff8dc7865..1b60fa620b8db48050f08bf95adf0102f873bd1b 100644 (file)
@@ -239,7 +239,8 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
                                err = zap_value_search(dp->dp_meta_objset,
                                    dsl_dir_phys(dd->dd_parent)->
                                    dd_child_dir_zapobj,
-                                   ddobj, 0, dd->dd_myname);
+                                   ddobj, 0, dd->dd_myname,
+                                   sizeof (dd->dd_myname));
                        }
                        if (err != 0)
                                goto errout;
index 603c76a2cd9bbf22a1ec1f38b472feb6115a7d0c..40e7bcf3ed1f8c853820ef6e5ac63620fddca138 100644 (file)
@@ -832,7 +832,12 @@ zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l,
 static int
 fzap_checkname(zap_name_t *zn)
 {
-       if (zn->zn_key_orig_numints * zn->zn_key_intlen > ZAP_MAXNAMELEN)
+       uint32_t maxnamelen = zn->zn_normbuf_len;
+       uint64_t len = (uint64_t)zn->zn_key_orig_numints * zn->zn_key_intlen;
+       /* Only allow directory zap to have longname */
+       if (len > maxnamelen ||
+           (len > ZAP_MAXNAMELEN &&
+           zn->zn_zap->zap_dnode->dn_type != DMU_OT_DIRECTORY_CONTENTS))
                return (SET_ERROR(ENAMETOOLONG));
        return (0);
 }
@@ -1102,7 +1107,7 @@ zap_create_link_dnsize(objset_t *os, dmu_object_type_t ot, uint64_t parent_obj,
 
 int
 zap_value_search(objset_t *os, uint64_t zapobj, uint64_t value, uint64_t mask,
-    char *name)
+    char *name, uint64_t namelen)
 {
        zap_cursor_t zc;
        int err;
@@ -1110,12 +1115,13 @@ zap_value_search(objset_t *os, uint64_t zapobj, uint64_t value, uint64_t mask,
        if (mask == 0)
                mask = -1ULL;
 
-       zap_attribute_t *za = zap_attribute_alloc();
+       zap_attribute_t *za = zap_attribute_long_alloc();
        for (zap_cursor_init(&zc, os, zapobj);
            (err = zap_cursor_retrieve(&zc, za)) == 0;
            zap_cursor_advance(&zc)) {
                if ((za->za_first_integer & mask) == (value & mask)) {
-                       (void) strlcpy(name, za->za_name, MAXNAMELEN);
+                       if (strlcpy(name, za->za_name, namelen) >= namelen)
+                               err = SET_ERROR(ENAMETOOLONG);
                        break;
                }
        }
@@ -1130,7 +1136,7 @@ zap_join(objset_t *os, uint64_t fromobj, uint64_t intoobj, dmu_tx_t *tx)
        zap_cursor_t zc;
        int err = 0;
 
-       zap_attribute_t *za = zap_attribute_alloc();
+       zap_attribute_t *za = zap_attribute_long_alloc();
        for (zap_cursor_init(&zc, os, fromobj);
            zap_cursor_retrieve(&zc, za) == 0;
            (void) zap_cursor_advance(&zc)) {
@@ -1155,7 +1161,7 @@ zap_join_key(objset_t *os, uint64_t fromobj, uint64_t intoobj,
        zap_cursor_t zc;
        int err = 0;
 
-       zap_attribute_t *za = zap_attribute_alloc();
+       zap_attribute_t *za = zap_attribute_long_alloc();
        for (zap_cursor_init(&zc, os, fromobj);
            zap_cursor_retrieve(&zc, za) == 0;
            (void) zap_cursor_advance(&zc)) {
@@ -1180,7 +1186,7 @@ zap_join_increment(objset_t *os, uint64_t fromobj, uint64_t intoobj,
        zap_cursor_t zc;
        int err = 0;
 
-       zap_attribute_t *za = zap_attribute_alloc();
+       zap_attribute_t *za = zap_attribute_long_alloc();
        for (zap_cursor_init(&zc, os, fromobj);
            zap_cursor_retrieve(&zc, za) == 0;
            (void) zap_cursor_advance(&zc)) {
index e52680dd40c02c3e94354458631874d29ab9f3cd..a428a040a4a32893bee896a8182cd972d40d7979 100644 (file)
@@ -131,12 +131,12 @@ zap_hash(zap_name_t *zn)
 }
 
 static int
-zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags)
+zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags,
+    size_t outlen)
 {
        ASSERT(!(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY));
 
        size_t inlen = strlen(name) + 1;
-       size_t outlen = ZAP_MAXNAMELEN;
 
        int err = 0;
        (void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
@@ -149,23 +149,39 @@ zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags)
 boolean_t
 zap_match(zap_name_t *zn, const char *matchname)
 {
+       boolean_t res = B_FALSE;
        ASSERT(!(zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY));
 
        if (zn->zn_matchtype & MT_NORMALIZE) {
-               char norm[ZAP_MAXNAMELEN];
+               size_t namelen = zn->zn_normbuf_len;
+               char normbuf[ZAP_MAXNAMELEN];
+               char *norm = normbuf;
 
-               if (zap_normalize(zn->zn_zap, matchname, norm,
-                   zn->zn_normflags) != 0)
-                       return (B_FALSE);
+               /*
+                * Cannot allocate this on-stack as it exceed the stack-limit of
+                * 1024.
+                */
+               if (namelen > ZAP_MAXNAMELEN)
+                       norm = kmem_alloc(namelen, KM_SLEEP);
 
-               return (strcmp(zn->zn_key_norm, norm) == 0);
+               if (zap_normalize(zn->zn_zap, matchname, norm,
+                   zn->zn_normflags, namelen) != 0) {
+                       res = B_FALSE;
+               } else {
+                       res = (strcmp(zn->zn_key_norm, norm) == 0);
+               }
+               if (norm != normbuf)
+                       kmem_free(norm, namelen);
        } else {
-               return (strcmp(zn->zn_key_orig, matchname) == 0);
+               res = (strcmp(zn->zn_key_orig, matchname) == 0);
        }
+       return (res);
 }
 
 static kmem_cache_t *zap_name_cache;
 static kmem_cache_t *zap_attr_cache;
+static kmem_cache_t *zap_name_long_cache;
+static kmem_cache_t *zap_attr_long_cache;
 
 void
 zap_init(void)
@@ -177,6 +193,14 @@ zap_init(void)
        zap_attr_cache = kmem_cache_create("zap_attr_cache",
            sizeof (zap_attribute_t) + ZAP_MAXNAMELEN,  0, NULL,
            NULL, NULL, NULL, NULL, 0);
+
+       zap_name_long_cache = kmem_cache_create("zap_name_long",
+           sizeof (zap_name_t) + ZAP_MAXNAMELEN_NEW, 0, NULL, NULL,
+           NULL, NULL, NULL, 0);
+
+       zap_attr_long_cache = kmem_cache_create("zap_attr_long_cache",
+           sizeof (zap_attribute_t) + ZAP_MAXNAMELEN_NEW,  0, NULL,
+           NULL, NULL, NULL, NULL, 0);
 }
 
 void
@@ -184,33 +208,47 @@ zap_fini(void)
 {
        kmem_cache_destroy(zap_name_cache);
        kmem_cache_destroy(zap_attr_cache);
+       kmem_cache_destroy(zap_name_long_cache);
+       kmem_cache_destroy(zap_attr_long_cache);
 }
 
 static zap_name_t *
-zap_name_alloc(zap_t *zap)
+zap_name_alloc(zap_t *zap, boolean_t longname)
 {
-       zap_name_t *zn = kmem_cache_alloc(zap_name_cache, KM_SLEEP);
+       kmem_cache_t *cache = longname ? zap_name_long_cache : zap_name_cache;
+       zap_name_t *zn = kmem_cache_alloc(cache, KM_SLEEP);
+
        zn->zn_zap = zap;
+       zn->zn_normbuf_len = longname ? ZAP_MAXNAMELEN_NEW : ZAP_MAXNAMELEN;
        return (zn);
 }
 
 void
 zap_name_free(zap_name_t *zn)
 {
-       kmem_cache_free(zap_name_cache, zn);
+       if (zn->zn_normbuf_len == ZAP_MAXNAMELEN) {
+               kmem_cache_free(zap_name_cache, zn);
+       } else {
+               ASSERT3U(zn->zn_normbuf_len, ==, ZAP_MAXNAMELEN_NEW);
+               kmem_cache_free(zap_name_long_cache, zn);
+       }
 }
 
 static int
 zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt)
 {
        zap_t *zap = zn->zn_zap;
+       size_t key_len = strlen(key) + 1;
+
+       /* Make sure zn is allocated for longname if key is long */
+       IMPLY(key_len > ZAP_MAXNAMELEN,
+           zn->zn_normbuf_len == ZAP_MAXNAMELEN_NEW);
 
        zn->zn_key_intlen = sizeof (*key);
        zn->zn_key_orig = key;
-       zn->zn_key_orig_numints = strlen(zn->zn_key_orig) + 1;
+       zn->zn_key_orig_numints = key_len;
        zn->zn_matchtype = mt;
        zn->zn_normflags = zap->zap_normflags;
-       zn->zn_normbuf_len = ZAP_MAXNAMELEN;
 
        /*
         * If we're dealing with a case sensitive lookup on a mixed or
@@ -226,7 +264,7 @@ zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt)
                 * what the hash is computed from.
                 */
                if (zap_normalize(zap, key, zn->zn_normbuf,
-                   zap->zap_normflags) != 0)
+                   zap->zap_normflags, zn->zn_normbuf_len) != 0)
                        return (SET_ERROR(ENOTSUP));
                zn->zn_key_norm = zn->zn_normbuf;
                zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
@@ -245,7 +283,7 @@ zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt)
                 * what the matching is based on.  (Not the hash!)
                 */
                if (zap_normalize(zap, key, zn->zn_normbuf,
-                   zn->zn_normflags) != 0)
+                   zn->zn_normflags, zn->zn_normbuf_len) != 0)
                        return (SET_ERROR(ENOTSUP));
                zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
        }
@@ -256,7 +294,8 @@ zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt)
 zap_name_t *
 zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt)
 {
-       zap_name_t *zn = zap_name_alloc(zap);
+       size_t key_len = strlen(key) + 1;
+       zap_name_t *zn = zap_name_alloc(zap, (key_len > ZAP_MAXNAMELEN));
        if (zap_name_init_str(zn, key, mt) != 0) {
                zap_name_free(zn);
                return (NULL);
@@ -491,7 +530,7 @@ mzap_open(dmu_buf_t *db)
                zfs_btree_create_custom(&zap->zap_m.zap_tree, mze_compare,
                    mze_find_in_buf, sizeof (mzap_ent_t), 512);
 
-               zap_name_t *zn = zap_name_alloc(zap);
+               zap_name_t *zn = zap_name_alloc(zap, B_FALSE);
                for (uint16_t i = 0; i < zap->zap_m.zap_num_chunks; i++) {
                        mzap_ent_phys_t *mze =
                            &zap_m_phys(zap)->mz_chunk[i];
@@ -698,7 +737,7 @@ mzap_upgrade(zap_t **zapp, const void *tag, dmu_tx_t *tx, zap_flags_t flags)
 
        fzap_upgrade(zap, tx, flags);
 
-       zap_name_t *zn = zap_name_alloc(zap);
+       zap_name_t *zn = zap_name_alloc(zap, B_FALSE);
        for (int i = 0; i < nchunks; i++) {
                mzap_ent_phys_t *mze = &mzp->mz_chunk[i];
                if (mze->mze_name[0] == 0)
@@ -1625,21 +1664,38 @@ zap_remove_uint64_by_dnode(dnode_t *dn, const uint64_t *key, int key_numints,
 }
 
 
-zap_attribute_t *
-zap_attribute_alloc(void)
+static zap_attribute_t *
+zap_attribute_alloc_impl(boolean_t longname)
 {
-       uint32_t len = ZAP_MAXNAMELEN;
        zap_attribute_t *za;
 
-       za = kmem_cache_alloc(zap_attr_cache, KM_SLEEP);
-       za->za_name_len = len;
+       za = kmem_cache_alloc((longname)? zap_attr_long_cache : zap_attr_cache,
+           KM_SLEEP);
+       za->za_name_len = (longname)? ZAP_MAXNAMELEN_NEW : ZAP_MAXNAMELEN;
        return (za);
 }
 
+zap_attribute_t *
+zap_attribute_alloc(void)
+{
+       return (zap_attribute_alloc_impl(B_FALSE));
+}
+
+zap_attribute_t *
+zap_attribute_long_alloc(void)
+{
+       return (zap_attribute_alloc_impl(B_TRUE));
+}
+
 void
 zap_attribute_free(zap_attribute_t *za)
 {
-       kmem_cache_free(zap_attr_cache, za);
+       if (za->za_name_len == ZAP_MAXNAMELEN) {
+               kmem_cache_free(zap_attr_cache, za);
+       } else {
+               ASSERT3U(za->za_name_len, ==, ZAP_MAXNAMELEN_NEW);
+               kmem_cache_free(zap_attr_long_cache, za);
+       }
 }
 
 /*
index e69b98896a2878fb8fea186710a55684b6237d83..8188a9e468653c1fbf00cb55f449d47f2712fcf4 100644 (file)
@@ -2594,6 +2594,41 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
                }
                break;
        }
+       case ZFS_PROP_LONGNAME:
+       {
+               zfsvfs_t *zfsvfs;
+
+               /*
+                * Ignore the checks if the property is being applied as part of
+                * 'zfs receive'. Because, we already check if the local pool
+                * has SPA_FEATURE_LONGNAME enabled in dmu_recv_begin_check().
+                */
+               if (source == ZPROP_SRC_RECEIVED) {
+                       cmn_err(CE_NOTE, "Skipping ZFS_PROP_LONGNAME checks "
+                           "for dsname=%s\n", dsname);
+                       err = -1;
+                       break;
+               }
+
+               if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_FALSE)) != 0) {
+                       cmn_err(CE_WARN, "%s:%d Failed to hold for dsname=%s "
+                           "err=%d\n", __FILE__, __LINE__, dsname, err);
+                       break;
+               }
+
+               if (!spa_feature_is_enabled(zfsvfs->z_os->os_spa,
+                   SPA_FEATURE_LONGNAME)) {
+                       err = ENOTSUP;
+               } else {
+                       /*
+                        * Set err to -1 to force the zfs_set_prop_nvlist code
+                        * down the default path to set the value in the nvlist.
+                        */
+                       err = -1;
+               }
+               zfsvfs_rele(zfsvfs, FTAG);
+               break;
+       }
        default:
                err = -1;
        }
index 2e28587c8b956e0cc6d4e5587b54028fb6c33019..824db8c689a7e2d5196bc612d741092b0c768b9a 100644 (file)
@@ -178,6 +178,7 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
        dmu_buf_t *prevdb = NULL;
        dmu_buf_t *sa_db = NULL;
        char *path = buf + len - 1;
+       char *comp_buf;
        int error;
 
        *path = '\0';
@@ -193,9 +194,10 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
                return (error);
        }
 
+       comp_buf = kmem_alloc(ZAP_MAXNAMELEN_NEW + 2, KM_SLEEP);
        for (;;) {
                uint64_t pobj = 0;
-               char component[MAXNAMELEN + 2];
+               char *component = comp_buf;
                size_t complen;
                int is_xattrdir = 0;
 
@@ -219,7 +221,8 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
                        strcpy(component + 1, "<xattrdir>");
                } else {
                        error = zap_value_search(osp, pobj, obj,
-                           ZFS_DIRENT_OBJ(-1ULL), component + 1);
+                           ZFS_DIRENT_OBJ(-1ULL), component + 1,
+                           ZAP_MAXNAMELEN_NEW);
                        if (error != 0)
                                break;
                }
@@ -250,6 +253,7 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
        if (error == 0)
                (void) memmove(buf, path, buf + len - path);
 
+       kmem_free(comp_buf, ZAP_MAXNAMELEN_NEW +2);
        return (error);
 }
 
index 4e262affb788a9c9036dab38d6898c79a0a17962..5534cd27f637edeaeae8c4920ad2cc1f831bf49e 100644 (file)
@@ -143,6 +143,10 @@ pre =
 post =
 tags = ['functional', 'largest_pool']
 
+[tests/functional/longname:Linux]
+tests = ['longname_001_pos', 'longname_002_pos', 'longname_003_pos']
+tags = ['functional', 'longname']
+
 [tests/functional/mmap:Linux]
 tests = ['mmap_libaio_001_pos', 'mmap_sync_001_pos']
 tags = ['functional', 'mmap']
@@ -187,7 +191,7 @@ tests = ['renameat2_noreplace', 'renameat2_exchange', 'renameat2_whiteout']
 tags = ['functional', 'renameat2']
 
 [tests/functional/rsend:Linux]
-tests = ['send_realloc_dnode_size', 'send_encrypted_files']
+tests = ['send_realloc_dnode_size', 'send_encrypted_files', 'send-c_longname']
 tags = ['functional', 'rsend']
 
 [tests/functional/simd:Linux]
index da6dc235cf571df920a5ab9e1447f516fd8e818d..206ee8ac154270b72053542eee912157622170a0 100644 (file)
@@ -1605,6 +1605,11 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
        functional/link_count/link_count_001.ksh \
        functional/link_count/link_count_root_inode.ksh \
        functional/link_count/setup.ksh \
+       functional/longname/cleanup.ksh \
+       functional/longname/longname_001_pos.ksh \
+       functional/longname/longname_002_pos.ksh \
+       functional/longname/longname_003_pos.ksh \
+       functional/longname/setup.ksh \
        functional/log_spacemap/log_spacemap_import_logs.ksh \
        functional/migration/cleanup.ksh \
        functional/migration/migration_001_pos.ksh \
@@ -1938,6 +1943,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
        functional/rsend/rsend_031_pos.ksh \
        functional/rsend/send-c_embedded_blocks.ksh \
        functional/rsend/send-c_incremental.ksh \
+       functional/rsend/send-c_longname.ksh \
        functional/rsend/send-c_lz4_disabled.ksh \
        functional/rsend/send-c_mixed_compression.ksh \
        functional/rsend/send-c_props.ksh \
index 50c1b7a9d09e9da5fd140b2d6eb27615b9640ef1..b5bc46dce993e34626df368a297a9b481a6b8b80 100644 (file)
@@ -110,5 +110,6 @@ if is_linux || is_freebsd; then
            "feature@vdev_zaps_v2"
            "feature@raidz_expansion"
            "feature@fast_dedup"
+           "feature@longname"
        )
 fi
diff --git a/tests/zfs-tests/tests/functional/longname/cleanup.ksh b/tests/zfs-tests/tests/functional/longname/cleanup.ksh
new file mode 100755 (executable)
index 0000000..aac8062
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/tests/zfs-tests/tests/functional/longname/longname_001_pos.ksh b/tests/zfs-tests/tests/functional/longname/longname_001_pos.ksh
new file mode 100755 (executable)
index 0000000..b7010fe
--- /dev/null
@@ -0,0 +1,132 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify the support for long filenames.
+#
+# STRATEGY:
+# 0.  On a fresh dataset ensure property "longname" is enabled by default.
+# 1.  Disable the longname.
+# 2.  Try to create a filename whose length is > 256 bytes. This should fail.
+# 3.  Enable "longname" property on the dataset.
+# 4.  Try to create files and dirs whose names are > 256 bytes.
+# 5.  Ensure that "ls" is able to list the file.
+# 6.  Ensure stat(1) is able to stat the file/directory.
+# 7.  Try to rename the files and directories
+# 8.  Try to delete the files and directories
+
+verify_runnable "global"
+
+WORKDIR=$TESTDIR/workdir
+MOVEDIR=$TESTDIR/movedir/level2/level3/level4/level5/level6
+
+function cleanup
+{
+        log_must rm -rf $WORKDIR
+        log_must rm -rf $TESTDIR/movedir
+}
+
+LONGNAME=$(printf 'a%.0s' {1..512})
+LONGFNAME="file-$LONGNAME"
+LONGDNAME="dir-$LONGNAME"
+LONGPNAME="mypipe-$LONGNAME"
+LONGCNAME="char_dev-$LONGNAME"
+LONGLNAME="link-$LONGNAME"
+LONGNAME_255=$(printf 'a%.0s' {1..255})
+LONGNAME_1023=$(printf 'a%.0s' {1..1023})
+
+
+log_assert "Check longname support for directories/files"
+
+log_onexit cleanup
+
+log_must mkdir $WORKDIR
+log_must mkdir -p $MOVEDIR
+
+# Disable longname support
+log_must zfs set longname=off $TESTPOOL/$TESTFS
+
+#Ensure a file of length 255bytes can be created
+log_must touch $WORKDIR/$LONGNAME_255
+
+#Where as file of length 256bytes should fail
+log_mustnot touch $WORKDIR/${LONGNAME_255}b
+
+# Try to create a file with long name with property "longname=off"
+log_mustnot touch $WORKDIR/$LONGFNAME
+log_mustnot mkdir $WORKDIR/$LONGDNAME
+
+# Enable longname support
+log_must zfs set longname=on $TESTPOOL/$TESTFS
+
+# Retry the longname creates and that should succeed
+log_must mkdir $WORKDIR/$LONGDNAME
+log_must touch $WORKDIR/$LONGFNAME
+
+# Should be able to create a file with name of 1023 chars
+log_must touch $WORKDIR/$LONGNAME_1023
+
+# And names longer that 1023 should fail
+log_mustnot touch $WORKDIR/${LONGNAME_1023}b
+
+# Ensure the longnamed dir/file can be listed.
+name=$(ls $WORKDIR/$LONGFNAME)
+if [[ "${name}" != "$WORKDIR/$LONGFNAME" ]]; then
+        log_fail "Unable to list: $WORKDIR/$LONGFNAME ret:$name"
+fi
+
+name=$(ls -d $WORKDIR/$LONGDNAME)
+if [[ "${name}" != "$WORKDIR/$LONGDNAME" ]]; then
+        log_fail "Unable to list: $WORKDIR/$LONGDNAME ret:$name"
+fi
+
+# Ensure stat works
+log_must stat $WORKDIR/$LONGFNAME
+log_must stat $WORKDIR/$LONGDNAME
+
+# Ensure softlinks can be created from a longname to
+# another longnamed file.
+log_must ln -s $WORKDIR/$LONGFNAME $WORKDIR/$LONGLNAME
+
+# Ensure a longnamed pipe and character device file
+# can be created
+log_must mknod $WORKDIR/$LONGPNAME p
+log_must mknod $WORKDIR/$LONGCNAME c 92 1
+
+# Ensure we can rename the longname file
+log_must mv $WORKDIR/$LONGFNAME $WORKDIR/file2
+
+# Delete the long named dir/file
+log_must rmdir $WORKDIR/$LONGDNAME
+log_must rm $WORKDIR/file2
+log_must rm $WORKDIR/$LONGPNAME
+log_must rm $WORKDIR/$LONGCNAME
+log_must rm $WORKDIR/$LONGLNAME
+
+log_pass
diff --git a/tests/zfs-tests/tests/functional/longname/longname_002_pos.ksh b/tests/zfs-tests/tests/functional/longname/longname_002_pos.ksh
new file mode 100755 (executable)
index 0000000..dd2acab
--- /dev/null
@@ -0,0 +1,115 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Check if longname feature is disabled by default and can be enabled.
+#
+# STRATEGY:
+# 1. Create a zpool with longname feature disabled
+# 2. Attempt to enable 'longname' property should fail.
+# 3. Attempt to create a longnamed (>255) file should fail.
+# 4. Enable the feature@longname
+# 5. Enable 'longname' property on the dataset.
+# 6. Should be able to create long named files and directories.
+# 7. Should be able to disable longname property.
+# 8. This should disallow creating new longnamed file/dirs. But, should be
+#    able to access existing longnamed files/dirs.
+verify_runnable "global"
+
+function cleanup
+{
+        log_must rm -rf $WORKDIR
+        poolexists $TESTPOOL && zpool destroy $TESTPOOL
+}
+
+log_assert "Check feature@longname and 'longname' dataset propery work correctly"
+
+log_onexit cleanup
+
+log_must zpool destroy $TESTPOOL
+
+log_must zpool create -o feature@longname=disabled $TESTPOOL $DISKS
+
+log_must zfs create $TESTPOOL/$TESTFS2
+
+log_must zfs set mountpoint=$TESTDIR2 $TESTPOOL/$TESTFS2
+
+log_mustnot zfs set longname=on $TESTPOOL/$TESTFS2
+
+LONGNAME=$(printf 'a%.0s' {1..512})
+LONGFNAME="file-$LONGNAME"
+LONGDNAME="dir-$LONGNAME"
+SHORTDNAME="dir-short"
+SHORTFNAME="file-short"
+WORKDIR=$TESTDIR2/workdir
+
+log_must mkdir $WORKDIR
+log_mustnot touch $WORKDIR/$LONGFNAME
+log_mustnot mkdir $WORKDIR/$LONGDNAME
+
+log_must zpool set feature@longname=enabled $TESTPOOL
+log_must zfs set longname=on $TESTPOOL/$TESTFS2
+
+log_must mkdir $WORKDIR/$LONGDNAME
+log_must touch $WORKDIR/$LONGFNAME
+
+# Ensure the above changes are synced out.
+log_must zpool sync $TESTPOOL
+
+# Ensure that the feature is activated once longnamed files are created.
+state=$(zpool get feature@longname -H -o value $TESTPOOL)
+log_note "feature@longname on pool: $TESTPOOL : $state"
+
+if [[ "$state" != "active" ]]; then
+       log_fail "feature@longname has state $state (expected active)"
+fi
+
+# Set longname=off.
+log_must zfs set longname=off $TESTPOOL/$TESTFS2
+
+# Ensure no new file/directory with longnames can be created or can be renamed
+# to.
+log_mustnot mkdir $WORKDIR/${LONGDNAME}.1
+log_mustnot touch $WORKDIR/${LONGFNAME}.1
+log_must mkdir $WORKDIR/$SHORTDNAME
+log_mustnot mv $WORKDIR/$SHORTDNAME $WORKDIR/${LONGDNAME}.1
+log_must touch $WORKDIR/$SHORTFNAME
+log_mustnot mv $WORKDIR/$SHORTFNAME $WORKDIR/${LONGFNAME}.1
+
+#Cleanup shortnames
+log_must rmdir $WORKDIR/$SHORTDNAME
+log_must rm $WORKDIR/$SHORTFNAME
+
+# But, should be able to stat and rename existing files
+log_must stat $WORKDIR/$LONGDNAME
+log_must stat $WORKDIR/$LONGFNAME
+log_must mv $WORKDIR/$LONGDNAME $WORKDIR/$SHORTDNAME
+log_must mv $WORKDIR/$LONGFNAME $WORKDIR/$SHORTFNAME
+
+log_pass
diff --git a/tests/zfs-tests/tests/functional/longname/longname_003_pos.ksh b/tests/zfs-tests/tests/functional/longname/longname_003_pos.ksh
new file mode 100755 (executable)
index 0000000..f684b51
--- /dev/null
@@ -0,0 +1,113 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Check if longnames are handled correctly by ZIL replay and feature is activated.
+#
+# STRATEGY:
+# 1. Create a zpool with longname feature disabled
+# 2. Enable the feature@longname
+# 3. Enable 'longname' property on the dataset.
+# 4. Freeze the zpool
+# 5. Create a longname
+# 6. Export and import the zpool.
+# 7. Replaying of longname create should activate the feature@longname
+verify_runnable "global"
+
+function cleanup
+{
+       log_must rm -rf $WORKDIR
+       poolexists $TESTPOOL && zpool destroy $TESTPOOL
+}
+
+log_assert "Check feature@longname and 'longname' dataset propery work correctly"
+
+log_onexit cleanup
+
+poolexists $TESTPOOL && zpool destroy $TESTPOOL
+
+log_must zpool create -o feature@longname=disabled $TESTPOOL $DISKS
+
+log_must zfs create $TESTPOOL/$TESTFS
+
+log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+LONGNAME=$(printf 'a%.0s' {1..512})
+LONGFNAME="file-$LONGNAME"
+LONGDNAME="dir-$LONGNAME"
+SHORTDNAME="dir-short"
+SHORTFNAME="file-short"
+WORKDIR=$TESTDIR/workdir
+
+log_must mkdir $WORKDIR
+
+log_must zpool set feature@longname=enabled $TESTPOOL
+log_must zfs set longname=on $TESTPOOL/$TESTFS
+
+# Ensure that the feature is NOT activated yet as no longnamed file is created.
+state=$(zpool get feature@longname -H -o value $TESTPOOL)
+log_note "feature@longname on pool: $TESTPOOL : $state"
+
+if [[ "$state" != "enabled" ]]; then
+       log_fail "feature@longname has state $state (expected enabled)"
+fi
+
+#
+# This dd command works around an issue where ZIL records aren't created
+# after freezing the pool unless a ZIL header already exists. Create a file
+# synchronously to force ZFS to write one out.
+#
+log_must dd if=/dev/zero of=/$WORKDIR/sync conv=fdatasync,fsync bs=1 count=1
+
+log_must zpool freeze $TESTPOOL
+
+log_must mkdir $WORKDIR/$LONGDNAME
+log_must touch $WORKDIR/$LONGFNAME
+
+# Export and re-import the zpool
+log_must zpool export $TESTPOOL
+log_must zpool import $TESTPOOL
+
+# Ensure that the feature is activated once longnamed files are created.
+state=$(zpool get feature@longname -H -o value $TESTPOOL)
+log_note "feature@longname on pool: $TESTPOOL : $state"
+if [[ "$state" != "active" ]]; then
+       log_fail "feature@longname has state $state (expected active)"
+fi
+
+# Destroying the dataset where the feature is activated should put the feature
+# back to 'enabled' state
+log_must zfs destroy -r $TESTPOOL/$TESTFS
+state=$(zpool get feature@longname -H -o value $TESTPOOL)
+log_note "feature@longname on pool: $TESTPOOL : $state"
+if [[ "$state" != "enabled" ]]; then
+       log_fail "feature@longname has state $state (expected active)"
+fi
+
+log_pass
diff --git a/tests/zfs-tests/tests/functional/longname/setup.ksh b/tests/zfs-tests/tests/functional/longname/setup.ksh
new file mode 100755 (executable)
index 0000000..3f67594
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
index 8f2222dceb0bd77784096cf8f82cc0a603f8fd69..b4fcdd7bbd244ef09812d146e002928b08d59ee0 100644 (file)
@@ -713,6 +713,7 @@ function stream_has_features
        feature[resuming]="100000"
        feature[redacted]="200000"
        feature[compressed]="400000"
+       feature[longname]="10000000"
 
        typeset flag known derived=0
        for flag in "$@"; do
diff --git a/tests/zfs-tests/tests/functional/rsend/send-c_longname.ksh b/tests/zfs-tests/tests/functional/rsend/send-c_longname.ksh
new file mode 100755 (executable)
index 0000000..3f7edc6
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/ksh -p
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+. $STF_SUITE/include/properties.shlib
+
+#
+# Description:
+# Verify that longname featureflag is present in the stream.
+#
+# Strategy:
+# 1. Create a filesystem with longnamed files/directories.
+# 2. Verify that the sendstream has the longname featureflag is present in the
+#    send stream.
+# 3. Verify the created streams can be received correctly.
+# 4. Verify that the longnamed files/directories are present in the received
+#    filesystem.
+#
+
+verify_runnable "both"
+
+log_assert "Verify that longnames are handled correctly in send stream."
+log_onexit cleanup_pool $POOL $POOL2 $POOL3
+
+typeset sendfs=$POOL/sendfs
+typeset recvfs=$POOL2/recvfs
+typeset recvfs3=$POOL3/recvfs
+typeset stream=$BACKDIR/stream
+typeset dump=$BACKDIR/dump
+
+log_must zfs create -o longname=on $sendfs
+typeset dir=$(get_prop mountpoint $sendfs)
+
+# Create a longnamed dir and a file in the send dataset
+LONGNAME=$(printf 'a%.0s' {1..512})
+LONGFNAME="file-$LONGNAME"
+LONGDNAME="dir-$LONGNAME"
+log_must mkdir $dir/$LONGDNAME
+log_must touch $dir/$LONGFNAME
+
+# When POOL3 is created by rsend.kshlib feature@longname is 'enabled'.
+# Recreate the POOL3 with feature@longname disabled.
+datasetexists $POOL3 && log_must zpool destroy $POOL3
+log_must zpool create -o feature@longname=disabled $POOL3 $DISK3
+
+# Generate the streams and zstreamdump output.
+log_must zfs snapshot $sendfs@now
+log_must eval "zfs send -p $sendfs@now >$stream"
+log_must eval "zstream dump -v <$stream >$dump"
+log_must eval "zfs recv $recvfs <$stream"
+cmp_ds_cont $sendfs $recvfs
+log_must stream_has_features $stream longname
+
+# Ensure the the receiving pool has feature@longname activated after receiving.
+feat_val=$(zpool get -H -o value feature@longname $POOL2)
+log_note "Zpool $POOL2 feature@longname=$feat_val"
+if [[ "$feat_val" != "active" ]]; then
+       log_fail "pool $POOL2 feature@longname=$feat_val (expected 'active')"
+fi
+
+# Receiving of the stream on $POOL3 should fail as longname is not enabled
+log_mustnot eval "zfs recv $recvfs3 <$stream"
+
+# Enable feature@longname and retry the receiving the stream.
+# It should succeed this time.
+log_must eval "zpool set feature@longname=enabled $POOL3"
+log_must eval "zfs recv $recvfs3 <$stream"
+
+log_must zfs get longname $recvfs3
+prop_val=$(zfs get -H -o value longname $recvfs3)
+log_note "dataset $recvfs3 has longname=$prop_val"
+if [[ "$prop_val" != "on" ]]; then
+       log_fail "$recvfs3 has longname=$prop_val (expected 'on')"
+fi
+
+#
+# TODO:
+# - Add a testcase to cover the case where send-stream does not contain
+#   properties (generated without "-p").
+#   In this case the target dataset would have longname files/directories which
+#   cannot be accessed if the dataset property 'longname=off'.
+#
+
+log_pass "Longnames are handled correctly in send/recv"