summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2008-02-26 17:16:48 +0000
committeralc <alc@FreeBSD.org>2008-02-26 17:16:48 +0000
commit0f6d386ab040ef54aae3b31491563ce4d847e79b (patch)
treeb8a5e70dfcae312f818c115771fd1ce7a4ee9318 /sys/vm
parentacbc673cee444a97dec8360417e1def350303d81 (diff)
downloadFreeBSD-src-0f6d386ab040ef54aae3b31491563ce4d847e79b.zip
FreeBSD-src-0f6d386ab040ef54aae3b31491563ce4d847e79b.tar.gz
Correct a long-standing error in vm_object_page_remove(). Specifically,
pmap_remove_all() must not be called on fictitious pages. To date, fictitious pages have been allocated from zeroed memory, effectively hiding this problem because the fictitious pages appear to have an empty pv list. Submitted by: Kostik Belousov Rewrite the comments describing vm_object_page_remove() to better describe what it does. Add an assertion. Reviewed by: Kostik Belousov MFC after: 1 week
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/vm_object.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 66ec1e9..a8ed619 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -1833,10 +1833,22 @@ vm_object_collapse(vm_object_t object)
/*
* vm_object_page_remove:
*
- * Removes all physical pages in the given range from the
- * object's list of pages. If the range's end is zero, all
- * physical pages from the range's start to the end of the object
- * are deleted.
+ * For the given object, either frees or invalidates each of the
+ * specified pages. In general, a page is freed. However, if a
+ * page is wired for any reason other than the existence of a
+ * managed, wired mapping, then it may be invalidated but not
+ * removed from the object. Pages are specified by the given
+ * range ["start", "end") and Boolean "clean_only". As a
+ * special case, if "end" is zero, then the range extends from
+ * "start" to the end of the object. If "clean_only" is TRUE,
+ * then only the non-dirty pages within the specified range are
+ * affected.
+ *
+ * In general, this operation should only be performed on objects
+ * that contain managed pages. There are two exceptions. First,
+ * it may be performed on the kernel and kmem objects. Second,
+ * it may be used by msync(..., MS_INVALIDATE) to invalidate
+ * device-backed pages.
*
* The object must be locked.
*/
@@ -1883,11 +1895,16 @@ again:
/*
* If the page is wired for any reason besides the
* existence of managed, wired mappings, then it cannot
- * be freed.
+ * be freed. For example, fictitious pages, which
+ * represent device memory, are inherently wired and
+ * cannot be freed. They can, however, be invalidated
+ * if "clean_only" is FALSE.
*/
if ((wirings = p->wire_count) != 0 &&
(wirings = pmap_page_wired_mappings(p)) != p->wire_count) {
- pmap_remove_all(p);
+ /* Fictitious pages do not have managed mappings. */
+ if ((p->flags & PG_FICTITIOUS) == 0)
+ pmap_remove_all(p);
/* Account for removal of managed, wired mappings. */
p->wire_count -= wirings;
if (!clean_only)
@@ -1896,6 +1913,8 @@ again:
}
if (vm_page_sleep_if_busy(p, TRUE, "vmopar"))
goto again;
+ KASSERT((p->flags & PG_FICTITIOUS) == 0,
+ ("vm_object_page_remove: page %p is fictitious", p));
if (clean_only && p->valid) {
pmap_remove_write(p);
if (p->valid & p->dirty)
OpenPOWER on IntegriCloud