[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