summaryrefslogtreecommitdiffstats
path: root/lib/libstand
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
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')
-rw-r--r--lib/libstand/close.c50
-rw-r--r--lib/libstand/lseek.c65
-rw-r--r--lib/libstand/open.c9
-rw-r--r--lib/libstand/read.c75
-rw-r--r--lib/libstand/stand.h6
5 files changed, 132 insertions, 73 deletions
diff --git a/lib/libstand/close.c b/lib/libstand/close.c
index aca6a65..bf81094 100644
--- a/lib/libstand/close.c
+++ b/lib/libstand/close.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $NetBSD: close.c,v 1.7 1997/01/22 00:38:09 cgd Exp $ */
/*-
@@ -67,30 +68,31 @@
#include "stand.h"
int
-close(fd)
- int fd;
+close(int fd)
{
- register struct open_file *f = &files[fd];
- int err1 = 0, err2 = 0;
+ struct open_file *f = &files[fd];
+ int err1 = 0, err2 = 0;
- if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
- errno = EBADF;
- return (-1);
- }
- if (!(f->f_flags & F_RAW) && f->f_ops)
- err1 = (f->f_ops->fo_close)(f);
- if (!(f->f_flags & F_NODEV) && f->f_dev)
- err2 = (f->f_dev->dv_close)(f);
- if (f->f_devdata != NULL)
- devclose(f);
- f->f_flags = 0;
- if (err1) {
- errno = err1;
- return (-1);
- }
- if (err2) {
- errno = err2;
- return (-1);
- }
- return (0);
+ if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (f->f_rabuf != NULL)
+ free(f->f_rabuf);
+ if (!(f->f_flags & F_RAW) && f->f_ops)
+ err1 = (f->f_ops->fo_close)(f);
+ if (!(f->f_flags & F_NODEV) && f->f_dev)
+ err2 = (f->f_dev->dv_close)(f);
+ if (f->f_devdata != NULL)
+ devclose(f);
+ f->f_flags = 0;
+ if (err1) {
+ errno = err1;
+ return (-1);
+ }
+ if (err2) {
+ errno = err2;
+ return (-1);
+ }
+ return (0);
}
diff --git a/lib/libstand/lseek.c b/lib/libstand/lseek.c
index 0894912..91f8612 100644
--- a/lib/libstand/lseek.c
+++ b/lib/libstand/lseek.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $NetBSD: lseek.c,v 1.4 1997/01/22 00:38:10 cgd Exp $ */
/*-
@@ -67,36 +68,46 @@
#include "stand.h"
off_t
-lseek(fd, offset, where)
- int fd;
- off_t offset;
- int where;
+lseek(int fd, off_t offset, int where)
{
- register struct open_file *f = &files[fd];
+ struct open_file *f = &files[fd];
- if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
- errno = EBADF;
- return (-1);
- }
+ if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ return (-1);
+ }
- if (f->f_flags & F_RAW) {
- /*
- * On RAW devices, update internal offset.
- */
- switch (where) {
- case SEEK_SET:
- f->f_offset = offset;
- break;
- case SEEK_CUR:
- f->f_offset += offset;
- break;
- case SEEK_END:
- default:
- errno = EOFFSET;
- return (-1);
- }
- return (f->f_offset);
+ if (f->f_flags & F_RAW) {
+ /*
+ * On RAW devices, update internal offset.
+ */
+ switch (where) {
+ case SEEK_SET:
+ f->f_offset = offset;
+ break;
+ case SEEK_CUR:
+ f->f_offset += offset;
+ break;
+ case SEEK_END:
+ default:
+ errno = EOFFSET;
+ return (-1);
}
+ return (f->f_offset);
+ }
+
+ /*
+ * If this is a relative seek, we need to correct the offset for
+ * bytes that we have already read but the caller doesn't know
+ * about.
+ */
+ if (where == SEEK_CUR)
+ offset -= f->f_ralen;
+
+ /*
+ * Invalidate the readahead buffer.
+ */
+ f->f_ralen = 0;
- return (f->f_ops->fo_seek)(f, offset, where);
+ return (f->f_ops->fo_seek)(f, offset, where);
}
diff --git a/lib/libstand/open.c b/lib/libstand/open.c
index 3a9127c..471f937 100644
--- a/lib/libstand/open.c
+++ b/lib/libstand/open.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $NetBSD: open.c,v 1.16 1997/01/28 09:41:03 pk Exp $ */
/*-
@@ -79,6 +80,13 @@ o_gethandle(void)
return(-1);
}
+static void
+o_rainit(struct open_file *f)
+{
+ f->f_rabuf = malloc(SOPEN_RASIZE);
+ f->f_ralen = 0;
+ f->f_raoffset = 0;
+}
int
open(const char *fname, int mode)
@@ -118,6 +126,7 @@ open(const char *fname, int mode)
if (error == 0) {
f->f_ops = file_system[i];
+ o_rainit(f);
return (fd);
}
if (error != EINVAL)
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);
+ }
}
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
index aa8e65f..e48565a 100644
--- a/lib/libstand/stand.h
+++ b/lib/libstand/stand.h
@@ -159,7 +159,11 @@ struct open_file {
void *f_devdata; /* device specific data */
struct fs_ops *f_ops; /* pointer to file system operations */
void *f_fsdata; /* file system specific data */
- off_t f_offset; /* current file offset (F_RAW) */
+ off_t f_offset; /* current file offset */
+ char *f_rabuf; /* readahead buffer pointer */
+ size_t f_ralen; /* valid data in readahead buffer */
+ off_t f_raoffset; /* consumer offset in readahead buffer */
+#define SOPEN_RASIZE 512
};
#define SOPEN_MAX 8
OpenPOWER on IntegriCloud