svn commit: r204200 - user/kib/vm6/sys/vm

Konstantin Belousov kib at FreeBSD.org
Mon Feb 22 15:35:31 UTC 2010


Author: kib
Date: Mon Feb 22 15:35:31 2010
New Revision: 204200
URL: http://svn.freebsd.org/changeset/base/204200

Log:
  Detect sequential writes in vnode_pager_write() and initiate immediate
  page cleanup for continous regions written sequentially. This allows
  the buffer clustering and UFS reallocation code to defragment the file.
  
  Tested by:	pho

Modified:
  user/kib/vm6/sys/vm/vm_object.h
  user/kib/vm6/sys/vm/vm_readwrite.c
  user/kib/vm6/sys/vm/vnode_pager.c

Modified: user/kib/vm6/sys/vm/vm_object.h
==============================================================================
--- user/kib/vm6/sys/vm/vm_object.h	Mon Feb 22 15:03:16 2010	(r204199)
+++ user/kib/vm6/sys/vm/vm_object.h	Mon Feb 22 15:35:31 2010	(r204200)
@@ -109,9 +109,13 @@ struct vm_object {
 		 * VNode pager
 		 *
 		 *	vnp_size - current size of file
+		 *	wpos - start write position for seq write detector
+		 *	off - offset from wpos for current write
 		 */
 		struct {
 			off_t vnp_size;
+			off_t wpos;
+			ssize_t off;
 		} vnp;
 
 		/*

Modified: user/kib/vm6/sys/vm/vm_readwrite.c
==============================================================================
--- user/kib/vm6/sys/vm/vm_readwrite.c	Mon Feb 22 15:03:16 2010	(r204199)
+++ user/kib/vm6/sys/vm/vm_readwrite.c	Mon Feb 22 15:35:31 2010	(r204200)
@@ -715,10 +715,10 @@ vnode_pager_write(struct vnode *vp, stru
 	vm_pindex_t idx, clean_start, clean_end;
 	vm_page_t reserv;
 	struct vattr vattr;
-	ssize_t size, size1, osize, osize1, resid, sresid;
-	int error, vn_locked, wpmax, wp, i;
+	ssize_t size, size1, osize, osize1, resid, sresid, written;
+	int error, vn_locked, wpmax, wp, i, pflags;
 	u_int bits;
-	boolean_t vnode_locked;
+	boolean_t vnode_locked, freed, freed1;
 	struct thread *td;
 
 	if (ioflags & (IO_EXT|IO_INVAL|IO_DIRECT))
@@ -735,6 +735,16 @@ vnode_pager_write(struct vnode *vp, stru
 	vnode_locked = TRUE;
 	error = 0;
 
+	/*
+	 * Reversed logic from vnode_generic_putpages().
+	 */
+	if (ioflags & IO_SYNC)
+		pflags = VM_PAGER_PUT_SYNC;
+	else if (ioflags & IO_ASYNC)
+		pflags = 0;
+	else
+		pflags = VM_PAGER_CLUSTER_OK;
+
 	wpmax = atomic_load_acq_int(&vmio_write_pack);
 	vm_page_t ma[wpmax + 1];
 
@@ -1002,6 +1012,7 @@ vnode_pager_write(struct vnode *vp, stru
 		error = uiomove_fromphys(ma, off, size, uio);
 		td->td_pflags &= ~TDP_VMIO;
 
+		freed = FALSE;
 		VM_OBJECT_LOCK(obj);
 		vm_page_lock_queues();
 		for (i = 0; i < wp; i++) {
@@ -1019,12 +1030,50 @@ vnode_pager_write(struct vnode *vp, stru
 				ma[i]->flags |= PG_WRITEDIRTY;
 				vmio_writedirty++;
 			}
+			freed1 = FALSE;
+			if (VM_PAGE_GETQUEUE(ma[i]) == PQ_HOLD)
+				freed = freed1 = TRUE;
 			vm_page_unhold(ma[i]);
-			vm_page_activate(ma[i]);
+			if (!freed1)
+				vm_page_activate(ma[i]);
 		}
-		vm_page_unlock_queues();
 		/* See the comment above about page dirtiness. */
 		vm_object_set_writeable_dirty(obj);
+
+		/*
+		 * Try to cluster writes.
+		 */
+		written = sresid - uio->uio_resid;
+		if (obj->un_pager.vnp.wpos + obj->un_pager.vnp.off ==
+		    uio->uio_offset - written) {
+			/*
+			 * Sequential writes detected, make a note and
+			 * try to take immediate advantage of it.
+			 */
+			if (!freed && OFF_TO_IDX(uio->uio_offset) >
+				OFF_TO_IDX(uio->uio_offset - written) &&
+			    vn_lock(vp, vn_locked | LK_NOWAIT) == 0) {
+				vm_pageout_flush(ma, wp, pflags);
+				VOP_UNLOCK(vp, 0);
+			}
+/* printf("seq write, wpos %jd off %jd written %d\n", (intmax_t)obj->un_pager.vnp.wpos, (intmax_t)obj->un_pager.vnp.off, written); */
+			obj->un_pager.vnp.off += written;
+		} else {
+			/*
+			 * Not a sequential write situation, still
+			 * might be good to not split large write in
+			 * the daemons struggling under pressure.
+			 */
+			if (!freed && wp >= vm_pageout_page_count &&
+			    vn_lock(vp, vn_locked | LK_NOWAIT) == 0) {
+				vm_pageout_flush(ma, wp, pflags);
+				VOP_UNLOCK(vp, 0);
+			}
+/* printf("nonseq write, wpos %jd off %jd wp %d\n", (intmax_t)obj->un_pager.vnp.wpos, (intmax_t)obj->un_pager.vnp.off, wp); */
+			obj->un_pager.vnp.wpos = uio->uio_offset;
+			obj->un_pager.vnp.off = 0;
+		}
+		vm_page_unlock_queues();
 		vm_object_pip_wakeup(obj);
 		VM_OBJECT_UNLOCK(obj);
 		if (error != 0)

Modified: user/kib/vm6/sys/vm/vnode_pager.c
==============================================================================
--- user/kib/vm6/sys/vm/vnode_pager.c	Mon Feb 22 15:03:16 2010	(r204199)
+++ user/kib/vm6/sys/vm/vnode_pager.c	Mon Feb 22 15:35:31 2010	(r204200)
@@ -1017,7 +1017,6 @@ vnode_pager_putpages(object, m, count, s
 {
 	int rtval;
 	struct vnode *vp;
-	struct mount *mp;
 	int bytes = count * PAGE_SIZE;
 
 	/*
@@ -1040,8 +1039,6 @@ vnode_pager_putpages(object, m, count, s
 	 */
 	vp = object->handle;
 	VM_OBJECT_UNLOCK(object);
-	if (vp->v_type != VREG)
-		mp = NULL;
 	rtval = VOP_PUTPAGES(vp, m, bytes, sync, rtvals, 0);
 	KASSERT(rtval != EOPNOTSUPP, 
 	    ("vnode_pager: stale FS putpages\n"));


More information about the svn-src-user mailing list