From 87b1ef74999311cdb3d0a1379bc1d3d0bc957708 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Sat, 1 Aug 2020 14:40:02 +1000 Subject: libmachdev: Install as translator when bootstrapping && fix rumpdisk injection --- libmachdev/trivfs_server.c | 85 +++++++++++++++++++++++++++++++++------------- rumpdisk/block-rump.c | 65 +++++++++++++++++++++++++++-------- rumpdisk/main.c | 2 +- 3 files changed, 114 insertions(+), 38 deletions(-) diff --git a/libmachdev/trivfs_server.c b/libmachdev/trivfs_server.c index c5407145..5d01e61d 100644 --- a/libmachdev/trivfs_server.c +++ b/libmachdev/trivfs_server.c @@ -54,18 +54,47 @@ int trivfs_support_write = 0; int trivfs_support_exec = 0; int trivfs_allow_open = O_READ | O_WRITE; -/* Our port classes. */ -struct port_class *trivfs_protid_class; +/* Our port classes */ struct port_class *trivfs_cntl_class; +struct port_class *trivfs_protid_class; + +/* Our control struct */ +struct trivfs_control *control; + +/* Are we providing bootstrap translator? */ +static boolean_t bootstrapped; + +/* Our underlying node for bootstrap */ +static mach_port_t underlying; /* Our control port */ -static mach_port_t machdev_ctl; +static mach_port_t control_port; + +/* Our device path for injecting bootstrapped translator onto */ +static char *devnode; /* Startup and shutdown notifications management */ struct port_class *machdev_shutdown_notify_class; static void arrange_shutdown_notification (void); +static void +install_as_translator (mach_port_t bootport) +{ + error_t err; + + underlying = file_name_lookup (devnode, O_NOTRANS, 0); + if (! MACH_PORT_VALID (underlying)) + return; + + /* Install translator */ + err = file_set_translator (underlying, + 0, FS_TRANS_SET, 0, + NULL, 0, + bootport, MACH_MSG_TYPE_COPY_SEND); + assert_perror_backtrace (err); +} + /* Implementation of notify interface */ kern_return_t do_mach_notify_port_deleted (struct port_info *pi, @@ -209,15 +238,14 @@ trivfs_S_fsys_startup (mach_port_t bootport, mach_port_t *realnode, mach_msg_type_name_t *realnodetype) { - machdev_ctl = cntl; - + control_port = cntl; *realnode = MACH_PORT_NULL; *realnodetype = MACH_MSG_TYPE_MOVE_SEND; return 0; } kern_return_t -trivfs_S_fsys_init (struct trivfs_control *tc, +trivfs_S_fsys_init (struct trivfs_control *fsys, mach_port_t reply, mach_msg_type_name_t replytype, mach_port_t procserver, mach_port_t authhandle) @@ -229,10 +257,11 @@ trivfs_S_fsys_init (struct trivfs_control *tc, mach_port_t root; retry_type retry; string_t retry_name; + mach_port_t right = MACH_PORT_NULL; - err = fsys_getroot (machdev_ctl, MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND, - idlist, 3, idlist, 3, 0, - &retry, retry_name, &root); + err = fsys_getroot (control_port, MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND, + idlist, 3, idlist, 3, 0, + &retry, retry_name, &root); assert_perror_backtrace (err); assert_backtrace (retry == FS_RETRY_NORMAL); assert_backtrace (retry_name[0] == '\0'); @@ -249,6 +278,15 @@ trivfs_S_fsys_init (struct trivfs_control *tc, _hurd_init (0, NULL, portarray, INIT_PORT_MAX, NULL, 0); arrange_shutdown_notification (); + + /* Install the bootstrap port on /dev/something so users + * can still access the bootstrapped device */ + if (bootstrapped) + { + right = ports_get_send_right (&control->pi); + install_as_translator (right); + control->underlying = underlying; + } return 0; } @@ -301,14 +339,8 @@ trivfs_S_fsys_getpriv (struct diskfs_control *init_bootstrap_port, { error_t err; mach_port_t right; - struct port_info *server_info; - - err = ports_create_port (trivfs_protid_class, port_bucket, - sizeof (struct port_info), &server_info); - assert_perror_backtrace (err); - right = ports_get_send_right (server_info); - ports_port_deref (server_info); + right = ports_get_send_right (&control->pi); err = get_privileged_ports (host_priv, NULL); if (!err) { @@ -326,20 +358,14 @@ resume_bootstrap_server(mach_port_t server_task, const char *server_name) error_t err; mach_port_t right; mach_port_t dev, cons; - struct port_info *server_info; assert_backtrace (server_task != MACH_PORT_NULL); - err = ports_create_port (trivfs_cntl_class, port_bucket, - sizeof (struct port_info), &server_info); - assert_perror_backtrace (err); - right = ports_get_send_right (server_info); - ports_port_deref (server_info); + right = ports_get_send_right (&control->pi); err = task_set_special_port (server_task, TASK_BOOTSTRAP_PORT, right); assert_perror_backtrace (err); err = mach_port_deallocate (mach_task_self (), right); assert_perror_backtrace (err); - err = task_resume (server_task); assert_perror_backtrace (err); @@ -363,17 +389,25 @@ machdev_trivfs_init(mach_port_t bootstrap_resume_task, const char *name, mach_po port_bucket = ports_create_bucket (); trivfs_cntl_class = ports_create_class (trivfs_clean_cntl, 0); trivfs_protid_class = ports_create_class (trivfs_clean_protid, 0); + trivfs_create_control (MACH_PORT_NULL, trivfs_cntl_class, port_bucket, + trivfs_protid_class, 0, &control); if (bootstrap_resume_task != MACH_PORT_NULL) { + devnode = strdup(name); resume_bootstrap_server(bootstrap_resume_task, name); *bootstrap = MACH_PORT_NULL; + /* We need to install as a translator later */ + bootstrapped = TRUE; } else { task_get_bootstrap_port (mach_task_self (), bootstrap); if (*bootstrap == MACH_PORT_NULL) error (1, 0, "must be started as a translator"); + + /* We do not need to install as a translator later */ + bootstrapped = FALSE; } return 0; @@ -451,6 +485,7 @@ machdev_trivfs_server(mach_port_t bootstrap) if (bootstrap != MACH_PORT_NULL) { + /* This path is executed when a parent exists */ err = trivfs_startup (bootstrap, 0, trivfs_cntl_class, port_bucket, trivfs_protid_class, port_bucket, &fsys); @@ -458,6 +493,10 @@ machdev_trivfs_server(mach_port_t bootstrap) if (err) error (1, err, "Contacting parent"); } + else + { + fsys = control; + } /* Launch. */ do 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; diff --git a/rumpdisk/main.c b/rumpdisk/main.c index 27a8ea38..3ee24341 100644 --- a/rumpdisk/main.c +++ b/rumpdisk/main.c @@ -118,7 +118,7 @@ main (int argc, char **argv) rump_register_block (); machdev_device_init (); - machdev_trivfs_init (bootstrap_resume_task, "fs", &bootstrap); + machdev_trivfs_init (bootstrap_resume_task, "/dev/rumpdisk", &bootstrap); err = pthread_create (&t, NULL, machdev_server, NULL); if (err) return err; -- cgit v1.2.3