fusefs: fix cache invalidation error from r346162

An off-by-one error led to the last page of a write not being removed from
its object, even though that page's buffer was marked as invalid.

PR:		235774
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-04-26 17:09:26 +00:00
parent 102c7ac083
commit 75d5cb29cb
2 changed files with 24 additions and 10 deletions

View File

@ -1927,10 +1927,13 @@ v_inval_buf_range(struct vnode *vp, off_t start, off_t end, int blksize)
{
struct bufobj *bo;
daddr_t startlbn, endlbn;
vm_pindex_t startp, endp;
/* Round "outwards" */
startlbn = start / blksize;
endlbn = howmany(end, blksize);
startp = OFF_TO_IDX(start);
endp = OFF_TO_IDX(end + PAGE_SIZE - 1);
ASSERT_VOP_LOCKED(vp, "v_inval_buf_range");
@ -1960,7 +1963,7 @@ v_inval_buf_range(struct vnode *vp, off_t start, off_t end, int blksize)
goto restart;
BO_UNLOCK(bo);
vn_pages_remove(vp, OFF_TO_IDX(start), OFF_TO_IDX(end));
vn_pages_remove(vp, startp, endp);
}
/* Like v_inval_buf_range, but operates on whole buffers instead of offsets */

View File

@ -413,17 +413,28 @@ TEST_F(WriteThrough, evicts_read_cache)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const char CONTENTS0[] = "abcdefgh";
const char CONTENTS1[] = "ijklmnop";
ssize_t bufsize = 65536;
/* End the write in the middle of a page */
ssize_t wrsize = bufsize - 1000;
char *contents0, *contents1, *readbuf, *expected;
uint64_t ino = 42;
int fd;
ssize_t bufsize = strlen(CONTENTS0) + 1;
char readbuf[bufsize];
contents0 = (char*)malloc(bufsize);
memset(contents0, 'X', bufsize);
contents0[bufsize - 1] = '\0'; // Null-terminate
contents1 = (char*)malloc(wrsize);
memset(contents1, 'Y', wrsize);
readbuf = (char*)calloc(bufsize, 1);
expected = (char*)malloc(bufsize);
memset(expected, 'Y', wrsize);
memset(expected + wrsize, 'X', bufsize - wrsize);
expected[bufsize - 1] = '\0'; // Null-terminate
expect_lookup(RELPATH, ino, bufsize);
expect_open(ino, 0, 1);
expect_read(ino, 0, bufsize, bufsize, CONTENTS0);
expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS1);
expect_read(ino, 0, bufsize, bufsize, contents0);
expect_write(ino, 0, wrsize, wrsize, 0, contents1);
fd = open(FULLPATH, O_RDWR);
EXPECT_LE(0, fd) << strerror(errno);
@ -433,13 +444,13 @@ TEST_F(WriteThrough, evicts_read_cache)
// Write directly, evicting cache
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
ASSERT_EQ(bufsize, write(fd, CONTENTS1, bufsize)) << strerror(errno);
ASSERT_EQ(wrsize, write(fd, contents1, wrsize)) << strerror(errno);
// Read again. Cache should be bypassed
expect_read(ino, 0, bufsize, bufsize, CONTENTS1);
expect_read(ino, 0, bufsize, bufsize, expected);
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
ASSERT_STREQ(readbuf, CONTENTS1);
ASSERT_STREQ(readbuf, expected);
/* Deliberately leak fd. close(2) will be tested in release.cc */
}