Hello,

On Tue, 28 Apr 2026 23:01:42 Samuel Thibault wrote:

Well, I managed to stop using libmachdev, but I still couldn't get the store from storeio.

> Opening the store can be done provided that you have the bootstrap
> port.  And you have it from the special port, you can just pick it
> up with task_get_bootstrap_port and use it. You just need to make
> sure that storeio resumes the next task after being ready to serve
> file_get_storage_info.

Passing the storeio_port obtained from task_get_bootstrap_port to store_create
doesn't produce an invalid port error, but it turns out that in this case,
cred = NULL is passed to trivfs_S_file_get_storage_info. I discovered that the
problem was that trivfs_begin_using_protid_payload couldn't find a suitable
class from trivfs_dynamic_protid_port_classes. I'm also confused about where
and with what parameters fsys_getroot should be called. I tried calling it in
storeio_bootstrap_startup after task_resume (next_task) with the
storeio_fsys->underlying parameter (I understand correctly that this is the
storeio process control port, right?), but this doesn't produce any results.

> Not sure what you mean. You don't need to interact with exec etc. before
> interacting with storeio and rumpdisk.

As far as I understand, the mechanism for calling exec from ext2fs is roughly analogous to what storeio requires for ext2fs. However, it expects fsys_startup
to be called from exec, so I don't think it's very applicable...

Thanks,

--
Mikhail Karpov
From a525e64e2d75d38512eae8e442769f437c43ca52 Mon Sep 17 00:00:00 2001
From: Mikhail Karpov <[email protected]>
Date: Wed, 6 May 2026 09:59:34 +0700
Subject: [PATCH] Adding storeio to the bootstrap chain

---
 libdiskfs/init-main.c |  26 ++++-
 storeio/storeio.c     | 265 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 280 insertions(+), 11 deletions(-)

diff --git a/libdiskfs/init-main.c b/libdiskfs/init-main.c
index 69c30fd1..c257c840 100644
--- a/libdiskfs/init-main.c
+++ b/libdiskfs/init-main.c
@@ -31,6 +31,7 @@ diskfs_init_main (struct argp *startup_argp,
 {
   error_t err;
   struct store_argp_params store_params = { 0 };
+  store_params.store_optional = 1;
   struct store *store;
 
   /* We must use ARGP_IN_ORDER for the parsing of --boot-command to work.  */
@@ -40,9 +41,14 @@ diskfs_init_main (struct argp *startup_argp,
   assert_perror_backtrace (err);
   *store_parsed = store_params.result;
 
-  err = store_parsed_name (*store_parsed, &diskfs_disk_name);
-  if (err)
-    error (2, err, "store_parsed_name");
+  //if (diskfs_boot_filesystem ())
+  //  diskfs_disk_name = "storeio";
+  //else
+  //  {
+      err = store_parsed_name (*store_parsed, &diskfs_disk_name);
+      if (err)
+        error (2, err, "store_parsed_name");
+  //  }
 
   /* This must come after the args have been parsed, as this is where the
      host priv ports are set for booting.  */
@@ -63,8 +69,18 @@ diskfs_init_main (struct argp *startup_argp,
   if (err)
     error (4, err, "diskfs_init_diskfs");
 
-  err = store_parsed_open (*store_parsed, diskfs_readonly ? STORE_READONLY : 0,
-			   &store);
+  //if (diskfs_boot_filesystem ())
+  //  {
+  //    mach_port_t storeio_port;
+  //    task_get_bootstrap_port (mach_task_self (), &storeio_port);
+  //    err = store_create (storeio_port, diskfs_readonly ? STORE_READONLY : 0,
+  //                        0, &store);
+  //    mach_port_deallocate (mach_task_self (), storeio_port);
+  //  }
+  //else
+    err = store_parsed_open (*store_parsed,
+                             diskfs_readonly ? STORE_READONLY : 0, &store);
+
   if (err)
     error (3, err, "%s", diskfs_disk_name);
 
diff --git a/storeio/storeio.c b/storeio/storeio.c
index 4e8a9628..2740e073 100644
--- a/storeio/storeio.c
+++ b/storeio/storeio.c
@@ -23,12 +23,16 @@
 #include <fcntl.h>
 #include <argp.h>
 #include <argz.h>
+#include <sys/mman.h>
 #include <sys/sysmacros.h>
 #include <stdbool.h>
 
 #include <hurd.h>
 #include <hurd/ports.h>
 #include <hurd/trivfs.h>
+#include <hurd/fsys.h>
+#include <hurd/startup.h>
+#include <hurd/paths.h>
 #include <version.h>
 
 #include "open.h"
@@ -48,6 +52,11 @@ static struct argp_option options[] =
   {"rdev",     'n', "ID", 0,
    "The stat rdev number for this node; may be either a"
    " single integer, or of the form MAJOR,MINOR"},
+  {0, 0, 0, 0,              "Boot options:"},
+  {"next-task", 'N', "TASK", 0, "Next bootstrap task"},
+  {"host-priv-port", 'H', "PORT", 0, "Port for bootstrapping host"},
+  {"device-master-port", 'P', "PORT", 0, "Port for bootstrapping device"
+   " master"},
   {0}
 };
 static const char doc[] = "Translator for devices and other stores";
@@ -57,6 +66,23 @@ const char *argp_program_version = STANDARD_HURD_VERSION (storeio);
 static bool debug=false;
 static char *debug_fname=NULL;
 
+/* The FS control port */
+static mach_port_t control_port;
+
+/* Startup and shutdown notifications management */
+struct port_class *shutdown_notify_class;
+
+static char **hurd_init_argv;
+
+struct port_bucket *port_bucket;
+
+/* Our parent's task, if applicable */
+static task_t parent_task;
+
+static task_t next_task;
+
+struct trivfs_control *storeio_fsys;
+
 /* Desired store parameters specified by the user.  */
 struct storeio_argp_params
 {
@@ -64,6 +90,66 @@ struct storeio_argp_params
   struct dev *dev;		/* We fill in its flag members.  */
 };
 
+static error_t
+storeio_bootstrap_startup (mach_port_t bootstrap)
+{
+  port_bucket = ports_create_bucket ();
+  struct port_class *trivfs_cntl_class;
+  trivfs_cntl_class = ports_create_class (trivfs_clean_cntl, 0);
+  struct port_class *trivfs_protid_class;
+  trivfs_protid_class = ports_create_class (trivfs_clean_protid, 0);
+
+  error_t err = trivfs_startup (bootstrap, 0, trivfs_cntl_class, port_bucket,
+                                trivfs_protid_class, 0, &storeio_fsys);
+  if (err)
+    return err;
+
+  err = fsys_getpriv (bootstrap, &_hurd_host_priv,
+                      &_hurd_device_master, &parent_task);
+  if (err)
+   return err;
+
+  mach_port_t right = ports_get_send_right (&storeio_fsys->pi);
+  err = task_set_special_port (next_task, TASK_BOOTSTRAP_PORT, right);
+  if (err)
+    return err;
+
+  err = mach_port_deallocate (mach_task_self (), right);
+  if (err)
+    return err;
+
+  err = task_resume (next_task);
+  if (err)
+    return err;
+
+  /* Make sure we have a console.  */
+  mach_port_t dev;
+  err = get_privileged_ports (NULL, &dev);
+  if (err)
+    return err;
+
+  mach_port_t cons;
+  err = device_open (dev, D_READ | D_WRITE, "console", &cons);
+  if (err)
+    return err;
+
+  err = mach_port_deallocate (mach_task_self (), dev);
+  if (err)
+    return err;
+
+  stdin = mach_open_devstream (cons, "r");
+  stdout = stderr = mach_open_devstream (cons, "w");
+  err = mach_port_deallocate (mach_task_self (), cons);
+  if (err)
+    return err;
+
+  setlinebuf (stderr);
+  printf ("storeio ");
+  fflush (stdout);
+
+  return 0;
+}
+
 /* Parse a single option.  */
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)
@@ -80,6 +166,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'e': params->dev->enforced = 1; break;
     case 'F': params->dev->no_fileio = 1; break;
 
+    case 'N': next_task = atoi (arg); break;
+    case 'H': _hurd_host_priv = atoi (arg); break;
+    case 'P': _hurd_device_master = atoi (arg); break;
+
     case 'n':
       {
 	char *start = arg, *end;
@@ -134,8 +224,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
 static const struct argp_child argp_kids[] = { { &store_argp }, {0} };
 static const struct argp argp = { options, parse_opt, 0, doc, argp_kids };
-
-struct trivfs_control *storeio_fsys;
 
 int
 main (int argc, char *argv[])
@@ -144,6 +232,7 @@ main (int argc, char *argv[])
   mach_port_t bootstrap;
   struct dev device;
   struct storeio_argp_params params;
+  hurd_init_argv = argv;
 
   memset (&device, 0, sizeof device);
   pthread_mutex_init (&device.lock, NULL);
@@ -165,10 +254,19 @@ main (int argc, char *argv[])
       if (bootstrap == MACH_PORT_NULL)
 	error (2, 0, "Must be started as a translator");
 
-      /* Reply to our parent */
-      err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &storeio_fsys);
-      if (err)
-	error (3, err, "trivfs_startup");
+      if (next_task != MACH_PORT_NULL)
+        {
+          err = storeio_bootstrap_startup (bootstrap);
+          if (err)
+            error (1, err, "storeio_bootstrap_startup");
+        }
+      else
+        {
+          /* Reply to our parent */
+          err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &storeio_fsys);
+          if (err)
+            error (3, err, "trivfs_startup");
+        }
     }
 
   storeio_fsys->hook = &device;
@@ -452,3 +550,158 @@ trivfs_S_fsys_syncfs (struct trivfs_control *cntl,
   else
     return 0;
 }
+
+/* Override the privileged ports for booting the system */
+kern_return_t
+trivfs_S_fsys_getpriv (struct trivfs_control *cntl,
+                       mach_port_t reply,
+                       mach_msg_type_name_t replytype,
+                       mach_port_t *host, mach_msg_type_name_t *host_privPoly,
+                       mach_port_t *dev, mach_msg_type_name_t *devPoly,
+                       mach_port_t *fstask, mach_msg_type_name_t *fstPoly)
+{
+  error_t err = get_privileged_ports (host, dev);
+  if (!err)
+    {
+      *fstask = mach_task_self ();
+      *host_privPoly = *devPoly = MACH_MSG_TYPE_MOVE_SEND;
+      *fstPoly = MACH_MSG_TYPE_COPY_SEND;
+    }
+
+  return err;
+}
+
+kern_return_t
+trivfs_S_fsys_startup (mach_port_t bootport,
+                       mach_port_t reply,
+                       mach_msg_type_name_t replytype,
+                       int flags,
+                       mach_port_t cntl,
+                       mach_port_t *realnode,
+                       mach_msg_type_name_t *realnodetype)
+{
+  control_port = cntl;
+  *realnode = MACH_PORT_NULL;
+  *realnodetype = MACH_MSG_TYPE_COPY_SEND;
+
+  mach_port_t mybootport;
+  task_get_bootstrap_port (mach_task_self (), &mybootport);
+  if (mybootport)
+    fsys_startup (mybootport, flags, control_port, MACH_MSG_TYPE_COPY_SEND,
+                  realnode);
+  return 0;
+}
+
+static void
+arrange_shutdown_notification (void)
+{
+  shutdown_notify_class = ports_create_class (0, 0);
+
+  /* Arrange to get notified when the system goes down */
+  struct port_info *pi;
+  error_t err = ports_create_port (shutdown_notify_class, port_bucket,
+                                   sizeof (struct port_info), &pi);
+  if (err)
+    return;
+
+  mach_port_t initport = file_name_lookup (_SERVERS_STARTUP, 0, 0);
+  if (initport == MACH_PORT_NULL)
+    {
+      mach_print ("WARNING: machdev not registered for shutdown\n");
+      return;
+    }
+
+  mach_port_t notify = ports_get_send_right (pi);
+  ports_port_deref (pi);
+  startup_request_notification (initport, notify, MACH_MSG_TYPE_MAKE_SEND,
+                                program_invocation_short_name);
+  mach_port_deallocate (mach_task_self (), notify);
+  mach_port_deallocate (mach_task_self (), initport);
+}
+
+static void
+essential_task (void)
+{
+  mach_port_t host;
+  error_t err = get_privileged_ports (&host, 0);
+  if (err)
+    {
+      mach_print ("WARNING: Cannot register as essential task\n");
+      return;
+    }
+
+  mach_port_t startup = file_name_lookup (_SERVERS_STARTUP, 0, 0);
+  if (startup == MACH_PORT_NULL)
+    {
+      mach_print ("WARNING: Cannot register as essential task\n");
+      mach_port_deallocate (mach_task_self (), host);
+      return;
+    }
+
+  startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL,
+                          program_invocation_short_name, host);
+  mach_port_deallocate (mach_task_self (), startup);
+  mach_port_deallocate (mach_task_self (), host);
+}
+
+kern_return_t
+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)
+{
+  /* Traverse to the bootstrapping server first */
+  error_t err;
+  mach_port_t bootstrap;
+  task_get_bootstrap_port (mach_task_self (), &bootstrap);
+  if (bootstrap)
+    {
+      process_t parent_proc;
+
+      err = proc_task2proc (procserver, parent_task, &parent_proc);
+      assert_perror_backtrace (err);
+
+      /* We don't need this anymore. */
+      mach_port_deallocate (mach_task_self (), parent_task);
+      parent_task = MACH_PORT_NULL;
+
+      proc_mark_exec(parent_proc);
+
+      err = fsys_init (bootstrap, parent_proc, MACH_MSG_TYPE_COPY_SEND, authhandle);
+      assert_perror_backtrace (err);
+
+      mach_port_deallocate (mach_task_self (), parent_proc);
+    }
+
+  mach_port_t root;
+  uid_t idlist[] = {0, 0, 0};
+  retry_type retry;
+  string_t retry_name;
+  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');
+  assert_backtrace (root != MACH_PORT_NULL);
+
+  mach_port_t *portarray = mmap (0, INIT_PORT_MAX * sizeof (*portarray),
+                                 PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ for (unsigned int i = 0; i < INIT_PORT_MAX; ++i)
+    portarray[i] = MACH_PORT_NULL;
+  portarray[INIT_PORT_PROC] = procserver;
+  portarray[INIT_PORT_AUTH] = authhandle;
+  portarray[INIT_PORT_CRDIR] = root;
+  portarray[INIT_PORT_CWDIR] = root;
+  _hurd_init (0, hurd_init_argv, portarray, INIT_PORT_MAX, NULL, 0);
+#ifdef HAVE__HURD_LIBC_PROC_INIT
+  _hurd_libc_proc_init (hurd_init_argv);
+#endif
+
+  /* Mark us as essential if bootstrapping.  */
+  essential_task ();
+
+  arrange_shutdown_notification ();
+
+  return 0;
+}
-- 
2.43.0

Reply via email to