aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/9pfs/9p-util.h39
-rw-r--r--hw/9pfs/9p.c2
2 files changed, 40 insertions, 1 deletions
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index 97e681e..2cc9a5d 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -19,6 +19,45 @@
#define O_PATH_9P_UTIL 0
#endif
+#if !defined(CONFIG_LINUX)
+
+/*
+ * Generates a Linux device number (a.k.a. dev_t) for given device major
+ * and minor numbers.
+ *
+ * To be more precise: it generates a device number in glibc's format
+ * (MMMM_Mmmm_mmmM_MMmm, 64 bits) actually, which is compatible with
+ * Linux's format (mmmM_MMmm, 32 bits), as described in <bits/sysmacros.h>.
+ */
+static inline uint64_t makedev_dotl(uint32_t dev_major, uint32_t dev_minor)
+{
+ uint64_t dev;
+
+ // from glibc sysmacros.h:
+ dev = (((uint64_t) (dev_major & 0x00000fffu)) << 8);
+ dev |= (((uint64_t) (dev_major & 0xfffff000u)) << 32);
+ dev |= (((uint64_t) (dev_minor & 0x000000ffu)) << 0);
+ dev |= (((uint64_t) (dev_minor & 0xffffff00u)) << 12);
+ return dev;
+}
+
+#endif
+
+/*
+ * Converts given device number from host's device number format to Linux
+ * device number format. As both the size of type dev_t and encoding of
+ * dev_t is system dependant, we have to convert them for Linux guests if
+ * host is not running Linux.
+ */
+static inline uint64_t host_dev_to_dotl_dev(dev_t dev)
+{
+#ifdef CONFIG_LINUX
+ return dev;
+#else
+ return makedev_dotl(major(dev), minor(dev));
+#endif
+}
+
#ifdef CONFIG_DARWIN
#define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 225f31f..4a296a0b 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1327,7 +1327,7 @@ static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
v9lstat->st_nlink = stbuf->st_nlink;
v9lstat->st_uid = stbuf->st_uid;
v9lstat->st_gid = stbuf->st_gid;
- v9lstat->st_rdev = stbuf->st_rdev;
+ v9lstat->st_rdev = host_dev_to_dotl_dev(stbuf->st_rdev);
v9lstat->st_size = stbuf->st_size;
v9lstat->st_blksize = stat_to_iounit(pdu, stbuf);
v9lstat->st_blocks = stbuf->st_blocks;