diff options
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vm_map.c | 10 | ||||
-rw-r--r-- | sys/vm/vm_object.c | 123 | ||||
-rw-r--r-- | sys/vm/vm_object.h | 9 | ||||
-rw-r--r-- | sys/vm/vnode_pager.c | 2 |
4 files changed, 83 insertions, 61 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 752354a..31886af 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -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 && diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 1a3d398..b5788f5 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -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 @@ again: 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); diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h index 0f4f47d..a11f144 100644 --- a/sys/vm/vm_object.h +++ b/sys/vm/vm_object.h @@ -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); diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index a8eca20..23ade63 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -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. |