Skip site navigation (1)Skip section navigation (2)
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>