All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Implement file handle based fs driver
@ 2011-09-09 10:54 Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 1/8] hw/9pfs: Make v9fs_string* functions non-static Aneesh Kumar K.V
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori

This patchset implement a file handle based fs driver for VirtFS server
Using file handle instead of names, simplify the rename handling in the
server. The changes also enable us to handle renames on the host. Since
we are not using pathnames, symlink related security issues are not
present with handle based fs driver.

-aneesh

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 1/8] hw/9pfs: Make v9fs_string* functions non-static
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 2/8] hw/9pfs: Use read-write lock for protecting fid path Aneesh Kumar K.V
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

We will use them later in other files

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 hw/9pfs/virtio-9p.c |   10 +++++-----
 hw/9pfs/virtio-9p.h |    5 +++++
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index d28edb7..dc3e32b 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -80,20 +80,20 @@ void cred_init(FsCred *credp)
     credp->fc_rdev = -1;
 }
 
-static void v9fs_string_init(V9fsString *str)
+void v9fs_string_init(V9fsString *str)
 {
     str->data = NULL;
     str->size = 0;
 }
 
-static void v9fs_string_free(V9fsString *str)
+void v9fs_string_free(V9fsString *str)
 {
     g_free(str->data);
     str->data = NULL;
     str->size = 0;
 }
 
-static void v9fs_string_null(V9fsString *str)
+void v9fs_string_null(V9fsString *str)
 {
     v9fs_string_free(str);
 }
@@ -192,7 +192,7 @@ alloc_print:
     return vsprintf(*strp, fmt, ap);
 }
 
-static void GCC_FMT_ATTR(2, 3)
+void GCC_FMT_ATTR(2, 3)
 v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
 {
     va_list ap;
@@ -208,7 +208,7 @@ v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
     str->size = err;
 }
 
-static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
 {
     v9fs_string_free(lhs);
     v9fs_string_sprintf(lhs, "%s", rhs->data);
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 17d44b4..8aeee4e 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -384,4 +384,9 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
 extern void virtio_9p_set_fd_limit(void);
 extern void v9fs_reclaim_fd(V9fsState *s);
+extern void v9fs_string_init(V9fsString *str);
+extern void v9fs_string_free(V9fsString *str);
+extern void v9fs_string_null(V9fsString *str);
+extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
+extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 2/8] hw/9pfs: Use read-write lock for protecting fid path.
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 1/8] hw/9pfs: Make v9fs_string* functions non-static Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 3/8] hw/9pfs: Move fid pathname tracking to seperate data type Aneesh Kumar K.V
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

On rename we take the write lock and this ensure path
doesn't change as we operate on them.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 hw/9pfs/codir.c            |   18 ++++++-
 hw/9pfs/cofile.c           |   32 +++++++++++--
 hw/9pfs/cofs.c             |   52 ++++++++++++++++++---
 hw/9pfs/coxattr.c          |    8 +++
 hw/9pfs/virtio-9p-coth.h   |   14 +++--
 hw/9pfs/virtio-9p-device.c |    1 +
 hw/9pfs/virtio-9p.c        |  110 +++++++++++++++++---------------------------
 hw/9pfs/virtio-9p.h        |    7 +++
 8 files changed, 155 insertions(+), 87 deletions(-)

diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index f17f927..c9a88ec 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -65,22 +65,34 @@ void v9fs_co_rewinddir(V9fsState *s, V9fsFidState *fidp)
         });
 }
 
-int v9fs_co_mkdir(V9fsState *s, char *name, mode_t mode, uid_t uid, gid_t gid)
+int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
+                  mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_mode = mode;
     cred.fc_uid = uid;
     cred.fc_gid = gid;
+    v9fs_string_init(&fullname);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mkdir(&s->ctx, name, &cred);
+            err = s->ops->mkdir(&s->ctx, fullname.data, &cred);
             if (err < 0) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -88,6 +100,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data);
@@ -97,6 +110,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
                 err = 0;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 0caf1e3..cc62846 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -21,6 +21,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lstat(&s->ctx, path->data, stbuf);
@@ -28,6 +29,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -49,6 +51,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags);
@@ -58,6 +61,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
                 err = 0;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
@@ -67,30 +71,48 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
     return err;
 }
 
-int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, char *fullname, gid_t gid,
-                  int flags, int mode)
+int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
+                  int flags, int mode, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_mode = mode & 07777;
     cred.fc_uid = fidp->uid;
     cred.fc_gid = gid;
+    v9fs_string_init(&fullname);
+    /*
+     * Hold the directory fid lock so that directory path name
+     * don't change. Read lock is fine because this fid cannot
+     * be used by any other operation.
+     */
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open2(&s->ctx, fullname, flags, &cred);
-            err = 0;
+            fidp->fs.fd = s->ops->open2(&s->ctx, fullname.data, flags, &cred);
             if (fidp->fs.fd == -1) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                    err = s->ops->close(&s->ctx, fidp->fs.fd);
+                } else {
+                    v9fs_string_copy(&fidp->path, &fullname);
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
             v9fs_reclaim_fd(s);
         }
     }
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -131,6 +153,7 @@ int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->link(&s->ctx, oldpath->data, newpath->data);
@@ -138,6 +161,7 @@ int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index a78fccb..98860f9 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -23,6 +23,8 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
     ssize_t len;
 
     buf->data = g_malloc(PATH_MAX);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+
     v9fs_co_run_in_worker(
         {
             len = s->ops->readlink(&s->ctx, path->data,
@@ -35,6 +37,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (err) {
         g_free(buf->data);
         buf->data = NULL;
@@ -47,6 +50,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->statfs(&s->ctx, path->data, stbuf);
@@ -54,6 +58,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -64,6 +69,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
 
     cred_init(&cred);
     cred.fc_mode = mode;
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chmod(&s->ctx, path->data, &cred);
@@ -71,6 +77,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -79,6 +86,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->utimensat(&s->ctx, path->data, times);
@@ -86,6 +94,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -97,6 +106,7 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     cred_init(&cred);
     cred.fc_uid = uid;
     cred.fc_gid = gid;
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chown(&s->ctx, path->data, &cred);
@@ -104,6 +114,7 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -111,6 +122,7 @@ int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->truncate(&s->ctx, path->data, size);
@@ -118,27 +130,39 @@ int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
-int v9fs_co_mknod(V9fsState *s, V9fsString *path, uid_t uid,
-                  gid_t gid, dev_t dev, mode_t mode)
+int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
+                  gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_uid  = uid;
     cred.fc_gid  = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
+    v9fs_string_init(&fullname);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mknod(&s->ctx, path->data, &cred);
+            err = s->ops->mknod(&s->ctx, fullname.data, &cred);
             if (err < 0) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -146,6 +170,7 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->remove(&s->ctx, path->data);
@@ -153,6 +178,7 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -170,22 +196,34 @@ int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
     return err;
 }
 
-int v9fs_co_symlink(V9fsState *s, V9fsFidState *fidp,
-                    const char *oldpath, const char *newpath, gid_t gid)
+int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
+                    const char *oldpath, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
+
 
     cred_init(&cred);
-    cred.fc_uid = fidp->uid;
+    cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
     cred.fc_mode = 0777;
+    v9fs_string_init(&fullname);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
+            err = s->ops->symlink(&s->ctx, oldpath, fullname.data, &cred);
             if (err < 0) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_string_free(&fullname);
     return err;
 }
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index a289389..7b93c8f 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -21,6 +21,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->llistxattr(&s->ctx, path->data, value, size);
@@ -28,6 +29,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -37,6 +39,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lgetxattr(&s->ctx, path->data,
@@ -46,6 +49,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -55,6 +59,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lsetxattr(&s->ctx, path->data,
@@ -64,6 +69,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -72,6 +78,7 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lremovexattr(&s->ctx, path->data,
@@ -80,5 +87,6 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index b7be9b5..e5f46c5 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -71,23 +71,25 @@ extern int v9fs_co_truncate(V9fsState *, V9fsString *, off_t);
 extern int v9fs_co_llistxattr(V9fsState *, V9fsString *, void *, size_t);
 extern int v9fs_co_lgetxattr(V9fsState *, V9fsString *,
                              V9fsString *, void *, size_t);
-extern int v9fs_co_mknod(V9fsState *, V9fsString *, uid_t,
-                         gid_t, dev_t, mode_t);
-extern int v9fs_co_mkdir(V9fsState *, char *, mode_t, uid_t, gid_t);
+extern int v9fs_co_mknod(V9fsState *, V9fsFidState *, V9fsString *, uid_t,
+                         gid_t, dev_t, mode_t, struct stat *);
+extern int v9fs_co_mkdir(V9fsState *, V9fsFidState *, V9fsString *,
+                         mode_t, uid_t, gid_t, struct stat *);
 extern int v9fs_co_remove(V9fsState *, V9fsString *);
 extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *);
 extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
 extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
 extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_open2(V9fsState *, V9fsFidState *, char *, gid_t, int, int);
+extern int v9fs_co_open2(V9fsState *, V9fsFidState *, V9fsString *,
+                         gid_t, int, int, struct stat *);
 extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
                              void *, size_t, int);
 extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
 extern int v9fs_co_closedir(V9fsState *, DIR *);
 extern int v9fs_co_close(V9fsState *, int);
 extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, const char *,
-                           const char *, gid_t);
+extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, V9fsString *,
+                           const char *, gid_t, struct stat *);
 extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *);
 extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
                            struct iovec *, int, int64_t);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 97f2da5..eea70cb 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -131,6 +131,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
                         s->tag_len;
     s->vdev.get_config = virtio_9p_get_config;
     s->fid_list = NULL;
+    qemu_co_rwlock_init(&s->rename_lock);
 
     if (v9fs_init_worker_threads() < 0) {
         fprintf(stderr, "worker thread initialization failed\n");
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index dc3e32b..356bb3b 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -1582,7 +1582,6 @@ static void v9fs_lcreate(void *opaque)
     gid_t gid;
     ssize_t err = 0;
     ssize_t offset = 7;
-    V9fsString fullname;
     V9fsString name;
     V9fsFidState *fidp;
     struct stat stbuf;
@@ -1590,7 +1589,6 @@ static void v9fs_lcreate(void *opaque)
     int32_t iounit;
     V9fsPDU *pdu = opaque;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
                   &mode, &gid);
 
@@ -1599,12 +1597,12 @@ static void v9fs_lcreate(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
 
     /* Ignore direct disk access hint until the server supports it. */
     flags &= ~O_DIRECT;
 
-    err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
+    err = v9fs_co_open2(pdu->s, fidp, &name, gid,
+                        flags | O_CREAT, mode, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -1617,17 +1615,7 @@ static void v9fs_lcreate(void *opaque)
          */
         fidp->flags |= FID_NON_RECLAIMABLE;
     }
-    iounit =  get_iounit(pdu->s, &fullname);
-
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
-    if (err < 0) {
-        fidp->fid_type = P9_FID_NONE;
-        if (fidp->fs.fd > 0) {
-            v9fs_co_close(pdu->s, fidp->fs.fd);
-        }
-        goto out;
-    }
-    v9fs_string_copy(&fidp->path, &fullname);
+    iounit =  get_iounit(pdu->s, &fidp->path);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
@@ -1636,7 +1624,6 @@ out:
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
-    v9fs_string_free(&fullname);
 }
 
 static void v9fs_fsync(void *opaque)
@@ -2102,11 +2089,12 @@ static void v9fs_create(void *opaque)
         goto out;
     }
     if (perm & P9_STAT_MODE_DIR) {
-        err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
-                            fidp->uid, -1);
+        err = v9fs_co_mkdir(pdu->s, fidp, &name, perm & 0777,
+                            fidp->uid, -1, &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
         v9fs_string_copy(&fidp->path, &fullname);
         err = v9fs_co_opendir(pdu->s, fidp);
         if (err < 0) {
@@ -2114,11 +2102,13 @@ static void v9fs_create(void *opaque)
         }
         fidp->fid_type = P9_FID_DIR;
     } else if (perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_co_symlink(pdu->s, fidp, extension.data,
-                              fullname.data, -1);
+        err = v9fs_co_symlink(pdu->s, fidp, &name,
+                              extension.data, -1 , &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else if (perm & P9_STAT_MODE_LINK) {
         int32_t nfid = atoi(extension.data);
         V9fsFidState *nfidp = get_fid(pdu->s, nfid);
@@ -2126,12 +2116,19 @@ static void v9fs_create(void *opaque)
             err = -EINVAL;
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
         err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
+        put_fid(pdu->s, nfidp);
         if (err < 0) {
-            put_fid(pdu->s, nfidp);
             goto out;
         }
-        put_fid(pdu->s, nfidp);
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_lstat(pdu->s, &fidp->path, &stbuf);
+        if (err < 0) {
+            fidp->fid_type = P9_FID_NONE;
+            goto out;
+        }
     } else if (perm & P9_STAT_MODE_DEVICE) {
         char ctype;
         uint32_t major, minor;
@@ -2155,26 +2152,32 @@ static void v9fs_create(void *opaque)
         }
 
         nmode |= perm & 0777;
-        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
-                            makedev(major, minor), nmode);
+        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+                            makedev(major, minor), nmode, &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
-        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
-                            0, S_IFIFO | (perm & 0777));
+        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+                            0, S_IFIFO | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else if (perm & P9_STAT_MODE_SOCKET) {
-        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
-                            0, S_IFSOCK | (perm & 0777));
+        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+                            0, S_IFSOCK | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else {
-        err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
-                            omode_to_uflags(mode)|O_CREAT, perm);
+        err = v9fs_co_open2(pdu->s, fidp, &name, -1,
+                            omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
         if (err < 0) {
             goto out;
         }
@@ -2188,16 +2191,7 @@ static void v9fs_create(void *opaque)
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
     }
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
-    if (err < 0) {
-        fidp->fid_type = P9_FID_NONE;
-        if (fidp->fs.fd) {
-            v9fs_co_close(pdu->s, fidp->fs.fd);
-        }
-        goto out;
-    }
     iounit = get_iounit(pdu->s, &fidp->path);
-    v9fs_string_copy(&fidp->path, &fullname);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
@@ -2215,7 +2209,6 @@ static void v9fs_symlink(void *opaque)
     V9fsPDU *pdu = opaque;
     V9fsString name;
     V9fsString symname;
-    V9fsString fullname;
     V9fsFidState *dfidp;
     V9fsQID qid;
     struct stat stbuf;
@@ -2224,7 +2217,6 @@ static void v9fs_symlink(void *opaque)
     gid_t gid;
     size_t offset = 7;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 
     dfidp = get_fid(pdu->s, dfid);
@@ -2232,13 +2224,7 @@ static void v9fs_symlink(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
-    err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
-    if (err < 0) {
-        goto out;
-    }
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    err = v9fs_co_symlink(pdu->s, dfidp, &name, symname.data, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2251,7 +2237,6 @@ out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&symname);
-    v9fs_string_free(&fullname);
 }
 
 static void v9fs_flush(void *opaque)
@@ -2469,7 +2454,9 @@ static void v9fs_rename(void *opaque)
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
 
+    qemu_co_rwlock_wrlock(&s->rename_lock);
     err = v9fs_complete_rename(s, fidp, newdirfid, &name);
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         err = offset;
     }
@@ -2551,7 +2538,9 @@ static void v9fs_renameat(void *opaque)
     pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
                   &old_name, &newdirfid, &new_name);
 
+    qemu_co_rwlock_wrlock(&s->rename_lock);
     err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         err = offset;
     }
@@ -2735,12 +2724,10 @@ static void v9fs_mknod(void *opaque)
     size_t offset = 7;
     V9fsString name;
     struct stat stbuf;
-    V9fsString fullname;
     V9fsFidState *fidp;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
                   &major, &minor, &gid);
 
@@ -2749,13 +2736,8 @@ static void v9fs_mknod(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-    err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
-                        makedev(major, minor), mode);
-    if (err < 0) {
-        goto out;
-    }
-    err = v9fs_co_lstat(s, &fullname, &stbuf);
+    err = v9fs_co_mknod(s, fidp, &name, fidp->uid, gid,
+                        makedev(major, minor), mode, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2766,7 +2748,6 @@ out:
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
-    v9fs_string_free(&fullname);
     v9fs_string_free(&name);
 }
 
@@ -2867,14 +2848,13 @@ static void v9fs_mkdir(void *opaque)
     size_t offset = 7;
     int32_t fid;
     struct stat stbuf;
-    V9fsString name, fullname;
     V9fsQID qid;
+    V9fsString name;
     V9fsFidState *fidp;
     gid_t gid;
     int mode;
     int err = 0;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 
     fidp = get_fid(pdu->s, fid);
@@ -2882,12 +2862,7 @@ static void v9fs_mkdir(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-    err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
-    if (err < 0) {
-        goto out;
-    }
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    err = v9fs_co_mkdir(pdu->s, fidp, &name, mode, fidp->uid, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2898,7 +2873,6 @@ out:
     put_fid(pdu->s, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
-    v9fs_string_free(&fullname);
     v9fs_string_free(&name);
 }
 
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 8aeee4e..4238a76 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -8,6 +8,8 @@
 #include <sys/resource.h>
 #include "hw/virtio.h"
 #include "fsdev/file-op-9p.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
 
 /* The feature bitmap for virtio 9P */
 /* The mount point is specified in a config variable */
@@ -237,6 +239,11 @@ typedef struct V9fsState
     size_t config_size;
     enum p9_proto_version proto_version;
     int32_t msize;
+    /*
+     * lock ensuring atomic path update
+     * on rename.
+     */
+    CoRwlock rename_lock;
 } V9fsState;
 
 typedef struct V9fsStatState {
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 3/8] hw/9pfs: Move fid pathname tracking to seperate data type.
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 1/8] hw/9pfs: Make v9fs_string* functions non-static Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 2/8] hw/9pfs: Use read-write lock for protecting fid path Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 4/8] hw/9pfs: Add init callback to fs driver Aneesh Kumar K.V
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

This enables us to add handles to track fids later. The
V9fsPath added is similar to V9fsString except that the
size include the NULL byte also.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 fsdev/file-op-9p.h        |   46 ++++---
 hw/9pfs/codir.c           |   20 ++-
 hw/9pfs/cofile.c          |   38 +++--
 hw/9pfs/cofs.c            |  114 +++++++++++----
 hw/9pfs/coxattr.c         |   17 +-
 hw/9pfs/virtio-9p-coth.h  |   34 +++--
 hw/9pfs/virtio-9p-local.c |  205 ++++++++++++++++++++-----
 hw/9pfs/virtio-9p.c       |  366 +++++++++++++++++++++++++--------------------
 hw/9pfs/virtio-9p.h       |    7 +-
 9 files changed, 548 insertions(+), 299 deletions(-)

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 1eda342..8a7dbdb 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -57,43 +57,53 @@ typedef struct FsContext
     struct xattr_operations **xops;
 } FsContext;
 
+typedef struct V9fsPath {
+    int16_t size;
+    char *data;
+} V9fsPath;
+
 void cred_init(FsCred *);
 
 typedef struct FileOperations
 {
-    int (*lstat)(FsContext *, const char *, struct stat *);
-    ssize_t (*readlink)(FsContext *, const char *, char *, size_t);
-    int (*chmod)(FsContext *, const char *, FsCred *);
-    int (*chown)(FsContext *, const char *, FsCred *);
-    int (*mknod)(FsContext *, const char *, FsCred *);
-    int (*utimensat)(FsContext *, const char *, const struct timespec *);
+    int (*lstat)(FsContext *, V9fsPath *, struct stat *);
+    ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
+    int (*chmod)(FsContext *, V9fsPath *, FsCred *);
+    int (*chown)(FsContext *, V9fsPath *, FsCred *);
+    int (*mknod)(FsContext *, V9fsPath *, const char *, FsCred *);
+    int (*utimensat)(FsContext *, V9fsPath *, const struct timespec *);
     int (*remove)(FsContext *, const char *);
-    int (*symlink)(FsContext *, const char *, const char *, FsCred *);
-    int (*link)(FsContext *, const char *, const char *);
+    int (*symlink)(FsContext *, const char *, V9fsPath *,
+                   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 *, const char *);
-    int (*open)(FsContext *, const char *, int);
-    int (*open2)(FsContext *, const char *, int, FsCred *);
+    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 (*mkdir)(FsContext *, const char *, FsCred *);
+    int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
     int (*fstat)(FsContext *, int, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
-    int (*truncate)(FsContext *, const char *, off_t);
+    int (*truncate)(FsContext *, V9fsPath *, off_t);
     int (*fsync)(FsContext *, int, int);
-    int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
-    ssize_t (*lgetxattr)(FsContext *, const char *,
+    int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
+    ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
                          const char *, void *, size_t);
-    ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
-    int (*lsetxattr)(FsContext *, const char *,
+    ssize_t (*llistxattr)(FsContext *, V9fsPath *, void *, size_t);
+    int (*lsetxattr)(FsContext *, V9fsPath *,
                      const char *, void *, size_t, int);
-    int (*lremovexattr)(FsContext *, const char *, const char *);
+    int (*lremovexattr)(FsContext *, V9fsPath *, const char *);
+    int (*name_to_path)(FsContext *, V9fsPath *, const char *, V9fsPath *);
+    int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name,
+                    V9fsPath *newdir, const char *new_name);
+    int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
     void *opaque;
 } FileOperations;
 
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index c9a88ec..2c50df8 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -70,29 +70,31 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
 {
     int err;
     FsCred cred;
-    V9fsString fullname;
+    V9fsPath path;
 
     cred_init(&cred);
     cred.fc_mode = mode;
     cred.fc_uid = uid;
     cred.fc_gid = gid;
-    v9fs_string_init(&fullname);
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mkdir(&s->ctx, fullname.data, &cred);
+            err = s->ops->mkdir(&s->ctx, &fidp->path, name->data,  &cred);
             if (err < 0) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
-    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -103,7 +105,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data);
+            fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
             if (!fidp->fs.dir) {
                 err = -errno;
             } else {
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index cc62846..69fad36 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -17,14 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
+int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lstat(&s->ctx, path->data, stbuf);
+            err = s->ops->lstat(&s->ctx, path, stbuf);
             if (err < 0) {
                 err = -errno;
             }
@@ -54,7 +54,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags);
+            fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
             if (fidp->fs.fd == -1) {
                 err = -errno;
             } else {
@@ -76,33 +76,40 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
 {
     int err;
     FsCred cred;
-    V9fsString fullname;
+    V9fsPath path;
+
 
     cred_init(&cred);
     cred.fc_mode = mode & 07777;
     cred.fc_uid = fidp->uid;
     cred.fc_gid = gid;
-    v9fs_string_init(&fullname);
     /*
      * Hold the directory fid lock so that directory path name
      * don't change. Read lock is fine because this fid cannot
      * be used by any other operation.
      */
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open2(&s->ctx, fullname.data, flags, &cred);
+            fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
+                                        name->data, flags, &cred);
             if (fidp->fs.fd == -1) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
-                    err = s->ops->close(&s->ctx, fidp->fs.fd);
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                        s->ops->close(&s->ctx, fidp->fs.fd);
+                    } else {
+                        v9fs_path_copy(&fidp->path, &path);
+                    }
                 } else {
-                    v9fs_string_copy(&fidp->path, &fullname);
+                    s->ops->close(&s->ctx, fidp->fs.fd);
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
@@ -112,7 +119,6 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
             v9fs_reclaim_fd(s);
         }
     }
-    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -149,14 +155,16 @@ int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
     return err;
 }
 
-int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
+                 V9fsFidState *newdirfid, V9fsString *name)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->link(&s->ctx, oldpath->data, newpath->data);
+            err = s->ops->link(&s->ctx, &oldfid->path,
+                               &newdirfid->path, name->data);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 98860f9..7f5220e 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,7 +17,7 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
+int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
 {
     int err;
     ssize_t len;
@@ -27,7 +27,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
 
     v9fs_co_run_in_worker(
         {
-            len = s->ops->readlink(&s->ctx, path->data,
+            len = s->ops->readlink(&s->ctx, path,
                                    buf->data, PATH_MAX - 1);
             if (len > -1) {
                 buf->size = len;
@@ -46,14 +46,14 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
     return err;
 }
 
-int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->statfs(&s->ctx, path->data, stbuf);
+            err = s->ops->statfs(&s->ctx, path, stbuf);
             if (err < 0) {
                 err = -errno;
             }
@@ -62,7 +62,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
     return err;
 }
 
-int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
+int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
 {
     int err;
     FsCred cred;
@@ -72,7 +72,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->chmod(&s->ctx, path->data, &cred);
+            err = s->ops->chmod(&s->ctx, path, &cred);
             if (err < 0) {
                 err = -errno;
             }
@@ -81,7 +81,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
     return err;
 }
 
-int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
+int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
                       struct timespec times[2])
 {
     int err;
@@ -89,7 +89,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->utimensat(&s->ctx, path->data, times);
+            err = s->ops->utimensat(&s->ctx, path, times);
             if (err < 0) {
                 err = -errno;
             }
@@ -98,7 +98,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
     return err;
 }
 
-int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
+int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
 {
     int err;
     FsCred cred;
@@ -109,7 +109,7 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->chown(&s->ctx, path->data, &cred);
+            err = s->ops->chown(&s->ctx, path, &cred);
             if (err < 0) {
                 err = -errno;
             }
@@ -118,14 +118,14 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     return err;
 }
 
-int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
+int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->truncate(&s->ctx, path->data, size);
+            err = s->ops->truncate(&s->ctx, path, size);
             if (err < 0) {
                 err = -errno;
             }
@@ -138,35 +138,38 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
                   gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 {
     int err;
+    V9fsPath path;
     FsCred cred;
-    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_uid  = uid;
     cred.fc_gid  = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
-    v9fs_string_init(&fullname);
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mknod(&s->ctx, fullname.data, &cred);
+            err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
             if (err < 0) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
-    v9fs_string_free(&fullname);
     return err;
 }
 
-int v9fs_co_remove(V9fsState *s, V9fsString *path)
+/* Only works with path name based fid */
+int v9fs_co_remove(V9fsState *s, V9fsPath *path)
 {
     int err;
 
@@ -182,7 +185,24 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
     return err;
 }
 
-int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
+{
+    int err;
+
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    return err;
+}
+
+/* Only work with path name based fid */
+int v9fs_co_rename(V9fsState *s, V9fsPath *oldpath, V9fsPath *newpath)
 {
     int err;
 
@@ -196,34 +216,68 @@ int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
     return err;
 }
 
+int v9fs_co_renameat(V9fsState *s, V9fsPath *olddirpath, V9fsString *oldname,
+                     V9fsPath *newdirpath, V9fsString *newname)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
+                                   newdirpath, newname->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
 int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
                     const char *oldpath, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
-    V9fsString fullname;
+    V9fsPath path;
 
 
     cred_init(&cred);
     cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
     cred.fc_mode = 0777;
-    v9fs_string_init(&fullname);
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->symlink(&s->ctx, oldpath, fullname.data, &cred);
+            err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
+                                  name->data, &cred);
             if (err < 0) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
-    v9fs_string_free(&fullname);
+    return err;
+}
+
+/*
+ * For path name based fid we don't block. So we can
+ * directly call the fs driver ops.
+ */
+int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                         const char *name, V9fsPath *path)
+{
+    int err;
+    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+    if (err < 0) {
+        err = -errno;
+    }
     return err;
 }
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index 7b93c8f..b723240 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -17,14 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
+int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->llistxattr(&s->ctx, path->data, value, size);
+            err = s->ops->llistxattr(&s->ctx, path, value, size);
             if (err < 0) {
                 err = -errno;
             }
@@ -33,7 +33,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
     return err;
 }
 
-int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
                       V9fsString *xattr_name,
                       void *value, size_t size)
 {
@@ -42,7 +42,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lgetxattr(&s->ctx, path->data,
+            err = s->ops->lgetxattr(&s->ctx, path,
                                     xattr_name->data,
                                     value, size);
             if (err < 0) {
@@ -53,7 +53,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
     return err;
 }
 
-int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
                       V9fsString *xattr_name, void *value,
                       size_t size, int flags)
 {
@@ -62,7 +62,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lsetxattr(&s->ctx, path->data,
+            err = s->ops->lsetxattr(&s->ctx, path,
                                     xattr_name->data, value,
                                     size, flags);
             if (err < 0) {
@@ -73,7 +73,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
     return err;
 }
 
-int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
                          V9fsString *xattr_name)
 {
     int err;
@@ -81,8 +81,7 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lremovexattr(&s->ctx, path->data,
-                                       xattr_name->data);
+            err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index e5f46c5..cd94571 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -56,43 +56,49 @@ typedef struct V9fsThPool {
 
 extern void co_run_in_worker_bh(void *);
 extern int v9fs_init_worker_threads(void);
-extern int v9fs_co_readlink(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_readlink(V9fsState *, V9fsPath *, V9fsString *);
 extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *,
                            struct dirent *, struct dirent **result);
 extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *);
 extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t);
 extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_statfs(V9fsState *, V9fsString *, struct statfs *);
-extern int v9fs_co_lstat(V9fsState *, V9fsString *, struct stat *);
-extern int v9fs_co_chmod(V9fsState *, V9fsString *, mode_t);
-extern int v9fs_co_utimensat(V9fsState *, V9fsString *, struct timespec [2]);
-extern int v9fs_co_chown(V9fsState *, V9fsString *, uid_t, gid_t);
-extern int v9fs_co_truncate(V9fsState *, V9fsString *, off_t);
-extern int v9fs_co_llistxattr(V9fsState *, V9fsString *, void *, size_t);
-extern int v9fs_co_lgetxattr(V9fsState *, V9fsString *,
+extern int v9fs_co_statfs(V9fsState *, V9fsPath *, struct statfs *);
+extern int v9fs_co_lstat(V9fsState *, V9fsPath *, struct stat *);
+extern int v9fs_co_chmod(V9fsState *, V9fsPath *, mode_t);
+extern int v9fs_co_utimensat(V9fsState *, V9fsPath *, struct timespec [2]);
+extern int v9fs_co_chown(V9fsState *, V9fsPath *, uid_t, gid_t);
+extern int v9fs_co_truncate(V9fsState *, V9fsPath *, off_t);
+extern int v9fs_co_llistxattr(V9fsState *, V9fsPath *, void *, size_t);
+extern int v9fs_co_lgetxattr(V9fsState *, V9fsPath *,
                              V9fsString *, void *, size_t);
 extern int v9fs_co_mknod(V9fsState *, V9fsFidState *, V9fsString *, uid_t,
                          gid_t, dev_t, mode_t, struct stat *);
 extern int v9fs_co_mkdir(V9fsState *, V9fsFidState *, V9fsString *,
                          mode_t, uid_t, gid_t, struct stat *);
-extern int v9fs_co_remove(V9fsState *, V9fsString *);
-extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_remove(V9fsState *, V9fsPath *);
+extern int v9fs_co_rename(V9fsState *, V9fsPath *, V9fsPath *);
+extern int v9fs_co_unlinkat(V9fsState *, V9fsPath *, V9fsString *, int flags);
+extern int v9fs_co_renameat(V9fsState *, V9fsPath *, V9fsString *,
+                            V9fsPath *, V9fsString *);
 extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
 extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
 extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
 extern int v9fs_co_open2(V9fsState *, V9fsFidState *, V9fsString *,
                          gid_t, int, int, struct stat *);
-extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
+extern int v9fs_co_lsetxattr(V9fsState *, V9fsPath *, V9fsString *,
                              void *, size_t, int);
-extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_lremovexattr(V9fsState *, V9fsPath *, V9fsString *);
 extern int v9fs_co_closedir(V9fsState *, DIR *);
 extern int v9fs_co_close(V9fsState *, int);
 extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
 extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, V9fsString *,
                            const char *, gid_t, struct stat *);
-extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_link(V9fsState *, V9fsFidState *,
+                        V9fsFidState *, V9fsString *);
 extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
                            struct iovec *, int, int64_t);
 extern int v9fs_co_preadv(V9fsState *, V9fsFidState *,
                           struct iovec *, int, int64_t);
+extern int v9fs_co_name_to_path(V9fsState *, V9fsPath *,
+                                const char *, V9fsPath *);
 #endif
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 61cbf8d..55f62f9 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -22,10 +22,12 @@
 #include <attr/xattr.h>
 
 
-static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
+static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 {
     int err;
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     err =  lstat(rpath(fs_ctx, path, buffer), stbuf);
     if (err) {
         return err;
@@ -59,6 +61,7 @@ static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
 static int local_set_xattr(const char *path, FsCred *credp)
 {
     int err;
+
     if (credp->fc_uid != -1) {
         err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
                 0);
@@ -91,9 +94,10 @@ static int local_set_xattr(const char *path, FsCred *credp)
 }
 
 static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
-        FsCred *credp)
+                                         FsCred *credp)
 {
     char buffer[PATH_MAX];
+
     if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
         return -1;
     }
@@ -110,11 +114,13 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
     return 0;
 }
 
-static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
-        char *buf, size_t bufsz)
+static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+                              char *buf, size_t bufsz)
 {
     ssize_t tsize = -1;
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     if (fs_ctx->fs_sm == SM_MAPPED) {
         int fd;
         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
@@ -143,15 +149,19 @@ static int local_closedir(FsContext *ctx, DIR *dir)
     return closedir(dir);
 }
 
-static int local_open(FsContext *ctx, const char *path, int flags)
+static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return open(rpath(ctx, path, buffer), flags);
 }
 
-static DIR *local_opendir(FsContext *ctx, const char *path)
+static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return opendir(rpath(ctx, path, buffer));
 }
 
@@ -166,7 +176,7 @@ static off_t local_telldir(FsContext *ctx, DIR *dir)
 }
 
 static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
-                         struct dirent **result)
+                           struct dirent **result)
 {
     return readdir_r(dir, entry, result);
 }
@@ -192,7 +202,7 @@ static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
 }
 
 static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt, off_t offset)
+                             int iovcnt, off_t offset)
 {
 #ifdef CONFIG_PREADV
     return pwritev(fd, iov, iovcnt, offset);
@@ -206,9 +216,11 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
 #endif
 }
 
-static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     if (fs_ctx->fs_sm == SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
@@ -218,18 +230,25 @@ static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
     return -1;
 }
 
-static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
 {
+    char *path;
     int err = -1;
     int serrno = 0;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         err = mknod(rpath(fs_ctx, path, buffer),
                 SM_LOCAL_MODE_BITS|S_IFREG, 0);
         if (err == -1) {
-            return err;
+            goto out;
         }
         local_set_xattr(rpath(fs_ctx, path, buffer), credp);
         if (err == -1) {
@@ -241,7 +260,7 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
                 credp->fc_rdev);
         if (err == -1) {
-            return err;
+            goto out;
         }
         err = local_post_create_passthrough(fs_ctx, path, credp);
         if (err == -1) {
@@ -249,25 +268,34 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
             goto err_end;
         }
     }
-    return err;
+    goto out;
 
 err_end:
     remove(rpath(fs_ctx, path, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
-static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
 {
+    char *path;
     int err = -1;
     int serrno = 0;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
         if (err == -1) {
-            return err;
+            goto out;
         }
         credp->fc_mode = credp->fc_mode|S_IFDIR;
         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
@@ -279,7 +307,7 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
                (fs_ctx->fs_sm == SM_NONE)) {
         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
         if (err == -1) {
-            return err;
+            goto out;
         }
         err = local_post_create_passthrough(fs_ctx, path, credp);
         if (err == -1) {
@@ -287,11 +315,13 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
             goto err_end;
         }
     }
-    return err;
+    goto out;
 
 err_end:
     remove(rpath(fs_ctx, path, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -325,19 +355,26 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
     return err;
 }
 
-static int local_open2(FsContext *fs_ctx, const char *path, int flags,
-        FsCred *credp)
+static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+                       int flags, FsCred *credp)
 {
+    char *path;
     int fd = -1;
     int err = -1;
     int serrno = 0;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
         if (fd == -1) {
-            return fd;
+            err = fd;
+            goto out;
         }
         credp->fc_mode = credp->fc_mode|S_IFREG;
         /* Set cleint credentials in xattr */
@@ -350,7 +387,8 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
                (fs_ctx->fs_sm == SM_NONE)) {
         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
         if (fd == -1) {
-            return fd;
+            err = fd;
+            goto out;
         }
         err = local_post_create_passthrough(fs_ctx, path, credp);
         if (err == -1) {
@@ -358,23 +396,32 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
             goto err_end;
         }
     }
-    return fd;
+    err = fd;
+    goto out;
 
 err_end:
     close(fd);
     remove(rpath(fs_ctx, path, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
 
 static int local_symlink(FsContext *fs_ctx, const char *oldpath,
-        const char *newpath, FsCred *credp)
+                         V9fsPath *dir_path, const char *name, FsCred *credp)
 {
     int err = -1;
     int serrno = 0;
+    char *newpath;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    newpath = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         int fd;
@@ -382,7 +429,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
         fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
                 SM_LOCAL_MODE_BITS);
         if (fd == -1) {
-            return fd;
+            err = fd;
+            goto out;
         }
         /* Write the oldpath (target) to the file. */
         oldpath_size = strlen(oldpath);
@@ -408,10 +456,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
                (fs_ctx->fs_sm == SM_NONE)) {
         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
         if (err) {
-            return err;
+            goto out;
         }
         err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
-                credp->fc_gid);
+                     credp->fc_gid);
         if (err == -1) {
             /*
              * If we fail to change ownership and if we are
@@ -424,24 +472,37 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
                 err = 0;
         }
     }
-    return err;
+    goto out;
 
 err_end:
     remove(rpath(fs_ctx, newpath, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
-static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
+static int local_link(FsContext *ctx, V9fsPath *oldpath,
+                      V9fsPath *dirpath, const char *name)
 {
+    int ret;
+    V9fsString newpath;
     char buffer[PATH_MAX], buffer1[PATH_MAX];
 
-    return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+    v9fs_string_init(&newpath);
+    v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
+
+    ret = link(rpath(ctx, oldpath->data, buffer),
+               rpath(ctx, newpath.data, buffer1));
+    v9fs_string_free(&newpath);
+    return ret;
 }
 
-static int local_truncate(FsContext *ctx, const char *path, off_t size)
+static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return truncate(rpath(ctx, path, buffer), size);
 }
 
@@ -453,9 +514,11 @@ static int local_rename(FsContext *ctx, const char *oldpath,
     return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
 }
 
-static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
             (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
         return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
@@ -470,12 +533,14 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
     return -1;
 }
 
-static int local_utimensat(FsContext *s, const char *path,
+static int local_utimensat(FsContext *s, V9fsPath *fs_path,
                            const struct timespec *buf)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
-            AT_SYMLINK_NOFOLLOW);
+                          AT_SYMLINK_NOFOLLOW);
 }
 
 static int local_remove(FsContext *ctx, const char *path)
@@ -493,36 +558,93 @@ static int local_fsync(FsContext *ctx, int fd, int datasync)
     }
 }
 
-static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
 {
     char buffer[PATH_MAX];
-   return statfs(rpath(s, path, buffer), stbuf);
+    char *path = fs_path->data;
+
+    return statfs(rpath(s, path, buffer), stbuf);
 }
 
-static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
                                const char *name, void *value, size_t size)
 {
+    char *path = fs_path->data;
+
     return v9fs_get_xattr(ctx, path, name, value, size);
 }
 
-static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                                 void *value, size_t size)
 {
+    char *path = fs_path->data;
+
     return v9fs_list_xattr(ctx, path, value, size);
 }
 
-static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
                            void *value, size_t size, int flags)
 {
+    char *path = fs_path->data;
+
     return v9fs_set_xattr(ctx, path, name, value, size, flags);
 }
 
-static int local_lremovexattr(FsContext *ctx,
-                              const char *path, const char *name)
+static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+                              const char *name)
 {
+    char *path = fs_path->data;
+
     return v9fs_remove_xattr(ctx, path, name);
 }
 
+static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                              const char *name, V9fsPath *target)
+{
+    if (dir_path) {
+        v9fs_string_sprintf((V9fsString *)target, "%s/%s",
+                            dir_path->data, name);
+    } else {
+        v9fs_string_sprintf((V9fsString *)target, "%s", name);
+    }
+    /* Bump the size for including terminating NULL */
+    target->size++;
+    return 0;
+}
+
+static int local_renameat(FsContext *ctx, V9fsPath *olddir,
+                          const char *old_name, V9fsPath *newdir,
+                          const char *new_name)
+{
+    int ret;
+    V9fsString old_full_name, new_full_name;
+
+    v9fs_string_init(&old_full_name);
+    v9fs_string_init(&new_full_name);
+
+    v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
+    v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
+
+    ret = local_rename(ctx, old_full_name.data, new_full_name.data);
+    v9fs_string_free(&old_full_name);
+    v9fs_string_free(&new_full_name);
+    return ret;
+}
+
+static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
+                          const char *name, int flags)
+{
+    int ret;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+    v9fs_string_init(&fullname);
+
+    v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
+    ret = remove(rpath(ctx, fullname.data, buffer));
+    v9fs_string_free(&fullname);
+
+    return ret;
+}
 
 FileOperations local_ops = {
     .lstat = local_lstat,
@@ -555,4 +677,7 @@ FileOperations local_ops = {
     .llistxattr = local_llistxattr,
     .lsetxattr = local_lsetxattr,
     .lremovexattr = local_lremovexattr,
+    .name_to_path = local_name_to_path,
+    .renameat  = local_renameat,
+    .unlinkat = local_unlinkat,
 };
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 356bb3b..82f1db5 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -214,16 +214,48 @@ void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
     v9fs_string_sprintf(lhs, "%s", rhs->data);
 }
 
+void v9fs_path_init(V9fsPath *path)
+{
+    path->data = NULL;
+    path->size = 0;
+}
+
+void v9fs_path_free(V9fsPath *path)
+{
+    g_free(path->data);
+    path->data = NULL;
+    path->size = 0;
+}
+
+void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
+{
+    v9fs_path_free(lhs);
+    lhs->data = g_malloc(rhs->size);
+    memcpy(lhs->data, rhs->data, rhs->size);
+    lhs->size = rhs->size;
+}
+
+int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                      const char *name, V9fsPath *path)
+{
+    int err;
+    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+    if (err < 0) {
+        err = -errno;
+    }
+    return err;
+}
+
 /*
  * Return TRUE if s1 is an ancestor of s2.
  *
  * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
  * As a special case, We treat s1 as ancestor of s2 if they are same!
  */
-static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
+static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
 {
-    if (!strncmp(s1->data, s2->data, s1->size)) {
-        if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
+    if (!strncmp(s1->data, s2->data, s1->size - 1)) {
+        if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
             return 1;
         }
     }
@@ -368,7 +400,7 @@ static int free_fid(V9fsState *s, V9fsFidState *fidp)
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(s, fidp);
     }
-    v9fs_string_free(&fidp->path);
+    v9fs_path_free(&fidp->path);
     g_free(fidp);
     return retval;
 }
@@ -484,14 +516,17 @@ void v9fs_reclaim_fd(V9fsState *s)
     }
 }
 
-static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
+static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsPath *path)
 {
     int err;
     V9fsFidState *fidp, head_fid;
 
     head_fid.next = s->fid_list;
     for (fidp = s->fid_list; fidp; fidp = fidp->next) {
-        if (!strcmp(fidp->path.data, str->data)) {
+        if (fidp->path.size != path->size) {
+            continue;
+        }
+        if (!memcmp(fidp->path.data, path->data, path->size)) {
             /* Mark the fid non reclaimable. */
             fidp->flags |= FID_NON_RECLAIMABLE;
 
@@ -998,7 +1033,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
     return mode;
 }
 
-static int stat_to_v9stat(V9fsState *s, V9fsString *name,
+static int stat_to_v9stat(V9fsState *s, V9fsPath *name,
                             const struct stat *stbuf,
                             V9fsStat *v9stat)
 {
@@ -1150,13 +1185,16 @@ static void print_sg(struct iovec *sg, int cnt)
     printf("}\n");
 }
 
-static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
+/* Will call this only for path name based fid */
+static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
 {
-    V9fsString str;
-    v9fs_string_init(&str);
-    v9fs_string_copy(&str, dst);
-    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
-    v9fs_string_free(&str);
+    V9fsPath str;
+    v9fs_path_init(&str);
+    v9fs_path_copy(&str, dst);
+    v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
+    v9fs_path_free(&str);
+    /* +1 to include terminating NULL */
+    dst->size++;
 }
 
 static void v9fs_version(void *opaque)
@@ -1202,7 +1240,12 @@ static void v9fs_attach(void *opaque)
         goto out_nofid;
     }
     fidp->uid = n_uname;
-    v9fs_string_sprintf(&fidp->path, "%s", "/");
+    err = v9fs_co_name_to_path(s, NULL, "/", &fidp->path);
+    if (err < 0) {
+        err = -EINVAL;
+        clunk_fid(s, fid);
+        goto out;
+    }
     err = fid_to_qid(s, fidp, &qid);
     if (err < 0) {
         err = -EINVAL;
@@ -1400,7 +1443,7 @@ static void v9fs_walk(void *opaque)
     int name_idx;
     V9fsQID *qids = NULL;
     int i, err = 0;
-    V9fsString path;
+    V9fsPath dpath, path;
     uint16_t nwnames;
     struct stat stbuf;
     size_t offset = 7;
@@ -1420,7 +1463,6 @@ static void v9fs_walk(void *opaque)
         for (i = 0; i < nwnames; i++) {
             offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
         }
-
     } else if (nwnames > P9_MAXWELEM) {
         err = -EINVAL;
         goto out_nofid;
@@ -1430,22 +1472,29 @@ static void v9fs_walk(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
+    v9fs_path_init(&dpath);
+    v9fs_path_init(&path);
+    /*
+     * Both dpath and path initially poin to fidp.
+     * Needed to handle request with nwnames == 0
+     */
+    v9fs_path_copy(&dpath, &fidp->path);
+    v9fs_path_copy(&path, &fidp->path);
+    for (name_idx = 0; name_idx < nwnames; name_idx++) {
+        err = v9fs_co_name_to_path(s, &dpath, wnames[name_idx].data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_lstat(s, &path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        stat_to_qid(&stbuf, &qids[name_idx]);
+        v9fs_path_copy(&dpath, &path);
+    }
     if (fid == newfid) {
         BUG_ON(fidp->fid_type != P9_FID_NONE);
-        v9fs_string_init(&path);
-        for (name_idx = 0; name_idx < nwnames; name_idx++) {
-            v9fs_string_sprintf(&path, "%s/%s",
-                                fidp->path.data, wnames[name_idx].data);
-            v9fs_string_copy(&fidp->path, &path);
-
-            err = v9fs_co_lstat(s, &fidp->path, &stbuf);
-            if (err < 0) {
-                v9fs_string_free(&path);
-                goto out;
-            }
-            stat_to_qid(&stbuf, &qids[name_idx]);
-        }
-        v9fs_string_free(&path);
+        v9fs_path_copy(&fidp->path, &path);
     } else {
         newfidp = alloc_fid(s, newfid);
         if (newfidp == NULL) {
@@ -1453,21 +1502,7 @@ static void v9fs_walk(void *opaque)
             goto out;
         }
         newfidp->uid = fidp->uid;
-        v9fs_string_init(&path);
-        v9fs_string_copy(&newfidp->path, &fidp->path);
-        for (name_idx = 0; name_idx < nwnames; name_idx++) {
-            v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
-                                wnames[name_idx].data);
-            v9fs_string_copy(&newfidp->path, &path);
-            err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
-            if (err < 0) {
-                clunk_fid(s, newfidp->fid);
-                v9fs_string_free(&path);
-                goto out;
-            }
-            stat_to_qid(&stbuf, &qids[name_idx]);
-        }
-        v9fs_string_free(&path);
+        v9fs_path_copy(&newfidp->path, &path);
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
 out:
@@ -1475,6 +1510,8 @@ out:
     if (newfidp) {
         put_fid(s, newfidp);
     }
+    v9fs_path_free(&dpath);
+    v9fs_path_free(&path);
 out_nofid:
     complete_pdu(s, pdu, err);
     if (nwnames && nwnames <= P9_MAXWELEM) {
@@ -1484,9 +1521,10 @@ out_nofid:
         g_free(wnames);
         g_free(qids);
     }
+    return;
 }
 
-static int32_t get_iounit(V9fsState *s, V9fsString *name)
+static int32_t get_iounit(V9fsState *s, V9fsPath *path)
 {
     struct statfs stbuf;
     int32_t iounit = 0;
@@ -1495,7 +1533,7 @@ static int32_t get_iounit(V9fsState *s, V9fsString *name)
      * iounit should be multiples of f_bsize (host filesystem block size
      * and as well as less than (client msize - P9_IOHDRSZ))
      */
-    if (!v9fs_co_statfs(s, name, &stbuf)) {
+    if (!v9fs_co_statfs(s, path, &stbuf)) {
         iounit = stbuf.f_bsize;
         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
     }
@@ -1705,7 +1743,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
 static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
                                      V9fsFidState *fidp, int32_t max_count)
 {
-    V9fsString name;
+    V9fsPath path;
     V9fsStat v9stat;
     int len, err = 0;
     int32_t count = 0;
@@ -1722,17 +1760,20 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
     dent = g_malloc(sizeof(struct dirent));
 
     while (1) {
-        v9fs_string_init(&name);
+        v9fs_path_init(&path);
         err = v9fs_co_readdir_r(s, fidp, dent, &result);
         if (err || !result) {
             break;
         }
-        v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
-        err = v9fs_co_lstat(s, &name, &stbuf);
+        err = v9fs_co_name_to_path(s, &fidp->path, dent->d_name, &path);
         if (err < 0) {
             goto out;
         }
-        err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
+        err = v9fs_co_lstat(s, &path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = stat_to_v9stat(s, &path, &stbuf, &v9stat);
         if (err < 0) {
             goto out;
         }
@@ -1742,18 +1783,18 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
             /* Ran out of buffer. Set dir back to old position and return */
             v9fs_co_seekdir(s, fidp, saved_dir_pos);
             v9fs_stat_free(&v9stat);
-            v9fs_string_free(&name);
+            v9fs_path_free(&path);
             g_free(dent);
             return count;
         }
         count += len;
         v9fs_stat_free(&v9stat);
-        v9fs_string_free(&name);
+        v9fs_path_free(&path);
         saved_dir_pos = dent->d_off;
     }
 out:
     g_free(dent);
-    v9fs_string_free(&name);
+    v9fs_path_free(&path);
     if (err < 0) {
         return err;
     }
@@ -2062,14 +2103,14 @@ static void v9fs_create(void *opaque)
     V9fsQID qid;
     int32_t perm;
     int8_t mode;
+    V9fsPath path;
     struct stat stbuf;
     V9fsString name;
     V9fsString extension;
-    V9fsString fullname;
     int iounit;
     V9fsPDU *pdu = opaque;
 
-    v9fs_string_init(&fullname);
+    v9fs_path_init(&path);
 
     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
                   &perm, &mode, &extension);
@@ -2079,23 +2120,17 @@ static void v9fs_create(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
-    if (!err) {
-        err = -EEXIST;
-        goto out;
-    } else if (err != -ENOENT) {
-        goto out;
-    }
     if (perm & P9_STAT_MODE_DIR) {
         err = v9fs_co_mkdir(pdu->s, fidp, &name, perm & 0777,
                             fidp->uid, -1, &stbuf);
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
         err = v9fs_co_opendir(pdu->s, fidp);
         if (err < 0) {
             goto out;
@@ -2107,23 +2142,29 @@ static void v9fs_create(void *opaque)
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_LINK) {
-        int32_t nfid = atoi(extension.data);
-        V9fsFidState *nfidp = get_fid(pdu->s, nfid);
-        if (nfidp == NULL) {
+        int32_t ofid = atoi(extension.data);
+        V9fsFidState *ofidp = get_fid(pdu->s, ofid);
+        if (ofidp == NULL) {
             err = -EINVAL;
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
-        put_fid(pdu->s, nfidp);
+        err = v9fs_co_link(pdu->s, ofidp, fidp, &name);
+        put_fid(pdu->s, ofidp);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
         if (err < 0) {
+            fidp->fid_type = P9_FID_NONE;
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        v9fs_path_copy(&fidp->path, &path);
         err = v9fs_co_lstat(pdu->s, &fidp->path, &stbuf);
         if (err < 0) {
             fidp->fid_type = P9_FID_NONE;
@@ -2157,24 +2198,33 @@ static void v9fs_create(void *opaque)
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
         err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
                             0, S_IFIFO | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_SOCKET) {
         err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
                             0, S_IFSOCK | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else {
         err = v9fs_co_open2(pdu->s, fidp, &name, -1,
                             omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
@@ -2201,7 +2251,7 @@ out_nofid:
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
    v9fs_string_free(&extension);
-   v9fs_string_free(&fullname);
+   v9fs_path_free(&path);
 }
 
 static void v9fs_symlink(void *opaque)
@@ -2254,12 +2304,10 @@ static void v9fs_link(void *opaque)
     V9fsState *s = pdu->s;
     int32_t dfid, oldfid;
     V9fsFidState *dfidp, *oldfidp;
-    V9fsString name, fullname;
+    V9fsString name;;
     size_t offset = 7;
     int err = 0;
 
-    v9fs_string_init(&fullname);
-
     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
 
     dfidp = get_fid(s, dfid);
@@ -2273,14 +2321,10 @@ static void v9fs_link(void *opaque)
         err = -ENOENT;
         goto out;
     }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
-    err = v9fs_co_link(s, &oldfidp->path, &fullname);
+    err = v9fs_co_link(s, oldfidp, dfidp, &name);
     if (!err) {
         err = offset;
     }
-    v9fs_string_free(&fullname);
-
 out:
     put_fid(s, dfidp);
 out_nofid:
@@ -2329,9 +2373,9 @@ static void v9fs_unlinkat(void *opaque)
     V9fsString name;
     int32_t dfid, flags;
     size_t offset = 7;
+    V9fsPath path;
     V9fsFidState *dfidp;
     V9fsPDU *pdu = opaque;
-    V9fsString full_name;
 
     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
 
@@ -2340,36 +2384,44 @@ static void v9fs_unlinkat(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-    v9fs_string_init(&full_name);
-    v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data);
     /*
      * IF the file is unlinked, we cannot reopen
      * the file later. So don't reclaim fd
      */
-    err = v9fs_mark_fids_unreclaim(pdu->s, &full_name);
+    v9fs_path_init(&path);
+    err = v9fs_co_name_to_path(pdu->s, &dfidp->path, name.data, &path);
+    if (err < 0) {
+        goto out_err;
+    }
+    err = v9fs_mark_fids_unreclaim(pdu->s, &path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_co_remove(pdu->s, &full_name);
+    err = v9fs_co_unlinkat(pdu->s, &dfidp->path, &name, flags);
     if (!err) {
         err = offset;
     }
 out_err:
     put_fid(pdu->s, dfidp);
-    v9fs_string_free(&full_name);
+    v9fs_path_free(&path);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
 
+
+/* Only works with path name based fid */
 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
                                 int32_t newdirfid, V9fsString *name)
 {
     char *end;
     int err = 0;
+    V9fsPath new_path;
+    V9fsFidState *tfidp;
     V9fsFidState *dirfidp = NULL;
     char *old_name, *new_name;
 
+    v9fs_path_init(&new_path);
     if (newdirfid != -1) {
         dirfidp = get_fid(s, newdirfid);
         if (dirfidp == NULL) {
@@ -2377,12 +2429,7 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
             goto out_nofid;
         }
         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
-
-        new_name = g_malloc0(dirfidp->path.size + name->size + 2);
-
-        strcpy(new_name, dirfidp->path.data);
-        strcat(new_name, "/");
-        strcat(new_name + dirfidp->path.size, name->data);
+        v9fs_co_name_to_path(s, &dirfidp->path, name->data, &new_path);
     } else {
         old_name = fidp->path.data;
         end = strrchr(old_name, '/');
@@ -2392,44 +2439,30 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
             end = old_name;
         }
         new_name = g_malloc0(end - old_name + name->size + 1);
-
         strncat(new_name, old_name, end - old_name);
         strncat(new_name + (end - old_name), name->data, name->size);
+        v9fs_co_name_to_path(s, NULL, new_name, &new_path);
+        g_free(new_name);
     }
-
-    v9fs_string_free(name);
-    name->data = new_name;
-    name->size = strlen(new_name);
-
-    if (strcmp(new_name, fidp->path.data) != 0) {
-        err = v9fs_co_rename(s, &fidp->path, name);
-        if (err < 0) {
-            goto out;
-        }
-        V9fsFidState *tfidp;
-        /*
-         * Fixup fid's pointing to the old name to
-         * start pointing to the new name
-         */
-        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
-            if (fidp == tfidp) {
-                /*
-                 * we replace name of this fid towards the end
-                 * so that our below strcmp will work
-                 */
-                continue;
-            }
-            if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
-                /* replace the name */
-                v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
-            }
+    err = v9fs_co_rename(s, &fidp->path, &new_path);
+    if (err < 0) {
+        goto out;
+    }
+    /*
+     * Fixup fid's pointing to the old name to
+     * start pointing to the new name
+     */
+    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+        if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
+            /* replace the name */
+            v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
         }
-        v9fs_string_copy(&fidp->path, name);
     }
 out:
     if (dirfidp) {
         put_fid(s, dirfidp);
     }
+    v9fs_path_free(&new_path);
 out_nofid:
     return err;
 }
@@ -2466,12 +2499,38 @@ out_nofid:
     v9fs_string_free(&name);
 }
 
+static void v9fs_fix_fid_paths(V9fsState *s, V9fsPath *olddir,
+                               V9fsString *old_name, V9fsPath *newdir,
+                               V9fsString *new_name)
+{
+    V9fsFidState *tfidp;
+    V9fsPath oldpath, newpath;
+
+
+    v9fs_path_init(&oldpath);
+    v9fs_path_init(&newpath);
+    v9fs_co_name_to_path(s, olddir, old_name->data, &oldpath);
+    v9fs_co_name_to_path(s, newdir, new_name->data, &newpath);
+
+    /*
+     * Fixup fid's pointing to the old name to
+     * start pointing to the new name
+     */
+    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+        if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
+            /* replace the name */
+            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
+        }
+    }
+    v9fs_path_free(&oldpath);
+    v9fs_path_free(&newpath);
+}
+
 static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
                                   V9fsString *old_name, int32_t newdirfid,
                                   V9fsString *new_name)
 {
     int err = 0;
-    V9fsString old_full_name, new_full_name;
     V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
 
     olddirfidp = get_fid(s, olddirfid);
@@ -2479,41 +2538,24 @@ static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
         err = -ENOENT;
         goto out;
     }
-    v9fs_string_init(&old_full_name);
-    v9fs_string_init(&new_full_name);
-
-    v9fs_string_sprintf(&old_full_name, "%s/%s",
-                        olddirfidp->path.data, old_name->data);
     if (newdirfid != -1) {
         newdirfidp = get_fid(s, newdirfid);
         if (newdirfidp == NULL) {
             err = -ENOENT;
             goto out;
         }
-        v9fs_string_sprintf(&new_full_name, "%s/%s",
-                            newdirfidp->path.data, new_name->data);
     } else {
-        v9fs_string_sprintf(&new_full_name, "%s/%s",
-                            olddirfidp->path.data, new_name->data);
+        newdirfidp = get_fid(s, olddirfid);
     }
 
-    if (strcmp(old_full_name.data, new_full_name.data) != 0) {
-        V9fsFidState *tfidp;
-        err = v9fs_co_rename(s, &old_full_name, &new_full_name);
-        if (err < 0) {
-            goto out;
-        }
-        /*
-         * Fixup fid's pointing to the old name to
-         * start pointing to the new name
-         */
-        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
-            if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
-                /* replace the name */
-                v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
-            }
-        }
+    err = v9fs_co_renameat(s, &olddirfidp->path, old_name,
+                           &newdirfidp->path, new_name);
+    if (err < 0) {
+        goto out;
     }
+    /* Only for path based fid  we need to do the below fixup */
+    v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
+                       &newdirfidp->path, new_name);
 out:
     if (olddirfidp) {
         put_fid(s, olddirfidp);
@@ -2521,8 +2563,6 @@ out:
     if (newdirfidp) {
         put_fid(s, newdirfidp);
     }
-    v9fs_string_free(&old_full_name);
-    v9fs_string_free(&new_full_name);
     return err;
 }
 
@@ -2899,7 +2939,7 @@ static void v9fs_xattrwalk(void *opaque)
         err = -EINVAL;
         goto out;
     }
-    v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
+    v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
     if (name.data[0] == 0) {
         /*
          * listxattr request. Get the size first
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 4238a76..8c7c3f0 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -206,7 +206,7 @@ struct V9fsFidState
 {
     int fid_type;
     int32_t fid;
-    V9fsString path;
+    V9fsPath path;
     union {
         int fd;
         DIR *dir;
@@ -396,4 +396,9 @@ extern void v9fs_string_free(V9fsString *str);
 extern void v9fs_string_null(V9fsString *str);
 extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
 extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
+extern void v9fs_path_init(V9fsPath *path);
+extern void v9fs_path_free(V9fsPath *path);
+extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
+extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                             const char *name, V9fsPath *path);
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 4/8] hw/9pfs: Add init callback to fs driver
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
                   ` (2 preceding siblings ...)
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 3/8] hw/9pfs: Move fid pathname tracking to seperate data type Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 5/8] hw/9pfs: Add fs driver specific details to fscontext Aneesh Kumar K.V
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

This call back can be used to do fs driver specific initialization.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 fsdev/file-op-9p.h         |    2 ++
 hw/9pfs/virtio-9p-device.c |    7 ++++++-
 hw/9pfs/virtio-9p-local.c  |    7 ++++++-
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 8a7dbdb..5221d6d 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -19,6 +19,7 @@
 #include <sys/stat.h>
 #include <sys/uio.h>
 #include <sys/vfs.h>
+
 #define SM_LOCAL_MODE_BITS    0600
 #define SM_LOCAL_DIR_MODE_BITS    0700
 
@@ -66,6 +67,7 @@ void cred_init(FsCred *);
 
 typedef struct FileOperations
 {
+    int (*init)(struct FsContext *);
     int (*lstat)(FsContext *, V9fsPath *, struct stat *);
     ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
     int (*chmod)(FsContext *, V9fsPath *, FsCred *);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index eea70cb..1ffe95b 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -45,7 +45,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
 }
 
 VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
- {
+{
     V9fsState *s;
     int i, len;
     struct stat stat;
@@ -133,6 +133,11 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     s->fid_list = NULL;
     qemu_co_rwlock_init(&s->rename_lock);
 
+    if (s->ops->init(&s->ctx) < 0) {
+        fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s"
+                " and export path:%s\n", conf->fsdev_id, s->ctx.fs_root);
+        exit(1);
+    }
     if (v9fs_init_worker_threads() < 0) {
         fprintf(stderr, "worker thread initialization failed\n");
         exit(1);
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 55f62f9..61954fe 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -21,7 +21,6 @@
 #include <sys/un.h>
 #include <attr/xattr.h>
 
-
 static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 {
     int err;
@@ -646,7 +645,13 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
     return ret;
 }
 
+static int local_init(FsContext *ctx)
+{
+    return 0;
+}
+
 FileOperations local_ops = {
+    .init  = local_init,
     .lstat = local_lstat,
     .readlink = local_readlink,
     .close = local_close,
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 5/8] hw/9pfs: Add fs driver specific details to fscontext
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
                   ` (3 preceding siblings ...)
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 4/8] hw/9pfs: Add init callback to fs driver Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 6/8] hw/9pfs: Avoid unnecessary get_fid in v9fs_clunk Aneesh Kumar K.V
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

Add a new context flag PATHNAME_FSCONTEXT and indicate whether
the fs driver track fid using path names. Also add a private
pointer that help us to track fs driver specific values in there

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 fsdev/file-op-9p.h         |    6 ++++
 hw/9pfs/codir.c            |    8 +++---
 hw/9pfs/cofile.c           |   16 ++++++------
 hw/9pfs/cofs.c             |   58 +++++++++++++++++++++++++------------------
 hw/9pfs/coxattr.c          |   16 ++++++------
 hw/9pfs/virtio-9p-device.c |    1 +
 hw/9pfs/virtio-9p-local.c  |    1 +
 hw/9pfs/virtio-9p.c        |   30 ++++++++++++++++------
 hw/9pfs/virtio-9p.h        |   21 ++++++++++++++++
 9 files changed, 105 insertions(+), 52 deletions(-)

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 5221d6d..8de8abf 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -50,12 +50,18 @@ typedef struct FsCred
 
 struct xattr_operations;
 
+/* FsContext flag values */
+#define PATHNAME_FSCONTEXT 0x1
+
 typedef struct FsContext
 {
+    int flags;
     char *fs_root;
     SecModel fs_sm;
     uid_t uid;
     struct xattr_operations **xops;
+    /* fs driver specific data */
+    void *private;
 } FsContext;
 
 typedef struct V9fsPath {
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 2c50df8..b379f93 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -76,7 +76,7 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
     cred.fc_mode = mode;
     cred.fc_uid = uid;
     cred.fc_gid = gid;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->mkdir(&s->ctx, &fidp->path, name->data,  &cred);
@@ -94,7 +94,7 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -102,7 +102,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
@@ -112,7 +112,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
                 err = 0;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 69fad36..1a99adc 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -21,7 +21,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lstat(&s->ctx, path, stbuf);
@@ -29,7 +29,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -51,7 +51,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
@@ -61,7 +61,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
                 err = 0;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
@@ -88,7 +88,7 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
      * don't change. Read lock is fine because this fid cannot
      * be used by any other operation.
      */
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
@@ -112,7 +112,7 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
@@ -160,7 +160,7 @@ int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->link(&s->ctx, &oldfid->path,
@@ -169,7 +169,7 @@ int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 7f5220e..9c3c9e9 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -23,8 +23,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
     ssize_t len;
 
     buf->data = g_malloc(PATH_MAX);
-    qemu_co_rwlock_rdlock(&s->rename_lock);
-
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             len = s->ops->readlink(&s->ctx, path,
@@ -37,7 +36,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (err) {
         g_free(buf->data);
         buf->data = NULL;
@@ -50,7 +49,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->statfs(&s->ctx, path, stbuf);
@@ -58,7 +57,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -69,7 +68,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
 
     cred_init(&cred);
     cred.fc_mode = mode;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chmod(&s->ctx, path, &cred);
@@ -77,7 +76,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -86,7 +85,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->utimensat(&s->ctx, path, times);
@@ -94,7 +93,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -106,7 +105,7 @@ int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
     cred_init(&cred);
     cred.fc_uid = uid;
     cred.fc_gid = gid;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chown(&s->ctx, path, &cred);
@@ -114,7 +113,7 @@ int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -122,7 +121,7 @@ int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->truncate(&s->ctx, path, size);
@@ -130,7 +129,7 @@ int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -146,7 +145,7 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
     cred.fc_gid  = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
@@ -164,7 +163,7 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -173,7 +172,7 @@ int v9fs_co_remove(V9fsState *s, V9fsPath *path)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->remove(&s->ctx, path->data);
@@ -181,7 +180,7 @@ int v9fs_co_remove(V9fsState *s, V9fsPath *path)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -189,7 +188,7 @@ int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
@@ -197,7 +196,7 @@ int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -244,7 +243,7 @@ int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
     cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
     cred.fc_mode = 0777;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
@@ -263,7 +262,7 @@ int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -275,9 +274,20 @@ int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
                          const char *name, V9fsPath *path)
 {
     int err;
-    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
-    if (err < 0) {
-        err = -errno;
+
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+        if (err < 0) {
+            err = -errno;
+        }
+    } else {
+        v9fs_co_run_in_worker(
+            {
+                err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+                if (err < 0) {
+                    err = -errno;
+                }
+            });
     }
     return err;
 }
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index b723240..dd2e4a5 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -21,7 +21,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->llistxattr(&s->ctx, path, value, size);
@@ -29,7 +29,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -39,7 +39,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lgetxattr(&s->ctx, path,
@@ -49,7 +49,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -59,7 +59,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lsetxattr(&s->ctx, path,
@@ -69,7 +69,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -78,7 +78,7 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
@@ -86,6 +86,6 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 1ffe95b..320ed95 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -124,6 +124,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     memcpy(s->tag, conf->tag, len);
     s->tag_len = len;
     s->ctx.uid = -1;
+    s->ctx.flags = 0;
 
     s->ops = fse->ops;
     s->vdev.get_features = virtio_9p_get_features;
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 61954fe..9559ff6 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -647,6 +647,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
 
 static int local_init(FsContext *ctx)
 {
+    ctx->flags |= PATHNAME_FSCONTEXT;
     return 0;
 }
 
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 82f1db5..2a68953 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -2332,6 +2332,7 @@ out_nofid:
     complete_pdu(s, pdu, err);
 }
 
+/* Only works with path name based fid */
 static void v9fs_remove(void *opaque)
 {
     int32_t fid;
@@ -2347,6 +2348,11 @@ static void v9fs_remove(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
+    /* if fs driver is not path based, return EOPNOTSUPP */
+    if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+        err = -EOPNOTSUPP;
+        goto out_err;
+    }
     /*
      * IF the file is unlinked, we cannot reopen
      * the file later. So don't reclaim fd
@@ -2467,6 +2473,7 @@ out_nofid:
     return err;
 }
 
+/* Only works with path name based fid */
 static void v9fs_rename(void *opaque)
 {
     int32_t fid;
@@ -2486,13 +2493,18 @@ static void v9fs_rename(void *opaque)
         goto out_nofid;
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
-
-    qemu_co_rwlock_wrlock(&s->rename_lock);
+    /* if fs driver is not path based, return EOPNOTSUPP */
+    if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+        err = -EOPNOTSUPP;
+        goto out;
+    }
+    v9fs_path_write_lock(s);
     err = v9fs_complete_rename(s, fidp, newdirfid, &name);
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         err = offset;
     }
+out:
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
@@ -2553,9 +2565,11 @@ static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
     if (err < 0) {
         goto out;
     }
-    /* Only for path based fid  we need to do the below fixup */
-    v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
-                       &newdirfidp->path, new_name);
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        /* Only for path based fid  we need to do the below fixup */
+        v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
+                           &newdirfidp->path, new_name);
+    }
 out:
     if (olddirfidp) {
         put_fid(s, olddirfidp);
@@ -2578,9 +2592,9 @@ static void v9fs_renameat(void *opaque)
     pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
                   &old_name, &newdirfid, &new_name);
 
-    qemu_co_rwlock_wrlock(&s->rename_lock);
+    v9fs_path_write_lock(s);
     err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         err = offset;
     }
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 8c7c3f0..80147d4 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -388,6 +388,27 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
     return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
 }
 
+static inline void v9fs_path_write_lock(V9fsState *s)
+{
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_wrlock(&s->rename_lock);
+    }
+}
+
+static inline void v9fs_path_read_lock(V9fsState *s)
+{
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_rdlock(&s->rename_lock);
+    }
+}
+
+static inline void v9fs_path_unlock(V9fsState *s)
+{
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_unlock(&s->rename_lock);
+    }
+}
+
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
 extern void virtio_9p_set_fd_limit(void);
 extern void v9fs_reclaim_fd(V9fsState *s);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 6/8] hw/9pfs: Avoid unnecessary get_fid in v9fs_clunk
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
                   ` (4 preceding siblings ...)
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 5/8] hw/9pfs: Add fs driver specific details to fscontext Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 7/8] hw/9pfs: Implement TFLUSH operation Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 8/8] hw/9pfs: Add handle based fs driver Aneesh Kumar K.V
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 hw/9pfs/virtio-9p.c |   20 ++++++++++----------
 1 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 2a68953..e51df2a 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -417,7 +417,7 @@ static void put_fid(V9fsState *s, V9fsFidState *fidp)
     }
 }
 
-static int clunk_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
 {
     V9fsFidState **fidpp, *fidp;
 
@@ -426,14 +426,13 @@ static int clunk_fid(V9fsState *s, int32_t fid)
             break;
         }
     }
-
     if (*fidpp == NULL) {
-        return -ENOENT;
+        return NULL;
     }
     fidp = *fidpp;
     *fidpp = fidp->next;
     fidp->clunked = 1;
-    return 0;
+    return fidp;
 }
 
 void v9fs_reclaim_fd(V9fsState *s)
@@ -1700,17 +1699,18 @@ static void v9fs_clunk(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = get_fid(s, fid);
+    fidp = clunk_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = clunk_fid(s, fidp->fid);
-    if (err < 0) {
-        goto out;
-    }
+    /*
+     * Bump the ref so that put_fid will
+     * free the fid.
+     */
+    fidp->ref++;
     err = offset;
-out:
+
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 7/8] hw/9pfs: Implement TFLUSH operation
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
                   ` (5 preceding siblings ...)
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 6/8] hw/9pfs: Avoid unnecessary get_fid in v9fs_clunk Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 8/8] hw/9pfs: Add handle based fs driver Aneesh Kumar K.V
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 hw/9pfs/codir.c            |   44 ++++-
 hw/9pfs/cofile.c           |   68 ++++++--
 hw/9pfs/cofs.c             |   79 +++++++--
 hw/9pfs/coxattr.c          |   24 ++-
 hw/9pfs/virtio-9p-coth.h   |   66 ++++----
 hw/9pfs/virtio-9p-device.c |    1 +
 hw/9pfs/virtio-9p.c        |  412 ++++++++++++++++++++++++--------------------
 hw/9pfs/virtio-9p.h        |   10 +-
 8 files changed, 439 insertions(+), 265 deletions(-)

diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index b379f93..72732e7 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -17,11 +17,15 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
+int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
                       struct dirent **result)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             errno = 0;
@@ -35,10 +39,14 @@ int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
     return err;
 }
 
-off_t v9fs_co_telldir(V9fsState *s, V9fsFidState *fidp)
+off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     off_t err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->telldir(&s->ctx, fidp->fs.dir);
@@ -49,29 +57,41 @@ off_t v9fs_co_telldir(V9fsState *s, V9fsFidState *fidp)
     return err;
 }
 
-void v9fs_co_seekdir(V9fsState *s, V9fsFidState *fidp, off_t offset)
+void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
 {
+    V9fsState *s = pdu->s;
+    if (v9fs_request_cancelled(pdu)) {
+        return;
+    }
     v9fs_co_run_in_worker(
         {
             s->ops->seekdir(&s->ctx, fidp->fs.dir, offset);
         });
 }
 
-void v9fs_co_rewinddir(V9fsState *s, V9fsFidState *fidp)
+void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
 {
+    V9fsState *s = pdu->s;
+    if (v9fs_request_cancelled(pdu)) {
+        return;
+    }
     v9fs_co_run_in_worker(
         {
             s->ops->rewinddir(&s->ctx, fidp->fs.dir);
         });
 }
 
-int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
+int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
                   mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
     V9fsPath path;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
     cred_init(&cred);
     cred.fc_mode = mode;
     cred.fc_uid = uid;
@@ -98,10 +118,14 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
     return err;
 }
 
-int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
+int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -116,16 +140,20 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
-            v9fs_reclaim_fd(s);
+            v9fs_reclaim_fd(pdu);
         }
     }
     return err;
 }
 
-int v9fs_co_closedir(V9fsState *s, DIR *dir)
+int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->closedir(&s->ctx, dir);
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 1a99adc..7ad4bec 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -17,10 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
+int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -33,10 +37,14 @@ int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
     return err;
 }
 
-int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
+int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->fstat(&s->ctx, fd, stbuf);
@@ -47,10 +55,14 @@ int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
     return err;
 }
 
-int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
+int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -65,20 +77,23 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
-            v9fs_reclaim_fd(s);
+            v9fs_reclaim_fd(pdu);
         }
     }
     return err;
 }
 
-int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
+int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
                   int flags, int mode, struct stat *stbuf)
 {
     int err;
     FsCred cred;
     V9fsPath path;
+    V9fsState *s = pdu->s;
 
-
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_mode = mode & 07777;
     cred.fc_uid = fidp->uid;
@@ -116,16 +131,20 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
-            v9fs_reclaim_fd(s);
+            v9fs_reclaim_fd(pdu);
         }
     }
     return err;
 }
 
-int v9fs_co_close(V9fsState *s, int fd)
+int v9fs_co_close(V9fsPDU *pdu, int fd)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->close(&s->ctx, fd);
@@ -139,11 +158,14 @@ int v9fs_co_close(V9fsState *s, int fd)
     return err;
 }
 
-int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
+int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
 {
-    int fd;
-    int err;
+    int fd, err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
@@ -155,11 +177,15 @@ int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
     return err;
 }
 
-int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
+int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
                  V9fsFidState *newdirfid, V9fsString *name)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -173,12 +199,15 @@ int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
     return err;
 }
 
-int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
+int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
                     struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd;
-    int err;
+    int fd, err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
@@ -190,12 +219,15 @@ int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
     return err;
 }
 
-int v9fs_co_preadv(V9fsState *s, V9fsFidState *fidp,
+int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
                    struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd;
-    int err;
+    int fd, err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 9c3c9e9..68745ad 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,11 +17,15 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
+int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
 {
     int err;
     ssize_t len;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     buf->data = g_malloc(PATH_MAX);
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
@@ -45,10 +49,14 @@ int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
     return err;
 }
 
-int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
+int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -61,11 +69,15 @@ int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
     return err;
 }
 
-int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
+int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
 {
     int err;
     FsCred cred;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_mode = mode;
     v9fs_path_read_lock(s);
@@ -80,11 +92,15 @@ int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
     return err;
 }
 
-int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
+int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
                       struct timespec times[2])
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -97,11 +113,15 @@ int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
     return err;
 }
 
-int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
+int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
 {
     int err;
     FsCred cred;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_uid = uid;
     cred.fc_gid = gid;
@@ -117,10 +137,14 @@ int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
     return err;
 }
 
-int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
+int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -133,13 +157,17 @@ int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
     return err;
 }
 
-int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
+int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
                   gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 {
     int err;
     V9fsPath path;
     FsCred cred;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_uid  = uid;
     cred.fc_gid  = gid;
@@ -168,10 +196,14 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
 }
 
 /* Only works with path name based fid */
-int v9fs_co_remove(V9fsState *s, V9fsPath *path)
+int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -184,10 +216,14 @@ int v9fs_co_remove(V9fsState *s, V9fsPath *path)
     return err;
 }
 
-int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
+int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -201,10 +237,14 @@ int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
 }
 
 /* Only work with path name based fid */
-int v9fs_co_rename(V9fsState *s, V9fsPath *oldpath, V9fsPath *newpath)
+int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
@@ -215,11 +255,15 @@ int v9fs_co_rename(V9fsState *s, V9fsPath *oldpath, V9fsPath *newpath)
     return err;
 }
 
-int v9fs_co_renameat(V9fsState *s, V9fsPath *olddirpath, V9fsString *oldname,
+int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
                      V9fsPath *newdirpath, V9fsString *newname)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
@@ -231,14 +275,17 @@ int v9fs_co_renameat(V9fsState *s, V9fsPath *olddirpath, V9fsString *oldname,
     return err;
 }
 
-int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
+int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
                     const char *oldpath, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
     V9fsPath path;
+    V9fsState *s = pdu->s;
 
-
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
@@ -270,10 +317,11 @@ int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
  * For path name based fid we don't block. So we can
  * directly call the fs driver ops.
  */
-int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
+int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
                          const char *name, V9fsPath *path)
 {
     int err;
+    V9fsState *s = pdu->s;
 
     if (s->ctx.flags & PATHNAME_FSCONTEXT) {
         err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
@@ -281,6 +329,9 @@ int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
             err = -errno;
         }
     } else {
+        if (v9fs_request_cancelled(pdu)) {
+            return -EINTR;
+        }
         v9fs_co_run_in_worker(
             {
                 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index dd2e4a5..8a48228 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -17,10 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
+int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -33,12 +37,16 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
     return err;
 }
 
-int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
+int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
                       V9fsString *xattr_name,
                       void *value, size_t size)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -53,12 +61,16 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
     return err;
 }
 
-int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
+int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
                       V9fsString *xattr_name, void *value,
                       size_t size, int flags)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -73,11 +85,15 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
     return err;
 }
 
-int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
+int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path,
                          V9fsString *xattr_name)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index cd94571..4630080 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -56,49 +56,49 @@ typedef struct V9fsThPool {
 
 extern void co_run_in_worker_bh(void *);
 extern int v9fs_init_worker_threads(void);
-extern int v9fs_co_readlink(V9fsState *, V9fsPath *, V9fsString *);
-extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *,
+extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *);
+extern int v9fs_co_readdir_r(V9fsPDU *, V9fsFidState *,
                            struct dirent *, struct dirent **result);
-extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *);
-extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t);
-extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_statfs(V9fsState *, V9fsPath *, struct statfs *);
-extern int v9fs_co_lstat(V9fsState *, V9fsPath *, struct stat *);
-extern int v9fs_co_chmod(V9fsState *, V9fsPath *, mode_t);
-extern int v9fs_co_utimensat(V9fsState *, V9fsPath *, struct timespec [2]);
-extern int v9fs_co_chown(V9fsState *, V9fsPath *, uid_t, gid_t);
-extern int v9fs_co_truncate(V9fsState *, V9fsPath *, off_t);
-extern int v9fs_co_llistxattr(V9fsState *, V9fsPath *, void *, size_t);
-extern int v9fs_co_lgetxattr(V9fsState *, V9fsPath *,
+extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *);
+extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t);
+extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
+extern int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
+extern int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
+extern int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
+extern int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
+extern int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+extern int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
+extern int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
                              V9fsString *, void *, size_t);
-extern int v9fs_co_mknod(V9fsState *, V9fsFidState *, V9fsString *, uid_t,
+extern int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t,
                          gid_t, dev_t, mode_t, struct stat *);
-extern int v9fs_co_mkdir(V9fsState *, V9fsFidState *, V9fsString *,
+extern int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *,
                          mode_t, uid_t, gid_t, struct stat *);
-extern int v9fs_co_remove(V9fsState *, V9fsPath *);
-extern int v9fs_co_rename(V9fsState *, V9fsPath *, V9fsPath *);
-extern int v9fs_co_unlinkat(V9fsState *, V9fsPath *, V9fsString *, int flags);
-extern int v9fs_co_renameat(V9fsState *, V9fsPath *, V9fsString *,
+extern int v9fs_co_remove(V9fsPDU *, V9fsPath *);
+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(V9fsState *, int, struct stat *);
-extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_open2(V9fsState *, V9fsFidState *, V9fsString *,
+extern int v9fs_co_fstat(V9fsPDU *, int, 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 *,
                          gid_t, int, int, struct stat *);
-extern int v9fs_co_lsetxattr(V9fsState *, V9fsPath *, V9fsString *,
+extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
                              void *, size_t, int);
-extern int v9fs_co_lremovexattr(V9fsState *, V9fsPath *, V9fsString *);
-extern int v9fs_co_closedir(V9fsState *, DIR *);
-extern int v9fs_co_close(V9fsState *, int);
-extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, V9fsString *,
+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_fsync(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
                            const char *, gid_t, struct stat *);
-extern int v9fs_co_link(V9fsState *, V9fsFidState *,
+extern int v9fs_co_link(V9fsPDU *, V9fsFidState *,
                         V9fsFidState *, V9fsString *);
-extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
+extern int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *,
                            struct iovec *, int, int64_t);
-extern int v9fs_co_preadv(V9fsState *, V9fsFidState *,
+extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *,
                           struct iovec *, int, int64_t);
-extern int v9fs_co_name_to_path(V9fsState *, V9fsPath *,
+extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
                                 const char *, V9fsPath *);
 #endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 320ed95..513e181 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -58,6 +58,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
                                     sizeof(V9fsState));
     /* initialize pdu allocator */
     QLIST_INIT(&s->free_list);
+    QLIST_INIT(&s->active_list);
     for (i = 0; i < (MAX_REQ - 1); i++) {
         QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
     }
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index e51df2a..c01c31a 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -269,29 +269,30 @@ static size_t v9fs_string_size(V9fsString *str)
 
 /*
  * returns 0 if fid got re-opened, 1 if not, < 0 on error */
-static int v9fs_reopen_fid(V9fsState *s, V9fsFidState *f)
+static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
 {
     int err = 1;
     if (f->fid_type == P9_FID_FILE) {
         if (f->fs.fd == -1) {
             do {
-                err = v9fs_co_open(s, f, f->open_flags);
-            } while (err == -EINTR);
+                err = v9fs_co_open(pdu, f, f->open_flags);
+            } while (err == -EINTR && !pdu->cancelled);
         }
     } else if (f->fid_type == P9_FID_DIR) {
         if (f->fs.dir == NULL) {
             do {
-                err = v9fs_co_opendir(s, f);
-            } while (err == -EINTR);
+                err = v9fs_co_opendir(pdu, f);
+            } while (err == -EINTR && !pdu->cancelled);
         }
     }
     return err;
 }
 
-static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
 {
     int err;
     V9fsFidState *f;
+    V9fsState *s = pdu->s;
 
     for (f = s->fid_list; f; f = f->next) {
         BUG_ON(f->clunked);
@@ -308,7 +309,7 @@ static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
              * while trying to free up some file
              * descriptors.
              */
-            err = v9fs_reopen_fid(s, f);
+            err = v9fs_reopen_fid(pdu, f);
             if (err < 0) {
                 f->ref--;
                 return NULL;
@@ -350,7 +351,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
     return f;
 }
 
-static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     int retval = 0;
 
@@ -368,12 +369,12 @@ static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
         goto free_out;
     }
     if (fidp->fs.xattr.len) {
-        retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+        retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
                                    fidp->fs.xattr.value,
                                    fidp->fs.xattr.len,
                                    fidp->fs.xattr.flags);
     } else {
-        retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+        retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
     }
 free_out:
     v9fs_string_free(&fidp->fs.xattr.name);
@@ -384,28 +385,28 @@ free_value:
     return retval;
 }
 
-static int free_fid(V9fsState *s, V9fsFidState *fidp)
+static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     int retval = 0;
 
     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(s, fidp->fs.fd);
+            retval = v9fs_co_close(pdu, fidp->fs.fd);
         }
     } else if (fidp->fid_type == P9_FID_DIR) {
         if (fidp->fs.dir != NULL) {
-            retval = v9fs_co_closedir(s, fidp->fs.dir);
+            retval = v9fs_co_closedir(pdu, fidp->fs.dir);
         }
     } else if (fidp->fid_type == P9_FID_XATTR) {
-        retval = v9fs_xattr_fid_clunk(s, fidp);
+        retval = v9fs_xattr_fid_clunk(pdu, fidp);
     }
     v9fs_path_free(&fidp->path);
     g_free(fidp);
     return retval;
 }
 
-static void put_fid(V9fsState *s, V9fsFidState *fidp)
+static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     BUG_ON(!fidp->ref);
     fidp->ref--;
@@ -413,7 +414,7 @@ static void put_fid(V9fsState *s, V9fsFidState *fidp)
      * Don't free the fid if it is in reclaim list
      */
     if (!fidp->ref && fidp->clunked) {
-        free_fid(s, fidp);
+        free_fid(pdu, fidp);
     }
 }
 
@@ -435,9 +436,10 @@ static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
     return fidp;
 }
 
-void v9fs_reclaim_fd(V9fsState *s)
+void v9fs_reclaim_fd(V9fsPDU *pdu)
 {
     int reclaim_count = 0;
+    V9fsState *s = pdu->s;
     V9fsFidState *f, *reclaim_list = NULL;
 
     for (f = s->fid_list; f; f = f->next) {
@@ -502,22 +504,23 @@ void v9fs_reclaim_fd(V9fsState *s)
         f = reclaim_list;
         reclaim_list = f->rclm_lst;
         if (f->fid_type == P9_FID_FILE) {
-            v9fs_co_close(s, f->fs_reclaim.fd);
+            v9fs_co_close(pdu, f->fs_reclaim.fd);
         } else if (f->fid_type == P9_FID_DIR) {
-            v9fs_co_closedir(s, f->fs_reclaim.dir);
+            v9fs_co_closedir(pdu, f->fs_reclaim.dir);
         }
         f->rclm_lst = NULL;
         /*
          * Now drop the fid reference, free it
          * if clunked.
          */
-        put_fid(s, f);
+        put_fid(pdu, f);
     }
 }
 
-static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsPath *path)
+static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
 {
     int err;
+    V9fsState *s = pdu->s;
     V9fsFidState *fidp, head_fid;
 
     head_fid.next = s->fid_list;
@@ -530,7 +533,7 @@ static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsPath *path)
             fidp->flags |= FID_NON_RECLAIMABLE;
 
             /* reopen the file/dir if already closed */
-            err = v9fs_reopen_fid(s, fidp);
+            err = v9fs_reopen_fid(pdu, fidp);
             if (err < 0) {
                 return -1;
             }
@@ -590,12 +593,12 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
     }
 }
 
-static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
+static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
 {
     struct stat stbuf;
     int err;
 
-    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (err < 0) {
         return err;
     }
@@ -608,8 +611,9 @@ static V9fsPDU *alloc_pdu(V9fsState *s)
     V9fsPDU *pdu = NULL;
 
     if (!QLIST_EMPTY(&s->free_list)) {
-	pdu = QLIST_FIRST(&s->free_list);
-	QLIST_REMOVE(pdu, next);
+        pdu = QLIST_FIRST(&s->free_list);
+        QLIST_REMOVE(pdu, next);
+        QLIST_INSERT_HEAD(&s->active_list, pdu, next);
     }
     return pdu;
 }
@@ -620,7 +624,14 @@ static void free_pdu(V9fsState *s, V9fsPDU *pdu)
         if (debug_9p_pdu) {
             pprint_pdu(pdu);
         }
-        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+        /*
+         * Cancelled pdu are added back to the freelist
+         * by flush request .
+         */
+        if (!pdu->cancelled) {
+            QLIST_REMOVE(pdu, next);
+            QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+        }
     }
 }
 
@@ -913,6 +924,9 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
     /* FIXME: we should batch these completions */
     virtio_notify(&s->vdev, s->vq);
 
+    /* Now wakeup anybody waiting in flush for this request */
+    qemu_co_queue_next(&pdu->complete);
+
     free_pdu(s, pdu);
 }
 
@@ -1032,7 +1046,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
     return mode;
 }
 
-static int stat_to_v9stat(V9fsState *s, V9fsPath *name,
+static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
                             const struct stat *stbuf,
                             V9fsStat *v9stat)
 {
@@ -1058,7 +1072,7 @@ static int stat_to_v9stat(V9fsState *s, V9fsPath *name,
     v9fs_string_null(&v9stat->extension);
 
     if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_co_readlink(s, name, &v9stat->extension);
+        err = v9fs_co_readlink(pdu, name, &v9stat->extension);
         if (err < 0) {
             return err;
         }
@@ -1239,13 +1253,13 @@ static void v9fs_attach(void *opaque)
         goto out_nofid;
     }
     fidp->uid = n_uname;
-    err = v9fs_co_name_to_path(s, NULL, "/", &fidp->path);
+    err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
     if (err < 0) {
         err = -EINVAL;
         clunk_fid(s, fid);
         goto out;
     }
-    err = fid_to_qid(s, fidp, &qid);
+    err = fid_to_qid(pdu, fidp, &qid);
     if (err < 0) {
         err = -EINVAL;
         clunk_fid(s, fid);
@@ -1254,7 +1268,7 @@ static void v9fs_attach(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&uname);
@@ -1274,16 +1288,16 @@ static void v9fs_stat(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (err < 0) {
         goto out;
     }
-    err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
+    err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
     if (err < 0) {
         goto out;
     }
@@ -1291,7 +1305,7 @@ static void v9fs_stat(void *opaque)
     err = offset;
     v9fs_stat_free(&v9stat);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1310,7 +1324,7 @@ static void v9fs_getattr(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -ENOENT;
         goto out_nofid;
@@ -1319,7 +1333,7 @@ static void v9fs_getattr(void *opaque)
      * Currently we only support BASIC fields in stat, so there is no
      * need to look at request_mask.
      */
-    retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (retval < 0) {
         goto out;
     }
@@ -1327,7 +1341,7 @@ static void v9fs_getattr(void *opaque)
     retval = offset;
     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, retval);
 }
@@ -1356,13 +1370,13 @@ static void v9fs_setattr(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
     if (v9iattr.valid & ATTR_MODE) {
-        err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
+        err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
         if (err < 0) {
             goto out;
         }
@@ -1389,7 +1403,7 @@ static void v9fs_setattr(void *opaque)
         } else {
             times[1].tv_nsec = UTIME_OMIT;
         }
-        err = v9fs_co_utimensat(s, &fidp->path, times);
+        err = v9fs_co_utimensat(pdu, &fidp->path, times);
         if (err < 0) {
             goto out;
         }
@@ -1407,21 +1421,21 @@ static void v9fs_setattr(void *opaque)
         if (!(v9iattr.valid & ATTR_GID)) {
             v9iattr.gid = -1;
         }
-        err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
+        err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
                             v9iattr.gid);
         if (err < 0) {
             goto out;
         }
     }
     if (v9iattr.valid & (ATTR_SIZE)) {
-        err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
+        err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
         if (err < 0) {
             goto out;
         }
     }
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1466,7 +1480,7 @@ static void v9fs_walk(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -1480,11 +1494,11 @@ static void v9fs_walk(void *opaque)
     v9fs_path_copy(&dpath, &fidp->path);
     v9fs_path_copy(&path, &fidp->path);
     for (name_idx = 0; name_idx < nwnames; name_idx++) {
-        err = v9fs_co_name_to_path(s, &dpath, wnames[name_idx].data, &path);
+        err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_lstat(s, &path, &stbuf);
+        err = v9fs_co_lstat(pdu, &path, &stbuf);
         if (err < 0) {
             goto out;
         }
@@ -1505,9 +1519,9 @@ static void v9fs_walk(void *opaque)
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
     if (newfidp) {
-        put_fid(s, newfidp);
+        put_fid(pdu, newfidp);
     }
     v9fs_path_free(&dpath);
     v9fs_path_free(&path);
@@ -1523,16 +1537,17 @@ out_nofid:
     return;
 }
 
-static int32_t get_iounit(V9fsState *s, V9fsPath *path)
+static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
 {
     struct statfs stbuf;
     int32_t iounit = 0;
+    V9fsState *s = pdu->s;
 
     /*
      * iounit should be multiples of f_bsize (host filesystem block size
      * and as well as less than (client msize - P9_IOHDRSZ))
      */
-    if (!v9fs_co_statfs(s, path, &stbuf)) {
+    if (!v9fs_co_statfs(pdu, path, &stbuf)) {
         iounit = stbuf.f_bsize;
         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
     }
@@ -1561,20 +1576,20 @@ static void v9fs_open(void *opaque)
     } else {
         pdu_unmarshal(pdu, offset, "db", &fid, &mode);
     }
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
 
-    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (err < 0) {
         goto out;
     }
     stat_to_qid(&stbuf, &qid);
     if (S_ISDIR(stbuf.st_mode)) {
-        err = v9fs_co_opendir(s, fidp);
+        err = v9fs_co_opendir(pdu, fidp);
         if (err < 0) {
             goto out;
         }
@@ -1590,7 +1605,7 @@ static void v9fs_open(void *opaque)
         } else {
             flags = omode_to_uflags(mode);
         }
-        err = v9fs_co_open(s, fidp, flags);
+        err = v9fs_co_open(pdu, fidp, flags);
         if (err < 0) {
             goto out;
         }
@@ -1603,12 +1618,12 @@ static void v9fs_open(void *opaque)
              */
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
-        iounit = get_iounit(s, &fidp->path);
+        iounit = get_iounit(pdu, &fidp->path);
         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
         err = offset;
     }
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1629,7 +1644,7 @@ static void v9fs_lcreate(void *opaque)
     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
                   &mode, &gid);
 
-    fidp = get_fid(pdu->s, dfid);
+    fidp = get_fid(pdu, dfid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -1637,8 +1652,7 @@ static void v9fs_lcreate(void *opaque)
 
     /* Ignore direct disk access hint until the server supports it. */
     flags &= ~O_DIRECT;
-
-    err = v9fs_co_open2(pdu->s, fidp, &name, gid,
+    err = v9fs_co_open2(pdu, fidp, &name, gid,
                         flags | O_CREAT, mode, &stbuf);
     if (err < 0) {
         goto out;
@@ -1652,12 +1666,12 @@ static void v9fs_lcreate(void *opaque)
          */
         fidp->flags |= FID_NON_RECLAIMABLE;
     }
-    iounit =  get_iounit(pdu->s, &fidp->path);
+    iounit =  get_iounit(pdu, &fidp->path);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
@@ -1674,16 +1688,16 @@ static void v9fs_fsync(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fsync(s, fidp, datasync);
+    err = v9fs_co_fsync(pdu, fidp, datasync);
     if (!err) {
         err = offset;
     }
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1711,7 +1725,7 @@ static void v9fs_clunk(void *opaque)
     fidp->ref++;
     err = offset;
 
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1740,7 +1754,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
     return offset;
 }
 
-static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
+static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
                                      V9fsFidState *fidp, int32_t max_count)
 {
     V9fsPath path;
@@ -1752,7 +1766,7 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
     struct dirent *dent, *result;
 
     /* save the directory position */
-    saved_dir_pos = v9fs_co_telldir(s, fidp);
+    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
     if (saved_dir_pos < 0) {
         return saved_dir_pos;
     }
@@ -1761,19 +1775,19 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
 
     while (1) {
         v9fs_path_init(&path);
-        err = v9fs_co_readdir_r(s, fidp, dent, &result);
+        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
         if (err || !result) {
             break;
         }
-        err = v9fs_co_name_to_path(s, &fidp->path, dent->d_name, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_lstat(s, &path, &stbuf);
+        err = v9fs_co_lstat(pdu, &path, &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = stat_to_v9stat(s, &path, &stbuf, &v9stat);
+        err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
         if (err < 0) {
             goto out;
         }
@@ -1781,7 +1795,7 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
         len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
         if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
             /* Ran out of buffer. Set dir back to old position and return */
-            v9fs_co_seekdir(s, fidp, saved_dir_pos);
+            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
             v9fs_stat_free(&v9stat);
             v9fs_path_free(&path);
             g_free(dent);
@@ -1815,7 +1829,7 @@ static void v9fs_read(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -1823,9 +1837,9 @@ static void v9fs_read(void *opaque)
     if (fidp->fid_type == P9_FID_DIR) {
 
         if (off == 0) {
-            v9fs_co_rewinddir(s, fidp);
+            v9fs_co_rewinddir(pdu, fidp);
         }
-        count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
+        count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
         if (count < 0) {
             err = count;
             goto out;
@@ -1848,12 +1862,12 @@ static void v9fs_read(void *opaque)
             }
             /* Loop in case of EINTR */
             do {
-                len = v9fs_co_preadv(s, fidp, sg, cnt, off);
+                len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
                 if (len >= 0) {
                     off   += len;
                     count += len;
                 }
-            } while (len == -EINTR);
+            } while (len == -EINTR && !pdu->cancelled);
             if (len < 0) {
                 /* IO error return the error */
                 err = len;
@@ -1870,7 +1884,7 @@ static void v9fs_read(void *opaque)
         err = -EINVAL;
     }
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1884,7 +1898,7 @@ static size_t v9fs_readdir_data_size(V9fsString *name)
     return 24 + v9fs_string_size(name);
 }
 
-static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
+static int v9fs_do_readdir(V9fsPDU *pdu,
                            V9fsFidState *fidp, int32_t max_count)
 {
     size_t size;
@@ -1896,7 +1910,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
     struct dirent *dent, *result;
 
     /* save the directory position */
-    saved_dir_pos = v9fs_co_telldir(s, fidp);
+    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
     if (saved_dir_pos < 0) {
         return saved_dir_pos;
     }
@@ -1904,7 +1918,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
     dent = g_malloc(sizeof(struct dirent));
 
     while (1) {
-        err = v9fs_co_readdir_r(s, fidp, dent, &result);
+        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
         if (err || !result) {
             break;
         }
@@ -1912,7 +1926,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
         v9fs_string_sprintf(&name, "%s", dent->d_name);
         if ((count + v9fs_readdir_data_size(&name)) > max_count) {
             /* Ran out of buffer. Set dir back to old position and return */
-            v9fs_co_seekdir(s, fidp, saved_dir_pos);
+            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
             v9fs_string_free(&name);
             g_free(dent);
             return count;
@@ -1956,7 +1970,7 @@ static void v9fs_readdir(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -EINVAL;
         goto out_nofid;
@@ -1966,11 +1980,11 @@ static void v9fs_readdir(void *opaque)
         goto out;
     }
     if (initial_offset == 0) {
-        v9fs_co_rewinddir(s, fidp);
+        v9fs_co_rewinddir(pdu, fidp);
     } else {
-        v9fs_co_seekdir(s, fidp, initial_offset);
+        v9fs_co_seekdir(pdu, fidp, initial_offset);
     }
-    count = v9fs_do_readdir(s, pdu, fidp, max_count);
+    count = v9fs_do_readdir(pdu, fidp, max_count);
     if (count < 0) {
         retval = count;
         goto out;
@@ -1979,7 +1993,7 @@ static void v9fs_readdir(void *opaque)
     retval += pdu_marshal(pdu, offset, "d", count);
     retval += count;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, retval);
 }
@@ -2046,7 +2060,7 @@ static void v9fs_write(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -2073,12 +2087,12 @@ static void v9fs_write(void *opaque)
         }
         /* Loop in case of EINTR */
         do {
-            len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
+            len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
             if (len >= 0) {
                 off   += len;
                 total += len;
             }
-        } while (len == -EINTR);
+        } while (len == -EINTR && !pdu->cancelled);
         if (len < 0) {
             /* IO error return the error */
             err = len;
@@ -2089,7 +2103,7 @@ static void v9fs_write(void *opaque)
     offset += pdu_marshal(pdu, offset, "d", total);
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -2115,57 +2129,57 @@ static void v9fs_create(void *opaque)
     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
                   &perm, &mode, &extension);
 
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
     if (perm & P9_STAT_MODE_DIR) {
-        err = v9fs_co_mkdir(pdu->s, fidp, &name, perm & 0777,
+        err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
                             fidp->uid, -1, &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
-        err = v9fs_co_opendir(pdu->s, fidp);
+        err = v9fs_co_opendir(pdu, fidp);
         if (err < 0) {
             goto out;
         }
         fidp->fid_type = P9_FID_DIR;
     } else if (perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_co_symlink(pdu->s, fidp, &name,
+        err = v9fs_co_symlink(pdu, fidp, &name,
                               extension.data, -1 , &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_LINK) {
         int32_t ofid = atoi(extension.data);
-        V9fsFidState *ofidp = get_fid(pdu->s, ofid);
+        V9fsFidState *ofidp = get_fid(pdu, ofid);
         if (ofidp == NULL) {
             err = -EINVAL;
             goto out;
         }
-        err = v9fs_co_link(pdu->s, ofidp, fidp, &name);
-        put_fid(pdu->s, ofidp);
+        err = v9fs_co_link(pdu, ofidp, fidp, &name);
+        put_fid(pdu, ofidp);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             fidp->fid_type = P9_FID_NONE;
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
-        err = v9fs_co_lstat(pdu->s, &fidp->path, &stbuf);
+        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
         if (err < 0) {
             fidp->fid_type = P9_FID_NONE;
             goto out;
@@ -2193,40 +2207,40 @@ static void v9fs_create(void *opaque)
         }
 
         nmode |= perm & 0777;
-        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             makedev(major, minor), nmode, &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
-        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             0, S_IFIFO | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_SOCKET) {
-        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             0, S_IFSOCK | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else {
-        err = v9fs_co_open2(pdu->s, fidp, &name, -1,
+        err = v9fs_co_open2(pdu, fidp, &name, -1,
                             omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
         if (err < 0) {
             goto out;
@@ -2241,12 +2255,12 @@ static void v9fs_create(void *opaque)
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
     }
-    iounit = get_iounit(pdu->s, &fidp->path);
+    iounit = get_iounit(pdu, &fidp->path);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
@@ -2269,12 +2283,12 @@ static void v9fs_symlink(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 
-    dfidp = get_fid(pdu->s, dfid);
+    dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
-    err = v9fs_co_symlink(pdu->s, dfidp, &name, symname.data, gid, &stbuf);
+    err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2282,7 +2296,7 @@ static void v9fs_symlink(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
-    put_fid(pdu->s, dfidp);
+    put_fid(pdu, dfidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
@@ -2291,9 +2305,28 @@ out_nofid:
 
 static void v9fs_flush(void *opaque)
 {
+    int16_t tag;
+    size_t offset = 7;
+    V9fsPDU *cancel_pdu;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    /* A nop call with no return */
+
+    pdu_unmarshal(pdu, offset, "w", &tag);
+
+    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
+        if (cancel_pdu->tag == tag) {
+            break;
+        }
+    }
+    if (cancel_pdu) {
+        cancel_pdu->cancelled = 1;
+        /*
+         * Wait for pdu to complete.
+         */
+        qemu_co_queue_wait(&cancel_pdu->complete);
+        cancel_pdu->cancelled = 0;
+        free_pdu(pdu->s, cancel_pdu);
+    }
     complete_pdu(s, pdu, 7);
     return;
 }
@@ -2310,23 +2343,23 @@ static void v9fs_link(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
 
-    dfidp = get_fid(s, dfid);
+    dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
 
-    oldfidp = get_fid(s, oldfid);
+    oldfidp = get_fid(pdu, oldfid);
     if (oldfidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-    err = v9fs_co_link(s, oldfidp, dfidp, &name);
+    err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
     if (!err) {
         err = offset;
     }
 out:
-    put_fid(s, dfidp);
+    put_fid(pdu, dfidp);
 out_nofid:
     v9fs_string_free(&name);
     complete_pdu(s, pdu, err);
@@ -2343,7 +2376,7 @@ static void v9fs_remove(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -2357,18 +2390,18 @@ static void v9fs_remove(void *opaque)
      * IF the file is unlinked, we cannot reopen
      * the file later. So don't reclaim fd
      */
-    err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
+    err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_co_remove(pdu->s, &fidp->path);
+    err = v9fs_co_remove(pdu, &fidp->path);
     if (!err) {
         err = offset;
     }
 out_err:
     /* For TREMOVE we need to clunk the fid even on failed remove */
     clunk_fid(pdu->s, fidp->fid);
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
@@ -2385,7 +2418,7 @@ static void v9fs_unlinkat(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
 
-    dfidp = get_fid(pdu->s, dfid);
+    dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -2395,20 +2428,20 @@ static void v9fs_unlinkat(void *opaque)
      * the file later. So don't reclaim fd
      */
     v9fs_path_init(&path);
-    err = v9fs_co_name_to_path(pdu->s, &dfidp->path, name.data, &path);
+    err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_mark_fids_unreclaim(pdu->s, &path);
+    err = v9fs_mark_fids_unreclaim(pdu, &path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_co_unlinkat(pdu->s, &dfidp->path, &name, flags);
+    err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
     if (!err) {
         err = offset;
     }
 out_err:
-    put_fid(pdu->s, dfidp);
+    put_fid(pdu, dfidp);
     v9fs_path_free(&path);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
@@ -2417,25 +2450,26 @@ out_nofid:
 
 
 /* Only works with path name based fid */
-static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
+static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
                                 int32_t newdirfid, V9fsString *name)
 {
     char *end;
     int err = 0;
     V9fsPath new_path;
     V9fsFidState *tfidp;
+    V9fsState *s = pdu->s;
     V9fsFidState *dirfidp = NULL;
     char *old_name, *new_name;
 
     v9fs_path_init(&new_path);
     if (newdirfid != -1) {
-        dirfidp = get_fid(s, newdirfid);
+        dirfidp = get_fid(pdu, newdirfid);
         if (dirfidp == NULL) {
             err = -ENOENT;
             goto out_nofid;
         }
         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
-        v9fs_co_name_to_path(s, &dirfidp->path, name->data, &new_path);
+        v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
     } else {
         old_name = fidp->path.data;
         end = strrchr(old_name, '/');
@@ -2447,10 +2481,10 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
         new_name = g_malloc0(end - old_name + name->size + 1);
         strncat(new_name, old_name, end - old_name);
         strncat(new_name + (end - old_name), name->data, name->size);
-        v9fs_co_name_to_path(s, NULL, new_name, &new_path);
+        v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
         g_free(new_name);
     }
-    err = v9fs_co_rename(s, &fidp->path, &new_path);
+    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
     if (err < 0) {
         goto out;
     }
@@ -2466,7 +2500,7 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
     }
 out:
     if (dirfidp) {
-        put_fid(s, dirfidp);
+        put_fid(pdu, dirfidp);
     }
     v9fs_path_free(&new_path);
 out_nofid:
@@ -2487,7 +2521,7 @@ static void v9fs_rename(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -2499,30 +2533,31 @@ static void v9fs_rename(void *opaque)
         goto out;
     }
     v9fs_path_write_lock(s);
-    err = v9fs_complete_rename(s, fidp, newdirfid, &name);
+    err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
     v9fs_path_unlock(s);
     if (!err) {
         err = offset;
     }
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
 
-static void v9fs_fix_fid_paths(V9fsState *s, V9fsPath *olddir,
+static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
                                V9fsString *old_name, V9fsPath *newdir,
                                V9fsString *new_name)
 {
     V9fsFidState *tfidp;
     V9fsPath oldpath, newpath;
+    V9fsState *s = pdu->s;
 
 
     v9fs_path_init(&oldpath);
     v9fs_path_init(&newpath);
-    v9fs_co_name_to_path(s, olddir, old_name->data, &oldpath);
-    v9fs_co_name_to_path(s, newdir, new_name->data, &newpath);
+    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
+    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
 
     /*
      * Fixup fid's pointing to the old name to
@@ -2538,44 +2573,45 @@ static void v9fs_fix_fid_paths(V9fsState *s, V9fsPath *olddir,
     v9fs_path_free(&newpath);
 }
 
-static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
+static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
                                   V9fsString *old_name, int32_t newdirfid,
                                   V9fsString *new_name)
 {
     int err = 0;
+    V9fsState *s = pdu->s;
     V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
 
-    olddirfidp = get_fid(s, olddirfid);
+    olddirfidp = get_fid(pdu, olddirfid);
     if (olddirfidp == NULL) {
         err = -ENOENT;
         goto out;
     }
     if (newdirfid != -1) {
-        newdirfidp = get_fid(s, newdirfid);
+        newdirfidp = get_fid(pdu, newdirfid);
         if (newdirfidp == NULL) {
             err = -ENOENT;
             goto out;
         }
     } else {
-        newdirfidp = get_fid(s, olddirfid);
+        newdirfidp = get_fid(pdu, olddirfid);
     }
 
-    err = v9fs_co_renameat(s, &olddirfidp->path, old_name,
+    err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
                            &newdirfidp->path, new_name);
     if (err < 0) {
         goto out;
     }
     if (s->ctx.flags & PATHNAME_FSCONTEXT) {
         /* Only for path based fid  we need to do the below fixup */
-        v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
+        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
                            &newdirfidp->path, new_name);
     }
 out:
     if (olddirfidp) {
-        put_fid(s, olddirfidp);
+        put_fid(pdu, olddirfidp);
     }
     if (newdirfidp) {
-        put_fid(s, newdirfidp);
+        put_fid(pdu, newdirfidp);
     }
     return err;
 }
@@ -2593,7 +2629,8 @@ static void v9fs_renameat(void *opaque)
                   &old_name, &newdirfid, &new_name);
 
     v9fs_path_write_lock(s);
-    err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+    err = v9fs_complete_renameat(pdu, olddirfid,
+                                 &old_name, newdirfid, &new_name);
     v9fs_path_unlock(s);
     if (!err) {
         err = offset;
@@ -2617,19 +2654,19 @@ static void v9fs_wstat(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
     /* do we need to sync the file? */
     if (donttouch_stat(&v9stat)) {
-        err = v9fs_co_fsync(s, fidp, 0);
+        err = v9fs_co_fsync(pdu, fidp, 0);
         goto out;
     }
     if (v9stat.mode != -1) {
         uint32_t v9_mode;
-        err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
         if (err < 0) {
             goto out;
         }
@@ -2640,7 +2677,7 @@ static void v9fs_wstat(void *opaque)
             err = -EIO;
             goto out;
         }
-        err = v9fs_co_chmod(s, &fidp->path,
+        err = v9fs_co_chmod(pdu, &fidp->path,
                             v9mode_to_mode(v9stat.mode,
                                            &v9stat.extension));
         if (err < 0) {
@@ -2661,32 +2698,32 @@ static void v9fs_wstat(void *opaque)
         } else {
             times[1].tv_nsec = UTIME_OMIT;
         }
-        err = v9fs_co_utimensat(s, &fidp->path, times);
+        err = v9fs_co_utimensat(pdu, &fidp->path, times);
         if (err < 0) {
             goto out;
         }
     }
     if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
-        err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
+        err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
         if (err < 0) {
             goto out;
         }
     }
     if (v9stat.name.size != 0) {
-        err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
+        err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
         if (err < 0) {
             goto out;
         }
     }
     if (v9stat.length != -1) {
-        err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
+        err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
         if (err < 0) {
             goto out;
         }
     }
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     v9fs_stat_free(&v9stat);
     complete_pdu(s, pdu, err);
@@ -2748,19 +2785,19 @@ static void v9fs_statfs(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -ENOENT;
         goto out_nofid;
     }
-    retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
+    retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
     if (retval < 0) {
         goto out;
     }
     retval = offset;
     retval += v9fs_fill_statfs(s, pdu, &stbuf);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, retval);
     return;
@@ -2785,12 +2822,12 @@ static void v9fs_mknod(void *opaque)
     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
                   &major, &minor, &gid);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_mknod(s, fidp, &name, fidp->uid, gid,
+    err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
                         makedev(major, minor), mode, &stbuf);
     if (err < 0) {
         goto out;
@@ -2799,7 +2836,7 @@ static void v9fs_mknod(void *opaque)
     err = offset;
     err += pdu_marshal(pdu, offset, "Q", &qid);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
@@ -2835,18 +2872,18 @@ static void v9fs_lock(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
     if (err < 0) {
         goto out;
     }
     status = P9_LOCK_SUCCESS;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     err = offset;
     err += pdu_marshal(pdu, offset, "b", status);
@@ -2874,12 +2911,12 @@ static void v9fs_getlock(void *opaque)
                   &glock->start, &glock->length, &glock->proc_id,
                   &glock->client_id);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2889,7 +2926,7 @@ static void v9fs_getlock(void *opaque)
                           &glock->client_id);
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&glock->client_id);
@@ -2911,12 +2948,12 @@ static void v9fs_mkdir(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_mkdir(pdu->s, fidp, &name, mode, fidp->uid, gid, &stbuf);
+    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2924,7 +2961,7 @@ static void v9fs_mkdir(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
@@ -2943,7 +2980,7 @@ static void v9fs_xattrwalk(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
-    file_fidp = get_fid(s, fid);
+    file_fidp = get_fid(pdu, fid);
     if (file_fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -2958,7 +2995,7 @@ static void v9fs_xattrwalk(void *opaque)
         /*
          * listxattr request. Get the size first
          */
-        size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
+        size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
         if (size < 0) {
             err = size;
             clunk_fid(s, xattr_fidp->fid);
@@ -2972,7 +3009,7 @@ static void v9fs_xattrwalk(void *opaque)
         xattr_fidp->fs.xattr.copied_len = -1;
         if (size) {
             xattr_fidp->fs.xattr.value = g_malloc(size);
-            err = v9fs_co_llistxattr(s, &xattr_fidp->path,
+            err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
                                      xattr_fidp->fs.xattr.value,
                                      xattr_fidp->fs.xattr.len);
             if (err < 0) {
@@ -2987,7 +3024,7 @@ static void v9fs_xattrwalk(void *opaque)
          * specific xattr fid. We check for xattr
          * presence also collect the xattr size
          */
-        size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
+        size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
                                  &name, NULL, 0);
         if (size < 0) {
             err = size;
@@ -3002,7 +3039,7 @@ static void v9fs_xattrwalk(void *opaque)
         xattr_fidp->fs.xattr.copied_len = -1;
         if (size) {
             xattr_fidp->fs.xattr.value = g_malloc(size);
-            err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
+            err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
                                     &name, xattr_fidp->fs.xattr.value,
                                     xattr_fidp->fs.xattr.len);
             if (err < 0) {
@@ -3014,9 +3051,9 @@ static void v9fs_xattrwalk(void *opaque)
         err = offset;
     }
 out:
-    put_fid(s, file_fidp);
+    put_fid(pdu, file_fidp);
     if (xattr_fidp) {
-        put_fid(s, xattr_fidp);
+        put_fid(pdu, xattr_fidp);
     }
 out_nofid:
     complete_pdu(s, pdu, err);
@@ -3039,7 +3076,7 @@ static void v9fs_xattrcreate(void *opaque)
     pdu_unmarshal(pdu, offset, "dsqd",
                   &fid, &name, &size, &flags);
 
-    file_fidp = get_fid(s, fid);
+    file_fidp = get_fid(pdu, fid);
     if (file_fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -3058,7 +3095,7 @@ static void v9fs_xattrcreate(void *opaque)
         xattr_fidp->fs.xattr.value = NULL;
     }
     err = offset;
-    put_fid(s, file_fidp);
+    put_fid(pdu, file_fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
@@ -3074,14 +3111,14 @@ static void v9fs_readlink(void *opaque)
     V9fsFidState *fidp;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
 
     v9fs_string_init(&target);
-    err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
+    err = v9fs_co_readlink(pdu, &fidp->path, &target);
     if (err < 0) {
         goto out;
     }
@@ -3089,7 +3126,7 @@ static void v9fs_readlink(void *opaque)
     err = offset;
     v9fs_string_free(&target);
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
@@ -3173,6 +3210,7 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
         memcpy(&pdu->size, ptr, 4);
         pdu->id = ptr[4];
         memcpy(&pdu->tag, ptr + 5, 2);
+        qemu_co_queue_init(&pdu->complete);
         submit_pdu(s, pdu);
     }
     free_pdu(s, pdu);
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 80147d4..60b8a56 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -131,6 +131,8 @@ struct V9fsPDU
     uint32_t size;
     uint16_t tag;
     uint8_t id;
+    uint8_t cancelled;
+    CoQueue complete;
     VirtQueueElement elem;
     struct V9fsState *s;
     QLIST_ENTRY(V9fsPDU) next;
@@ -231,6 +233,7 @@ typedef struct V9fsState
     VirtQueue *vq;
     V9fsPDU pdus[MAX_REQ];
     QLIST_HEAD(, V9fsPDU) free_list;
+    QLIST_HEAD(, V9fsPDU) active_list;
     V9fsFidState *fid_list;
     FileOperations *ops;
     FsContext ctx;
@@ -409,9 +412,14 @@ static inline void v9fs_path_unlock(V9fsState *s)
     }
 }
 
+static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
+{
+    return pdu->cancelled;
+}
+
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
 extern void virtio_9p_set_fd_limit(void);
-extern void v9fs_reclaim_fd(V9fsState *s);
+extern void v9fs_reclaim_fd(V9fsPDU *pdu);
 extern void v9fs_string_init(V9fsString *str);
 extern void v9fs_string_free(V9fsString *str);
 extern void v9fs_string_null(V9fsString *str);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 8/8] hw/9pfs: Add handle based fs driver
  2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
                   ` (6 preceding siblings ...)
  2011-09-09 10:54 ` [Qemu-devel] [PATCH 7/8] hw/9pfs: Implement TFLUSH operation Aneesh Kumar K.V
@ 2011-09-09 10:54 ` Aneesh Kumar K.V
  7 siblings, 0 replies; 9+ messages in thread
From: Aneesh Kumar K.V @ 2011-09-09 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Aneesh Kumar K.V

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 Makefile.objs              |    8 +-
 fsdev/qemu-fsdev.c         |    1 +
 fsdev/qemu-fsdev.h         |    1 +
 hw/9pfs/virtio-9p-handle.c |  611 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 617 insertions(+), 4 deletions(-)
 create mode 100644 hw/9pfs/virtio-9p-handle.c

diff --git a/Makefile.objs b/Makefile.objs
index 26b885b..d315d01 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -302,11 +302,11 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o
-9pfs-nested-$(CONFIG_VIRTFS) +=  virtio-9p-local.o virtio-9p-xattr.o
-9pfs-nested-$(CONFIG_VIRTFS) +=   virtio-9p-xattr-user.o virtio-9p-posix-acl.o
+9pfs-nested-$(CONFIG_VIRTFS)  = virtio-9p.o virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
-9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o
+9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
 
 hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
 $(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 336d7e4..768819f 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -23,6 +23,7 @@ static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
 
 static FsTypeTable FsTypes[] = {
     { .name = "local", .ops = &local_ops},
+    { .name = "handle", .ops = &handle_ops},
 };
 
 int qemu_fsdev_add(QemuOpts *opts)
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index f9f08d3..e04931a 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -52,4 +52,5 @@ typedef struct FsTypeListEntry {
 int qemu_fsdev_add(QemuOpts *opts);
 FsTypeEntry *get_fsdev_fsentry(char *id);
 extern FileOperations local_ops;
+extern FileOperations handle_ops;
 #endif
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
new file mode 100644
index 0000000..5c8b5ed
--- /dev/null
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -0,0 +1,611 @@
+/*
+ * Virtio 9p handle callback
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *    Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <attr/xattr.h>
+#include <unistd.h>
+
+struct handle_data {
+    int mountfd;
+    int handle_bytes;
+};
+
+#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14
+struct file_handle {
+        unsigned int handle_bytes;
+        int handle_type;
+        unsigned char handle[0];
+};
+#endif
+
+#ifndef AT_EMPTY_PATH
+#define AT_EMPTY_PATH   0x1000  /* Allow empty relative pathname */
+#endif
+#ifndef O_PATH
+#define O_PATH    010000000
+#endif
+
+#ifndef __NR_name_to_handle_at
+#if defined(__i386__)
+#define __NR_name_to_handle_at  341
+#define __NR_open_by_handle_at  342
+#elif defined(__x86_64__)
+#define __NR_name_to_handle_at  303
+#define __NR_open_by_handle_at  304
+#endif
+#endif
+
+#ifdef __NR_name_to_handle_at
+static inline int name_to_handle(int dirfd, const char *name,
+                                 struct file_handle *fh, int *mnt_id, int flags)
+{
+    return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags);
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+    return syscall(__NR_open_by_handle_at, mountfd, fh, flags);
+}
+#else
+static inline int name_to_handle(int dirfd, const char *name,
+                                 struct file_handle *fh, int *mnt_id, int flags)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+    errno = ENOSYS;
+    return -1;
+}
+#endif
+
+static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
+{
+    int fd, ret;
+    fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);;
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchmod(fd, credp->fc_mode & 07777);
+    if (ret < 0) {
+        goto err_out;
+    }
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+err_out:
+    close(fd);
+    return ret;
+}
+
+
+static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
+                        struct stat *stbuf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+                               char *buf, size_t bufsz)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = readlinkat(fd, "", buf, bufsz);
+    close(fd);
+    return ret;
+}
+
+static int handle_close(FsContext *ctx, int fd)
+{
+    return close(fd);
+}
+
+static int handle_closedir(FsContext *ctx, DIR *dir)
+{
+    return closedir(dir);
+}
+
+static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+{
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    return open_by_handle(data->mountfd, fs_path->data, flags);
+}
+
+static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path)
+{
+    int fd;
+    fd = handle_open(ctx, fs_path, O_DIRECTORY);
+    if (fd < 0) {
+        return NULL;
+    }
+    return fdopendir(fd);
+}
+
+static void handle_rewinddir(FsContext *ctx, DIR *dir)
+{
+    return rewinddir(dir);
+}
+
+static off_t handle_telldir(FsContext *ctx, DIR *dir)
+{
+    return telldir(dir);
+}
+
+static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+                            struct dirent **result)
+{
+    return readdir_r(dir, entry, result);
+}
+
+static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off)
+{
+    return seekdir(dir, off);
+}
+
+static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+                             int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return preadv(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+                              int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return pwritev(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return writev(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchmod(fd, credp->fc_mode);
+    close(fd);
+    return ret;
+}
+
+static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
+    if (!ret) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = mkdirat(dirfd, name, credp->fc_mode);
+    if (!ret) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+{
+    return fstat(fd, stbuf);
+}
+
+static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+                       int flags, FsCred *credp)
+{
+    int ret;
+    int dirfd, fd;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
+    if (fd >= 0) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+        if (ret < 0) {
+            close(fd);
+            fd = ret;
+        }
+    }
+    close(dirfd);
+    return fd;
+}
+
+
+static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
+                          V9fsPath *dir_path, const char *name, FsCred *credp)
+{
+    int fd, dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = symlinkat(oldpath, dirfd, name);
+    if (!ret) {
+        fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
+        if (fd < 0) {
+            ret = fd;
+            goto err_out;
+        }
+        ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+        close(fd);
+    }
+err_out:
+    close(dirfd);
+    return ret;
+}
+
+static int handle_link(FsContext *ctx, V9fsPath *oldpath,
+                       V9fsPath *dirpath, const char *name)
+{
+    int oldfd, newdirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
+    if (oldfd < 0) {
+        return oldfd;
+    }
+    newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
+    if (newdirfd < 0) {
+        close(oldfd);
+        return newdirfd;
+    }
+    ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
+    close(newdirfd);
+    close(oldfd);
+    return ret;
+}
+
+static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = ftruncate(fd, size);
+    close(fd);
+    return ret;
+}
+
+static int handle_rename(FsContext *ctx, const char *oldpath,
+                         const char *newpath)
+{
+    errno = EOPNOTSUPP;
+    return -1;
+}
+
+static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+    close(fd);
+    return ret;
+}
+
+static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
+                            const struct timespec *buf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = futimens(fd, buf);
+    close(fd);
+    return ret;
+}
+
+static int handle_remove(FsContext *ctx, const char *path)
+{
+    errno = EOPNOTSUPP;
+    return -1;
+}
+
+static int handle_fsync(FsContext *ctx, int fd, int datasync)
+{
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
+}
+
+static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
+                         struct statfs *stbuf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fstatfs(fd, stbuf);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
+                                const char *name, void *value, size_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fgetxattr(fd, name, value, size);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
+                                 void *value, size_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = flistxattr(fd, value, size);
+    close(fd);
+    return ret;
+}
+
+static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fsetxattr(fd, name, value, size, flags);
+    close(fd);
+    return ret;
+}
+
+static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+                               const char *name)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fremovexattr(fd, name);
+    close(fd);
+    return ret;
+}
+
+static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                              const char *name, V9fsPath *target)
+{
+    char buffer[PATH_MAX];
+    struct file_handle *fh;
+    int dirfd, ret, mnt_id;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    /* "." and ".." are not allowed */
+    if (!strcmp(name, ".") || !strcmp(name, "..")) {
+        errno = EINVAL;
+        return -1;
+
+    }
+    if (dir_path) {
+        dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    } else {
+        /* relative to export root */
+        dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
+    }
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
+    fh->handle_bytes = data->handle_bytes;
+    /* add a "./" at the begining of the path */
+    snprintf(buffer, PATH_MAX, "./%s", name);
+    /* flag = 0 imply don't follow symlink */
+    ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
+    if (!ret) {
+        target->data = (char *)fh;
+        target->size = sizeof(struct file_handle) + data->handle_bytes;
+    } else {
+        g_free(fh);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
+                           const char *old_name, V9fsPath *newdir,
+                           const char *new_name)
+{
+    int olddirfd, newdirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
+    if (olddirfd < 0) {
+        return olddirfd;
+    }
+    newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
+    if (newdirfd < 0) {
+        close(olddirfd);
+        return newdirfd;
+    }
+    ret = renameat(olddirfd, old_name, newdirfd, new_name);
+    close(newdirfd);
+    close(olddirfd);
+    return ret;
+}
+
+static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
+                           const char *name, int flags)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+
+    ret = unlinkat(dirfd, name, flags);
+    close(dirfd);
+    return ret;
+}
+
+static int handle_init(FsContext *ctx)
+{
+    int ret, mnt_id;
+    struct file_handle fh;
+    struct handle_data *data = g_malloc(sizeof(struct handle_data));
+    data->mountfd = open(ctx->fs_root, O_DIRECTORY);
+    if (data->mountfd < 0) {
+        ret = data->mountfd;
+        goto err_out;
+    }
+    memset(&fh, 0, sizeof(struct file_handle));
+    ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
+    if (ret && errno == EOVERFLOW) {
+        data->handle_bytes = fh.handle_bytes;
+        ctx->private = data;
+        ret = 0;
+        goto out;
+    }
+    /* we got 0 byte handle ? */
+    ret = -1;
+    close(data->mountfd);
+err_out:
+    g_free(data);
+out:
+    return ret;
+}
+
+FileOperations handle_ops = {
+    .init         = handle_init,
+    .lstat        = handle_lstat,
+    .readlink     = handle_readlink,
+    .close        = handle_close,
+    .closedir     = handle_closedir,
+    .open         = handle_open,
+    .opendir      = handle_opendir,
+    .rewinddir    = handle_rewinddir,
+    .telldir      = handle_telldir,
+    .readdir_r    = handle_readdir_r,
+    .seekdir      = handle_seekdir,
+    .preadv       = handle_preadv,
+    .pwritev      = handle_pwritev,
+    .chmod        = handle_chmod,
+    .mknod        = handle_mknod,
+    .mkdir        = handle_mkdir,
+    .fstat        = handle_fstat,
+    .open2        = handle_open2,
+    .symlink      = handle_symlink,
+    .link         = handle_link,
+    .truncate     = handle_truncate,
+    .rename       = handle_rename,
+    .chown        = handle_chown,
+    .utimensat    = handle_utimensat,
+    .remove       = handle_remove,
+    .fsync        = handle_fsync,
+    .statfs       = handle_statfs,
+    .lgetxattr    = handle_lgetxattr,
+    .llistxattr   = handle_llistxattr,
+    .lsetxattr    = handle_lsetxattr,
+    .lremovexattr = handle_lremovexattr,
+    .name_to_path = handle_name_to_path,
+    .renameat     = handle_renameat,
+    .unlinkat     = handle_unlinkat,
+};
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-09-09 10:57 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-09 10:54 [Qemu-devel] [PATCH] Implement file handle based fs driver Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 1/8] hw/9pfs: Make v9fs_string* functions non-static Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 2/8] hw/9pfs: Use read-write lock for protecting fid path Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 3/8] hw/9pfs: Move fid pathname tracking to seperate data type Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 4/8] hw/9pfs: Add init callback to fs driver Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 5/8] hw/9pfs: Add fs driver specific details to fscontext Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 6/8] hw/9pfs: Avoid unnecessary get_fid in v9fs_clunk Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 7/8] hw/9pfs: Implement TFLUSH operation Aneesh Kumar K.V
2011-09-09 10:54 ` [Qemu-devel] [PATCH 8/8] hw/9pfs: Add handle based fs driver Aneesh Kumar K.V

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.