From 21bf6f025d94c2987dfe30a0b327b6dfab7a8bff Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 4 Jun 2010 16:51:24 +0200 Subject: support block devices in the DDE library. --- libmachdev/block.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 libmachdev/block.c (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c new file mode 100644 index 00000000..54048fde --- /dev/null +++ b/libmachdev/block.c @@ -0,0 +1,250 @@ +/* + * Linux block driver support. + * + * Copyright (C) 1996 The University of Utah and the Computer Systems + * Laboratory at the University of Utah (CSL) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Shantanu Goel, University of Utah CSL + */ + +#include +#include +#include + +#include "mach_U.h" + +#include +#include + +#define MACH_INCLUDE + +#include + +#include "vm_param.h" +#include "device_reply_U.h" +#include "dev_hdr.h" +#include "util.h" +#include "mach_glue.h" + +/* One of these is associated with each open instance of a device. */ +struct block_data +{ + struct port_info port; /* device port */ + struct emul_device device; /* generic device structure */ + dev_mode_t mode; + struct block_device *dev; +}; + +/* Return a send right associated with network device ND. */ +static mach_port_t +dev_to_port (void *nd) +{ + return (nd + ? ports_get_send_right (nd) + : MACH_PORT_NULL); +} + +extern struct device_emulation_ops linux_block_emulation_ops; + +#define DISK_NAME_LEN 32 + +/* Parse the device NAME. + Set *SLICE to be the DOS partition and + *PART the BSD/Mach partition, if any. */ +static char * +translate_name (char *name, int *slice, int *part) +{ + char *p, *q, *end; + char *ret; + int disk_num; + + /* Parse name into name, unit, DOS partition (slice) and partition. */ + for (*slice = 0, *part = -1, p = name; isalpha (*p); p++) + ; + if (p == name || ! isdigit (*p)) + return NULL; + end = p; + disk_num = strtol (p, &p, 0); + if (disk_num < 0 || disk_num > 26) + return NULL; +// do +// p++; +// while (isdigit (*p)); + if (*p) + { + q = p; + if (*q == 's' && isdigit (*(q + 1))) + { + q++; + do + *slice = *slice * 10 + *q++ - '0'; + while (isdigit (*q)); + if (! *q) + goto find_major; + } + if (! isalpha (*q) || *(q + 1)) + return NULL; + *part = *q - 'a'; + } + +find_major: + ret = malloc (DISK_NAME_LEN); + sprintf (ret, "hd%c", 'a' + disk_num); + return ret; +} + +static io_return_t +device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + dev_mode_t mode, char *name, device_t *devp) +{ + io_return_t err = D_SUCCESS; + struct block_data *bd = NULL; + int slice, part; + char *dev_name = NULL; + + dev_name = translate_name (name, &slice, &part); + + // TODO when the port isn't used by clients, it should be destroyed. + err = create_device_port (sizeof (*bd), &bd); + if (err) + { + ddekit_printf ("after create_device_port: cannot create a port\n"); + goto out; + } + bd->dev = open_block_dev (dev_name, slice, mode); + if (bd->dev < 0) + { + ddekit_printf ("open_block_dev fails with %d\n", bd->dev); + err = linux_to_mach_error (err); + goto out; + } + bd->device.emul_data = bd; + bd->device.emul_ops = &linux_block_emulation_ops; + bd->mode = mode; + +out: + free (dev_name); + if (err) + { + if (bd) + { + ports_destroy_right (bd); + bd = NULL; + } + } + else + *devp = ports_get_right (bd); + return err; +} + +static io_return_t +device_write (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, io_buf_ptr_t data, unsigned int count, + int *bytes_written) +{ + struct block_data *bd = d; + /* the number of pages that contain DATA. */ + int npages = (((int) data + count) - ((int) data & ~PAGE_MASK) + + PAGE_MASK) / PAGE_SIZE; + io_return_t err = D_SUCCESS; + int i; + int writes = 0; + + void write_done (int err) + { + int len = err ? 0 : count; + writes--; + if (writes == 0) + { + err = linux_to_mach_error (err); + ds_device_write_reply (reply_port, reply_port_type, err, len); + } + } + + /* the data is at the beginning of a page. */ + if ((int) data & ~PAGE_MASK) + return D_INVALID_OPERATION; + + if ((bd->mode & D_WRITE) == 0) + return D_INVALID_OPERATION; + + for (i = 0; i < npages; i++) + { + int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? + PAGE_SIZE - ((int) data &~PAGE_MASK) : count; + + err = block_dev_write (bd->dev, bn, data, count, write_done); + if (err) + break; + bn += count >> 9; + data += size; + count -= size; + writes++; + } + if (writes) + return MIG_NO_REPLY; + return linux_to_mach_error (err); +} + +static io_return_t +device_read (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, int count, io_buf_ptr_t *data, + unsigned *bytes_read) +{ + struct block_data *bd = d; + + if ((bd->mode & D_READ) == 0) + return D_INVALID_OPERATION; + *bytes_read = 0; + return D_SUCCESS; +} + +static io_return_t +device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t *count) +{ + struct block_data *bd = (struct block_data *) d; + return D_SUCCESS; +} + +struct device_emulation_ops linux_block_emulation_ops = +{ + NULL, + NULL, + dev_to_port, + device_open, + NULL, + device_write, + NULL, + device_read, + NULL, + NULL, + device_get_status, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +void register_block() +{ + extern void reg_dev_emul (struct device_emulation_ops *ops); + reg_dev_emul (&linux_block_emulation_ops); +} -- cgit v1.2.3 From 70d6d54fe949a7743bd5091e74aab2477336b5d3 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 17 Jun 2010 07:45:06 +0200 Subject: fix a bug in linux_block_emulation_ops --- libmachdev/block.c | 1 + 1 file changed, 1 insertion(+) (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c index 54048fde..080338d8 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -225,6 +225,7 @@ device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, struct device_emulation_ops linux_block_emulation_ops = { + NULL, NULL, NULL, dev_to_port, -- cgit v1.2.3 From e9762c27cfc0b614ca09b4812351c83167501447 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 17 Jun 2010 11:12:47 +0200 Subject: fix a bug in device_open in libmachdev. check the negative error value. --- libmachdev/block.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c index 080338d8..3dddd74a 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -115,6 +115,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, struct block_data *bd = NULL; int slice, part; char *dev_name = NULL; + int dev_err; dev_name = translate_name (name, &slice, &part); @@ -126,10 +127,11 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, goto out; } bd->dev = open_block_dev (dev_name, slice, mode); - if (bd->dev < 0) + dev_err = (int) bd->dev; + if (dev_err < 0) { - ddekit_printf ("open_block_dev fails with %d\n", bd->dev); - err = linux_to_mach_error (err); + ddekit_printf ("open_block_dev %s fails with %d\n", dev_name, bd->dev); + err = linux_to_mach_error (dev_err); goto out; } bd->device.emul_data = bd; -- cgit v1.2.3 From f80f44bbb8bc4707c19f017775e2f806cf40e81f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 21 Jun 2010 08:09:12 +0200 Subject: create send right when block device is opened. --- libmachdev/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c index 3dddd74a..5400f60b 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -149,7 +149,7 @@ out: } } else - *devp = ports_get_right (bd); + *devp = ports_get_send_right (bd); return err; } -- cgit v1.2.3 From 823e9dd9c55a1f34259c5398497439f5663ff2a4 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 21 Jun 2010 09:59:01 +0200 Subject: fix port leak in block glue code of libmachdev. --- libmachdev/Makefile | 5 ++++- libmachdev/block.c | 9 +++++++-- libmachdev/device_emul.h | 3 ++- libmachdev/ds_routines.c | 4 ++-- libmachdev/net.c | 4 +++- 5 files changed, 18 insertions(+), 7 deletions(-) (limited to 'libmachdev/block.c') diff --git a/libmachdev/Makefile b/libmachdev/Makefile index e65a453a..22909949 100644 --- a/libmachdev/Makefile +++ b/libmachdev/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libmachdev SRCS = deviceUser.c machUser.c net.c ds_routines.c queue.c trivfs_server.c \ - device_replyUser.c deviceServer.c notifyServer.c misc.c block.c + device_replyUser.c ourdeviceServer.c notifyServer.c misc.c block.c LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \ util.h queue.h io_req.h if_ether.h machdev.h linux-errno.h \ errno-base.h @@ -31,3 +31,6 @@ OBJS = $(SRCS:.c=.o) $(MIGSTUBS) include ../Makeconf CFLAGS += -I$(top_srcdir)/libddekit/include + +ourdevice.defs: device.defs + $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out[ ]*device[ ]*:[ ]*device_t/s/device_t/mach_port_send_t/' > $@ diff --git a/libmachdev/block.c b/libmachdev/block.c index 5400f60b..4aa07672 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -109,7 +109,8 @@ find_major: static io_return_t device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, - dev_mode_t mode, char *name, device_t *devp) + dev_mode_t mode, char *name, device_t *devp, + mach_msg_type_name_t *devicePoly) { io_return_t err = D_SUCCESS; struct block_data *bd = NULL; @@ -149,7 +150,11 @@ out: } } else - *devp = ports_get_send_right (bd); + { + *devp = ports_get_send_right (bd); + ports_port_deref (bd); + *devicePoly = MACH_MSG_TYPE_MOVE_SEND; + } return err; } diff --git a/libmachdev/device_emul.h b/libmachdev/device_emul.h index a5bc4f77..e27799cb 100644 --- a/libmachdev/device_emul.h +++ b/libmachdev/device_emul.h @@ -36,7 +36,8 @@ struct device_emulation_ops void (*dealloc) (void *); mach_port_t (*dev_to_port) (void *); io_return_t (*open) (mach_port_t, mach_msg_type_name_t, - dev_mode_t, char *, device_t *); + dev_mode_t, char *, device_t *, + mach_msg_type_name_t *type); io_return_t (*close) (void *); io_return_t (*write) (void *, mach_port_t, mach_msg_type_name_t, dev_mode_t, recnum_t, io_buf_ptr_t, unsigned, int *); diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c index df9146a0..71457e03 100644 --- a/libmachdev/ds_routines.c +++ b/libmachdev/ds_routines.c @@ -161,7 +161,7 @@ ds_device_irq_enable (mach_port_t master_port, io_return_t ds_device_open (mach_port_t open_port, mach_port_t reply_port, mach_msg_type_name_t reply_port_type, dev_mode_t mode, - char *name, device_t *devp) + char *name, device_t *devp, mach_msg_type_name_t *devicePoly) { int i; io_return_t err; @@ -181,7 +181,7 @@ ds_device_open (mach_port_t open_port, mach_port_t reply_port, for (i = 0; i < NUM_EMULATION; i++) { err = (*emulation_list[i]->open) (reply_port, reply_port_type, - mode, name, devp); + mode, name, devp, devicePoly); if (err != D_NO_SUCH_DEVICE) break; } diff --git a/libmachdev/net.c b/libmachdev/net.c index 8c435b4b..b9d76731 100644 --- a/libmachdev/net.c +++ b/libmachdev/net.c @@ -273,7 +273,8 @@ void if_init_queues(ifp) static io_return_t device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, - dev_mode_t mode, char *name, device_t *devp) + dev_mode_t mode, char *name, device_t *devp, + mach_msg_type_name_t *devicePoly) { io_return_t err = D_SUCCESS; struct net_device *dev; @@ -357,6 +358,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, } *devp = ports_get_right (nd); + *devicePoly = MACH_MSG_TYPE_COPY_SEND; return D_SUCCESS; } -- cgit v1.2.3 From 3de13f2a911c402fc1275582d30b2f934cf433e5 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 8 Aug 2010 08:05:16 +0200 Subject: check if the device exists. --- libmachdev/block.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c index 4aa07672..b239ecff 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -118,9 +118,14 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, char *dev_name = NULL; int dev_err; + // TODO I need to check whether the device has been opened before. + // if it has been opened with the same `flag', return the same port, + // otherwise, return a different port. + // I need to have a reference to count the number of open. dev_name = translate_name (name, &slice, &part); + if (dev_name == NULL) + return D_NO_SUCH_DEVICE; - // TODO when the port isn't used by clients, it should be destroyed. err = create_device_port (sizeof (*bd), &bd); if (err) { -- cgit v1.2.3 From e30a817d6d2a1d71223caa238781a76104a54840 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 8 Aug 2010 08:08:36 +0200 Subject: fix a bug in device_write for the block device. --- libmachdev/block.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c index b239ecff..48fe6cd6 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -198,12 +198,12 @@ device_write (void *d, mach_port_t reply_port, for (i = 0; i < npages; i++) { int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? - PAGE_SIZE - ((int) data &~PAGE_MASK) : count; + count : PAGE_SIZE - ((int) data &~PAGE_MASK); - err = block_dev_write (bd->dev, bn, data, count, write_done); + err = block_dev_write (bd->dev, bn, data, size, write_done); if (err) break; - bn += count >> 9; + bn += size >> 9; data += size; count -= size; writes++; -- cgit v1.2.3 From 793af51f505adfa1ea138dc76be731faab58b1a6 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 8 Aug 2010 08:10:25 +0200 Subject: implement device_read for block devices. --- libdde_linux26/lib/src/mach_glue/block.c | 6 ++-- libmachdev/block.c | 55 ++++++++++++++++++++++++++++++-- libmachdev/mach_glue.h | 4 +-- 3 files changed, 57 insertions(+), 8 deletions(-) (limited to 'libmachdev/block.c') diff --git a/libdde_linux26/lib/src/mach_glue/block.c b/libdde_linux26/lib/src/mach_glue/block.c index a856cc9b..ea44d87f 100644 --- a/libdde_linux26/lib/src/mach_glue/block.c +++ b/libdde_linux26/lib/src/mach_glue/block.c @@ -20,8 +20,8 @@ struct block_device *open_block_dev (char *name, int part, fmode_t mode) /* write a piece of data to a block device. * DATA must be in one page. * SECTORNR: the writing location in sectors. */ -int block_dev_write (struct block_device *dev, int sectornr, - char *data, int count, void (*write_done (int err))) +int block_dev_rw (struct block_device *dev, int sectornr, + char *data, int count, int rw, void (*write_done (int err))) { int err = 0; struct bio *bio; @@ -63,7 +63,7 @@ int block_dev_write (struct block_device *dev, int sectornr, bio->bi_end_io = end_bio; bio->bi_private = NULL; bio_get (bio); - submit_bio (WRITE, bio); + submit_bio (rw, bio); if (bio_flagged (bio, BIO_EOPNOTSUPP)) { err = -EOPNOTSUPP; diff --git a/libmachdev/block.c b/libmachdev/block.c index 48fe6cd6..2a4b9ae2 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "mach_U.h" @@ -40,6 +41,11 @@ #include "util.h" #include "mach_glue.h" +/* for submit_bio(). But it might not be very proper to keep + * my own definitions of these macros. */ +#define READ 0 +#define WRITE 1 + /* One of these is associated with each open instance of a device. */ struct block_data { @@ -180,6 +186,7 @@ device_write (void *d, mach_port_t reply_port, void write_done (int err) { int len = err ? 0 : count; + // TODO maybe I should send the reply as long as there is an error. writes--; if (writes == 0) { @@ -200,7 +207,7 @@ device_write (void *d, mach_port_t reply_port, int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? count : PAGE_SIZE - ((int) data &~PAGE_MASK); - err = block_dev_write (bd->dev, bn, data, size, write_done); + err = block_dev_rw (bd->dev, bn, data, size, WRITE, write_done); if (err) break; bn += size >> 9; @@ -220,11 +227,53 @@ device_read (void *d, mach_port_t reply_port, unsigned *bytes_read) { struct block_data *bd = d; + io_return_t err = D_SUCCESS; + int i; + int reads = 0; + char *buf; + int npages = (count + PAGE_SIZE - 1) / PAGE_SIZE; + + void read_done (int err) + { + int len = err ? 0 : count; + reads--; + if (reads == 0) + { + err = linux_to_mach_error (err); + ds_device_read_reply (reply_port, reply_port_type, err, buf, len); + } + } if ((bd->mode & D_READ) == 0) return D_INVALID_OPERATION; - *bytes_read = 0; - return D_SUCCESS; + + if (count == 0) + return 0; + + *data = 0; + buf = mmap (NULL, npages * PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (buf == MAP_FAILED) + return errno; + + ddekit_printf ("read %d pages.\n", npages); + for (i = 0; i < npages; i++) + { + int size = count > PAGE_SIZE ? PAGE_SIZE : count; + ddekit_printf ("read %d bytes starting from %d\n", size, bn); + + err = block_dev_rw (bd->dev, bn, buf + i * PAGE_SIZE, + size, READ, read_done); + if (err) + break; + bn += size >> 9; + count -= size; + reads++; + } + // TODO when should I deallocate the buffer? + if (reads) + return MIG_NO_REPLY; + return linux_to_mach_error (err); } static io_return_t diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h index 770ea51b..7b122583 100644 --- a/libmachdev/mach_glue.h +++ b/libmachdev/mach_glue.h @@ -33,8 +33,8 @@ void skb_done_head_init(); /* block device */ struct block_device; struct block_device *open_block_dev (char *name, int part, dev_mode_t mode); -int block_dev_write (struct block_device *dev, int sectornr, - char *data, int count, void (*write_done) (int err)); +int block_dev_rw (struct block_device *dev, int sectornr, + char *data, int count, int rw, void (*write_done) (int err)); int l4dde26_process_from_ddekit(ddekit_thread_t *t); -- cgit v1.2.3 From bbc9b208562c0497b0034e77369a07e2985ae763 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Aug 2010 14:27:15 +0200 Subject: fix a bug in device_read for block devices. --- libmachdev/block.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'libmachdev/block.c') diff --git a/libmachdev/block.c b/libmachdev/block.c index 2a4b9ae2..756a07bf 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -232,6 +232,7 @@ device_read (void *d, mach_port_t reply_port, int reads = 0; char *buf; int npages = (count + PAGE_SIZE - 1) / PAGE_SIZE; + int rest = count; void read_done (int err) { @@ -259,7 +260,7 @@ device_read (void *d, mach_port_t reply_port, ddekit_printf ("read %d pages.\n", npages); for (i = 0; i < npages; i++) { - int size = count > PAGE_SIZE ? PAGE_SIZE : count; + int size = rest > PAGE_SIZE ? PAGE_SIZE : rest; ddekit_printf ("read %d bytes starting from %d\n", size, bn); err = block_dev_rw (bd->dev, bn, buf + i * PAGE_SIZE, @@ -267,7 +268,7 @@ device_read (void *d, mach_port_t reply_port, if (err) break; bn += size >> 9; - count -= size; + rest -= size; reads++; } // TODO when should I deallocate the buffer? -- cgit v1.2.3