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:
parent
bade5944c9
commit
ba20acfdb2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=65470
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user