From aef1512d7fbaf9604cdf428cbc97632651568cf9 Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Mon, 23 Sep 2024 22:54:17 +0000 Subject: [PATCH] Support for longnames for files/directories (FreeBSD part) Signed-off-by: Chunwei Chen --- module/os/freebsd/zfs/zfs_dir.c | 8 ++++++++ module/os/freebsd/zfs/zfs_vfsops.c | 13 ++++++++++++- module/os/freebsd/zfs/zfs_vnops_os.c | 25 ++++++++++++++++++++++++- tests/runfiles/common.run | 4 ++++ tests/runfiles/linux.run | 4 ---- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/module/os/freebsd/zfs/zfs_dir.c b/module/os/freebsd/zfs/zfs_dir.c index 1ac0ab1ed384..4f1f8ea38a44 100644 --- a/module/os/freebsd/zfs/zfs_dir.c +++ b/module/os/freebsd/zfs/zfs_dir.c @@ -627,6 +627,14 @@ 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(dl->dl_name) >= ZAP_MAXNAMELEN) { + 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, diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index b96393df4626..a3fac1636981 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -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); diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index 9df1fef60a13..1eb1713dc115 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -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; diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index f89a4b3e0aae..bedb8462f9f4 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -764,6 +764,10 @@ tags = ['functional', 'limits'] tests = ['link_count_001', 'link_count_root_inode'] tags = ['functional', 'link_count'] +[tests/functional/longname] +tests = ['longname_001_pos', 'longname_002_pos', 'longname_003_pos'] +tags = ['functional', 'longname'] + [tests/functional/migration] tests = ['migration_001_pos', 'migration_002_pos', 'migration_003_pos', 'migration_004_pos', 'migration_005_pos', 'migration_006_pos', diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 21ea7fd3b0af..aff7fbb91b53 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -142,10 +142,6 @@ 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']