aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2022-09-25 17:56:11 +0000
committerAlan Somers <asomers@FreeBSD.org>2022-09-25 21:02:23 +0000
commit0a192b3abab19deac70f762cd1ec45ba09ec47ca (patch)
treea69de5d5d9f93e4d175455747774368a56cf8de8
parent550e01c552474babae468011191ecc5130cc153e (diff)
downloadsrc-0a192b3abab19deac70f762cd1ec45ba09ec47ca.tar.gz
src-0a192b3abab19deac70f762cd1ec45ba09ec47ca.zip
fusefs: respect RLIMIT_FSIZE during truncate
PR: 164793 MFC after: 2 weeks Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D36703
-rw-r--r--sys/fs/fuse/fuse_vnops.c3
-rw-r--r--tests/sys/fs/fusefs/setattr.cc44
2 files changed, 46 insertions, 1 deletions
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index e89b831a4859..6fa9a2b248c6 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2248,6 +2248,9 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
case VREG:
if (vfs_isrdonly(mp))
return (EROFS);
+ err = vn_rlimit_trunc(vap->va_size, td);
+ if (err)
+ return (err);
break;
default:
/*
diff --git a/tests/sys/fs/fusefs/setattr.cc b/tests/sys/fs/fusefs/setattr.cc
index 00b37ec7965a..e245c274ba07 100644
--- a/tests/sys/fs/fusefs/setattr.cc
+++ b/tests/sys/fs/fusefs/setattr.cc
@@ -31,10 +31,14 @@
*/
extern "C" {
+#include <sys/types.h>
+#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <fcntl.h>
#include <semaphore.h>
+#include <signal.h>
}
#include "mockfs.hh"
@@ -42,11 +46,15 @@ extern "C" {
using namespace testing;
-class Setattr : public FuseTest {};
+class Setattr : public FuseTest {
+public:
+static sig_atomic_t s_sigxfsz;
+};
class RofsSetattr: public Setattr {
public:
virtual void SetUp() {
+ s_sigxfsz = 0;
m_ro = true;
Setattr::SetUp();
}
@@ -61,6 +69,12 @@ virtual void SetUp() {
};
+sig_atomic_t Setattr::s_sigxfsz = 0;
+
+void sigxfsz_handler(int __unused sig) {
+ Setattr::s_sigxfsz = 1;
+}
+
/*
* If setattr returns a non-zero cache timeout, then subsequent VOP_GETATTRs
* should use the cached attributes, rather than query the daemon
@@ -553,6 +567,34 @@ TEST_F(Setattr, truncate_discards_cached_data) {
leak(fd);
}
+/* truncate should fail if it would cause the file to exceed RLIMIT_FSIZE */
+TEST_F(Setattr, truncate_rlimit_rsize)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ struct rlimit rl;
+ const uint64_t ino = 42;
+ const uint64_t oldsize = 0;
+ const uint64_t newsize = 100'000'000;
+
+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
+ .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
+ SET_OUT_HEADER_LEN(out, entry);
+ out.body.entry.attr.mode = S_IFREG | 0644;
+ out.body.entry.nodeid = ino;
+ out.body.entry.attr.size = oldsize;
+ })));
+
+ rl.rlim_cur = newsize / 2;
+ rl.rlim_max = 10 * newsize;
+ ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno);
+ ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno);
+
+ EXPECT_EQ(-1, truncate(FULLPATH, newsize));
+ EXPECT_EQ(EFBIG, errno);
+ EXPECT_EQ(1, s_sigxfsz);
+}
+
/* Change a file's timestamps */
TEST_F(Setattr, utimensat) {
const char FULLPATH[] = "mountpoint/some_file.txt";