From aed76ef1f778cc4185ddd699631316d05d6811b6 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 12 Sep 2010 10:30:38 -0700 Subject: [PATCH] kernel - Fix one-cycle MP race in vshouldmsync() * vshouldmsync() is the mntvnode fast function, which is called without any vnode lock. vp->v_object can thus get ripped out from under the scan function. Hold vmobj_token through the scan so any pointer accessed via v_object remains stable (even if no longer related to the vnode due to the race). Reported-by: swildner --- sys/kern/vfs_mount.c | 7 +++++++ sys/kern/vfs_subr.c | 14 ++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 0ccb9039cb..47fb214fc5 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -986,6 +986,11 @@ insmntque(struct vnode *vp, struct mount *mp) * arbitrarily block. The scanning code guarentees consistency of operation * even if the slow function deletes or moves the node, or blocks and some * other thread deletes or moves the node. + * + * NOTE: We hold vmobj_token to prevent a VM object from being destroyed + * out from under the fastfunc()'s vnode test. It will not prevent + * v_object from getting NULL'd out but it will ensure that the + * pointer (if we race) will remain stable. */ int vmntvnodescan( @@ -1003,6 +1008,7 @@ vmntvnodescan( int count = 0; lwkt_gettoken(&mntvnode_token); + lwkt_gettoken(&vmobj_token); /* * If asked to do one pass stop after iterating available vnodes. @@ -1121,6 +1127,7 @@ next: info.vp = TAILQ_NEXT(vp, v_nmntvnodes); } TAILQ_REMOVE(&mntvnodescan_list, &info, entry); + lwkt_reltoken(&vmobj_token); lwkt_reltoken(&mntvnode_token); return(r); } diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 32a333bfea..398820edbf 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -153,16 +153,22 @@ rb_buf_compare(struct buf *b1, struct buf *b2) /* * Returns non-zero if the vnode is a candidate for lazy msyncing. + * + * NOTE: v_object is not stable (this scan can race), however the + * mntvnodescan code holds vmobj_token so any VM object we + * do find will remain stable storage. */ static __inline int vshouldmsync(struct vnode *vp) { + vm_object_t object; + if (vp->v_auxrefs != 0 || vp->v_sysref.refcnt > 0) return (0); /* other holders */ - if (vp->v_object && - (vp->v_object->ref_count || vp->v_object->resident_page_count)) { - return (0); - } + object = vp->v_object; + cpu_ccfence(); + if (object && (object->ref_count || object->resident_page_count)) + return(0); return (1); } -- 2.41.0