diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2011-05-24 15:10:56 +0530 |
---|---|---|
committer | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2011-09-22 21:38:52 +0530 |
commit | 02cb7f3a256517cbf3136caff2863fbafc57b540 (patch) | |
tree | 1d741e85dfe584b35a4a5e69a086d7b19fafd0ad /hw/9pfs | |
parent | 70c18fc08bcc9e9bbd8c00ca5e694e07890687e5 (diff) |
hw/9pfs: Use read-write lock for protecting fid path.
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>
Diffstat (limited to 'hw/9pfs')
-rw-r--r-- | hw/9pfs/codir.c | 18 | ||||
-rw-r--r-- | hw/9pfs/cofile.c | 32 | ||||
-rw-r--r-- | hw/9pfs/cofs.c | 52 | ||||
-rw-r--r-- | hw/9pfs/coxattr.c | 8 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-coth.h | 14 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-device.c | 1 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.c | 110 | ||||
-rw-r--r-- | 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 f17f927c10..c9a88ecb60 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 0caf1e3cee..cc62846c82 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 a78fccbe23..98860f9189 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 a289389e49..7b93c8f478 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 b7be9b5f1f..e5f46c5449 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 97f2da5f0e..eea70cb1f3 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 dc3e32b53d..356bb3b095 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 8aeee4ee9c..4238a76136 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 { |