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
This commit is contained in:
parent
253d42b75f
commit
688559667f
@ -1833,10 +1833,22 @@ vm_object_collapse(vm_object_t object)
|
|||||||
/*
|
/*
|
||||||
* vm_object_page_remove:
|
* vm_object_page_remove:
|
||||||
*
|
*
|
||||||
* Removes all physical pages in the given range from the
|
* For the given object, either frees or invalidates each of the
|
||||||
* object's list of pages. If the range's end is zero, all
|
* specified pages. In general, a page is freed. However, if a
|
||||||
* physical pages from the range's start to the end of the object
|
* page is wired for any reason other than the existence of a
|
||||||
* are deleted.
|
* 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.
|
* The object must be locked.
|
||||||
*/
|
*/
|
||||||
@ -1883,11 +1895,16 @@ vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end,
|
|||||||
/*
|
/*
|
||||||
* If the page is wired for any reason besides the
|
* If the page is wired for any reason besides the
|
||||||
* existence of managed, wired mappings, then it cannot
|
* 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 &&
|
if ((wirings = p->wire_count) != 0 &&
|
||||||
(wirings = pmap_page_wired_mappings(p)) != p->wire_count) {
|
(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. */
|
/* Account for removal of managed, wired mappings. */
|
||||||
p->wire_count -= wirings;
|
p->wire_count -= wirings;
|
||||||
if (!clean_only)
|
if (!clean_only)
|
||||||
@ -1896,6 +1913,8 @@ vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end,
|
|||||||
}
|
}
|
||||||
if (vm_page_sleep_if_busy(p, TRUE, "vmopar"))
|
if (vm_page_sleep_if_busy(p, TRUE, "vmopar"))
|
||||||
goto again;
|
goto again;
|
||||||
|
KASSERT((p->flags & PG_FICTITIOUS) == 0,
|
||||||
|
("vm_object_page_remove: page %p is fictitious", p));
|
||||||
if (clean_only && p->valid) {
|
if (clean_only && p->valid) {
|
||||||
pmap_remove_write(p);
|
pmap_remove_write(p);
|
||||||
if (p->valid & p->dirty)
|
if (p->valid & p->dirty)
|
||||||
|
Loading…
Reference in New Issue
Block a user