Correct an error of omission in the reimplementation of the page

cache: vm_object_page_remove() should convert any cached pages that
fall with the specified range to free pages.  Otherwise, there could
be a problem if a file is first truncated and then regrown.
Specifically, some old data from prior to the truncation might reappear.

Generalize vm_page_cache_free() to support the conversion of either a
subset or the entirety of an object's cached pages.

Reported by: tegge
Reviewed by: tegge
Approved by: re (kensmith)
This commit is contained in:
Alan Cox 2007-09-27 04:21:59 +00:00
parent fed3ad6334
commit c944491426
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=172341
3 changed files with 48 additions and 18 deletions

View File

@ -653,7 +653,7 @@ vm_object_terminate(vm_object_t object)
vm_page_unlock_queues();
if (__predict_false(object->cache != NULL))
vm_page_cache_free(object);
vm_page_cache_free(object, 0, 0);
/*
* Let the pager know object is dead.
@ -1680,7 +1680,7 @@ vm_object_collapse(vm_object_t object)
* Free any cached pages from backing_object.
*/
if (__predict_false(backing_object->cache != NULL))
vm_page_cache_free(backing_object);
vm_page_cache_free(backing_object, 0, 0);
}
/*
* Object now shadows whatever backing_object did.
@ -1849,6 +1849,8 @@ vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end,
}
vm_page_unlock_queues();
vm_object_pip_wakeup(object);
if (__predict_false(object->cache != NULL))
vm_page_cache_free(object, start, end);
}
/*

View File

@ -794,28 +794,55 @@ vm_page_rename(vm_page_t m, vm_object_t new_object, vm_pindex_t new_pindex)
}
/*
* Convert all of the cached pages belonging to the given object
* into free pages. If the given object has cached pages and is
* backed by a vnode, reduce the vnode's hold count.
* Convert all of the given object's cached pages that have a
* pindex within the given range into free pages. If the value
* zero is given for "end", then the range's upper bound is
* infinity. If the given object is backed by a vnode and it
* transitions from having one or more cached pages to none, the
* vnode's hold count is reduced.
*/
void
vm_page_cache_free(vm_object_t object)
vm_page_cache_free(vm_object_t object, vm_pindex_t start, vm_pindex_t end)
{
vm_page_t m, root;
vm_page_t m, m_next;
boolean_t empty;
mtx_lock(&vm_page_queue_free_mtx);
empty = object->cache == NULL;
while ((m = object->cache) != NULL) {
if (m->left == NULL)
root = m->right;
else if (m->right == NULL)
root = m->left;
if (__predict_false(object->cache == NULL)) {
mtx_unlock(&vm_page_queue_free_mtx);
return;
}
m = object->cache = vm_page_splay(start, object->cache);
if (m->pindex < start) {
if (m->right == NULL)
m = NULL;
else {
root = vm_page_splay(m->pindex, m->left);
root->right = m->right;
m_next = vm_page_splay(start, m->right);
m_next->left = m;
m->right = NULL;
m = object->cache = m_next;
}
m->object->cache = root;
}
/*
* At this point, "m" is either (1) a reference to the page
* with the least pindex that is greater than or equal to
* "start" or (2) NULL.
*/
for (; m != NULL && (m->pindex < end || end == 0); m = m_next) {
/*
* Find "m"'s successor and remove "m" from the
* object's cache.
*/
if (m->right == NULL) {
object->cache = m->left;
m_next = NULL;
} else {
m_next = vm_page_splay(start, m->right);
m_next->left = m->left;
object->cache = m_next;
}
/* Convert "m" to a free page. */
m->object = NULL;
m->valid = 0;
/* Clear PG_CACHED and set PG_FREE. */
@ -825,8 +852,9 @@ vm_page_cache_free(vm_object_t object)
cnt.v_cache_count--;
cnt.v_free_count++;
}
empty = object->cache == NULL;
mtx_unlock(&vm_page_queue_free_mtx);
if (object->type == OBJT_VNODE && !empty)
if (object->type == OBJT_VNODE && empty)
vdrop(object->handle);
}

View File

@ -320,7 +320,7 @@ void vm_page_activate (vm_page_t);
vm_page_t vm_page_alloc (vm_object_t, vm_pindex_t, int);
vm_page_t vm_page_grab (vm_object_t, vm_pindex_t, int);
void vm_page_cache (register vm_page_t);
void vm_page_cache_free(vm_object_t);
void vm_page_cache_free(vm_object_t, vm_pindex_t, vm_pindex_t);
void vm_page_cache_remove(vm_page_t);
void vm_page_cache_transfer(vm_object_t, vm_pindex_t, vm_object_t);
int vm_page_try_to_cache (vm_page_t);