From 9eb725fe9b9b717bb3ff10184f4c998001e6b449 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Thu, 8 Oct 2026 21:57:34 +0200 Subject: [PATCH] fs/v9fs: Set st_ino and d_ino from the qid path. stat() returned st_ino 0 and readdir() returned d_ino 0 for every file on a v9fs mount, although 9P identifies each file by its qid path. Programs that skip directory entries with d_ino 0, or that compare st_dev and st_ino to find out if two paths are the same file, do not work on such a mount. Fold the 64-bit qid path into ino_t the same way for both, so that they match, and never return 0. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli --- fs/v9fs/client.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/fs/v9fs/client.c b/fs/v9fs/client.c index ab5589b5721..31a7b9f05e1 100644 --- a/fs/v9fs/client.c +++ b/fs/v9fs/client.c @@ -378,6 +378,24 @@ struct v9fs_fid_s * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: v9fs_qid_ino + * + * Description: + * Return the file serial number (st_ino, d_ino) for a qid path. The + * qid path identifies the file on the server; it is folded into ino_t + * and never 0, because programs such as GNU make skip directory entries + * with d_ino 0. + * + ****************************************************************************/ + +static inline ino_t v9fs_qid_ino(uint64_t path) +{ + ino_t ino = (ino_t)(path ^ (path >> 32)); + + return ino != 0 ? ino : 1; +} + /**************************************************************************** * v9fs_get_tagid ****************************************************************************/ @@ -814,6 +832,7 @@ int v9fs_client_stat(FAR struct v9fs_client_s *client, uint32_t fid, return ret; } + buf->st_ino = v9fs_qid_ino(response.qid.path); buf->st_mode = response.mode; buf->st_uid = response.uid; buf->st_gid = response.gid; @@ -1016,6 +1035,7 @@ ssize_t v9fs_client_convertdir(FAR const uint8_t *buffer, size_t bufsize, off_t head, FAR off_t *offset, FAR struct dirent *entry) { + uint64_t qidpath; uint64_t off; uint16_t name_len; off_t next = head; @@ -1030,8 +1050,13 @@ ssize_t v9fs_client_convertdir(FAR const uint8_t *buffer, size_t bufsize, return -EIO; } - /* Skip the qid part (13 Bytes) */ + /* The qid part (13 Bytes): type, version, then the path that identifies + * the file. + */ + memcpy(&qidpath, buffer + next + V9FS_BIT8SZ + V9FS_BIT32SZ, + sizeof(uint64_t)); + entry->d_ino = v9fs_qid_ino(qidpath); next += V9FS_QIDSZ; /* Read the offset (8 bytes) */