Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Mar 2019 19:08:48 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r345422 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs
Message-ID:  <201903221908.x2MJ8mmC002095@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Fri Mar 22 19:08:48 2019
New Revision: 345422
URL: https://svnweb.freebsd.org/changeset/base/345422

Log:
  fusefs: support VOP_MKNOD
  
  PR:		236236
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/fuse2/sys/fs/fuse/fuse_vnops.c
  projects/fuse2/tests/sys/fs/fusefs/mknod.cc
  projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
  projects/fuse2/tests/sys/fs/fusefs/open.cc

Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c	Fri Mar 22 18:42:34 2019	(r345421)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c	Fri Mar 22 19:08:48 2019	(r345422)
@@ -1134,10 +1134,21 @@ static int
 fuse_vnop_mknod(struct vop_mknod_args *ap)
 {
 
-	return (EINVAL);
-}
+	struct vnode *dvp = ap->a_dvp;
+	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));
+}
+
 /*
     struct vnop_open_args {
 	struct vnode *a_vp;
@@ -1161,9 +1172,10 @@ fuse_vnop_open(struct vop_open_args *ap)
 	int error, isdir = 0;
 	int32_t fuse_open_flags;
 
-	if (fuse_isdeadfs(vp)) {
+	if (fuse_isdeadfs(vp))
 		return ENXIO;
-	}
+	if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
+		return (EOPNOTSUPP);
 	if ((mode & (FREAD | FWRITE)) == 0)
 		return EINVAL;
 

Modified: projects/fuse2/tests/sys/fs/fusefs/mknod.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/mknod.cc	Fri Mar 22 18:42:34 2019	(r345421)
+++ projects/fuse2/tests/sys/fs/fusefs/mknod.cc	Fri Mar 22 19:08:48 2019	(r345422)
@@ -37,6 +37,13 @@ extern "C" {
 
 using namespace testing;
 
+#ifndef VNOVAL
+#define VNOVAL (-1)	/* Defined in sys/vnode.h */
+#endif
+
+const char FULLPATH[] = "mountpoint/some_file.txt";
+const char RELPATH[] = "some_file.txt";
+
 class Mknod: public FuseTest {
 
 public:
@@ -50,9 +57,7 @@ virtual void SetUp() {
 }
 
 /* Test an OK creation of a file with the given mode and device number */
-void test_ok(mode_t mode, dev_t dev) {
-	const char FULLPATH[] = "mountpoint/some_file.txt";
-	const char RELPATH[] = "some_file.txt";
+void expect_mknod(mode_t mode, dev_t dev) {
 	uint64_t ino = 42;
 
 	EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
@@ -63,19 +68,18 @@ void test_ok(mode_t mode, dev_t dev) {
 				sizeof(fuse_mknod_in);
 			return (in->header.opcode == FUSE_MKNOD &&
 				in->body.mknod.mode == mode &&
-				in->body.mknod.rdev == dev &&
+				in->body.mknod.rdev == (uint32_t)dev &&
 				(0 == strcmp(RELPATH, name)));
 		}, Eq(true)),
 		_)
 	).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;
-		out->body.create.entry.attr.rdev = dev;
+		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;
+		out->body.entry.attr.rdev = dev;
 	})));
-	EXPECT_EQ(0, mknod(FULLPATH, mode, dev)) << strerror(errno);
 }
 
 };
@@ -85,27 +89,28 @@ void test_ok(mode_t mode, dev_t dev) {
  * though FreeBSD doesn't use block devices, this is useful when copying media
  * from or preparing media for other operating systems.
  */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236236 */
-TEST_F(Mknod, DISABLED_blk)
+TEST_F(Mknod, blk)
 {
-	test_ok(S_IFBLK | 0755, 0xfe00); /* /dev/vda's device number on Linux */
+	mode_t mode = S_IFBLK | 0755;
+	dev_t rdev = 0xfe00; /* /dev/vda's device number on Linux */
+	expect_mknod(mode, rdev);
+	EXPECT_EQ(0, mknod(FULLPATH, mode, rdev)) << strerror(errno);
 }
 
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236236 */
-TEST_F(Mknod, DISABLED_chr)
+TEST_F(Mknod, chr)
 {
-	test_ok(S_IFCHR | 0755, 0x64);	/* /dev/fuse's device number */
+	mode_t mode = S_IFCHR | 0755;
+	dev_t rdev = 54;			/* /dev/fuse's device number */
+	expect_mknod(mode, rdev);
+	EXPECT_EQ(0, mknod(FULLPATH, mode, rdev)) << strerror(errno);
 }
 
 /* 
  * The daemon is responsible for checking file permissions (unless the
  * default_permissions mount option was used)
  */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236236 */
-TEST_F(Mknod, DISABLED_eperm)
+TEST_F(Mknod, eperm)
 {
-	const char FULLPATH[] = "mountpoint/some_file.txt";
-	const char RELPATH[] = "some_file.txt";
 	mode_t mode = S_IFIFO | 0755;
 
 	EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
@@ -120,19 +125,26 @@ TEST_F(Mknod, DISABLED_eperm)
 		}, Eq(true)),
 		_)
 	).WillOnce(Invoke(ReturnErrno(EPERM)));
-	EXPECT_NE(0, mknod(FULLPATH, mode, 0));
+	EXPECT_NE(0, mkfifo(FULLPATH, mode));
 	EXPECT_EQ(EPERM, errno);
 }
 
-
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236236 */
-TEST_F(Mknod, DISABLED_fifo)
+TEST_F(Mknod, fifo)
 {
-	test_ok(S_IFIFO | 0755, 0);
+	mode_t mode = S_IFIFO | 0755;
+	dev_t rdev = VNOVAL;		/* Fifos don't have device numbers */
+	expect_mknod(mode, rdev);
+	EXPECT_EQ(0, mkfifo(FULLPATH, mode)) << strerror(errno);
 }
 
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236236 */
+/* 
+ * fusefs(5) lacks VOP_WHITEOUT support.  No bugzilla entry, because that's a
+ * feature, not a bug
+ */
 TEST_F(Mknod, DISABLED_whiteout)
 {
-	test_ok(S_IFWHT | 0755, 0);
+	mode_t mode = S_IFWHT | 0755;
+	dev_t rdev = VNOVAL;	/* whiteouts don't have device numbers */
+	expect_mknod(mode, rdev);
+	EXPECT_EQ(0, mknod(FULLPATH, mode, 0)) << strerror(errno);
 }

Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc	Fri Mar 22 18:42:34 2019	(r345421)
+++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc	Fri Mar 22 19:08:48 2019	(r345422)
@@ -175,6 +175,10 @@ void debug_fuseop(const mockfs_buf_in *in)
 		case FUSE_LOOKUP:
 			printf(" %s", in->body.lookup);
 			break;
+		case FUSE_MKNOD:
+			printf(" mode=%#o rdev=%x", in->body.mknod.mode,
+				in->body.mknod.rdev);
+			break;
 		case FUSE_OPEN:
 			printf(" flags=%#x mode=%#o",
 				in->body.open.flags, in->body.open.mode);

Modified: projects/fuse2/tests/sys/fs/fusefs/open.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/open.cc	Fri Mar 22 18:42:34 2019	(r345421)
+++ projects/fuse2/tests/sys/fs/fusefs/open.cc	Fri Mar 22 19:08:48 2019	(r345422)
@@ -82,6 +82,30 @@ void test_ok(int os_flags, int fuse_flags) {
 
 
 /* 
+ * fusefs(5) does not support I/O on device nodes (neither does UFS).  But it
+ * shouldn't crash
+ */
+TEST_F(Open, chr)
+{
+	const char FULLPATH[] = "mountpoint/zero";
+	const char RELPATH[] = "zero";
+	uint64_t ino = 42;
+
+	EXPECT_LOOKUP(1, RELPATH)
+	.WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+		SET_OUT_HEADER_LEN(out, entry);
+		out->body.entry.attr.mode = S_IFCHR | 0644;
+		out->body.entry.nodeid = ino;
+		out->body.entry.attr.nlink = 1;
+		out->body.entry.attr_valid = UINT64_MAX;
+		out->body.entry.attr.rdev = 44;	/* /dev/zero's rdev */
+	})));
+
+	ASSERT_EQ(-1, open(FULLPATH, O_RDONLY));
+	EXPECT_EQ(EOPNOTSUPP, errno);
+}
+
+/* 
  * The fuse daemon fails the request with enoent.  This usually indicates a
  * race condition: some other FUSE client removed the file in between when the
  * kernel checked for it with lookup and tried to open it
@@ -124,6 +148,26 @@ TEST_F(Open, eperm)
 	).WillOnce(Invoke(ReturnErrno(EPERM)));
 	EXPECT_NE(0, open(FULLPATH, O_RDONLY));
 	EXPECT_EQ(EPERM, errno);
+}
+
+/* fusefs(5) does not yet support I/O on fifos.  But it shouldn't crash. */
+TEST_F(Open, fifo)
+{
+	const char FULLPATH[] = "mountpoint/zero";
+	const char RELPATH[] = "zero";
+	uint64_t ino = 42;
+
+	EXPECT_LOOKUP(1, RELPATH)
+	.WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+		SET_OUT_HEADER_LEN(out, entry);
+		out->body.entry.attr.mode = S_IFIFO | 0644;
+		out->body.entry.nodeid = ino;
+		out->body.entry.attr.nlink = 1;
+		out->body.entry.attr_valid = UINT64_MAX;
+	})));
+
+	ASSERT_EQ(-1, open(FULLPATH, O_RDONLY));
+	EXPECT_EQ(EOPNOTSUPP, errno);
 }
 
 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236340 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903221908.x2MJ8mmC002095>