diff mbox

[5/8] hw/9pfs: Abstract open state of fid to V9fsFidOpenState

Message ID 1319127460-5181-6-git-send-email-aneesh.kumar@linux.vnet.ibm.com
State New
Headers show

Commit Message

Aneesh Kumar K.V Oct. 20, 2011, 4:17 p.m. UTC
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>

To implement synthetic file system in Qemu we may not really
require file descriptor and Dir *. Make generic code use
V9fsFidOpenState instead.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 fsdev/file-op-9p.h         |   32 ++++++++------
 hw/9pfs/codir.c            |   16 ++++----
 hw/9pfs/cofile.c           |   37 +++++++---------
 hw/9pfs/virtio-9p-coth.h   |    6 +-
 hw/9pfs/virtio-9p-handle.c |   96 ++++++++++++++++++++++++------------------
 hw/9pfs/virtio-9p-local.c  |  100 ++++++++++++++++++++++++++------------------
 hw/9pfs/virtio-9p.c        |   12 +++---
 hw/9pfs/virtio-9p.h        |   21 +++++----
 8 files changed, 179 insertions(+), 141 deletions(-)
diff mbox

Patch

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 5788ff91..1928da2 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -78,6 +78,8 @@  typedef struct V9fsPath {
     char *data;
 } V9fsPath;
 
+typedef union V9fsFidOpenState V9fsFidOpenState;
+
 void cred_init(FsCred *);
 
 typedef struct FileOperations
@@ -94,22 +96,26 @@  typedef struct FileOperations
                    const char *, FsCred *);
     int (*link)(FsContext *, V9fsPath *, V9fsPath *, const char *);
     int (*setuid)(FsContext *, uid_t);
-    int (*close)(FsContext *, int);
-    int (*closedir)(FsContext *, DIR *);
-    DIR *(*opendir)(FsContext *, V9fsPath *);
-    int (*open)(FsContext *, V9fsPath *, int);
-    int (*open2)(FsContext *, V9fsPath *, const char *, int, FsCred *);
-    void (*rewinddir)(FsContext *, DIR *);
-    off_t (*telldir)(FsContext *, DIR *);
-    int (*readdir_r)(FsContext *, DIR *, struct dirent *, struct dirent **);
-    void (*seekdir)(FsContext *, DIR *, off_t);
-    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
-    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
+    int (*close)(FsContext *, V9fsFidOpenState *);
+    int (*closedir)(FsContext *, V9fsFidOpenState *);
+    int (*opendir)(FsContext *, V9fsPath *, V9fsFidOpenState *);
+    int (*open)(FsContext *, V9fsPath *, int, V9fsFidOpenState *);
+    int (*open2)(FsContext *, V9fsPath *, const char *,
+                 int, FsCred *, V9fsFidOpenState *);
+    void (*rewinddir)(FsContext *, V9fsFidOpenState *);
+    off_t (*telldir)(FsContext *, V9fsFidOpenState *);
+    int (*readdir_r)(FsContext *, V9fsFidOpenState *,
+                     struct dirent *, struct dirent **);
+    void (*seekdir)(FsContext *, V9fsFidOpenState *, off_t);
+    ssize_t (*preadv)(FsContext *, V9fsFidOpenState *,
+                      const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, V9fsFidOpenState *,
+                       const struct iovec *, int, off_t);
     int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
-    int (*fstat)(FsContext *, int, struct stat *);
+    int (*fstat)(FsContext *, V9fsFidOpenState *, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
     int (*truncate)(FsContext *, V9fsPath *, off_t);
-    int (*fsync)(FsContext *, int, int);
+    int (*fsync)(FsContext *, V9fsFidOpenState *, int);
     int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
     ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
                          const char *, void *, size_t);
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 72732e7..9b6d47d 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -29,7 +29,7 @@  int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
     v9fs_co_run_in_worker(
         {
             errno = 0;
-            err = s->ops->readdir_r(&s->ctx, fidp->fs.dir, dent, result);
+            err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result);
             if (!*result && errno) {
                 err = -errno;
             } else {
@@ -49,7 +49,7 @@  off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->telldir(&s->ctx, fidp->fs.dir);
+            err = s->ops->telldir(&s->ctx, &fidp->fs);
             if (err < 0) {
                 err = -errno;
             }
@@ -65,7 +65,7 @@  void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
     }
     v9fs_co_run_in_worker(
         {
-            s->ops->seekdir(&s->ctx, fidp->fs.dir, offset);
+            s->ops->seekdir(&s->ctx, &fidp->fs, offset);
         });
 }
 
@@ -77,7 +77,7 @@  void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
     }
     v9fs_co_run_in_worker(
         {
-            s->ops->rewinddir(&s->ctx, fidp->fs.dir);
+            s->ops->rewinddir(&s->ctx, &fidp->fs);
         });
 }
 
@@ -129,8 +129,8 @@  int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
-            if (!fidp->fs.dir) {
+            err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
+            if (err < 0) {
                 err = -errno;
             } else {
                 err = 0;
@@ -146,7 +146,7 @@  int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
     return err;
 }
 
-int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
+int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
 {
     int err;
     V9fsState *s = pdu->s;
@@ -156,7 +156,7 @@  int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->closedir(&s->ctx, dir);
+            err = s->ops->closedir(&s->ctx, fs);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 692811e..586b038 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -61,7 +61,7 @@  int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
     return err;
 }
 
-int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
+int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
 {
     int err;
     V9fsState *s = pdu->s;
@@ -71,7 +71,7 @@  int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->fstat(&s->ctx, fd, stbuf);
+            err = s->ops->fstat(&s->ctx, &fidp->fs, stbuf);
             if (err < 0) {
                 err = -errno;
             }
@@ -90,8 +90,8 @@  int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
-            if (fidp->fs.fd == -1) {
+            err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
+            if (err == -1) {
                 err = -errno;
             } else {
                 err = 0;
@@ -130,9 +130,9 @@  int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
-                                        name->data, flags, &cred);
-            if (fidp->fs.fd == -1) {
+            err = s->ops->open2(&s->ctx, &fidp->path,
+                                name->data, flags, &cred, &fidp->fs);
+            if (err < 0) {
                 err = -errno;
             } else {
                 v9fs_path_init(&path);
@@ -141,12 +141,12 @@  int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
                     err = s->ops->lstat(&s->ctx, &path, stbuf);
                     if (err < 0) {
                         err = -errno;
-                        s->ops->close(&s->ctx, fidp->fs.fd);
+                        s->ops->close(&s->ctx, &fidp->fs);
                     } else {
                         v9fs_path_copy(&fidp->path, &path);
                     }
                 } else {
-                    s->ops->close(&s->ctx, fidp->fs.fd);
+                    s->ops->close(&s->ctx, &fidp->fs);
                 }
                 v9fs_path_free(&path);
             }
@@ -161,7 +161,7 @@  int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
     return err;
 }
 
-int v9fs_co_close(V9fsPDU *pdu, int fd)
+int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
 {
     int err;
     V9fsState *s = pdu->s;
@@ -171,7 +171,7 @@  int v9fs_co_close(V9fsPDU *pdu, int fd)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->close(&s->ctx, fd);
+            err = s->ops->close(&s->ctx, fs);
             if (err < 0) {
                 err = -errno;
             }
@@ -184,16 +184,15 @@  int v9fs_co_close(V9fsPDU *pdu, int fd)
 
 int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
 {
-    int fd, err;
+    int err;
     V9fsState *s = pdu->s;
 
     if (v9fs_request_cancelled(pdu)) {
         return -EINTR;
     }
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
-            err = s->ops->fsync(&s->ctx, fd, datasync);
+            err = s->ops->fsync(&s->ctx, &fidp->fs, datasync);
             if (err < 0) {
                 err = -errno;
             }
@@ -226,16 +225,15 @@  int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
 int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
                     struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd, err;
+    int err;
     V9fsState *s = pdu->s;
 
     if (v9fs_request_cancelled(pdu)) {
         return -EINTR;
     }
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
-            err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
+            err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
             if (err < 0) {
                 err = -errno;
             }
@@ -246,16 +244,15 @@  int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
 int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
                    struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd, err;
+    int err;
     V9fsState *s = pdu->s;
 
     if (v9fs_request_cancelled(pdu)) {
         return -EINTR;
     }
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
-            err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
+            err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index ca96b9c..c4b74b0 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -80,7 +80,7 @@  extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *);
 extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags);
 extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *,
                             V9fsPath *, V9fsString *);
-extern int v9fs_co_fstat(V9fsPDU *, int, struct stat *);
+extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *);
 extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *);
 extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
 extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
@@ -88,8 +88,8 @@  extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
 extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
                              void *, size_t, int);
 extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *);
-extern int v9fs_co_closedir(V9fsPDU *, DIR *);
-extern int v9fs_co_close(V9fsPDU *, int);
+extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *);
+extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *);
 extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int);
 extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
                            const char *, gid_t, struct stat *);
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 98809f1..c38e0e7 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -133,81 +133,91 @@  static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     return ret;
 }
 
-static int handle_close(FsContext *ctx, int fd)
+static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return close(fd);
+    return close(fs->fd);
 }
 
-static int handle_closedir(FsContext *ctx, DIR *dir)
+static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return closedir(dir);
+    return closedir(fs->dir);
 }
 
-static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+static int handle_open(FsContext *ctx, V9fsPath *fs_path,
+                       int flags, V9fsFidOpenState *fs)
 {
     struct handle_data *data = (struct handle_data *)ctx->private;
 
-    return open_by_handle(data->mountfd, fs_path->data, flags);
+    fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
+    return fs->fd;
 }
 
-static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path)
+static int handle_opendir(FsContext *ctx,
+                          V9fsPath *fs_path, V9fsFidOpenState *fs)
 {
-    int fd;
-    fd = handle_open(ctx, fs_path, O_DIRECTORY);
-    if (fd < 0) {
-        return NULL;
+    int ret;
+    ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
+    if (ret < 0) {
+        return -1;
     }
-    return fdopendir(fd);
+    fs->dir = fdopendir(ret);
+    if (!fs->dir) {
+        return -1;
+    }
+    return 0;
 }
 
-static void handle_rewinddir(FsContext *ctx, DIR *dir)
+static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return rewinddir(dir);
+    return rewinddir(fs->dir);
 }
 
-static off_t handle_telldir(FsContext *ctx, DIR *dir)
+static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return telldir(dir);
+    return telldir(fs->dir);
 }
 
-static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                            struct dirent *entry,
                             struct dirent **result)
 {
-    return readdir_r(dir, entry, result);
+    return readdir_r(fs->dir, entry, result);
 }
 
-static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off)
+static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 {
-    return seekdir(dir, off);
+    return seekdir(fs->dir, off);
 }
 
-static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                             const struct iovec *iov,
                              int iovcnt, off_t offset)
 {
 #ifdef CONFIG_PREADV
-    return preadv(fd, iov, iovcnt, offset);
+    return preadv(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        return readv(fd, iov, iovcnt);
+        return readv(fs->fd, iov, iovcnt);
     }
 #endif
 }
 
-static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                              const struct iovec *iov,
                               int iovcnt, off_t offset)
 {
     ssize_t ret;
 #ifdef CONFIG_PREADV
-    ret = pwritev(fd, iov, iovcnt, offset);
+    ret = pwritev(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        ret = writev(fd, iov, iovcnt);
+        ret = writev(fs->fd, iov, iovcnt);
     }
 #endif
 #ifdef CONFIG_SYNC_FILE_RANGE
@@ -217,7 +227,7 @@  static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
          * We want to ensure that we don't leave dirty pages in the cache
          * after write when writeout=immediate is sepcified.
          */
-        sync_file_range(fd, offset, ret,
+        sync_file_range(fs->fd, offset, ret,
                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
     }
 #endif
@@ -274,13 +284,14 @@  static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
     return ret;
 }
 
-static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs,
+                        struct stat *stbuf)
 {
-    return fstat(fd, stbuf);
+    return fstat(fs->fd, stbuf);
 }
 
 static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
-                       int flags, FsCred *credp)
+                        int flags, FsCred *credp, V9fsFidOpenState *fs)
 {
     int ret;
     int dirfd, fd;
@@ -296,6 +307,8 @@  static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         if (ret < 0) {
             close(fd);
             fd = ret;
+        } else {
+            fs->fd = fd;
         }
     }
     close(dirfd);
@@ -411,12 +424,12 @@  static int handle_remove(FsContext *ctx, const char *path)
     return -1;
 }
 
-static int handle_fsync(FsContext *ctx, int fd, int datasync)
+static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
 {
     if (datasync) {
-        return qemu_fdatasync(fd);
+        return qemu_fdatasync(fs->fd);
     } else {
-        return fsync(fd);
+        return fsync(fs->fd);
     }
 }
 
@@ -575,7 +588,8 @@  static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
 static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
                                  mode_t st_mode, uint64_t *st_gen)
 {
-    int err, fd;
+    int err;
+    V9fsFidOpenState fid_open;
 
     /*
      * Do not try to open special files like device nodes, fifos etc
@@ -584,12 +598,12 @@  static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
             return 0;
     }
-    fd = handle_open(ctx, path, O_RDONLY);
-    if (fd < 0) {
-        return fd;
+    err = handle_open(ctx, path, O_RDONLY, &fid_open);
+    if (err < 0) {
+        return err;
     }
-    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
-    handle_close(ctx, fd);
+    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+    handle_close(ctx, &fid_open);
     return err;
 }
 
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index b611681..782dc0a 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -156,81 +156,91 @@  static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     return tsize;
 }
 
-static int local_close(FsContext *ctx, int fd)
+static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return close(fd);
+    return close(fs->fd);
 }
 
-static int local_closedir(FsContext *ctx, DIR *dir)
+static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return closedir(dir);
+    return closedir(fs->dir);
 }
 
-static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+static int local_open(FsContext *ctx, V9fsPath *fs_path,
+                      int flags, V9fsFidOpenState *fs)
 {
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    return open(rpath(ctx, path, buffer), flags);
+    fs->fd = open(rpath(ctx, path, buffer), flags);
+    return fs->fd;
 }
 
-static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path)
+static int local_opendir(FsContext *ctx,
+                         V9fsPath *fs_path, V9fsFidOpenState *fs)
 {
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    return opendir(rpath(ctx, path, buffer));
+    fs->dir = opendir(rpath(ctx, path, buffer));
+    if (!fs->dir) {
+        return -1;
+    }
+    return 0;
 }
 
-static void local_rewinddir(FsContext *ctx, DIR *dir)
+static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return rewinddir(dir);
+    return rewinddir(fs->dir);
 }
 
-static off_t local_telldir(FsContext *ctx, DIR *dir)
+static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return telldir(dir);
+    return telldir(fs->dir);
 }
 
-static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                           struct dirent *entry,
                            struct dirent **result)
 {
-    return readdir_r(dir, entry, result);
+    return readdir_r(fs->dir, entry, result);
 }
 
-static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
+static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 {
-    return seekdir(dir, off);
+    return seekdir(fs->dir, off);
 }
 
-static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                            const struct iovec *iov,
                             int iovcnt, off_t offset)
 {
 #ifdef CONFIG_PREADV
-    return preadv(fd, iov, iovcnt, offset);
+    return preadv(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        return readv(fd, iov, iovcnt);
+        return readv(fs->fd, iov, iovcnt);
     }
 #endif
 }
 
-static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                             const struct iovec *iov,
                              int iovcnt, off_t offset)
 {
     ssize_t ret
 ;
 #ifdef CONFIG_PREADV
-    ret = pwritev(fd, iov, iovcnt, offset);
+    ret = pwritev(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        ret = writev(fd, iov, iovcnt);
+        ret = writev(fs->fd, iov, iovcnt);
     }
 #endif
 #ifdef CONFIG_SYNC_FILE_RANGE
@@ -240,7 +250,7 @@  static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
          * We want to ensure that we don't leave dirty pages in the cache
          * after write when writeout=immediate is sepcified.
          */
-        sync_file_range(fd, offset, ret,
+        sync_file_range(fs->fd, offset, ret,
                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
     }
 #endif
@@ -356,10 +366,11 @@  out:
     return err;
 }
 
-static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+static int local_fstat(FsContext *fs_ctx,
+                       V9fsFidOpenState *fs, struct stat *stbuf)
 {
     int err;
-    err = fstat(fd, stbuf);
+    err = fstat(fs->fd, stbuf);
     if (err) {
         return err;
     }
@@ -370,16 +381,20 @@  static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
         mode_t tmp_mode;
         dev_t tmp_dev;
 
-        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.uid",
+                      &tmp_uid, sizeof(uid_t)) > 0) {
             stbuf->st_uid = tmp_uid;
         }
-        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.gid",
+                      &tmp_gid, sizeof(gid_t)) > 0) {
             stbuf->st_gid = tmp_gid;
         }
-        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.mode",
+                      &tmp_mode, sizeof(mode_t)) > 0) {
             stbuf->st_mode = tmp_mode;
         }
-        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.rdev",
+                      &tmp_dev, sizeof(dev_t)) > 0) {
                 stbuf->st_rdev = tmp_dev;
         }
     }
@@ -387,7 +402,7 @@  static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
 }
 
 static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
-                       int flags, FsCred *credp)
+                       int flags, FsCred *credp, V9fsFidOpenState *fs)
 {
     char *path;
     int fd = -1;
@@ -428,6 +443,7 @@  static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         }
     }
     err = fd;
+    fs->fd = fd;
     goto out;
 
 err_end:
@@ -577,12 +593,12 @@  static int local_remove(FsContext *ctx, const char *path)
     return remove(rpath(ctx, path, buffer));
 }
 
-static int local_fsync(FsContext *ctx, int fd, int datasync)
+static int local_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
 {
     if (datasync) {
-        return qemu_fdatasync(fd);
+        return qemu_fdatasync(fs->fd);
     } else {
-        return fsync(fd);
+        return fsync(fs->fd);
     }
 }
 
@@ -677,7 +693,9 @@  static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
 static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
                                 mode_t st_mode, uint64_t *st_gen)
 {
-    int err, fd;
+    int err;
+    V9fsFidOpenState fid_open;
+
     /*
      * Do not try to open special files like device nodes, fifos etc
      * We can get fd for regular files and directories only
@@ -685,12 +703,12 @@  static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
             return 0;
     }
-    fd = local_open(ctx, path, O_RDONLY);
-    if (fd < 0) {
-        return fd;
+    err = local_open(ctx, path, O_RDONLY, &fid_open);
+    if (err < 0) {
+        return err;
     }
-    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
-    local_close(ctx, fd);
+    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+    local_close(ctx, &fid_open);
     return err;
 }
 
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index edb160a..d3dc9a1 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -455,11 +455,11 @@  static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
     if (fidp->fid_type == P9_FID_FILE) {
         /* If we reclaimed the fd no need to close */
         if (fidp->fs.fd != -1) {
-            retval = v9fs_co_close(pdu, fidp->fs.fd);
+            retval = v9fs_co_close(pdu, &fidp->fs);
         }
     } else if (fidp->fid_type == P9_FID_DIR) {
         if (fidp->fs.dir != NULL) {
-            retval = v9fs_co_closedir(pdu, fidp->fs.dir);
+            retval = v9fs_co_closedir(pdu, &fidp->fs);
         }
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(pdu, fidp);
@@ -567,9 +567,9 @@  void v9fs_reclaim_fd(V9fsPDU *pdu)
         f = reclaim_list;
         reclaim_list = f->rclm_lst;
         if (f->fid_type == P9_FID_FILE) {
-            v9fs_co_close(pdu, f->fs_reclaim.fd);
+            v9fs_co_close(pdu, &f->fs_reclaim);
         } else if (f->fid_type == P9_FID_DIR) {
-            v9fs_co_closedir(pdu, f->fs_reclaim.dir);
+            v9fs_co_closedir(pdu, &f->fs_reclaim);
         }
         f->rclm_lst = NULL;
         /*
@@ -3010,7 +3010,7 @@  static void v9fs_lock(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -3053,7 +3053,7 @@  static void v9fs_getlock(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp, &stbuf);
     if (err < 0) {
         goto out;
     }
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 802f580..6273b85 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -204,20 +204,23 @@  typedef struct V9fsXattr
     int flags;
 } V9fsXattr;
 
+/*
+ * Filled by fs driver on open and other
+ * calls.
+ */
+union V9fsFidOpenState {
+    int fd;
+    DIR *dir;
+    V9fsXattr xattr;
+};
+
 struct V9fsFidState
 {
     int fid_type;
     int32_t fid;
     V9fsPath path;
-    union {
-        int fd;
-        DIR *dir;
-        V9fsXattr xattr;
-    } fs;
-    union {
-        int fd;
-        DIR *dir;
-    } fs_reclaim;
+    V9fsFidOpenState fs;
+    V9fsFidOpenState fs_reclaim;
     int flags;
     int open_flags;
     uid_t uid;