diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -375,24 +375,35 @@ return (vaccess_vexec_smr(mode, node->tn_uid, node->tn_gid, cred)); } +static int +tmpfs_access_locked(struct vnode *vp, struct tmpfs_node *node, + accmode_t accmode, struct ucred *cred) +{ + if (!mtx_owned(TMPFS_NODE_MTX(node))) { + ASSERT_VOP_LOCKED(vp, + "tmpfs_access_locked needs locked vnode or node"); + } + + if ((accmode & VWRITE) != 0 && (node->tn_flags & IMMUTABLE) != 0) + return (EPERM); + return (vaccess(vp->v_type, node->tn_mode, node->tn_uid, node->tn_gid, + accmode, cred)); +} + int tmpfs_access(struct vop_access_args *v) { struct vnode *vp = v->a_vp; - accmode_t accmode = v->a_accmode; struct ucred *cred = v->a_cred; + struct tmpfs_node *node = VP_TO_TMPFS_NODE(vp); mode_t all_x = S_IXUSR | S_IXGRP | S_IXOTH; - int error; - struct tmpfs_node *node; - - MPASS(VOP_ISLOCKED(vp)); - - node = VP_TO_TMPFS_NODE(vp); + accmode_t accmode = v->a_accmode; /* * Common case path lookup. */ - if (__predict_true(accmode == VEXEC && (node->tn_mode & all_x) == all_x)) + if (__predict_true(accmode == VEXEC && + (node->tn_mode & all_x) == all_x)) return (0); switch (vp->v_type) { @@ -401,10 +412,9 @@ case VLNK: /* FALLTHROUGH */ case VREG: - if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { - error = EROFS; - goto out; - } + if ((accmode & VWRITE) != 0 && + (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) + return (EROFS); break; case VBLK: @@ -417,22 +427,10 @@ break; default: - error = EINVAL; - goto out; - } - - if (accmode & VWRITE && node->tn_flags & IMMUTABLE) { - error = EPERM; - goto out; + return (EINVAL); } - error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, node->tn_gid, - accmode, cred); - -out: - MPASS(VOP_ISLOCKED(vp)); - - return (error); + return (tmpfs_access_locked(vp, node, accmode, cred)); } int @@ -1129,7 +1127,10 @@ if (de->td_node->tn_type == VDIR) { struct tmpfs_node *n; - error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, curthread); + TMPFS_NODE_LOCK(fnode); + error = tmpfs_access_locked(fvp, fnode, VWRITE, + tcnp->cn_cred); + TMPFS_NODE_UNLOCK(fnode); if (error) { if (newname != NULL) free(newname, M_TMPFSNAME); @@ -1157,7 +1158,7 @@ TMPFS_UNLOCK(tmp); error = EINVAL; if (newname != NULL) - free(newname, M_TMPFSNAME); + free(newname, M_TMPFSNAME); goto out_locked; } parent = n->tn_dir.tn_parent;