diff options
| author | Ryan Zezeski <rpz@joyent.com> | 2016-10-11 20:49:51 -0400 |
|---|---|---|
| committer | Ryan Zezeski <rpz@joyent.com> | 2016-10-25 16:08:40 -0400 |
| commit | 9da8cf47c514f040c3b3b8111c2e76cb0501d52c (patch) | |
| tree | 4d235ae8efb7f986dfb031f2cdf18b8633f5dda3 | |
| parent | 3125ad3bb6fb793491e3fc152ef05eb4cd221797 (diff) | |
| download | illumos-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.run | 5 | ||||
| -rw-r--r-- | usr/src/test/os-tests/tests/Makefile | 3 | ||||
| -rw-r--r-- | usr/src/test/os-tests/tests/sdevfs/Makefile | 47 | ||||
| -rw-r--r-- | usr/src/test/os-tests/tests/sdevfs/sdevfs_eisdir.c | 73 | ||||
| -rw-r--r-- | usr/src/uts/common/fs/dev/sdev_vnops.c | 32 |
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); |
