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:
parent
102c7ac083
commit
75d5cb29cb
@ -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 */
|
||||
|
@ -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 */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user