Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Aug 2013 17:27:13 +0000 (UTC)
From:      Alan Cox <alc@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r254719 - head/sys/vm
Message-ID:  <201308231727.r7NHRDUI077451@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: alc
Date: Fri Aug 23 17:27:12 2013
New Revision: 254719
URL: http://svnweb.freebsd.org/changeset/base/254719

Log:
  Addendum to r254141: The call to vm_radix_insert() in vm_page_cache() can
  reclaim the last preexisting cached page in the object, resulting in a call
  to vdrop().  Detect this scenario so that the vnode's hold count is
  correctly maintained.  Otherwise, we panic.
  
  Reported by:	scottl
  Tested by:	pho
  Discussed with:	attilio, jeff, kib

Modified:
  head/sys/vm/vm_page.c
  head/sys/vm/vm_radix.c
  head/sys/vm/vm_radix.h

Modified: head/sys/vm/vm_page.c
==============================================================================
--- head/sys/vm/vm_page.c	Fri Aug 23 17:03:43 2013	(r254718)
+++ head/sys/vm/vm_page.c	Fri Aug 23 17:27:12 2013	(r254719)
@@ -2558,6 +2558,15 @@ vm_page_cache(vm_page_t m)
 		vm_page_free(m);
 		return;
 	}
+
+	/*
+	 * The above call to vm_radix_insert() could reclaim the one pre-
+	 * existing cached page from this object, resulting in a call to
+	 * vdrop().
+	 */
+	if (!cache_was_empty)
+		cache_was_empty = vm_radix_is_singleton(&object->cache);
+
 	m->flags |= PG_CACHED;
 	cnt.v_cache_count++;
 	PCPU_INC(cnt.v_tcached);

Modified: head/sys/vm/vm_radix.c
==============================================================================
--- head/sys/vm/vm_radix.c	Fri Aug 23 17:03:43 2013	(r254718)
+++ head/sys/vm/vm_radix.c	Fri Aug 23 17:27:12 2013	(r254719)
@@ -432,6 +432,21 @@ restart:
 }
 
 /*
+ * Returns TRUE if the specified radix tree contains a single leaf and FALSE
+ * otherwise.
+ */
+boolean_t
+vm_radix_is_singleton(struct vm_radix *rtree)
+{
+	struct vm_radix_node *rnode;
+
+	rnode = vm_radix_getroot(rtree);
+	if (rnode == NULL)
+		return (FALSE);
+	return (vm_radix_isleaf(rnode));
+}
+
+/*
  * Returns the value stored at the index.  If the index is not present,
  * NULL is returned.
  */

Modified: head/sys/vm/vm_radix.h
==============================================================================
--- head/sys/vm/vm_radix.h	Fri Aug 23 17:03:43 2013	(r254718)
+++ head/sys/vm/vm_radix.h	Fri Aug 23 17:27:12 2013	(r254719)
@@ -37,6 +37,7 @@
 
 void		vm_radix_init(void);
 int		vm_radix_insert(struct vm_radix *rtree, vm_page_t page);
+boolean_t	vm_radix_is_singleton(struct vm_radix *rtree);
 vm_page_t	vm_radix_lookup(struct vm_radix *rtree, vm_pindex_t index);
 vm_page_t	vm_radix_lookup_ge(struct vm_radix *rtree, vm_pindex_t index);
 vm_page_t	vm_radix_lookup_le(struct vm_radix *rtree, vm_pindex_t index);



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