18,0)
des="UNIX domain socket" dev=uds
;;
+ 5[6-9],0|6[0-3],0)
+ drive=`expr $major - 56`
+ des="vnode disk $drive" dev=vnd$drive
+ ;;
+ 5[6-9],[1-4]|6[0-3],[1-4])
+ drive=`expr $major - 56`
+ par=`expr $minor - 1`
+ des="vnode disk $drive partition $par" dev=vnd${drive}p${par}
+ ;;
+ 5[6-9],12[89]|5[6-9],13[0-9]|5[6-9],14[0-3]|6[0-3],12[89]|5[6-9],13[0-9]|5[6-9],14[0-3])
+ drive=`expr $major - 56`
+ par=`expr \\( \\( $minor - 128 \\) / 4 \\) % 4`
+ sub=`expr \\( $minor - 128 \\) % 4`
+ des="vnode disk $drive partition $par slice $sub"
+ dev=vnd${drive}p${par}s${sub}
+ ;;
BAD,BAD)
des= dev=
;;
eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57 \
tsl2550b1s39 tsl2550b2s39 tsl2550b3s39 \
sht21b1s40 sht21b2s40 sht21b3s40 \
- bmp085b1s77 bmp085b2s77 bmp085b3s77
+ bmp085b1s77 bmp085b2s77 bmp085b3s77 \
+ vnd0 vnd0p0 vnd0p0s0 vnd1 vnd1p0 vnd1p0s0 \
+ vnd2 vnd3 vnd4 vnd5 vnd6 vnd7
;;
0:|1:-\?)
cat >&2 <<EOF
fbd # Make /dev/fbd
hello # Make /dev/hello
video # Make /dev/video
+ vnd0 vnd0p0 vnd0p0s0 .. # Make vnode disks /dev/vnd[0-7] and (sub)partitions
std # All standard devices
EOF
exit 1
$e mknod bmp085b${b}s77 c ${m} 0
$e chmod 444 bmp085b${b}s77
;;
+ vnd[0-7])
+ # Whole vnode disk devices.
+ d=`expr $dev : 'vnd\\(.\\)'` # Disk number.
+ maj=`expr $d + 56` # Major device number.
+ $e mknod $dev b $maj 0
+ $e chmod 600 $dev
+ ;;
+ vnd[0-7]p[0-3])
+ # Vnode disk primary partitions.
+ n=`expr $dev : '\\(.*\\).'` # Name prefix.
+ d=`expr $dev : 'vnd\\(.\\)'` # Disk number.
+ maj=`expr $d + 56` # Major device number.
+ alldev=
+
+ for p in 0 1 2 3
+ do
+ m=`expr 1 + $p` # Minor device number.
+ $e mknod $n$p b $maj $m
+ alldev="$alldev $n$p"
+ done
+ echo $alldev | xargs $e chmod 600
+ ;;
+ vnd[0-7]p[0-3]s[0-3])
+ # Vnode disk subpartition.
+ n=`expr $dev : '\\(.*\\)...'` # Name prefix.
+ d=`expr $dev : 'vnd\\(.\\)'` # Disk number.
+ maj=`expr $d + 56` # Major device number.
+ alldev=
+
+ for p in 0 1 2 3
+ do
+ for s in 0 1 2 3
+ do
+ m=`expr 128 + $p '*' 4 + $s` # Minor device number.
+ $e mknod ${n}${p}s${s} b $maj $m
+ alldev="$alldev ${n}${p}s${s}"
+ done
+ done
+ echo $alldev | xargs $e chmod 600
+ ;;
*)
echo "$0: don't know about $dev" >&2
ex=1
./usr/include/dev minix-sys
./usr/include/dev/i2c minix-sys
./usr/include/dev/i2c/i2c_io.h minix-sys
+./usr/include/dev/vndvar.h minix-sys
./usr/include/dirent.h minix-sys
./usr/include/disktab.h minix-sys
./usr/include/dlfcn.h minix-sys
./usr/sbin/vfs minix-sys
./usr/sbin/vipw minix-sys
./usr/sbin/vm minix-sys
+./usr/sbin/vnd minix-sys
./usr/sbin/zic minix-sys
./usr/share minix-sys
./usr/share/atf minix-sys atf
SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
e1000 fbd filter floppy fxp hello lance log mmc orinoco pci printer \
random readclock rtl8139 rtl8169 ti1225 tty vbox acpi \
- virtio_blk virtio_net
+ virtio_blk virtio_net vnd
.endif
.if ${MACHINE_ARCH} == "earm"
SUBDIR= bmp085 cat24c256 fb gpio i2c mmc lan8710a log readclock \
- sht21 tda19988 tps65217 tps65950 tsl2550 tty random
+ sht21 tda19988 tps65217 tps65950 tsl2550 tty random vnd
.endif
.endif # ${MKIMAGEONLY} != "yes"
--- /dev/null
+# Makefile for the VNode Disk driver (VND)
+PROG= vnd
+SRCS= vnd.c
+
+DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS}
+LDADD+= -lblockdriver -lsys
+
+MAN=
+
+BINDIR?= /usr/sbin
+
+.include <minix.service.mk>
--- /dev/null
+Development notes regarding VND. Original document by David van Moolenbroek.
+
+
+DESIGN DECISIONS
+
+As simple as the VND driver implementation looks, several important decisions
+had to be made in the design process. These decisions are listed here.
+
+Multiple instances instead of a single instance: The decision to spawn a
+separate driver instance for each VND unit was not ideologically inspired, but
+rather based on a practical issue. Namely, users may reasonably expect to be
+able to set up a VND using a backing file that resides on a file system hosted
+on another VND. If one single driver instance were to host both VND units, its
+implementation would have to perform all its backcalls to VFS asynchronously,
+so as to be able to process another incoming request that was initiated as part
+of such an ongoing backcall. As of writing, MINIX3 does not support any form of
+asynchronous I/O, but this would not even be sufficient: the asynchrony would
+have to extend even to the close(2) call that takes place during device
+unconfiguration, as this call could spark I/O to another VND device.
+Ultimately, using one driver instance per VND unit avoids these complications
+altogether, thus making nesting possible with a maximum depth of the number of
+VFS threads. Of course, this comes at the cost of having more VND driver
+processes; in order to avoid this cost in the common case, driver instances are
+dynamically started and stopped by vndconfig(8).
+
+dupfrom(2) instead of openas(2): Compared to the NetBSD interface, the MINIX3
+VND API requires that the user program configuring a device pass in a file
+descriptor in the vnd_ioctl structure instead of a pointer to a path name.
+While binary compatibility with NetBSD would be impossible anyway (MINIX3 can
+not support pointers in IOCTL data structures), providing a path name buffer
+would be closer to what NetBSD does. There are two reasons behind the choice to
+pass in a file descriptor instead. First, performing an open(2)-like call as
+a driver backcall is tricky in terms of avoiding deadlocks in VFS, since it
+would by nature violate the VFS locking order. On top of that, special
+provisions would have to be added to support opening a file in the context of
+another process so that chrooted processes would be supported, for example.
+In contrast, copying a file descriptor to a remote process is relatively easy
+because there is only one potential deadlock case to cover - that of the given
+file descriptor identifying the VFS filp object used to control the very same
+device - and VFS need only implement a procedure that very much resembles
+sending a file descriptor across a UNIX domain socket. Second, since passing a
+file descriptor is effectively passing an object capability, it is easier to
+improve the isolation of the VND drivers in the future, as described below.
+
+No separate control device: The driver uses the same minor (block) device for
+configuration and for actual (whole-disk) I/O, instead of exposing a separate
+device that exists only for the purpose of configuring the device. The reason
+for this is that such a control device simply does not fit the NetBSD
+opendisk(3) API. While MINIX3 may at some point implement support for NetBSD's
+notion of raw devices, such raw devices are still expected to support I/O, and
+that means they cannot be control-only. In this regard, it should be mentioned
+that the entire VND infrastructure relies on block caches being invalidated
+properly upon (un)configuration of VND units, and that such invalidation
+(through the REQ_FLUSH file system request) is currently initiated only by
+closing block devices. Support for configuration or I/O through character
+devices would thus require more work on that side first. In any case, the
+primary downside of not having a separate control device is that handling
+access permissions on device open is a bit of a hack in order to keep the
+MINIX3 userland happy.
+
+
+FUTURE IMPROVEMENTS
+
+Currently, the VND driver instances are run as root just and only because the
+dupfrom(2) call requires root. Obviously, nonroot user processes should never
+be able to copy file descriptors from arbitrary processes, and thus, some
+security check is required there. However, an access control list for VFS calls
+would be a much better solution: in that case, VND driver processes can be
+given exclusive rights to the use of the dupfrom(2) call, while they can be
+given a normal driver UID at the same time.
+
+In MINIX3's dependability model, drivers are generally not considered to be
+malicious. However, the VND case is interesting because it is possible to
+isolate individual driver instances to the point of actual "least authority".
+The dupfrom(2) call currently allows any file descriptor to be copied, but it
+would be possible to extend the scheme to let user processes (and vndconfig(8)
+in particular) mark the file descriptors that may be the target of a dupfrom(2)
+call. One of several schemes may be implemented in VFS for this purpose. For
+example, each process could be allowed to mark one of its file descriptors as
+"copyable" using a new VFS call, and VFS would then allow dupfrom(2) only on a
+"copyable" file descriptor from a process blocked on a call to the driver that
+invoked dupfrom(2). This approach precludes hiding a VND driver behind a RAID
+or FBD (etc) driver, but more sophisticated approaches can solve that as well.
+Regardless of the scheme, the end result would be a situation where the VND
+drivers are strictly limited to operating on the resources given to them.
--- /dev/null
+/* VNode Disk driver, by D.C. van Moolenbroek <david@minix3.org> */
+
+#include <minix/drivers.h>
+#include <minix/blockdriver.h>
+#include <minix/drvlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define VND_BUF_SIZE 65536
+
+static struct {
+ int fd; /* file descriptor for the underlying file */
+ int openct; /* number of times the device is open */
+ int exiting; /* exit after the last close? */
+ int rdonly; /* is the device set up read-only? */
+ dev_t dev; /* device on which the file resides */
+ ino_t ino; /* inode number of the file */
+ struct device part[DEV_PER_DRIVE]; /* partition bases and sizes */
+ struct device subpart[SUB_PER_DRIVE]; /* same for subpartitions */
+ struct part_geom geom; /* geometry information */
+ char *buf; /* intermediate I/O transfer buffer */
+} state;
+
+static unsigned int instance;
+
+static int vnd_open(devminor_t, int);
+static int vnd_close(devminor_t);
+static int vnd_transfer(devminor_t, int, u64_t, endpoint_t, iovec_t *,
+ unsigned int, int);
+static int vnd_ioctl(devminor_t, unsigned long, endpoint_t, cp_grant_id_t,
+ endpoint_t);
+static struct device *vnd_part(devminor_t);
+static void vnd_geometry(devminor_t, struct part_geom *);
+
+static struct blockdriver vnd_dtab = {
+ .bdr_type = BLOCKDRIVER_TYPE_DISK,
+ .bdr_open = vnd_open,
+ .bdr_close = vnd_close,
+ .bdr_transfer = vnd_transfer,
+ .bdr_ioctl = vnd_ioctl,
+ .bdr_part = vnd_part,
+ .bdr_geometry = vnd_geometry
+};
+
+/*
+ * Parse partition tables.
+ */
+static void
+vnd_partition(void)
+{
+ memset(state.part, 0, sizeof(state.part));
+ memset(state.subpart, 0, sizeof(state.subpart));
+
+ state.part[0].dv_size = state.geom.size;
+
+ partition(&vnd_dtab, 0, P_PRIMARY, FALSE /*atapi*/);
+}
+
+/*
+ * Open a device.
+ */
+static int
+vnd_open(devminor_t minor, int access)
+{
+ /* No sub/partition devices are available before initialization. */
+ if (state.fd == -1 && minor != 0)
+ return ENXIO;
+ else if (state.fd != -1 && vnd_part(minor) == NULL)
+ return ENXIO;
+
+ /*
+ * If the device either is not configured or configured as read-only,
+ * block open calls that request write permission. This is what user-
+ * land expects, although it does mean that vnconfig(8) has to open the
+ * device as read-only in order to (un)configure it.
+ */
+ if (access & BDEV_W_BIT) {
+ if (state.fd == -1)
+ return ENXIO;
+ if (state.rdonly)
+ return EACCES;
+ }
+
+ /*
+ * Userland expects that if the device is opened after having been
+ * fully closed, partition tables are (re)parsed. Since we already
+ * parse partition tables upon initialization, we could skip this for
+ * the first open, but that would introduce more state.
+ */
+ if (state.fd != -1 && state.openct == 0) {
+ vnd_partition();
+
+ /* Make sure our target device didn't just disappear. */
+ if (vnd_part(minor) == NULL)
+ return ENXIO;
+ }
+
+ state.openct++;
+
+ return OK;
+}
+
+/*
+ * Close a device.
+ */
+static int
+vnd_close(devminor_t UNUSED(minor))
+{
+ if (state.openct == 0) {
+ printf("VND%u: closing already-closed device\n", instance);
+ return EINVAL;
+ }
+
+ state.openct--;
+
+ if (state.exiting)
+ blockdriver_terminate();
+
+ return OK;
+}
+
+/*
+ * Copy a number of bytes from or to the caller, to or from the intermediate
+ * buffer. If the given endpoint is SELF, a local memory copy must be made.
+ */
+static int
+vnd_copy(iovec_s_t *iov, size_t iov_off, size_t bytes, endpoint_t endpt,
+ int do_write)
+{
+ struct vscp_vec vvec[SCPVEC_NR], *vvp;
+ size_t off, chunk;
+ int count;
+ char *ptr;
+
+ assert(bytes > 0 && bytes <= VND_BUF_SIZE);
+
+ vvp = vvec;
+ count = 0;
+
+ for (off = 0; off < bytes; off += chunk) {
+ chunk = MIN(bytes - off, iov->iov_size - iov_off);
+
+ if (endpt == SELF) {
+ ptr = (char *) iov->iov_grant + iov_off;
+
+ if (do_write)
+ memcpy(&state.buf[off], ptr, chunk);
+ else
+ memcpy(ptr, &state.buf[off], chunk);
+ } else {
+ assert(count < SCPVEC_NR); /* SCPVEC_NR >= NR_IOREQS */
+
+ vvp->v_from = do_write ? endpt : SELF;
+ vvp->v_to = do_write ? SELF : endpt;
+ vvp->v_bytes = chunk;
+ vvp->v_gid = iov->iov_grant;
+ vvp->v_offset = iov_off;
+ vvp->v_addr = (vir_bytes) &state.buf[off];
+
+ vvp++;
+ count++;
+ }
+
+ iov_off += chunk;
+ if (iov_off == iov->iov_size) {
+ iov++;
+ iov_off = 0;
+ }
+ }
+
+ if (endpt != SELF)
+ return sys_vsafecopy(vvec, count);
+ else
+ return OK;
+}
+
+/*
+ * Advance the given I/O vector, and the offset into its first element, by the
+ * given number of bytes.
+ */
+static iovec_s_t *
+vnd_advance(iovec_s_t *iov, size_t *iov_offp, size_t bytes)
+{
+ size_t iov_off;
+
+ assert(bytes > 0 && bytes <= VND_BUF_SIZE);
+
+ iov_off = *iov_offp;
+
+ while (bytes > 0) {
+ if (bytes >= iov->iov_size - iov_off) {
+ bytes -= iov->iov_size - iov_off;
+ iov++;
+ iov_off = 0;
+ } else {
+ iov_off += bytes;
+ bytes = 0;
+ }
+ }
+
+ *iov_offp = iov_off;
+ return iov;
+}
+
+/*
+ * Perform data transfer on the selected device.
+ */
+static int
+vnd_transfer(devminor_t minor, int do_write, u64_t position,
+ endpoint_t endpt, iovec_t *iovt, unsigned int nr_req, int flags)
+{
+ struct device *dv;
+ iovec_s_t *iov;
+ size_t off, chunk, bytes, iov_off;
+ ssize_t r;
+ unsigned int i;
+
+ iov = (iovec_s_t *) iovt;
+
+ if (state.fd == -1 || (dv = vnd_part(minor)) == NULL)
+ return ENXIO;
+
+ /* Prevent write operations on devices opened as write-only. */
+ if (do_write && state.rdonly)
+ return EACCES;
+
+ /* Determine the total number of bytes to transfer. */
+ if (position >= dv->dv_size)
+ return 0;
+
+ bytes = 0;
+
+ for (i = 0; i < nr_req; i++) {
+ if (iov[i].iov_size == 0 || iov[i].iov_size > LONG_MAX)
+ return EINVAL;
+ bytes += iov[i].iov_size;
+ if (bytes > LONG_MAX)
+ return EINVAL;
+ }
+
+ if (bytes > dv->dv_size - position)
+ bytes = dv->dv_size - position;
+
+ position += dv->dv_base;
+
+ /* Perform the actual transfer, in chunks if necessary. */
+ iov_off = 0;
+
+ for (off = 0; off < bytes; off += chunk) {
+ chunk = MIN(bytes - off, VND_BUF_SIZE);
+
+ assert((unsigned int) (iov - (iovec_s_t *) iovt) < nr_req);
+
+ /* For reads, read in the data for the chunk; possibly less. */
+ if (!do_write) {
+ chunk = r = pread64(state.fd, state.buf, chunk,
+ position);
+
+ if (r < 0) {
+ printf("VND%u: pread failed (%d)\n", instance,
+ -errno);
+ return -errno;
+ }
+ if (r == 0)
+ break;
+ }
+
+ /* Copy the data for this chunk from or to the caller. */
+ if ((r = vnd_copy(iov, iov_off, chunk, endpt, do_write)) < 0) {
+ printf("VND%u: data copy failed (%d)\n", instance, r);
+ return r;
+ }
+
+ /* For writes, write the data to the file; possibly less. */
+ if (do_write) {
+ chunk = r = pwrite64(state.fd, state.buf, chunk,
+ position);
+
+ if (r <= 0) {
+ if (r < 0)
+ r = -errno;
+ printf("VND%u: pwrite failed (%d)\n", instance,
+ r);
+ return (r < 0) ? r : EIO;
+ }
+ }
+
+ /* Move ahead on the I/O vector and the file position. */
+ iov = vnd_advance(iov, &iov_off, chunk);
+
+ position += chunk;
+ }
+
+ /* If force-write is requested, flush the underlying file to disk. */
+ if (do_write && (flags & BDEV_FORCEWRITE))
+ fsync(state.fd);
+
+ /* Return the number of bytes transferred. */
+ return off;
+}
+
+/*
+ * Initialize the size and geometry for the device and any partitions. If the
+ * user provided a geometry, this will be used; otherwise, a geometry will be
+ * computed.
+ */
+static int
+vnd_layout(u64_t size, struct vnd_ioctl *vnd)
+{
+ u64_t sectors;
+
+ state.geom.base = 0ULL;
+
+ if (vnd->vnd_flags & VNDIOF_HASGEOM) {
+ /*
+ * The geometry determines the accessible part of the file.
+ * The resulting size must not exceed the file size.
+ */
+ state.geom.cylinders = vnd->vnd_geom.vng_ncylinders;
+ state.geom.heads = vnd->vnd_geom.vng_ntracks;
+ state.geom.sectors = vnd->vnd_geom.vng_nsectors;
+
+ state.geom.size = (u64_t) state.geom.cylinders *
+ state.geom.heads * state.geom.sectors *
+ vnd->vnd_geom.vng_secsize;
+ if (state.geom.size == 0 || state.geom.size > size)
+ return EINVAL;
+ } else {
+ sectors = size / SECTOR_SIZE;
+ state.geom.size = sectors * SECTOR_SIZE;
+
+ if (sectors >= 32 * 64) {
+ state.geom.cylinders = sectors / (32 * 64);
+ state.geom.heads = 64;
+ state.geom.sectors = 32;
+ } else {
+ state.geom.cylinders = sectors;
+ state.geom.heads = 1;
+ state.geom.sectors = 1;
+ }
+ }
+
+ /*
+ * Parse partition tables immediately, so that (sub)partitions can be
+ * opened right away. The first open will perform the same procedure,
+ * but that is only necessary to match userland expectations.
+ */
+ vnd_partition();
+
+ return OK;
+}
+
+/*
+ * Process I/O control requests.
+ */
+static int
+vnd_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt,
+ cp_grant_id_t grant, endpoint_t user_endpt)
+{
+ struct vnd_ioctl vnd;
+ struct vnd_user vnu;
+ struct stat st;
+ int r;
+
+ switch (request) {
+ case VNDIOCSET:
+ /*
+ * The VND must not be busy. Note that the caller has the
+ * device open to perform the IOCTL request.
+ */
+ if (state.fd != -1 || state.openct != 1)
+ return EBUSY;
+
+ if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &vnd,
+ sizeof(vnd))) != OK)
+ return r;
+
+ /*
+ * Issue a special VFS backcall that copies a file descriptor
+ * to the current process, from the user process ultimately
+ * making the IOCTL call. The result is either a newly
+ * allocated file descriptor or an error.
+ */
+ if ((state.fd = dupfrom(user_endpt, vnd.vnd_fildes)) == -1)
+ return -errno;
+
+ /* The target file must be regular. */
+ if (fstat(state.fd, &st) == -1) {
+ printf("VND%u: fstat failed (%d)\n", instance, -errno);
+ r = -errno;
+ }
+ if (r == OK && !S_ISREG(st.st_mode))
+ r = EINVAL;
+
+ /*
+ * Allocate memory for an intermediate I/O transfer buffer. In
+ * order to save on memory in the common case, the buffer is
+ * only allocated when the vnd is in use. We use mmap instead
+ * of malloc to allow the memory to be actually freed later.
+ */
+ if (r == OK) {
+ state.buf = minix_mmap(NULL, VND_BUF_SIZE, PROT_READ |
+ PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (state.buf == MAP_FAILED)
+ r = ENOMEM;
+ }
+
+ if (r != OK) {
+ close(state.fd);
+ state.fd = -1;
+ return r;
+ }
+
+ /* Set various device state fields. */
+ state.dev = st.st_dev;
+ state.ino = st.st_ino;
+ state.rdonly = !!(vnd.vnd_flags & VNDIOF_READONLY);
+
+ r = vnd_layout(st.st_size, &vnd);
+
+ /* Upon success, return the device size to userland. */
+ if (r == OK) {
+ vnd.vnd_size = state.geom.size;
+
+ r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &vnd,
+ sizeof(vnd));
+ }
+
+ if (r != OK) {
+ minix_munmap(state.buf, VND_BUF_SIZE);
+ close(state.fd);
+ state.fd = -1;
+ }
+
+ return r;
+
+ case VNDIOCCLR:
+ /* The VND can only be cleared if it has been configured. */
+ if (state.fd == -1)
+ return ENXIO;
+
+ if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &vnd,
+ sizeof(vnd))) != OK)
+ return r;
+
+ /* The caller has the device open to do the IOCTL request. */
+ if (!(vnd.vnd_flags & VNDIOF_FORCE) && state.openct != 1)
+ return EBUSY;
+
+ /*
+ * Close the associated file descriptor immediately, but do not
+ * allow reuse until the device has been closed by the other
+ * users.
+ */
+ minix_munmap(state.buf, VND_BUF_SIZE);
+ close(state.fd);
+ state.fd = -1;
+
+ return OK;
+
+ case VNDIOCGET:
+ /*
+ * We need not copy in the given structure. It would contain
+ * the requested unit number, but each driver instance provides
+ * only one unit anyway.
+ */
+
+ memset(&vnu, 0, sizeof(vnu));
+
+ vnu.vnu_unit = instance;
+
+ /* Leave these fields zeroed if the device is not in use. */
+ if (state.fd != -1) {
+ vnu.vnu_dev = state.dev;
+ vnu.vnu_ino = state.ino;
+ }
+
+ return sys_safecopyto(endpt, grant, 0, (vir_bytes) &vnu,
+ sizeof(vnu));
+
+ case DIOCOPENCT:
+ return sys_safecopyto(endpt, grant, 0,
+ (vir_bytes) &state.openct, sizeof(state.openct));
+
+ case DIOCFLUSH:
+ if (state.fd == -1)
+ return ENXIO;
+
+ fsync(state.fd);
+
+ return OK;
+ }
+
+ return ENOTTY;
+}
+
+/*
+ * Return a pointer to the partition structure for the given minor device.
+ */
+static struct device *
+vnd_part(devminor_t minor)
+{
+ if (minor >= 0 && minor < DEV_PER_DRIVE)
+ return &state.part[minor];
+ else if ((unsigned int) (minor -= MINOR_d0p0s0) < SUB_PER_DRIVE)
+ return &state.subpart[minor];
+ else
+ return NULL;
+}
+
+/*
+ * Return geometry information.
+ */
+static void
+vnd_geometry(devminor_t UNUSED(minor), struct part_geom *part)
+{
+ part->cylinders = state.geom.cylinders;
+ part->heads = state.geom.heads;
+ part->sectors = state.geom.sectors;
+}
+
+/*
+ * Initialize the device.
+ */
+static int
+vnd_init(int UNUSED(type), sef_init_info_t *UNUSED(info))
+{
+ long v;
+
+ /*
+ * No support for crash recovery. The driver would have no way to
+ * reacquire the file descriptor for the target file.
+ */
+
+ /*
+ * The instance number is used for two purposes: reporting errors, and
+ * returning the proper unit number to userland in VNDIOCGET calls.
+ */
+ v = 0;
+ (void) env_parse("instance", "d", 0, &v, 0, 255);
+ instance = (unsigned int) v;
+
+ state.openct = 0;
+ state.exiting = FALSE;
+ state.fd = -1;
+
+ return OK;
+}
+
+/*
+ * Process an incoming signal.
+ */
+static void
+vnd_signal(int signo)
+{
+
+ /* In case of a termination signal, initiate driver shutdown. */
+ if (signo != SIGTERM)
+ return;
+
+ state.exiting = TRUE;
+
+ /* Keep running until the device has been fully closed. */
+ if (state.openct == 0)
+ blockdriver_terminate();
+}
+
+/*
+ * Set callbacks and initialize the System Event Framework (SEF).
+ */
+static void
+vnd_startup(void)
+{
+
+ /* Register init and signal callbacks. */
+ sef_setcb_init_fresh(vnd_init);
+ sef_setcb_signal_handler(vnd_signal);
+
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
+/*
+ * Driver task.
+ */
+int
+main(int argc, char **argv)
+{
+
+ /* Initialize the driver. */
+ env_setargs(argc, argv);
+ vnd_startup();
+
+ /* Process requests until shutdown. */
+ blockdriver_task(&vnd_dtab);
+
+ return 0;
+}
at_wini
;
};
+
+service vnd
+{
+ ipc
+ SYSTEM VFS RS VM
+ ;
+ uid 0; # only for dupfrom(2)
+};
#define BMP085B1S77_MAJOR 53 /* 53 = /dev/bmp085b1s77 (bmp085) */
#define BMP085B2S77_MAJOR 54 /* 54 = /dev/bmp085b2s77 (bmp085) */
#define BMP085B3S77_MAJOR 55 /* 55 = /dev/bmp085b3s77 (bmp085) */
-
+ /* 56-63 = /dev/vnd[0-7] (vnd) */
/* Minor device numbers for memory driver. */
# define RAM_DEV_OLD 0 /* minor device for /dev/ram */
_IOC_IN)
#define _IORW(x,y,t) ((x << 8) | y | ((sizeof(t) & _IOCPARM_MASK) << 16) |\
_IOC_INOUT)
+#define _IOWR(x,y,t) _IORW(x,y,t) /* NetBSD compatibility */
#define _IOW_BIG(y,t) (y | ((sizeof(t) & _IOCPARM_MASK_BIG) << 8) \
| _IOC_IN | _IOC_BIG)
.endfor
# Import from sys-minix
-.for i in access.c brk.c close.c environ.c execve.c fork.c \
+.for i in access.c brk.c close.c environ.c execve.c fork.c fsync.c \
getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \
- link.c loadname.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \
- read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stack_utils.c \
- stat.c stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \
- brksize.S _ipc.S _senda.S ucontext.S mmap.c init.c
+ init.c link.c loadname.c lseek.c lseek64.c _mcontext.c mknod.c \
+ mmap.c nanosleep.c open.c pread.c pwrite.c read.c reboot.c sbrk.c \
+ select.c setuid.c sigprocmask.c stack_utils.c stat.c stime.c \
+ syscall.c _ucontext.c umask.c unlink.c waitpid.c write.c \
+ brksize.S _ipc.S _senda.S ucontext.S
.PATH.c: ${LIBCDIR}/sys-minix
.PATH.S: ${ARCHDIR}/sys-minix
SRCS+= ${i}
2013/04/23 12:00:00,sys/dev/i2c/Makefile
2013/04/23 12:00:00,sys/dev/i2c/i2c_io.h
2013/07/22 12:00:00,sys/dev/videomode
+2013/07/31 12:00:00,sys/dev/vndvar.h
2012/01/16 18:47:57,sys/lib/libsa
2012/10/17 12:00:00,sys/lib/libz
2012/10/17 12:00:00,sys/Makefile
# Only install includes which are used by userland
INCS= biovar.h ccdvar.h cgdvar.h fssvar.h keylock.h kttcpio.h lockstat.h \
md.h vndvar.h
+.else
+INCS= vndvar.h
.endif
.include <bsd.kinc.mk>
--- /dev/null
+/* $NetBSD: vndvar.h,v 1.31 2011/06/29 09:12:42 hannken Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * from: Utah $Hdr: fdioctl.h 1.1 90/07/09$
+ *
+ * @(#)vnioctl.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _SYS_DEV_VNDVAR_H_
+#define _SYS_DEV_VNDVAR_H_
+
+#ifndef __minix
+#include <sys/pool.h>
+#endif
+
+/*
+ * Vnode disk pseudo-geometry information.
+ */
+struct vndgeom {
+ u_int32_t vng_secsize; /* # bytes per sector */
+ u_int32_t vng_nsectors; /* # data sectors per track */
+ u_int32_t vng_ntracks; /* # tracks per cylinder */
+ u_int32_t vng_ncylinders; /* # cylinders per unit */
+};
+
+/*
+ * Ioctl definitions for file (vnode) disk pseudo-device.
+ */
+struct vnd_ioctl {
+#ifndef __minix
+ char *vnd_file; /* pathname of file to mount */
+#else
+ int vnd_fildes; /* file descriptor of file to mount */
+#endif
+ int vnd_flags; /* flags; see below */
+ struct vndgeom vnd_geom; /* geometry to emulate */
+#ifndef __minix
+ unsigned int vnd_osize; /* (returned) size of disk */
+#endif
+ uint64_t vnd_size; /* (returned) size of disk */
+};
+
+/* vnd_flags */
+#define VNDIOF_HASGEOM 0x01 /* use specified geometry */
+#define VNDIOF_READONLY 0x02 /* as read-only device */
+#define VNDIOF_FORCE 0x04 /* force close */
+
+#ifndef __minix
+#ifdef _KERNEL
+
+struct vnode;
+
+/*
+ * A vnode disk's state information.
+ */
+struct vnd_softc {
+ device_t sc_dev;
+ int sc_flags; /* flags */
+ size_t sc_size; /* size of vnd */
+ struct vnode *sc_vp; /* vnode */
+ kauth_cred_t sc_cred; /* credentials */
+ int sc_maxactive; /* max # of active requests */
+ struct bufq_state *sc_tab; /* transfer queue */
+ int sc_active; /* number of active transfers */
+ struct disk sc_dkdev; /* generic disk device info */
+ struct vndgeom sc_geom; /* virtual geometry */
+ struct pool sc_vxpool; /* vndxfer pool */
+ struct pool sc_vbpool; /* vndbuf pool */
+ struct lwp *sc_kthread; /* kernel thread */
+ u_int32_t sc_comp_blksz; /* precompressed block size */
+ u_int32_t sc_comp_numoffs;/* count of compressed block offsets */
+ u_int64_t *sc_comp_offsets;/* file idx's to compressed blocks */
+ unsigned char *sc_comp_buff; /* compressed data buffer */
+ unsigned char *sc_comp_decombuf;/* decompressed data buffer */
+ int32_t sc_comp_buffblk;/*current decompressed block */
+ z_stream sc_comp_stream;/* decompress descriptor */
+};
+#endif
+
+/* sc_flags */
+#define VNF_INITED 0x001 /* unit has been initialized */
+#define VNF_WLABEL 0x002 /* label area is writable */
+#define VNF_LABELLING 0x004 /* unit is currently being labelled */
+#define VNF_WANTED 0x008 /* someone is waiting to obtain a lock */
+#define VNF_LOCKED 0x010 /* unit is locked */
+#define VNF_READONLY 0x020 /* unit is read-only */
+#define VNF_KLABEL 0x040 /* keep label on close */
+#define VNF_VLABEL 0x080 /* label is valid */
+#define VNF_KTHREAD 0x100 /* thread is running */
+#define VNF_VUNCONF 0x200 /* device is unconfiguring */
+#define VNF_COMP 0x400 /* file is compressed */
+#define VNF_CLEARING 0x800 /* unit is being torn down */
+#define VNF_USE_VN_RDWR 0x1000 /* have to use vn_rdwr() */
+
+/* structure of header in a compressed file */
+struct vnd_comp_header
+{
+ char preamble[128];
+ u_int32_t block_size;
+ u_int32_t num_blocks;
+};
+#endif
+
+/*
+ * A simple structure for describing which vnd units are in use.
+ */
+
+struct vnd_user {
+ int vnu_unit; /* which vnd unit */
+ dev_t vnu_dev; /* file is on this device... */
+ ino_t vnu_ino; /* ...at this inode */
+};
+
+/*
+ * Before you can use a unit, it must be configured with VNDIOCSET.
+ * The configuration persists across opens and closes of the device;
+ * an VNDIOCCLR must be used to reset a configuration. An attempt to
+ * VNDIOCSET an already active unit will return EBUSY.
+ */
+#define VNDIOCSET _IOWR('F', 0, struct vnd_ioctl) /* enable disk */
+#define VNDIOCCLR _IOW('F', 1, struct vnd_ioctl) /* disable disk */
+#define VNDIOCGET _IOWR('F', 3, struct vnd_user) /* get list */
+
+#ifdef _KERNEL
+/*
+ * Everything else is kernel-private, mostly exported for compat/netbsd32.
+ *
+ * NetBSD 3.0 had a 32-bit value for vnu_ino.
+ *
+ * NetBSD 5.0 had a 32-bit value for vnu_dev, and vnd_size.
+ */
+struct vnd_user30 {
+ int vnu_unit; /* which vnd unit */
+ uint32_t vnu_dev; /* file is on this device... */
+ uint32_t vnu_ino; /* ...at this inode */
+};
+#define VNDIOCGET30 _IOWR('F', 2, struct vnd_user30) /* get list */
+
+struct vnd_user50 {
+ int vnu_unit; /* which vnd unit */
+ uint32_t vnu_dev; /* file is on this device... */
+ ino_t vnu_ino; /* ...at this inode */
+};
+#define VNDIOCGET50 _IOWR('F', 3, struct vnd_user50) /* get list */
+
+struct vnd_ioctl50 {
+ char *vnd_file; /* pathname of file to mount */
+ int vnd_flags; /* flags; see below */
+ struct vndgeom vnd_geom; /* geometry to emulate */
+ unsigned int vnd_size; /* (returned) size of disk */
+};
+#define VNDIOCSET50 _IOWR('F', 0, struct vnd_ioctl50)
+#define VNDIOCCLR50 _IOW('F', 1, struct vnd_ioctl50)
+
+#endif /* _KERNEL */
+
+#endif /* _SYS_DEV_VNDVAR_H_ */
#include <sys/ioc_block.h> /* 'b' */
#include <sys/ioc_fbd.h> /* 'B' */
#include <sys/ioc_fb.h> /* 'V' */
+#include <dev/vndvar.h> /* 'F' */
#if defined(_NETBSD_SOURCE)
#define TIOCDRAIN TCDRAIN