summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_object.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_object.c')
-rw-r--r--sys/vm/vm_object.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 1c47fa7..21e7d7b 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -1775,6 +1775,83 @@ vm_object_set_writeable_dirty(vm_object_t object)
}
}
+/*
+ * Performs the copy_on_write operations necessary to allow the virtual copies
+ * into user space to work. This has to be called for write(2) system calls
+ * from other processes, file unlinking, and file size shrinkage.
+ */
+void
+vm_freeze_copyopts(vm_object_t object, vm_pindex_t froma, vm_pindex_t toa)
+{
+ int rv;
+ vm_object_t robject;
+ vm_pindex_t idx;
+
+ GIANT_REQUIRED;
+ if ((object == NULL) ||
+ ((object->flags & OBJ_OPT) == 0))
+ return;
+
+ if (object->shadow_count > object->ref_count)
+ panic("vm_freeze_copyopts: sc > rc");
+
+ while ((robject = TAILQ_FIRST(&object->shadow_head)) != NULL) {
+ vm_pindex_t bo_pindex;
+ vm_page_t m_in, m_out;
+
+ bo_pindex = OFF_TO_IDX(robject->backing_object_offset);
+
+ vm_object_reference(robject);
+
+ vm_object_pip_wait(robject, "objfrz");
+
+ if (robject->ref_count == 1) {
+ vm_object_deallocate(robject);
+ continue;
+ }
+
+ vm_object_pip_add(robject, 1);
+
+ for (idx = 0; idx < robject->size; idx++) {
+
+ m_out = vm_page_grab(robject, idx,
+ VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
+
+ if (m_out->valid == 0) {
+ m_in = vm_page_grab(object, bo_pindex + idx,
+ VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
+ if (m_in->valid == 0) {
+ rv = vm_pager_get_pages(object, &m_in, 1, 0);
+ if (rv != VM_PAGER_OK) {
+ printf("vm_freeze_copyopts: cannot read page from file: %lx\n", (long)m_in->pindex);
+ continue;
+ }
+ vm_page_deactivate(m_in);
+ }
+
+ vm_page_protect(m_in, VM_PROT_NONE);
+ pmap_copy_page(m_in, m_out);
+ m_out->valid = m_in->valid;
+ vm_page_dirty(m_out);
+ vm_page_activate(m_out);
+ vm_page_wakeup(m_in);
+ }
+ vm_page_wakeup(m_out);
+ }
+
+ object->shadow_count--;
+ object->ref_count--;
+ TAILQ_REMOVE(&object->shadow_head, robject, shadow_list);
+ robject->backing_object = NULL;
+ robject->backing_object_offset = 0;
+
+ vm_object_pip_wakeup(robject);
+ vm_object_deallocate(robject);
+ }
+
+ vm_object_clear_flag(object, OBJ_OPT);
+}
+
#include "opt_ddb.h"
#ifdef DDB
#include <sys/kernel.h>
OpenPOWER on IntegriCloud