MFp4 - Refine locking to eliminate some potential race/panics:

- Copy before testing a pointer.  This closes a race window.
 - Use msleep with the node interlock instead of tsleep.
 - Do proper locking around access to tn_vpstate.
 - Assert vnode VOP lock for dir_{atta,de}tach to capture
   inconsistent locking.

Suggested by:	kib
Submitted by:	delphij
Reviewed by:	Howard Su
Approved by:	re (tmpfs blanket)
This commit is contained in:
Xin LI 2007-08-03 06:24:31 +00:00
parent 036b81aa96
commit fb7557140e
2 changed files with 22 additions and 21 deletions

View File

@ -256,6 +256,7 @@ LIST_HEAD(tmpfs_node_list, tmpfs_node);
#define TMPFS_NODE_LOCK(node) mtx_lock(&(node)->tn_interlock)
#define TMPFS_NODE_UNLOCK(node) mtx_unlock(&(node)->tn_interlock)
#define TMPFS_NODE_MTX(node) (&(node)->tn_interlock)
#define TMPFS_VNODE_ALLOCATING 1
#define TMPFS_VNODE_WANT 2

View File

@ -215,9 +215,8 @@ tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
break;
case VREG:
if (node->tn_reg.tn_aobj != NULL) {
if (node->tn_reg.tn_aobj != NULL)
vm_object_deallocate(node->tn_reg.tn_aobj);
}
pages = node->tn_reg.tn_aobj_pages;
break;
@ -309,11 +308,8 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp,
int error;
struct vnode *vp;
vp = NULL;
loop:
if (node->tn_vnode != NULL) {
vp = node->tn_vnode;
if ((vp = node->tn_vnode) != NULL) {
error = vget(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (error)
return error;
@ -337,12 +333,16 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp,
TMPFS_NODE_LOCK(node);
if (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) {
node->tn_vpstate |= TMPFS_VNODE_WANT;
TMPFS_NODE_UNLOCK(node);
(void) tsleep((caddr_t) &node->tn_vpstate, 0, "tmpfs_vplock", 0);
goto loop;
}
error = msleep((caddr_t) &node->tn_vpstate,
TMPFS_NODE_MTX(node), PDROP | PCATCH,
"tmpfs_vplock", 0);
if (error)
return error;
node->tn_vpstate |= TMPFS_VNODE_ALLOCATING;
goto loop;
} else
node->tn_vpstate |= TMPFS_VNODE_ALLOCATING;
TMPFS_NODE_UNLOCK(node);
/* Get a new vnode and associate it with our node. */
@ -367,21 +367,18 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp,
case VBLK:
/* FALLTHROUGH */
case VCHR:
break;
/* FALLTHROUGH */
case VDIR:
break;
case VFIFO:
vp->v_op = &tmpfs_fifoop_entries;
break;
/* FALLTHROUGH */
case VLNK:
/* FALLTHROUGH */
case VREG:
/* FALLTHROUGH */
case VSOCK:
break;
case VFIFO:
vp->v_op = &tmpfs_fifoop_entries;
break;
default:
MPASS(0);
@ -391,6 +388,7 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp,
error = insmntque(vp, mp);
if (error) {
node->tn_vnode = NULL;
TMPFS_NODE_LOCK(node);
if (node->tn_vpstate & TMPFS_VNODE_WANT) {
node->tn_vpstate &= ~TMPFS_VNODE_WANT;
TMPFS_NODE_UNLOCK(node);
@ -402,8 +400,8 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp,
node->tn_vnode = vp;
unlock:
MPASS(node->tn_vpstate & TMPFS_VNODE_ALLOCATING);
TMPFS_NODE_LOCK(node);
MPASS(node->tn_vpstate & TMPFS_VNODE_ALLOCATING);
node->tn_vpstate &= ~TMPFS_VNODE_ALLOCATING;
if (node->tn_vpstate & TMPFS_VNODE_WANT) {
@ -530,6 +528,7 @@ tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de)
{
struct tmpfs_node *dnode;
ASSERT_VOP_ELOCKED(vp, __func__);
dnode = VP_TO_TMPFS_DIR(vp);
TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries);
dnode->tn_size += sizeof(struct tmpfs_dirent);
@ -549,6 +548,7 @@ tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de)
{
struct tmpfs_node *dnode;
ASSERT_VOP_ELOCKED(vp, __func__);
dnode = VP_TO_TMPFS_DIR(vp);
if (dnode->tn_dir.tn_readdir_lastp == de) {
@ -873,7 +873,7 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize)
swap_pager_freespace(uobj,
newpages, oldpages - newpages);
vm_object_page_remove(uobj,
OFF_TO_IDX(newsize + PAGE_MASK), 0, FALSE);
OFF_TO_IDX(newsize + PAGE_MASK), 0, FALSE);
}
/*