Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir() APIs

2023-03-17 Thread Christian Schoenebeck
On Friday, March 17, 2023 5:36:37 AM CET Shi, Guohuai wrote:
[...]
> > > > > > +do {
> > > > > > +full_dir_entry = get_full_path_win32(hDir,
> > > > > > + dd_data.name);
> > > > > > +
> > > > > > +if (full_dir_entry == NULL) {
> > > > > > +err = ENOMEM;
> > > > > > +break;
> > > > > > +}
> > > > > > +
> > > > > > +/*
> > > > > > + * Open every entry and get the file informations.
> > > > > > + *
> > > > > > + * Skip symbolic links during reading directory.
> > > > > > + */
> > > > > > +hDirEntry = CreateFile(full_dir_entry,
> > > > > > +   GENERIC_READ,
> > > > > > +   FILE_SHARE_READ | FILE_SHARE_WRITE
> > > > > > +   | FILE_SHARE_DELETE,
> > > > > > +   NULL,
> > > > > > +   OPEN_EXISTING,
> > > > > > +   FILE_FLAG_BACKUP_SEMANTICS
> > > > > > +   | FILE_FLAG_OPEN_REPARSE_POINT,
> > > > > > + NULL);
> > > > > > +
> > > > > > +if (hDirEntry != INVALID_HANDLE_VALUE) {
> > > > > > +if (GetFileInformationByHandle(hDirEntry,
> > > > > > +   &FileInfo) == TRUE) {
> > > > > > +attribute = FileInfo.dwFileAttributes;
> > > > > > +
> > > > > > +/* only save validate entries */
> > > > > > +if ((attribute & FILE_ATTRIBUTE_REPARSE_POINT) == 
> > > > > > 0) {
> > > > > > +if (index >= list_count) {
> > > > > > +list_count = list_count + 16;
> > > > >
> > > > > Magic number 16 again.
> > > > >
> > > > > > +file_id_list = g_realloc(file_id_list,
> > > > > > + sizeof(uint64_t)
> > > > > > + * list_count);
> > > > >
> > > > > OK, so here we are finally at the point where you chose the
> > > > > overall behaviour for this that we discussed before.
> > > > >
> > > > > So you are constantly appending 16 entry chunks to the end of the
> > > > > array, periodically reallocate the entire array, and potentially
> > > > > end up with one giant dense array with *all* file IDs of the 
> > > > > directory.
> > > > >
> > > > > That's not really what I had in mind, as it still has the
> > > > > potential to easily crash QEMU if there are large directories on host.
> > > > > Theoretically a Windows directory might then consume up to 16 GB
> > > > > of RAM for looking up only one single directory.
> > > > >
> > > > > So is this the implementation that you said was very slow, or did
> > > > > you test a different one? Remember, my orgiginal idea (as starting
> > > > > point for Windows) was to only cache *one* file ID (the last being
> > > > > looked up). That's it. Not a list of file IDs.
> > > >
> > > > If only cache one file ID, that means for every read directory 
> > > > operation.
> > > > we need to look up whole directory to find out the next ID larger
> > > > than last
> > > cached one.
> > > >
> > > > I provided some performance test in last patch:
> > > > Run test for read directory with 100, 1000, 1 entries #1, For
> > > > file name cache solution, the time cost is: 2, 9, 44 (in ms).
> > > > #2, For file id cache solution, the time cost: 3, 438, 4338 (in ms).
> > > > This
> > > is current solution.
> > > > #3, for cache one id solution, I just tested it: 4, 4788, more than
> > > > one minutes (in ms)
> > > >
> > > > I think it is not a good idea to cache one file id, it would be very
> > > > bad performance
> > >
> > > Yes, the performce would be lousy, but at least we would have a basis
> > > that just works^TM. Correct behaviour always comes before performance.
> > > And from there you could add additional patches on top to address
> > > performance improvements. Because the point is: your implementation is
> > > also suboptimal, and more importantly: prone to crashes like we discussed
> > before.
> > >
> > > Regarding performance: for instance you are re-allocating an entire
> > > dense buffer on every 16 new entries. That will slow down things
> > > extremely. Please use a container from glib, because these are
> > > handling resize operations more smoothly for you out of the box, i.e.
> > > typically by doubling the container capacity instead of re-allocating
> > frequently with small chunks like you did.
> > >
> > > However I am still not convinced that allocating a huge dense buffer
> > > with
> > > *all* file IDs of a directory makes sense.
> > >
> > > On the long-term it would make sense to do it like other implementations:
> > > store a snapshot of the directory temporarily on disk. That way it
> > > would not matter how huge the directory is. But that's a complex
> > > implementation, so not something that I would do in this series already.
> > >
> > > O

RE: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir() APIs

2023-03-16 Thread Shi, Guohuai



> -Original Message-
> From: Shi, Guohuai
> Sent: Friday, March 17, 2023 01:28
> To: Christian Schoenebeck ; Greg Kurz
> ; qemu-devel@nongnu.org
> Cc: Meng, Bin 
> Subject: RE: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir()
> APIs
> 
> 
> 
> > -Original Message-
> > From: Christian Schoenebeck 
> > Sent: Thursday, March 16, 2023 19:05
> > To: Greg Kurz ; qemu-devel@nongnu.org
> > Cc: Meng, Bin ; Shi, Guohuai
> > 
> > Subject: Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific
> > xxxdir() APIs
> >
> > CAUTION: This email comes from a non Wind River email account!
> > Do not click links or open attachments unless you recognize the sender
> > and know the content is safe.
> >
> > On Wednesday, March 15, 2023 8:05:34 PM CET Shi, Guohuai wrote:
> > >
> > > > -Original Message-
> > > > From: Christian Schoenebeck 
> > > > Sent: Wednesday, March 15, 2023 00:06
> > > > To: Greg Kurz ; qemu-devel@nongnu.org
> > > > Cc: Shi, Guohuai ; Meng, Bin
> > > > 
> > > > Subject: Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific
> > > > xxxdir() APIs
> > > >
> > > > CAUTION: This email comes from a non Wind River email account!
> > > > Do not click links or open attachments unless you recognize the
> > > > sender and know the content is safe.
> > > >
> > > > On Monday, February 20, 2023 11:08:03 AM CET Bin Meng wrote:
> > > > > From: Guohuai Shi 
> > > > >
> > > > > This commit implements Windows specific xxxdir() APIs for safety
> > > > > directory access.
> > > >
> > > > That comment is seriously too short for this patch.
> > > >
> > > > 1. You should describe the behaviour implementation that you have
> > > > chosen and why you have chosen it.
> > > >
> > > > 2. Like already said in the previous version of the patch, you
> > > > should place a link to the discussion we had on this issue.
> > > >
> > > > > Signed-off-by: Guohuai Shi 
> > > > > Signed-off-by: Bin Meng 
> > > > > ---
> > > > >
> > > > >  hw/9pfs/9p-util.h   |   6 +
> > > > >  hw/9pfs/9p-util-win32.c | 443
> > > > > 
> > > > >  2 files changed, 449 insertions(+)
> > > > >
> > > > > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index
> > > > > 0f159fb4ce..c1c251fbd1 100644
> > > > > --- a/hw/9pfs/9p-util.h
> > > > > +++ b/hw/9pfs/9p-util.h
> > > > > @@ -141,6 +141,12 @@ int unlinkat_win32(int dirfd, const char
> > > > > *pathname, int flags);  int statfs_win32(const char *root_path,
> > > > > struct statfs *stbuf);  int openat_dir(int dirfd, const char
> > > > > *name);  int openat_file(int dirfd, const char *name, int flags,
> > > > > mode_t mode);
> > > > > +DIR *opendir_win32(const char *full_file_name); int
> > > > > +closedir_win32(DIR *pDir); struct dirent *readdir_win32(DIR
> > > > > +*pDir); void rewinddir_win32(DIR *pDir); void seekdir_win32(DIR
> > > > > +*pDir, long pos); long telldir_win32(DIR *pDir);
> > > > >  #endif
> > > > >
> > > > >  static inline void close_preserve_errno(int fd) diff --git
> > > > > a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c index
> > > > > a99d579a06..e9408f3c45 100644
> > > > > --- a/hw/9pfs/9p-util-win32.c
> > > > > +++ b/hw/9pfs/9p-util-win32.c
> > > > > @@ -37,6 +37,16 @@
> > > > >   *Windows does not support opendir, the directory fd is created 
> > > > > by
> > > > >   *CreateFile and convert to fd by _open_osfhandle(). Keep the fd
> > open
> > > > will
> > > > >   *lock and protect the directory (can not be modified or 
> > > > > replaced)
> > > > > + *
> > > > > + * 5. Neither Windows native APIs, nor MinGW provide a POSIX
> > > > > + compatible
> > > > API for
> > > > > + *acquiring directory entries in a safe way. Calling those APIs
> > > > (native
> > > > > + *_findfirst() and _findnext() or MinGW's readdir(), seekdir() 
> > > > > and
> > > > > + *telldir()) d

RE: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir() APIs

2023-03-16 Thread Shi, Guohuai



> -Original Message-
> From: Christian Schoenebeck 
> Sent: Thursday, March 16, 2023 19:05
> To: Greg Kurz ; qemu-devel@nongnu.org
> Cc: Meng, Bin ; Shi, Guohuai
> 
> Subject: Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir()
> APIs
> 
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and
> know the content is safe.
> 
> On Wednesday, March 15, 2023 8:05:34 PM CET Shi, Guohuai wrote:
> >
> > > -Original Message-
> > > From: Christian Schoenebeck 
> > > Sent: Wednesday, March 15, 2023 00:06
> > > To: Greg Kurz ; qemu-devel@nongnu.org
> > > Cc: Shi, Guohuai ; Meng, Bin
> > > 
> > > Subject: Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific
> > > xxxdir() APIs
> > >
> > > CAUTION: This email comes from a non Wind River email account!
> > > Do not click links or open attachments unless you recognize the
> > > sender and know the content is safe.
> > >
> > > On Monday, February 20, 2023 11:08:03 AM CET Bin Meng wrote:
> > > > From: Guohuai Shi 
> > > >
> > > > This commit implements Windows specific xxxdir() APIs for safety
> > > > directory access.
> > >
> > > That comment is seriously too short for this patch.
> > >
> > > 1. You should describe the behaviour implementation that you have
> > > chosen and why you have chosen it.
> > >
> > > 2. Like already said in the previous version of the patch, you
> > > should place a link to the discussion we had on this issue.
> > >
> > > > Signed-off-by: Guohuai Shi 
> > > > Signed-off-by: Bin Meng 
> > > > ---
> > > >
> > > >  hw/9pfs/9p-util.h   |   6 +
> > > >  hw/9pfs/9p-util-win32.c | 443
> > > > 
> > > >  2 files changed, 449 insertions(+)
> > > >
> > > > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index
> > > > 0f159fb4ce..c1c251fbd1 100644
> > > > --- a/hw/9pfs/9p-util.h
> > > > +++ b/hw/9pfs/9p-util.h
> > > > @@ -141,6 +141,12 @@ int unlinkat_win32(int dirfd, const char
> > > > *pathname, int flags);  int statfs_win32(const char *root_path,
> > > > struct statfs *stbuf);  int openat_dir(int dirfd, const char
> > > > *name);  int openat_file(int dirfd, const char *name, int flags,
> > > > mode_t mode);
> > > > +DIR *opendir_win32(const char *full_file_name); int
> > > > +closedir_win32(DIR *pDir); struct dirent *readdir_win32(DIR
> > > > +*pDir); void rewinddir_win32(DIR *pDir); void seekdir_win32(DIR
> > > > +*pDir, long pos); long telldir_win32(DIR *pDir);
> > > >  #endif
> > > >
> > > >  static inline void close_preserve_errno(int fd) diff --git
> > > > a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c index
> > > > a99d579a06..e9408f3c45 100644
> > > > --- a/hw/9pfs/9p-util-win32.c
> > > > +++ b/hw/9pfs/9p-util-win32.c
> > > > @@ -37,6 +37,16 @@
> > > >   *Windows does not support opendir, the directory fd is created by
> > > >   *CreateFile and convert to fd by _open_osfhandle(). Keep the fd
> open
> > > will
> > > >   *lock and protect the directory (can not be modified or replaced)
> > > > + *
> > > > + * 5. Neither Windows native APIs, nor MinGW provide a POSIX
> > > > + compatible
> > > API for
> > > > + *acquiring directory entries in a safe way. Calling those APIs
> > > (native
> > > > + *_findfirst() and _findnext() or MinGW's readdir(), seekdir() and
> > > > + *telldir()) directly can lead to an inconsistent state if
> directory
> > > is
> > > > + *modified in between, e.g. the same directory appearing more than
> > > once
> > > > + *in output, or directories not appearing at all in output even
> though
> > > they
> > > > + *were neither newly created nor deleted. POSIX does not define
> what
> > > happens
> > > > + *with deleted or newly created directories in between, but it
> > > guarantees a
> > > > + *consistent state.
> > > >   */
> > > >
> > > >  #include "qemu/osdep.h"
> > > > @@ -51,6 +61,25 @@
> > > >
> > > >  #define V9FS_MAGIC  0x

Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir() APIs

2023-03-16 Thread Christian Schoenebeck
On Wednesday, March 15, 2023 8:05:34 PM CET Shi, Guohuai wrote:
> 
> > -Original Message-
> > From: Christian Schoenebeck 
> > Sent: Wednesday, March 15, 2023 00:06
> > To: Greg Kurz ; qemu-devel@nongnu.org
> > Cc: Shi, Guohuai ; Meng, Bin
> > 
> > Subject: Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir()
> > APIs
> > 
> > CAUTION: This email comes from a non Wind River email account!
> > Do not click links or open attachments unless you recognize the sender and
> > know the content is safe.
> > 
> > On Monday, February 20, 2023 11:08:03 AM CET Bin Meng wrote:
> > > From: Guohuai Shi 
> > >
> > > This commit implements Windows specific xxxdir() APIs for safety
> > > directory access.
> > 
> > That comment is seriously too short for this patch.
> > 
> > 1. You should describe the behaviour implementation that you have chosen and
> > why you have chosen it.
> > 
> > 2. Like already said in the previous version of the patch, you should place 
> > a
> > link to the discussion we had on this issue.
> > 
> > > Signed-off-by: Guohuai Shi 
> > > Signed-off-by: Bin Meng 
> > > ---
> > >
> > >  hw/9pfs/9p-util.h   |   6 +
> > >  hw/9pfs/9p-util-win32.c | 443
> > > 
> > >  2 files changed, 449 insertions(+)
> > >
> > > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index
> > > 0f159fb4ce..c1c251fbd1 100644
> > > --- a/hw/9pfs/9p-util.h
> > > +++ b/hw/9pfs/9p-util.h
> > > @@ -141,6 +141,12 @@ int unlinkat_win32(int dirfd, const char
> > > *pathname, int flags);  int statfs_win32(const char *root_path, struct
> > > statfs *stbuf);  int openat_dir(int dirfd, const char *name);  int
> > > openat_file(int dirfd, const char *name, int flags, mode_t mode);
> > > +DIR *opendir_win32(const char *full_file_name); int
> > > +closedir_win32(DIR *pDir); struct dirent *readdir_win32(DIR *pDir);
> > > +void rewinddir_win32(DIR *pDir); void seekdir_win32(DIR *pDir, long
> > > +pos); long telldir_win32(DIR *pDir);
> > >  #endif
> > >
> > >  static inline void close_preserve_errno(int fd) diff --git
> > > a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c index
> > > a99d579a06..e9408f3c45 100644
> > > --- a/hw/9pfs/9p-util-win32.c
> > > +++ b/hw/9pfs/9p-util-win32.c
> > > @@ -37,6 +37,16 @@
> > >   *Windows does not support opendir, the directory fd is created by
> > >   *CreateFile and convert to fd by _open_osfhandle(). Keep the fd open
> > will
> > >   *lock and protect the directory (can not be modified or replaced)
> > > + *
> > > + * 5. Neither Windows native APIs, nor MinGW provide a POSIX compatible
> > API for
> > > + *acquiring directory entries in a safe way. Calling those APIs
> > (native
> > > + *_findfirst() and _findnext() or MinGW's readdir(), seekdir() and
> > > + *telldir()) directly can lead to an inconsistent state if directory
> > is
> > > + *modified in between, e.g. the same directory appearing more than
> > once
> > > + *in output, or directories not appearing at all in output even 
> > > though
> > they
> > > + *were neither newly created nor deleted. POSIX does not define what
> > happens
> > > + *with deleted or newly created directories in between, but it
> > guarantees a
> > > + *consistent state.
> > >   */
> > >
> > >  #include "qemu/osdep.h"
> > > @@ -51,6 +61,25 @@
> > >
> > >  #define V9FS_MAGIC  0x53465039  /* string "9PFS" */
> > >
> > > +/*
> > > + * MinGW and Windows does not provide a safe way to seek directory
> > > +while other
> > > + * thread is modifying the same directory.
> > > + *
> > > + * This structure is used to store sorted file id and ensure
> > > +directory seek
> > > + * consistency.
> > > + */
> > > +struct dir_win32 {
> > > +struct dirent dd_dir;
> > > +uint32_t offset;
> > > +uint32_t total_entries;
> > > +HANDLE hDir;
> > > +uint32_t dir_name_len;
> > > +uint64_t dot_id;
> > > +uint64_t dot_dot_id;
> > > +uint64_t *file_id_list;
> > > +char dd_name[1];
> > > +};
> > > +
> > >  /*
> > >   * win32_error_to_posix - convert Win32

RE: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir() APIs

2023-03-15 Thread Shi, Guohuai



> -Original Message-
> From: Christian Schoenebeck 
> Sent: Wednesday, March 15, 2023 00:06
> To: Greg Kurz ; qemu-devel@nongnu.org
> Cc: Shi, Guohuai ; Meng, Bin
> 
> Subject: Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir()
> APIs
> 
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and
> know the content is safe.
> 
> On Monday, February 20, 2023 11:08:03 AM CET Bin Meng wrote:
> > From: Guohuai Shi 
> >
> > This commit implements Windows specific xxxdir() APIs for safety
> > directory access.
> 
> That comment is seriously too short for this patch.
> 
> 1. You should describe the behaviour implementation that you have chosen and
> why you have chosen it.
> 
> 2. Like already said in the previous version of the patch, you should place a
> link to the discussion we had on this issue.
> 
> > Signed-off-by: Guohuai Shi 
> > Signed-off-by: Bin Meng 
> > ---
> >
> >  hw/9pfs/9p-util.h   |   6 +
> >  hw/9pfs/9p-util-win32.c | 443
> > 
> >  2 files changed, 449 insertions(+)
> >
> > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index
> > 0f159fb4ce..c1c251fbd1 100644
> > --- a/hw/9pfs/9p-util.h
> > +++ b/hw/9pfs/9p-util.h
> > @@ -141,6 +141,12 @@ int unlinkat_win32(int dirfd, const char
> > *pathname, int flags);  int statfs_win32(const char *root_path, struct
> > statfs *stbuf);  int openat_dir(int dirfd, const char *name);  int
> > openat_file(int dirfd, const char *name, int flags, mode_t mode);
> > +DIR *opendir_win32(const char *full_file_name); int
> > +closedir_win32(DIR *pDir); struct dirent *readdir_win32(DIR *pDir);
> > +void rewinddir_win32(DIR *pDir); void seekdir_win32(DIR *pDir, long
> > +pos); long telldir_win32(DIR *pDir);
> >  #endif
> >
> >  static inline void close_preserve_errno(int fd) diff --git
> > a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c index
> > a99d579a06..e9408f3c45 100644
> > --- a/hw/9pfs/9p-util-win32.c
> > +++ b/hw/9pfs/9p-util-win32.c
> > @@ -37,6 +37,16 @@
> >   *Windows does not support opendir, the directory fd is created by
> >   *CreateFile and convert to fd by _open_osfhandle(). Keep the fd open
> will
> >   *lock and protect the directory (can not be modified or replaced)
> > + *
> > + * 5. Neither Windows native APIs, nor MinGW provide a POSIX compatible
> API for
> > + *acquiring directory entries in a safe way. Calling those APIs
> (native
> > + *_findfirst() and _findnext() or MinGW's readdir(), seekdir() and
> > + *telldir()) directly can lead to an inconsistent state if directory
> is
> > + *modified in between, e.g. the same directory appearing more than
> once
> > + *in output, or directories not appearing at all in output even though
> they
> > + *were neither newly created nor deleted. POSIX does not define what
> happens
> > + *with deleted or newly created directories in between, but it
> guarantees a
> > + *consistent state.
> >   */
> >
> >  #include "qemu/osdep.h"
> > @@ -51,6 +61,25 @@
> >
> >  #define V9FS_MAGIC  0x53465039  /* string "9PFS" */
> >
> > +/*
> > + * MinGW and Windows does not provide a safe way to seek directory
> > +while other
> > + * thread is modifying the same directory.
> > + *
> > + * This structure is used to store sorted file id and ensure
> > +directory seek
> > + * consistency.
> > + */
> > +struct dir_win32 {
> > +struct dirent dd_dir;
> > +uint32_t offset;
> > +uint32_t total_entries;
> > +HANDLE hDir;
> > +uint32_t dir_name_len;
> > +uint64_t dot_id;
> > +uint64_t dot_dot_id;
> > +uint64_t *file_id_list;
> > +char dd_name[1];
> > +};
> > +
> >  /*
> >   * win32_error_to_posix - convert Win32 error to POSIX error number
> >   *
> > @@ -977,3 +1006,417 @@ int qemu_mknodat(int dirfd, const char *filename,
> mode_t mode, dev_t dev)
> >  errno = ENOTSUP;
> >  return -1;
> >  }
> > +
> > +static int file_id_compare(const void *id_ptr1, const void *id_ptr2)
> > +{
> > +uint64_t id[2];
> > +
> > +id[0] = *(uint64_t *)id_ptr1;
> > +id[1] = *(uint64_t *)id_ptr2;
> > +
> > +if (id[0] > id[1]) {
> > +return 1;
> > +} else if (id[0] < id[1]) {
> > +return -1;

Re: [PATCH v5 04/16] hw/9pfs: Implement Windows specific xxxdir() APIs

2023-03-14 Thread Christian Schoenebeck
On Monday, February 20, 2023 11:08:03 AM CET Bin Meng wrote:
> From: Guohuai Shi 
> 
> This commit implements Windows specific xxxdir() APIs for safety
> directory access.

That comment is seriously too short for this patch.

1. You should describe the behaviour implementation that you have chosen and
why you have chosen it.

2. Like already said in the previous version of the patch, you should place a
link to the discussion we had on this issue.

> Signed-off-by: Guohuai Shi 
> Signed-off-by: Bin Meng 
> ---
> 
>  hw/9pfs/9p-util.h   |   6 +
>  hw/9pfs/9p-util-win32.c | 443 
>  2 files changed, 449 insertions(+)
> 
> diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> index 0f159fb4ce..c1c251fbd1 100644
> --- a/hw/9pfs/9p-util.h
> +++ b/hw/9pfs/9p-util.h
> @@ -141,6 +141,12 @@ int unlinkat_win32(int dirfd, const char *pathname, int 
> flags);
>  int statfs_win32(const char *root_path, struct statfs *stbuf);
>  int openat_dir(int dirfd, const char *name);
>  int openat_file(int dirfd, const char *name, int flags, mode_t mode);
> +DIR *opendir_win32(const char *full_file_name);
> +int closedir_win32(DIR *pDir);
> +struct dirent *readdir_win32(DIR *pDir);
> +void rewinddir_win32(DIR *pDir);
> +void seekdir_win32(DIR *pDir, long pos);
> +long telldir_win32(DIR *pDir);
>  #endif
>  
>  static inline void close_preserve_errno(int fd)
> diff --git a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c
> index a99d579a06..e9408f3c45 100644
> --- a/hw/9pfs/9p-util-win32.c
> +++ b/hw/9pfs/9p-util-win32.c
> @@ -37,6 +37,16 @@
>   *Windows does not support opendir, the directory fd is created by
>   *CreateFile and convert to fd by _open_osfhandle(). Keep the fd open 
> will
>   *lock and protect the directory (can not be modified or replaced)
> + *
> + * 5. Neither Windows native APIs, nor MinGW provide a POSIX compatible API 
> for
> + *acquiring directory entries in a safe way. Calling those APIs (native
> + *_findfirst() and _findnext() or MinGW's readdir(), seekdir() and
> + *telldir()) directly can lead to an inconsistent state if directory is
> + *modified in between, e.g. the same directory appearing more than once
> + *in output, or directories not appearing at all in output even though 
> they
> + *were neither newly created nor deleted. POSIX does not define what 
> happens
> + *with deleted or newly created directories in between, but it 
> guarantees a
> + *consistent state.
>   */
>  
>  #include "qemu/osdep.h"
> @@ -51,6 +61,25 @@
>  
>  #define V9FS_MAGIC  0x53465039  /* string "9PFS" */
>  
> +/*
> + * MinGW and Windows does not provide a safe way to seek directory while 
> other
> + * thread is modifying the same directory.
> + *
> + * This structure is used to store sorted file id and ensure directory seek
> + * consistency.
> + */
> +struct dir_win32 {
> +struct dirent dd_dir;
> +uint32_t offset;
> +uint32_t total_entries;
> +HANDLE hDir;
> +uint32_t dir_name_len;
> +uint64_t dot_id;
> +uint64_t dot_dot_id;
> +uint64_t *file_id_list;
> +char dd_name[1];
> +};
> +
>  /*
>   * win32_error_to_posix - convert Win32 error to POSIX error number
>   *
> @@ -977,3 +1006,417 @@ int qemu_mknodat(int dirfd, const char *filename, 
> mode_t mode, dev_t dev)
>  errno = ENOTSUP;
>  return -1;
>  }
> +
> +static int file_id_compare(const void *id_ptr1, const void *id_ptr2)
> +{
> +uint64_t id[2];
> +
> +id[0] = *(uint64_t *)id_ptr1;
> +id[1] = *(uint64_t *)id_ptr2;
> +
> +if (id[0] > id[1]) {
> +return 1;
> +} else if (id[0] < id[1]) {
> +return -1;
> +} else {
> +return 0;
> +}
> +}
> +
> +static int get_next_entry(struct dir_win32 *stream)
> +{
> +HANDLE hDirEntry = INVALID_HANDLE_VALUE;
> +char *entry_name;
> +char *entry_start;
> +FILE_ID_DESCRIPTOR fid;
> +DWORD attribute;
> +
> +if (stream->file_id_list[stream->offset] == stream->dot_id) {
> +strcpy(stream->dd_dir.d_name, ".");
> +return 0;
> +}
> +
> +if (stream->file_id_list[stream->offset] == stream->dot_dot_id) {
> +strcpy(stream->dd_dir.d_name, "..");
> +return 0;
> +}
> +
> +fid.dwSize = sizeof(fid);
> +fid.Type = FileIdType;
> +
> +fid.FileId.QuadPart = stream->file_id_list[stream->offset];
> +
> +hDirEntry = OpenFileById(stream->hDir, &fid, GENERIC_READ,
> + FILE_SHARE_READ | FILE_SHARE_WRITE
> + | FILE_SHARE_DELETE,
> + NULL,
> + FILE_FLAG_BACKUP_SEMANTICS
> + | FILE_FLAG_OPEN_REPARSE_POINT);

What's the purpose of FILE_FLAG_OPEN_REPARSE_POINT here? As it's apparently
not obvious, please add a comment.

> +
> +if (hDirEntry == INVALID_HANDLE_VALUE) {
> +/*
> + * Not open it successfully, it may be deleted.

Wrong English. "Open fa