MFp4: Several fixes to tmpfs which makes it to survive from pho@'s

strees2 suite, to quote his letter, this change:

1. It removes the tn_lookup_dirent stuff. I think this cannot be fixed,
   because nothing protects vnode/tmpfs node between lookup is done, and
   actual operation is performed, in the case the vnode lock is dropped.
   At least, this is the case with the from vnode for rename.

   For now, we do the linear lookup in the parent node. This has its own
   drawbacks. Not mentioning speed (that could be fixed by using hash), the
   real problem is the situation where several hardlinks exist in the dvp.
   But, I think this is fixable.

2. The patch restores the VV_ROOT flag on the root vnode after it became
   reclaimed and allocated again. This fixes MPASS assertion at the start
   of the tmpfs_lookup() reported by many.

Submitted by:	kib
This commit is contained in:
Xin LI 2007-11-18 04:52:40 +00:00
parent e0f51ae7cd
commit 7871e52bfd
4 changed files with 46 additions and 33 deletions

View File

@ -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);

View File

@ -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 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag,
/* FALLTHROUGH */
case VCHR:
/* FALLTHROUGH */
case VDIR:
/* FALLTHROUGH */
case VLNK:
/* FALLTHROUGH */
case VREG:
@ -381,6 +381,10 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag,
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 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag,
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);
}
/* --------------------------------------------------------------------- */
/*

View File

@ -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);
}

View File

@ -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));