From owner-svn-src-projects@freebsd.org Mon Jun 17 16:56:53 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8EAD015BF4E3 for ; Mon, 17 Jun 2019 16:56:53 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 331F771F6C; Mon, 17 Jun 2019 16:56:53 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 0EF6E829; Mon, 17 Jun 2019 16:56:53 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x5HGuqXf003920; Mon, 17 Jun 2019 16:56:52 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x5HGupbU003915; Mon, 17 Jun 2019 16:56:51 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201906171656.x5HGupbU003915@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Mon, 17 Jun 2019 16:56:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r349147 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 349147 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 331F771F6C X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.98 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.98)[-0.982,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 Jun 2019 16:56:53 -0000 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 { 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),