summaryrefslogtreecommitdiffstats
path: root/lib/libzpool/kernel.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2010-08-26 11:56:53 -0700
committerBrian Behlendorf <[email protected]>2010-08-31 13:42:00 -0700
commitd603ed6c278f9c25b17ba8e75e9bce6e5d715ac0 (patch)
tree61dc04f07ed9772dd97faefd879412e2a6578be0 /lib/libzpool/kernel.c
parentf1fb119f6bb0c3185ec88912e4488fdd9ec08ab2 (diff)
Add linux user disk support
This topic branch contains all the changes needed to integrate the user side zfs tools with Linux style devices. Primarily this includes fixing up the Solaris libefi library to be Linux friendly, and integrating with the libblkid library which is provided by e2fsprogs. Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'lib/libzpool/kernel.c')
-rw-r--r--lib/libzpool/kernel.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index 494e544ea..6f06f4001 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -35,6 +35,8 @@
#include <sys/processor.h>
#include <sys/zfs_context.h>
#include <sys/utsname.h>
+#include <sys/time.h>
+#include <sys/mount.h> /* for BLKGETSIZE64 */
#include <sys/systeminfo.h>
/*
@@ -533,7 +535,11 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
* for its size. So -- gag -- we open the block device to get
* its size, and remember it for subsequent VOP_GETATTR().
*/
+#if defined(__sun__) || defined(__sun)
if (strncmp(path, "/dev/", 5) == 0) {
+#else
+ if (0) {
+#endif
char *dsk;
fd = open64(path, O_RDONLY);
if (fd == -1) {
@@ -562,6 +568,14 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
}
}
+ if (!(flags & FCREAT) && S_ISBLK(st.st_mode)) {
+#ifdef __linux__
+ flags |= O_DIRECT;
+#endif
+ /* We shouldn't be writing to block devices in userspace */
+ VERIFY(!(flags & FWRITE));
+ }
+
if (flags & FCREAT)
old_umask = umask(0);
@@ -584,6 +598,16 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
return (err);
}
+#ifdef __linux__
+ /* In Linux, use an ioctl to get the size of a block device. */
+ if (S_ISBLK(st.st_mode)) {
+ if (ioctl(fd, BLKGETSIZE64, &st.st_size) != 0) {
+ err = errno;
+ close(fd);
+ return (err);
+ }
+ }
+#endif
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
*vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
@@ -637,6 +661,16 @@ vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
}
}
+#ifdef __linux__
+ if (rc == -1 && errno == EINVAL) {
+ /*
+ * Under Linux, this most likely means an alignment issue
+ * (memory or disk) due to O_DIRECT, so we abort() in order to
+ * catch the offender.
+ */
+ abort();
+ }
+#endif
if (rc == -1)
return (errno);