From patchwork Mon Jun 6 17:48:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Aneesh Kumar K.V" X-Patchwork-Id: 99035 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id ED69CB6F9C for ; Tue, 7 Jun 2011 06:52:09 +1000 (EST) Received: from localhost ([::1]:51822 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTgmK-0005G1-Cg for incoming@patchwork.ozlabs.org; Mon, 06 Jun 2011 16:52:04 -0400 Received: from eggs.gnu.org ([140.186.70.92]:56191) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTdux-0000Cq-AU for qemu-devel@nongnu.org; Mon, 06 Jun 2011 13:48:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QTdut-0003en-RS for qemu-devel@nongnu.org; Mon, 06 Jun 2011 13:48:47 -0400 Received: from e23smtp05.au.ibm.com ([202.81.31.147]:41850) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTdus-0003eD-5j for qemu-devel@nongnu.org; Mon, 06 Jun 2011 13:48:43 -0400 Received: from d23relay04.au.ibm.com (d23relay04.au.ibm.com [202.81.31.246]) by e23smtp05.au.ibm.com (8.14.4/8.13.1) with ESMTP id p56HgK4J025920 for ; Tue, 7 Jun 2011 03:42:20 +1000 Received: from d23av04.au.ibm.com (d23av04.au.ibm.com [9.190.235.139]) by d23relay04.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p56Hlmhx909520 for ; Tue, 7 Jun 2011 03:47:48 +1000 Received: from d23av04.au.ibm.com (loopback [127.0.0.1]) by d23av04.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p56HmSW8002492 for ; Tue, 7 Jun 2011 03:48:28 +1000 Received: from skywalker.in.ibm.com ([9.79.216.200]) by d23av04.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p56HmLur002415; Tue, 7 Jun 2011 03:48:26 +1000 From: "Aneesh Kumar K.V" To: qemu-devel@nongnu.org Date: Mon, 6 Jun 2011 23:18:17 +0530 Message-Id: <1307382497-3737-4-git-send-email-aneesh.kumar@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1307382497-3737-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com> References: <1307382497-3737-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 202.81.31.147 Cc: aliguori@us.ibm.com, "Aneesh Kumar K.V" Subject: [Qemu-devel] [PATCH 4/4] hw/9pfs: Use read-write lock for protecting fid path. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- hw/9pfs/codir.c | 18 ++++++- hw/9pfs/cofile.c | 32 +++++++++++-- hw/9pfs/cofs.c | 51 +++++++++++++++++--- hw/9pfs/coxattr.c | 8 +++ hw/9pfs/virtio-9p-coth.h | 14 +++-- hw/9pfs/virtio-9p-device.c | 1 + hw/9pfs/virtio-9p.c | 113 ++++++++++++++++--------------------------- hw/9pfs/virtio-9p.h | 7 +++ 8 files changed, 154 insertions(+), 90 deletions(-) diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 2c26f72..e7b724c 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -66,22 +66,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; } @@ -89,6 +101,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); @@ -98,6 +111,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 60468bc..7f40a4c 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -23,6 +23,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf) ssize_t len; buf->data = qemu_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 +36,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf) err = -errno; } }); + qemu_co_rwlock_unlock(&s->rename_lock); if (err) { qemu_free(buf->data); buf->data = NULL; @@ -47,6 +49,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 +57,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 +68,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 +76,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 +85,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 +93,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path, err = -errno; } }); + qemu_co_rwlock_unlock(&s->rename_lock); return err; } @@ -97,6 +105,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 +113,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 +121,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 +129,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 +169,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 +177,7 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path) err = -errno; } }); + qemu_co_rwlock_unlock(&s->rename_lock); return err; } @@ -170,22 +195,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 55edc45..6c8b4bc 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -137,6 +137,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 792b16a..175abdb 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -1589,7 +1589,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; @@ -1597,8 +1596,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); @@ -1607,11 +1604,10 @@ static void v9fs_lcreate(void *opaque) err = -ENOENT; goto out_nofid; } - v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data); flags = get_dotl_openflags(pdu->s, flags); - err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, - flags | O_CREAT, mode); + err = v9fs_co_open2(pdu->s, fidp, &name, gid, + flags | O_CREAT, mode, &stbuf); if (err < 0) { goto out; } @@ -1624,17 +1620,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; @@ -1643,7 +1629,6 @@ out: out_nofid: complete_pdu(pdu->s, pdu, err); v9fs_string_free(&name); - v9fs_string_free(&fullname); } static void v9fs_fsync(void *opaque) @@ -2109,11 +2094,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) { @@ -2121,11 +2107,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); @@ -2133,12 +2121,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; @@ -2162,26 +2157,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; } @@ -2195,16 +2196,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; @@ -2223,7 +2215,6 @@ static void v9fs_symlink(void *opaque) V9fsPDU *pdu = opaque; V9fsString name; V9fsString symname; - V9fsString fullname; V9fsFidState *dfidp; V9fsQID qid; struct stat stbuf; @@ -2232,8 +2223,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); @@ -2241,13 +2230,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; } @@ -2260,7 +2243,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) @@ -2439,7 +2421,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; } @@ -2522,7 +2506,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; } @@ -2706,12 +2692,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); @@ -2720,13 +2704,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; } @@ -2737,7 +2716,6 @@ out: put_fid(s, fidp); out_nofid: complete_pdu(s, pdu, err); - v9fs_string_free(&fullname); v9fs_string_free(&name); } @@ -2836,14 +2814,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); @@ -2851,12 +2828,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; } @@ -2867,7 +2839,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 1f5d283..2ecece3 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -8,6 +8,8 @@ #include #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 */ @@ -236,6 +238,11 @@ typedef struct V9fsState enum p9_proto_version proto_version; int32_t msize; int reclaim_in_prgs; + /* + * lock ensuring atomic path update + * on rename. + */ + CoRwlock rename_lock; } V9fsState; typedef struct V9fsStatState {