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.
This commit is contained in:
Mike Smith 2000-09-05 09:52:50 +00:00
parent bade5944c9
commit ba20acfdb2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=65470
5 changed files with 132 additions and 73 deletions

View File

@ -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);
}

View File

@ -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;
return (f->f_ops->fo_seek)(f, offset, where);
/*
* Invalidate the readahead buffer.
*/
f->f_ralen = 0;
return (f->f_ops->fo_seek)(f, offset, where);
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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