libbdev: initial version

The "bdev" library provides basic primitives for file systems to talk
to block device drivers, hiding the details of the underlying protocol
and interaction model.

This version of libbdev is rather basic. It is planned to support the
following features in the long run:

 - asynchronous requests and replies;
 - recovery support for underlying block drivers;
 - retrying of failed I/O requests.

The commit also changes our block-based file systems (mfs, ext2, isofs)
to make use of libbdev.
This commit is contained in:
David van Moolenbroek 2011-11-09 14:29:12 +01:00
parent 0bb27bb0b1
commit af01bda509
43 changed files with 698 additions and 1227 deletions

View file

@ -5,6 +5,7 @@
INCS+= env.h fetch.h hgfs.h lib.h libutil.h timers.h INCS+= env.h fetch.h hgfs.h lib.h libutil.h timers.h
INCS+= minix/acpi.h minix/ansi.h minix/audio_fw.h minix/bitmap.h \ INCS+= minix/acpi.h minix/ansi.h minix/audio_fw.h minix/bitmap.h \
minix/bdev.h \
minix/callnr.h minix/com.h minix/compiler.h minix/config.h \ minix/callnr.h minix/com.h minix/compiler.h minix/config.h \
minix/const.h minix/cpufeature.h minix/crtso.h minix/debug.h \ minix/const.h minix/cpufeature.h minix/crtso.h minix/debug.h \
minix/devio.h minix/devman.h minix/dmap.h minix/driver.h \ minix/devio.h minix/devman.h minix/dmap.h minix/driver.h \

View file

@ -0,0 +1,19 @@
#ifndef __MINIX_BDEV_H
#define __MINIX_BDEV_H
#define BDEV_NOFLAGS 0
extern void bdev_driver(dev_t dev, endpoint_t endpt);
extern int bdev_open(dev_t dev, int access);
extern int bdev_close(dev_t dev);
extern int bdev_read(dev_t dev, u64_t pos, char *buf, int count, int flags);
extern int bdev_write(dev_t dev, u64_t pos, char *buf, int count, int flags);
extern int bdev_gather(dev_t dev, u64_t pos, iovec_t *vec, int count,
int flags, vir_bytes *size);
extern int bdev_scatter(dev_t dev, u64_t pos, iovec_t *vec, int count,
int flags, vir_bytes *size);
extern int bdev_ioctl(dev_t dev, int request, void *buf);
#endif /* __MINIX_BDEV_H */

View file

@ -18,7 +18,7 @@ SUBDIR= csu ${LIBCOMPAT_DIR} ${LIBC_DIR} libdriver libnetdriver \
libedit ${LIBM_DIR} libsys libtimers libminixutil libbz2 libl libhgfs \ libedit ${LIBM_DIR} libsys libtimers libminixutil libbz2 libl libhgfs \
libz libfetch libarchive libvtreefs libaudiodriver libmthread \ libz libfetch libarchive libvtreefs libaudiodriver libmthread \
libexec libdevman libusb ${LIBMINLIB_DIR} ${LIBASYN_DIR} \ libexec libdevman libusb ${LIBMINLIB_DIR} ${LIBASYN_DIR} \
libddekit libminixfs libddekit libminixfs libbdev
.if defined(NBSD_LIBC) && (${NBSD_LIBC} != "no") .if defined(NBSD_LIBC) && (${NBSD_LIBC} != "no")
SUBDIR+= libelf libminc libcrypt libterminfo libcurses libvassert libutil SUBDIR+= libelf libminc libcrypt libterminfo libcurses libvassert libutil

8
lib/libbdev/Makefile Normal file
View file

@ -0,0 +1,8 @@
# Makefile for libbdev
.include <bsd.own.mk>
LIB= bdev
SRCS= bdev.c ipc.c driver.c
.include <bsd.lib.mk>

348
lib/libbdev/bdev.c Normal file
View file

@ -0,0 +1,348 @@
/* libbdev - block device interfacing library, by D.C. van Moolenbroek */
/* This is a preliminary, bare-essentials-only version of this library. */
#include <minix/drivers.h>
#include <minix/bdev.h>
#include <minix/ioctl.h>
#include <assert.h>
#include "proto.h"
void bdev_driver(dev_t dev, endpoint_t endpt)
{
/* Associate a driver with the given (major) device, using its endpoint.
* File system usage note: typically called from mount and newdriver.
*/
static int first = TRUE;
if (first) {
/* Initialize the driver endpoint array. */
bdev_driver_init();
first = FALSE;
}
bdev_update(dev, endpt);
}
static int bdev_opcl(int req, dev_t dev, int access)
{
/* Open or close the given minor device.
*/
message m;
m.m_type = req;
m.DEVICE = minor(dev);
m.COUNT = access;
return bdev_sendrec(dev, &m);
}
int bdev_open(dev_t dev, int access)
{
/* Open the given minor device.
* File system usage note: typically called from mount, after bdev_driver.
*/
return bdev_opcl(DEV_OPEN, dev, access);
}
int bdev_close(dev_t dev)
{
/* Close the given minor device.
* File system usage note: typically called from unmount.
*/
return bdev_opcl(DEV_CLOSE, dev, 0);
}
static int bdev_rdwt_setup(int req, dev_t dev, u64_t pos, char *buf, int count,
int UNUSED(flags), message *m)
{
/* Set up a single-buffer read/write request.
*/
endpoint_t endpt;
cp_grant_id_t grant;
int access;
if ((endpt = bdev_driver_get(dev)) == NONE)
return EDEADSRCDST;
access = (req == DEV_READ_S) ? CPF_WRITE : CPF_READ;
grant = cpf_grant_direct(endpt, (vir_bytes) buf, count, access);
if (!GRANT_VALID(grant)) {
printf("bdev: unable to allocate grant!\n");
return EINVAL;
}
m->m_type = req;
m->DEVICE = minor(dev);
m->POSITION = ex64lo(pos);
m->HIGHPOS = ex64hi(pos);
m->COUNT = count;
m->IO_GRANT = (void *) grant;
return OK;
}
static void bdev_rdwt_cleanup(message *m)
{
/* Clean up a single-buffer read/write request.
*/
cp_grant_id_t grant;
grant = (cp_grant_id_t) m->IO_GRANT;
cpf_revoke(grant);
}
static int bdev_rdwt(int req, dev_t dev, u64_t pos, char *buf, int count,
int flags)
{
/* Perform a read or write call using a single buffer.
*/
message m;
int r;
if ((r = bdev_rdwt_setup(req, dev, pos, buf, count, flags, &m)) != OK)
return r;
r = bdev_sendrec(dev, &m);
bdev_rdwt_cleanup(&m);
return r;
}
static int bdev_vrdwt_setup(int req, dev_t dev, u64_t pos, iovec_t *vec,
int count, int UNUSED(flags), message *m, iovec_s_t *gvec,
cp_grant_id_t *grants, vir_bytes *size)
{
/* Set up a vectored read/write request.
*/
endpoint_t endpt;
cp_grant_id_t grant;
int i, access;
assert(count <= NR_IOREQS);
if ((endpt = bdev_driver_get(dev)) == NONE)
return EDEADSRCDST;
access = (req == DEV_GATHER_S) ? CPF_WRITE : CPF_READ;
*size = 0;
for (i = 0; i < count; i++) {
grants[i] = cpf_grant_direct(endpt, vec[i].iov_addr, vec[i].iov_size,
access);
if (!GRANT_VALID(grants[i])) {
printf("bdev: unable to allocate grant!\n");
for (i--; i >= 0; i--)
cpf_revoke(grants[i]);
return EINVAL;
}
/* We keep a separate grants array to prevent local leaks if the driver
* ends up clobbering the grant vector. Future protocol updates should
* make the grant for the vector read-only.
*/
gvec[i].iov_grant = grants[i];
gvec[i].iov_size = vec[i].iov_size;
assert(*size + vec[i].iov_size > *size);
*size += vec[i].iov_size;
}
grant = cpf_grant_direct(endpt, (vir_bytes) gvec, sizeof(gvec[0]) * count,
CPF_READ | CPF_WRITE);
if (!GRANT_VALID(grant)) {
printf("bdev: unable to allocate grant!\n");
for (i = count - 1; i >= 0; i--)
cpf_revoke(grants[i]);
return EINVAL;
}
m->m_type = req;
m->DEVICE = minor(dev);
m->POSITION = ex64lo(pos);
m->HIGHPOS = ex64hi(pos);
m->COUNT = count;
m->IO_GRANT = (void *) grant;
return OK;
}
static void bdev_vrdwt_cleanup(message *m, cp_grant_id_t *grants)
{
/* Clean up a vectored read/write request.
*/
cp_grant_id_t grant;
int i;
grant = (cp_grant_id_t) m->IO_GRANT;
cpf_revoke(grant);
for (i = m->COUNT - 1; i >= 0; i--)
cpf_revoke(grants[i]);
}
static int bdev_vrdwt_adjust(dev_t dev, iovec_s_t *gvec, int count,
vir_bytes *size)
{
/* Adjust the number of bytes transferred, by subtracting from it the number of
* bytes *not* transferred according to the result vector.
*/
int i;
for (i = 0; i < count; i++) {
if (*size < gvec[i].iov_size) {
printf("bdev: driver (%d) returned bad vector\n",
bdev_driver_get(dev));
return FALSE;
}
*size -= gvec[i].iov_size;
}
return TRUE;
}
static int bdev_vrdwt(int req, dev_t dev, u64_t pos, iovec_t *vec, int count,
int flags, vir_bytes *size)
{
/* Perform a read or write call using a vector of buffer.
*/
iovec_s_t gvec[NR_IOREQS];
cp_grant_id_t grants[NR_IOREQS];
message m;
int r;
if ((r = bdev_vrdwt_setup(req, dev, pos, vec, count, flags, &m, gvec,
grants, size)) != OK) {
*size = 0;
return r;
}
r = bdev_sendrec(dev, &m);
bdev_vrdwt_cleanup(&m, grants);
/* Also return the number of bytes transferred. */
if (!bdev_vrdwt_adjust(dev, gvec, count, size)) {
*size = 0;
r = EIO;
}
return r;
}
int bdev_read(dev_t dev, u64_t pos, char *buf, int count, int flags)
{
/* Perform a read call into a single buffer.
*/
return bdev_rdwt(DEV_READ_S, dev, pos, buf, count, flags);
}
int bdev_write(dev_t dev, u64_t pos, char *buf, int count, int flags)
{
/* Perform a write call from a single buffer.
*/
return bdev_rdwt(DEV_WRITE_S, dev, pos, buf, count, flags);
}
int bdev_gather(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags,
vir_bytes *size)
{
/* Perform a read call into a vector of buffers.
*/
return bdev_vrdwt(DEV_GATHER_S, dev, pos, vec, count, flags, size);
}
int bdev_scatter(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags,
vir_bytes *size)
{
/* Perform a write call from a vector of buffers.
*/
return bdev_vrdwt(DEV_SCATTER_S, dev, pos, vec, count, flags, size);
}
static int bdev_ioctl_setup(dev_t dev, int request, void *buf, message *m)
{
/* Set up an I/O control request.
*/
endpoint_t endpt;
size_t size;
cp_grant_id_t grant;
int access;
if ((endpt = bdev_driver_get(dev)) == NONE)
return EDEADSRCDST;
if (_MINIX_IOCTL_BIG(request))
size = _MINIX_IOCTL_SIZE_BIG(request);
else
size = _MINIX_IOCTL_SIZE(request);
access = 0;
if (_MINIX_IOCTL_IOR(access)) access |= CPF_WRITE;
if (_MINIX_IOCTL_IOW(access)) access |= CPF_READ;
/* The size may be 0, in which case 'buf' need not be a valid pointer. */
grant = cpf_grant_direct(endpt, (vir_bytes) buf, size, access);
if (!GRANT_VALID(grant)) {
printf("bdev: unable to allocate grant!\n");
return EINVAL;
}
m->m_type = DEV_IOCTL_S;
m->DEVICE = minor(dev);
m->REQUEST = request;
m->IO_GRANT = (void *) grant;
return OK;
}
static void bdev_ioctl_cleanup(message *m)
{
/* Clean up an I/O control request.
*/
cp_grant_id_t grant;
grant = (cp_grant_id_t) m->IO_GRANT;
cpf_revoke(grant);
}
int bdev_ioctl(dev_t dev, int request, void *buf)
{
/* Perform an I/O control request.
*/
message m;
int r;
if ((r = bdev_ioctl_setup(dev, request, buf, &m)) != OK)
return r;
r = bdev_sendrec(dev, &m);
bdev_ioctl_cleanup(&m);
return r;
}

58
lib/libbdev/driver.c Normal file
View file

@ -0,0 +1,58 @@
/* libbdev - driver endpoint management */
#include <minix/drivers.h>
#include <minix/bdev.h>
#include <assert.h>
#include "proto.h"
static endpoint_t driver_endpt[NR_DEVICES];
void bdev_driver_init(void)
{
/* Initialize the driver table.
*/
int i;
for (i = 0; i < NR_DEVICES; i++)
driver_endpt[i] = NONE;
}
void bdev_driver_clear(dev_t dev)
{
/* Clear information about a driver.
*/
int major;
major = major(dev);
assert(major >= 0 && major < NR_DEVICES);
driver_endpt[major] = NONE;
}
void bdev_driver_set(dev_t dev, endpoint_t endpt)
{
/* Set the endpoint for a driver.
*/
int major;
major = major(dev);
assert(major >= 0 && major < NR_DEVICES);
driver_endpt[major] = endpt;
}
endpoint_t bdev_driver_get(dev_t dev)
{
/* Return the endpoint for a driver, or NONE if we do not know its endpoint.
*/
int major;
major = major(dev);
assert(major >= 0 && major < NR_DEVICES);
return driver_endpt[major];
}

89
lib/libbdev/ipc.c Normal file
View file

@ -0,0 +1,89 @@
/* libbdev - IPC and recovery functions */
#include <minix/drivers.h>
#include <minix/bdev.h>
#include <assert.h>
#include "proto.h"
static void bdev_cancel(dev_t dev)
{
/* Recovering the driver for the given device has failed repeatedly. Mark it as
* permanently unusable, and clean up any associated calls and resources.
*/
printf("bdev: driver for major %d crashed\n", major(dev));
/* Mark the driver as unusable. */
bdev_driver_clear(dev);
}
void bdev_update(dev_t dev, endpoint_t endpt)
{
/* Set the endpoint for a driver. Perform recovery if necessary.
*/
endpoint_t old_endpt;
old_endpt = bdev_driver_get(dev);
bdev_driver_set(dev, endpt);
/* If updating the driver causes an endpoint change, the driver has
* restarted.
*/
if (old_endpt != NONE && old_endpt != endpt)
bdev_cancel(dev);
}
int bdev_sendrec(dev_t dev, const message *m_orig)
{
/* Send a request to the given device, and wait for the reply.
*/
endpoint_t endpt;
message m;
int r;
/* If we have no usable driver endpoint, fail instantly. */
if ((endpt = bdev_driver_get(dev)) == NONE)
return EDEADSRCDST;
/* Send the request and block until we receive a reply. */
m = *m_orig;
m.USER_ENDPT = (endpoint_t) -1; /* synchronous request; no ID */
r = sendrec(endpt, &m);
/* This version of libbdev does not support recovery. Forget the driver. */
if (r == EDEADSRCDST) {
bdev_cancel(dev);
return EDEADSRCDST;
}
if (r != OK) {
printf("bdev: IPC to driver (%d) failed (%d)\n", endpt, r);
return r;
}
if (m.m_type != TASK_REPLY) {
printf("bdev: driver (%d) sent weird response (%d)\n",
endpt, m.m_type);
return EIO;
}
/* ERESTART signifies a driver restart. Again, we do not support this yet. */
if (m.REP_STATUS == ERESTART) {
bdev_cancel(dev);
return EDEADSRCDST;
}
if (m.REP_ENDPT != (endpoint_t) -1) {
printf("bdev: driver (%d) sent invalid response (%d)\n",
endpt, m.REP_ENDPT);
return EIO;
}
/* We got a reply to our request. */
return m.REP_STATUS;
}

14
lib/libbdev/proto.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef _BDEV_PROTO_H
#define _BDEV_PROTO_H
/* driver.c */
extern void bdev_driver_init(void);
extern void bdev_driver_clear(dev_t dev);
extern void bdev_driver_set(dev_t dev, endpoint_t endpt);
extern endpoint_t bdev_driver_get(dev_t dev);
/* ipc.c */
extern void bdev_update(dev_t dev, endpoint_t endpt);
extern int bdev_sendrec(dev_t dev, const message *m_orig);
#endif /* _BDEV_PROTO_H */

View file

@ -1,12 +1,12 @@
# Makefile for ext2 filesystem # Makefile for ext2 filesystem
PROG= ext2 PROG= ext2
SRCS= balloc.c cache.c device.c link.c \ SRCS= balloc.c cache.c link.c \
mount.c misc.c open.c protect.c read.c \ mount.c misc.c open.c protect.c read.c \
stadir.c table.c time.c utility.c \ stadir.c table.c time.c utility.c \
write.c ialloc.c inode.c main.c path.c \ write.c ialloc.c inode.c main.c path.c \
super.c super.c
DPADD+= ${LIBSYS} DPADD+= ${LIBSYS}
LDADD+= -lminixfs -lsys LDADD+= -lminixfs -lbdev -lsys
MAN= MAN=

View file

@ -17,6 +17,7 @@
#include "fs.h" #include "fs.h"
#include <minix/u64.h> #include <minix/u64.h>
#include <minix/bdev.h>
#include <minix/libminixfs.h> #include <minix/libminixfs.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
@ -290,14 +291,18 @@ PRIVATE void rw_block(
* is not reported to the caller. If the error occurred while purging a block * is not reported to the caller. If the error occurred while purging a block
* from the cache, it is not clear what the caller could do about it anyway. * from the cache, it is not clear what the caller could do about it anyway.
*/ */
int r, op, op_failed = 0; int r, op_failed = 0;
u64_t pos; u64_t pos;
dev_t dev; dev_t dev;
if ( (dev = bp->b_dev) != NO_DEV) { if ( (dev = bp->b_dev) != NO_DEV) {
pos = mul64u(bp->b_blocknr, fs_block_size); pos = mul64u(bp->b_blocknr, fs_block_size);
op = (rw_flag == READING ? MFS_DEV_READ : MFS_DEV_WRITE); if (rw_flag == READING)
r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, fs_block_size); r = bdev_read(dev, pos, bp->b_data, fs_block_size,
BDEV_NOFLAGS);
else
r = bdev_write(dev, pos, bp->b_data, fs_block_size,
BDEV_NOFLAGS);
if (r < 0) { if (r < 0) {
printf("Ext2(%d) I/O error on device %d/%d, block %u\n", printf("Ext2(%d) I/O error on device %d/%d, block %u\n",
SELF_E, major(dev), minor(dev), bp->b_blocknr); SELF_E, major(dev), minor(dev), bp->b_blocknr);
@ -382,6 +387,8 @@ PUBLIC void rw_scattered(
register int i; register int i;
register iovec_t *iop; register iovec_t *iop;
static iovec_t *iovec = NULL; static iovec_t *iovec = NULL;
vir_bytes size;
u64_t pos;
int j, r; int j, r;
STATICINIT(iovec, NR_IOREQS); STATICINIT(iovec, NR_IOREQS);
@ -414,16 +421,18 @@ PUBLIC void rw_scattered(
iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_addr = (vir_bytes) bp->b_data;
iop->iov_size = (vir_bytes) fs_block_size; iop->iov_size = (vir_bytes) fs_block_size;
} }
r = block_dev_io(rw_flag == WRITING ? MFS_DEV_SCATTER : MFS_DEV_GATHER, pos = mul64u(bufq[0]->b_blocknr, fs_block_size);
dev, SELF_E, iovec, if (rw_flag == READING)
mul64u(bufq[0]->b_blocknr, fs_block_size), j); r = bdev_gather(dev, pos, iovec, j, BDEV_NOFLAGS, &size);
else
r = bdev_scatter(dev, pos, iovec, j, BDEV_NOFLAGS, &size);
/* Harvest the results. Dev_io reports the first error it may have /* Harvest the results. Dev_io reports the first error it may have
* encountered, but we only care if it's the first block that failed. * encountered, but we only care if it's the first block that failed.
*/ */
for (i = 0, iop = iovec; i < j; i++, iop++) { for (i = 0, iop = iovec; i < j; i++, iop++) {
bp = bufq[i]; bp = bufq[i];
if (iop->iov_size != 0) { if (size < iop->iov_size) {
/* Transfer failed. An error? Do we care? */ /* Transfer failed. An error? Do we care? */
if (r != OK && i == 0) { if (r != OK && i == 0) {
printf( printf(
@ -440,6 +449,7 @@ PUBLIC void rw_scattered(
} else { } else {
bp->b_dirt = CLEAN; bp->b_dirt = CLEAN;
} }
size -= iop->iov_size;
} }
bufq += i; bufq += i;
bufqsize -= i; bufqsize -= i;

View file

@ -116,12 +116,6 @@
#define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m)) #define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m))
/* Args to dev_bio/dev_io */
#define MFS_DEV_READ 10001
#define MFS_DEV_WRITE 10002
#define MFS_DEV_SCATTER 10003
#define MFS_DEV_GATHER 10004
/* FS states */ /* FS states */
#define EXT2_VALID_FS 0x0001 /* Cleanly unmounted */ #define EXT2_VALID_FS 0x0001 /* Cleanly unmounted */
#define EXT2_ERROR_FS 0x0002 /* Errors detected */ #define EXT2_ERROR_FS 0x0002 /* Errors detected */

View file

@ -1,359 +0,0 @@
#include "fs.h"
#include <minix/com.h>
#include <minix/endpoint.h>
#include <minix/safecopies.h>
#include <minix/u64.h>
#include <string.h>
#include "inode.h"
#include "super.h"
#include "const.h"
#include "drivers.h"
#include <minix/vfsif.h>
FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t driver,
cp_grant_id_t *gid, int *op, cp_grant_id_t *gids, endpoint_t *io_ept,
void **buffer, int *vec_grants, size_t bytes));
FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *,
int));
FORWARD _PROTOTYPE( int gen_opcl, (endpoint_t driver_e, int op,
dev_t dev, endpoint_t proc_e, int flags) );
FORWARD _PROTOTYPE( int gen_io, (endpoint_t task_nr, message *mess_ptr) );
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
PUBLIC int fs_new_driver(void)
{
/* New driver endpoint for this device */
dev_t dev;
dev = (dev_t) fs_m_in.REQ_DEV;
driver_endpoints[major(dev)].driver_e = (endpoint_t) fs_m_in.REQ_DRIVER_E;
return(OK);
}
/*===========================================================================*
* safe_io_conversion *
*===========================================================================*/
PRIVATE int safe_io_conversion(driver, gid, op, gids, io_ept, buffer,
vec_grants, bytes)
endpoint_t driver;
cp_grant_id_t *gid;
int *op;
cp_grant_id_t *gids;
endpoint_t *io_ept;
void **buffer;
int *vec_grants;
size_t bytes;
{
unsigned int j;
int access;
iovec_t *v;
static iovec_t *new_iovec;
STATICINIT(new_iovec, NR_IOREQS);
/* Number of grants allocated in vector I/O. */
*vec_grants = 0;
/* Driver can handle it - change request to a safe one. */
*gid = GRANT_INVALID;
switch(*op) {
case MFS_DEV_READ:
case MFS_DEV_WRITE:
/* Change to safe op. */
*op = *op == MFS_DEV_READ ? DEV_READ_S : DEV_WRITE_S;
*gid = cpf_grant_direct(driver, (vir_bytes) *buffer, bytes,
*op == DEV_READ_S ? CPF_WRITE : CPF_READ);
if(*gid == GRANT_INVALID) {
panic("cpf_grant_magic of buffer failed");
}
break;
case MFS_DEV_GATHER:
case MFS_DEV_SCATTER:
/* Change to safe op. */
*op = *op == MFS_DEV_GATHER ? DEV_GATHER_S : DEV_SCATTER_S;
/* Grant access to my new i/o vector. */
*gid = cpf_grant_direct(driver, (vir_bytes) new_iovec,
bytes * sizeof(iovec_t), CPF_READ|CPF_WRITE);
if(*gid == GRANT_INVALID) {
panic("cpf_grant_direct of vector failed");
}
v = (iovec_t *) *buffer;
/* Grant access to i/o buffers. */
for(j = 0; j < bytes; j++) {
if(j >= NR_IOREQS)
panic("vec too big: %u", bytes);
access = (*op == DEV_GATHER_S) ? CPF_WRITE : CPF_READ;
new_iovec[j].iov_addr = gids[j] =
cpf_grant_direct(driver, (vir_bytes) v[j].iov_addr,
(size_t) v[j].iov_size, access);
if(!GRANT_VALID(gids[j])) {
panic("ext2: grant to iovec buf failed");
}
new_iovec[j].iov_size = v[j].iov_size;
(*vec_grants)++;
}
/* Set user's vector to the new one. */
*buffer = new_iovec;
break;
default:
panic("Illegal operation %d\n", *op);
break;
}
/* If we have converted to a safe operation, I/O
* endpoint becomes FS if it wasn't already.
*/
if(GRANT_VALID(*gid)) {
*io_ept = SELF_E;
return 1;
}
/* Not converted to a safe operation (because there is no
* copying involved in this operation).
*/
return 0;
}
/*===========================================================================*
* safe_io_cleanup *
*===========================================================================*/
PRIVATE void safe_io_cleanup(gid, gids, gids_size)
cp_grant_id_t gid;
cp_grant_id_t *gids;
int gids_size;
{
/* Free resources (specifically, grants) allocated by safe_io_conversion(). */
int j;
(void) cpf_revoke(gid);
for(j = 0; j < gids_size; j++)
(void) cpf_revoke(gids[j]);
return;
}
/*===========================================================================*
* block_dev_io *
*===========================================================================*/
PUBLIC int block_dev_io(
int op, /* MFS_DEV_READ, MFS_DEV_WRITE, etc. */
dev_t dev, /* major-minor device number */
endpoint_t proc_e, /* in whose address space is buf? */
void *buffer, /* virtual address of the buffer */
u64_t pos, /* byte position */
size_t bytes /* how many bytes to transfer */
)
{
/* Read or write from a device. The parameter 'dev' tells which one. */
int r, safe;
message m;
cp_grant_id_t gid = GRANT_INVALID;
int vec_grants;
int op_used;
void *buf_used;
static cp_grant_id_t *gids;
endpoint_t driver_e;
STATICINIT(gids, NR_IOREQS);
/* Determine driver endpoint for this device */
driver_e = driver_endpoints[major(dev)].driver_e;
/* See if driver is roughly valid. */
if (driver_e == NONE) {
printf("ext2(%d) block_dev_io: no driver for dev %x\n", SELF_E, dev);
return(EDEADEPT);
}
/* The io vector copying relies on this I/O being for FS itself. */
if(proc_e != SELF_E) {
printf("ext2(%d) doing block_dev_io for non-self %d\n", SELF_E, proc_e);
panic("doing block_dev_io for non-self: %d", proc_e);
}
/* By default, these are right. */
m.USER_ENDPT = proc_e;
m.ADDRESS = buffer;
buf_used = buffer;
/* Convert parameters to 'safe mode'. */
op_used = op;
safe = safe_io_conversion(driver_e, &gid, &op_used, gids, &m.USER_ENDPT,
&buf_used, &vec_grants, bytes);
/* Set up rest of the message. */
if (safe) m.IO_GRANT = (char *) gid;
m.m_type = op_used;
m.DEVICE = minor(dev);
m.POSITION = ex64lo(pos);
m.COUNT = bytes;
m.HIGHPOS = ex64hi(pos);
/* Call the task. */
r = sendrec(driver_e, &m);
if(r == OK && m.REP_STATUS == ERESTART) r = EDEADEPT;
/* As block I/O never SUSPENDs, safe cleanup must be done whether
* the I/O succeeded or not. */
if (safe) safe_io_cleanup(gid, gids, vec_grants);
/* RECOVERY:
* - send back dead driver number
* - VFS unmaps it, waits for new driver
* - VFS sends the new driver endp for the FS proc and the request again
*/
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("ext2(%d) dead driver %d\n", SELF_E, driver_e);
driver_endpoints[major(dev)].driver_e = NONE;
return(r);
} else if (r == ELOCKED) {
printf("ext2(%d) ELOCKED talking to %d\n", SELF_E, driver_e);
return(r);
} else
panic("call_task: can't send/receive: %d", r);
} else {
/* Did the process we did the sendrec() for get a result? */
if (m.REP_ENDPT != proc_e) {
printf("ext2(%d) strange device reply from %d, type = %d, proc "
"= %d (not %d) (2) ignored\n", SELF_E, m.m_source,
m.m_type, proc_e, m.REP_ENDPT);
r = EIO;
}
}
/* Task has completed. See if call completed. */
if (m.REP_STATUS == SUSPEND) {
panic("ext2 block_dev_io: driver returned SUSPEND");
}
if(buffer != buf_used && r == OK) {
memcpy(buffer, buf_used, bytes * sizeof(iovec_t));
}
return(m.REP_STATUS);
}
/*===========================================================================*
* dev_open *
*===========================================================================*/
PUBLIC int dev_open(
endpoint_t driver_e,
dev_t dev, /* device to open */
endpoint_t proc_e, /* process to open for */
int flags /* mode bits and flags */
)
{
int major, r;
/* Determine the major device number call the device class specific
* open/close routine. (This is the only routine that must check the
* device number for being in range. All others can trust this check.)
*/
major = major(dev);
if (major >= NR_DEVICES) {
printf("Major device number %d not in range\n", major(dev));
return(EIO);
}
r = gen_opcl(driver_e, DEV_OPEN, dev, proc_e, flags);
if (r == SUSPEND) panic("suspend on open from");
return(r);
}
/*===========================================================================*
* dev_close *
*===========================================================================*/
PUBLIC void dev_close(
endpoint_t driver_e,
dev_t dev /* device to close */
)
{
(void) gen_opcl(driver_e, DEV_CLOSE, dev, 0, 0);
}
/*===========================================================================*
* gen_opcl *
*===========================================================================*/
PRIVATE int gen_opcl(
endpoint_t driver_e,
int op, /* operation, DEV_OPEN or DEV_CLOSE */
dev_t dev, /* device to open or close */
endpoint_t proc_e, /* process to open/close for */
int flags /* mode bits and flags */
)
{
/* Called from the dmap struct in table.c on opens & closes of special files.*/
message dev_mess;
dev_mess.m_type = op;
dev_mess.DEVICE = minor(dev);
dev_mess.USER_ENDPT = proc_e;
dev_mess.COUNT = flags;
/* Call the task. */
(void) gen_io(driver_e, &dev_mess);
return(dev_mess.REP_STATUS);
}
/*===========================================================================*
* gen_io *
*===========================================================================*/
PRIVATE int gen_io(
endpoint_t task_nr, /* which task to call */
message *mess_ptr /* pointer to message for task */
)
{
/* All file system I/O ultimately comes down to I/O on major/minor device
* pairs. These lead to calls on the following routines via the dmap table.
*/
int r, proc_e;
proc_e = mess_ptr->USER_ENDPT;
r = sendrec(task_nr, mess_ptr);
if(r == OK && mess_ptr->REP_STATUS == ERESTART)
r = EDEADEPT;
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("fs: dead driver %d\n", task_nr);
panic("should handle crashed drivers");
return(r);
}
if (r == ELOCKED) {
printf("fs: ELOCKED talking to %d\n", task_nr);
return(r);
}
panic("call_task: can't send/receive: %d", r);
}
/* Did the process we did the sendrec() for get a result? */
if (mess_ptr->REP_ENDPT != proc_e) {
printf("fs: strange device reply from %d, type = %d, proc = %d (not "
"%d) (2) ignored\n", mess_ptr->m_source, mess_ptr->m_type,
proc_e,
mess_ptr->REP_ENDPT);
return(EIO);
}
return(OK);
}

View file

@ -1,11 +0,0 @@
#ifndef EXT2_DRIVERS_H
#define EXT2_DRIVERS_H
/* Driver endpoints for major devices. Only the block devices
* are mapped here, it's a subset of the mapping in the VFS */
EXTERN struct driver_endpoints {
endpoint_t driver_e;
} driver_endpoints[NR_DEVICES];
#endif /* EXT2_DRIVERS_H */

View file

@ -11,7 +11,6 @@
#include <minix/optset.h> #include <minix/optset.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "drivers.h"
/* Declare some local functions. */ /* Declare some local functions. */
FORWARD _PROTOTYPE(void get_work, (message *m_in) ); FORWARD _PROTOTYPE(void get_work, (message *m_in) );
@ -101,6 +100,8 @@ PUBLIC int main(int argc, char *argv[])
if (error == OK) if (error == OK)
read_ahead(); /* do block read ahead */ read_ahead(); /* do block read ahead */
} }
return 0;
} }
/*===========================================================================* /*===========================================================================*
@ -151,10 +152,6 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
init_inode_cache(); init_inode_cache();
/* Init driver mapping */
for (i = 0; i < NR_DEVICES; ++i)
driver_endpoints[i].driver_e = NONE;
SELF_E = getprocnr(); SELF_E = getprocnr();
/* just a small number before we find out the block size at mount time */ /* just a small number before we find out the block size at mount time */

View file

@ -5,6 +5,7 @@
#include "fs.h" #include "fs.h"
#include <assert.h> #include <assert.h>
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/bdev.h>
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
@ -62,3 +63,20 @@ PUBLIC int fs_flush()
return(OK); return(OK);
} }
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
PUBLIC int fs_new_driver(void)
{
/* Set a new driver endpoint for this device. */
dev_t dev;
endpoint_t endpt;
dev = (dev_t) fs_m_in.REQ_DEV;
endpt = (endpoint_t) fs_m_in.REQ_DRIVER_E;
bdev_driver(dev, endpt);
return(OK);
}

View file

@ -10,9 +10,9 @@
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include "drivers.h"
#include <minix/ds.h> #include <minix/ds.h>
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/bdev.h>
/*===========================================================================* /*===========================================================================*
@ -61,11 +61,10 @@ PUBLIC int fs_readsuper()
} }
/* Map the driver endpoint for this major */ /* Map the driver endpoint for this major */
driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = driver_e; bdev_driver(fs_dev, driver_e);
/* Open the device the file system lives on. */ /* Open the device the file system lives on. */
if (dev_open(driver_e, fs_dev, driver_e, if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT)) != OK) {
readonly ? R_BIT : (R_BIT|W_BIT)) != OK) {
return(EINVAL); return(EINVAL);
} }
@ -79,7 +78,7 @@ PUBLIC int fs_readsuper()
/* Is it recognized as a Minix filesystem? */ /* Is it recognized as a Minix filesystem? */
if (r != OK) { if (r != OK) {
superblock->s_dev = NO_DEV; superblock->s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(r); return(r);
} }
@ -120,7 +119,7 @@ PUBLIC int fs_readsuper()
if (superblock->s_state == EXT2_ERROR_FS) { if (superblock->s_state == EXT2_ERROR_FS) {
printf("ext2: filesystem wasn't cleanly unmounted previous time\n"); printf("ext2: filesystem wasn't cleanly unmounted previous time\n");
superblock->s_dev = NO_DEV; superblock->s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(EINVAL); return(EINVAL);
} }
@ -134,7 +133,7 @@ PUBLIC int fs_readsuper()
if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) {
printf("ext2: couldn't get root inode\n"); printf("ext2: couldn't get root inode\n");
superblock->s_dev = NO_DEV; superblock->s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(EINVAL); return(EINVAL);
} }
@ -142,7 +141,7 @@ PUBLIC int fs_readsuper()
printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__);
put_inode(root_ip); put_inode(root_ip);
superblock->s_dev = NO_DEV; superblock->s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(EINVAL); return(EINVAL);
} }
@ -151,7 +150,7 @@ PUBLIC int fs_readsuper()
__FILE__, __LINE__); __FILE__, __LINE__);
put_inode(root_ip); put_inode(root_ip);
superblock->s_dev = NO_DEV; superblock->s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(EINVAL); return(EINVAL);
} }
@ -253,7 +252,7 @@ PUBLIC int fs_unmount()
} }
/* Close the device the file system lives on. */ /* Close the device the file system lives on. */
dev_close(driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e, fs_dev); bdev_close(fs_dev);
/* Finish off the unmount. */ /* Finish off the unmount. */
superblock->s_dev = NO_DEV; superblock->s_dev = NO_DEV;

View file

@ -21,6 +21,7 @@
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/libminixfs.h>
PUBLIC char dot1[2] = "."; /* used for search_dir to bypass the access */ PUBLIC char dot1[2] = "."; /* used for search_dir to bypass the access */
PUBLIC char dot2[3] = ".."; /* permissions for . and .. */ PUBLIC char dot2[3] = ".."; /* permissions for . and .. */

View file

@ -26,14 +26,6 @@ _PROTOTYPE( void set_blocksize, (unsigned int blocksize, u32_t blocks,
_PROTOTYPE( void rw_scattered, (dev_t dev, _PROTOTYPE( void rw_scattered, (dev_t dev,
struct buf **bufq, int bufqsize, int rw_flag) ); struct buf **bufq, int bufqsize, int rw_flag) );
/* device.c */
_PROTOTYPE( int block_dev_io, (int op, dev_t dev, endpoint_t proc_e,
void *buf, u64_t pos, size_t bytes) );
_PROTOTYPE( int dev_open, (endpoint_t driver_e, dev_t dev, endpoint_t proc_e,
int flags) );
_PROTOTYPE( void dev_close, (endpoint_t driver_e, dev_t dev) );
_PROTOTYPE( int fs_new_driver, (void) );
/* ialloc.c */ /* ialloc.c */
_PROTOTYPE( struct inode *alloc_inode, (struct inode *parent, mode_t bits)); _PROTOTYPE( struct inode *alloc_inode, (struct inode *parent, mode_t bits));
_PROTOTYPE( void free_inode, (struct inode *rip) ); _PROTOTYPE( void free_inode, (struct inode *rip) );
@ -59,6 +51,7 @@ _PROTOTYPE( int truncate_inode, (struct inode *rip, off_t len) );
/* misc.c */ /* misc.c */
_PROTOTYPE( int fs_flush, (void) ); _PROTOTYPE( int fs_flush, (void) );
_PROTOTYPE( int fs_sync, (void) ); _PROTOTYPE( int fs_sync, (void) );
_PROTOTYPE( int fs_new_driver, (void) );
/* mount.c */ /* mount.c */
_PROTOTYPE( int fs_mountpoint, (void) ); _PROTOTYPE( int fs_mountpoint, (void) );

View file

@ -14,6 +14,7 @@
#include <assert.h> #include <assert.h>
#include <minix/com.h> #include <minix/com.h>
#include <minix/u64.h> #include <minix/u64.h>
#include <minix/bdev.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
@ -92,9 +93,8 @@ register struct super_block *sp; /* pointer to a superblock */
panic("can't allocate memory for super_block buffers"); panic("can't allocate memory for super_block buffers");
assert(_MIN_BLOCK_SIZE <= sizeof(*ondisk_superblock)); assert(_MIN_BLOCK_SIZE <= sizeof(*ondisk_superblock));
r = block_dev_io(MFS_DEV_READ, dev, SELF_E, r = bdev_read(dev, cvu64(super_block_offset), (char*) ondisk_superblock,
(char*) ondisk_superblock, cvu64(super_block_offset), _MIN_BLOCK_SIZE, BDEV_NOFLAGS);
_MIN_BLOCK_SIZE);
if (r != _MIN_BLOCK_SIZE) if (r != _MIN_BLOCK_SIZE)
return(EINVAL); return(EINVAL);
@ -178,9 +178,8 @@ register struct super_block *sp; /* pointer to a superblock */
gdt_position = (opt.block_with_super + 1) * 1024; gdt_position = (opt.block_with_super + 1) * 1024;
} }
r = block_dev_io(MFS_DEV_READ, dev, SELF_E, r = bdev_read(dev, cvu64(gdt_position), (char*) ondisk_group_descs,
(char*) ondisk_group_descs, cvu64(gdt_position), gd_size, BDEV_NOFLAGS);
gd_size);
if (r != gd_size) { if (r != gd_size) {
printf("Can not read group descriptors\n"); printf("Can not read group descriptors\n");
return(EINVAL); return(EINVAL);
@ -232,8 +231,8 @@ struct super_block *sp; /* pointer to a superblock */
super_copy(ondisk_superblock, sp); super_copy(ondisk_superblock, sp);
r = block_dev_io(MFS_DEV_WRITE, sp->s_dev, SELF_E, r = bdev_write(sp->s_dev, cvu64(super_block_offset), (char *) sp,
sp, cvu64(super_block_offset), SUPER_SIZE_D); SUPER_SIZE_D, BDEV_NOFLAGS);
if (r != SUPER_SIZE_D) if (r != SUPER_SIZE_D)
printf("ext2: Warning, failed to write superblock to the disk!\n"); printf("ext2: Warning, failed to write superblock to the disk!\n");
@ -250,9 +249,8 @@ struct super_block *sp; /* pointer to a superblock */
copy_group_descriptors(ondisk_group_descs, sp->s_group_desc, copy_group_descriptors(ondisk_group_descs, sp->s_group_desc,
sp->s_groups_count); sp->s_groups_count);
r = block_dev_io(MFS_DEV_WRITE, sp->s_dev, SELF_E, r = bdev_write(sp->s_dev, cvu64(gdt_position),
(char*) ondisk_group_descs, cvu64(gdt_position), (char*) ondisk_group_descs, gd_size, BDEV_NOFLAGS);
gd_size);
if (r != gd_size) { if (r != gd_size) {
printf("Can not write group descriptors\n"); printf("Can not write group descriptors\n");
} }

View file

@ -11,7 +11,6 @@
#include "inode.h" #include "inode.h"
#include "buf.h" #include "buf.h"
#include "super.h" #include "super.h"
#include "drivers.h"
PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
no_sys, /* 0 not used */ no_sys, /* 0 not used */

View file

@ -1,10 +1,10 @@
# Makefile for ISO9660 fs # Makefile for ISO9660 fs
PROG= isofs PROG= isofs
SRCS= main.c table.c mount.c super.c inode.c device.c \ SRCS= main.c table.c mount.c super.c inode.c \
utility.c misc.c path.c read.c stadir.c cache.c utility.c misc.c path.c read.c stadir.c cache.c
DPADD+= ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBSYS} ${LIBTIMERS}
LDADD+= -lsys -ltimers LDADD+= -lbdev -lsys
MAN= MAN=

View file

@ -14,6 +14,7 @@
#include "inc.h" #include "inc.h"
#include <minix/com.h> #include <minix/com.h>
#include <minix/u64.h> #include <minix/u64.h>
#include <minix/bdev.h>
#include "buf.h" #include "buf.h"
FORWARD _PROTOTYPE(int read_block, (struct buf *)); FORWARD _PROTOTYPE(int read_block, (struct buf *));
@ -89,7 +90,7 @@ register struct buf *bp; /* pointer to the buffer to be released */
PRIVATE int read_block(bp) PRIVATE int read_block(bp)
register struct buf *bp; /* buffer pointer */ register struct buf *bp; /* buffer pointer */
{ {
int r, op; int r;
u64_t pos; u64_t pos;
int block_size; int block_size;
@ -98,8 +99,7 @@ register struct buf *bp; /* buffer pointer */
pos = mul64u(bp->b_blocknr, block_size); /* get absolute position */ pos = mul64u(bp->b_blocknr, block_size); /* get absolute position */
op = MFS_DEV_READ; /* flag to read */ r = bdev_read(fs_dev, pos, bp->b_data, block_size, BDEV_NOFLAGS);
r = block_dev_io(op, fs_dev, SELF_E, bp->b_data, pos, block_size, 0);
if (r != block_size) { if (r != block_size) {
if (r >= 0) r = END_OF_FILE; if (r >= 0) r = END_OF_FILE;
if (r != END_OF_FILE) if (r != END_OF_FILE)

View file

@ -55,11 +55,6 @@
/* maximum size of length of name file used in dir records */ /* maximum size of length of name file used in dir records */
#define ISO9660_MAX_FILE_ID_LEN 32 #define ISO9660_MAX_FILE_ID_LEN 32
#define MFS_DEV_READ 10001
#define MFS_DEV_WRITE 10002
#define MFS_DEV_SCATTER 10003
#define MFS_DEV_GATHER 10004
#define END_OF_FILE (-104) /* eof detected */ #define END_OF_FILE (-104) /* eof detected */
/* Miscellaneous constants */ /* Miscellaneous constants */

View file

@ -1,337 +0,0 @@
#include "inc.h"
#include <minix/vfsif.h>
FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t, cp_grant_id_t *,
int *, cp_grant_id_t *, int,
endpoint_t *, void **, int *,
vir_bytes));
FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *,
int));
FORWARD _PROTOTYPE( int gen_opcl, (endpoint_t driver_e, int op,
dev_t dev, int proc_e, int flags));
FORWARD _PROTOTYPE( int gen_io, (endpoint_t task_nr, message *mess_ptr));
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
PUBLIC int fs_new_driver(void)
{
/* New driver endpoint for this device */
driver_endpoints[(fs_m_in.REQ_DEV >> MAJOR) & BYTE].driver_e =
fs_m_in.REQ_DRIVER_E;
return(OK);
}
/*===========================================================================*
* safe_io_conversion *
*===========================================================================*/
PRIVATE int safe_io_conversion(driver, gid, op, gids, gids_size,
io_ept, buf, vec_grants, bytes)
endpoint_t driver;
cp_grant_id_t *gid;
int *op;
cp_grant_id_t *gids;
int gids_size;
endpoint_t *io_ept;
void **buf;
int *vec_grants;
vir_bytes bytes;
{
int j;
iovec_t *v;
static iovec_t new_iovec[NR_IOREQS];
/* Number of grants allocated in vector I/O. */
*vec_grants = 0;
/* Driver can handle it - change request to a safe one. */
*gid = GRANT_INVALID;
switch(*op) {
case MFS_DEV_READ:
case MFS_DEV_WRITE:
/* Change to safe op. */
*op = *op == MFS_DEV_READ ? DEV_READ_S : DEV_WRITE_S;
if((*gid=cpf_grant_direct(driver, (vir_bytes) *buf,
bytes, *op == DEV_READ_S ? CPF_WRITE :
CPF_READ)) < 0) {
panic("cpf_grant_magic of buffer failed");
}
break;
case MFS_DEV_GATHER:
case MFS_DEV_SCATTER:
/* Change to safe op. */
*op = *op == MFS_DEV_GATHER ?
DEV_GATHER_S : DEV_SCATTER_S;
/* Grant access to my new i/o vector. */
if((*gid = cpf_grant_direct(driver,
(vir_bytes) new_iovec, bytes * sizeof(iovec_t),
CPF_READ | CPF_WRITE)) < 0) {
panic("cpf_grant_direct of vector failed");
}
v = (iovec_t *) *buf;
/* Grant access to i/o buffers. */
for(j = 0; j < bytes; j++) {
if(j >= NR_IOREQS)
panic("vec too big: %d", bytes);
new_iovec[j].iov_addr = gids[j] =
cpf_grant_direct(driver, (vir_bytes)
v[j].iov_addr, v[j].iov_size,
*op == DEV_GATHER_S ? CPF_WRITE : CPF_READ);
if(!GRANT_VALID(gids[j])) {
panic("mfs: grant to iovec buf failed");
}
new_iovec[j].iov_size = v[j].iov_size;
(*vec_grants)++;
}
/* Set user's vector to the new one. */
*buf = new_iovec;
break;
}
/* If we have converted to a safe operation, I/O
* endpoint becomes FS if it wasn't already.
*/
if(GRANT_VALID(*gid)) {
*io_ept = SELF_E;
return 1;
}
/* Not converted to a safe operation (because there is no
* copying involved in this operation).
*/
return 0;
}
/*===========================================================================*
* safe_io_cleanup *
*===========================================================================*/
PRIVATE void safe_io_cleanup(gid, gids, gids_size)
cp_grant_id_t gid;
cp_grant_id_t *gids;
int gids_size;
{
/* Free resources (specifically, grants) allocated by safe_io_conversion(). */
int j;
cpf_revoke(gid);
for(j = 0; j < gids_size; j++)
cpf_revoke(gids[j]);
return;
}
/*===========================================================================*
* dev_open *
*===========================================================================*/
PUBLIC int dev_open(
endpoint_t driver_e,
dev_t dev, /* device to open */
int proc, /* process to open for */
int flags /* mode bits and flags */
)
{
int major, r;
/* Determine the major device number call the device class specific
* open/close routine. (This is the only routine that must check the
* device number for being in range. All others can trust this check.)
*/
major = (dev >> MAJOR) & BYTE;
if (major >= NR_DEVICES) major = 0;
r = gen_opcl(driver_e, DEV_OPEN, dev, proc, flags);
if (r == SUSPEND) panic("suspend on open from");
return(r);
}
/*===========================================================================*
* block_dev_io *
*===========================================================================*/
PUBLIC int block_dev_io(
int op, /* MFS_DEV_READ, MFS_DEV_WRITE, etc. */
dev_t dev, /* major-minor device number */
int proc_e, /* in whose address space is buf? */
void *buf, /* virtual address of the buffer */
u64_t pos, /* byte position */
int bytes, /* how many bytes to transfer */
int flags /* special flags, like O_NONBLOCK */
)
{
/* Read or write from a device. The parameter 'dev' tells which one. */
int r, safe;
message m;
cp_grant_id_t gid = GRANT_INVALID;
int vec_grants;
int op_used;
void *buf_used;
static cp_grant_id_t gids[NR_IOREQS];
endpoint_t driver_e;
/* Determine driver endpoint for this device */
driver_e = driver_endpoints[(dev >> MAJOR) & BYTE].driver_e;
/* See if driver is roughly valid. */
if (driver_e == NONE) return(EDEADEPT);
/* The io vector copying relies on this I/O being for FS itself. */
if(proc_e != SELF_E) {
printf("ISOFS(%d) doing block_dev_io for non-self %d\n", SELF_E, proc_e);
panic("doing block_dev_io for non-self: %d", proc_e);
}
/* By default, these are right. */
m.USER_ENDPT = proc_e;
m.ADDRESS = buf;
buf_used = buf;
/* Convert parameters to 'safe mode'. */
op_used = op;
safe = safe_io_conversion(driver_e, &gid,
&op_used, gids, NR_IOREQS, &m.USER_ENDPT, &buf_used,
&vec_grants, bytes);
/* Set up rest of the message. */
if (safe) m.IO_GRANT = (char *) gid;
m.m_type = op_used;
m.DEVICE = (dev >> MINOR) & BYTE;
m.POSITION = ex64lo(pos);
m.COUNT = bytes;
m.HIGHPOS = ex64hi(pos);
/* Call the task. */
r = sendrec(driver_e, &m);
if(r == OK && m.REP_STATUS == ERESTART) r = EDEADEPT;
/* As block I/O never SUSPENDs, safe cleanup must be done whether
* the I/O succeeded or not. */
if (safe) safe_io_cleanup(gid, gids, vec_grants);
/* RECOVERY:
* - send back dead driver number
* - VFS unmaps it, waits for new driver
* - VFS sends the new driver endp for the FS proc and the request again
*/
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("ISOFS(%d) dead driver %d\n", SELF_E, driver_e);
driver_endpoints[(dev >> MAJOR) & BYTE].driver_e = NONE;
return(r);
}
else if (r == ELOCKED) {
return(r);
}
else
panic("call_task: can't send/receive: %d", r);
} else {
/* Did the process we did the sendrec() for get a result? */
if (m.REP_ENDPT != proc_e) {
printf("ISOFS (%d) strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n", SELF_E, m.m_source, m.m_type, proc_e, m.REP_ENDPT);
r = EIO;
}
}
/* Task has completed. See if call completed. */
if (m.REP_STATUS == SUSPEND) {
panic("ISOFS block_dev_io: driver returned SUSPEND");
}
if(buf != buf_used && r == OK) {
memcpy(buf, buf_used, bytes * sizeof(iovec_t));
}
return(m.REP_STATUS);
}
/*===========================================================================*
* gen_opcl *
*===========================================================================*/
PRIVATE int gen_opcl(
endpoint_t driver_e,
int op, /* operation, DEV_OPEN or DEV_CLOSE */
dev_t dev, /* device to open or close */
int proc_e, /* process to open/close for */
int flags /* mode bits and flags */
)
{
/* Called from the dmap struct in table.c on opens & closes of special files.*/
message dev_mess;
dev_mess.m_type = op;
dev_mess.DEVICE = (dev >> MINOR) & BYTE;
dev_mess.USER_ENDPT = proc_e;
dev_mess.COUNT = flags;
/* Call the task. */
gen_io(driver_e, &dev_mess);
return(dev_mess.REP_STATUS);
}
/*===========================================================================*
* gen_io *
*===========================================================================*/
PRIVATE int gen_io(task_nr, mess_ptr)
endpoint_t task_nr; /* which task to call */
message *mess_ptr; /* pointer to message for task */
{
/* All file system I/O ultimately comes down to I/O on major/minor device
* pairs. These lead to calls on the following routines via the dmap table.
*/
int r, proc_e;
proc_e = mess_ptr->USER_ENDPT;
r = sendrec(task_nr, mess_ptr);
if(r == OK && mess_ptr->REP_STATUS == ERESTART) r = EDEADEPT;
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("fs: dead driver %d\n", task_nr);
panic("should handle crashed drivers");
/* dmap_unmap_by_endpt(task_nr); */
return r;
}
if (r == ELOCKED) {
printf("fs: ELOCKED talking to %d\n", task_nr);
return r;
}
panic("call_task: can't send/receive: %d", r);
}
/* Did the process we did the sendrec() for get a result? */
if (mess_ptr->REP_ENDPT != proc_e) {
printf(
"fs: strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n",
mess_ptr->m_source,
mess_ptr->m_type,
proc_e,
mess_ptr->REP_ENDPT);
return(EIO);
}
return(OK);
}
/*===========================================================================*
* dev_close *
*===========================================================================*/
PUBLIC void dev_close(endpoint_t driver_e, dev_t dev)
{
(void) gen_opcl(driver_e, DEV_CLOSE, dev, 0, 0);
}

View file

@ -1,9 +0,0 @@
#include <minix/dmap.h>
/* Driver endpoints for major devices. Only the block devices
* are mapped here, it's a subset of the mapping in the VFS */
EXTERN struct driver_endpoints {
endpoint_t driver_e;
} driver_endpoints[NR_DEVICES];

View file

@ -31,4 +31,3 @@
#include "proto.h" #include "proto.h"
#include "super.h" #include "super.h"
#include "glo.h" #include "glo.h"
#include "drivers.h"

View file

@ -1,5 +1,3 @@
/* This file contains the main directory for the server. It waits for a /* This file contains the main directory for the server. It waits for a
* request and then send a response. */ * request and then send a response. */
@ -101,11 +99,7 @@ PRIVATE void sef_local_startup()
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
{ {
/* Initialize the iso9660fs server. */ /* Initialize the iso9660fs server. */
int i;
/* Init driver mapping */
for (i = 0; i < NR_DEVICES; ++i)
driver_endpoints[i].driver_e = NONE;
/* SELF_E will contain the id of this process */ /* SELF_E will contain the id of this process */
SELF_E = getprocnr(); SELF_E = getprocnr();
/* hash_init(); */ /* Init the table with the ids */ /* hash_init(); */ /* Init the table with the ids */

View file

@ -1,6 +1,7 @@
#include "inc.h" #include "inc.h"
#include <fcntl.h> #include <fcntl.h>
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/bdev.h>
/*===========================================================================* /*===========================================================================*
@ -12,3 +13,20 @@ PUBLIC int fs_sync()
return(OK); /* sync() can't fail */ return(OK); /* sync() can't fail */
} }
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
PUBLIC int fs_new_driver()
{
/* Set a new driver endpoint for this device. */
dev_t dev;
endpoint_t endpt;
dev = (dev_t) fs_m_in.REQ_DEV;
endpt = (endpoint_t) fs_m_in.REQ_DRIVER_E;
bdev_driver(dev, endpt);
return(OK);
}

View file

@ -1,6 +1,7 @@
#include "inc.h" #include "inc.h"
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/ds.h> #include <minix/ds.h>
#include <minix/bdev.h>
#include "const.h" #include "const.h"
#include "glo.h" #include "glo.h"
@ -39,18 +40,19 @@ PUBLIC int fs_readsuper() {
} }
/* Map the driver endpoint for this major */ /* Map the driver endpoint for this major */
driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = driver_e; bdev_driver(fs_dev, driver_e);
/* Open the device the file system lives on */ /* Open the device the file system lives on */
if (dev_open(driver_e, fs_dev, driver_e, if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT)) != OK) {
readonly ? R_BIT : (R_BIT|W_BIT)) != OK) {
return(EINVAL); return(EINVAL);
} }
/* Read the superblock */ /* Read the superblock */
r = read_vds(&v_pri, fs_dev); r = read_vds(&v_pri, fs_dev);
if (r != OK) if (r != OK) {
bdev_close(fs_dev);
return(r); return(r);
}
/* Return some root inode properties */ /* Return some root inode properties */
fs_m_out.RES_INODE_NR = ID_DIR_RECORD(v_pri.dir_rec_root); fs_m_out.RES_INODE_NR = ID_DIR_RECORD(v_pri.dir_rec_root);
@ -102,7 +104,7 @@ PUBLIC int fs_mountpoint()
*===========================================================================*/ *===========================================================================*/
PUBLIC int fs_unmount(void) { PUBLIC int fs_unmount(void) {
release_v_pri(&v_pri); /* Release the super block */ release_v_pri(&v_pri); /* Release the super block */
dev_close(driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e, fs_dev); bdev_close(fs_dev);
unmountdone = TRUE; unmountdone = TRUE;
return(OK); return(OK);
} }

View file

@ -13,14 +13,6 @@ _PROTOTYPE( void reply, (int who, message *m_out) );
_PROTOTYPE(struct buf *get_block,(block_t block)); _PROTOTYPE(struct buf *get_block,(block_t block));
_PROTOTYPE(void put_block,(struct buf *bp)); _PROTOTYPE(void put_block,(struct buf *bp));
/* device.c */
_PROTOTYPE( int block_dev_io, (int op, dev_t dev, int proc, void *buf,
u64_t pos, int bytes, int flags) );
_PROTOTYPE( int dev_open, (endpoint_t driver_e, dev_t dev, int proc,
int flags) );
_PROTOTYPE( void dev_close, (endpoint_t driver_e, dev_t dev) );
_PROTOTYPE( int fs_new_driver, (void) );
/* inode.c */ /* inode.c */
_PROTOTYPE( int create_dir_record,(struct dir_record *dir, char *buffer, _PROTOTYPE( int create_dir_record,(struct dir_record *dir, char *buffer,
u32_t address) ); u32_t address) );
@ -35,6 +27,7 @@ _PROTOTYPE( int release_dir_record, (struct dir_record *dir) );
/* misc.c */ /* misc.c */
_PROTOTYPE( int fs_sync, (void) ); _PROTOTYPE( int fs_sync, (void) );
_PROTOTYPE( int fs_new_driver, (void) );
/* mount.c */ /* mount.c */
_PROTOTYPE( int fs_readsuper, (void) ); _PROTOTYPE( int fs_readsuper, (void) );

View file

@ -5,6 +5,7 @@
#include <string.h> #include <string.h>
#include <minix/com.h> #include <minix/com.h>
#include <minix/u64.h> #include <minix/u64.h>
#include <minix/bdev.h>
/* This function is called when the filesystem is umounted. It releases the /* This function is called when the filesystem is umounted. It releases the
* super block. */ * super block. */
@ -94,7 +95,7 @@ PUBLIC int read_vds(
while (!vol_ok && i++<MAX_ATTEMPTS) { while (!vol_ok && i++<MAX_ATTEMPTS) {
/* Read the sector of the super block. */ /* Read the sector of the super block. */
r = block_dev_io(MFS_DEV_READ, dev, SELF_E, sbbuf, offset, ISO9660_MIN_BLOCK_SIZE, 0); r = bdev_read(dev, offset, sbbuf, ISO9660_MIN_BLOCK_SIZE, BDEV_NOFLAGS);
if (r != ISO9660_MIN_BLOCK_SIZE) /* Damaged sector or what? */ if (r != ISO9660_MIN_BLOCK_SIZE) /* Damaged sector or what? */
continue; continue;

View file

@ -1,12 +1,12 @@
# Makefile for Minix File System (MFS) # Makefile for Minix File System (MFS)
PROG= mfs PROG= mfs
SRCS= cache.c device.c link.c \ SRCS= cache.c link.c \
mount.c misc.c open.c protect.c read.c \ mount.c misc.c open.c protect.c read.c \
stadir.c stats.c table.c time.c utility.c \ stadir.c stats.c table.c time.c utility.c \
write.c inode.c main.c path.c super.c write.c inode.c main.c path.c super.c
DPADD+= ${LIBM} ${LIBSYS} DPADD+= ${LIBM} ${LIBSYS}
LDADD+= -lminixfs -lsys LDADD+= -lminixfs -lbdev -lsys
MAN= MAN=

View file

@ -16,6 +16,7 @@
#include "fs.h" #include "fs.h"
#include <minix/u64.h> #include <minix/u64.h>
#include <minix/bdev.h>
#include <sys/param.h> #include <sys/param.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
@ -326,7 +327,7 @@ int rw_flag; /* READING or WRITING */
* is not reported to the caller. If the error occurred while purging a block * is not reported to the caller. If the error occurred while purging a block
* from the cache, it is not clear what the caller could do about it anyway. * from the cache, it is not clear what the caller could do about it anyway.
*/ */
int r, op, op_failed; int r, op_failed;
u64_t pos; u64_t pos;
dev_t dev; dev_t dev;
@ -334,8 +335,12 @@ int rw_flag; /* READING or WRITING */
if ( (dev = bp->b_dev) != NO_DEV) { if ( (dev = bp->b_dev) != NO_DEV) {
pos = mul64u(bp->b_blocknr, fs_block_size); pos = mul64u(bp->b_blocknr, fs_block_size);
op = (rw_flag == READING ? MFS_DEV_READ : MFS_DEV_WRITE); if (rw_flag == READING)
r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, fs_block_size); r = bdev_read(dev, pos, bp->b_data, fs_block_size,
BDEV_NOFLAGS);
else
r = bdev_write(dev, pos, bp->b_data, fs_block_size,
BDEV_NOFLAGS);
if (r < 0) { if (r < 0) {
printf("MFS(%d) I/O error on device %d/%d, block %u\n", printf("MFS(%d) I/O error on device %d/%d, block %u\n",
SELF_E, major(dev), minor(dev), bp->b_blocknr); SELF_E, major(dev), minor(dev), bp->b_blocknr);
@ -420,6 +425,8 @@ PUBLIC void rw_scattered(
register int i; register int i;
register iovec_t *iop; register iovec_t *iop;
static iovec_t *iovec = NULL; static iovec_t *iovec = NULL;
vir_bytes size;
u64_t pos;
int j, r; int j, r;
STATICINIT(iovec, NR_IOREQS); STATICINIT(iovec, NR_IOREQS);
@ -442,7 +449,7 @@ PUBLIC void rw_scattered(
} }
} }
/* Set up I/O vector and do I/O. The result of dev_io is OK if everything /* Set up I/O vector and do I/O. The result of bdev I/O is OK if everything
* went fine, otherwise the error code for the first failed transfer. * went fine, otherwise the error code for the first failed transfer.
*/ */
while (bufqsize > 0) { while (bufqsize > 0) {
@ -452,16 +459,18 @@ PUBLIC void rw_scattered(
iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_addr = (vir_bytes) bp->b_data;
iop->iov_size = (vir_bytes) fs_block_size; iop->iov_size = (vir_bytes) fs_block_size;
} }
r = block_dev_io(rw_flag == WRITING ? MFS_DEV_SCATTER : MFS_DEV_GATHER, pos = mul64u(bufq[0]->b_blocknr, fs_block_size);
dev, SELF_E, iovec, if (rw_flag == READING)
mul64u(bufq[0]->b_blocknr, fs_block_size), j); r = bdev_gather(dev, pos, iovec, j, BDEV_NOFLAGS, &size);
else
r = bdev_scatter(dev, pos, iovec, j, BDEV_NOFLAGS, &size);
/* Harvest the results. Dev_io reports the first error it may have /* Harvest the results. libbdev reports the first error it may have
* encountered, but we only care if it's the first block that failed. * encountered, but we only care if it's the first block that failed.
*/ */
for (i = 0, iop = iovec; i < j; i++, iop++) { for (i = 0, iop = iovec; i < j; i++, iop++) {
bp = bufq[i]; bp = bufq[i];
if (iop->iov_size != 0) { if (size < iop->iov_size) {
/* Transfer failed. An error? Do we care? */ /* Transfer failed. An error? Do we care? */
if (r != OK && i == 0) { if (r != OK && i == 0) {
printf( printf(
@ -478,6 +487,7 @@ PUBLIC void rw_scattered(
} else { } else {
bp->b_dirt = CLEAN; bp->b_dirt = CLEAN;
} }
size -= iop->iov_size;
} }
bufq += i; bufq += i;
bufqsize -= i; bufqsize -= i;

View file

@ -98,11 +98,5 @@
#define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m)) #define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m))
/* Args to dev_bio/dev_io */
#define MFS_DEV_READ 10001
#define MFS_DEV_WRITE 10002
#define MFS_DEV_SCATTER 10003
#define MFS_DEV_GATHER 10004
#endif #endif

View file

@ -1,360 +0,0 @@
#include "fs.h"
#include <minix/com.h>
#include <minix/endpoint.h>
#include <minix/safecopies.h>
#include <minix/u64.h>
#include <string.h>
#include "inode.h"
#include "super.h"
#include "const.h"
#include "drivers.h"
#include <minix/vfsif.h>
FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t driver,
cp_grant_id_t *gid, int *op, cp_grant_id_t *gids, endpoint_t *io_ept,
void **buffer, int *vec_grants, size_t bytes));
FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *,
int));
FORWARD _PROTOTYPE( int gen_opcl, (endpoint_t driver_e, int op,
dev_t dev, endpoint_t proc_e, int flags) );
FORWARD _PROTOTYPE( int gen_io, (endpoint_t task_nr, message *mess_ptr) );
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
PUBLIC int fs_new_driver(void)
{
/* New driver endpoint for this device */
dev_t dev;
dev = (dev_t) fs_m_in.REQ_DEV;
driver_endpoints[major(dev)].driver_e = (endpoint_t) fs_m_in.REQ_DRIVER_E;
return(OK);
}
/*===========================================================================*
* safe_io_conversion *
*===========================================================================*/
PRIVATE int safe_io_conversion(driver, gid, op, gids, io_ept, buffer,
vec_grants, bytes)
endpoint_t driver;
cp_grant_id_t *gid;
int *op;
cp_grant_id_t *gids;
endpoint_t *io_ept;
void **buffer;
int *vec_grants;
size_t bytes;
{
unsigned int j;
int access;
iovec_t *v;
static iovec_t *new_iovec;
STATICINIT(new_iovec, NR_IOREQS);
/* Number of grants allocated in vector I/O. */
*vec_grants = 0;
/* Driver can handle it - change request to a safe one. */
*gid = GRANT_INVALID;
switch(*op) {
case MFS_DEV_READ:
case MFS_DEV_WRITE:
/* Change to safe op. */
*op = *op == MFS_DEV_READ ? DEV_READ_S : DEV_WRITE_S;
*gid = cpf_grant_direct(driver, (vir_bytes) *buffer, bytes,
*op == DEV_READ_S ? CPF_WRITE : CPF_READ);
if(*gid == GRANT_INVALID) {
panic("cpf_grant_magic of buffer failed");
}
break;
case MFS_DEV_GATHER:
case MFS_DEV_SCATTER:
/* Change to safe op. */
*op = *op == MFS_DEV_GATHER ? DEV_GATHER_S : DEV_SCATTER_S;
/* Grant access to my new i/o vector. */
*gid = cpf_grant_direct(driver, (vir_bytes) new_iovec,
bytes * sizeof(iovec_t), CPF_READ|CPF_WRITE);
if(*gid == GRANT_INVALID) {
panic("cpf_grant_direct of vector failed");
}
v = (iovec_t *) *buffer;
/* Grant access to i/o buffers. */
for(j = 0; j < bytes; j++) {
if(j >= NR_IOREQS)
panic("vec too big: %u", bytes);
access = (*op == DEV_GATHER_S) ? CPF_WRITE : CPF_READ;
new_iovec[j].iov_addr = gids[j] =
cpf_grant_direct(driver, (vir_bytes) v[j].iov_addr,
(size_t) v[j].iov_size, access);
if(!GRANT_VALID(gids[j])) {
panic("mfs: grant to iovec buf failed");
}
new_iovec[j].iov_size = v[j].iov_size;
(*vec_grants)++;
}
/* Set user's vector to the new one. */
*buffer = new_iovec;
break;
default:
panic("Illegal operation %d\n", *op);
break;
}
/* If we have converted to a safe operation, I/O
* endpoint becomes FS if it wasn't already.
*/
if(GRANT_VALID(*gid)) {
*io_ept = SELF_E;
return 1;
}
/* Not converted to a safe operation (because there is no
* copying involved in this operation).
*/
return 0;
}
/*===========================================================================*
* safe_io_cleanup *
*===========================================================================*/
PRIVATE void safe_io_cleanup(gid, gids, gids_size)
cp_grant_id_t gid;
cp_grant_id_t *gids;
int gids_size;
{
/* Free resources (specifically, grants) allocated by safe_io_conversion(). */
int j;
(void) cpf_revoke(gid);
for(j = 0; j < gids_size; j++)
(void) cpf_revoke(gids[j]);
return;
}
/*===========================================================================*
* block_dev_io *
*===========================================================================*/
PUBLIC int block_dev_io(
int op, /* MFS_DEV_READ, MFS_DEV_WRITE, etc. */
dev_t dev, /* major-minor device number */
endpoint_t proc_e, /* in whose address space is buf? */
void *buffer, /* virtual address of the buffer */
u64_t pos, /* byte position */
size_t bytes /* how many bytes to transfer */
)
{
/* Read or write from a device. The parameter 'dev' tells which one. */
int r, safe;
message m;
cp_grant_id_t gid = GRANT_INVALID;
int vec_grants;
int op_used;
void *buf_used;
static cp_grant_id_t *gids;
endpoint_t driver_e;
STATICINIT(gids, NR_IOREQS);
/* Determine driver endpoint for this device */
driver_e = driver_endpoints[major(dev)].driver_e;
/* See if driver is roughly valid. */
if (driver_e == NONE) {
printf("MFS(%d) block_dev_io: no driver for dev %x\n", SELF_E, dev);
return(EDEADEPT);
}
/* The io vector copying relies on this I/O being for FS itself. */
if(proc_e != SELF_E) {
printf("MFS(%d) doing block_dev_io for non-self %d\n", SELF_E, proc_e);
panic("doing block_dev_io for non-self: %d", proc_e);
}
/* By default, these are right. */
m.USER_ENDPT = proc_e;
m.ADDRESS = buffer;
buf_used = buffer;
/* Convert parameters to 'safe mode'. */
op_used = op;
safe = safe_io_conversion(driver_e, &gid, &op_used, gids, &m.USER_ENDPT,
&buf_used, &vec_grants, bytes);
/* Set up rest of the message. */
if (safe) m.IO_GRANT = (char *) gid;
m.m_type = op_used;
m.DEVICE = minor(dev);
m.POSITION = ex64lo(pos);
m.COUNT = bytes;
m.HIGHPOS = ex64hi(pos);
/* Call the task. */
r = sendrec(driver_e, &m);
if(r == OK && m.REP_STATUS == ERESTART) r = EDEADEPT;
/* As block I/O never SUSPENDs, safe cleanup must be done whether
* the I/O succeeded or not. */
if (safe) safe_io_cleanup(gid, gids, vec_grants);
/* RECOVERY:
* - send back dead driver number
* - VFS unmaps it, waits for new driver
* - VFS sends the new driver endp for the FS proc and the request again
*/
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("MFS(%d) dead driver %d\n", SELF_E, driver_e);
driver_endpoints[major(dev)].driver_e = NONE;
return(r);
} else if (r == ELOCKED) {
printf("MFS(%d) ELOCKED talking to %d\n", SELF_E, driver_e);
return(r);
} else
panic("call_task: can't send/receive: %d", r);
} else {
/* Did the process we did the sendrec() for get a result? */
if (m.REP_ENDPT != proc_e) {
printf("MFS(%d) strange device reply from %d, type = %d, proc "
"= %d (not %d) (2) ignored\n", SELF_E, m.m_source,
m.m_type, proc_e, m.REP_ENDPT);
r = EIO;
}
}
/* Task has completed. See if call completed. */
if (m.REP_STATUS == SUSPEND) {
panic("MFS block_dev_io: driver returned SUSPEND");
}
if(buffer != buf_used && r == OK) {
memcpy(buffer, buf_used, bytes * sizeof(iovec_t));
}
return(m.REP_STATUS);
}
/*===========================================================================*
* dev_open *
*===========================================================================*/
PUBLIC int dev_open(
endpoint_t driver_e,
dev_t dev, /* device to open */
endpoint_t proc_e, /* process to open for */
int flags /* mode bits and flags */
)
{
int major, r;
/* Determine the major device number call the device class specific
* open/close routine. (This is the only routine that must check the
* device number for being in range. All others can trust this check.)
*/
major = major(dev);
if (major >= NR_DEVICES) {
printf("Major device number %d not in range\n", major(dev));
return(EIO);
}
r = gen_opcl(driver_e, DEV_OPEN, dev, proc_e, flags);
if (r == SUSPEND) panic("suspend on open from");
return(r);
}
/*===========================================================================*
* dev_close *
*===========================================================================*/
PUBLIC void dev_close(
endpoint_t driver_e,
dev_t dev /* device to close */
)
{
(void) gen_opcl(driver_e, DEV_CLOSE, dev, 0, 0);
}
/*===========================================================================*
* gen_opcl *
*===========================================================================*/
PRIVATE int gen_opcl(
endpoint_t driver_e,
int op, /* operation, DEV_OPEN or DEV_CLOSE */
dev_t dev, /* device to open or close */
endpoint_t proc_e, /* process to open/close for */
int flags /* mode bits and flags */
)
{
/* Called from the dmap struct in table.c on opens & closes of special files.*/
message dev_mess;
dev_mess.m_type = op;
dev_mess.DEVICE = minor(dev);
dev_mess.USER_ENDPT = proc_e;
dev_mess.COUNT = flags;
/* Call the task. */
(void) gen_io(driver_e, &dev_mess);
return(dev_mess.REP_STATUS);
}
/*===========================================================================*
* gen_io *
*===========================================================================*/
PRIVATE int gen_io(
endpoint_t task_nr, /* which task to call */
message *mess_ptr /* pointer to message for task */
)
{
/* All file system I/O ultimately comes down to I/O on major/minor device
* pairs. These lead to calls on the following routines via the dmap table.
*/
int r, proc_e;
proc_e = mess_ptr->USER_ENDPT;
r = sendrec(task_nr, mess_ptr);
if(r == OK && mess_ptr->REP_STATUS == ERESTART)
r = EDEADEPT;
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("fs: dead driver %d\n", task_nr);
panic("should handle crashed drivers");
return(r);
}
if (r == ELOCKED) {
printf("fs: ELOCKED talking to %d\n", task_nr);
return(r);
}
panic("call_task: can't send/receive: %d", r);
}
/* Did the process we did the sendrec() for get a result? */
if (mess_ptr->REP_ENDPT != proc_e) {
printf("fs: strange device reply from %d, type = %d, proc = %d (not "
"%d) (2) ignored\n", mess_ptr->m_source, mess_ptr->m_type,
proc_e,
mess_ptr->REP_ENDPT);
return(EIO);
}
return(OK);
}

View file

@ -1,11 +0,0 @@
#ifndef __MFS_DRIVERS_H__
#define __MFS_DRIVERS_H__
/* Driver endpoints for major devices. Only the block devices
* are mapped here, it's a subset of the mapping in the VFS */
EXTERN struct driver_endpoints {
endpoint_t driver_e;
} driver_endpoints[NR_DEVICES];
#endif

View file

@ -9,7 +9,6 @@
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "drivers.h"
/* Declare some local functions. */ /* Declare some local functions. */
@ -118,10 +117,6 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
init_inode_cache(); init_inode_cache();
/* Init driver mapping */
for (i = 0; i < NR_DEVICES; ++i)
driver_endpoints[i].driver_e = NONE;
SELF_E = getprocnr(); SELF_E = getprocnr();
buf_pool(DEFAULT_NR_BUFS); buf_pool(DEFAULT_NR_BUFS);
fs_block_size = _MIN_BLOCK_SIZE; fs_block_size = _MIN_BLOCK_SIZE;

View file

@ -1,6 +1,7 @@
#include "fs.h" #include "fs.h"
#include <assert.h> #include <assert.h>
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/bdev.h>
#include "inode.h" #include "inode.h"
@ -50,3 +51,20 @@ PUBLIC int fs_flush()
return(OK); return(OK);
} }
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
PUBLIC int fs_new_driver(void)
{
/* Set a new driver endpoint for this device. */
dev_t dev;
endpoint_t endpt;
dev = (dev_t) fs_m_in.REQ_DEV;
endpt = (endpoint_t) fs_m_in.REQ_DRIVER_E;
bdev_driver(dev, endpt);
return(OK);
}

View file

@ -1,9 +1,9 @@
#include "fs.h" #include "fs.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include "drivers.h"
#include <minix/ds.h> #include <minix/ds.h>
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/bdev.h>
/*===========================================================================* /*===========================================================================*
@ -49,11 +49,10 @@ PUBLIC int fs_readsuper()
} }
/* Map the driver endpoint for this major */ /* Map the driver endpoint for this major */
driver_endpoints[major(fs_dev)].driver_e = driver_e; bdev_driver(fs_dev, driver_e);
/* Open the device the file system lives on. */ /* Open the device the file system lives on. */
if (dev_open(driver_e, fs_dev, driver_e, if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) {
readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) {
return(EINVAL); return(EINVAL);
} }
@ -64,7 +63,7 @@ PUBLIC int fs_readsuper()
/* Is it recognized as a Minix filesystem? */ /* Is it recognized as a Minix filesystem? */
if (r != OK) { if (r != OK) {
superblock.s_dev = NO_DEV; superblock.s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(r); return(r);
} }
@ -74,7 +73,7 @@ PUBLIC int fs_readsuper()
if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) {
printf("MFS: couldn't get root inode\n"); printf("MFS: couldn't get root inode\n");
superblock.s_dev = NO_DEV; superblock.s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(EINVAL); return(EINVAL);
} }
@ -82,7 +81,7 @@ PUBLIC int fs_readsuper()
printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__);
put_inode(root_ip); put_inode(root_ip);
superblock.s_dev = NO_DEV; superblock.s_dev = NO_DEV;
dev_close(driver_e, fs_dev); bdev_close(fs_dev);
return(EINVAL); return(EINVAL);
} }
@ -162,7 +161,7 @@ PUBLIC int fs_unmount()
(void) fs_sync(); (void) fs_sync();
/* Close the device the file system lives on. */ /* Close the device the file system lives on. */
dev_close(driver_endpoints[major(fs_dev)].driver_e, fs_dev); bdev_close(fs_dev);
/* Finish off the unmount. */ /* Finish off the unmount. */
superblock.s_dev = NO_DEV; superblock.s_dev = NO_DEV;

View file

@ -19,6 +19,7 @@
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/libminixfs.h>
PUBLIC char dot1[2] = "."; /* used for search_dir to bypass the access */ PUBLIC char dot1[2] = "."; /* used for search_dir to bypass the access */

View file

@ -22,14 +22,6 @@ _PROTOTYPE( void set_blocksize, (struct super_block *) );
_PROTOTYPE( void rw_scattered, (dev_t dev, _PROTOTYPE( void rw_scattered, (dev_t dev,
struct buf **bufq, int bufqsize, int rw_flag) ); struct buf **bufq, int bufqsize, int rw_flag) );
/* device.c */
_PROTOTYPE( int block_dev_io, (int op, dev_t dev, endpoint_t proc_e,
void *buf, u64_t pos, size_t bytes) );
_PROTOTYPE( int dev_open, (endpoint_t driver_e, dev_t dev, endpoint_t proc_e,
int flags) );
_PROTOTYPE( void dev_close, (endpoint_t driver_e, dev_t dev) );
_PROTOTYPE( int fs_new_driver, (void) );
/* inode.c */ /* inode.c */
_PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t bits) ); _PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t bits) );
_PROTOTYPE( void dup_inode, (struct inode *ip) ); _PROTOTYPE( void dup_inode, (struct inode *ip) );
@ -52,6 +44,7 @@ _PROTOTYPE( int truncate_inode, (struct inode *rip, off_t len) );
/* misc.c */ /* misc.c */
_PROTOTYPE( int fs_flush, (void) ); _PROTOTYPE( int fs_flush, (void) );
_PROTOTYPE( int fs_sync, (void) ); _PROTOTYPE( int fs_sync, (void) );
_PROTOTYPE( int fs_new_driver, (void) );
/* mount.c */ /* mount.c */
_PROTOTYPE( int fs_mountpoint, (void) ); _PROTOTYPE( int fs_mountpoint, (void) );

View file

@ -15,6 +15,7 @@
#include <string.h> #include <string.h>
#include <minix/com.h> #include <minix/com.h>
#include <minix/u64.h> #include <minix/u64.h>
#include <minix/bdev.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
@ -194,8 +195,8 @@ register struct super_block *sp; /* pointer to a superblock */
if (dev == NO_DEV) if (dev == NO_DEV)
panic("request for super_block of NO_DEV"); panic("request for super_block of NO_DEV");
r = block_dev_io(MFS_DEV_READ, dev, SELF_E, sbbuf, cvu64(SUPER_BLOCK_BYTES), r = bdev_read(dev, cvu64(SUPER_BLOCK_BYTES), sbbuf, _MIN_BLOCK_SIZE,
_MIN_BLOCK_SIZE); BDEV_NOFLAGS);
if (r != _MIN_BLOCK_SIZE) if (r != _MIN_BLOCK_SIZE)
return(EINVAL); return(EINVAL);

View file

@ -9,7 +9,6 @@
#include "inode.h" #include "inode.h"
#include "buf.h" #include "buf.h"
#include "super.h" #include "super.h"
#include "drivers.h"
PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
no_sys, /* 0 not used */ no_sys, /* 0 not used */