Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Oct 2019 03:57:56 +0000 (UTC)
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r354007 - in stable/12/stand: . common efi/loader i386/loader
Message-ID:  <201910240357.x9O3vuIv037608@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevans
Date: Thu Oct 24 03:57:56 2019
New Revision: 354007
URL: https://svnweb.freebsd.org/changeset/base/354007

Log:
  MFC r346759: loader: implement map-vdisk and unmap-vdisk commands
  
  illumos update: https://www.illumos.org/issues/10598
  
  Add map-vdisk and unmap-vdisk commands to create virtual disk interface on
  top of file. This will allow to use disk image from file system to load and
  start the kernel.
  
  By mapping file, we create vdiskX device, the device will be listed by lsdev
  [-v] and can be accessed directly as ls vdisk0p1:/path or can be used as
  value for currdev variable.
  
  vdisk strategy function does not use bcache as we have bcache used with
  backing file. vdisk can be unmapped when all consumers have closed the open
  files.
  
  In first iteration we do not support the zfs images because zfs pools do
  keep the device open (there is no "zpool export" mechanism). Adding zfs
  support is relatively simple, we just need to run zfs disk probe after
  mapping is done.

Added:
  stable/12/stand/common/vdisk.c
     - copied unchanged from r346759, head/stand/common/vdisk.c
Modified:
  stable/12/stand/common/help.common
  stable/12/stand/efi/loader/conf.c
  stable/12/stand/i386/loader/conf.c
  stable/12/stand/loader.mk
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/stand/common/help.common
==============================================================================
--- stable/12/stand/common/help.common	Thu Oct 24 03:52:32 2019	(r354006)
+++ stable/12/stand/common/help.common	Thu Oct 24 03:57:56 2019	(r354007)
@@ -99,6 +99,13 @@
 	List loaded modules. If [-v] is specified, print more details.
 
 ################################################################################
+# Tmap-vdisk DMap virtual disk
+
+	map-vdisk filename
+
+	Map file as virtual disk.
+
+################################################################################
 # Tmore DPage files
 
 	more <filename> [<filename> ...]
@@ -395,6 +402,13 @@
 	unload
 
 	This command removes any kernel and all loaded modules from memory.
+
+################################################################################
+# Tunmap-vdisk DUnmap virtual disk
+
+	unmap-vdisk diskname
+
+	Delete virtual disk mapping.
 
 ################################################################################
 # Tunset DUnset a variable

Copied: stable/12/stand/common/vdisk.c (from r346759, head/stand/common/vdisk.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/stand/common/vdisk.c	Thu Oct 24 03:57:56 2019	(r354007, copy of r346759, head/stand/common/vdisk.c)
@@ -0,0 +1,417 @@
+/*-
+ * Copyright 2019 Toomas Soome <tsoome@me.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <stdarg.h>
+#include <machine/_inttypes.h>
+#include <bootstrap.h>
+#include <sys/disk.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <disk.h>
+
+static int vdisk_init(void);
+static int vdisk_strategy(void *, int, daddr_t, size_t, char *, size_t *);
+static int vdisk_open(struct open_file *, ...);
+static int vdisk_close(struct open_file *);
+static int vdisk_ioctl(struct open_file *, u_long, void *);
+static int vdisk_print(int);
+
+struct devsw vdisk_dev = {
+	.dv_name = "vdisk",
+	.dv_type = DEVT_DISK,
+	.dv_init = vdisk_init,
+	.dv_strategy = vdisk_strategy,
+	.dv_open = vdisk_open,
+	.dv_close = vdisk_close,
+	.dv_ioctl = vdisk_ioctl,
+	.dv_print = vdisk_print,
+	.dv_cleanup = NULL
+};
+
+typedef STAILQ_HEAD(vdisk_info_list, vdisk_info) vdisk_info_list_t;
+
+typedef struct vdisk_info
+{
+	STAILQ_ENTRY(vdisk_info)	vdisk_link; /* link in device list */
+	char			*vdisk_path;
+	int			vdisk_unit;
+	int			vdisk_fd;
+	uint64_t		vdisk_size;	/* size in bytes */
+	uint32_t		vdisk_sectorsz;
+	uint32_t		vdisk_open;	/* reference counter */
+} vdisk_info_t;
+
+static vdisk_info_list_t vdisk_list;	/* list of mapped vdisks. */
+
+static vdisk_info_t *
+vdisk_get_info(struct devdesc *dev)
+{
+	vdisk_info_t *vd;
+
+	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
+		if (vd->vdisk_unit == dev->d_unit)
+			return (vd);
+	}
+	return (vd);
+}
+
+COMMAND_SET(map_vdisk, "map-vdisk", "map file as virtual disk", command_mapvd);
+
+static int
+command_mapvd(int argc, char *argv[])
+{
+	vdisk_info_t *vd, *p;
+	struct stat sb;
+
+	if (argc != 2) {
+		printf("usage: %s filename\n", argv[0]);
+		return (CMD_ERROR);
+	}
+
+	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
+		if (strcmp(vd->vdisk_path, argv[1]) == 0) {
+			printf("%s: file %s is already mapped as %s%d\n",
+			    argv[0], argv[1], vdisk_dev.dv_name,
+			    vd->vdisk_unit);
+			return (CMD_ERROR);
+		}
+	}
+
+	if (stat(argv[1], &sb) < 0) {
+		/*
+		 * ENOSYS is really ENOENT because we did try to walk
+		 * through devsw list to try to open this file.
+		 */
+		if (errno == ENOSYS)
+			errno = ENOENT;
+
+		printf("%s: stat failed: %s\n", argv[0], strerror(errno));
+		return (CMD_ERROR);
+	}
+
+	/*
+	 * Avoid mapping small files.
+	 */
+	if (sb.st_size < 1024 * 1024) {
+		printf("%s: file %s is too small.\n", argv[0], argv[1]);
+		return (CMD_ERROR);
+	}
+
+	vd = calloc(1, sizeof (*vd));
+	if (vd == NULL) {
+		printf("%s: out of memory\n", argv[0]);
+		return (CMD_ERROR);
+	}
+	vd->vdisk_path = strdup(argv[1]);
+	if (vd->vdisk_path == NULL) {
+		free (vd);
+		printf("%s: out of memory\n", argv[0]);
+		return (CMD_ERROR);
+	}
+	vd->vdisk_fd = open(vd->vdisk_path, O_RDONLY);
+	if (vd->vdisk_fd < 0) {
+		printf("%s: open failed: %s\n", argv[0], strerror(errno));
+		free(vd->vdisk_path);
+		free(vd);
+		return (CMD_ERROR);
+	}
+
+	vd->vdisk_size = sb.st_size;
+	vd->vdisk_sectorsz = DEV_BSIZE;
+	STAILQ_FOREACH(p, &vdisk_list, vdisk_link) {
+		vdisk_info_t *n;
+		if (p->vdisk_unit == vd->vdisk_unit) {
+			vd->vdisk_unit++;
+			continue;
+		}
+		n = STAILQ_NEXT(p, vdisk_link);
+		if (p->vdisk_unit < vd->vdisk_unit) {
+			if (n == NULL) {
+				/* p is last elem */
+				STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link);
+				break;
+			}
+			if (n->vdisk_unit > vd->vdisk_unit) {
+				/* p < vd < n */
+				STAILQ_INSERT_AFTER(&vdisk_list, p, vd,
+				    vdisk_link);
+				break;
+			}
+			/* else n < vd or n == vd */
+			vd->vdisk_unit++;
+			continue;
+		}
+		/* p > vd only if p is the first element */
+		STAILQ_INSERT_HEAD(&vdisk_list, vd, vdisk_link);
+		break;
+	}
+
+	/* if the list was empty or contiguous */
+	if (p == NULL)
+		STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link);
+
+	printf("%s: file %s is mapped as %s%d\n", argv[0], vd->vdisk_path,
+	    vdisk_dev.dv_name, vd->vdisk_unit);
+	return (CMD_OK);
+}
+
+COMMAND_SET(unmap_vdisk, "unmap-vdisk", "unmap virtual disk", command_unmapvd);
+
+/*
+ * unmap-vdisk vdiskX
+ */
+static int
+command_unmapvd(int argc, char *argv[])
+{
+	size_t len;
+	vdisk_info_t *vd;
+	long unit;
+	char *end;
+
+	if (argc != 2) {
+		printf("usage: %s %sN\n", argv[0], vdisk_dev.dv_name);
+		return (CMD_ERROR);
+	}
+
+	len = strlen(vdisk_dev.dv_name);
+	if (strncmp(vdisk_dev.dv_name, argv[1], len) != 0) {
+		printf("%s: unknown device %s\n", argv[0], argv[1]);
+		return (CMD_ERROR);
+	}
+	errno = 0;
+	unit = strtol(argv[1] + len, &end, 10);
+	if (errno != 0 || (*end != '\0' && strcmp(end, ":") != 0)) {
+		printf("%s: unknown device %s\n", argv[0], argv[1]);
+		return (CMD_ERROR);
+	}
+
+	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
+		if (vd->vdisk_unit == unit)
+			break;
+	}
+
+	if (vd == NULL) {
+		printf("%s: unknown device %s\n", argv[0], argv[1]);
+		return (CMD_ERROR);
+	}
+
+	if (vd->vdisk_open != 0) {
+		printf("%s: %s is in use, unable to unmap.\n",
+		    argv[0], argv[1]);
+		return (CMD_ERROR);
+	}
+
+	STAILQ_REMOVE(&vdisk_list, vd, vdisk_info, vdisk_link);
+	close(vd->vdisk_fd);
+	free(vd->vdisk_path);
+	free(vd);
+	printf("%s (%s) unmapped\n", argv[1], vd->vdisk_path);
+
+	return (CMD_OK);
+}
+
+static int
+vdisk_init(void)
+{
+	STAILQ_INIT(&vdisk_list);
+	return (0);
+}
+
+static int
+vdisk_strategy(void *devdata, int rw, daddr_t blk, size_t size,
+    char *buf, size_t *rsize)
+{
+	struct disk_devdesc *dev;
+	vdisk_info_t *vd;
+	ssize_t rv;
+
+	dev = devdata;
+	if (dev == NULL)
+		return (EINVAL);
+	vd = vdisk_get_info((struct devdesc *)dev);
+	if (vd == NULL)
+		return (EINVAL);
+
+	if (size == 0 || (size % 512) != 0)
+		return (EIO);
+
+	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+		daddr_t offset;
+
+		offset = dev->d_offset * vd->vdisk_sectorsz;
+		offset /= 512;
+		blk += offset;
+	}
+	if (lseek(vd->vdisk_fd, blk << 9, SEEK_SET) == -1)
+		return (EIO);
+
+	errno = 0;
+	switch (rw & F_MASK) {
+	case F_READ:
+		rv = read(vd->vdisk_fd, buf, size);
+		break;
+	case F_WRITE:
+		rv = write(vd->vdisk_fd, buf, size);
+		break;
+	default:
+		return (ENOSYS);
+	}
+
+	if (errno == 0 && rsize != NULL) {
+		*rsize = rv;
+	}
+	return (errno);
+}
+
+static int
+vdisk_open(struct open_file *f, ...)
+{
+	va_list args;
+	struct disk_devdesc *dev;
+	vdisk_info_t *vd;
+	int rc = 0;
+
+	va_start(args, f);
+	dev = va_arg(args, struct disk_devdesc *);
+	va_end(args);
+	if (dev == NULL)
+		return (EINVAL);
+	vd = vdisk_get_info((struct devdesc *)dev);
+	if (vd == NULL)
+		return (EINVAL);
+
+	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+		rc = disk_open(dev, vd->vdisk_size, vd->vdisk_sectorsz);
+	}
+	if (rc == 0)
+		vd->vdisk_open++;
+	return (rc);
+}
+
+static int
+vdisk_close(struct open_file *f)
+{
+	struct disk_devdesc *dev;
+	vdisk_info_t *vd;
+
+	dev = (struct disk_devdesc *)(f->f_devdata);
+	if (dev == NULL)
+		return (EINVAL);
+	vd = vdisk_get_info((struct devdesc *)dev);
+	if (vd == NULL)
+		return (EINVAL);
+
+	vd->vdisk_open--;
+	if (dev->dd.d_dev->dv_type == DEVT_DISK)
+		return (disk_close(dev));
+	return (0);
+}
+
+static int
+vdisk_ioctl(struct open_file *f, u_long cmd, void *data)
+{
+	struct disk_devdesc *dev;
+	vdisk_info_t *vd;
+	int rc;
+
+	dev = (struct disk_devdesc *)(f->f_devdata);
+	if (dev == NULL)
+		return (EINVAL);
+	vd = vdisk_get_info((struct devdesc *)dev);
+	if (vd == NULL)
+		return (EINVAL);
+
+	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+		rc = disk_ioctl(dev, cmd, data);
+		if (rc != ENOTTY)
+			return (rc);
+	}
+
+	switch (cmd) {
+	case DIOCGSECTORSIZE:
+		*(u_int *)data = vd->vdisk_sectorsz;
+		break;
+	case DIOCGMEDIASIZE:
+		*(uint64_t *)data = vd->vdisk_size;
+		break;
+	default:
+		return (ENOTTY);
+	}
+	return (0);
+}
+
+static int
+vdisk_print(int verbose)
+{
+	int ret = 0;
+	vdisk_info_t *vd;
+	char line[80];
+
+	if (STAILQ_EMPTY(&vdisk_list))
+		return (ret);
+
+	printf("%s devices:", vdisk_dev.dv_name);
+	if ((ret = pager_output("\n")) != 0)
+		return (ret);
+
+	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
+		struct disk_devdesc vd_dev;
+
+		if (verbose) {
+			printf("  %s", vd->vdisk_path);
+			if ((ret = pager_output("\n")) != 0)
+				break;
+		}
+		snprintf(line, sizeof(line),
+		    "    %s%d", vdisk_dev.dv_name, vd->vdisk_unit);
+		printf("%s:    %" PRIu64 " X %u blocks", line,
+		    vd->vdisk_size / vd->vdisk_sectorsz,
+		    vd->vdisk_sectorsz);
+		if ((ret = pager_output("\n")) != 0)
+			break;
+
+		vd_dev.dd.d_dev = &vdisk_dev;
+		vd_dev.dd.d_unit = vd->vdisk_unit;
+		vd_dev.d_slice = -1;
+		vd_dev.d_partition = -1;
+
+		ret = disk_open(&vd_dev, vd->vdisk_size, vd->vdisk_sectorsz);
+		if (ret == 0) {
+			ret = disk_print(&vd_dev, line, verbose);
+			disk_close(&vd_dev);
+			if (ret != 0)
+				break;
+		} else {
+			ret = 0;
+		}
+	}
+
+	return (ret);
+}

Modified: stable/12/stand/efi/loader/conf.c
==============================================================================
--- stable/12/stand/efi/loader/conf.c	Thu Oct 24 03:52:32 2019	(r354006)
+++ stable/12/stand/efi/loader/conf.c	Thu Oct 24 03:57:56 2019	(r354007)
@@ -33,11 +33,14 @@ __FBSDID("$FreeBSD$");
 #include <efilib.h>
 #include <efizfs.h>
 
+extern struct devsw vdisk_dev;
+
 struct devsw *devsw[] = {
 	&efipart_fddev,
 	&efipart_cddev,
 	&efipart_hddev,
 	&efinet_dev,
+	&vdisk_dev,
 #ifdef EFI_ZFS_BOOT
 	&zfs_dev,
 #endif

Modified: stable/12/stand/i386/loader/conf.c
==============================================================================
--- stable/12/stand/i386/loader/conf.c	Thu Oct 24 03:52:32 2019	(r354006)
+++ stable/12/stand/i386/loader/conf.c	Thu Oct 24 03:57:56 2019	(r354007)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #if defined(LOADER_FIREWIRE_SUPPORT)
 extern struct devsw fwohci;
 #endif
+extern struct devsw vdisk_dev;
 
 /* Exported for libstand */
 struct devsw *devsw[] = {
@@ -60,6 +61,7 @@ struct devsw *devsw[] = {
 #if defined(LOADER_FIREWIRE_SUPPORT)
     &fwohci,
 #endif
+    &vdisk_dev,
 #if defined(LOADER_ZFS_SUPPORT)
     &zfs_dev,
 #endif

Modified: stable/12/stand/loader.mk
==============================================================================
--- stable/12/stand/loader.mk	Thu Oct 24 03:52:32 2019	(r354006)
+++ stable/12/stand/loader.mk	Thu Oct 24 03:57:56 2019	(r354007)
@@ -31,7 +31,7 @@ SRCS+=	metadata.c
 .endif
 
 .if ${LOADER_DISK_SUPPORT:Uyes} == "yes"
-SRCS+=	disk.c part.c
+SRCS+=	disk.c part.c vdisk.c
 .endif
 
 .if ${LOADER_NET_SUPPORT:Uno} == "yes"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910240357.x9O3vuIv037608>