diff options
author | Alan Somers <asomers@FreeBSD.org> | 2022-09-25 22:53:36 +0000 |
---|---|---|
committer | Alan Somers <asomers@FreeBSD.org> | 2022-09-26 21:22:29 +0000 |
commit | 52360ca32ff90b605ac7481fd79e6a251e8b5116 (patch) | |
tree | d19f3e3f004fb4940c216929eea597f54f91ebcc /tests | |
parent | 0b9bc97342f98a911985ace5527aef97863dfd23 (diff) | |
download | src-52360ca32ff90b605ac7481fd79e6a251e8b5116.tar.gz src-52360ca32ff90b605ac7481fd79e6a251e8b5116.zip |
copy_file_range: truncate write if it would exceed RLIMIT_FSIZE
PR: 266611
MFC after: 2 weeks
Reviewed by: kib
Differential Revision: https://reviews.freebsd.org/D36706
Diffstat (limited to 'tests')
-rw-r--r-- | tests/sys/fs/fusefs/copy_file_range.cc | 113 |
1 files changed, 88 insertions, 25 deletions
diff --git a/tests/sys/fs/fusefs/copy_file_range.cc b/tests/sys/fs/fusefs/copy_file_range.cc index 7e1189648de3..84101ca6c984 100644 --- a/tests/sys/fs/fusefs/copy_file_range.cc +++ b/tests/sys/fs/fusefs/copy_file_range.cc @@ -44,22 +44,6 @@ using namespace testing; class CopyFileRange: public FuseTest { public: -static sig_atomic_t s_sigxfsz; - -void SetUp() { - s_sigxfsz = 0; - FuseTest::SetUp(); -} - -void TearDown() { - struct sigaction sa; - - bzero(&sa, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigaction(SIGXFSZ, &sa, NULL); - - FuseTest::TearDown(); -} void expect_maybe_lseek(uint64_t ino) { @@ -114,12 +98,6 @@ void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, }; -sig_atomic_t CopyFileRange::s_sigxfsz = 0; - -void sigxfsz_handler(int __unused sig) { - CopyFileRange::s_sigxfsz = 1; -} - class CopyFileRange_7_27: public CopyFileRange { public: @@ -137,6 +115,37 @@ virtual void SetUp() { } }; +class CopyFileRangeRlimitFsize: public CopyFileRange { +public: +static sig_atomic_t s_sigxfsz; +struct rlimit m_initial_limit; + +virtual void SetUp() { + s_sigxfsz = 0; + getrlimit(RLIMIT_FSIZE, &m_initial_limit); + CopyFileRange::SetUp(); +} + +void TearDown() { + struct sigaction sa; + + setrlimit(RLIMIT_FSIZE, &m_initial_limit); + + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGXFSZ, &sa, NULL); + + FuseTest::TearDown(); +} + +}; + +sig_atomic_t CopyFileRangeRlimitFsize::s_sigxfsz = 0; + +void sigxfsz_handler(int __unused sig) { + CopyFileRangeRlimitFsize::s_sigxfsz = 1; +} + TEST_F(CopyFileRange, eio) { const char FULLPATH1[] = "mountpoint/src.txt"; @@ -313,8 +322,11 @@ TEST_F(CopyFileRange, fallback) ASSERT_EQ(len, copy_file_range(fd1, &start1, fd2, &start2, len, 0)); } -/* fusefs should respect RLIMIT_FSIZE */ -TEST_F(CopyFileRange, rlimit_fsize) +/* + * copy_file_range should send SIGXFSZ and return EFBIG when the operation + * would exceed the limit imposed by RLIMIT_FSIZE. + */ +TEST_F(CopyFileRangeRlimitFsize, signal) { const char FULLPATH1[] = "mountpoint/src.txt"; const char RELPATH1[] = "src.txt"; @@ -344,7 +356,7 @@ TEST_F(CopyFileRange, rlimit_fsize) ).Times(0); rl.rlim_cur = fsize2; - rl.rlim_max = 10 * fsize2; + rl.rlim_max = m_initial_limit.rlim_max; ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno); ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno); @@ -355,6 +367,57 @@ TEST_F(CopyFileRange, rlimit_fsize) EXPECT_EQ(1, s_sigxfsz); } +/* + * When crossing the RLIMIT_FSIZE boundary, writes should be truncated, not + * aborted. + * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=266611 + */ +TEST_F(CopyFileRangeRlimitFsize, truncate) +{ + const char FULLPATH1[] = "mountpoint/src.txt"; + const char RELPATH1[] = "src.txt"; + const char FULLPATH2[] = "mountpoint/dst.txt"; + const char RELPATH2[] = "dst.txt"; + struct rlimit rl; + const uint64_t ino1 = 42; + const uint64_t ino2 = 43; + const uint64_t fh1 = 0xdeadbeef1a7ebabe; + const uint64_t fh2 = 0xdeadc0de88c0ffee; + off_t fsize1 = 1 << 20; /* 1 MiB */ + off_t fsize2 = 1 << 19; /* 512 KiB */ + off_t start1 = 1 << 18; + off_t start2 = fsize2; + ssize_t len = 65536; + off_t limit = start2 + len / 2; + int fd1, fd2; + + expect_lookup(RELPATH1, ino1, S_IFREG | 0644, fsize1, 1); + expect_lookup(RELPATH2, ino2, S_IFREG | 0644, fsize2, 1); + expect_open(ino1, 0, 1, fh1); + expect_open(ino2, 0, 1, fh2); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in.header.opcode == FUSE_COPY_FILE_RANGE && + (off_t)in.body.copy_file_range.off_out == start2 && + in.body.copy_file_range.len == (size_t)len / 2 + ); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { + SET_OUT_HEADER_LEN(out, write); + out.body.write.size = len / 2; + }))); + + rl.rlim_cur = limit; + rl.rlim_max = m_initial_limit.rlim_max; + ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno); + ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno); + + fd1 = open(FULLPATH1, O_RDONLY); + fd2 = open(FULLPATH2, O_WRONLY); + ASSERT_EQ(len / 2, copy_file_range(fd1, &start1, fd2, &start2, len, 0)); +} + TEST_F(CopyFileRange, ok) { const char FULLPATH1[] = "mountpoint/src.txt"; |