Add a new option, OBJPR_NOTMAPPED, to vm_object_page_remove(). Passing this

option to vm_object_page_remove() asserts that the specified range of pages
is not mapped, or more precisely that none of these pages have any managed
mappings.  Thus, vm_object_page_remove() need not call pmap_remove_all() on
the pages.

This change not only saves time by eliminating pointless calls to
pmap_remove_all(), but it also eliminates an inconsistency in the use of
pmap_remove_all() versus related functions, like pmap_remove_write().  It
eliminates harmless but pointless calls to pmap_remove_all() that were being
performed on PG_UNMANAGED pages.

Update all of the existing assertions on pmap_remove_all() to reflect this
change.

Reviewed by:	kib
This commit is contained in:
Alan Cox 2011-06-29 16:40:41 +00:00
parent b37e0f6e9a
commit 6bbee8e28a
14 changed files with 100 additions and 78 deletions

View File

@ -2847,8 +2847,8 @@ pmap_remove_all(vm_page_t m)
vm_offset_t va;
vm_page_t free;
KASSERT((m->flags & PG_FICTITIOUS) == 0,
("pmap_remove_all: page %p is fictitious", m));
KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
("pmap_remove_all: page %p is not managed", m));
free = NULL;
vm_page_lock_queues();
pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m));

View File

@ -3120,8 +3120,8 @@ pmap_remove_all(vm_page_t m)
pmap_t curpm;
int flags = 0;
KASSERT((m->flags & PG_FICTITIOUS) == 0,
("pmap_remove_all: page %p is fictitious", m));
KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
("pmap_remove_all: page %p is not managed", m));
if (TAILQ_EMPTY(&m->md.pv_list))
return;
vm_page_lock_queues();

View File

@ -926,7 +926,7 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize)
if (newpages < oldpages) {
swap_pager_freespace(uobj, newpages, oldpages -
newpages);
vm_object_page_remove(uobj, newpages, 0, FALSE);
vm_object_page_remove(uobj, newpages, 0, 0);
}
/*

View File

@ -2927,8 +2927,8 @@ pmap_remove_all(vm_page_t m)
vm_offset_t va;
vm_page_t free;
KASSERT((m->flags & PG_FICTITIOUS) == 0,
("pmap_remove_all: page %p is fictitious", m));
KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
("pmap_remove_all: page %p is not managed", m));
free = NULL;
vm_page_lock_queues();
sched_pin();

View File

@ -2421,8 +2421,8 @@ pmap_remove_all(vm_page_t m)
pt_entry_t *pte, tpte;
vm_page_t free;
KASSERT((m->flags & PG_FICTITIOUS) == 0,
("pmap_remove_all: page %p is fictitious", m));
KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
("pmap_remove_all: page %p is not managed", m));
free = NULL;
vm_page_lock_queues();
sched_pin();

View File

@ -1424,8 +1424,8 @@ pmap_remove_all(vm_page_t m)
pmap_t oldpmap;
pv_entry_t pv;
KASSERT((m->flags & PG_FICTITIOUS) == 0,
("pmap_remove_all: page %p is fictitious", m));
KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
("pmap_remove_all: page %p is not managed", m));
vm_page_lock_queues();
while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
struct ia64_lpte *pte;

View File

@ -264,7 +264,7 @@ shm_dotruncate(struct shmfd *shmfd, off_t length)
/* Toss in memory pages. */
if (nobjsize < object->size)
vm_object_page_remove(object, nobjsize, object->size,
FALSE);
0);
/* Toss pages from swap. */
if (object->type == OBJT_SWAP)

View File

@ -1190,8 +1190,8 @@ bufobj_invalbuf(struct bufobj *bo, int flags, int slpflag, int slptimeo)
*/
if (bo->bo_object != NULL && (flags & (V_ALT | V_NORMAL)) == 0) {
VM_OBJECT_LOCK(bo->bo_object);
vm_object_page_remove(bo->bo_object, 0, 0,
(flags & V_SAVE) ? TRUE : FALSE);
vm_object_page_remove(bo->bo_object, 0, 0, (flags & V_SAVE) ?
OBJPR_CLEANONLY : 0);
VM_OBJECT_UNLOCK(bo->bo_object);
}

View File

@ -1711,8 +1711,8 @@ pmap_remove_all(vm_page_t m)
pv_entry_t pv;
pt_entry_t *pte, tpte;
KASSERT((m->flags & PG_FICTITIOUS) == 0,
("pmap_remove_all: page %p is fictitious", m));
KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
("pmap_remove_all: page %p is not managed", m));
vm_page_lock_queues();
if (m->md.pv_flags & PV_TABLE_REF)

View File

@ -128,7 +128,7 @@ ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
if ((object = vp->v_object) == NULL)
return;
VM_OBJECT_LOCK(object);
vm_object_page_remove(object, start, end, FALSE);
vm_object_page_remove(object, start, end, 0);
VM_OBJECT_UNLOCK(object);
}

View File

@ -2708,7 +2708,15 @@ vm_map_entry_delete(vm_map_t map, vm_map_entry_t entry)
((object->flags & (OBJ_NOSPLIT|OBJ_ONEMAPPING)) == OBJ_ONEMAPPING ||
object == kernel_object || object == kmem_object)) {
vm_object_collapse(object);
vm_object_page_remove(object, offidxstart, offidxend, FALSE);
/*
* The option OBJPR_NOTMAPPED can be passed here
* because vm_map_delete() already performed
* pmap_remove() on the only mapping to this range
* of pages.
*/
vm_object_page_remove(object, offidxstart, offidxend,
OBJPR_NOTMAPPED);
if (object->type == OBJT_SWAP)
swap_pager_freespace(object, offidxstart, count);
if (offidxend >= object->size &&

View File

@ -923,6 +923,10 @@ vm_object_page_collect_flush(vm_object_t object, vm_page_t p, int pagerflags,
* We invalidate (remove) all pages from the address space
* for semantic correctness.
*
* If the backing object is a device object with unmanaged pages, then any
* mappings to the specified range of pages must be removed before this
* function is called.
*
* Note: certain anonymous maps, such as MAP_NOSYNC maps,
* may start out with a NULL object.
*/
@ -978,12 +982,19 @@ vm_object_sync(vm_object_t object, vm_ooffset_t offset, vm_size_t size,
}
if ((object->type == OBJT_VNODE ||
object->type == OBJT_DEVICE) && invalidate) {
boolean_t purge;
purge = old_msync || (object->type == OBJT_DEVICE);
vm_object_page_remove(object,
OFF_TO_IDX(offset),
OFF_TO_IDX(offset + size + PAGE_MASK),
purge ? FALSE : TRUE);
if (object->type == OBJT_DEVICE)
/*
* The option OBJPR_NOTMAPPED must be passed here
* because vm_object_page_remove() cannot remove
* unmanaged mappings.
*/
flags = OBJPR_NOTMAPPED;
else if (old_msync)
flags = 0;
else
flags = OBJPR_CLEANONLY;
vm_object_page_remove(object, OFF_TO_IDX(offset),
OFF_TO_IDX(offset + size + PAGE_MASK), flags);
}
VM_OBJECT_UNLOCK(object);
}
@ -1754,76 +1765,70 @@ vm_object_collapse(vm_object_t object)
* vm_object_page_remove:
*
* 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.
* 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 the option
* OBJPR_CLEANONLY. As a special case, if "end" is zero, then the range
* extends from "start" to the end of the object. If the option
* OBJPR_CLEANONLY is specified, then only the non-dirty pages within the
* specified range are affected. If the option OBJPR_NOTMAPPED is
* specified, then the pages within the specified range must have no
* mappings. Otherwise, if this option is not specified, any mappings to
* the specified pages are removed before the pages are freed or
* invalidated.
*
* 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. In both of these cases, "clean_only"
* must be FALSE.
* In general, this operation should only be performed on objects that
* contain managed pages. There are, however, two exceptions. First, it
* is performed on the kernel and kmem objects by vm_map_entry_delete().
* Second, it is used by msync(..., MS_INVALIDATE) to invalidate device-
* backed pages. In both of these cases, the option OBJPR_CLEANONLY must
* not be specified and the option OBJPR_NOTMAPPED must be specified.
*
* The object must be locked.
*/
void
vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end,
boolean_t clean_only)
int options)
{
vm_page_t p, next;
int wirings;
VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
KASSERT((object->type != OBJT_DEVICE && object->type != OBJT_PHYS) ||
(options & (OBJPR_CLEANONLY | OBJPR_NOTMAPPED)) == OBJPR_NOTMAPPED,
("vm_object_page_remove: illegal options for object %p", object));
if (object->resident_page_count == 0)
goto skipmemq;
/*
* Since physically-backed objects do not use managed pages, we can't
* remove pages from the object (we must instead remove the page
* references, and then destroy the object).
*/
KASSERT(object->type != OBJT_PHYS || object == kernel_object ||
object == kmem_object,
("attempt to remove pages from a physical object"));
vm_object_pip_add(object, 1);
again:
p = vm_page_find_least(object, start);
/*
* Assert: the variable p is either (1) the page with the
* least pindex greater than or equal to the parameter pindex
* or (2) NULL.
* Here, the variable "p" is either (1) the page with the least pindex
* greater than or equal to the parameter "start" or (2) NULL.
*/
for (;
p != NULL && (p->pindex < end || end == 0);
p = next) {
for (; p != NULL && (p->pindex < end || end == 0); p = next) {
next = TAILQ_NEXT(p, listq);
/*
* If the page is wired for any reason besides the
* existence of managed, wired mappings, then it cannot
* 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 the page is wired for any reason besides the existence
* of managed, wired mappings, then it cannot be freed. For
* example, fictitious pages, which represent device memory,
* are inherently wired and cannot be freed. They can,
* however, be invalidated if the option OBJPR_CLEANONLY is
* not specified.
*/
vm_page_lock(p);
if ((wirings = p->wire_count) != 0 &&
(wirings = pmap_page_wired_mappings(p)) != p->wire_count) {
/* Fictitious pages do not have managed mappings. */
if ((p->flags & PG_FICTITIOUS) == 0)
if ((options & OBJPR_NOTMAPPED) == 0) {
pmap_remove_all(p);
/* Account for removal of managed, wired mappings. */
p->wire_count -= wirings;
if (!clean_only) {
/* Account for removal of wired mappings. */
if (wirings != 0)
p->wire_count -= wirings;
}
if ((options & OBJPR_CLEANONLY) == 0) {
p->valid = 0;
vm_page_undirty(p);
}
@ -1834,17 +1839,20 @@ vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end,
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 ((options & OBJPR_CLEANONLY) != 0 && p->valid != 0) {
if ((options & OBJPR_NOTMAPPED) == 0)
pmap_remove_write(p);
if (p->dirty) {
vm_page_unlock(p);
continue;
}
}
pmap_remove_all(p);
/* Account for removal of managed, wired mappings. */
if (wirings != 0)
p->wire_count -= wirings;
if ((options & OBJPR_NOTMAPPED) == 0) {
pmap_remove_all(p);
/* Account for removal of wired mappings. */
if (wirings != 0)
p->wire_count -= wirings;
}
vm_page_free(p);
vm_page_unlock(p);
}
@ -1991,9 +1999,8 @@ vm_object_coalesce(vm_object_t prev_object, vm_ooffset_t prev_offset,
* deallocation.
*/
if (next_pindex < prev_object->size) {
vm_object_page_remove(prev_object,
next_pindex,
next_pindex + next_size, FALSE);
vm_object_page_remove(prev_object, next_pindex, next_pindex +
next_size, 0);
if (prev_object->type == OBJT_SWAP)
swap_pager_freespace(prev_object,
next_pindex, next_size);

View File

@ -168,6 +168,12 @@ struct vm_object {
#define OBJPC_INVAL 0x2 /* invalidate */
#define OBJPC_NOSYNC 0x4 /* skip if PG_NOSYNC */
/*
* The following options are supported by vm_object_page_remove().
*/
#define OBJPR_CLEANONLY 0x1 /* Don't remove dirty pages. */
#define OBJPR_NOTMAPPED 0x2 /* Don't unmap pages. */
TAILQ_HEAD(object_q, vm_object);
extern struct object_q vm_object_list; /* list of allocated objects */
@ -219,7 +225,8 @@ void vm_object_set_writeable_dirty (vm_object_t);
void vm_object_init (void);
void vm_object_page_clean(vm_object_t object, vm_ooffset_t start,
vm_ooffset_t end, int flags);
void vm_object_page_remove (vm_object_t, vm_pindex_t, vm_pindex_t, boolean_t);
void vm_object_page_remove(vm_object_t object, vm_pindex_t start,
vm_pindex_t end, int options);
boolean_t vm_object_populate(vm_object_t, vm_pindex_t, vm_pindex_t);
void vm_object_print(long addr, boolean_t have_addr, long count, char *modif);
void vm_object_reference (vm_object_t);

View File

@ -387,7 +387,7 @@ vnode_pager_setsize(vp, nsize)
*/
if (nobjsize < object->size)
vm_object_page_remove(object, nobjsize, object->size,
FALSE);
0);
/*
* this gets rid of garbage at the end of a page that is now
* only partially backed by the vnode.