summaryrefslogtreecommitdiffstats
path: root/lib/libstand/read.c
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>2000-09-05 09:52:50 +0000
committermsmith <msmith@FreeBSD.org>2000-09-05 09:52:50 +0000
commit6ff92c14b7a65f64dea4e0d4e8d19b2dcf3f57b3 (patch)
treeded2222e22c2d532e900757ec03c1d5306a3e570 /lib/libstand/read.c
parent75c63c707d89253e9bd44217d8975ec16bec5aa5 (diff)
downloadFreeBSD-src-6ff92c14b7a65f64dea4e0d4e8d19b2dcf3f57b3.zip
FreeBSD-src-6ff92c14b7a65f64dea4e0d4e8d19b2dcf3f57b3.tar.gz
Implement readahead buffering for non-raw files. This drastically improves
the efficiency of byte-by-byte read operations on filesystems not already supported by the block cache (especially NFS). This should be a welcome change for users booting via PXE, as the loader now reads its startup files almost instantly, instead of taking tens of seconds.
Diffstat (limited to 'lib/libstand/read.c')
-rw-r--r--lib/libstand/read.c75
1 files changed, 54 insertions, 21 deletions
diff --git a/lib/libstand/read.c b/lib/libstand/read.c
index 5b14a75..28ff47e 100644
--- a/lib/libstand/read.c
+++ b/lib/libstand/read.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $NetBSD: read.c,v 1.8 1997/01/22 00:38:12 cgd Exp $ */
/*-
@@ -68,29 +69,61 @@
#include "stand.h"
ssize_t
-read(fd, dest, bcount)
- int fd;
- void *dest;
- size_t bcount;
+read(int fd, void *dest, size_t bcount)
{
- register struct open_file *f = &files[fd];
- size_t resid;
+ struct open_file *f = &files[fd];
+ size_t resid;
- if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) {
- errno = EBADF;
- return (-1);
+ if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (f->f_flags & F_RAW) {
+ twiddle();
+ errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ btodb(f->f_offset), bcount, dest, &resid);
+ if (errno)
+ return (-1);
+ f->f_offset += resid;
+ return (resid);
+ }
+
+ /*
+ * Optimise reads from regular files using a readahead buffer.
+ * If the request can't be satisfied from the current buffer contents,
+ * check to see if it should be bypassed, or refill the buffer and complete
+ * the request.
+ */
+ resid = bcount;
+ for (;;) {
+ size_t ccount, cresid;
+ /* how much can we supply? */
+ ccount = imin(f->f_ralen, resid);
+ if (ccount > 0) {
+ bcopy(f->f_rabuf + f->f_raoffset, dest, ccount);
+ f->f_raoffset += ccount;
+ f->f_ralen -= ccount;
+ resid -= ccount;
+ if (resid == 0)
+ return(bcount);
+ dest += ccount;
}
- if (f->f_flags & F_RAW) {
- twiddle();
- errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- btodb(f->f_offset), bcount, dest, &resid);
- if (errno)
- return (-1);
- f->f_offset += resid;
- return (resid);
+
+ /* will filling the readahead buffer again not help? */
+ if (resid >= SOPEN_RASIZE) {
+ /* bypass the rest of the request and leave the buffer empty */
+ if ((errno = (f->f_ops->fo_read)(f, dest, resid, &cresid)))
+ return(bcount - resid);
+ return(bcount - cresid);
}
- resid = bcount;
- if ((errno = (f->f_ops->fo_read)(f, dest, bcount, &resid)))
- return (-1);
- return (ssize_t)(bcount - resid);
+
+ /* fetch more data */
+ if ((errno = (f->f_ops->fo_read)(f, f->f_rabuf, SOPEN_RASIZE, &cresid)))
+ return(bcount - resid); /* behave like fread() */
+ f->f_raoffset = 0;
+ f->f_ralen = SOPEN_RASIZE - cresid;
+ /* no more data, return what we had */
+ if (f->f_ralen == 0)
+ return(bcount - resid);
+ }
}
OpenPOWER on IntegriCloud