Skip to content

Conversation

@no1wudi
Copy link
Contributor

@no1wudi no1wudi commented Sep 20, 2024

Summary

Currently implementations of dirent.h do not have a field for the inode number, but it is required by POSIX.

For better compatibility with POSIX based applications, it is should be added even if it is not actually implemented.

PR coupled with nuttx-apps PR apache/nuttx-apps#2593.

Impact

  • include/dirent.h.
  • include/nuttx/fs/hostfs.h.
  • Makes implementation compatible with POSIX.

Testing

CI and local machine

@github-actions github-actions bot added the Size: XS The size of the change in this PR is very small label Sep 20, 2024
no1wudi added a commit to no1wudi/nuttx-apps that referenced this pull request Sep 20, 2024
Refer to apache/nuttx#13556,
should be merged together.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
Copy link
Contributor

@yamt yamt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we add the field, i guess we should set a sane value.
at least it should be consistent with st_ino.

@no1wudi
Copy link
Contributor Author

no1wudi commented Sep 20, 2024

if we add the field, i guess we should set a sane value. at least it should be consistent with st_ino.

I'm not familiar with implementations of VFS, did you mean something like this?

static ssize_t dir_read(FAR struct file *filep, FAR char *buffer,
                        size_t buflen)
{
  FAR struct fs_dirent_s *dir = filep->f_priv;
#ifndef CONFIG_DISABLE_MOUNTPOINT
  FAR struct inode *inode = dir->fd_root;
#endif
  FAR struct dirent *dirent = (FAR struct dirent *)buffer;
  int ret;

  /* Verify that we were provided with a valid directory structure */

  if (buffer == NULL || buflen < sizeof(struct dirent))
    {
      return -EINVAL;
    }

  /* The way we handle the readdir depends on the type of inode
   * that we are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if (INODE_IS_MOUNTPT(inode))
    {
      ret = inode->u.i_mops->readdir(inode, dir, dirent);
    }
  else
#endif
    {
      /* The node is part of the root pseudo file system */

      ret = read_pseudodir(dir, dirent);
    }

  /* ret < 0 is an error. Special case: ret = -ENOENT is end of file */

  if (ret < 0)
    {
      if (ret == -ENOENT)
        {
          ret = 0;
        }

      return ret;
    }

  >>> New added  here <<<

  dirent->d_ino = dir->fd_root->i_ino;


  filep->f_pos++;
  return sizeof(struct dirent);
}

Currently implementations of dirent.h do not have a field for the inode number,
but it is required by POSIX.

For better compatibility with POSIX based applications, it is should be added
even if it is not actually implemented, now just use i_ino from inode for it.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
@github-actions github-actions bot added Arch: simulator Issues related to the SIMulator Area: File System File System issues Size: S The size of the change in this PR is small and removed Size: XS The size of the change in this PR is very small labels Sep 23, 2024

/* REVISIT: Should we use i_ino for the d_ino field? */

dirent->d_ino = dir->fd_root->i_ino;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d_ino should match st_ino of the file referenced by the directory entry.

a naive implementation would be something like:

fstat(dirent->d_name, &st);
dirent->d_ino = st.st_ino;

iirc, on nuttx, most filesystems just use st_ino = 0.
for those filesystems, it can be optimized to d_ino = 0.

@yamt
Copy link
Contributor

yamt commented Sep 24, 2024

honestly speaking, i'm not sure if it's worth to implement d_ino for nuttx.
as the most filesystems here don't implement inode numbers at all,
applications using d_ino likely need modifications to deal with the situation anyway.

what's your motivation to add d_ino?

@no1wudi
Copy link
Contributor Author

no1wudi commented Sep 24, 2024

what's your motivation to add d_ino?

@yamt I'm porting Rust std library to NuttX, the ino is required by it: https://doc.rust-lang.org/std/os/unix/fs/trait.DirEntryExt.html#tymethod.ino

But this is not used by Rust itself, leave it to 0 is OK if nobody really need it. So in the first PR I just add the missing field to make the compiler happy.

@no1wudi
Copy link
Contributor Author

no1wudi commented Sep 24, 2024

And I'm reusing the unix port, so the strcut layout should be aligned to POSIX if possible even if we don't implement it yet

@lupyuen
Copy link
Member

lupyuen commented Sep 24, 2024

And I'm reusing the unix port, so the strcut layout should be aligned to POSIX if possible even if we don't implement it yet

@no1wudi I think we might need to customise the Unix Port, and make it work for NuttX? It seems a bit odd that we need to add extra Kernel Fields to NuttX, just to support Rust.

@no1wudi
Copy link
Contributor Author

no1wudi commented Sep 24, 2024

@no1wudi I think we might need to customise the Unix Port, and make it work for NuttX? It seems a bit odd that we need to add extra Kernel Fields to NuttX, just to support Rust.

It's OK that just leave it to 0 in Rust side for NuttX, if it's better

@no1wudi no1wudi closed this Sep 24, 2024
@yamt
Copy link
Contributor

yamt commented Sep 24, 2024

what's your motivation to add d_ino?

@yamt I'm porting Rust std library to NuttX, the ino is required by it: https://doc.rust-lang.org/std/os/unix/fs/trait.DirEntryExt.html#tymethod.ino

But this is not used by Rust itself, leave it to 0 is OK if nobody really need it. So in the first PR I just add the missing field to make the compiler happy.

as it can be a bit expensive to perform fstat equivalent on each entries, it might be better to avoid doing that by default.

however, unfortunately, there is no reserved values for inode numbers to indicate the "no inode number available" situation as far as i know.
that is, 0 is not really a special value.
it's unfortunate because, even on a posix environment, it's often tricky to provide inode numbers for some filesystems w/o hard links.
having said that, my impression is that it isn't too uncommon to use 0 for that purpose. (at least it's certainly better than uninitialized stack garbage.)

wrt rust, depending on how serious your port is, you might need to consider emulating the inode number by yourself.
(not only d_ino, but also st_ino.)
otoh, maybe the least invasive thing is to patch your rust port to provide 0 by itself, rather than modifying nuttx.

FYI, wasi-libc tries to emulate d_ino by itself for similar reasons. (well, another motivation there is windows support)
https://github.com/WebAssembly/wasi-libc/blob/7d4d3b83fc66c79b3faa5989e67ed2d1042dacaf/libc-bottom-half/cloudlibc/src/libc/dirent/readdir.c#L87-L110

@no1wudi
Copy link
Contributor Author

no1wudi commented Sep 24, 2024

wrt rust, depending on how serious your port is, you might need to consider emulating the inode number by yourself. (not only d_ino, but also st_ino.) otoh, maybe the least invasive thing is to patch your rust port to provide 0 by itself, rather than modifying nuttx.

Maybe not 0 but panic if user try to use it for now on NuttX, Rust std allow some unsupported features if platform don't support it.

FYI, wasi-libc tries to emulate d_ino by itself for similar reasons. (well, another motivation there is windows support) https://github.com/WebAssembly/wasi-libc/blob/7d4d3b83fc66c79b3faa5989e67ed2d1042dacaf/libc-bottom-half/cloudlibc/src/libc/dirent/readdir.c#L87-L110

Thanks for your information, I guess it should be emulated in NuttX side as your comments above instead of Rust side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: simulator Issues related to the SIMulator Area: File System File System issues Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants