Fix a few zdb bugs when trying to open a pool

Specifically, the following bugs are fixed in this patch:

1) zdb wasn't getting the correct device size when the vdev is a
block device.  In Solaris, fstat64() returns the device size but
in Linux an ioctl() is needed.

2) We were opening block devices with O_DIRECT, which caused pread64()
to fail with EINVAL due to memory alignment issues.  This was fixed by
the previous umem cache alignment fix in stub implementation to align
objects correctly.  But we still needed to add a check for the error here.

3) We also make sure that we don't try to open a block device in write
mode in userspace.  This shouldn't happen, because zdb opens devices
in read-only mode, and ztest only uses files.
This commit is contained in:
Ricardo M. Correia 2010-03-10 12:03:48 -08:00 committed by Brian Behlendorf
parent 1186ea3781
commit 2c79a2fa6a
1 changed files with 25 additions and 4 deletions

View File

@ -37,6 +37,7 @@
#include <sys/zfs_context.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <sys/mount.h> /* for BLKGETSIZE64 */
#include <sys/systeminfo.h>
/*
@ -552,13 +553,13 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
return (errno);
}
#ifdef __linux__
if (!(flags & FCREAT) && S_ISBLK(st.st_mode)) {
#ifdef __linux__
flags |= O_DIRECT;
if (flags & FWRITE)
flags |= O_EXCL;
}
#endif
/* We shouldn't be writing to block devices in userspace */
VERIFY(!(flags & FWRITE));
}
if (flags & FCREAT)
old_umask = umask(0);
@ -581,6 +582,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);
@ -634,6 +645,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);