@@ -4466,6 +4466,28 @@ zfs_freebsd_fplookup_vexec(struct vop_fplookup_vexec_args *v)
4466
4466
}
4467
4467
#endif
4468
4468
4469
+ #if __FreeBSD_version >= 1300139
4470
+ static int
4471
+ zfs_freebsd_fplookup_symlink (struct vop_fplookup_symlink_args * v )
4472
+ {
4473
+ vnode_t * vp ;
4474
+ znode_t * zp ;
4475
+ char * target ;
4476
+
4477
+ vp = v -> a_vp ;
4478
+ zp = VTOZ_SMR (vp );
4479
+ if (__predict_false (zp == NULL )) {
4480
+ return (EAGAIN );
4481
+ }
4482
+
4483
+ target = atomic_load_consume_ptr (& zp -> z_cached_symlink );
4484
+ if (target == NULL ) {
4485
+ return (EAGAIN );
4486
+ }
4487
+ return (cache_symlink_resolve (v -> a_fpl , target , strlen (target )));
4488
+ }
4489
+ #endif
4490
+
4469
4491
#ifndef _SYS_SYSPROTO_H_
4470
4492
struct vop_access_args {
4471
4493
struct vnode * a_vp ;
@@ -4953,6 +4975,10 @@ zfs_freebsd_symlink(struct vop_symlink_args *ap)
4953
4975
struct componentname * cnp = ap -> a_cnp ;
4954
4976
vattr_t * vap = ap -> a_vap ;
4955
4977
znode_t * zp = NULL ;
4978
+ #if __FreeBSD_version >= 1300139
4979
+ char * symlink ;
4980
+ size_t symlink_len ;
4981
+ #endif
4956
4982
int rc ;
4957
4983
4958
4984
ASSERT (cnp -> cn_flags & SAVENAME );
@@ -4963,8 +4989,21 @@ zfs_freebsd_symlink(struct vop_symlink_args *ap)
4963
4989
4964
4990
rc = zfs_symlink (VTOZ (ap -> a_dvp ), cnp -> cn_nameptr , vap ,
4965
4991
ap -> a_target , & zp , cnp -> cn_cred , 0 /* flags */ );
4966
- if (rc == 0 )
4992
+ if (rc == 0 ) {
4967
4993
* ap -> a_vpp = ZTOV (zp );
4994
+ ASSERT_VOP_ELOCKED (ZTOV (zp ), __func__ );
4995
+ #if __FreeBSD_version >= 1300139
4996
+ MPASS (zp -> z_cached_symlink == NULL );
4997
+ symlink_len = strlen (ap -> a_target );
4998
+ symlink = cache_symlink_alloc (symlink_len + 1 , M_WAITOK );
4999
+ if (symlink != NULL ) {
5000
+ memcpy (symlink , ap -> a_target , symlink_len );
5001
+ symlink [symlink_len ] = '\0' ;
5002
+ atomic_store_rel_ptr ((uintptr_t * )& zp -> z_cached_symlink ,
5003
+ (uintptr_t )symlink );
5004
+ }
5005
+ #endif
5006
+ }
4968
5007
return (rc );
4969
5008
}
4970
5009
@@ -4980,8 +5019,42 @@ static int
4980
5019
zfs_freebsd_readlink (struct vop_readlink_args * ap )
4981
5020
{
4982
5021
zfs_uio_t uio ;
5022
+ int error ;
5023
+ #if __FreeBSD_version >= 1300139
5024
+ znode_t * zp = VTOZ (ap -> a_vp );
5025
+ char * symlink , * base ;
5026
+ size_t symlink_len ;
5027
+ bool trycache ;
5028
+ #endif
5029
+
4983
5030
zfs_uio_init (& uio , ap -> a_uio );
4984
- return (zfs_readlink (ap -> a_vp , & uio , ap -> a_cred , NULL ));
5031
+ #if __FreeBSD_version >= 1300139
5032
+ trycache = false;
5033
+ if (zfs_uio_segflg (& uio ) == UIO_SYSSPACE &&
5034
+ zfs_uio_iovcnt (& uio ) == 1 ) {
5035
+ base = zfs_uio_iovbase (& uio , 0 );
5036
+ symlink_len = zfs_uio_iovlen (& uio , 0 );
5037
+ trycache = true;
5038
+ }
5039
+ #endif
5040
+ error = zfs_readlink (ap -> a_vp , & uio , ap -> a_cred , NULL );
5041
+ #if __FreeBSD_version >= 1300139
5042
+ if (atomic_load_ptr (& zp -> z_cached_symlink ) != NULL ||
5043
+ error != 0 || !trycache ) {
5044
+ return (error );
5045
+ }
5046
+ symlink_len -= zfs_uio_resid (& uio );
5047
+ symlink = cache_symlink_alloc (symlink_len + 1 , M_WAITOK );
5048
+ if (symlink != NULL ) {
5049
+ memcpy (symlink , base , symlink_len );
5050
+ symlink [symlink_len ] = '\0' ;
5051
+ if (!atomic_cmpset_rel_ptr ((uintptr_t * )& zp -> z_cached_symlink ,
5052
+ (uintptr_t )NULL , (uintptr_t )symlink )) {
5053
+ cache_symlink_free (symlink , symlink_len + 1 );
5054
+ }
5055
+ }
5056
+ #endif
5057
+ return (error );
4985
5058
}
4986
5059
4987
5060
#ifndef _SYS_SYSPROTO_H_
@@ -5743,6 +5816,9 @@ struct vop_vector zfs_vnodeops = {
5743
5816
.vop_reclaim = zfs_freebsd_reclaim ,
5744
5817
#if __FreeBSD_version >= 1300102
5745
5818
.vop_fplookup_vexec = zfs_freebsd_fplookup_vexec ,
5819
+ #endif
5820
+ #if __FreeBSD_version >= 1300139
5821
+ .vop_fplookup_symlink = zfs_freebsd_fplookup_symlink ,
5746
5822
#endif
5747
5823
.vop_access = zfs_freebsd_access ,
5748
5824
.vop_allocate = VOP_EINVAL ,
@@ -5792,6 +5868,9 @@ struct vop_vector zfs_fifoops = {
5792
5868
.vop_fsync = zfs_freebsd_fsync ,
5793
5869
#if __FreeBSD_version >= 1300102
5794
5870
.vop_fplookup_vexec = zfs_freebsd_fplookup_vexec ,
5871
+ #endif
5872
+ #if __FreeBSD_version >= 1300139
5873
+ .vop_fplookup_symlink = zfs_freebsd_fplookup_symlink ,
5795
5874
#endif
5796
5875
.vop_access = zfs_freebsd_access ,
5797
5876
.vop_getattr = zfs_freebsd_getattr ,
@@ -5815,6 +5894,9 @@ struct vop_vector zfs_shareops = {
5815
5894
.vop_default = & default_vnodeops ,
5816
5895
#if __FreeBSD_version >= 1300121
5817
5896
.vop_fplookup_vexec = VOP_EAGAIN ,
5897
+ #endif
5898
+ #if __FreeBSD_version >= 1300139
5899
+ .vop_fplookup_symlink = VOP_EAGAIN ,
5818
5900
#endif
5819
5901
.vop_access = zfs_freebsd_access ,
5820
5902
.vop_inactive = zfs_freebsd_inactive ,
0 commit comments