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
68aaa0cd09
commit
35b5ad0087
@ -312,6 +312,19 @@ fuse_internal_fsync(struct vnode *vp,
|
||||
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 */
|
||||
|
||||
int
|
||||
|
@ -228,6 +228,11 @@ struct pseudo_dirent {
|
||||
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,
|
||||
struct fuse_filehandle *fufh, struct fuse_iov *cookediov);
|
||||
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;
|
||||
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
|
||||
* 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;
|
||||
|
||||
if (fuse_isdeadfs(dvp)) {
|
||||
return ENXIO;
|
||||
}
|
||||
bzero(&fdi, sizeof(fdi));
|
||||
|
||||
if ((vap->va_type != VREG && vap->va_type != VSOCK))
|
||||
if (vap->va_type != VREG)
|
||||
return (EINVAL);
|
||||
|
||||
if (!fsess_isimpl(mp, FUSE_CREATE)) {
|
||||
if (!fsess_isimpl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
|
||||
/* Fallback to FUSE_MKNOD/FUSE_OPEN */
|
||||
fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
|
||||
cred, mode, &op);
|
||||
@ -1163,15 +1167,11 @@ fuse_vnop_mknod(struct vop_mknod_args *ap)
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct fuse_mknod_in fmni;
|
||||
|
||||
if (fuse_isdeadfs(dvp))
|
||||
return ENXIO;
|
||||
|
||||
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));
|
||||
return fuse_internal_mknod(dvp, vpp, cnp, vap);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -30,8 +30,6 @@
|
||||
|
||||
extern "C" {
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
}
|
||||
|
||||
#include "mockfs.hh"
|
||||
@ -310,34 +308,6 @@ TEST_F(Create, ok)
|
||||
/* 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:
|
||||
* 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_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_CREATE);
|
||||
return (in->header.opcode == FUSE_MKNOD);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).InSequence(seq)
|
||||
.WillOnce(Invoke(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;
|
||||
SET_OUT_HEADER_LEN(out, entry);
|
||||
out->body.entry.attr.mode = mode;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.entry_valid = UINT64_MAX;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
})));
|
||||
|
||||
EXPECT_LOOKUP(1, RELPATH)
|
||||
.InSequence(seq)
|
||||
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
extern "C" {
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
}
|
||||
|
||||
#include "mockfs.hh"
|
||||
@ -137,6 +139,28 @@ TEST_F(Mknod, fifo)
|
||||
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
|
||||
* feature, not a bug
|
||||
|
Loading…
x
Reference in New Issue
Block a user