aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/tmpfs/tmpfs_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/tmpfs/tmpfs_vnops.c')
-rw-r--r--sys/fs/tmpfs/tmpfs_vnops.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 66568e07b4d7..c716b393efdd 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -1444,13 +1444,40 @@ tmpfs_readlink(struct vop_readlink_args *v)
node = VP_TO_TMPFS_NODE(vp);
- error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
+ error = uiomove(node->tn_link_target, MIN(node->tn_size, uio->uio_resid),
uio);
tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node);
return (error);
}
+/*
+ * VOP_FPLOOKUP_SYMLINK routines are subject to special circumstances, see
+ * the comment above cache_fplookup for details.
+ *
+ * Check tmpfs_alloc_node for tmpfs-specific synchronisation notes.
+ */
+static int
+tmpfs_fplookup_symlink(struct vop_fplookup_symlink_args *v)
+{
+ struct vnode *vp;
+ struct tmpfs_node *node;
+ char *symlink;
+
+ vp = v->a_vp;
+ node = VP_TO_TMPFS_NODE_SMR(vp);
+ atomic_thread_fence_acq();
+ if (__predict_false(node == NULL))
+ return (EAGAIN);
+ if (!atomic_load_char(&node->tn_link_smr))
+ return (EAGAIN);
+ symlink = atomic_load_ptr(&node->tn_link_target);
+ if (symlink == NULL)
+ return (EAGAIN);
+
+ return (cache_symlink_resolve(v->a_fpl, symlink, node->tn_size));
+}
+
static int
tmpfs_inactive(struct vop_inactive_args *v)
{
@@ -1807,6 +1834,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
.vop_open = tmpfs_open,
.vop_close = tmpfs_close,
.vop_fplookup_vexec = tmpfs_fplookup_vexec,
+ .vop_fplookup_symlink = tmpfs_fplookup_symlink,
.vop_access = tmpfs_access,
.vop_stat = tmpfs_stat,
.vop_getattr = tmpfs_getattr,