summaryrefslogtreecommitdiff
path: root/sys/kern/vfs_bio.c
diff options
context:
space:
mode:
authorMike Belopuhov <mikeb@cvs.openbsd.org>2017-07-12 11:13:23 +0000
committerMike Belopuhov <mikeb@cvs.openbsd.org>2017-07-12 11:13:23 +0000
commit674a39490c64e2e8d3716dcb7dde4c5241255fc1 (patch)
treedf7c2de8b0b6a0281ceed03d53d998a0e37c40bd /sys/kern/vfs_bio.c
parent127439ed2b58ab563084242d516ee4f726acdf53 (diff)
Invalidate read-ahead buffers when read short
Buffercache performs read-ahead for cluster reads by extending the length of an original read operation to the MAXPHYS (64k). Upon I/O completion, the length is trimmed and the buffer is returned to the filesystem and the remaining data is cached. However, under certain circumstances, the underlying hardware may fail to do a complete I/O operation and return with a non- zero value of the residual length (i.e. data that wasn't read). The residual length may exceed the size of an original request and must be re-adjusted to uphold the contract with the caller, e.g. the filesystem. At the same time, read-ahead buffers that cover chunks of memory corresponding to the residual length must be invalidated and not cached. Discussed at length during d2k17, ok tedu
Diffstat (limited to 'sys/kern/vfs_bio.c')
-rw-r--r--sys/kern/vfs_bio.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 95bc80bc0e6..88adfeff237 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_bio.c,v 1.182 2017/04/18 13:41:32 beck Exp $ */
+/* $OpenBSD: vfs_bio.c,v 1.183 2017/07/12 11:13:22 mikeb Exp $ */
/* $NetBSD: vfs_bio.c,v 1.44 1996/06/11 11:15:36 pk Exp $ */
/*
@@ -536,7 +536,23 @@ bread_cluster_callback(struct buf *bp)
bp->b_bcount = newsize;
}
- for (i = 1; xbpp[i] != 0; i++) {
+ /* Invalidate read-ahead buffers if read short */
+ if (bp->b_resid > 0) {
+ for (i = 0; xbpp[i] != NULL; i++)
+ continue;
+ for (i = i - 1; i != 0; i--) {
+ if (xbpp[i]->b_bufsize <= bp->b_resid) {
+ bp->b_resid -= xbpp[i]->b_bufsize;
+ SET(xbpp[i]->b_flags, B_INVAL);
+ } else if (bp->b_resid > 0) {
+ bp->b_resid = 0;
+ SET(xbpp[i]->b_flags, B_INVAL);
+ } else
+ break;
+ }
+ }
+
+ for (i = 1; xbpp[i] != NULL; i++) {
if (ISSET(bp->b_flags, B_ERROR))
SET(xbpp[i]->b_flags, B_INVAL | B_ERROR);
biodone(xbpp[i]);
@@ -607,7 +623,7 @@ bread_cluster(struct vnode *vp, daddr_t blkno, int size, struct buf **rbpp)
bp = xbpp[0];
- xbpp[howmany] = 0;
+ xbpp[howmany] = NULL;
inc = btodb(size);