Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F106979027
D36706.id111035.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D36706.id111035.diff
View Options
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -811,6 +811,7 @@
struct thread *td;
struct uio io;
off_t outfilesize;
+ ssize_t r = 0;
pid_t pid;
int err;
@@ -858,11 +859,11 @@
if (err)
goto unlock;
+ io.uio_resid = *ap->a_lenp;
if (ap->a_fsizetd) {
io.uio_offset = *ap->a_outoffp;
- io.uio_resid = *ap->a_lenp;
- err = vn_rlimit_fsize(outvp, &io, ap->a_fsizetd);
- if (err)
+ err = vn_rlimit_fsizex(outvp, &io, 0, &r, ap->a_fsizetd);
+ if (err != 0)
goto unlock;
}
@@ -871,7 +872,7 @@
goto unlock;
err = fuse_inval_buf_range(outvp, outfilesize, *ap->a_outoffp,
- *ap->a_outoffp + *ap->a_lenp);
+ *ap->a_outoffp + io.uio_resid);
if (err)
goto unlock;
@@ -883,7 +884,7 @@
fcfri->nodeid_out = VTOI(outvp);
fcfri->fh_out = outfufh->fh_id;
fcfri->off_out = *ap->a_outoffp;
- fcfri->len = *ap->a_lenp;
+ fcfri->len = io.uio_resid;
fcfri->flags = 0;
err = fdisp_wait_answ(&fdi);
@@ -915,6 +916,10 @@
ap->a_incred, ap->a_outcred, ap->a_fsizetd);
}
+ /*
+ * No need to call vn_rlimit_fsizex_res before return, since the uio is
+ * local.
+ */
return (err);
}
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -3889,6 +3889,7 @@
struct uio io;
struct nfsmount *nmp;
size_t len, len2;
+ ssize_t r;
int error, inattrflag, outattrflag, ret, ret2;
off_t inoff, outoff;
bool consecutive, must_commit, tryoutcred;
@@ -3937,7 +3938,12 @@
*/
io.uio_offset = *ap->a_outoffp;
io.uio_resid = *ap->a_lenp;
- error = vn_rlimit_fsize(outvp, &io, ap->a_fsizetd);
+ error = vn_rlimit_fsizex(outvp, &io, 0, &r, ap->a_fsizetd);
+ *ap->a_lenp = io.uio_resid;
+ /*
+ * No need to call vn_rlimit_fsizex_res before return, since the uio is
+ * local.
+ */
/*
* Flush the input file so that the data is up to date before
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -3261,12 +3261,11 @@
{
struct vattr va, inva;
struct mount *mp;
- struct uio io;
off_t startoff, endoff, xfer, xfer2;
u_long blksize;
int error, interrupted;
bool cantseek, readzeros, eof, lastblock, holetoeof;
- ssize_t aresid;
+ ssize_t aresid, r = 0;
size_t copylen, len, rem, savlen;
char *dat;
long holein, holeout;
@@ -3295,13 +3294,20 @@
error = vn_lock(outvp, LK_EXCLUSIVE);
if (error == 0) {
/*
- * If fsize_td != NULL, do a vn_rlimit_fsize() call,
+ * If fsize_td != NULL, do a vn_rlimit_fsizex() call,
* now that outvp is locked.
*/
if (fsize_td != NULL) {
+ struct uio io;
+
io.uio_offset = *outoffp;
io.uio_resid = len;
- error = vn_rlimit_fsize(outvp, &io, fsize_td);
+ error = vn_rlimit_fsizex(outvp, &io, 0, &r, fsize_td);
+ len = savlen = io.uio_resid;
+ /*
+ * No need to call vn_rlimit_fsizex_res before return,
+ * since the uio is local.
+ */
}
if (VOP_PATHCONF(outvp, _PC_MIN_HOLE_SIZE, &holeout) != 0)
holeout = 0;
diff --git a/tests/sys/fs/fusefs/copy_file_range.cc b/tests/sys/fs/fusefs/copy_file_range.cc
--- a/tests/sys/fs/fusefs/copy_file_range.cc
+++ b/tests/sys/fs/fusefs/copy_file_range.cc
@@ -44,22 +44,6 @@
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 @@
};
-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 @@
}
};
+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 @@
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 @@
).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 @@
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";
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 9, 10:36 AM (6 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15731757
Default Alt Text
D36706.id111035.diff (6 KB)
Attached To
Mode
D36706: copy_file_range: truncate write if it would exceed RLIMIT_FSIZE
Attached
Detach File
Event Timeline
Log In to Comment