changeset 3782:d53b92e6d144

6524333 Service domain panics if it fails to map pages for a disk on file 6527265 Hard hang in guest ldom on issuing the format command 6530040 vds does not close underlying physical device or file properly
author achartre
date Fri, 09 Mar 2007 01:04:32 -0800
parents 41d7a70cdf1d
children c865a2700370
files usr/src/uts/sun4v/io/vdc.c usr/src/uts/sun4v/io/vds.c
diffstat 2 files changed, 316 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/sun4v/io/vdc.c	Thu Mar 08 17:32:28 2007 -0800
+++ b/usr/src/uts/sun4v/io/vdc.c	Fri Mar 09 01:04:32 2007 -0800
@@ -3422,6 +3422,7 @@
 			mutex_enter(&vdcp->lock);
 
 			vdcp->state = VDC_STATE_RESETTING;
+			vdcp->self_reset = B_TRUE;
 			break;
 
 		case VDC_STATE_RESETTING:
--- a/usr/src/uts/sun4v/io/vds.c	Thu Mar 08 17:32:28 2007 -0800
+++ b/usr/src/uts/sun4v/io/vds.c	Fri Mar 09 01:04:32 2007 -0800
@@ -50,6 +50,7 @@
 #include <sys/vtoc.h>
 #include <sys/vfs.h>
 #include <sys/stat.h>
+#include <vm/seg_map.h>
 
 /* Virtual disk server initialization flags */
 #define	VDS_LDI			0x01
@@ -114,6 +115,19 @@
 		(((vd)->xfer_mode == 0) ? "null client" :		\
 		    "unsupported client")))
 
+/* For IO to raw disk on file */
+#define	VD_FILE_SLICE_NONE	-1
+
+/* Read disk label from a disk on file */
+#define	VD_FILE_LABEL_READ(vd, labelp) \
+	vd_file_rw(vd, VD_FILE_SLICE_NONE, VD_OP_BREAD, (caddr_t)labelp, \
+	    0, sizeof (struct dk_label))
+
+/* Write disk label to a disk on file */
+#define	VD_FILE_LABEL_WRITE(vd, labelp)	\
+	vd_file_rw(vd, VD_FILE_SLICE_NONE, VD_OP_BWRITE, (caddr_t)labelp, \
+	    0, sizeof (struct dk_label))
+
 /*
  * Specification of an MD node passed to the MDEG to filter any
  * 'vport' nodes that do not belong to the specified node. This
@@ -295,7 +309,6 @@
 	ushort_t		max_xfer_sz;	/* max xfer size in DEV_BSIZE */
 	boolean_t		pseudo;		/* underlying pseudo dev */
 	boolean_t		file;		/* underlying file */
-	char			*file_maddr;	/* file mapping address */
 	vnode_t			*file_vnode;	/* file vnode */
 	size_t			file_size;	/* file size */
 	struct dk_efi		dk_efi;		/* synthetic for slice type */
@@ -371,6 +384,124 @@
 static int vd_setup_vd(vd_t *vd);
 static boolean_t vd_enabled(vd_t *vd);
 
+/*
+ * Function:
+ *	vd_file_rw
+ *
+ * Description:
+ * 	Read or write to a disk on file.
+ *
+ * Parameters:
+ *	vd		- disk on which the operation is performed.
+ *	slice		- slice on which the operation is performed,
+ *			  VD_FILE_SLICE_NONE indicates that the operation
+ *			  is done on the raw disk.
+ *	operation	- operation to execute: read (VD_OP_BREAD) or
+ *			  write (VD_OP_BWRITE).
+ *	data		- buffer where data are read to or written from.
+ *	blk		- starting block for the operation.
+ *	len		- number of bytes to read or write.
+ *
+ * Return Code:
+ *	n >= 0		- success, n indicates the number of bytes read
+ *			  or written.
+ *	-1		- error.
+ */
+static ssize_t
+vd_file_rw(vd_t *vd, int slice, int operation, caddr_t data, size_t blk,
+    size_t len)
+{
+	caddr_t	maddr;
+	size_t offset, maxlen, moffset, mlen, n;
+	uint_t smflags;
+	enum seg_rw srw;
+
+	ASSERT(vd->file);
+	ASSERT(len > 0);
+
+	if (slice == VD_FILE_SLICE_NONE) {
+		/* raw disk access */
+		offset = blk * DEV_BSIZE;
+	} else {
+		ASSERT(slice >= 0 && slice < V_NUMPAR);
+		if (blk >= vd->vtoc.v_part[slice].p_size) {
+			/* address past the end of the slice */
+			PR0("req_addr (0x%lx) > psize (0x%lx)",
+			    blk, vd->vtoc.v_part[slice].p_size);
+			return (0);
+		}
+
+		offset = (vd->vtoc.v_part[slice].p_start + blk) * DEV_BSIZE;
+
+		/*
+		 * If the requested size is greater than the size
+		 * of the partition, truncate the read/write.
+		 */
+		maxlen = (vd->vtoc.v_part[slice].p_size - blk) * DEV_BSIZE;
+
+		if (len > maxlen) {
+			PR0("I/O size truncated to %lu bytes from %lu bytes",
+			    maxlen, len);
+			len = maxlen;
+		}
+	}
+
+	/*
+	 * We have to ensure that we are reading/writing into the mmap
+	 * range. If we have a partial disk image (e.g. an image of
+	 * s0 instead s2) the system can try to access slices that
+	 * are not included into the disk image.
+	 */
+	if ((offset + len) >= vd->file_size) {
+		PR0("offset + nbytes (0x%lx + 0x%lx) >= "
+		    "file_size (0x%lx)", offset, len, vd->file_size);
+		return (-1);
+	}
+
+	srw = (operation == VD_OP_BREAD)? S_READ : S_WRITE;
+	smflags = (operation == VD_OP_BREAD)? 0 : SM_WRITE;
+	n = len;
+
+	do {
+		/*
+		 * segmap_getmapflt() returns a MAXBSIZE chunk which is
+		 * MAXBSIZE aligned.
+		 */
+		moffset = offset & MAXBOFFSET;
+		mlen = MIN(MAXBSIZE - moffset, n);
+		maddr = segmap_getmapflt(segkmap, vd->file_vnode, offset,
+		    mlen, 1, srw);
+		/*
+		 * Fault in the pages so we can check for error and ensure
+		 * that we can safely used the mapped address.
+		 */
+		if (segmap_fault(kas.a_hat, segkmap, maddr, mlen,
+		    F_SOFTLOCK, srw) != 0) {
+			(void) segmap_release(segkmap, maddr, 0);
+			return (-1);
+		}
+
+		if (operation == VD_OP_BREAD)
+			bcopy(maddr + moffset, data, mlen);
+		else
+			bcopy(data, maddr + moffset, mlen);
+
+		if (segmap_fault(kas.a_hat, segkmap, maddr, mlen,
+		    F_SOFTUNLOCK, srw) != 0) {
+			(void) segmap_release(segkmap, maddr, 0);
+			return (-1);
+		}
+		if (segmap_release(segkmap, maddr, smflags) != 0)
+			return (-1);
+		n -= mlen;
+		offset += mlen;
+		data += mlen;
+
+	} while (n > 0);
+
+	return (len);
+}
+
 static int
 vd_start_bio(vd_task_t *task)
 {
@@ -379,8 +510,6 @@
 	vd_dring_payload_t	*request	= task->request;
 	struct buf		*buf		= &task->buf;
 	uint8_t			mtype;
-	caddr_t			addr;
-	size_t			offset, maxlen;
 	int 			slice;
 
 	ASSERT(vd != NULL);
@@ -429,61 +558,21 @@
 
 	/* Start the block I/O */
 	if (vd->file) {
-
-		if (request->addr >= vd->vtoc.v_part[slice].p_size) {
-			/* address past the end of the slice */
-			PR0("req_addr (0x%lx) > psize (0x%lx)",
-			    request->addr, vd->vtoc.v_part[slice].p_size);
-			request->nbytes = 0;
-			status = 0;
-			goto cleanup;
-		}
-
-		offset = (vd->vtoc.v_part[slice].p_start +
-		    request->addr) * DEV_BSIZE;
-
-		/*
-		 * If the requested size is greater than the size
-		 * of the partition, truncate the read/write.
-		 */
-		maxlen = (vd->vtoc.v_part[slice].p_size -
-		    request->addr) * DEV_BSIZE;
-
-		if (request->nbytes > maxlen) {
-			PR0("I/O size truncated to %lu bytes from %lu bytes",
-			    maxlen, request->nbytes);
-			request->nbytes = maxlen;
-		}
-
-		/*
-		 * We have to ensure that we are reading/writing into the mmap
-		 * range. If we have a partial disk image (e.g. an image of
-		 * s0 instead s2) the system can try to access slices that
-		 * are not included into the disk image.
-		 */
-		if ((offset + request->nbytes) >= vd->file_size) {
-			PR0("offset + nbytes (0x%lx + 0x%lx) >= "
-			    "file_size (0x%lx)", offset, request->nbytes,
-			    vd->file_size);
+		rv = vd_file_rw(vd, slice, request->operation, buf->b_un.b_addr,
+		    request->addr, request->nbytes);
+		if (rv < 0) {
 			request->nbytes = 0;
 			status = EIO;
-			goto cleanup;
+		} else {
+			request->nbytes = rv;
+			status = 0;
 		}
-
-		addr = vd->file_maddr + offset;
-
-		if (request->operation == VD_OP_BREAD)
-			bcopy(addr, buf->b_un.b_addr, request->nbytes);
-		else
-			bcopy(buf->b_un.b_addr, addr, request->nbytes);
-
 	} else {
 		status = ldi_strategy(vd->ldi_handle[slice], buf);
 		if (status == 0)
 			return (EINPROGRESS); /* will complete on completionq */
 	}
 
-cleanup:
 	/* Clean up after error */
 	rv = ldc_mem_release(task->mhdl, 0, buf->b_bcount);
 	if (rv) {
@@ -869,14 +958,14 @@
 	return (0);
 }
 
-static short
+static ushort_t
 vd_lbl2cksum(struct dk_label *label)
 {
 	int	count;
-	short	sum, *sp;
+	ushort_t sum, *sp;
 
 	count =	(sizeof (struct dk_label)) / (sizeof (short)) - 1;
-	sp = (short *)label;
+	sp = (ushort_t *)label;
 	sum = 0;
 	while (count--) {
 		sum ^= *sp++;
@@ -889,7 +978,8 @@
 vd_do_slice_ioctl(vd_t *vd, int cmd, void *ioctl_arg)
 {
 	dk_efi_t *dk_ioc;
-	struct dk_label *label;
+	struct dk_label label;
+	struct vtoc *vtoc;
 	int i;
 
 	switch (vd->vdisk_label) {
@@ -909,30 +999,60 @@
 			if (!vd->file)
 				return (ENOTSUP);
 			ASSERT(ioctl_arg != NULL);
-			bcopy(ioctl_arg, &vd->vtoc, sizeof (vd->vtoc));
-			/* write new VTOC to file */
-			label = (struct dk_label *)vd->file_maddr;
-			label->dkl_vtoc.v_nparts = vd->vtoc.v_nparts;
-			label->dkl_vtoc.v_sanity = vd->vtoc.v_sanity;
-			label->dkl_vtoc.v_version = vd->vtoc.v_version;
-			bcopy(vd->vtoc.v_volume, label->dkl_vtoc.v_volume,
+			vtoc = (struct vtoc *)ioctl_arg;
+
+			if (vtoc->v_sanity != VTOC_SANE ||
+			    vtoc->v_sectorsz != DEV_BSIZE ||
+			    vtoc->v_nparts != V_NUMPAR)
+				return (EINVAL);
+
+			bzero(&label, sizeof (label));
+			label.dkl_ncyl = vd->dk_geom.dkg_ncyl;
+			label.dkl_acyl = vd->dk_geom.dkg_acyl;
+			label.dkl_pcyl = vd->dk_geom.dkg_pcyl;
+			label.dkl_nhead = vd->dk_geom.dkg_nhead;
+			label.dkl_nsect = vd->dk_geom.dkg_nsect;
+			label.dkl_intrlv = vd->dk_geom.dkg_intrlv;
+			label.dkl_apc = vd->dk_geom.dkg_apc;
+			label.dkl_rpm = vd->dk_geom.dkg_rpm;
+			label.dkl_write_reinstruct =
+				vd->dk_geom.dkg_write_reinstruct;
+			label.dkl_read_reinstruct =
+				vd->dk_geom.dkg_read_reinstruct;
+
+			label.dkl_vtoc.v_nparts = vtoc->v_nparts;
+			label.dkl_vtoc.v_sanity = vtoc->v_sanity;
+			label.dkl_vtoc.v_version = vtoc->v_version;
+			for (i = 0; i < vtoc->v_nparts; i++) {
+				label.dkl_vtoc.v_timestamp[i] =
+				    vtoc->timestamp[i];
+				label.dkl_vtoc.v_part[i].p_tag =
+				    vtoc->v_part[i].p_tag;
+				label.dkl_vtoc.v_part[i].p_flag =
+				    vtoc->v_part[i].p_flag;
+				label.dkl_map[i].dkl_cylno =
+					vtoc->v_part[i].p_start /
+					(label.dkl_nhead * label.dkl_nsect);
+				label.dkl_map[i].dkl_nblk =
+				    vtoc->v_part[i].p_size;
+			}
+			bcopy(vtoc->v_asciilabel, label.dkl_asciilabel,
+			    LEN_DKL_ASCII);
+			bcopy(vtoc->v_volume, label.dkl_vtoc.v_volume,
 			    LEN_DKL_VVOL);
-			for (i = 0; i < vd->vtoc.v_nparts; i++) {
-				label->dkl_vtoc.v_timestamp[i] =
-				    vd->vtoc.timestamp[i];
-				label->dkl_vtoc.v_part[i].p_tag =
-				    vd->vtoc.v_part[i].p_tag;
-				label->dkl_vtoc.v_part[i].p_flag =
-				    vd->vtoc.v_part[i].p_flag;
-				label->dkl_map[i].dkl_cylno =
-				    vd->vtoc.v_part[i].p_start /
-				    (label->dkl_nhead * label->dkl_nsect);
-				label->dkl_map[i].dkl_nblk =
-				    vd->vtoc.v_part[i].p_size;
-			}
+			bcopy(vtoc->v_bootinfo, label.dkl_vtoc.v_bootinfo,
+			    sizeof (vtoc->v_bootinfo));
 
 			/* re-compute checksum */
-			label->dkl_cksum = vd_lbl2cksum(label);
+			label.dkl_magic = DKL_MAGIC;
+			label.dkl_cksum = vd_lbl2cksum(&label);
+
+			/* write label to file */
+			if (VD_FILE_LABEL_WRITE(vd, &label) < 0)
+				return (EIO);
+
+			/* update the cached vdisk VTOC */
+			bcopy(vtoc, &vd->vtoc, sizeof (vd->vtoc));
 
 			return (0);
 		default:
@@ -2423,7 +2543,7 @@
 	if ((status = ldi_ioctl(vd->ldi_handle[0], DKIOCGMEDIAINFO,
 	    (intptr_t)&dk_minfo, (vd_open_flags | FKIOCTL),
 	    kcred, &rval)) != 0) {
-		PR0("ldi_ioctl(DKIOCGMEDIAINFO) returned errno %d",
+		PRN("ldi_ioctl(DKIOCGMEDIAINFO) returned errno %d",
 		    status);
 		return (status);
 	}
@@ -2474,9 +2594,10 @@
 		if ((status = ldi_open_by_dev(&vd->dev[slice], OTYP_BLK,
 		    vd_open_flags | FNDELAY, kcred, &vd->ldi_handle[slice],
 		    vd->vds->ldi_ident)) != 0) {
-			PR0("ldi_open_by_dev() returned errno %d "
+			PRN("ldi_open_by_dev() returned errno %d "
 			    "for slice %u", status, slice);
 			/* vds_destroy_vd() will close any open slices */
+			vd->ldi_handle[slice] = NULL;
 			return (status);
 		}
 	}
@@ -2527,24 +2648,24 @@
 vd_setup_file(vd_t *vd)
 {
 	int 		i, rval, status;
-	short		sum;
+	ushort_t	sum;
 	vattr_t		vattr;
 	dev_t		dev;
 	char		*file_path = vd->device_path;
 	char		dev_path[MAXPATHLEN + 1];
 	ldi_handle_t	lhandle;
 	struct dk_cinfo	dk_cinfo;
-	struct dk_label *label;
+	struct dk_label label;
 
 	/* make sure the file is valid */
 	if ((status = lookupname(file_path, UIO_SYSSPACE, FOLLOW,
 		NULLVPP, &vd->file_vnode)) != 0) {
-		PR0("Cannot lookup file(%s) errno %d", file_path, status);
+		PRN("Cannot lookup file(%s) errno %d", file_path, status);
 		return (status);
 	}
 
 	if (vd->file_vnode->v_type != VREG) {
-		PR0("Invalid file type (%s)\n", file_path);
+		PRN("Invalid file type (%s)\n", file_path);
 		VN_RELE(vd->file_vnode);
 		return (EBADF);
 	}
@@ -2552,15 +2673,20 @@
 
 	if ((status = vn_open(file_path, UIO_SYSSPACE, vd_open_flags | FOFFMAX,
 	    0, &vd->file_vnode, 0, 0)) != 0) {
-		PR0("vn_open(%s) = errno %d", file_path, status);
+		PRN("vn_open(%s) = errno %d", file_path, status);
 		return (status);
 	}
 
+	/*
+	 * We set vd->file now so that vds_destroy_vd will take care of
+	 * closing the file and releasing the vnode in case of an error.
+	 */
+	vd->file = B_TRUE;
+	vd->pseudo = B_FALSE;
+
 	vattr.va_mask = AT_SIZE;
 	if ((status = VOP_GETATTR(vd->file_vnode, &vattr, 0, kcred)) != 0) {
-		PR0("VOP_GETATTR(%s) = errno %d", file_path, status);
-		(void) VOP_CLOSE(vd->file_vnode, vd_open_flags, 1, 0, kcred);
-		VN_RELE(vd->file_vnode);
+		PRN("VOP_GETATTR(%s) = errno %d", file_path, status);
 		return (EIO);
 	}
 
@@ -2569,32 +2695,30 @@
 	if (vd->file_size < sizeof (struct dk_label)) {
 		PRN("Size of file has to be at least %ld bytes",
 		    sizeof (struct dk_label));
-		(void) VOP_CLOSE(vd->file_vnode, vd_open_flags, 1, 0, kcred);
-		VN_RELE(vd->file_vnode);
 		return (EIO);
 	}
 
-	if ((status = VOP_MAP(vd->file_vnode, 0, &kas, &vd->file_maddr,
-	    vd->file_size, PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
-	    MAP_SHARED, kcred)) != 0) {
-		PR0("VOP_MAP(%s) = errno %d", file_path, status);
-		(void) VOP_CLOSE(vd->file_vnode, vd_open_flags, 1, 0, kcred);
-		VN_RELE(vd->file_vnode);
+	if (vd->file_vnode->v_flag & VNOMAP) {
+		PRN("File %s cannot be mapped", file_path);
 		return (EIO);
 	}
 
-	label = (struct dk_label *)vd->file_maddr;
+	/* read label from file */
+	if (VD_FILE_LABEL_READ(vd, &label) < 0) {
+		PRN("Can't read label from %s", file_path);
+		return (EIO);
+	}
 
 	/* label checksum */
-	sum = vd_lbl2cksum(label);
-
-	if (label->dkl_magic != DKL_MAGIC || label->dkl_cksum != sum) {
+	sum = vd_lbl2cksum(&label);
+
+	if (label.dkl_magic != DKL_MAGIC || label.dkl_cksum != sum) {
 		PR0("%s has an invalid disk label "
 		    "(magic=%x cksum=%x (expect %x))",
-		    file_path, label->dkl_magic, label->dkl_cksum, sum);
+		    file_path, label.dkl_magic, label.dkl_cksum, sum);
 
 		/* default label */
-		bzero(label, sizeof (struct dk_label));
+		bzero(&label, sizeof (struct dk_label));
 
 		/*
 		 * We must have a resonable number of cylinders and sectors so
@@ -2612,63 +2736,69 @@
 		 * sectors = disk_size / (phys_cylinders * blk_size)
 		 */
 		if (vd->file_size < (2 * 1024 * 1024))
-			label->dkl_pcyl = vd->file_size / (100 * 1024);
+			label.dkl_pcyl = vd->file_size / (100 * 1024);
 		else
-			label->dkl_pcyl = vd->file_size / (300 * 1024);
-
-		if (label->dkl_pcyl == 0)
-			label->dkl_pcyl = 1;
-
-		if (label->dkl_pcyl > 2)
-			label->dkl_acyl = 2;
+			label.dkl_pcyl = vd->file_size / (300 * 1024);
+
+		if (label.dkl_pcyl == 0)
+			label.dkl_pcyl = 1;
+
+		if (label.dkl_pcyl > 2)
+			label.dkl_acyl = 2;
 		else
-			label->dkl_acyl = 0;
-
-		label->dkl_nsect = vd->file_size /
-			(DEV_BSIZE * label->dkl_pcyl);
-		label->dkl_ncyl = label->dkl_pcyl - label->dkl_acyl;
-		label->dkl_nhead = 1;
-		label->dkl_write_reinstruct = 0;
-		label->dkl_read_reinstruct = 0;
-		label->dkl_rpm = 7200;
-		label->dkl_apc = 0;
-		label->dkl_intrlv = 0;
-		label->dkl_magic = DKL_MAGIC;
+			label.dkl_acyl = 0;
+
+		label.dkl_nsect = vd->file_size /
+			(DEV_BSIZE * label.dkl_pcyl);
+		label.dkl_ncyl = label.dkl_pcyl - label.dkl_acyl;
+		label.dkl_nhead = 1;
+		label.dkl_write_reinstruct = 0;
+		label.dkl_read_reinstruct = 0;
+		label.dkl_rpm = 7200;
+		label.dkl_apc = 0;
+		label.dkl_intrlv = 0;
+		label.dkl_magic = DKL_MAGIC;
 
 		PR0("requested disk size: %ld bytes\n", vd->file_size);
-		PR0("setup: ncyl=%d nhead=%d nsec=%d\n", label->dkl_pcyl,
-		    label->dkl_nhead, label->dkl_nsect);
+		PR0("setup: ncyl=%d nhead=%d nsec=%d\n", label.dkl_pcyl,
+		    label.dkl_nhead, label.dkl_nsect);
 		PR0("provided disk size: %ld bytes\n", (uint64_t)
-		    (label->dkl_pcyl *
-			label->dkl_nhead * label->dkl_nsect * DEV_BSIZE));
+		    (label.dkl_pcyl *
+			label.dkl_nhead * label.dkl_nsect * DEV_BSIZE));
 
 		/*
 		 * We must have a correct label name otherwise format(1m) will
 		 * not recognized the disk as labeled.
 		 */
-		(void) snprintf(label->dkl_asciilabel, LEN_DKL_ASCII,
+		(void) snprintf(label.dkl_asciilabel, LEN_DKL_ASCII,
 		    "SUNVDSK cyl %d alt %d hd %d sec %d",
-		    label->dkl_ncyl, label->dkl_acyl, label->dkl_nhead,
-		    label->dkl_nsect);
+		    label.dkl_ncyl, label.dkl_acyl, label.dkl_nhead,
+		    label.dkl_nsect);
 
 		/* default VTOC */
-		label->dkl_vtoc.v_version = V_VERSION;
-		label->dkl_vtoc.v_nparts = 8;
-		label->dkl_vtoc.v_sanity = VTOC_SANE;
-		label->dkl_vtoc.v_part[2].p_tag = V_BACKUP;
-		label->dkl_map[2].dkl_cylno = 0;
-		label->dkl_map[2].dkl_nblk = label->dkl_ncyl *
-			label->dkl_nhead * label->dkl_nsect;
-		label->dkl_map[0] = label->dkl_map[2];
-		label->dkl_map[0] = label->dkl_map[2];
-		label->dkl_cksum = vd_lbl2cksum(label);
+		label.dkl_vtoc.v_version = V_VERSION;
+		label.dkl_vtoc.v_nparts = V_NUMPAR;
+		label.dkl_vtoc.v_sanity = VTOC_SANE;
+		label.dkl_vtoc.v_part[2].p_tag = V_BACKUP;
+		label.dkl_map[2].dkl_cylno = 0;
+		label.dkl_map[2].dkl_nblk = label.dkl_ncyl *
+			label.dkl_nhead * label.dkl_nsect;
+		label.dkl_map[0] = label.dkl_map[2];
+		label.dkl_map[0] = label.dkl_map[2];
+		label.dkl_cksum = vd_lbl2cksum(&label);
+
+		/* write default label to file */
+		if (VD_FILE_LABEL_WRITE(vd, &label) < 0) {
+			PRN("Can't write label to %s", file_path);
+			return (EIO);
+		}
 	}
 
-	vd->nslices = label->dkl_vtoc.v_nparts;
+	vd->nslices = label.dkl_vtoc.v_nparts;
 
 	/* sector size = block size = DEV_BSIZE */
-	vd->vdisk_size = (label->dkl_pcyl *
-	    label->dkl_nhead * label->dkl_nsect) / DEV_BSIZE;
+	vd->vdisk_size = (label.dkl_pcyl *
+	    label.dkl_nhead * label.dkl_nsect) / DEV_BSIZE;
 	vd->vdisk_type = VD_DISK_TYPE_DISK;
 	vd->vdisk_label = VD_DISK_LABEL_VTOC;
 	vd->max_xfer_sz = maxphys / DEV_BSIZE; /* default transfer size */
@@ -2705,37 +2835,34 @@
 	PR0("using for file %s, dev %s, max_xfer = %u blks",
 	    file_path, dev_path, vd->max_xfer_sz);
 
-	vd->pseudo = B_FALSE;
-	vd->file = B_TRUE;
-
-	vd->dk_geom.dkg_ncyl = label->dkl_ncyl;
-	vd->dk_geom.dkg_acyl = label->dkl_acyl;
-	vd->dk_geom.dkg_pcyl = label->dkl_pcyl;
-	vd->dk_geom.dkg_nhead = label->dkl_nhead;
-	vd->dk_geom.dkg_nsect = label->dkl_nsect;
-	vd->dk_geom.dkg_intrlv = label->dkl_intrlv;
-	vd->dk_geom.dkg_apc = label->dkl_apc;
-	vd->dk_geom.dkg_rpm = label->dkl_rpm;
-	vd->dk_geom.dkg_write_reinstruct = label->dkl_write_reinstruct;
-	vd->dk_geom.dkg_read_reinstruct = label->dkl_read_reinstruct;
-
-	vd->vtoc.v_sanity = label->dkl_vtoc.v_sanity;
-	vd->vtoc.v_version = label->dkl_vtoc.v_version;
+	vd->dk_geom.dkg_ncyl = label.dkl_ncyl;
+	vd->dk_geom.dkg_acyl = label.dkl_acyl;
+	vd->dk_geom.dkg_pcyl = label.dkl_pcyl;
+	vd->dk_geom.dkg_nhead = label.dkl_nhead;
+	vd->dk_geom.dkg_nsect = label.dkl_nsect;
+	vd->dk_geom.dkg_intrlv = label.dkl_intrlv;
+	vd->dk_geom.dkg_apc = label.dkl_apc;
+	vd->dk_geom.dkg_rpm = label.dkl_rpm;
+	vd->dk_geom.dkg_write_reinstruct = label.dkl_write_reinstruct;
+	vd->dk_geom.dkg_read_reinstruct = label.dkl_read_reinstruct;
+
+	vd->vtoc.v_sanity = label.dkl_vtoc.v_sanity;
+	vd->vtoc.v_version = label.dkl_vtoc.v_version;
 	vd->vtoc.v_sectorsz = DEV_BSIZE;
-	vd->vtoc.v_nparts = label->dkl_vtoc.v_nparts;
-
-	bcopy(label->dkl_vtoc.v_volume, vd->vtoc.v_volume,
+	vd->vtoc.v_nparts = label.dkl_vtoc.v_nparts;
+
+	bcopy(label.dkl_vtoc.v_volume, vd->vtoc.v_volume,
 	    LEN_DKL_VVOL);
-	bcopy(label->dkl_asciilabel, vd->vtoc.v_asciilabel,
+	bcopy(label.dkl_asciilabel, vd->vtoc.v_asciilabel,
 	    LEN_DKL_ASCII);
 
 	for (i = 0; i < vd->nslices; i++) {
-		vd->vtoc.timestamp[i] = label->dkl_vtoc.v_timestamp[i];
-		vd->vtoc.v_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag;
-		vd->vtoc.v_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag;
-		vd->vtoc.v_part[i].p_start = label->dkl_map[i].dkl_cylno *
-			label->dkl_nhead * label->dkl_nsect;
-		vd->vtoc.v_part[i].p_size = label->dkl_map[i].dkl_nblk;
+		vd->vtoc.timestamp[i] = label.dkl_vtoc.v_timestamp[i];
+		vd->vtoc.v_part[i].p_tag = label.dkl_vtoc.v_part[i].p_tag;
+		vd->vtoc.v_part[i].p_flag = label.dkl_vtoc.v_part[i].p_flag;
+		vd->vtoc.v_part[i].p_start = label.dkl_map[i].dkl_cylno *
+			label.dkl_nhead * label.dkl_nsect;
+		vd->vtoc.v_part[i].p_size = label.dkl_map[i].dkl_nblk;
 		vd->ldi_handle[i] = NULL;
 		vd->dev[i] = NULL;
 	}
@@ -2758,12 +2885,13 @@
 	if ((status = ldi_open_by_name(device_path, vd_open_flags | FNDELAY,
 	    kcred, &vd->ldi_handle[0], vd->vds->ldi_ident)) != 0) {
 		PR0("ldi_open_by_name(%s) = errno %d", device_path, status);
+		vd->ldi_handle[0] = NULL;
 
 		/* this may not be a device try opening as a file */
 		if (status == ENXIO || status == ENODEV)
 			status = vd_setup_file(vd);
 		if (status) {
-			PR0("Cannot use device/file (%s), errno=%d\n",
+			PRN("Cannot use device/file (%s), errno=%d\n",
 			    device_path, status);
 			if (status == ENXIO || status == ENODEV ||
 			    status == ENOENT) {
@@ -2856,11 +2984,11 @@
 
 	/* Initialize dk_geom structure for single-slice device */
 	if (vd->dk_geom.dkg_nsect == 0) {
-		PR0("%s geometry claims 0 sectors per track", device_path);
+		PRN("%s geometry claims 0 sectors per track", device_path);
 		return (EIO);
 	}
 	if (vd->dk_geom.dkg_nhead == 0) {
-		PR0("%s geometry claims 0 heads", device_path);
+		PRN("%s geometry claims 0 heads", device_path);
 		return (EIO);
 	}
 	vd->dk_geom.dkg_ncyl =
@@ -2958,19 +3086,22 @@
 	ldc_attr.mode		= LDC_MODE_UNRELIABLE;
 	ldc_attr.mtu		= VD_LDC_MTU;
 	if ((status = ldc_init(ldc_id, &ldc_attr, &vd->ldc_handle)) != 0) {
-		PR0("ldc_init(%lu) = errno %d", ldc_id, status);
+		PRN("Could not initialize LDC channel %lu, "
+		    "init failed with error %d", ldc_id, status);
 		return (status);
 	}
 	vd->initialized |= VD_LDC;
 
 	if ((status = ldc_reg_callback(vd->ldc_handle, vd_handle_ldc_events,
 		(caddr_t)vd)) != 0) {
-		PR0("ldc_reg_callback() returned errno %d", status);
+		PRN("Could not initialize LDC channel %lu,"
+		    "reg_callback failed with error %d", ldc_id, status);
 		return (status);
 	}
 
 	if ((status = ldc_open(vd->ldc_handle)) != 0) {
-		PR0("ldc_open() returned errno %d", status);
+		PRN("Could not initialize LDC channel %lu,"
+		    "open failed with error %d", ldc_id, status);
 		return (status);
 	}
 
@@ -2981,7 +3112,8 @@
 	/* Allocate the inband task memory handle */
 	status = ldc_mem_alloc_handle(vd->ldc_handle, &(vd->inband_task.mhdl));
 	if (status) {
-		PR0("ldc_mem_alloc_handle() returned err %d ", status);
+		PRN("Could not initialize LDC channel %lu,"
+		    "alloc_handle failed with error %d", ldc_id, status);
 		return (ENXIO);
 	}
 
@@ -3097,21 +3229,18 @@
 		kmem_free(vd->inband_task.msg, vd->max_msglen);
 		vd->inband_task.msg = NULL;
 	}
-	if (vd->initialized & VD_DISK_READY) {
-		if (vd->file) {
-			/* Unmap and close file */
-			(void) as_unmap(&kas, vd->file_maddr, vd->file_size);
-			(void) VOP_CLOSE(vd->file_vnode, vd_open_flags, 1,
-			    0, kcred);
-			VN_RELE(vd->file_vnode);
-		} else {
-			/* Close any open backing-device slices */
-			for (uint_t slice = 0; slice < vd->nslices; slice++) {
-				if (vd->ldi_handle[slice] != NULL) {
-					PR0("Closing slice %u", slice);
-					(void) ldi_close(vd->ldi_handle[slice],
-					    vd_open_flags | FNDELAY, kcred);
-				}
+	if (vd->file) {
+		/* Close file */
+		(void) VOP_CLOSE(vd->file_vnode, vd_open_flags, 1,
+		    0, kcred);
+		VN_RELE(vd->file_vnode);
+	} else {
+		/* Close any open backing-device slices */
+		for (uint_t slice = 0; slice < vd->nslices; slice++) {
+			if (vd->ldi_handle[slice] != NULL) {
+				PR0("Closing slice %u", slice);
+				(void) ldi_close(vd->ldi_handle[slice],
+				    vd_open_flags | FNDELAY, kcred);
 			}
 		}
 	}