Add VND driver, providing loopback devices

Change-Id: I40fa695e28c67477a75383e6f1550e451afcab41
This commit is contained in:
David van Moolenbroek 2013-09-18 14:02:17 +02:00 committed by Lionel Sambuc
parent dba2d1f8b4
commit 6989311826
15 changed files with 1000 additions and 9 deletions

View file

@ -196,6 +196,22 @@ do
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=
;;

View file

@ -33,7 +33,9 @@ case $#:$1 in
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
@ -67,6 +69,7 @@ Where key is one of the following:
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
@ -331,6 +334,46 @@ do
$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

View file

@ -668,6 +668,7 @@
./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
@ -4766,6 +4767,7 @@
./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

View file

@ -19,12 +19,12 @@ SUBDIR= log tty
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"

12
drivers/vnd/Makefile Normal file
View file

@ -0,0 +1,12 @@
# 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>

85
drivers/vnd/NOTES Normal file
View file

@ -0,0 +1,85 @@
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.

601
drivers/vnd/vnd.c Normal file
View file

@ -0,0 +1,601 @@
/* 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;
}

View file

@ -684,3 +684,11 @@ service fbd
at_wini
;
};
service vnd
{
ipc
SYSTEM VFS RS VM
;
uid 0; # only for dupfrom(2)
};

View file

@ -71,7 +71,7 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY };
#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 */

View file

@ -34,6 +34,7 @@
_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)

View file

@ -143,12 +143,13 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale
.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}

View file

@ -114,6 +114,7 @@
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

View file

@ -21,6 +21,8 @@ INCSDIR= /usr/include/dev
# 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>

218
sys/dev/vndvar.h Normal file
View file

@ -0,0 +1,218 @@
/* $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_ */

View file

@ -23,6 +23,7 @@
#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