From patchwork Thu Apr 15 14:11:08 2010 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: 50257 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 57DDAB7CFA for ; Fri, 16 Apr 2010 00:47:53 +1000 (EST) Received: from localhost ([127.0.0.1]:45766 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O2QM3-00066R-8y for incoming@patchwork.ozlabs.org; Thu, 15 Apr 2010 10:47:43 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1O2Pta-0003YQ-6G for qemu-devel@nongnu.org; Thu, 15 Apr 2010 10:18:18 -0400 Received: from [140.186.70.92] (port=50361 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O2PtK-0003GA-Vt for qemu-devel@nongnu.org; Thu, 15 Apr 2010 10:18:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1O2Pn7-0000Lk-OQ for qemu-devel@nongnu.org; Thu, 15 Apr 2010 10:11:53 -0400 Received: from e28smtp09.in.ibm.com ([122.248.162.9]:50205) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1O2Pn3-0000K0-AI for qemu-devel@nongnu.org; Thu, 15 Apr 2010 10:11:34 -0400 Received: from d28relay03.in.ibm.com (d28relay03.in.ibm.com [9.184.220.60]) by e28smtp09.in.ibm.com (8.14.3/8.13.1) with ESMTP id o3FDLq0i022628 for ; Thu, 15 Apr 2010 18:51:52 +0530 Received: from d28av01.in.ibm.com (d28av01.in.ibm.com [9.184.220.63]) by d28relay03.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o3FEBVVO1605794 for ; Thu, 15 Apr 2010 19:41:31 +0530 Received: from d28av01.in.ibm.com (loopback [127.0.0.1]) by d28av01.in.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o3FEBVPW030956 for ; Thu, 15 Apr 2010 19:41:31 +0530 Received: from skywalker.in.ibm.com ([9.77.204.187]) by d28av01.in.ibm.com (8.14.3/8.13.1/NCO v10.0 AVin) with ESMTP id o3FEBDaM030329; Thu, 15 Apr 2010 19:41:30 +0530 From: "Aneesh Kumar K.V" To: qemu-devel@nongnu.org Date: Thu, 15 Apr 2010 19:41:08 +0530 Message-Id: <1271340671-19558-19-git-send-email-aneesh.kumar@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.0.4.360.g11766c In-Reply-To: <1271340671-19558-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com> References: <1271340671-19558-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) Cc: ericvh@gmail.com, aliguori@us.ibm.com, aneesh.kumar@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH -V5 18/21] virtio-9p: Add P9_TWSTAT support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Anthony Liguori Implement P9_TWSTAT support. This gets file and directory creation to work. [jvrao@linux.vnet.ibm.com: strdup to qemu_strdup conversion] [aneesh.kumar@linux.vnet.ibm.com: v9fs_fix_path] Signed-off-by: Anthony Liguori Signed-off-by: Aneesh Kumar K.V --- hw/file-op-9p.h | 5 + hw/virtio-9p-local.c | 50 +++++++++ hw/virtio-9p.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 326 insertions(+), 2 deletions(-) diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h index 5049b2e..8ba1927 100644 --- a/hw/file-op-9p.h +++ b/hw/file-op-9p.h @@ -30,8 +30,10 @@ typedef struct FileOperations int (*lstat)(FsContext *, const char *, struct stat *); ssize_t (*readlink)(FsContext *, const char *, char *, size_t); int (*chmod)(FsContext *, const char *, mode_t); + int (*chown)(FsContext *, const char *, uid_t, gid_t); int (*mknod)(FsContext *, const char *, mode_t, dev_t); int (*mksock)(FsContext *, const char *); + int (*utime)(FsContext *, const char *, const struct utimbuf *); int (*symlink)(FsContext *, const char *, const char *); int (*link)(FsContext *, const char *, const char *); int (*setuid)(FsContext *, uid_t); @@ -49,6 +51,9 @@ typedef struct FileOperations off_t (*lseek)(FsContext *, int, off_t, int); int (*mkdir)(FsContext *, const char *, mode_t); int (*fstat)(FsContext *, int, struct stat *); + int (*rename)(FsContext *, const char *, const char *); + int (*truncate)(FsContext *, const char *, off_t); + int (*fsync)(FsContext *, int); void *opaque; } FileOperations; #endif diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c index f6781ca..5a011f3 100644 --- a/hw/virtio-9p-local.c +++ b/hw/virtio-9p-local.c @@ -212,6 +212,51 @@ static int local_link(FsContext *ctx, const char *oldpath, const char *newpath) return err; } +static int local_truncate(FsContext *ctx, const char *path, off_t size) +{ + return truncate(rpath(ctx, path), size); +} + +static int local_rename(FsContext *ctx, const char *oldpath, + const char *newpath) +{ + char *tmp; + int err; + + tmp = qemu_strdup(rpath(ctx, oldpath)); + if (tmp == NULL) { + return -1; + } + + err = rename(tmp, rpath(ctx, newpath)); + if (err == -1) { + int serrno = errno; + qemu_free(tmp); + errno = serrno; + } else { + qemu_free(tmp); + } + + return err; + +} + +static int local_chown(FsContext *ctx, const char *path, uid_t uid, gid_t gid) +{ + return chown(rpath(ctx, path), uid, gid); +} + +static int local_utime(FsContext *ctx, const char *path, + const struct utimbuf *buf) +{ + return utime(rpath(ctx, path), buf); +} + +static int local_fsync(FsContext *ctx, int fd) +{ + return fsync(fd); +} + FileOperations local_ops = { .lstat = local_lstat, .setuid = local_setuid, @@ -235,4 +280,9 @@ FileOperations local_ops = { .open2 = local_open2, .symlink = local_symlink, .link = local_link, + .truncate = local_truncate, + .rename = local_rename, + .chown = local_chown, + .utime = local_utime, + .fsync = local_fsync, }; diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index faf13b2..b6a635b 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -144,6 +144,33 @@ static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath) return s->ops->link(&s->ctx, oldpath->data, newpath->data); } +static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size) +{ + return s->ops->truncate(&s->ctx, path->data, size); +} + +static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath, + V9fsString *newpath) +{ + return s->ops->rename(&s->ctx, oldpath->data, newpath->data); +} + +static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid) +{ + return s->ops->chown(&s->ctx, path->data, uid, gid); +} + +static int v9fs_do_utime(V9fsState *s, V9fsString *path, + const struct utimbuf *buf) +{ + return s->ops->utime(&s->ctx, path->data, buf); +} + +static int v9fs_do_fsync(V9fsState *s, int fd) +{ + return s->ops->fsync(&s->ctx, fd); +} + static void v9fs_string_init(V9fsString *str) { str->data = NULL; @@ -931,6 +958,15 @@ static void v9fs_dummy(V9fsState *s, V9fsPDU *pdu) (void) print_sg; } +static void v9fs_fix_path(V9fsString *dst, V9fsString *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); +} + static void v9fs_version(V9fsState *s, V9fsPDU *pdu) { int32_t msize; @@ -1933,11 +1969,244 @@ static void v9fs_remove(V9fsState *s, V9fsPDU *pdu) } } +typedef struct V9fsWstatState +{ + V9fsPDU *pdu; + size_t offset; + int16_t unused; + V9fsStat v9stat; + V9fsFidState *fidp; + struct stat stbuf; + V9fsString nname; +} V9fsWstatState; + +static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + err = vs->offset; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.name.size != 0) { + v9fs_string_free(&vs->nname); + } + + if (vs->v9stat.length != -1) { + if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) { + err = -errno; + } + } + v9fs_wstat_post_truncate(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err) +{ + V9fsFidState *fidp; + if (err < 0) { + goto out; + } + + if (vs->v9stat.name.size != 0) { + char *old_name, *new_name; + char *end; + + old_name = vs->fidp->path.data; + end = strrchr(old_name, '/'); + if (end) { + end++; + } else { + end = old_name; + } + + new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1); + + memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1); + memcpy(new_name, old_name, end - old_name); + memcpy(new_name + (end - old_name), vs->v9stat.name.data, + vs->v9stat.name.size); + vs->nname.data = new_name; + vs->nname.size = strlen(new_name); + + if (strcmp(new_name, vs->fidp->path.data) != 0) { + if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) { + err = -errno; + } else { + /* + * Fixup fid's pointing to the old name to + * start pointing to the new name + */ + for (fidp = s->fid_list; fidp; fidp = fidp->next) { + + if (vs->fidp == fidp) { + /* + * we replace name of this fid towards the end + * so that our below strcmp will work + */ + continue; + } + if (!strncmp(vs->fidp->path.data, fidp->path.data, + strlen(vs->fidp->path.data))) { + /* replace the name */ + v9fs_fix_path(&fidp->path, &vs->nname, + strlen(vs->fidp->path.data)); + } + } + v9fs_string_copy(&vs->fidp->path, &vs->nname); + } + } + } + v9fs_wstat_post_rename(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.n_gid != -1) { + if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid, + vs->v9stat.n_gid)) { + err = -errno; + } + } + v9fs_wstat_post_chown(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.mtime != -1) { + struct utimbuf tb; + tb.actime = 0; + tb.modtime = vs->v9stat.mtime; + if (v9fs_do_utime(s, &vs->fidp->path, &tb)) { + err = -errno; + } + } + + v9fs_wstat_post_utime(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err == -1) { + err = -errno; + } + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err) +{ + uint32_t v9_mode; + + if (err == -1) { + err = -errno; + goto out; + } + + v9_mode = stat_to_v9mode(&vs->stbuf); + + if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) != + (v9_mode & P9_STAT_MODE_TYPE_BITS)) { + /* Attempting to change the type */ + err = -EIO; + goto out; + } + + if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode, + &vs->v9stat.extension))) { + err = -errno; + } + v9fs_wstat_post_chmod(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu) { - if (debug_9p_pdu) { - pprint_pdu(pdu); + int32_t fid; + V9fsWstatState *vs; + int err = 0; + + vs = qemu_malloc(sizeof(*vs)); + vs->pdu = pdu; + vs->offset = 7; + + pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat); + + vs->fidp = lookup_fid(s, fid); + if (vs->fidp == NULL) { + err = -EINVAL; + goto out; } + + /* do we need to sync the file? */ + if (donttouch_stat(&vs->v9stat)) { + err = v9fs_do_fsync(s, vs->fidp->fd); + v9fs_wstat_post_fsync(s, vs, err); + return; + } + + if (vs->v9stat.mode != -1) { + err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf); + v9fs_wstat_post_lstat(s, vs, err); + return; + } + + v9fs_wstat_post_chmod(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); } typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);