diff options
author | delphij <delphij@FreeBSD.org> | 2009-10-11 07:03:56 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2009-10-11 07:03:56 +0000 |
commit | 3af844143a011aa4b7f11fdf2429e752e219a8bc (patch) | |
tree | b60e455bba502c70843ad5fe0cb6ec8aa2645d57 /sys/fs/tmpfs/tmpfs_subr.c | |
parent | 79c1f884ef6881dc506df5a23203f4cc0a447a35 (diff) | |
download | FreeBSD-src-3af844143a011aa4b7f11fdf2429e752e219a8bc.zip FreeBSD-src-3af844143a011aa4b7f11fdf2429e752e219a8bc.tar.gz |
Add locking around access to parent node, and bail out when the parent
node is already freed rather than panicking the system.
PR: kern/122038
Submitted by: gk
Tested by: pho
MFC after: 1 week
Diffstat (limited to 'sys/fs/tmpfs/tmpfs_subr.c')
-rw-r--r-- | sys/fs/tmpfs/tmpfs_subr.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index dad634e..8dc8338 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -124,7 +124,9 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type, nnode->tn_dir.tn_readdir_lastn = 0; nnode->tn_dir.tn_readdir_lastp = NULL; nnode->tn_links++; + TMPFS_NODE_LOCK(nnode->tn_dir.tn_parent); nnode->tn_dir.tn_parent->tn_links++; + TMPFS_NODE_UNLOCK(nnode->tn_dir.tn_parent); break; case VFIFO: @@ -187,6 +189,7 @@ tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) #ifdef INVARIANTS TMPFS_NODE_LOCK(node); MPASS(node->tn_vnode == NULL); + MPASS((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0); TMPFS_NODE_UNLOCK(node); #endif @@ -312,6 +315,7 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag, loop: TMPFS_NODE_LOCK(node); if ((vp = node->tn_vnode) != NULL) { + MPASS((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0); VI_LOCK(vp); TMPFS_NODE_UNLOCK(node); vholdl(vp); @@ -330,6 +334,14 @@ loop: goto out; } + if ((node->tn_vpstate & TMPFS_VNODE_DOOMED) || + (node->tn_type == VDIR && node->tn_dir.tn_parent == NULL)) { + TMPFS_NODE_UNLOCK(node); + error = ENOENT; + vp = NULL; + goto out; + } + /* * otherwise lock the vp list while we call getnewvnode * since that can block. @@ -375,6 +387,7 @@ loop: vp->v_op = &tmpfs_fifoop_entries; break; case VDIR: + MPASS(node->tn_dir.tn_parent != NULL); if (node->tn_dir.tn_parent == node) vp->v_vflag |= VV_ROOT; break; @@ -428,10 +441,9 @@ tmpfs_free_vp(struct vnode *vp) node = VP_TO_TMPFS_NODE(vp); - TMPFS_NODE_LOCK(node); + mtx_assert(TMPFS_NODE_MTX(node), MA_OWNED); node->tn_vnode = NULL; vp->v_data = NULL; - TMPFS_NODE_UNLOCK(node); } /* --------------------------------------------------------------------- */ @@ -653,7 +665,18 @@ tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio) TMPFS_VALIDATE_DIR(node); MPASS(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT); + /* + * Return ENOENT if the current node is already removed. + */ + TMPFS_ASSERT_LOCKED(node); + if (node->tn_dir.tn_parent == NULL) { + return (ENOENT); + } + + TMPFS_NODE_LOCK(node->tn_dir.tn_parent); dent.d_fileno = node->tn_dir.tn_parent->tn_id; + TMPFS_NODE_UNLOCK(node->tn_dir.tn_parent); + dent.d_type = DT_DIR; dent.d_namlen = 2; dent.d_name[0] = '.'; |