Add VND driver, providing loopback devices
Change-Id: I40fa695e28c67477a75383e6f1550e451afcab41
This commit is contained in:
parent
dba2d1f8b4
commit
6989311826
15 changed files with 1000 additions and 9 deletions
|
@ -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=
|
||||
;;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
12
drivers/vnd/Makefile
Normal 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
85
drivers/vnd/NOTES
Normal 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
601
drivers/vnd/vnd.c
Normal 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;
|
||||
}
|
|
@ -684,3 +684,11 @@ service fbd
|
|||
at_wini
|
||||
;
|
||||
};
|
||||
|
||||
service vnd
|
||||
{
|
||||
ipc
|
||||
SYSTEM VFS RS VM
|
||||
;
|
||||
uid 0; # only for dupfrom(2)
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
218
sys/dev/vndvar.h
Normal 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_ */
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue