Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Dec 2014 16:42:35 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r275619 - head/sys/kern
Message-ID:  <201412081642.sB8GgZbm006861@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Dec  8 16:42:34 2014
New Revision: 275619
URL: https://svnweb.freebsd.org/changeset/base/275619

Log:
  When getnewbuf_reuse_bp() is called to reclaim some (clean) buffer,
  the vnode owning the buffer is not locked.  More, it cannot be locked
  safely, since getnewbuf_reuse_bp() is called from newbuf(), and some
  other vnode is already locked, for which reused buffer will be
  reassigned.
  
  As the consequence, reclamation of the owning vnode could go in
  parallel, in particular, the call to vnode_destroy_vobject(), which
  deallocates the vm object and zeroes the v_bufobj->bo_object.  Note
  that the pages wired by the buffer are left wired and can be safely
  freed by the vfs_vmio_release() without the need for the vm object
  lock.  Also, seeing stale pointer to the v_object is safe due to vm
  object type stability.
  
  Check for bo_bufobj != NULL and cache the value in local variable to
  avoid trying to lock NULL vm object.
  
  Reported and tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

Modified:
  head/sys/kern/vfs_bio.c

Modified: head/sys/kern/vfs_bio.c
==============================================================================
--- head/sys/kern/vfs_bio.c	Mon Dec  8 16:33:18 2014	(r275618)
+++ head/sys/kern/vfs_bio.c	Mon Dec  8 16:42:34 2014	(r275619)
@@ -1883,15 +1883,18 @@ out:
 static void
 vfs_vmio_release(struct buf *bp)
 {
-	int i;
+	vm_object_t obj;
 	vm_page_t m;
+	int i;
 
 	if ((bp->b_flags & B_UNMAPPED) == 0) {
 		BUF_CHECK_MAPPED(bp);
 		pmap_qremove(trunc_page((vm_offset_t)bp->b_data), bp->b_npages);
 	} else
 		BUF_CHECK_UNMAPPED(bp);
-	VM_OBJECT_WLOCK(bp->b_bufobj->bo_object);
+	obj = bp->b_bufobj->bo_object;
+	if (obj != NULL)
+		VM_OBJECT_WLOCK(obj);
 	for (i = 0; i < bp->b_npages; i++) {
 		m = bp->b_pages[i];
 		bp->b_pages[i] = NULL;
@@ -1916,7 +1919,8 @@ vfs_vmio_release(struct buf *bp)
 			vm_page_try_to_cache(m);
 		vm_page_unlock(m);
 	}
-	VM_OBJECT_WUNLOCK(bp->b_bufobj->bo_object);
+	if (obj != NULL)
+		VM_OBJECT_WUNLOCK(obj);
 	
 	if (bp->b_bufsize) {
 		bufspacewakeup();



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201412081642.sB8GgZbm006861>