From owner-svn-src-projects@freebsd.org Sat Mar 23 00:22:31 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 167421555C70 for ; Sat, 23 Mar 2019 00:22:31 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id AE58F6B2C7; Sat, 23 Mar 2019 00:22:30 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8A10959; Sat, 23 Mar 2019 00:22:30 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x2N0MU0k070204; Sat, 23 Mar 2019 00:22:30 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x2N0MUQV070202; Sat, 23 Mar 2019 00:22:30 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201903230022.x2N0MUQV070202@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Sat, 23 Mar 2019 00:22:30 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r345429 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 345429 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: AE58F6B2C7 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.97 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.97)[-0.968,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 23 Mar 2019 00:22:31 -0000 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",