fusefs: respect RLIMIT_FSIZE

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-06-03 23:24:07 +00:00
parent 6ff7f297f8
commit a639731ba9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=348593
2 changed files with 61 additions and 0 deletions

View File

@ -447,6 +447,9 @@ fuse_write_directbackend(struct vnode *vp, struct uio *uio,
if (ioflag & IO_APPEND)
uio_setoffset(uio, filesize);
if (vn_rlimit_fsize(vp, uio, uio->uio_td))
return (EFBIG);
fdisp_init(&fdi, 0);
while (uio->uio_resid > 0) {
@ -579,6 +582,9 @@ fuse_write_biobackend(struct vnode *vp, struct uio *uio,
if (ioflag & IO_APPEND)
uio_setoffset(uio, filesize);
if (vn_rlimit_fsize(vp, uio, uio->uio_td))
return (EFBIG);
/*
* Find all of this file's B_NEEDCOMMIT buffers. If our writes
* would exceed the local maximum per-file write commit size when

View File

@ -31,12 +31,15 @@
extern "C" {
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <aio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
}
@ -48,6 +51,22 @@ using namespace testing;
class Write: 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_lookup(const char *relpath, uint64_t ino, uint64_t size)
{
@ -73,6 +92,8 @@ void expect_write(uint64_t ino, uint64_t offset, uint64_t isize,
};
sig_atomic_t Write::s_sigxfsz = 0;
class Write_7_8: public FuseTest {
public:
@ -158,6 +179,10 @@ void expect_write(uint64_t ino, uint64_t offset, uint64_t isize,
}
};
void sigxfsz_handler(int __unused sig) {
Write::s_sigxfsz = 1;
}
/* AIO writes need to set the header's pid field correctly */
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
TEST_F(AioWrite, DISABLED_aio_write)
@ -372,6 +397,36 @@ TEST_F(Write, direct_io_short_write_iov)
/* Deliberately leak fd. close(2) will be tested in release.cc */
}
/* fusefs should respect RLIMIT_FSIZE */
TEST_F(Write, rlimit_fsize)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const char *CONTENTS = "abcdefgh";
struct rlimit rl;
ssize_t bufsize = strlen(CONTENTS);
off_t offset = 1'000'000'000;
uint64_t ino = 42;
int fd;
expect_lookup(RELPATH, ino, 0);
expect_open(ino, 0, 1);
rl.rlim_cur = offset;
rl.rlim_max = 10 * offset;
ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno);
ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno);
fd = open(FULLPATH, O_WRONLY);
EXPECT_LE(0, fd) << strerror(errno);
ASSERT_EQ(-1, pwrite(fd, CONTENTS, bufsize, offset));
EXPECT_EQ(EFBIG, errno);
EXPECT_EQ(1, s_sigxfsz);
/* Deliberately leak fd. close(2) will be tested in release.cc */
}
/*
* If the kernel cannot be sure which uid, gid, or pid was responsible for a
* write, then it must set the FUSE_WRITE_CACHE bit