mirror of
https://github.com/opnsense/src.git
synced 2026-06-06 07:12:52 -04:00
fusefs: add a test for the max_read= mount option
When set, this limits the amount of data that the kernel will request of the server in any single read operation. The option has always been available in our fusefs implementation, but never covered by the test suite. MFC after: 2 weeks Sponsored by: ConnectWise
This commit is contained in:
parent
c0661bbbd0
commit
9f31c47460
5 changed files with 72 additions and 3 deletions
|
|
@ -416,7 +416,8 @@ void MockFS::debug_response(const mockfs_buf_out &out) {
|
|||
}
|
||||
}
|
||||
|
||||
MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
|
||||
MockFS::MockFS(int max_read, int max_readahead, bool allow_other,
|
||||
bool default_permissions,
|
||||
bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags,
|
||||
uint32_t kernel_minor_version, uint32_t max_write, bool async,
|
||||
bool noclusterr, unsigned time_gran, bool nointr, bool noatime,
|
||||
|
|
@ -424,6 +425,7 @@ MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
|
|||
: m_daemon_id(NULL),
|
||||
m_kernel_minor_version(kernel_minor_version),
|
||||
m_kq(pm == KQ ? kqueue() : -1),
|
||||
m_maxread(max_read),
|
||||
m_maxreadahead(max_readahead),
|
||||
m_pid(getpid()),
|
||||
m_uniques(new std::unordered_set<uint64_t>),
|
||||
|
|
@ -470,6 +472,12 @@ MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
|
|||
build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
|
||||
sprintf(fdstr, "%d", m_fuse_fd);
|
||||
build_iovec(&iov, &iovlen, "fd", fdstr, -1);
|
||||
if (m_maxread > 0) {
|
||||
char val[10];
|
||||
|
||||
snprintf(val, sizeof(val), "%d", m_maxread);
|
||||
build_iovec(&iov, &iovlen, "max_read=", &val, -1);
|
||||
}
|
||||
if (allow_other) {
|
||||
build_iovec(&iov, &iovlen, "allow_other",
|
||||
__DECONST(void*, &trueval), sizeof(bool));
|
||||
|
|
|
|||
|
|
@ -294,6 +294,12 @@ class MockFS {
|
|||
|
||||
int m_kq;
|
||||
|
||||
/*
|
||||
* If nonzero, the maximum size in bytes of a read that the kernel will
|
||||
* send to the server.
|
||||
*/
|
||||
int m_maxread;
|
||||
|
||||
/* The max_readahead file system option */
|
||||
uint32_t m_maxreadahead;
|
||||
|
||||
|
|
@ -355,7 +361,7 @@ class MockFS {
|
|||
bool m_quit;
|
||||
|
||||
/* Create a new mockfs and mount it to a tempdir */
|
||||
MockFS(int max_readahead, bool allow_other,
|
||||
MockFS(int max_read, int max_readahead, bool allow_other,
|
||||
bool default_permissions, bool push_symlinks_in, bool ro,
|
||||
enum poll_method pm, uint32_t flags,
|
||||
uint32_t kernel_minor_version, uint32_t max_write, bool async,
|
||||
|
|
|
|||
|
|
@ -111,6 +111,13 @@ class ReadAhead: public Read,
|
|||
}
|
||||
};
|
||||
|
||||
class ReadMaxRead: public Read {
|
||||
virtual void SetUp() {
|
||||
m_maxread = 16384;
|
||||
Read::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
class ReadNoatime: public Read {
|
||||
virtual void SetUp() {
|
||||
m_noatime = true;
|
||||
|
|
@ -840,6 +847,52 @@ TEST_F(Read, mmap)
|
|||
leak(fd);
|
||||
}
|
||||
|
||||
|
||||
/* When max_read is set, large reads will be split up as necessary */
|
||||
TEST_F(ReadMaxRead, split)
|
||||
{
|
||||
const char FULLPATH[] = "mountpoint/some_file.txt";
|
||||
const char RELPATH[] = "some_file.txt";
|
||||
uint64_t ino = 42;
|
||||
int fd;
|
||||
ssize_t bufsize = 65536;
|
||||
ssize_t fragsize = bufsize / 4;
|
||||
char *rbuf, *frag0, *frag1, *frag2, *frag3;
|
||||
|
||||
rbuf = new char[bufsize]();
|
||||
frag0 = new char[fragsize]();
|
||||
frag1 = new char[fragsize]();
|
||||
frag2 = new char[fragsize]();
|
||||
frag3 = new char[fragsize]();
|
||||
memset(frag0, '0', fragsize);
|
||||
memset(frag1, '1', fragsize);
|
||||
memset(frag2, '2', fragsize);
|
||||
memset(frag3, '3', fragsize);
|
||||
|
||||
expect_lookup(RELPATH, ino, bufsize);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_read(ino, 0, fragsize, fragsize, frag0);
|
||||
expect_read(ino, fragsize, fragsize, fragsize, frag1);
|
||||
expect_read(ino, 2 * fragsize, fragsize, fragsize, frag2);
|
||||
expect_read(ino, 3 * fragsize, fragsize, fragsize, frag3);
|
||||
|
||||
fd = open(FULLPATH, O_RDONLY);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
|
||||
ASSERT_EQ(bufsize, read(fd, rbuf, bufsize)) << strerror(errno);
|
||||
ASSERT_EQ(0, memcmp(rbuf, frag0, fragsize));
|
||||
ASSERT_EQ(0, memcmp(rbuf + fragsize, frag1, fragsize));
|
||||
ASSERT_EQ(0, memcmp(rbuf + 2 * fragsize, frag2, fragsize));
|
||||
ASSERT_EQ(0, memcmp(rbuf + 3 * fragsize, frag3, fragsize));
|
||||
|
||||
delete[] frag3;
|
||||
delete[] frag2;
|
||||
delete[] frag1;
|
||||
delete[] frag0;
|
||||
delete[] rbuf;
|
||||
leak(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* The kernel should not update the cached atime attribute during a read, if
|
||||
* MNT_NOATIME is used.
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void FuseTest::SetUp() {
|
|||
m_maxwrite = MIN(libfuse_max_write, (uint32_t)m_maxphys / 2);
|
||||
|
||||
try {
|
||||
m_mock = new MockFS(m_maxreadahead, m_allow_other,
|
||||
m_mock = new MockFS(m_maxread, m_maxreadahead, m_allow_other,
|
||||
m_default_permissions, m_push_symlinks_in, m_ro,
|
||||
m_pm, m_init_flags, m_kernel_minor_version,
|
||||
m_maxwrite, m_async, m_noclusterr, m_time_gran,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ bool is_unsafe_aio_enabled(void);
|
|||
extern const uint32_t libfuse_max_write;
|
||||
class FuseTest : public ::testing::Test {
|
||||
protected:
|
||||
uint32_t m_maxread;
|
||||
uint32_t m_maxreadahead;
|
||||
uint32_t m_maxwrite;
|
||||
uint32_t m_init_flags;
|
||||
|
|
@ -80,6 +81,7 @@ class FuseTest : public ::testing::Test {
|
|||
unsigned long m_maxphys;
|
||||
|
||||
FuseTest():
|
||||
m_maxread(0),
|
||||
m_maxreadahead(0),
|
||||
m_maxwrite(0),
|
||||
m_init_flags(0),
|
||||
|
|
|
|||
Loading…
Reference in a new issue