summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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