Date: Mon, 17 Jun 2019 16:56:51 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r349147 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs Message-ID: <201906171656.x5HGupbU003915@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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),
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201906171656.x5HGupbU003915>