From patchwork Mon Nov 21 13:36:12 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mohan Kumar M X-Patchwork-Id: 126783 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 10E71B71D4 for ; Tue, 22 Nov 2011 00:37:13 +1100 (EST) Received: from localhost ([::1]:45944 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RSU3U-0008V3-OS for incoming@patchwork.ozlabs.org; Mon, 21 Nov 2011 08:37:04 -0500 Received: from eggs.gnu.org ([140.186.70.92]:46527) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RSU3C-0008Il-Ny for qemu-devel@nongnu.org; Mon, 21 Nov 2011 08:36:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RSU37-0008Rn-RT for qemu-devel@nongnu.org; Mon, 21 Nov 2011 08:36:46 -0500 Received: from e23smtp03.au.ibm.com ([202.81.31.145]:56526) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RSU36-0008QV-QQ for qemu-devel@nongnu.org; Mon, 21 Nov 2011 08:36:41 -0500 Received: from /spool/local by e23smtp03.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 21 Nov 2011 13:31:28 +1000 Received: from d23relay04.au.ibm.com ([202.81.31.246]) by e23smtp03.au.ibm.com ([202.81.31.209]) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 21 Nov 2011 13:31:25 +1000 Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay04.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id pALDXEg02789472 for ; Tue, 22 Nov 2011 00:33:14 +1100 Received: from d23av03.au.ibm.com (loopback [127.0.0.1]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id pALDaS1J005497 for ; Tue, 22 Nov 2011 00:36:28 +1100 Received: from explorer.in.ibm.com (explorer.in.ibm.com [9.122.21.115]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id pALDaGuB004347; Tue, 22 Nov 2011 00:36:27 +1100 From: "M. Mohan Kumar" To: qemu-devel@nongnu.org, aneesh.kumar@linux.vnet.ibm.com, stefanha@gmail.com, berrange@redhat.com Date: Mon, 21 Nov 2011 19:06:12 +0530 Message-Id: <1321882578-7498-8-git-send-email-mohan@in.ibm.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1321882578-7498-1-git-send-email-mohan@in.ibm.com> References: <1321882578-7498-1-git-send-email-mohan@in.ibm.com> x-cbid: 11112103-6102-0000-0000-00000035DDD2 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.81.31.145 Cc: "M. Mohan Kumar" Subject: [Qemu-devel] [PATCH V3 07/13] hw/9pfs: Add stat/readlink/statfs for proxy FS 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 From: "M. Mohan Kumar" Signed-off-by: M. Mohan Kumar --- fsdev/virtfs-proxy-helper.c | 182 +++++++++++++++++++++++++++++++++++++++++ hw/9pfs/virtio-9p-proxy.c | 189 +++++++++++++++++++++++++++++++++++++++++-- hw/9pfs/virtio-9p-proxy.h | 34 ++++++++ 3 files changed, 397 insertions(+), 8 deletions(-) diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 246be77..7510827 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "qemu-common.h" #include "virtio-9p-marshal.h" #include "hw/9pfs/virtio-9p-proxy.h" @@ -257,6 +259,171 @@ static int setfsugid(int uid, int gid) } /* + * send response in two parts + * 1) ProxyHeader + * 2) Response or error status + * This function should be called with marshaling response + * send_response constructs header part and error part only. + * send response sends {ProxyHeader,Response} if the request was success + * otherwise sends {ProxyHeader,error status} + */ +static int send_response(int sock, struct iovec *iovec, int size) +{ + int retval; + ProxyHeader header; + + /* + * If response size exceeds available iovec->iov_len, + * we return EOVERFLOW + */ + if (size > (int)iovec->iov_len) { + size = -EOVERFLOW; + } + + if (size < 0) { + header.type = T_ERROR; + header.size = sizeof(size); + proxy_marshal(iovec, 1, HDR_SZ, "d", size); + } else { + header.type = T_SUCCESS; + header.size = size; + } + + proxy_marshal(iovec, 1, 0, "dd", header.type, header.size); + retval = socket_write(sock, iovec->iov_base, header.size + HDR_SZ); + if (retval != header.size + HDR_SZ) { + return -EIO; + } + return 0; +} + +static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat) +{ + memset(pr_stat, 0, sizeof(*pr_stat)); + pr_stat->st_dev = stat->st_dev; + pr_stat->st_ino = stat->st_ino; + pr_stat->st_nlink = stat->st_nlink; + pr_stat->st_mode = stat->st_mode; + pr_stat->st_uid = stat->st_uid; + pr_stat->st_gid = stat->st_gid; + pr_stat->st_rdev = stat->st_rdev; + pr_stat->st_size = stat->st_size; + pr_stat->st_blksize = stat->st_blksize; + pr_stat->st_blocks = stat->st_blocks; + pr_stat->st_atim_sec = stat->st_atim.tv_sec; + pr_stat->st_atim_nsec = stat->st_atim.tv_nsec; + pr_stat->st_mtim_sec = stat->st_mtim.tv_sec; + pr_stat->st_mtim_nsec = stat->st_mtim.tv_nsec; + pr_stat->st_ctim_sec = stat->st_ctim.tv_sec; + pr_stat->st_ctim_nsec = stat->st_ctim.tv_nsec; +} + +static void statfs_to_prstatfs(ProxyStatFS *pr_stfs, struct statfs *stfs) +{ + memset(pr_stfs, 0, sizeof(*pr_stfs)); + pr_stfs->f_type = stfs->f_type; + pr_stfs->f_bsize = stfs->f_bsize; + pr_stfs->f_blocks = stfs->f_blocks; + pr_stfs->f_bfree = stfs->f_bfree; + pr_stfs->f_bavail = stfs->f_bavail; + pr_stfs->f_files = stfs->f_files; + pr_stfs->f_ffree = stfs->f_ffree; + pr_stfs->f_fsid[0] = stfs->f_fsid.__val[0]; + pr_stfs->f_fsid[1] = stfs->f_fsid.__val[1]; + pr_stfs->f_namelen = stfs->f_namelen; + pr_stfs->f_frsize = stfs->f_frsize; +} + +/* + * Gets stat/statfs information and packs in out_iovec structure + * on success returns number of bytes packed in out_iovec struture + * otherwise returns -errno + */ +static int do_stat(int type, struct iovec *iovec, struct iovec *out_iovec) +{ + V9fsString path; + struct stat st_buf; + ProxyStat pr_stat; + struct statfs stfs_buf; + ProxyStatFS pr_stfs; + int retval = 0; + + if (proxy_unmarshal(iovec, 1, HDR_SZ, "s", &path) < 0) { + return -EOVERFLOW; + } + + switch (type) { + case T_LSTAT: + retval = lstat(path.data, &st_buf); + if (retval < 0) { + retval = -errno; + } else { + stat_to_prstat(&pr_stat, &st_buf); + retval = proxy_marshal(out_iovec, 1, HDR_SZ, + "qqqdddqqqqqqqqqq", pr_stat.st_dev, + pr_stat.st_ino, pr_stat.st_nlink, + pr_stat.st_mode, pr_stat.st_uid, + pr_stat.st_gid, pr_stat.st_rdev, + pr_stat.st_size, pr_stat.st_blksize, + pr_stat.st_blocks, + pr_stat.st_atim_sec, pr_stat.st_atim_nsec, + pr_stat.st_mtim_sec, pr_stat.st_mtim_nsec, + pr_stat.st_ctim_sec, pr_stat.st_ctim_nsec); + if (retval < 0) { + retval = -EOVERFLOW; + } + } + break; + case T_STATFS: + retval = statfs(path.data, &stfs_buf); + if (retval < 0) { + retval = -errno; + } else { + statfs_to_prstatfs(&pr_stfs, &stfs_buf); + retval = proxy_marshal(out_iovec, 1, HDR_SZ, + "qqqqqqqqqqq", pr_stfs.f_type, pr_stfs.f_bsize, + pr_stfs.f_blocks, pr_stfs.f_bfree, pr_stfs.f_bavail, + pr_stfs.f_files, pr_stfs.f_ffree, + pr_stfs.f_fsid[0], pr_stfs.f_fsid[1], + pr_stfs.f_namelen, pr_stfs.f_frsize); + if (retval < 0) { + retval = -EOVERFLOW; + } + } + break; + } + v9fs_string_free(&path); + return retval; +} + +static int do_readlink(struct iovec *iovec, struct iovec *out_iovec) +{ + V9fsString target, path; + int size, retval; + char *buffer; + + if (proxy_unmarshal(iovec, 1, HDR_SZ, "sd", &path, &size) < 0) { + return -EOVERFLOW; + } + buffer = g_malloc(size); + v9fs_string_init(&target); + retval = readlink(path.data, buffer, size); + if (retval > 0) { + buffer[retval] = '\0'; + v9fs_string_sprintf(&target, "%s", buffer); + retval = proxy_marshal(out_iovec, 1, HDR_SZ, "s", &target); + if (retval < 0) { + retval = -EOVERFLOW; + } + } else { + retval = -errno; + } + v9fs_string_free(&target); + v9fs_string_free(&path); + return retval; +} + +/* * create a other filesystem objects and send 0 on success * return -errno on error */ @@ -371,6 +538,7 @@ static int process_requests(int sock) int type, retval = 0; V9fsString oldpath, path; struct iovec in_iovec, out_iovec; + int size = 0; in_iovec.iov_base = g_malloc(BUFF_SZ); in_iovec.iov_len = BUFF_SZ; @@ -404,6 +572,13 @@ static int process_requests(int sock) v9fs_string_free(&oldpath); v9fs_string_free(&path); break; + case T_LSTAT: + case T_STATFS: + size = do_stat(type, &in_iovec, &out_iovec); + break; + case T_READLINK: + size = do_readlink(&in_iovec, &out_iovec); + break; default: goto error; break; @@ -420,6 +595,13 @@ static int process_requests(int sock) case T_LINK: send_status(sock, &out_iovec, retval); break; + case T_LSTAT: + case T_STATFS: + case T_READLINK: + if (send_response(sock, &out_iovec, size) < 0) { + goto error; + } + break; default: goto error; break; diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index f116773..aca799e 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -89,6 +89,124 @@ static ssize_t socket_read(int sockfd, void *buff, size_t size) return retval; } +/* Converts proxy_statfs to VFS statfs structure */ +static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) +{ + memset(stfs, 0, sizeof(*stfs)); + stfs->f_type = prstfs->f_type; + stfs->f_bsize = prstfs->f_bsize; + stfs->f_blocks = prstfs->f_blocks; + stfs->f_bfree = prstfs->f_bfree; + stfs->f_bavail = prstfs->f_bavail; + stfs->f_files = prstfs->f_files; + stfs->f_ffree = prstfs->f_ffree; + stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFUL; + stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFFUL; + stfs->f_namelen = prstfs->f_namelen; + stfs->f_frsize = prstfs->f_frsize; +} + +/* Converts proxy_stat structure to VFS stat structure */ +static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) +{ + memset(stbuf, 0, sizeof(*stbuf)); + stbuf->st_dev = prstat->st_dev; + stbuf->st_ino = prstat->st_ino; + stbuf->st_nlink = prstat->st_nlink; + stbuf->st_mode = prstat->st_mode; + stbuf->st_uid = prstat->st_uid; + stbuf->st_gid = prstat->st_gid; + stbuf->st_rdev = prstat->st_rdev; + stbuf->st_size = prstat->st_size; + stbuf->st_blksize = prstat->st_blksize; + stbuf->st_blocks = prstat->st_blocks; + stbuf->st_atim.tv_sec = prstat->st_atim_sec; + stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; + stbuf->st_mtime = prstat->st_mtim_sec; + stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; + stbuf->st_ctime = prstat->st_ctim_sec; + stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; +} + +/* + * Response contains two parts + * {header, data} + * header.type == T_ERROR, data -> -errno + * header.type == T_SUCCESS, data -> response + * size of errno/response is given by header.size + */ +static int v9fs_receive_response(V9fsProxy *proxy, int type, + int *sock_error, void *response) +{ + int retval, error; + ProxyHeader header; + struct iovec *reply = &proxy->in_iovec; + + *sock_error = 0; + + retval = socket_read(proxy->sockfd, reply->iov_base, HDR_SZ); + if (retval != HDR_SZ) { + *sock_error = 1; + return -EIO; + } + proxy_unmarshal(reply, 1, 0, "dd", &header.type, &header.size); + if (header.size > BUFF_SZ) { + error_report("response exceeds maximum size\n"); + return -EIO; + } + + retval = socket_read(proxy->sockfd, reply->iov_base + HDR_SZ, header.size); + if (retval != header.size) { + *sock_error = 1; + return -EIO; + } + /* there was an error during processing request */ + if (header.type == T_ERROR) { + proxy_unmarshal(reply, 1, HDR_SZ, "d", &error); + return error; + } + + switch (type) { + case T_LSTAT: { + ProxyStat prstat; + proxy_unmarshal(reply, 1, HDR_SZ, + "qqqdddqqqqqqqqqq", &prstat.st_dev, + &prstat.st_ino, &prstat.st_nlink, + &prstat.st_mode, &prstat.st_uid, + &prstat.st_gid, &prstat.st_rdev, + &prstat.st_size, &prstat.st_blksize, + &prstat.st_blocks, + &prstat.st_atim_sec, &prstat.st_atim_nsec, + &prstat.st_mtim_sec, &prstat.st_mtim_nsec, + &prstat.st_ctim_sec, &prstat.st_ctim_nsec); + prstat_to_stat(response, &prstat); + break; + } + case T_STATFS: { + ProxyStatFS prstfs; + proxy_unmarshal(reply, 1, HDR_SZ, + "qqqqqqqqqqq", &prstfs.f_type, &prstfs.f_bsize, + &prstfs.f_blocks, &prstfs.f_bfree, &prstfs.f_bavail, + &prstfs.f_files, &prstfs.f_ffree, + &prstfs.f_fsid[0], &prstfs.f_fsid[1], + &prstfs.f_namelen, &prstfs.f_frsize); + prstatfs_to_statfs(response, &prstfs); + break; + } + case T_READLINK: { + V9fsString target; + proxy_unmarshal(reply, 1, HDR_SZ, "s", &target); + strcpy(response, target.data); + v9fs_string_free(&target); + break; + } + default: + *sock_error = 1; + return -1; + } + + return 0; +} static int v9fs_receive_status(V9fsProxy *proxy, int *sock_error, struct iovec *reply) @@ -127,6 +245,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, int sock_error, flags, mode, uid, gid; struct iovec *iovec = NULL, *reply = NULL; dev_t rdev; + int size = 0; qemu_mutex_lock(&proxy->mutex); @@ -218,6 +337,37 @@ static int v9fs_request(V9fsProxy *proxy, int type, proxy_marshal(iovec, 1, 0, "dd", header.type, header.size); header.size += HDR_SZ; break; + case T_LSTAT: + path = va_arg(ap, V9fsString *); + header.size = proxy_marshal(iovec, 1, HDR_SZ, "s", path); + if (header.size < 0) { + goto out_overflow; + } + header.type = T_LSTAT; + proxy_marshal(iovec, 1, 0, "dd", header.type, header.size); + header.size += HDR_SZ; + break; + case T_READLINK: + path = va_arg(ap, V9fsString *); + size = va_arg(ap, int); + header.size = proxy_marshal(iovec, 1, HDR_SZ, "sd", path, size); + if (header.size < 0) { + goto out_overflow; + } + header.type = T_READLINK; + proxy_marshal(iovec, 1, 0, "dd", header.type, header.size); + header.size += HDR_SZ; + break; + case T_STATFS: + path = va_arg(ap, V9fsString *); + header.size = proxy_marshal(iovec, 1, HDR_SZ, "s", path); + if (header.size < 0) { + goto out_overflow; + } + header.type = T_STATFS; + proxy_marshal(iovec, 1, 0, "dd", header.type, header.size); + header.size += HDR_SZ; + break; default: error_report("Invalid type %d\n", type); va_end(ap); @@ -252,6 +402,14 @@ static int v9fs_request(V9fsProxy *proxy, int type, goto close_error; } break; + case T_LSTAT: + case T_READLINK: + case T_STATFS: + retval = v9fs_receive_response(proxy, type, &sock_error, response); + if (sock_error) { + goto close_error; + } + break; } qemu_mutex_unlock(&proxy->mutex); return retval; @@ -269,15 +427,26 @@ error: static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { - errno = EOPNOTSUPP; - return -1; + int retval; + retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path); + if (retval < 0) { + errno = -retval; + return -1; + } + return retval; } static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char *buf, size_t bufsz) { - errno = EOPNOTSUPP; - return -1; + int retval; + retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd", + fs_path, bufsz); + if (retval < 0) { + errno = -retval; + return -1; + } + return strlen(buf); } static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) @@ -493,8 +662,7 @@ static int proxy_link(FsContext *ctx, V9fsPath *oldpath, v9fs_string_init(&newpath); v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); - retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", - oldpath, &newpath); + retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath); v9fs_string_free(&newpath); if (retval < 0) { errno = -retval; @@ -547,8 +715,13 @@ static int proxy_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync) static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) { - errno = EOPNOTSUPP; - return -1; + int retval; + retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path); + if (retval < 0) { + errno = -retval; + return -1; + } + return retval; } static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h index 9a43f64..4d8dcc2 100644 --- a/hw/9pfs/virtio-9p-proxy.h +++ b/hw/9pfs/virtio-9p-proxy.h @@ -30,6 +30,40 @@ enum { T_MKDIR, T_SYMLINK, T_LINK, + T_LSTAT, + T_READLINK, + T_STATFS, }; +typedef struct { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_nlink; + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_atim_sec; + uint64_t st_atim_nsec; + uint64_t st_mtim_sec; + uint64_t st_mtim_nsec; + uint64_t st_ctim_sec; + uint64_t st_ctim_nsec; +} ProxyStat; + +typedef struct { + uint64_t f_type; + uint64_t f_bsize; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; + uint64_t f_fsid[2]; + uint64_t f_namelen; + uint64_t f_frsize; +} ProxyStatFS; #endif