Date: Sat, 23 Mar 2019 00:22:30 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r345429 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs Message-ID: <201903230022.x2N0MUQV070202@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Sat Mar 23 00:22:29 2019 New Revision: 345429 URL: https://svnweb.freebsd.org/changeset/base/345429 Log: fusefs: fallback to MKNOD/OPEN if a filesystem doesn't support CREATE If a FUSE filesystem returns ENOSYS for FUSE_CREATE, then fallback to FUSE_MKNOD/FUSE_OPEN. Also, fix a memory leak in the error path of fuse_vnop_create. And do a little cleanup in fuse_vnop_open. PR: 199934 Reported by: samm@os2.kiev.ua Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c projects/fuse2/tests/sys/fs/fusefs/create.cc projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_vnops.c Fri Mar 22 23:55:35 2019 (r345428) +++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Sat Mar 23 00:22:29 2019 (r345429) @@ -309,6 +309,29 @@ fuse_vnop_close(struct vop_close_args *ap) return 0; } +static void +fdisp_make_mknod_for_fallback( + struct fuse_dispatcher *fdip, + struct componentname *cnp, + struct vnode *dvp, + uint64_t parentnid, + struct thread *td, + struct ucred *cred, + mode_t mode, + enum fuse_opcode *op) +{ + struct fuse_mknod_in *fmni; + + fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1); + *op = FUSE_MKNOD; + fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred); + fmni = fdip->indata; + fmni->mode = mode; + fmni->rdev = 0; + memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr, + cnp->cn_namelen); + ((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0'; +} /* struct vnop_create_args { struct vnode *a_dvp; @@ -329,51 +352,54 @@ fuse_vnop_create(struct vop_create_args *ap) struct fuse_open_in *foi; struct fuse_entry_out *feo; - struct fuse_dispatcher fdi; + struct fuse_open_out *foo; + struct fuse_dispatcher fdi, fdi2; struct fuse_dispatcher *fdip = &fdi; + struct fuse_dispatcher *fdip2 = NULL; int err; struct mount *mp = vnode_mount(dvp); uint64_t parentnid = VTOFUD(dvp)->nid; mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode); - uint64_t x_fh_id; - uint32_t x_open_flags; + enum fuse_opcode op; if (fuse_isdeadfs(dvp)) { return ENXIO; } bzero(&fdi, sizeof(fdi)); - /* XXX: Will we ever want devices ? */ - if ((vap->va_type != VREG)) { - printf("fuse_vnop_create: unsupported va_type %d\n", - vap->va_type); + if ((vap->va_type != VREG)) return (EINVAL); - } - fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1); if (!fsess_isimpl(mp, FUSE_CREATE)) { - SDT_PROBE2(fuse, , vnops, trace, 1, - "eh, daemon doesn't implement create?"); - return (EINVAL); + /* Fallback to FUSE_MKNOD/FUSE_OPEN */ + fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td, + cred, mode, &op); + } else { + /* Use FUSE_CREATE */ + op = FUSE_CREATE; + fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1); + fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred); + foi = fdip->indata; + foi->mode = mode; + foi->flags = O_CREAT | O_RDWR; + memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr, + cnp->cn_namelen); + ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0'; } - fdisp_make(fdip, FUSE_CREATE, vnode_mount(dvp), parentnid, td, cred); - foi = fdip->indata; - foi->mode = mode; - foi->flags = O_CREAT | O_RDWR; - - memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr, - cnp->cn_namelen); - ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0'; - err = fdisp_wait_answ(fdip); if (err) { - if (err == ENOSYS) + if (err == ENOSYS && op == FUSE_CREATE) { fsess_set_notimpl(mp, FUSE_CREATE); - goto out; + fdisp_make_mknod_for_fallback(fdip, cnp, dvp, + parentnid, td, cred, mode, &op); + err = fdisp_wait_answ(fdip); + } + if (err) + goto out; } feo = fdip->answ; @@ -381,11 +407,28 @@ fuse_vnop_create(struct vop_create_args *ap) if ((err = fuse_internal_checkentry(feo, VREG))) { goto out; } + + if (op == FUSE_CREATE) { + foo = (struct fuse_open_out*)(feo + 1); + } else { + /* Issue a separate FUSE_OPEN */ + fdip2 = &fdi2; + fdisp_init(fdip2, sizeof(*foi)); + fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td, + cred); + foi = fdip2->indata; + foi->mode = mode; + foi->flags = O_RDWR; + err = fdisp_wait_answ(fdip2); + if (err) + goto out; + foo = fdip2->answ; + } err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, VREG); if (err) { struct fuse_release_in *fri; uint64_t nodeid = feo->nodeid; - uint64_t fh_id = ((struct fuse_open_out *)(feo + 1))->fh; + uint64_t fh_id = foo->fh; fdisp_init(fdip, sizeof(*fri)); fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred); @@ -394,19 +437,17 @@ fuse_vnop_create(struct vop_create_args *ap) fri->flags = OFLAGS(mode); fuse_insert_callback(fdip->tick, fuse_internal_forget_callback); fuse_insert_message(fdip->tick); - return err; + goto out; } ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create"); - fdip->answ = feo + 1; - - x_fh_id = ((struct fuse_open_out *)(feo + 1))->fh; - x_open_flags = ((struct fuse_open_out *)(feo + 1))->open_flags; - fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, x_fh_id); - fuse_vnode_open(*vpp, x_open_flags, td); + fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, foo->fh); + fuse_vnode_open(*vpp, foo->open_flags, td); cache_purge_negative(dvp); out: + if (fdip2) + fdisp_destroy(fdip2); fdisp_destroy(fdip); return err; } @@ -1165,13 +1206,11 @@ fuse_vnop_open(struct vop_open_args *ap) int mode = ap->a_mode; struct thread *td = ap->a_td; struct ucred *cred = ap->a_cred; + int32_t fuse_open_flags = 0; fufh_type_t fufh_type; struct fuse_vnode_data *fvdat; - int error, isdir = 0; - int32_t fuse_open_flags; - if (fuse_isdeadfs(vp)) return ENXIO; if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO) @@ -1182,31 +1221,25 @@ fuse_vnop_open(struct vop_open_args *ap) fvdat = VTOFUD(vp); if (vnode_isdir(vp)) { - isdir = 1; - } - fuse_open_flags = 0; - if (isdir) { fufh_type = FUFH_RDONLY; } else { fufh_type = fuse_filehandle_xlate_from_fflags(mode); - /* - * For WRONLY opens, force DIRECT_IO. This is necessary - * since writing a partial block through the buffer cache - * will result in a read of the block and that read won't - * be allowed by the WRONLY open. - */ - if (fufh_type == FUFH_WRONLY || - (fvdat->flag & FN_DIRECTIO) != 0) - fuse_open_flags = FOPEN_DIRECT_IO; } + /* + * For WRONLY opens, force DIRECT_IO. This is necessary since writing + * a partial block through the buffer cache will result in a read of + * the block and that read won't be allowed by the WRONLY open. + */ + if (fufh_type == FUFH_WRONLY || (fvdat->flag & FN_DIRECTIO) != 0) + fuse_open_flags = FOPEN_DIRECT_IO; + if (fuse_filehandle_validrw(vp, fufh_type) != FUFH_INVALID) { fuse_vnode_open(vp, fuse_open_flags, td); return 0; } - error = fuse_filehandle_open(vp, fufh_type, NULL, td, cred); - return error; + return fuse_filehandle_open(vp, fufh_type, NULL, td, cred); } static int Modified: projects/fuse2/tests/sys/fs/fusefs/create.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/create.cc Fri Mar 22 23:55:35 2019 (r345428) +++ projects/fuse2/tests/sys/fs/fusefs/create.cc Sat Mar 23 00:22:29 2019 (r345429) @@ -113,9 +113,7 @@ TEST_F(Create, eexist) * If the daemon doesn't implement FUSE_CREATE, then the kernel should fallback * to FUSE_MKNOD/FUSE_OPEN */ -/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236236 */ -/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236557 */ -TEST_F(Create, DISABLED_Enosys) +TEST_F(Create, Enosys) { const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; @@ -146,11 +144,11 @@ TEST_F(Create, DISABLED_Enosys) }, Eq(true)), _) ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) { - SET_OUT_HEADER_LEN(out, create); - out->body.create.entry.attr.mode = S_IFREG | 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 = S_IFREG | mode; + out->body.entry.nodeid = ino; + out->body.entry.entry_valid = UINT64_MAX; + out->body.entry.attr_valid = UINT64_MAX; }))); EXPECT_CALL(*m_mock, process( Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Fri Mar 22 23:55:35 2019 (r345428) +++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Sat Mar 23 00:22:29 2019 (r345429) @@ -160,6 +160,14 @@ void debug_fuseop(const mockfs_buf_in *in) in->header.unique, in->header.len); } switch (in->header.opcode) { + const char *name, *value; + + case FUSE_CREATE: + name = (const char*)in->body.bytes + + sizeof(fuse_open_in); + printf(" flags=%#x name=%s", + in->body.open.flags, name); + break; case FUSE_FLUSH: printf(" lock_owner=%lu", in->body.flush.lock_owner); break; @@ -229,12 +237,10 @@ void debug_fuseop(const mockfs_buf_in *in) * In theory neither the xattr name and value need be * ASCII, but in this test suite they always are. */ - { - const char *attr = (const char*)in->body.bytes + - sizeof(fuse_setxattr_in); - const char *v = attr + strlen(attr) + 1; - printf(" %s=%s", attr, v); - } + name = (const char*)in->body.bytes + + sizeof(fuse_setxattr_in); + value = name + strlen(name) + 1; + printf(" %s=%s", name, value); break; case FUSE_WRITE: printf(" offset=%lu size=%u flags=%u",
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903230022.x2N0MUQV070202>