svn commit: r345768 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs
Alan Somers
asomers at FreeBSD.org
Tue Sep 3 14:06:06 UTC 2019
Author: asomers
Date: Mon Apr 1 16:36:02 2019
New Revision: 345768
URL: https://svnweb.freebsd.org/changeset/base/345768
Log:
fusefs: allow opening files O_EXEC
O_EXEC is useful for fexecve(2) and fchdir(2). Treat it as another fufh
type alongside the existing RDONLY, WRONLY, and RDWR. Prior to r345742 this
would've caused a memory and performance penalty.
PR: 236329
Sponsored by: The FreeBSD Foundation
Modified:
projects/fuse2/sys/fs/fuse/fuse_file.c
projects/fuse2/sys/fs/fuse/fuse_file.h
projects/fuse2/sys/fs/fuse/fuse_vnops.c
projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
projects/fuse2/tests/sys/fs/fusefs/open.cc
projects/fuse2/tests/sys/fs/fusefs/opendir.cc
projects/fuse2/tests/sys/fs/fusefs/readdir.cc
projects/fuse2/tests/sys/fs/fusefs/releasedir.cc
projects/fuse2/tests/sys/fs/fusefs/utils.cc
Modified: projects/fuse2/sys/fs/fuse/fuse_file.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.c Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/sys/fs/fuse/fuse_file.c Mon Apr 1 16:36:02 2019 (r345768)
@@ -121,12 +121,8 @@ fuse_filehandle_open(struct vnode *vp, fufh_type_t fuf
if (vnode_isdir(vp)) {
op = FUSE_OPENDIR;
- if (fufh_type != FUFH_RDONLY) {
- SDT_PROBE2(fuse, , file, trace, 1,
- "non-rdonly fh requested for a directory?");
- printf("FUSE:non-rdonly fh requested for a directory?\n");
- fufh_type = FUFH_RDONLY;
- }
+ /* vn_open_vnode already rejects FWRITE on directories */
+ MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC);
}
fdisp_init(&fdi, sizeof(*foi));
fdisp_make_vp(&fdi, op, vp, td, cred);
Modified: projects/fuse2/sys/fs/fuse/fuse_file.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.h Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/sys/fs/fuse/fuse_file.h Mon Apr 1 16:36:02 2019 (r345768)
@@ -72,14 +72,11 @@
*/
typedef enum fufh_type {
FUFH_INVALID = -1,
- FUFH_RDONLY = 0,
- FUFH_WRONLY = 1,
- FUFH_RDWR = 2,
- /* TODO: add FUFH_EXEC */
+ FUFH_RDONLY = O_RDONLY,
+ FUFH_WRONLY = O_WRONLY,
+ FUFH_RDWR = O_RDWR,
+ FUFH_EXEC = O_EXEC,
} fufh_type_t;
-_Static_assert(FUFH_RDONLY == O_RDONLY, "RDONLY");
-_Static_assert(FUFH_WRONLY == O_WRONLY, "WRONLY");
-_Static_assert(FUFH_RDWR == O_RDWR, "RDWR");
struct fuse_filehandle {
LIST_ENTRY(fuse_filehandle) next;
@@ -110,6 +107,8 @@ fuse_filehandle_xlate_from_fflags(int fflags)
return FUFH_WRONLY;
else if (fflags & (FREAD))
return FUFH_RDONLY;
+ else if (fflags & (FEXEC))
+ return FUFH_EXEC;
else
panic("FUSE: What kind of a flag is this (%x)?", fflags);
}
@@ -123,6 +122,7 @@ fuse_filehandle_xlate_to_oflags(fufh_type_t type)
case FUFH_RDONLY:
case FUFH_WRONLY:
case FUFH_RDWR:
+ case FUFH_EXEC:
oflags = type;
break;
default:
Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Mon Apr 1 16:36:02 2019 (r345768)
@@ -285,7 +285,8 @@ fuse_vnop_close(struct vop_close_args *ap)
if (vnode_isdir(vp)) {
struct fuse_filehandle *fufh;
- if (fuse_filehandle_get(vp, O_RDONLY, &fufh) == 0)
+ if ((fuse_filehandle_get(vp, O_RDONLY, &fufh) == 0) ||
+ (fuse_filehandle_get(vp, O_EXEC, &fufh) == 0))
fuse_filehandle_close(vp, fufh, NULL, cred);
return 0;
}
@@ -1201,16 +1202,12 @@ fuse_vnop_open(struct vop_open_args *ap)
return ENXIO;
if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
return (EOPNOTSUPP);
- if ((mode & (FREAD | FWRITE)) == 0)
+ if ((mode & (FREAD | FWRITE | FEXEC)) == 0)
return EINVAL;
fvdat = VTOFUD(vp);
- if (vnode_isdir(vp)) {
- fufh_type = FUFH_RDONLY;
- } else {
- fufh_type = fuse_filehandle_xlate_from_fflags(mode);
- }
+ fufh_type = fuse_filehandle_xlate_from_fflags(mode);
if (fuse_filehandle_validrw(vp, fufh_type) != FUFH_INVALID) {
fuse_vnode_open(vp, 0, td);
@@ -1303,7 +1300,7 @@ fuse_vnop_readdir(struct vop_readdir_args *ap)
return EINVAL;
}
- if ((err = fuse_filehandle_get(vp, O_RDONLY, &fufh)) != 0) {
+ if ((err = fuse_filehandle_get(vp, FUFH_RDONLY, &fufh)) != 0) {
SDT_PROBE2(fuse, , vnops, trace, 1,
"calling readdir() before open()");
err = fuse_filehandle_open(vp, O_RDONLY, &fufh, NULL, cred);
Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Mon Apr 1 16:36:02 2019 (r345768)
@@ -200,7 +200,8 @@ void debug_fuseop(const mockfs_buf_in *in)
in->body.read.size);
break;
case FUSE_READDIR:
- printf(" offset=%lu size=%u", in->body.readdir.offset,
+ printf(" fh=%#lx offset=%lu size=%u",
+ in->body.readdir.fh, in->body.readdir.offset,
in->body.readdir.size);
break;
case FUSE_RELEASE:
Modified: projects/fuse2/tests/sys/fs/fusefs/open.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/open.cc Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/tests/sys/fs/fusefs/open.cc Mon Apr 1 16:36:02 2019 (r345768)
@@ -250,8 +250,7 @@ TEST_F(Open, o_excl)
test_ok(O_WRONLY | O_EXCL, O_WRONLY);
}
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236329 */
-TEST_F(Open, DISABLED_o_exec)
+TEST_F(Open, o_exec)
{
test_ok(O_EXEC, O_EXEC);
}
Modified: projects/fuse2/tests/sys/fs/fusefs/opendir.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/opendir.cc Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/tests/sys/fs/fusefs/opendir.cc Mon Apr 1 16:36:02 2019 (r345768)
@@ -44,6 +44,29 @@ void expect_lookup(const char *relpath, uint64_t ino)
{
FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 0, 1);
}
+
+void expect_opendir(uint64_t ino, uint32_t flags, ProcessMockerT r)
+{
+ /* opendir(3) calls fstatfs */
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([](auto in) {
+ return (in->header.opcode == FUSE_STATFS);
+ }, Eq(true)),
+ _)
+ ).WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, statfs);
+ })));
+
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in->header.opcode == FUSE_OPENDIR &&
+ in->header.nodeid == ino &&
+ in->body.opendir.flags == flags);
+ }, Eq(true)),
+ _)
+ ).WillOnce(Invoke(r));
+}
+
};
@@ -59,14 +82,8 @@ TEST_F(Opendir, enoent)
uint64_t ino = 42;
expect_lookup(RELPATH, ino);
+ expect_opendir(ino, O_RDONLY, ReturnErrno(ENOENT));
- EXPECT_CALL(*m_mock, process(
- ResultOf([=](auto in) {
- return (in->header.opcode == FUSE_OPENDIR &&
- in->header.nodeid == ino);
- }, Eq(true)),
- _)
- ).WillOnce(Invoke(ReturnErrno(ENOENT)));
EXPECT_NE(0, open(FULLPATH, O_DIRECTORY));
EXPECT_EQ(ENOENT, errno);
}
@@ -82,15 +99,8 @@ TEST_F(Opendir, eperm)
uint64_t ino = 42;
expect_lookup(RELPATH, ino);
+ expect_opendir(ino, O_RDONLY, ReturnErrno(EPERM));
- EXPECT_CALL(*m_mock, process(
- ResultOf([=](auto in) {
- return (in->header.opcode == FUSE_OPENDIR &&
- in->header.nodeid == ino);
- }, Eq(true)),
- _)
- ).WillOnce(Invoke(ReturnErrno(EPERM)));
-
EXPECT_NE(0, open(FULLPATH, O_DIRECTORY));
EXPECT_EQ(EPERM, errno);
}
@@ -102,45 +112,43 @@ TEST_F(Opendir, open)
uint64_t ino = 42;
expect_lookup(RELPATH, ino);
-
- EXPECT_CALL(*m_mock, process(
- ResultOf([=](auto in) {
- return (in->header.opcode == FUSE_OPENDIR &&
- in->header.nodeid == ino);
- }, Eq(true)),
- _)
- ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+ expect_opendir(ino, O_RDONLY,
+ ReturnImmediate([=](auto in __unused, auto out) {
SET_OUT_HEADER_LEN(out, open);
- })));
+ }));
EXPECT_LE(0, open(FULLPATH, O_DIRECTORY)) << strerror(errno);
}
-TEST_F(Opendir, opendir)
+/* Directories can be opened O_EXEC for stuff like fchdir(2) */
+TEST_F(Opendir, open_exec)
{
const char FULLPATH[] = "mountpoint/some_dir";
const char RELPATH[] = "some_dir";
uint64_t ino = 42;
+ int fd;
expect_lookup(RELPATH, ino);
- EXPECT_CALL(*m_mock, process(
- ResultOf([](auto in) {
- return (in->header.opcode == FUSE_STATFS);
- }, Eq(true)),
- _)
- ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
- SET_OUT_HEADER_LEN(out, statfs);
- })));
+ expect_opendir(ino, O_EXEC,
+ ReturnImmediate([=](auto in __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, open);
+ }));
- EXPECT_CALL(*m_mock, process(
- ResultOf([=](auto in) {
- return (in->header.opcode == FUSE_OPENDIR &&
- in->header.nodeid == ino);
- }, Eq(true)),
- _)
- ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+ fd = open(FULLPATH, O_EXEC | O_DIRECTORY);
+ ASSERT_LE(0, fd) << strerror(errno);
+}
+
+TEST_F(Opendir, opendir)
+{
+ const char FULLPATH[] = "mountpoint/some_dir";
+ const char RELPATH[] = "some_dir";
+ uint64_t ino = 42;
+
+ expect_lookup(RELPATH, ino);
+ expect_opendir(ino, O_RDONLY,
+ ReturnImmediate([=](auto in __unused, auto out) {
SET_OUT_HEADER_LEN(out, open);
- })));
+ }));
errno = 0;
EXPECT_NE(NULL, opendir(FULLPATH)) << strerror(errno);
Modified: projects/fuse2/tests/sys/fs/fusefs/readdir.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/readdir.cc Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/tests/sys/fs/fusefs/readdir.cc Mon Apr 1 16:36:02 2019 (r345768)
@@ -52,6 +52,7 @@ void expect_readdir(uint64_t ino, uint64_t off, vector
ResultOf([=](auto in) {
return (in->header.opcode == FUSE_READDIR &&
in->header.nodeid == ino &&
+ in->body.readdir.fh == FH &&
in->body.readdir.offset == off);
}, Eq(true)),
_)
Modified: projects/fuse2/tests/sys/fs/fusefs/releasedir.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/releasedir.cc Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/tests/sys/fs/fusefs/releasedir.cc Mon Apr 1 16:36:02 2019 (r345768)
@@ -30,6 +30,7 @@
extern "C" {
#include <dirent.h>
+#include <fcntl.h>
}
#include "mockfs.hh"
@@ -106,4 +107,22 @@ TEST_F(ReleaseDir, ok)
ASSERT_NE(NULL, dir) << strerror(errno);
ASSERT_EQ(0, closedir(dir)) << strerror(errno);
+}
+
+/* Directories opened O_EXEC should be properly released, too */
+TEST_F(ReleaseDir, o_exec)
+{
+ const char FULLPATH[] = "mountpoint/some_dir";
+ const char RELPATH[] = "some_dir";
+ uint64_t ino = 42;
+ int fd;
+
+ expect_lookup(RELPATH, ino);
+ expect_opendir(ino);
+ expect_releasedir(ino, ReturnErrno(0));
+
+ fd = open(FULLPATH, O_EXEC | O_DIRECTORY);
+ EXPECT_LE(0, fd) << strerror(errno);
+
+ ASSERT_EQ(0, close(fd)) << strerror(errno);
}
Modified: projects/fuse2/tests/sys/fs/fusefs/utils.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/utils.cc Mon Apr 1 16:15:29 2019 (r345767)
+++ projects/fuse2/tests/sys/fs/fusefs/utils.cc Mon Apr 1 16:36:02 2019 (r345768)
@@ -166,6 +166,7 @@ void FuseTest::expect_open(uint64_t ino, uint32_t flag
void FuseTest::expect_opendir(uint64_t ino)
{
+ /* opendir(3) calls fstatfs */
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in->header.opcode == FUSE_STATFS);
More information about the svn-src-projects
mailing list