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:
parent
a4724ef3b4
commit
9d3ffe57ce
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user