Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107239415
D33389.id99858.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D33389.id99858.diff
View Options
Index: sys/fs/fuse/fuse_internal.c
===================================================================
--- sys/fs/fuse/fuse_internal.c
+++ sys/fs/fuse/fuse_internal.c
@@ -1072,6 +1072,10 @@
fsess_set_notimpl(data->mp, FUSE_DESTROY);
}
+ if (!fuse_libabi_geq(data, 7, 19)) {
+ fsess_set_notimpl(data->mp, FUSE_FALLOCATE);
+ }
+
if (fuse_libabi_geq(data, 7, 23) && fiio->time_gran >= 1 &&
fiio->time_gran <= 1000000000)
data->time_gran = fiio->time_gran;
Index: sys/fs/fuse/fuse_ipc.c
===================================================================
--- sys/fs/fuse/fuse_ipc.c
+++ sys/fs/fuse/fuse_ipc.c
@@ -845,6 +845,10 @@
err = (blen == 0) ? 0 : EINVAL;
break;
+ case FUSE_FALLOCATE:
+ err = (blen == 0) ? 0 : EINVAL;
+ break;
+
case FUSE_LSEEK:
err = (blen == sizeof(struct fuse_lseek_out)) ? 0 : EINVAL;
break;
Index: sys/fs/fuse/fuse_vnops.c
===================================================================
--- sys/fs/fuse/fuse_vnops.c
+++ sys/fs/fuse/fuse_vnops.c
@@ -127,6 +127,7 @@
/* vnode ops */
static vop_access_t fuse_vnop_access;
static vop_advlock_t fuse_vnop_advlock;
+static vop_allocate_t fuse_vnop_allocate;
static vop_bmap_t fuse_vnop_bmap;
static vop_close_t fuse_fifo_close;
static vop_close_t fuse_vnop_close;
@@ -180,7 +181,7 @@
VFS_VOP_VECTOR_REGISTER(fuse_fifoops);
struct vop_vector fuse_vnops = {
- .vop_allocate = VOP_EINVAL,
+ .vop_allocate = fuse_vnop_allocate,
.vop_default = &default_vnodeops,
.vop_access = fuse_vnop_access,
.vop_advlock = fuse_vnop_advlock,
@@ -550,6 +551,94 @@
return err;
}
+static int
+fuse_vnop_allocate(struct vop_allocate_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ off_t *len = ap->a_len;
+ off_t *offset = ap->a_offset;
+ struct ucred *cred = ap->a_cred;
+ struct fuse_filehandle *fufh;
+ struct mount *mp = vnode_mount(vp);
+ struct fuse_dispatcher fdi;
+ struct fuse_fallocate_in *ffi;
+ struct uio io;
+ pid_t pid = curthread->td_proc->p_pid;
+ struct fuse_vnode_data *fvdat = VTOFUD(vp);
+ off_t filesize;
+ int err;
+
+ if (fuse_isdeadfs(vp))
+ return (ENXIO);
+
+ switch (vp->v_type) {
+ case VFIFO:
+ return (ESPIPE);
+ case VLNK:
+ case VREG:
+ if (vfs_isrdonly(mp))
+ return (EROFS);
+ break;
+ default:
+ return (ENODEV);
+ }
+
+ if (vfs_isrdonly(mp))
+ return (EROFS);
+
+ if (fsess_not_impl(mp, FUSE_FALLOCATE))
+ return (EINVAL);
+
+ io.uio_offset = *offset;
+ io.uio_resid = *len;
+ err = vn_rlimit_fsize(vp, &io, curthread);
+ if (err)
+ return (err);
+
+ err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
+ if (err)
+ return (err);
+
+ fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
+
+ err = fuse_vnode_size(vp, &filesize, cred, curthread);
+ if (err)
+ return (err);
+ fuse_inval_buf_range(vp, filesize, *offset, *offset + *len);
+
+ fdisp_init(&fdi, sizeof(*ffi));
+ fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
+ ffi = fdi.indata;
+ ffi->fh = fufh->fh_id;
+ ffi->offset = *offset;
+ ffi->length = *len;
+ ffi->mode = 0;
+ err = fdisp_wait_answ(&fdi);
+
+ if (err == ENOSYS) {
+ fsess_set_notimpl(mp, FUSE_FALLOCATE);
+ err = EINVAL;
+ } else if (err == EOPNOTSUPP) {
+ /*
+ * The file system server does not support FUSE_FALLOCATE with
+ * the supplied mode. That's effectively the same thing as
+ * ENOSYS since we only ever issue mode=0.
+ * TODO: revise this section once we support fspacectl.
+ */
+ fsess_set_notimpl(mp, FUSE_FALLOCATE);
+ err = EINVAL;
+ } else if (!err) {
+ *offset += *len;
+ *len = 0;
+ fuse_vnode_undirty_cached_timestamps(vp, false);
+ fuse_internal_clear_suid_on_write(vp, cred, curthread);
+ if (*offset > fvdat->cached_attrs.va_size)
+ fuse_vnode_setsize(vp, *offset, false);
+ }
+
+ return (err);
+}
+
/* {
struct vnode *a_vp;
daddr_t a_bn;
Index: tests/sys/fs/fusefs/Makefile
===================================================================
--- tests/sys/fs/fusefs/Makefile
+++ tests/sys/fs/fusefs/Makefile
@@ -19,6 +19,7 @@
GTESTS+= default_permissions_privileged
GTESTS+= destroy
GTESTS+= dev_fuse_poll
+GTESTS+= fallocate
GTESTS+= fifo
GTESTS+= flush
GTESTS+= forget
Index: tests/sys/fs/fusefs/default_permissions.cc
===================================================================
--- tests/sys/fs/fusefs/default_permissions.cc
+++ tests/sys/fs/fusefs/default_permissions.cc
@@ -163,6 +163,7 @@
class CopyFileRange: public DefaultPermissions {};
class Lookup: public DefaultPermissions {};
class Open: public DefaultPermissions {};
+class PosixFallocate: public DefaultPermissions {};
class Setattr: public DefaultPermissions {};
class Unlink: public DefaultPermissions {};
class Utimensat: public DefaultPermissions {};
@@ -498,7 +499,7 @@
}
/* A write by a non-owner should clear a file's SGID bit */
-TEST_F(CopyFileRange, clear_guid)
+TEST_F(CopyFileRange, clear_sgid)
{
const char FULLPATH_IN[] = "mountpoint/in.txt";
const char RELPATH_IN[] = "in.txt";
@@ -877,6 +878,92 @@
leak(fd);
}
+/* A write by a non-owner should clear a file's SGID bit */
+TEST_F(PosixFallocate, clear_sgid)
+{
+ const char FULLPATH[] = "mountpoint/file.txt";
+ const char RELPATH[] = "file.txt";
+ struct stat sb;
+ uint64_t ino = 42;
+ mode_t oldmode = 02777;
+ mode_t newmode = 0777;
+ off_t fsize = 16;
+ off_t off = 8;
+ off_t len = 8;
+ int fd;
+
+ expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755, UINT64_MAX, 1);
+ FuseTest::expect_lookup(RELPATH, ino, S_IFREG | oldmode, fsize,
+ 1, UINT64_MAX, 0, 0);
+ expect_open(ino, 0, 1);
+ expect_fallocate(ino, off, len, 0, 0);
+ expect_chmod(ino, newmode, fsize);
+
+ fd = open(FULLPATH, O_WRONLY);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(0, posix_fallocate(fd, off, len)) << strerror(errno);
+ ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
+ EXPECT_EQ(S_IFREG | newmode, sb.st_mode);
+
+ leak(fd);
+}
+
+/* A write by a non-owner should clear a file's SUID bit */
+TEST_F(PosixFallocate, clear_suid)
+{
+ const char FULLPATH[] = "mountpoint/file.txt";
+ const char RELPATH[] = "file.txt";
+ struct stat sb;
+ uint64_t ino = 42;
+ mode_t oldmode = 04777;
+ mode_t newmode = 0777;
+ off_t fsize = 16;
+ off_t off = 8;
+ off_t len = 8;
+ int fd;
+
+ expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755, UINT64_MAX, 1);
+ FuseTest::expect_lookup(RELPATH, ino, S_IFREG | oldmode, fsize,
+ 1, UINT64_MAX, 0, 0);
+ expect_open(ino, 0, 1);
+ expect_fallocate(ino, off, len, 0, 0);
+ expect_chmod(ino, newmode, fsize);
+
+ fd = open(FULLPATH, O_WRONLY);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(0, posix_fallocate(fd, off, len)) << strerror(errno);
+ ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
+ EXPECT_EQ(S_IFREG | newmode, sb.st_mode);
+
+ leak(fd);
+}
+
+/*
+ * posix_fallcoate() of a file without writable permissions should succeed as
+ * long as the file descriptor is writable. This is important when combined
+ * with O_CREAT
+ */
+TEST_F(PosixFallocate, posix_fallocate_of_newly_created_file)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const uint64_t ino = 42;
+ off_t off = 8;
+ off_t len = 8;
+ int fd;
+
+ expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0777, UINT64_MAX, 1);
+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
+ .WillOnce(Invoke(ReturnErrno(ENOENT)));
+ expect_create(RELPATH, ino);
+ expect_fallocate(ino, off, len, 0, 0);
+
+ fd = open(FULLPATH, O_CREAT | O_RDWR, 0);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(0, posix_fallocate(fd, off, len)) << strerror(errno);
+ leak(fd);
+}
+
TEST_F(Rename, eacces_on_srcdir)
{
const char FULLDST[] = "mountpoint/d/dst";
Index: tests/sys/fs/fusefs/fallocate.cc
===================================================================
--- /dev/null
+++ tests/sys/fs/fusefs/fallocate.cc
@@ -0,0 +1,302 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Alan Somers
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+extern "C" {
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "mntopts.h" // for build_iovec
+}
+
+#include "mockfs.hh"
+#include "utils.hh"
+
+using namespace testing;
+
+class Fallocate: public FuseTest{};
+
+class PosixFallocate: public Fallocate {
+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);
+
+ Fallocate::TearDown();
+}
+
+};
+
+sig_atomic_t PosixFallocate::s_sigxfsz = 0;
+
+void sigxfsz_handler(int __unused sig) {
+ PosixFallocate::s_sigxfsz = 1;
+}
+
+class PosixFallocate_7_18: public PosixFallocate {
+public:
+virtual void SetUp() {
+ m_kernel_minor_version = 18;
+ PosixFallocate::SetUp();
+}
+};
+
+
+/*
+ * TODO: test cases:
+ * * test the race with VOP_LOOKUP and VFS_VGET in last_local_modify.cc
+ */
+
+/*
+ * If the server returns ENOSYS, it indicates that the server does not support
+ * FUSE_FALLOCATE. This and future calls should return EINVAL.
+ */
+TEST_F(PosixFallocate, enosys)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1000;
+ int fd;
+
+ expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
+ expect_open(ino, 0, 1);
+ expect_fallocate(ino, offset, length, 0, ENOSYS);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));
+
+ /* Subsequent calls shouldn't query the daemon*/
+ EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));
+
+ leak(fd);
+}
+
+/*
+ * EOPNOTSUPP means either "the file system does not support fallocate" or "the
+ * file system does not support fallocate with the supplied mode". fusefs
+ * should conservatively assume the latter, and not issue any more fallocate
+ * operations with the same mode.
+ */
+TEST_F(PosixFallocate, eopnotsupp)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1000;
+ int fd;
+
+ expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
+ expect_open(ino, 0, 1);
+ expect_fallocate(ino, offset, length, 0, EOPNOTSUPP);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));
+
+ /* Subsequent calls shouldn't query the daemon*/
+ EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));
+
+ leak(fd);
+}
+
+/* EIO is not a permanent error, and may be retried */
+TEST_F(PosixFallocate, eio)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1000;
+ int fd;
+
+ expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
+ expect_open(ino, 0, 1);
+ expect_fallocate(ino, offset, length, 0, EIO);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(EIO, posix_fallocate(fd, offset, length));
+
+ expect_fallocate(ino, offset, length, 0, 0);
+
+ EXPECT_EQ(0, posix_fallocate(fd, offset, length));
+
+ leak(fd);
+}
+
+TEST_F(PosixFallocate, erofs)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ struct statfs statbuf;
+ struct iovec *iov = NULL;
+ int iovlen = 0;
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1000;
+ int fd;
+ int newflags;
+
+ expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
+ expect_open(ino, 0, 1);
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([](auto in) {
+ return (in.header.opcode == FUSE_STATFS);
+ }, Eq(true)),
+ _)
+ ).WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out)
+ {
+ /*
+ * All of the fields except f_flags are don't care, and f_flags
+ * is set by the VFS
+ */
+ SET_OUT_HEADER_LEN(out, statfs);
+ })));
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+
+ /* Remount read-only */
+ ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
+ newflags = statbuf.f_flags | MNT_UPDATE | MNT_RDONLY;
+ build_iovec(&iov, &iovlen, "fstype", (void*)statbuf.f_fstypename, -1);
+ build_iovec(&iov, &iovlen, "fspath", (void*)statbuf.f_mntonname, -1);
+ build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
+ ASSERT_EQ(0, nmount(iov, iovlen, newflags)) << strerror(errno);
+
+ EXPECT_EQ(EROFS, posix_fallocate(fd, offset, length));
+
+ leak(fd);
+}
+
+TEST_F(PosixFallocate, ok)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ struct stat sb0, sb1;
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1000;
+ int fd;
+
+ 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.entry_valid = UINT64_MAX;
+ out.body.entry.attr_valid = UINT64_MAX;
+ })));
+ expect_open(ino, 0, 1);
+ expect_fallocate(ino, offset, length, 0, 0);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ ASSERT_EQ(0, fstat(fd, &sb0)) << strerror(errno);
+ EXPECT_EQ(0, posix_fallocate(fd, offset, length));
+ /*
+ * Despite the originally cached file size of zero, stat should now
+ * return either the new size or requery the daemon.
+ */
+ EXPECT_EQ(0, stat(FULLPATH, &sb1));
+ EXPECT_EQ(length, (uint64_t)sb1.st_size);
+
+ /* mtime and ctime should be updated */
+ EXPECT_EQ(sb0.st_atime, sb1.st_atime);
+ EXPECT_NE(sb0.st_mtime, sb1.st_mtime);
+ EXPECT_NE(sb0.st_ctime, sb1.st_ctime);
+
+ leak(fd);
+}
+
+/* fusefs should respect RLIMIT_FSIZE */
+TEST_F(PosixFallocate, rlimit_fsize)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ struct rlimit rl;
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1'000'000;
+ int fd;
+
+ expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
+ expect_open(ino, 0, 1);
+
+ rl.rlim_cur = length / 2;
+ rl.rlim_max = 10 * length;
+ ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno);
+ ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(EFBIG, posix_fallocate(fd, offset, length));
+ EXPECT_EQ(1, s_sigxfsz);
+
+ leak(fd);
+}
+
+/* With older servers, no FUSE_FALLOCATE should be attempted */
+TEST_F(PosixFallocate_7_18, einval)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ uint64_t offset = 0;
+ uint64_t length = 1000;
+ int fd;
+
+ expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
+ expect_open(ino, 0, 1);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));
+
+ leak(fd);
+}
Index: tests/sys/fs/fusefs/mockfs.hh
===================================================================
--- tests/sys/fs/fusefs/mockfs.hh
+++ tests/sys/fs/fusefs/mockfs.hh
@@ -159,6 +159,7 @@
];
fuse_copy_file_range_in copy_file_range;
fuse_create_in create;
+ fuse_fallocate_in fallocate;
fuse_flush_in flush;
fuse_fsync_in fsync;
fuse_fsync_in fsyncdir;
Index: tests/sys/fs/fusefs/mockfs.cc
===================================================================
--- tests/sys/fs/fusefs/mockfs.cc
+++ tests/sys/fs/fusefs/mockfs.cc
@@ -207,6 +207,14 @@
printf(" flags=%#x name=%s",
in.body.open.flags, name);
break;
+ case FUSE_FALLOCATE:
+ printf(" fh=%#" PRIx64 " offset=%" PRIu64
+ " length=%" PRIx64 " mode=%#x",
+ in.body.fallocate.fh,
+ in.body.fallocate.offset,
+ in.body.fallocate.length,
+ in.body.fallocate.mode);
+ break;
case FUSE_FLUSH:
printf(" fh=%#" PRIx64 " lock_owner=%" PRIu64,
in.body.flush.fh,
@@ -684,6 +692,10 @@
EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt));
EXPECT_EQ((size_t)buflen, inlen);
break;
+ case FUSE_FALLOCATE:
+ EXPECT_EQ(inlen, fih + sizeof(in.body.fallocate));
+ EXPECT_EQ((size_t)buflen, inlen);
+ break;
case FUSE_BMAP:
EXPECT_EQ(inlen, fih + sizeof(in.body.bmap));
EXPECT_EQ((size_t)buflen, inlen);
@@ -699,7 +711,6 @@
break;
case FUSE_NOTIFY_REPLY:
case FUSE_BATCH_FORGET:
- case FUSE_FALLOCATE:
case FUSE_IOCTL:
case FUSE_POLL:
case FUSE_READDIRPLUS:
Index: tests/sys/fs/fusefs/utils.hh
===================================================================
--- tests/sys/fs/fusefs/utils.hh
+++ tests/sys/fs/fusefs/utils.hh
@@ -113,6 +113,14 @@
/* Expect FUSE_DESTROY and shutdown the daemon */
void expect_destroy(int error);
+ /*
+ * Create an expectation that FUSE_FALLOCATE will be called with the
+ * given inode, offset, length, and mode, exactly times times and
+ * returning error
+ */
+ void expect_fallocate(uint64_t ino, uint64_t offset, uint64_t length,
+ uint32_t mode, int error, int times=1);
+
/*
* Create an expectation that FUSE_FLUSH will be called times times for
* the given inode
Index: tests/sys/fs/fusefs/utils.cc
===================================================================
--- tests/sys/fs/fusefs/utils.cc
+++ tests/sys/fs/fusefs/utils.cc
@@ -225,6 +225,23 @@
})));
}
+void
+FuseTest::expect_fallocate(uint64_t ino, uint64_t offset, uint64_t length,
+ uint32_t mode, int error, int times)
+{
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in.header.opcode == FUSE_FALLOCATE &&
+ in.header.nodeid == ino &&
+ in.body.fallocate.offset == offset &&
+ in.body.fallocate.length == length &&
+ in.body.fallocate.mode == mode);
+ }, Eq(true)),
+ _)
+ ).Times(times)
+ .WillRepeatedly(Invoke(ReturnErrno(error)));
+}
+
void
FuseTest::expect_flush(uint64_t ino, int times, ProcessMockerT r)
{
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 12, 5:39 PM (18 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15771702
Default Alt Text
D33389.id99858.diff (18 KB)
Attached To
Mode
D33389: fusefs: implement VOP_ALLOCATE
Attached
Detach File
Event Timeline
Log In to Comment