Hello,

On Mon, 5 Oct 2026 23:37:13 Samuel Thibault wrote:

> And indeed, trivfs_S_io_map has disappeared, but netfs_S_io_map was not

> introduced.

It is not strictly necessary to implement the netfs_S_io_map function,

because we could implement netfs_get_filemap instead, which would be called
by the netfs_S_io_map function in libnetfs.  However, in our case, we need to implement netfs_S_io_map specifically because the behavior of trivfs_S_io_map
from storeio differs from the netfs_S_io_map implementation in libnetfs.
Examining the code reveals that trivfs_S_io_map returned an error only if the
dev_get_memory_object function failed, even though memobj could be
MACH_PORT_NULL.  In the netfs_S_io_map implementation, an error is returned
if memobj is MACH_PORT_NULL.  I do not know which behavior is more correct.
We can either modify the behavior of netfs_S_io_map to match trivfs_S_io_map

or simply override netfs_S_io_map in storeio.

> Also, ls -l /dev/zero returns

>
> ls: reading directory '/dev/zero': Not a directory
>
> I guess it should be fixed into not showing the directory type when

> there is not partition table.

We can override netfs_S_io_stat and return the desired mode when

netfs_root_node is accessed.  We need to override this function because
modifying netfs_root_node->nn_stat.st_mode directly is not allowed, as it

leads to errors.

> Also,

>
> € sudo ls /dev/sd0/ -l
> total 1
> b--------- 1 root root 86, 77 oct.   5 21:39 1
> b--------- 1 root root 86, 77 oct.   5 21:39 2
>

> It's missing some permissions 🙂

This was resolved by adding code to netfs_report_access instead of returning

EOPNOTSUPP.

Thanks,

--
Mikhail Karpov
From 50b3b85fe2fc4b8a741bd28bf846d1b972e092b4 Mon Sep 17 00:00:00 2001
From: Mikhail Karpov <[email protected]>
Date: Tue, 6 Oct 2026 21:18:05 +0700
Subject: [PATCH 3/3] Fixing the mmap and st_mode issue

---
 storeio/dev.h     |   4 +-
 storeio/part.c    |   1 +
 storeio/storeio.c | 134 ++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 114 insertions(+), 25 deletions(-)

diff --git a/storeio/dev.h b/storeio/dev.h
index beeb1fe..aae008e 100644
--- a/storeio/dev.h
+++ b/storeio/dev.h
@@ -27,8 +27,6 @@
 #include <stdio.h>
 #include <unistd.h>
 
-extern mach_port_t underlying_node;
-
 /* Information about backend store, which we presumptively call a "device".  */
 struct dev
 {
@@ -94,6 +92,8 @@ struct storeio_stat
 };
 
 extern struct storeio_stat storeio_stat;
+extern mach_port_t underlying_node;
+extern mode_t root_node_mode;
 
 error_t create_node (struct node **node, char *name, struct node *dir);
 error_t check_dev (struct node *node, struct store *store, int flags);
diff --git a/storeio/part.c b/storeio/part.c
index 5c9c6a2..47d37df 100644
--- a/storeio/part.c
+++ b/storeio/part.c
@@ -114,6 +114,7 @@ create_partitions (void)
   const int flags = ((storeio_stat.readonly ? STORE_READONLY : 0)
                      | (storeio_stat.no_fileio ? STORE_NO_FILEIO : 0));
 
+  root_node_mode = S_IFDIR;
   struct store *source, *store;
   struct node **part;
   char *node_name;
diff --git a/storeio/storeio.c b/storeio/storeio.c
index 3302c5c..348afde 100644
--- a/storeio/storeio.c
+++ b/storeio/storeio.c
@@ -64,6 +64,7 @@ const char *argp_program_version = STANDARD_HURD_VERSION (storeio);
 char *netfs_server_name = "storeio";
 char *netfs_server_version = HURD_VERSION;
 int netfs_maxsymlinks = 0; /* arbitrary */
+mode_t root_node_mode = 0;
 
 char *debug_file_name = NULL;
 FILE *debug_file;
@@ -153,18 +154,24 @@ create_node (struct node **node, char *name, struct node *dir)
 static inline void
 change_node_mode (struct node *node)
 {
-  node->nn_stat.st_mode &= S_IFMT;
-
+  mode_t mode;
   if (storeio_stat.inhibit_cache)
+    mode = S_IFCHR;
+  else
     {
-      node->nn_stat.st_mode |= S_IFCHR;
-      return;
+      if (node->nn->dev->store && node->nn->dev->store->block_size == 1)
+        mode = S_IFCHR;
+      else
+        mode = S_IFBLK;
     }
 
-  if (node->nn->dev->store && node->nn->dev->store->block_size == 1)
-    node->nn_stat.st_mode |= S_IFCHR;
+  if (node == netfs_root_node)
+    {
+      if (root_node_mode != S_IFDIR)
+        root_node_mode = mode;
+    }
   else
-    node->nn_stat.st_mode |= S_IFBLK;
+    node->nn_stat.st_mode = mode | (node->nn_stat.st_mode & ~S_IFMT);
 }
 
 error_t
@@ -215,8 +222,7 @@ check_dev (struct node *node, struct store *store, int flags)
       if (dev->store->block_size > 1)
         node->nn_stat.st_blksize = dev->store->block_size;
 
-      if (node != netfs_root_node)
-        change_node_mode (node);
+      change_node_mode (node);
     }
   pthread_mutex_unlock (&dev->lock);
 
@@ -553,6 +559,7 @@ netfs_validate_stat (struct node *np, struct iouser *cred)
       np->nn_stat.st_blksize = 0;
     }
 
+  np->nn_translated = np->nn_stat.st_mode;
   return 0;
 }
 
@@ -870,22 +877,17 @@ netfs_attempt_write (struct iouser *cred, struct node *np, loff_t offset,
 error_t
 netfs_report_access (struct iouser *cred, struct node *np, int *types)
 {
-  return EOPNOTSUPP;
-}
+  *types = 0;
+  if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0)
+    *types |= O_READ;
 
-mach_port_t
-netfs_get_filemap (struct node *np, vm_prot_t prot)
-{
-  mach_port_t memobj;
-  errno = dev_get_memory_object (np->nn->dev, prot, &memobj);
-  if (errno)
-    {
-      debug ("netfs_get_filemap (np: %p, vm_prot_t: %d):\n", np, prot);
-      memobj = MACH_PORT_NULL;
-      debug ("dev_get_memory_object return err: %d\n", errno);
-    }
+  if (fshelp_access (&np->nn_stat, S_IWRITE, cred) == 0)
+    *types |= O_WRITE;
+
+  if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0)
+    *types |= O_EXEC;
 
-  return memobj;
+  return 0;
 }
 
 struct iouser *
@@ -1109,3 +1111,89 @@ netfs_file_get_storage_info (struct iouser *cred, struct node *np,
 
   return err;
 }
+
+kern_return_t
+netfs_S_io_stat (struct protid *user, io_statbuf_t *statbuf)
+{
+  if (!user)
+    return EOPNOTSUPP;
+
+  struct node *node = user->po->np;
+  pthread_mutex_lock (&node->lock);
+
+  error_t err = netfs_validate_stat (node, user->user);
+  if (err)
+    {
+      pthread_mutex_unlock (&node->lock);
+      return err;
+    }
+
+  memcpy (statbuf, &node->nn_stat, sizeof (struct stat));
+
+  if (node == netfs_root_node)
+    statbuf->st_mode = root_node_mode | (statbuf->st_mode & ~S_IFMT);
+
+  /* Set S_IATRANS and S_IROOT bits as appropriate.  */
+  statbuf->st_mode &= ~(S_IATRANS | S_IROOT);
+  if (fshelp_translated (&node->transbox))
+    statbuf->st_mode |= S_IATRANS; /* Has an active translator.  */
+
+  if (user->po->shadow_root == node || node == netfs_root_node)
+    statbuf->st_mode |= S_IROOT; /* Is a root node.  */
+
+  pthread_mutex_unlock (&node->lock);
+  return 0;
+}
+
+kern_return_t
+netfs_S_io_map (struct protid *user,
+		mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype,
+		mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype)
+{
+  if (!user)
+    return EOPNOTSUPP;
+
+  if (user->po->openstat & (O_READ | O_WRITE) == 0)
+    return EBADF;
+
+  *wrobj = *rdobj = MACH_PORT_NULL;
+
+  struct node *node = user->po->np;
+  int flags = user->po->openstat & (O_READ | O_WRITE);
+  vm_prot_t prot = ((flags & O_READ) ? VM_PROT_READ : 0)
+                    | ((flags & O_WRITE) ? VM_PROT_WRITE : 0);
+
+  pthread_mutex_lock (&node->lock);
+  memory_object_t memobj;
+  error_t err = dev_get_memory_object (node->nn->dev, prot, &memobj);
+  if (err)
+    {
+      pthread_mutex_unlock (&node->lock);
+      return err;
+    }
+
+  switch (flags)
+    {
+    case O_READ | O_WRITE:
+      *wrobj = *rdobj = memobj;
+      if (memobj != MACH_PORT_NULL)
+        mach_port_mod_refs (mach_task_self (), memobj,
+                            MACH_PORT_RIGHT_SEND, 1);
+      break;
+
+    case O_READ:
+      *rdobj = memobj;
+      break;
+
+    case O_WRITE:
+      *wrobj = memobj;
+      break;
+    }
+
+  pthread_mutex_unlock (&node->lock);
+
+  *rdobjtype = MACH_MSG_TYPE_MOVE_SEND;
+  *wrobjtype = MACH_MSG_TYPE_MOVE_SEND;
+
+  return 0;
+}
-- 
2.43.0

Reply via email to