Skip to content

Commit 749ad3d

Browse files
committed
FreeBSD: add support for lockless symlink lookup
Signed-off-by: Mateusz Guzik <[email protected]>
1 parent a631283 commit 749ad3d

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

include/os/freebsd/zfs/sys/zfs_znode_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern "C" {
5454
#define ZNODE_OS_FIELDS \
5555
struct zfsvfs *z_zfsvfs; \
5656
vnode_t *z_vnode; \
57+
char *z_cached_symlink; \
5758
uint64_t z_uid; \
5859
uint64_t z_gid; \
5960
uint64_t z_gen; \

module/os/freebsd/zfs/zfs_vnops_os.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4466,6 +4466,28 @@ zfs_freebsd_fplookup_vexec(struct vop_fplookup_vexec_args *v)
44664466
}
44674467
#endif
44684468

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+
44694491
#ifndef _SYS_SYSPROTO_H_
44704492
struct vop_access_args {
44714493
struct vnode *a_vp;
@@ -4953,6 +4975,10 @@ zfs_freebsd_symlink(struct vop_symlink_args *ap)
49534975
struct componentname *cnp = ap->a_cnp;
49544976
vattr_t *vap = ap->a_vap;
49554977
znode_t *zp = NULL;
4978+
#if __FreeBSD_version >= 1300139
4979+
char *symlink;
4980+
size_t symlink_len;
4981+
#endif
49564982
int rc;
49574983

49584984
ASSERT(cnp->cn_flags & SAVENAME);
@@ -4963,8 +4989,21 @@ zfs_freebsd_symlink(struct vop_symlink_args *ap)
49634989

49644990
rc = zfs_symlink(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap,
49654991
ap->a_target, &zp, cnp->cn_cred, 0 /* flags */);
4966-
if (rc == 0)
4992+
if (rc == 0) {
49674993
*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+
}
49685007
return (rc);
49695008
}
49705009

@@ -4980,8 +5019,42 @@ static int
49805019
zfs_freebsd_readlink(struct vop_readlink_args *ap)
49815020
{
49825021
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+
49835030
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);
49855058
}
49865059

49875060
#ifndef _SYS_SYSPROTO_H_
@@ -5743,6 +5816,9 @@ struct vop_vector zfs_vnodeops = {
57435816
.vop_reclaim = zfs_freebsd_reclaim,
57445817
#if __FreeBSD_version >= 1300102
57455818
.vop_fplookup_vexec = zfs_freebsd_fplookup_vexec,
5819+
#endif
5820+
#if __FreeBSD_version >= 1300139
5821+
.vop_fplookup_symlink = zfs_freebsd_fplookup_symlink,
57465822
#endif
57475823
.vop_access = zfs_freebsd_access,
57485824
.vop_allocate = VOP_EINVAL,
@@ -5792,6 +5868,9 @@ struct vop_vector zfs_fifoops = {
57925868
.vop_fsync = zfs_freebsd_fsync,
57935869
#if __FreeBSD_version >= 1300102
57945870
.vop_fplookup_vexec = zfs_freebsd_fplookup_vexec,
5871+
#endif
5872+
#if __FreeBSD_version >= 1300139
5873+
.vop_fplookup_symlink = zfs_freebsd_fplookup_symlink,
57955874
#endif
57965875
.vop_access = zfs_freebsd_access,
57975876
.vop_getattr = zfs_freebsd_getattr,
@@ -5815,6 +5894,9 @@ struct vop_vector zfs_shareops = {
58155894
.vop_default = &default_vnodeops,
58165895
#if __FreeBSD_version >= 1300121
58175896
.vop_fplookup_vexec = VOP_EAGAIN,
5897+
#endif
5898+
#if __FreeBSD_version >= 1300139
5899+
.vop_fplookup_symlink = VOP_EAGAIN,
58185900
#endif
58195901
.vop_access = zfs_freebsd_access,
58205902
.vop_inactive = zfs_freebsd_inactive,

module/os/freebsd/zfs/zfs_znode.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
444444
zp->z_blksz = blksz;
445445
zp->z_seq = 0x7A4653;
446446
zp->z_sync_cnt = 0;
447+
#if __FreeBSD_version >= 1300139
448+
atomic_store_ptr(&zp->z_cached_symlink, NULL);
449+
#endif
447450

448451
vp = ZTOV(zp);
449452

@@ -1237,6 +1240,9 @@ void
12371240
zfs_znode_free(znode_t *zp)
12381241
{
12391242
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
1243+
#if __FreeBSD_version >= 1300139
1244+
char *symlink;
1245+
#endif
12401246

12411247
ASSERT(zp->z_sa_hdl == NULL);
12421248
zp->z_vnode = NULL;
@@ -1246,6 +1252,15 @@ zfs_znode_free(znode_t *zp)
12461252
zfsvfs->z_nr_znodes--;
12471253
mutex_exit(&zfsvfs->z_znodes_lock);
12481254

1255+
#if __FreeBSD_version >= 1300139
1256+
symlink = atomic_load_ptr(&zp->z_cached_symlink);
1257+
if (symlink != NULL) {
1258+
atomic_store_rel_ptr((uintptr_t *)&zp->z_cached_symlink,
1259+
(uintptr_t)NULL);
1260+
cache_symlink_free(symlink, strlen(symlink) + 1);
1261+
}
1262+
#endif
1263+
12491264
if (zp->z_acl_cached) {
12501265
zfs_acl_free(zp->z_acl_cached);
12511266
zp->z_acl_cached = NULL;

0 commit comments

Comments
 (0)