diff options
| author | Alan Somers <asomers@FreeBSD.org> | 2019-06-25 17:24:43 +0000 |
|---|---|---|
| committer | Alan Somers <asomers@FreeBSD.org> | 2019-06-25 17:24:43 +0000 |
| commit | b9e20197551d547fc3ebcb747a568d50ca98c47d (patch) | |
| tree | 9605f046a53b0b17587aca84aecaebe1a16e3cee /tests/sys | |
| parent | 48417ae0ba1b0b42d8ad04679a0b7c9dd43eb1f2 (diff) | |
Notes
Diffstat (limited to 'tests/sys')
| -rw-r--r-- | tests/sys/fs/fusefs/read.cc | 62 | ||||
| -rw-r--r-- | tests/sys/fs/fusefs/write.cc | 33 |
2 files changed, 92 insertions, 3 deletions
diff --git a/tests/sys/fs/fusefs/read.cc b/tests/sys/fs/fusefs/read.cc index 2ef9f6be55ace..5694a8f5f79fb 100644 --- a/tests/sys/fs/fusefs/read.cc +++ b/tests/sys/fs/fusefs/read.cc @@ -413,7 +413,8 @@ TEST_F(Read, eio) /* * If the server returns a short read when direct io is not in use, that - * indicates EOF and we should update the file size. + * indicates EOF, because of a server-side truncation. We should invalidate + * all cached attributes. We may update the file size, */ TEST_F(ReadCacheable, eof) { @@ -425,18 +426,21 @@ TEST_F(ReadCacheable, eof) uint64_t offset = 100; ssize_t bufsize = strlen(CONTENTS); ssize_t partbufsize = 3 * bufsize / 4; + ssize_t r; char buf[bufsize]; struct stat sb; expect_lookup(RELPATH, ino, offset + bufsize); expect_open(ino, 0, 1); expect_read(ino, 0, offset + bufsize, offset + partbufsize, CONTENTS); + expect_getattr(ino, offset + partbufsize); fd = open(FULLPATH, O_RDONLY); ASSERT_LE(0, fd) << strerror(errno); - ASSERT_EQ(partbufsize, pread(fd, buf, bufsize, offset)) - << strerror(errno); + r = pread(fd, buf, bufsize, offset); + ASSERT_LE(0, r) << strerror(errno); + EXPECT_EQ(partbufsize, r) << strerror(errno); ASSERT_EQ(0, fstat(fd, &sb)); EXPECT_EQ((off_t)(offset + partbufsize), sb.st_size); /* Deliberately leak fd. close(2) will be tested in release.cc */ @@ -459,6 +463,7 @@ TEST_F(ReadCacheable, eof_of_whole_buffer) expect_open(ino, 0, 1); expect_read(ino, 2 * m_maxbcachebuf, bufsize, bufsize, CONTENTS); expect_read(ino, m_maxbcachebuf, m_maxbcachebuf, 0, CONTENTS); + expect_getattr(ino, m_maxbcachebuf); fd = open(FULLPATH, O_RDONLY); ASSERT_LE(0, fd) << strerror(errno); @@ -586,6 +591,57 @@ TEST_F(ReadCacheable, mmap) /* Deliberately leak fd. close(2) will be tested in release.cc */ } +/* + * A read via mmap comes up short, indicating that the file was truncated + * server-side. + */ +TEST_F(ReadCacheable, mmap_eof) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const char *CONTENTS = "abcdefgh"; + uint64_t ino = 42; + int fd; + ssize_t len; + size_t bufsize = strlen(CONTENTS); + struct stat sb; + void *p; + + len = getpagesize(); + + expect_lookup(RELPATH, ino, 100000); + expect_open(ino, 0, 1); + /* mmap may legitimately try to read more data than is available */ + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in.header.opcode == FUSE_READ && + in.header.nodeid == ino && + in.body.read.fh == Read::FH && + in.body.read.offset == 0 && + in.body.read.size >= bufsize); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { + out.header.len = sizeof(struct fuse_out_header) + bufsize; + memmove(out.body.bytes, CONTENTS, bufsize); + }))); + expect_getattr(ino, bufsize); + + fd = open(FULLPATH, O_RDONLY); + ASSERT_LE(0, fd) << strerror(errno); + + p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + ASSERT_NE(MAP_FAILED, p) << strerror(errno); + + /* The file size should be automatically truncated */ + ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize)); + ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno); + EXPECT_EQ((off_t)bufsize, sb.st_size); + + ASSERT_EQ(0, munmap(p, len)) << strerror(errno); + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + /* * Just as when FOPEN_DIRECT_IO is used, reads with O_DIRECT should bypass * cache and to straight to the daemon diff --git a/tests/sys/fs/fusefs/write.cc b/tests/sys/fs/fusefs/write.cc index b59273385b390..df6ef36366f2a 100644 --- a/tests/sys/fs/fusefs/write.cc +++ b/tests/sys/fs/fusefs/write.cc @@ -528,6 +528,39 @@ TEST_F(Write, rlimit_fsize) /* Deliberately leak fd. close(2) will be tested in release.cc */ } +/* + * A short read indicates EOF. Test that nothing bad happens if we get EOF + * during the R of a RMW operation. + */ +TEST_F(WriteCacheable, eof_during_rmw) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const char *CONTENTS = "abcdefgh"; + const char *INITIAL = "XXXXXXXXXX"; + uint64_t ino = 42; + uint64_t offset = 1; + ssize_t bufsize = strlen(CONTENTS); + off_t orig_fsize = 10; + off_t truncated_fsize = 5; + off_t final_fsize = bufsize; + int fd; + + FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, orig_fsize, 1); + expect_open(ino, 0, 1); + expect_read(ino, 0, orig_fsize, truncated_fsize, INITIAL, O_RDWR); + expect_getattr(ino, truncated_fsize); + expect_read(ino, 0, final_fsize, final_fsize, INITIAL, O_RDWR); + maybe_expect_write(ino, offset, bufsize, CONTENTS); + + fd = open(FULLPATH, O_RDWR); + EXPECT_LE(0, fd) << strerror(errno); + + ASSERT_EQ(bufsize, pwrite(fd, CONTENTS, bufsize, offset)) + << strerror(errno); + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + /* * If the kernel cannot be sure which uid, gid, or pid was responsible for a * write, then it must set the FUSE_WRITE_CACHE bit |
