[Midnightbsd-cvs] src [7917] trunk: Refine the implementation of POSIX_FADV_NOREUSE to perform

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed Sep 14 15:48:34 EDT 2016


Revision: 7917
          http://svnweb.midnightbsd.org/src/?rev=7917
Author:   laffer1
Date:     2016-09-14 15:48:34 -0400 (Wed, 14 Sep 2016)
Log Message:
-----------
Refine the implementation of POSIX_FADV_NOREUSE to perform
POSIX_FADV_DONTNEED requests on the currently accessed portion of the
file on each read(2) or write(2) rather than using direct I/O.  This
gives much better performance including read-ahead and write clustering
similar to normal read(2) and write(2) calls.

If subsequent read(2) and write(2) calls are sequential, then the
POSIX_FADV_DONTNEED requests will cover the entire sequentially-accessed
range.

Obtained from: FreeBSD

Modified Paths:
--------------
    trunk/lib/libc/sys/posix_fadvise.2
    trunk/sys/kern/vfs_syscalls.c
    trunk/sys/kern/vfs_vnops.c
    trunk/sys/sys/file.h

Modified: trunk/lib/libc/sys/posix_fadvise.2
===================================================================
--- trunk/lib/libc/sys/posix_fadvise.2	2016-09-14 19:47:16 UTC (rev 7916)
+++ trunk/lib/libc/sys/posix_fadvise.2	2016-09-14 19:48:34 UTC (rev 7917)
@@ -28,7 +28,7 @@
 .\"	@(#)madvise.2	8.1 (Berkeley) 6/9/93
 .\" $MidnightBSD$
 .\"
-.Dd February 25, 2012
+.Dd June 19, 2012
 .Dt POSIX_FADVISE 2
 .Os
 .Sh NAME
@@ -84,10 +84,9 @@
 .It Dv POSIX_FADV_NOREUSE
 Tells the system that the specified data will only be accessed once and
 then not reused.
-Accesses to data within the specified range are treated as if the file
-descriptor has the
-.Dv O_DIRECT
-flag enabled.
+The system may decrease the in-memory priority of data once it has been
+read or written.
+Future access to this data may require a read operation.
 .El
 .Pp
 .Sh RETURN VALUES

Modified: trunk/sys/kern/vfs_syscalls.c
===================================================================
--- trunk/sys/kern/vfs_syscalls.c	2016-09-14 19:47:16 UTC (rev 7916)
+++ trunk/sys/kern/vfs_syscalls.c	2016-09-14 19:48:34 UTC (rev 7917)
@@ -4954,6 +4954,8 @@
 			new->fa_advice = advice;
 			new->fa_start = offset;
 			new->fa_end = end;
+			new->fa_prevstart = 0;
+			new->fa_prevend = 0;
 			fp->f_advice = new;
 			new = fa;
 		}

Modified: trunk/sys/kern/vfs_vnops.c
===================================================================
--- trunk/sys/kern/vfs_vnops.c	2016-09-14 19:47:16 UTC (rev 7916)
+++ trunk/sys/kern/vfs_vnops.c	2016-09-14 19:48:34 UTC (rev 7917)
@@ -519,6 +519,7 @@
 	int error, ioflag;
 	struct mtx *mtxp;
 	int advice, vfslocked;
+	off_t offset, start, end;
 
 	KASSERT(uio->uio_td == td, ("uio_td %p is not td %p",
 	    uio->uio_td, td));
@@ -558,19 +559,14 @@
 	switch (advice) {
 	case POSIX_FADV_NORMAL:
 	case POSIX_FADV_SEQUENTIAL:
+	case POSIX_FADV_NOREUSE:
 		ioflag |= sequential_heuristic(uio, fp);
 		break;
 	case POSIX_FADV_RANDOM:
 		/* Disable read-ahead for random I/O. */
 		break;
-	case POSIX_FADV_NOREUSE:
-		/*
-		 * Request the underlying FS to discard the buffers
-		 * and pages after the I/O is complete.
-		 */
-		ioflag |= IO_DIRECT;
-		break;
 	}
+	offset = uio->uio_offset;
 
 #ifdef MAC
 	error = mac_vnode_check_read(active_cred, fp->f_cred, vp);
@@ -587,6 +583,39 @@
 	}
 	fp->f_nextoff = uio->uio_offset;
 	VOP_UNLOCK(vp, 0);
+	if (error == 0 && advice == POSIX_FADV_NOREUSE &&
+	    offset != uio->uio_offset) {
+		/*
+		 * Use POSIX_FADV_DONTNEED to flush clean pages and
+		 * buffers for the backing file after a
+		 * POSIX_FADV_NOREUSE read(2).  To optimize the common
+		 * case of using POSIX_FADV_NOREUSE with sequential
+		 * access, track the previous implicit DONTNEED
+		 * request and grow this request to include the
+		 * current read(2) in addition to the previous
+		 * DONTNEED.  With purely sequential access this will
+		 * cause the DONTNEED requests to continously grow to
+		 * cover all of the previously read regions of the
+		 * file.  This allows filesystem blocks that are
+		 * accessed by multiple calls to read(2) to be flushed
+		 * once the last read(2) finishes.
+		 */
+		start = offset;
+		end = uio->uio_offset - 1;
+		mtx_lock(mtxp);
+		if (fp->f_advice != NULL &&
+		    fp->f_advice->fa_advice == POSIX_FADV_NOREUSE) {
+			if (start != 0 && fp->f_advice->fa_prevend + 1 == start)
+				start = fp->f_advice->fa_prevstart;
+			else if (fp->f_advice->fa_prevstart != 0 &&
+			    fp->f_advice->fa_prevstart == end + 1)
+				end = fp->f_advice->fa_prevend;
+			fp->f_advice->fa_prevstart = start;
+			fp->f_advice->fa_prevend = end;
+		}
+		mtx_unlock(mtxp);
+		error = VOP_ADVISE(vp, start, end, POSIX_FADV_DONTNEED);
+	}
 	VFS_UNLOCK_GIANT(vfslocked);
 	return (error);
 }
@@ -607,6 +636,7 @@
 	int error, ioflag, lock_flags;
 	struct mtx *mtxp;
 	int advice, vfslocked;
+	off_t offset, start, end;
 
 	KASSERT(uio->uio_td == td, ("uio_td %p is not td %p",
 	    uio->uio_td, td));
@@ -641,6 +671,7 @@
 	if ((flags & FOF_OFFSET) == 0)
 		uio->uio_offset = fp->f_offset;
 	advice = POSIX_FADV_NORMAL;
+	mtxp = NULL;
 	if (fp->f_advice != NULL) {
 		mtxp = mtx_pool_find(mtxpool_sleep, fp);
 		mtx_lock(mtxp);
@@ -653,19 +684,14 @@
 	switch (advice) {
 	case POSIX_FADV_NORMAL:
 	case POSIX_FADV_SEQUENTIAL:
+	case POSIX_FADV_NOREUSE:
 		ioflag |= sequential_heuristic(uio, fp);
 		break;
 	case POSIX_FADV_RANDOM:
 		/* XXX: Is this correct? */
 		break;
-	case POSIX_FADV_NOREUSE:
-		/*
-		 * Request the underlying FS to discard the buffers
-		 * and pages after the I/O is complete.
-		 */
-		ioflag |= IO_DIRECT;
-		break;
 	}
+	offset = uio->uio_offset;
 
 #ifdef MAC
 	error = mac_vnode_check_write(active_cred, fp->f_cred, vp);
@@ -678,6 +704,55 @@
 	VOP_UNLOCK(vp, 0);
 	if (vp->v_type != VCHR)
 		vn_finished_write(mp);
+	if (error == 0 && advice == POSIX_FADV_NOREUSE &&
+	    offset != uio->uio_offset) {
+		/*
+		 * Use POSIX_FADV_DONTNEED to flush clean pages and
+		 * buffers for the backing file after a
+		 * POSIX_FADV_NOREUSE write(2).  To optimize the
+		 * common case of using POSIX_FADV_NOREUSE with
+		 * sequential access, track the previous implicit
+		 * DONTNEED request and grow this request to include
+		 * the current write(2) in addition to the previous
+		 * DONTNEED.  With purely sequential access this will
+		 * cause the DONTNEED requests to continously grow to
+		 * cover all of the previously written regions of the
+		 * file.
+		 *
+		 * Note that the blocks just written are almost
+		 * certainly still dirty, so this only works when
+		 * VOP_ADVISE() calls from subsequent writes push out
+		 * the data written by this write(2) once the backing
+		 * buffers are clean.  However, as compared to forcing
+		 * IO_DIRECT, this gives much saner behavior.  Write
+		 * clustering is still allowed, and clean pages are
+		 * merely moved to the cache page queue rather than
+		 * outright thrown away.  This means a subsequent
+		 * read(2) can still avoid hitting the disk if the
+		 * pages have not been reclaimed.
+		 *
+		 * This does make POSIX_FADV_NOREUSE largely useless
+		 * with non-sequential access.  However, sequential
+		 * access is the more common use case and the flag is
+		 * merely advisory.
+		 */
+		start = offset;
+		end = uio->uio_offset - 1;
+		mtx_lock(mtxp);
+		if (fp->f_advice != NULL &&
+		    fp->f_advice->fa_advice == POSIX_FADV_NOREUSE) {
+			if (start != 0 && fp->f_advice->fa_prevend + 1 == start)
+				start = fp->f_advice->fa_prevstart;
+			else if (fp->f_advice->fa_prevstart != 0 &&
+			    fp->f_advice->fa_prevstart == end + 1)
+				end = fp->f_advice->fa_prevend;
+			fp->f_advice->fa_prevstart = start;
+			fp->f_advice->fa_prevend = end;
+		}
+		mtx_unlock(mtxp);
+		error = VOP_ADVISE(vp, start, end, POSIX_FADV_DONTNEED);
+	}
+	
 unlock:
 	VFS_UNLOCK_GIANT(vfslocked);
 	return (error);

Modified: trunk/sys/sys/file.h
===================================================================
--- trunk/sys/sys/file.h	2016-09-14 19:47:16 UTC (rev 7916)
+++ trunk/sys/sys/file.h	2016-09-14 19:48:34 UTC (rev 7917)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)file.h	8.3 (Berkeley) 1/9/95
- * $MidnightBSD: src/sys/sys/file.h,v 1.5 2012/10/09 04:05:36 laffer1 Exp $
+ * $MidnightBSD$
  */
 
 #ifndef _SYS_FILE_H_
@@ -126,6 +126,8 @@
 	int		fa_advice;	/* (f) FADV_* type. */
 	off_t		fa_start;	/* (f) Region start. */
 	off_t		fa_end;		/* (f) Region end. */
+	off_t		fa_prevstart;	/* (f) Previous NOREUSE start. */
+	off_t		fa_prevend;	/* (f) Previous NOREUSE end. */
 };
 
 struct file {



More information about the Midnightbsd-cvs mailing list