Date: Fri, 15 Mar 2019 20:16:36 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r345201 - projects/fuse2/tests/sys/fs/fuse Message-ID: <201903152016.x2FKGaqb048685@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Fri Mar 15 20:16:35 2019 New Revision: 345201 URL: https://svnweb.freebsd.org/changeset/base/345201 Log: fuse(4): add tests for the FUSE_ASYNC_READ option Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/tests/sys/fs/fuse/read.cc Modified: projects/fuse2/tests/sys/fs/fuse/read.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/read.cc Fri Mar 15 18:59:04 2019 (r345200) +++ projects/fuse2/tests/sys/fs/fuse/read.cc Fri Mar 15 20:16:35 2019 (r345201) @@ -55,6 +55,7 @@ void expect_lookup(const char *relpath, uint64_t ino) }; class AioRead: public Read { +public: virtual void SetUp() { const char *node = "vfs.aio.enable_unsafe"; int val = 0; @@ -69,6 +70,13 @@ virtual void SetUp() { } }; +class AsyncRead: public AioRead { + virtual void SetUp() { + m_init_flags = FUSE_ASYNC_READ; + AioRead::SetUp(); + } +}; + class ReadAhead: public Read, public WithParamInterface<uint32_t> { virtual void SetUp() { m_maxreadahead = GetParam(); @@ -105,6 +113,159 @@ TEST_F(AioRead, aio_read) ASSERT_EQ(0, aio_read(&iocb)) << strerror(errno); ASSERT_EQ(bufsize, aio_waitcomplete(&piocb, NULL)) << strerror(errno); ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize)); + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + +/* + * Without the FUSE_ASYNC_READ mount option, fuse(4) should ensure that there + * is at most one outstanding read operation per file handle + */ +TEST_F(AioRead, async_read_disabled) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + uint64_t ino = 42; + int fd; + ssize_t bufsize = 50; + char buf0[bufsize], buf1[bufsize]; + off_t off0 = 0; + off_t off1 = 4096; + struct aiocb iocb0, iocb1; + + expect_lookup(RELPATH, ino); + expect_open(ino, 0, 1); + expect_getattr(ino, bufsize); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_READ && + in->header.nodeid == ino && + in->body.read.fh == FH && + in->body.read.offset == (uint64_t)off0 && + in->body.read.size == bufsize); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in __unused, auto &out __unused) { + /* Filesystem is slow to respond */ + })); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_READ && + in->header.nodeid == ino && + in->body.read.fh == FH && + in->body.read.offset == (uint64_t)off1 && + in->body.read.size == bufsize); + }, Eq(true)), + _) + ).Times(0); + + fd = open(FULLPATH, O_RDONLY); + ASSERT_LE(0, fd) << strerror(errno); + + /* + * Submit two AIO read requests, and respond to neither. If the + * filesystem ever gets the second read request, then we failed to + * limit outstanding reads. + */ + iocb0.aio_nbytes = bufsize; + iocb0.aio_fildes = fd; + iocb0.aio_buf = buf0; + iocb0.aio_offset = off0; + iocb0.aio_sigevent.sigev_notify = SIGEV_NONE; + ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno); + + iocb1.aio_nbytes = bufsize; + iocb1.aio_fildes = fd; + iocb1.aio_buf = buf1; + iocb1.aio_offset = off1; + iocb1.aio_sigevent.sigev_notify = SIGEV_NONE; + ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno); + + /* + * Sleep for awhile to make sure the kernel has had a chance to issue + * the second read, even though the first has not yet returned + */ + usleep(250'000); + + /* Deliberately leak iocbs */ + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + +/* + * With the FUSE_ASYNC_READ mount option, fuse(4) may issue multiple + * simultaneous read requests on the same file handle. + */ +/* + * Disabled because we don't yet implement FUSE_ASYNC_READ. No bugzilla + * entry, because that's a feature request, not a bug. + */ +TEST_F(AsyncRead, DISABLED_async_read) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + uint64_t ino = 42; + int fd; + ssize_t bufsize = 50; + char buf0[bufsize], buf1[bufsize]; + off_t off0 = 0; + off_t off1 = 4096; + struct aiocb iocb0, iocb1; + + expect_lookup(RELPATH, ino); + expect_open(ino, 0, 1); + expect_getattr(ino, bufsize); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_READ && + in->header.nodeid == ino && + in->body.read.fh == FH && + in->body.read.offset == (uint64_t)off0 && + in->body.read.size == bufsize); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in __unused, auto &out __unused) { + /* Filesystem is slow to respond */ + })); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_READ && + in->header.nodeid == ino && + in->body.read.fh == FH && + in->body.read.offset == (uint64_t)off1 && + in->body.read.size == bufsize); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in __unused, auto &out __unused) { + /* Filesystem is slow to respond */ + })); + + fd = open(FULLPATH, O_RDONLY); + ASSERT_LE(0, fd) << strerror(errno); + + /* + * Submit two AIO read requests, but respond to neither. Ensure that + * we received both. + */ + iocb0.aio_nbytes = bufsize; + iocb0.aio_fildes = fd; + iocb0.aio_buf = buf0; + iocb0.aio_offset = off0; + iocb0.aio_sigevent.sigev_notify = SIGEV_NONE; + ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno); + + iocb1.aio_nbytes = bufsize; + iocb1.aio_fildes = fd; + iocb1.aio_buf = buf1; + iocb1.aio_offset = off1; + iocb1.aio_sigevent.sigev_notify = SIGEV_NONE; + ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno); + + /* + * Sleep for awhile to make sure the kernel has had a chance to issue + * both reads. + */ + usleep(250'000); + + /* Deliberately leak iocbs */ /* Deliberately leak fd. close(2) will be tested in release.cc */ }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903152016.x2FKGaqb048685>