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
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=346756
@ -1927,10 +1927,13 @@ v_inval_buf_range(struct vnode *vp, off_t start, off_t end, int blksize)
|
|||||||
{
|
{
|
||||||
struct bufobj *bo;
|
struct bufobj *bo;
|
||||||
daddr_t startlbn, endlbn;
|
daddr_t startlbn, endlbn;
|
||||||
|
vm_pindex_t startp, endp;
|
||||||
|
|
||||||
/* Round "outwards" */
|
/* Round "outwards" */
|
||||||
startlbn = start / blksize;
|
startlbn = start / blksize;
|
||||||
endlbn = howmany(end, 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");
|
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;
|
goto restart;
|
||||||
|
|
||||||
BO_UNLOCK(bo);
|
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 */
|
/* 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 FULLPATH[] = "mountpoint/some_file.txt";
|
||||||
const char RELPATH[] = "some_file.txt";
|
const char RELPATH[] = "some_file.txt";
|
||||||
const char CONTENTS0[] = "abcdefgh";
|
ssize_t bufsize = 65536;
|
||||||
const char CONTENTS1[] = "ijklmnop";
|
/* End the write in the middle of a page */
|
||||||
|
ssize_t wrsize = bufsize - 1000;
|
||||||
|
char *contents0, *contents1, *readbuf, *expected;
|
||||||
uint64_t ino = 42;
|
uint64_t ino = 42;
|
||||||
int fd;
|
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_lookup(RELPATH, ino, bufsize);
|
||||||
expect_open(ino, 0, 1);
|
expect_open(ino, 0, 1);
|
||||||
expect_read(ino, 0, bufsize, bufsize, CONTENTS0);
|
expect_read(ino, 0, bufsize, bufsize, contents0);
|
||||||
expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS1);
|
expect_write(ino, 0, wrsize, wrsize, 0, contents1);
|
||||||
|
|
||||||
fd = open(FULLPATH, O_RDWR);
|
fd = open(FULLPATH, O_RDWR);
|
||||||
EXPECT_LE(0, fd) << strerror(errno);
|
EXPECT_LE(0, fd) << strerror(errno);
|
||||||
@ -433,13 +444,13 @@ TEST_F(WriteThrough, evicts_read_cache)
|
|||||||
|
|
||||||
// Write directly, evicting cache
|
// Write directly, evicting cache
|
||||||
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
|
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
|
// 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(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
|
||||||
ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << 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 */
|
/* Deliberately leak fd. close(2) will be tested in release.cc */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user