fusefs: create sockets with FUSE_MKNOD, not FUSE_CREATE
libfuse expects sockets to be created with FUSE_MKNOD, not FUSE_CREATE, because that's how Linux does it. My first attempt at creating sockets (r346894) used FUSE_CREATE because FreeBSD uses VOP_CREATE for this purpose. There are no backwards-compatibility concerns with this change, because socket support hasn't yet been merged to head. Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
002e54b0aa
commit
d5ff268834
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=347395
@ -312,6 +312,19 @@ fuse_internal_fsync(struct vnode *vp,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mknod */
|
||||||
|
int
|
||||||
|
fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp,
|
||||||
|
struct componentname *cnp, struct vattr *vap)
|
||||||
|
{
|
||||||
|
struct fuse_mknod_in fmni;
|
||||||
|
|
||||||
|
fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode);
|
||||||
|
fmni.rdev = vap->va_rdev;
|
||||||
|
return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni,
|
||||||
|
sizeof(fmni), vap->va_type));
|
||||||
|
}
|
||||||
|
|
||||||
/* readdir */
|
/* readdir */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -228,6 +228,11 @@ struct pseudo_dirent {
|
|||||||
uint32_t d_namlen;
|
uint32_t d_namlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* mknod */
|
||||||
|
int fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp,
|
||||||
|
struct componentname *cnp, struct vattr *vap);
|
||||||
|
|
||||||
|
/* readdir */
|
||||||
int fuse_internal_readdir(struct vnode *vp, struct uio *uio,
|
int fuse_internal_readdir(struct vnode *vp, struct uio *uio,
|
||||||
struct fuse_filehandle *fufh, struct fuse_iov *cookediov);
|
struct fuse_filehandle *fufh, struct fuse_iov *cookediov);
|
||||||
int fuse_internal_readdir_processdata(struct uio *uio, size_t reqsize,
|
int fuse_internal_readdir_processdata(struct uio *uio, size_t reqsize,
|
||||||
|
@ -537,6 +537,13 @@ fuse_vnop_create(struct vop_create_args *ap)
|
|||||||
enum fuse_opcode op;
|
enum fuse_opcode op;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
if (fuse_isdeadfs(dvp))
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
/* FUSE expects sockets to be created with FUSE_MKNOD */
|
||||||
|
if (vap->va_type == VSOCK)
|
||||||
|
return fuse_internal_mknod(dvp, vpp, cnp, vap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VOP_CREATE doesn't tell us the open(2) flags, so we guess. Only a
|
* VOP_CREATE doesn't tell us the open(2) flags, so we guess. Only a
|
||||||
* writable mode makes sense, and we might as well include readability
|
* writable mode makes sense, and we might as well include readability
|
||||||
@ -544,15 +551,12 @@ fuse_vnop_create(struct vop_create_args *ap)
|
|||||||
*/
|
*/
|
||||||
flags = O_RDWR;
|
flags = O_RDWR;
|
||||||
|
|
||||||
if (fuse_isdeadfs(dvp)) {
|
|
||||||
return ENXIO;
|
|
||||||
}
|
|
||||||
bzero(&fdi, sizeof(fdi));
|
bzero(&fdi, sizeof(fdi));
|
||||||
|
|
||||||
if ((vap->va_type != VREG && vap->va_type != VSOCK))
|
if (vap->va_type != VREG)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
|
||||||
if (!fsess_isimpl(mp, FUSE_CREATE)) {
|
if (!fsess_isimpl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
|
||||||
/* Fallback to FUSE_MKNOD/FUSE_OPEN */
|
/* Fallback to FUSE_MKNOD/FUSE_OPEN */
|
||||||
fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
|
fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
|
||||||
cred, mode, &op);
|
cred, mode, &op);
|
||||||
@ -1163,15 +1167,11 @@ fuse_vnop_mknod(struct vop_mknod_args *ap)
|
|||||||
struct vnode **vpp = ap->a_vpp;
|
struct vnode **vpp = ap->a_vpp;
|
||||||
struct componentname *cnp = ap->a_cnp;
|
struct componentname *cnp = ap->a_cnp;
|
||||||
struct vattr *vap = ap->a_vap;
|
struct vattr *vap = ap->a_vap;
|
||||||
struct fuse_mknod_in fmni;
|
|
||||||
|
|
||||||
if (fuse_isdeadfs(dvp))
|
if (fuse_isdeadfs(dvp))
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
|
|
||||||
fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode);
|
return fuse_internal_mknod(dvp, vpp, cnp, vap);
|
||||||
fmni.rdev = vap->va_rdev;
|
|
||||||
return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni,
|
|
||||||
sizeof(fmni), vap->va_type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "mockfs.hh"
|
#include "mockfs.hh"
|
||||||
@ -310,34 +308,6 @@ TEST_F(Create, ok)
|
|||||||
/* Deliberately leak fd. close(2) will be tested in release.cc */
|
/* Deliberately leak fd. close(2) will be tested in release.cc */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a unix-domain socket */
|
|
||||||
TEST_F(Create, socket)
|
|
||||||
{
|
|
||||||
const char FULLPATH[] = "mountpoint/some_sock";
|
|
||||||
const char RELPATH[] = "some_sock";
|
|
||||||
mode_t mode = S_IFSOCK | 0755;
|
|
||||||
struct sockaddr_un sa;
|
|
||||||
uint64_t ino = 42;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
|
|
||||||
expect_create(RELPATH, mode,
|
|
||||||
ReturnImmediate([=](auto in __unused, auto out) {
|
|
||||||
SET_OUT_HEADER_LEN(out, create);
|
|
||||||
out->body.create.entry.attr.mode = mode;
|
|
||||||
out->body.create.entry.nodeid = ino;
|
|
||||||
out->body.create.entry.entry_valid = UINT64_MAX;
|
|
||||||
out->body.create.entry.attr_valid = UINT64_MAX;
|
|
||||||
}));
|
|
||||||
|
|
||||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
ASSERT_LE(0, fd) << strerror(errno);
|
|
||||||
sa.sun_family = AF_UNIX;
|
|
||||||
strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
|
|
||||||
ASSERT_EQ(0, bind(fd, (struct sockaddr*)&sa, sizeof(sa)))
|
|
||||||
<< strerror(errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A regression test for a bug that affected old FUSE implementations:
|
* A regression test for a bug that affected old FUSE implementations:
|
||||||
* open(..., O_WRONLY | O_CREAT, 0444) should work despite the seeming
|
* open(..., O_WRONLY | O_CREAT, 0444) should work despite the seeming
|
||||||
|
@ -159,17 +159,18 @@ TEST_F(Socket, read_write)
|
|||||||
EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
|
EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
|
||||||
EXPECT_CALL(*m_mock, process(
|
EXPECT_CALL(*m_mock, process(
|
||||||
ResultOf([=](auto in) {
|
ResultOf([=](auto in) {
|
||||||
return (in->header.opcode == FUSE_CREATE);
|
return (in->header.opcode == FUSE_MKNOD);
|
||||||
}, Eq(true)),
|
}, Eq(true)),
|
||||||
_)
|
_)
|
||||||
).InSequence(seq)
|
).InSequence(seq)
|
||||||
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
|
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
|
||||||
SET_OUT_HEADER_LEN(out, create);
|
SET_OUT_HEADER_LEN(out, entry);
|
||||||
out->body.create.entry.attr.mode = mode;
|
out->body.entry.attr.mode = mode;
|
||||||
out->body.create.entry.nodeid = ino;
|
out->body.entry.nodeid = ino;
|
||||||
out->body.create.entry.entry_valid = UINT64_MAX;
|
out->body.entry.entry_valid = UINT64_MAX;
|
||||||
out->body.create.entry.attr_valid = UINT64_MAX;
|
out->body.entry.attr_valid = UINT64_MAX;
|
||||||
})));
|
})));
|
||||||
|
|
||||||
EXPECT_LOOKUP(1, RELPATH)
|
EXPECT_LOOKUP(1, RELPATH)
|
||||||
.InSequence(seq)
|
.InSequence(seq)
|
||||||
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
|
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "mockfs.hh"
|
#include "mockfs.hh"
|
||||||
@ -137,6 +139,28 @@ TEST_F(Mknod, fifo)
|
|||||||
EXPECT_EQ(0, mkfifo(FULLPATH, mode)) << strerror(errno);
|
EXPECT_EQ(0, mkfifo(FULLPATH, mode)) << strerror(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a unix-domain socket.
|
||||||
|
*
|
||||||
|
* This test case doesn't actually need root privileges.
|
||||||
|
*/
|
||||||
|
TEST_F(Mknod, socket)
|
||||||
|
{
|
||||||
|
mode_t mode = S_IFSOCK | 0755;
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int fd;
|
||||||
|
dev_t rdev = -1; /* Really it's a don't care */
|
||||||
|
|
||||||
|
expect_mknod(mode, rdev);
|
||||||
|
|
||||||
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
ASSERT_LE(0, fd) << strerror(errno);
|
||||||
|
sa.sun_family = AF_UNIX;
|
||||||
|
strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
|
||||||
|
ASSERT_EQ(0, bind(fd, (struct sockaddr*)&sa, sizeof(sa)))
|
||||||
|
<< strerror(errno);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fusefs(5) lacks VOP_WHITEOUT support. No bugzilla entry, because that's a
|
* fusefs(5) lacks VOP_WHITEOUT support. No bugzilla entry, because that's a
|
||||||
* feature, not a bug
|
* feature, not a bug
|
||||||
|
Loading…
Reference in New Issue
Block a user