diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index 943f4d8..dea2434 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -238,12 +238,6 @@ struct tmpfs_node { * allocated for it or it has been reclaimed). */ struct vnode * tn_vnode; - /* Pointer to the node returned by tmpfs_lookup() after doing a - * delete or a rename lookup; its value is only valid in these two - * situations. In case we were looking up . or .., it holds a null - * pointer. */ - struct tmpfs_dirent * tn_lookup_dirent; - /* interlock to protect tn_vpstate */ struct mtx tn_interlock; @@ -425,6 +419,8 @@ void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *); void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *); struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node, struct componentname *cnp); +struct tmpfs_dirent *tmpfs_dir_search(struct tmpfs_node *node, + struct tmpfs_node *f); int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index a4e9b6e..9a794ad 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -125,6 +125,8 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type, case VDIR: TAILQ_INIT(&nnode->tn_dir.tn_dirhead); + MPASS(parent != nnode); + MPASS(IMPLIES(parent == NULL, tmp->tm_root == NULL)); nnode->tn_dir.tn_parent = (parent == NULL) ? nnode : parent; nnode->tn_dir.tn_readdir_lastn = 0; nnode->tn_dir.tn_readdir_lastp = NULL; @@ -370,8 +372,6 @@ loop: /* FALLTHROUGH */ case VCHR: /* FALLTHROUGH */ - case VDIR: - /* FALLTHROUGH */ case VLNK: /* FALLTHROUGH */ case VREG: @@ -381,6 +381,10 @@ loop: case VFIFO: vp->v_op = &tmpfs_fifoop_entries; break; + case VDIR: + if (node->tn_dir.tn_parent == node) + vp->v_vflag |= VV_ROOT; + break; default: MPASS(0); @@ -388,8 +392,11 @@ loop: vnode_pager_setsize(vp, node->tn_size); error = insmntque(vp, mp); - if (error) + if (error) { + vgone(vp); + vput(vp); vp = NULL; + } unlock: TMPFS_NODE_LOCK(node); @@ -480,6 +487,7 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, } parent = dnode; + MPASS(parent != NULL); } else parent = NULL; @@ -598,6 +606,20 @@ tmpfs_dir_lookup(struct tmpfs_node *node, struct componentname *cnp) return found ? de : NULL; } +struct tmpfs_dirent * +tmpfs_dir_search(struct tmpfs_node *node, struct tmpfs_node *f) +{ + struct tmpfs_dirent *de; + + TMPFS_VALIDATE_DIR(node); + node->tn_status |= TMPFS_NODE_ACCESSED; + TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) { + if (de->td_node == f) + return (de); + } + return (NULL); +} + /* --------------------------------------------------------------------- */ /* diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c index 371c11a..16a0b6b 100644 --- a/sys/fs/tmpfs/tmpfs_vfsops.c +++ b/sys/fs/tmpfs/tmpfs_vfsops.c @@ -154,7 +154,6 @@ tmpfs_node_ctor(void *mem, int size, void *arg, int flags) node->tn_lockf = NULL; node->tn_vnode = NULL; node->tn_vpstate = 0; - node->tn_lookup_dirent = NULL; return (0); } diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 206b9de..e9e3677 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -106,12 +106,9 @@ tmpfs_lookup(struct vop_cachedlookup_args *v) vn_lock(dvp, ltype | LK_RETRY, td); vdrop(dvp); - - dnode->tn_dir.tn_parent->tn_lookup_dirent = NULL; } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { VREF(dvp); *vpp = dvp; - dnode->tn_lookup_dirent = NULL; error = 0; } else { de = tmpfs_dir_lookup(dnode, cnp); @@ -178,7 +175,6 @@ tmpfs_lookup(struct vop_cachedlookup_args *v) *vpp = NULL; goto out; } - tnode->tn_lookup_dirent = de; cnp->cn_flags |= SAVENAME; } else { error = tmpfs_alloc_vp(dvp->v_mount, tnode, @@ -786,7 +782,7 @@ tmpfs_remove(struct vop_remove_args *v) dnode = VP_TO_TMPFS_DIR(dvp); node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); - de = node->tn_lookup_dirent; + de = tmpfs_dir_search(dnode, node); MPASS(de != NULL); /* Files marked as immutable or append-only cannot be deleted. */ @@ -906,10 +902,7 @@ tmpfs_rename(struct vop_rename_args *v) MPASS(fcnp->cn_flags & HASBUF); MPASS(tcnp->cn_flags & HASBUF); - fdnode = VP_TO_TMPFS_DIR(fdvp); - fnode = VP_TO_TMPFS_NODE(fvp); tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); - de = fnode->tn_lookup_dirent; /* Disallow cross-device renames. * XXX Why isn't this done by the caller? */ @@ -927,11 +920,22 @@ tmpfs_rename(struct vop_rename_args *v) goto out; } + /* If we need to move the directory between entries, lock the + * source so that we can safely operate on it. */ + if (tdvp != fdvp) { + error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, tcnp->cn_thread); + if (error != 0) + goto out; + } + fdnode = VP_TO_TMPFS_DIR(fdvp); + fnode = VP_TO_TMPFS_NODE(fvp); + de = tmpfs_dir_search(fdnode, fnode); + /* Avoid manipulating '.' and '..' entries. */ if (de == NULL) { MPASS(fvp->v_type == VDIR); error = EINVAL; - goto out; + goto out_locked; } MPASS(de->td_node == fnode); @@ -946,34 +950,26 @@ tmpfs_rename(struct vop_rename_args *v) if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (tdnode->tn_flags & (APPEND | IMMUTABLE))) { error = EPERM; - goto out; + goto out_locked; } if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) { if (tnode->tn_size > 0) { error = ENOTEMPTY; - goto out; + goto out_locked; } } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) { error = ENOTDIR; - goto out; + goto out_locked; } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) { error = EISDIR; - goto out; + goto out_locked; } else { MPASS(fnode->tn_type != VDIR && tnode->tn_type != VDIR); } } - /* If we need to move the directory between entries, lock the - * source so that we can safely operate on it. */ - if (fdnode != tdnode) { - error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, tcnp->cn_thread); - if (error != 0) - goto out; - } - if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (fdnode->tn_flags & (APPEND | IMMUTABLE))) { error = EPERM; @@ -1045,7 +1041,7 @@ tmpfs_rename(struct vop_rename_args *v) * from the target directory. */ if (tvp != NULL) { /* Remove the old entry from the target directory. */ - de = tnode->tn_lookup_dirent; + de = tmpfs_dir_search(tdnode, tnode); tmpfs_dir_detach(tdvp, de); /* Free the directory entry we just deleted. Note that the @@ -1133,7 +1129,7 @@ tmpfs_rmdir(struct vop_rmdir_args *v) /* Get the directory entry associated with node (vp). This was * filled by tmpfs_lookup while looking up the entry. */ - de = node->tn_lookup_dirent; + de = tmpfs_dir_search(dnode, node); MPASS(TMPFS_DIRENT_MATCHES(de, v->a_cnp->cn_nameptr, v->a_cnp->cn_namelen));