fusefs: implement non-clustered readahead
fusefs will now read ahead at most one cache block at a time (usually 64 KB). Clustered reads are still TODO. Individual file systems may disable read ahead by setting fuse_init_out.max_readahead=0 during initialization. Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
eadd12d35d
commit
d569012f45
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=349147
@ -908,6 +908,7 @@ fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
|
||||
|
||||
if (fuse_libabi_geq(data, 7, 5)) {
|
||||
if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) {
|
||||
data->max_readahead = fiio->max_readahead;
|
||||
data->max_write = fiio->max_write;
|
||||
if (fiio->flags & FUSE_ASYNC_READ)
|
||||
data->dataflags |= FSESS_ASYNC_READ;
|
||||
@ -951,9 +952,8 @@ fuse_internal_send_init(struct fuse_data *data, struct thread *td)
|
||||
fiii->major = FUSE_KERNEL_VERSION;
|
||||
fiii->minor = FUSE_KERNEL_MINOR_VERSION;
|
||||
/*
|
||||
* fusefs currently doesn't do any readahead other than fetching whole
|
||||
* buffer cache block sized regions at once. So the max readahead is
|
||||
* the size of a buffer cache block.
|
||||
* fusefs currently reads ahead no more than one cache block at a time.
|
||||
* See fuse_read_biobackend
|
||||
*/
|
||||
fiii->max_readahead = maxbcachebuf;
|
||||
/*
|
||||
|
@ -271,16 +271,22 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid)
|
||||
{
|
||||
struct buf *bp;
|
||||
daddr_t lbn;
|
||||
int bcount;
|
||||
int err, n = 0, on = 0;
|
||||
struct mount *mp;
|
||||
struct fuse_data *data;
|
||||
daddr_t lbn, nextlbn;
|
||||
int bcount, nextsize;
|
||||
int err, n = 0, on = 0, seqcount;
|
||||
off_t filesize;
|
||||
|
||||
const int biosize = fuse_iosize(vp);
|
||||
mp = vnode_mount(vp);
|
||||
data = fuse_get_mpdata(mp);
|
||||
|
||||
if (uio->uio_offset < 0)
|
||||
return (EINVAL);
|
||||
|
||||
seqcount = ioflag >> IO_SEQSHIFT;
|
||||
|
||||
err = fuse_vnode_size(vp, &filesize, cred, curthread);
|
||||
if (err)
|
||||
return err;
|
||||
@ -302,12 +308,25 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
} else {
|
||||
bcount = biosize;
|
||||
}
|
||||
nextlbn = lbn + 1;
|
||||
nextsize = MIN(biosize, filesize - nextlbn * biosize);
|
||||
|
||||
SDT_PROBE4(fusefs, , io, read_bio_backend_start,
|
||||
biosize, (int)lbn, on, bcount);
|
||||
|
||||
/* TODO: readahead. See ext2_read for an example */
|
||||
err = bread(vp, lbn, bcount, NOCRED, &bp);
|
||||
if (bcount < biosize) {
|
||||
/* If near EOF, don't do readahead */
|
||||
err = bread(vp, lbn, bcount, NOCRED, &bp);
|
||||
/* TODO: clustered read */
|
||||
} else if (seqcount > 1 && data->max_readahead >= nextsize) {
|
||||
/* Try non-clustered readahead */
|
||||
err = breadn(vp, lbn, bcount, &nextlbn, &nextsize, 1,
|
||||
NOCRED, &bp);
|
||||
} else {
|
||||
/* Just read what was requested */
|
||||
err = bread(vp, lbn, bcount, NOCRED, &bp);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
|
@ -197,6 +197,7 @@ struct fuse_data {
|
||||
uint32_t fuse_libabi_major;
|
||||
uint32_t fuse_libabi_minor;
|
||||
|
||||
uint32_t max_readahead;
|
||||
uint32_t max_write;
|
||||
uint32_t max_read;
|
||||
uint32_t subtype;
|
||||
|
@ -112,7 +112,7 @@ virtual void SetUp() {
|
||||
class ReadAhead: public ReadCacheable, public WithParamInterface<uint32_t> {
|
||||
virtual void SetUp() {
|
||||
m_maxreadahead = GetParam();
|
||||
Read::SetUp();
|
||||
ReadCacheable::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
@ -747,37 +747,40 @@ TEST_F(ReadCacheable, DISABLED_sendfile_eio)
|
||||
}
|
||||
|
||||
/* fuse(4) should honor the filesystem's requested m_readahead parameter */
|
||||
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236472 */
|
||||
TEST_P(ReadAhead, DISABLED_readahead) {
|
||||
TEST_P(ReadAhead, readahead) {
|
||||
const char FULLPATH[] = "mountpoint/some_file.txt";
|
||||
const char RELPATH[] = "some_file.txt";
|
||||
const char *CONTENTS0 = "abcdefghijklmnop";
|
||||
uint64_t ino = 42;
|
||||
int fd;
|
||||
ssize_t bufsize = 8;
|
||||
ssize_t filesize = m_maxbcachebuf * 2;
|
||||
char *contents;
|
||||
char buf[bufsize];
|
||||
int fd, i;
|
||||
ssize_t bufsize = m_maxbcachebuf;
|
||||
ssize_t filesize = m_maxbcachebuf * 4;
|
||||
char *rbuf, *contents;
|
||||
|
||||
ASSERT_TRUE(GetParam() < (uint32_t)m_maxbcachebuf)
|
||||
<< "Test assumes that max_readahead < maxbcachebuf";
|
||||
|
||||
contents = (char*)calloc(1, filesize);
|
||||
contents = (char*)malloc(filesize);
|
||||
ASSERT_NE(NULL, contents);
|
||||
memmove(contents, CONTENTS0, strlen(CONTENTS0));
|
||||
memset(contents, 'X', filesize);
|
||||
rbuf = (char*)calloc(1, bufsize);
|
||||
|
||||
expect_lookup(RELPATH, ino, filesize);
|
||||
expect_open(ino, 0, 1);
|
||||
/* fuse(4) should only read ahead the allowed amount */
|
||||
expect_read(ino, 0, GetParam(), GetParam(), contents);
|
||||
expect_read(ino, 0, m_maxbcachebuf, m_maxbcachebuf, contents);
|
||||
for (i = 0; i < (int)GetParam() / m_maxbcachebuf; i++) {
|
||||
off_t offs = (i + 1) * m_maxbcachebuf;
|
||||
expect_read(ino, offs, m_maxbcachebuf, m_maxbcachebuf,
|
||||
contents + offs);
|
||||
}
|
||||
|
||||
fd = open(FULLPATH, O_RDONLY);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
|
||||
ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
|
||||
ASSERT_EQ(0, memcmp(buf, CONTENTS0, bufsize));
|
||||
/* Set the internal readahead counter to a "large" value */
|
||||
ASSERT_EQ(0, fcntl(fd, F_READAHEAD, 1'000'000'000)) << strerror(errno);
|
||||
|
||||
ASSERT_EQ(bufsize, read(fd, rbuf, bufsize)) << strerror(errno);
|
||||
ASSERT_EQ(0, memcmp(rbuf, contents, bufsize));
|
||||
|
||||
/* Deliberately leak fd. close(2) will be tested in release.cc */
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(RA, ReadAhead, ::testing::Values(0u, 2048u));
|
||||
INSTANTIATE_TEST_CASE_P(RA, ReadAhead, ::testing::Values(0u, 65536));
|
||||
|
@ -61,11 +61,7 @@ class FuseTest : public ::testing::Test {
|
||||
int m_maxbcachebuf;
|
||||
|
||||
FuseTest():
|
||||
/*
|
||||
* libfuse's default max_readahead is UINT_MAX, though it can
|
||||
* be lowered
|
||||
*/
|
||||
m_maxreadahead(UINT_MAX),
|
||||
m_maxreadahead(0),
|
||||
m_maxwrite(default_max_write),
|
||||
m_init_flags(0),
|
||||
m_allow_other(false),
|
||||
|
Loading…
Reference in New Issue
Block a user