svn commit: r349147 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs
Alan Somers
asomers at FreeBSD.org
Mon Jun 17 16:56:53 UTC 2019
Author: asomers
Date: Mon Jun 17 16:56:51 2019
New Revision: 349147
URL: https://svnweb.freebsd.org/changeset/base/349147
Log:
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
Modified:
projects/fuse2/sys/fs/fuse/fuse_internal.c
projects/fuse2/sys/fs/fuse/fuse_io.c
projects/fuse2/sys/fs/fuse/fuse_ipc.h
projects/fuse2/tests/sys/fs/fusefs/read.cc
projects/fuse2/tests/sys/fs/fusefs/utils.hh
Modified: projects/fuse2/sys/fs/fuse/fuse_internal.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_internal.c Mon Jun 17 16:54:51 2019 (r349146)
+++ projects/fuse2/sys/fs/fuse/fuse_internal.c Mon Jun 17 16:56:51 2019 (r349147)
@@ -908,6 +908,7 @@ fuse_internal_init_callback(struct fuse_ticket *tick,
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
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;
/*
Modified: projects/fuse2/sys/fs/fuse/fuse_io.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_io.c Mon Jun 17 16:54:51 2019 (r349146)
+++ projects/fuse2/sys/fs/fuse/fuse_io.c Mon Jun 17 16:56:51 2019 (r349147)
@@ -271,16 +271,22 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio
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
} 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;
Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_ipc.h Mon Jun 17 16:54:51 2019 (r349146)
+++ projects/fuse2/sys/fs/fuse/fuse_ipc.h Mon Jun 17 16:56:51 2019 (r349147)
@@ -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;
Modified: projects/fuse2/tests/sys/fs/fusefs/read.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/read.cc Mon Jun 17 16:54:51 2019 (r349146)
+++ projects/fuse2/tests/sys/fs/fusefs/read.cc Mon Jun 17 16:56:51 2019 (r349147)
@@ -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));
Modified: projects/fuse2/tests/sys/fs/fusefs/utils.hh
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/utils.hh Mon Jun 17 16:54:51 2019 (r349146)
+++ projects/fuse2/tests/sys/fs/fusefs/utils.hh Mon Jun 17 16:56:51 2019 (r349147)
@@ -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),
More information about the svn-src-projects
mailing list