diff --git a/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
index 7cdf5fe462547b7bdfe65907a8e2353cbb3a36f0..168e09c7d2c7eca882fd01997bccb4d0e2bac5ae 100644
--- a/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ b/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -507,6 +507,11 @@ zfs_read(vnode_t *vp, struct file* fp, uio_t *uio, int ioflag)
 	xuio_t		*xuio = NULL;
 #endif
 
+	// Return EISDIR when reading from a directory, as Linux does.
+	if (vp->v_type == VDIR) {
+	    return EISDIR;
+	}
+
 	ZFS_ENTER(zfsvfs);
 	ZFS_VERIFY_ZP(zp);
 	os = zfsvfs->z_os;
diff --git a/build.mk b/build.mk
index 0bdb0144f4e39d50761faabef0010919ee989e76..c1d77d0965bd1699b47e6e14ff8af4457855a885 100644
--- a/build.mk
+++ b/build.mk
@@ -240,6 +240,7 @@ tests += tests/tst-pipe.so
 tests += tests/tst-yield.so
 tests += tests/misc-ctxsw.so
 tests += tests/tst-readdir.so
+tests += tests/tst-read.so
 tests += tests/tst-remove.so
 tests += tests/misc-wake.so
 tests += tests/tst-epoll.so
diff --git a/tests/tst-read.cc b/tests/tst-read.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6147457f8d53190e50292718d6d416a8023183ea
--- /dev/null
+++ b/tests/tst-read.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+// To compile on Linux, use: g++ -g -pthread -std=c++11 tests/tst-read.cc
+
+#include <sys/timerfd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <chrono>
+#include <thread>
+
+#include <errno.h>
+static int tests = 0, fails = 0;
+
+template<typename T>
+bool do_expect(T actual, T expected, const char *actuals, const char *expecteds, const char *file, int line)
+{
+    ++tests;
+    if (actual != expected) {
+        fails++;
+        std::cout << "FAIL: " << file << ":" << line << ": For " << actuals
+                << " expected " << expecteds << "(" << expected << "), saw "
+                << actual << ".\n";
+        return false;
+    }
+    std::cout << "OK: " << file << ":" << line << ".\n";
+    return true;
+}
+template<typename T>
+bool do_expectge(T actual, T expected, const char *actuals, const char *expecteds, const char *file, int line)
+{
+    ++tests;
+    if (actual < expected) {
+        fails++;
+        std::cout << "FAIL: " << file << ":" << line << ": For " << actuals
+                << " expected >=" << expecteds << ", saw " << actual << ".\n";
+        return false;
+    }
+    std::cout << "OK: " << file << ":" << line << ".\n";
+    return true;
+}
+#define expect(actual, expected) do_expect(actual, expected, #actual, #expected, __FILE__, __LINE__)
+#define expectge(actual, expected) do_expectge(actual, expected, #actual, #expected, __FILE__, __LINE__)
+#define expect_errno(call, experrno) ( \
+        do_expect((long)(call), (long)-1, #call, "-1", __FILE__, __LINE__) && \
+        do_expect(errno, experrno, #call " errno",  #experrno, __FILE__, __LINE__) )
+#define expect_success(var, call) \
+        errno = 0; \
+        var = call; \
+        do_expectge(var, 0, #call, "0", __FILE__, __LINE__); \
+        do_expect(errno, 0, #call " errno",  "0", __FILE__, __LINE__);
+
+int main()
+{
+    // Test how reading from a directory fails with EISDIR, as in Linux.
+    int fd;
+    expect_success(fd, open("/tmp", O_RDONLY));
+    char buf[1024];
+    expect_errno(read(fd, buf, 10), EISDIR);
+
+    std::cout << "SUMMARY: " << tests << " tests, " << fails << " failures\n";
+    return fails == 0 ? 0 : 1;
+}