summaryrefslogtreecommitdiff
path: root/rumpdisk/block-rump.c
diff options
context:
space:
mode:
Diffstat (limited to 'rumpdisk/block-rump.c')
-rw-r--r--rumpdisk/block-rump.c65
1 files changed, 51 insertions, 14 deletions
diff --git a/rumpdisk/block-rump.c b/rumpdisk/block-rump.c
index f7444260..9727328f 100644
--- a/rumpdisk/block-rump.c
+++ b/rumpdisk/block-rump.c
@@ -53,7 +53,7 @@ struct block_data
char name[DISK_NAME_LEN]; /* eg /dev/wd0 */
off_t media_size; /* total block device size */
uint32_t block_size; /* size in bytes of 1 sector */
- bool taken; /* simple refcount */
+ bool opening; /* simple lock */
struct block_data *next;
};
@@ -75,18 +75,31 @@ search_bd (char *name)
while (bd)
{
if (!strcmp (bd->name, name))
- return bd;
+ return bd;
bd = bd->next;
}
return NULL;
}
/* BSD name of whole disk device is /dev/wdXd
- * but we will receive /dev/wdX as the name */
+ * but we will receive /dev/wdX as the name
+ * or @/dev/master:/dev/wdX */
static void
translate_name (char *output, int len, char *name)
{
- snprintf (output, len - 1, "%sd", name);
+ char *pos;
+ char *rest;
+
+ /* Parse @master:/dev/hello */
+ if ( (name[0] == '@') && (pos = strchr (name, ':')) )
+ {
+ rest = pos+1;
+ snprintf (output, len - 1, "%sd", rest);
+ }
+ else
+ {
+ snprintf (output, len - 1, "%sd", name);
+ }
}
static boolean_t
@@ -105,7 +118,7 @@ is_disk_device (char *name, int len)
for (i = 0; i < MAX_DISK_DEV; i++)
{
dev = (char *)allowed_devs[i];
- /* /dev/XXN but we only care about /dev/XX prefix */
+ /* /dev/XXNd but we only care about /dev/XX prefix */
if (! strncmp (dev, name, 7))
return TRUE;
}
@@ -142,6 +155,8 @@ device_close (void *d)
{
struct block_data *bd = d;
+ ports_port_deref (bd);
+ ports_destroy_right (bd);
return rump_errno2host (rump_sys_close (bd->rump_fd));
}
@@ -175,18 +190,19 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
off_t media_size;
uint32_t block_size;
- if (! is_disk_device (name, 8))
- return D_NO_SUCH_DEVICE;
-
translate_name (dev_name, DISK_NAME_LEN, name);
+ if (! is_disk_device (dev_name, 8))
+ return D_NO_SUCH_DEVICE;
+
/* Find previous device or open if new */
- bd = search_bd (name);
+ bd = search_bd (dev_name);
if (!bd)
{
err = machdev_create_device_port (sizeof (*bd), &bd);
- snprintf (bd->name, DISK_NAME_LEN, "%s", name);
+ snprintf (bd->name, DISK_NAME_LEN, "%s", dev_name);
+ bd->opening = true;
bd->mode = mode;
bd->device.emul_data = bd;
bd->device.emul_ops = &rump_block_emulation_ops;
@@ -194,8 +210,8 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
err = rump_sys_open (dev_name, dev_mode_to_rump_mode (bd->mode));
if (err < 0)
{
- err = rump_errno2host (errno);
- goto out;
+ err = rump_errno2host (errno);
+ goto out;
}
bd->rump_fd = err;
@@ -221,6 +237,20 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
}
out:
+ if (err == D_ALREADY_OPEN)
+ {
+ if (bd)
+ {
+ *devp = ports_get_right (bd);
+ *devicePoly = MACH_MSG_TYPE_MAKE_SEND;
+ return D_SUCCESS;
+ }
+ else
+ {
+ return D_ALREADY_OPEN;
+ }
+ }
+
if (err)
{
if (bd)
@@ -233,10 +263,11 @@ out:
if (bd)
{
- bd->next = block_head;
- block_head = bd;
*devp = ports_get_right (bd);
*devicePoly = MACH_MSG_TYPE_MAKE_SEND;
+ bd->next = block_head;
+ bd->opening = false;
+ block_head = bd;
}
return err;
}
@@ -253,6 +284,9 @@ device_write (void *d, mach_port_t reply_port,
if ((bd->mode & D_WRITE) == 0)
return D_INVALID_OPERATION;
+ if (bd->opening)
+ return D_WOULD_BLOCK;
+
written = rump_sys_pwrite (bd->rump_fd, (const void *)data, (size_t)count, (off_t)bn * bd->block_size);
if (written < 0)
{
@@ -281,6 +315,9 @@ device_read (void *d, mach_port_t reply_port,
if ((bd->mode & D_READ) == 0)
return D_INVALID_OPERATION;
+ if (bd->opening)
+ return D_WOULD_BLOCK;
+
if (count == 0)
return D_SUCCESS;