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
This commit is contained in:
alc 2013-08-23 17:27:12 +00:00
parent e9e439afa6
commit 1a535523cd
3 changed files with 25 additions and 0 deletions

View File

@ -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);

View File

@ -431,6 +431,21 @@ vm_radix_insert(struct vm_radix *rtree, vm_page_t page)
return (0);
}
/*
* 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.

View File

@ -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);