summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Zezeski <rpz@joyent.com>2016-10-11 20:49:51 -0400
committerRyan Zezeski <rpz@joyent.com>2016-10-25 16:08:40 -0400
commit9da8cf47c514f040c3b3b8111c2e76cb0501d52c (patch)
tree4d235ae8efb7f986dfb031f2cdf18b8633f5dda3
parent3125ad3bb6fb793491e3fc152ef05eb4cd221797 (diff)
downloadillumos-joyent-9da8cf47c514f040c3b3b8111c2e76cb0501d52c.tar.gz
OS-5710 sdev_create() doesn't enforce EISDIR in non-GZ
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r--usr/src/test/os-tests/runfiles/default.run5
-rw-r--r--usr/src/test/os-tests/tests/Makefile3
-rw-r--r--usr/src/test/os-tests/tests/sdevfs/Makefile47
-rw-r--r--usr/src/test/os-tests/tests/sdevfs/sdevfs_eisdir.c73
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vnops.c32
5 files changed, 157 insertions, 3 deletions
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run
index c209180fba..d2d5f502ed 100644
--- a/usr/src/test/os-tests/runfiles/default.run
+++ b/usr/src/test/os-tests/runfiles/default.run
@@ -11,6 +11,7 @@
#
# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2016 Joyent, Inc.
#
[DEFAULT]
@@ -42,6 +43,10 @@ tests = ['secflags_aslr',
[/opt/os-tests/tests/sigqueue]
tests = ['sigqueue_queue_size']
+[/opt/os-tests/tests/sdevfs]
+user = root
+tests = ['sdevfs_eisdir']
+
[/opt/os-tests/tests/tmpfs]
user = root
tests = ['tmpfs_badmount', 'tmpfs_enospc']
diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile
index 991f3fde5b..fcbab56508 100644
--- a/usr/src/test/os-tests/tests/Makefile
+++ b/usr/src/test/os-tests/tests/Makefile
@@ -11,8 +11,9 @@
#
# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2016 Joyent, Inc.
#
-SUBDIRS = poll secflags sigqueue spoof-ras tmpfs file-locking
+SUBDIRS = poll secflags sigqueue spoof-ras sdevfs tmpfs file-locking
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/os-tests/tests/sdevfs/Makefile b/usr/src/test/os-tests/tests/sdevfs/Makefile
new file mode 100644
index 0000000000..4d72e332b7
--- /dev/null
+++ b/usr/src/test/os-tests/tests/sdevfs/Makefile
@@ -0,0 +1,47 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests/sdevfs
+
+PROGS = sdevfs_eisdir
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+CMDS = $(PROGS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROGS)
+
+install: all $(CMDS)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROGS)
+
+clean:
+ -$(RM) *.o
+
+$(CMDS): $(TESTDIR) $(PROGS)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/os-tests/tests/sdevfs/sdevfs_eisdir.c b/usr/src/test/os-tests/tests/sdevfs/sdevfs_eisdir.c
new file mode 100644
index 0000000000..a1cc386ce7
--- /dev/null
+++ b/usr/src/test/os-tests/tests/sdevfs/sdevfs_eisdir.c
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * open(2) should return EISDIR when asking for write access on a dir.
+ * This test should return the same results in both GZ and NGZ contexts.
+ */
+#include <stdio.h>
+#include <strings.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/debug.h>
+#include <sys/statvfs.h>
+
+#define SD_TEST_DIR "/dev/zvol"
+
+int
+main(int argc, char *argv[])
+{
+ struct stat st;
+ struct statvfs vfs;
+ int ret;
+
+ if (stat(SD_TEST_DIR, &st) != 0) {
+ fprintf(stderr, "test failed: failed to stat %s\n",
+ SD_TEST_DIR);
+ return (1);
+ }
+
+ if ((st.st_mode & S_IFMT) != S_IFDIR) {
+ fprintf(stderr, "test failed: %s is not a dir\n", SD_TEST_DIR);
+ return (1);
+ }
+
+ if (statvfs(SD_TEST_DIR, &vfs) != 0) {
+ fprintf(stderr, "test failed: failed to stat vfs for %s: %s\n",
+ SD_TEST_DIR, strerror(errno));
+ return (1);
+ }
+
+ if (strncmp("dev", vfs.f_basetype, FSTYPSZ) != 0) {
+ fprintf(stderr, "test failed: asked to run on non-dev\n");
+ return (1);
+ }
+
+ ret = open(SD_TEST_DIR, O_RDWR, 0);
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, EISDIR);
+
+ /*
+ * It's important to test both O_RDWR and O_RDWR | O_CREAT
+ * because of the different code paths taken in sdev.
+ */
+ ret = open(SD_TEST_DIR, O_RDWR | O_CREAT, 0);
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, EISDIR);
+
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/dev/sdev_vnops.c b/usr/src/uts/common/fs/dev/sdev_vnops.c
index 6ce4b0b174..100fba3cac 100644
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vnops.c
@@ -660,10 +660,38 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
return (ENOENT);
}
- /* non-global do not allow pure node creation */
+ /*
+ * Nodes cannot be created in NGZ context.
+ */
if (!SDEV_IS_GLOBAL(parent)) {
rw_exit(&parent->sdev_dotdot->sdev_contents);
- return (prof_lookup(dvp, nm, vpp, cred));
+ error = prof_lookup(dvp, nm, vpp, cred);
+
+ /*
+ * In this case, we can't create a vnode but we can
+ * open an existing one. However, we still want to
+ * enforce the open(2) error semantics as if this was
+ * a regular sdev_create() in GZ context. Since we
+ * know the vnode already exists (error == 0) we a)
+ * return EEXIST if exclusive access was requested, or
+ * b) return EISDIR if write access was requested on a
+ * directory. Otherwise, we return the value from
+ * prof_lookup() as is.
+ */
+ if (error == 0) {
+ if (excl == EXCL) {
+ error = EEXIST;
+ } else if (((*vpp)->v_type == VDIR) &&
+ (mode & VWRITE)) {
+ error = EISDIR;
+ }
+
+ if (error != 0)
+ VN_RELE(*vpp);
+ }
+
+
+ return (error);
}
rw_exit(&parent->sdev_dotdot->sdev_contents);