summaryrefslogtreecommitdiffstats
path: root/lib/libzpool/kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libzpool/kernel.c')
-rw-r--r--lib/libzpool/kernel.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index a45102699..31d3336a8 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
+#include <libgen.h>
#include <sys/signal.h>
#include <sys/spa.h>
#include <sys/stat.h>
@@ -50,6 +51,9 @@ char hw_serial[HW_HOSTID_LEN];
struct utsname hw_utsname;
vmem_t *zio_arena = NULL;
+/* If set, all blocks read will be copied to the specified directory. */
+char *vn_dumpdir = NULL;
+
/* this only exists to have its address taken */
struct proc p0;
@@ -588,6 +592,7 @@ int
vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
{
int fd;
+ int dump_fd;
vnode_t *vp;
int old_umask = 0;
char *realpath;
@@ -655,13 +660,31 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
* FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
*/
fd = open64(realpath, flags - FREAD, mode);
- free(realpath);
+ err = errno;
if (flags & FCREAT)
(void) umask(old_umask);
+ if (vn_dumpdir != NULL) {
+ char *dumppath = umem_zalloc(MAXPATHLEN, UMEM_NOFAIL);
+ (void) snprintf(dumppath, MAXPATHLEN,
+ "%s/%s", vn_dumpdir, basename(realpath));
+ dump_fd = open64(dumppath, O_CREAT | O_WRONLY, 0666);
+ umem_free(dumppath, MAXPATHLEN);
+ if (dump_fd == -1) {
+ err = errno;
+ free(realpath);
+ close(fd);
+ return (err);
+ }
+ } else {
+ dump_fd = -1;
+ }
+
+ free(realpath);
+
if (fd == -1)
- return (errno);
+ return (err);
if (fstat64_blk(fd, &st) == -1) {
err = errno;
@@ -676,6 +699,7 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
vp->v_fd = fd;
vp->v_size = st.st_size;
vp->v_path = spa_strdup(path);
+ vp->v_dump_fd = dump_fd;
return (0);
}
@@ -708,6 +732,11 @@ vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
if (uio == UIO_READ) {
rc = pread64(vp->v_fd, addr, len, offset);
+ if (vp->v_dump_fd != -1) {
+ int status =
+ pwrite64(vp->v_dump_fd, addr, rc, offset);
+ ASSERT(status != -1);
+ }
} else {
/*
* To simulate partial disk writes, we split writes into two
@@ -750,6 +779,8 @@ void
vn_close(vnode_t *vp)
{
close(vp->v_fd);
+ if (vp->v_dump_fd != -1)
+ close(vp->v_dump_fd);
spa_strfree(vp->v_path);
umem_free(vp, sizeof (vnode_t));
}