summaryrefslogtreecommitdiffstats
path: root/sys/vm/vnode_pager.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2012-02-23 21:07:16 +0000
committerkib <kib@FreeBSD.org>2012-02-23 21:07:16 +0000
commitf315a59476bc5812458ae81c8b4eb4c37f8a3aea (patch)
tree9d31f51a13c9699dab2dae074d2eac6a044b601d /sys/vm/vnode_pager.c
parentdc536a5db9b7b0b09ddaf1d12a42331848272300 (diff)
downloadFreeBSD-src-f315a59476bc5812458ae81c8b4eb4c37f8a3aea.zip
FreeBSD-src-f315a59476bc5812458ae81c8b4eb4c37f8a3aea.tar.gz
Account the writeable shared mappings backed by file in the vnode
v_writecount. Keep the amount of the virtual address space used by the mappings in the new vm_object un_pager.vnp.writemappings counter. The vnode v_writecount is incremented when writemappings gets non-zero value, and decremented when writemappings is returned to zero. Writeable shared vnode-backed mappings are accounted for in vm_mmap(), and vm_map_insert() is instructed to set MAP_ENTRY_VN_WRITECNT flag on the created map entry. During deferred map entry deallocation, vm_map_process_deferred() checks for MAP_ENTRY_VN_WRITECOUNT and decrements writemappings for the vm object. Now, the writeable mount cannot be demoted to read-only while writeable shared mappings of the vnodes from the mount point exist. Also, execve(2) fails for such files with ETXTBUSY, as it should be. Noted by: tegge Reviewed by: tegge (long time ago, early version), alc Tested by: pho MFC after: 3 weeks
Diffstat (limited to 'sys/vm/vnode_pager.c')
-rw-r--r--sys/vm/vnode_pager.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 929fa4f..609205a 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -222,6 +222,7 @@ retry:
object = vm_object_allocate(OBJT_VNODE, OFF_TO_IDX(round_page(size)));
object->un_pager.vnp.vnp_size = size;
+ object->un_pager.vnp.writemappings = 0;
object->handle = handle;
VI_LOCK(vp);
@@ -268,10 +269,16 @@ vnode_pager_dealloc(object)
wakeup(object);
}
ASSERT_VOP_ELOCKED(vp, "vnode_pager_dealloc");
+ if (object->un_pager.vnp.writemappings > 0) {
+ object->un_pager.vnp.writemappings = 0;
+ vp->v_writecount--;
+ }
vp->v_object = NULL;
vp->v_vflag &= ~VV_TEXT;
+ VM_OBJECT_UNLOCK(object);
while (refs-- > 0)
vunref(vp);
+ VM_OBJECT_LOCK(object);
}
static boolean_t
@@ -1215,3 +1222,81 @@ vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written)
}
VM_OBJECT_UNLOCK(obj);
}
+
+void
+vnode_pager_update_writecount(vm_object_t object, vm_offset_t start,
+ vm_offset_t end)
+{
+ struct vnode *vp;
+ vm_ooffset_t old_wm;
+
+ VM_OBJECT_LOCK(object);
+ if (object->type != OBJT_VNODE) {
+ VM_OBJECT_UNLOCK(object);
+ return;
+ }
+ old_wm = object->un_pager.vnp.writemappings;
+ object->un_pager.vnp.writemappings += (vm_ooffset_t)end - start;
+ vp = object->handle;
+ if (old_wm == 0 && object->un_pager.vnp.writemappings != 0) {
+ ASSERT_VOP_ELOCKED(vp, "v_writecount inc");
+ vp->v_writecount++;
+ } else if (old_wm != 0 && object->un_pager.vnp.writemappings == 0) {
+ ASSERT_VOP_ELOCKED(vp, "v_writecount dec");
+ vp->v_writecount--;
+ }
+ VM_OBJECT_UNLOCK(object);
+}
+
+void
+vnode_pager_release_writecount(vm_object_t object, vm_offset_t start,
+ vm_offset_t end)
+{
+ struct vnode *vp;
+ struct mount *mp;
+ vm_offset_t inc;
+ int vfslocked;
+
+ VM_OBJECT_LOCK(object);
+
+ /*
+ * First, recheck the object type to account for the race when
+ * the vnode is reclaimed.
+ */
+ if (object->type != OBJT_VNODE) {
+ VM_OBJECT_UNLOCK(object);
+ return;
+ }
+
+ /*
+ * Optimize for the case when writemappings is not going to
+ * zero.
+ */
+ inc = end - start;
+ if (object->un_pager.vnp.writemappings != inc) {
+ object->un_pager.vnp.writemappings -= inc;
+ VM_OBJECT_UNLOCK(object);
+ return;
+ }
+
+ vp = object->handle;
+ vhold(vp);
+ VM_OBJECT_UNLOCK(object);
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ mp = NULL;
+ vn_start_write(vp, &mp, V_WAIT);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+
+ /*
+ * Decrement the object's writemappings, by swapping the start
+ * and end arguments for vnode_pager_update_writecount(). If
+ * there was not a race with vnode reclaimation, then the
+ * vnode's v_writecount is decremented.
+ */
+ vnode_pager_update_writecount(object, end, start);
+ VOP_UNLOCK(vp, 0);
+ vdrop(vp);
+ if (mp != NULL)
+ vn_finished_write(mp);
+ VFS_UNLOCK_GIANT(vfslocked);
+}
OpenPOWER on IntegriCloud