From patchwork Mon Jul 12 15:23:28 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sripathi Kodi X-Patchwork-Id: 58623 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 19B39B6F06 for ; Tue, 13 Jul 2010 01:25:52 +1000 (EST) Received: from localhost ([127.0.0.1]:54911 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OYKt3-0000l2-Tt for incoming@patchwork.ozlabs.org; Mon, 12 Jul 2010 11:25:42 -0400 Received: from [140.186.70.92] (port=33659 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OYKrJ-0008Ms-HS for qemu-devel@nongnu.org; Mon, 12 Jul 2010 11:23:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OYKr6-00023s-Ok for qemu-devel@nongnu.org; Mon, 12 Jul 2010 11:23:46 -0400 Received: from e23smtp06.au.ibm.com ([202.81.31.148]:55640) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OYKr5-00022s-Mt for qemu-devel@nongnu.org; Mon, 12 Jul 2010 11:23:40 -0400 Received: from d23relay03.au.ibm.com (d23relay03.au.ibm.com [202.81.31.245]) by e23smtp06.au.ibm.com (8.14.4/8.13.1) with ESMTP id o6CFNKx3001559 for ; Tue, 13 Jul 2010 01:23:20 +1000 Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay03.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o6CFNX7c1855568 for ; Tue, 13 Jul 2010 01:23:33 +1000 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 o6CFNX5A013068 for ; Tue, 13 Jul 2010 01:23:33 +1000 Received: from sripathi.in.ibm.com ([9.77.125.99]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id o6CFNVIM013052 for ; Tue, 13 Jul 2010 01:23:32 +1000 Received: from localhost.localdomain (localhost [IPv6:::1]) by sripathi.in.ibm.com (Postfix) with ESMTP id C4BF0AEFC6 for ; Mon, 12 Jul 2010 20:53:28 +0530 (IST) From: Sripathi Kodi To: qemu-devel@nongnu.org Date: Mon, 12 Jul 2010 20:53:28 +0530 Message-ID: <20100712152328.18945.15966.stgit@localhost.localdomain> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Subject: [Qemu-devel] [PATCH] virtio-9p: getattr server implementation for 9P2000.L protocol. 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: M. Mohan Kumar This is a new version of getattr patch for 9P2000.L that I posted some time ago. This version adds 3 fields to the on-the-wire data: file creation time generation number data version It also adds a bit field to indicate which fields of the structure have valid data. Usually the server fills in at least all the basic fields, but it may fill in the additional fields if possible. The server will use the bit field to tell the client which fields it has populated. Currently there is no clean way for the server to obtain these additional fields, so it sends back just the basic fields. The client (Linux kernel) patch corresponding to this is at http://sourceforge.net/mailarchive/forum.php?thread_name=20100712143815.6665.35892.stgit%40localhost.localdomain&forum_name=v9fs-developer Comments welcome. SYNOPSIS size[4] Tgetattr tag[2] fid[4] request_mask[8] size[4] Rgetattr tag[2] lstat[n] DESCRIPTION The getattr transaction inquires about the file identified by fid. request_mask is a bit mask that specifies which fields of the stat structure is the client interested in. The reply will contain a machine-independent directory entry, laid out as follows: st_result_mask[8] Bit mask that indicates which fields in the stat structure have been populated by the server qid.type[1] the type of the file (directory, etc.), represented as a bit vector corresponding to the high 8 bits of the file's mode word. qid.vers[4] version number for given path qid.path[8] the file server's unique identification for the file st_mode[4] Permission and flags st_uid[4] User id of owner st_gid[4] Group ID of owner st_nlink[8] Number of hard links st_rdev[8] Device ID (if special file) st_size[8] Size, in bytes st_blksize[8] Block size for file system IO st_blocks[8] Number of file system blocks allocated st_atime_sec[8] Time of last access, seconds st_atime_nsec[8] Time of last access, nanoseconds st_mtime_sec[8] Time of last modification, seconds st_mtime_nsec[8] Time of last modification, nanoseconds st_ctime_sec[8] Time of last status change, seconds st_ctime_nsec[8] Time of last status change, nanoseconds st_btime_sec[8] Time of creation (birth) of file, seconds st_btime_nsec[8] Time of creation (birth) of file, nanoseconds st_gen[8] Inode generation st_data_version[8] Data version number request_mask and result_mask bit masks contain the following bits #define P9_STATS_MODE 0x00000001ULL #define P9_STATS_NLINK 0x00000002ULL #define P9_STATS_UID 0x00000004ULL #define P9_STATS_GID 0x00000008ULL #define P9_STATS_RDEV 0x00000010ULL #define P9_STATS_ATIME 0x00000020ULL #define P9_STATS_MTIME 0x00000040ULL #define P9_STATS_CTIME 0x00000080ULL #define P9_STATS_INO 0x00000100ULL #define P9_STATS_SIZE 0x00000200ULL #define P9_STATS_BLOCKS 0x00000400ULL #define P9_STATS_BTIME 0x00000800ULL #define P9_STATS_GEN 0x00001000ULL #define P9_STATS_DATA_VERSION 0x00002000ULL #define P9_STATS_BASIC 0x000007ffULL #define P9_STATS_ALL 0x00003fffULL This patch implements the client side of getattr implementation for 9P2000.L. It introduces a new structure p9_stat_dotl for getting Linux stat information along with QID. The data layout is similar to stat structure in Linux user space with the following major differences: inode (st_ino) is not part of data. Instead qid is. device (st_dev) is not part of data because this doesn't make sense on the client. All time variables are 64 bit wide on the wire. The kernel seems to use 32 bit variables for these variables. However, some of the architectures have used 64 bit variables and glibc exposes 64 bit variables to user space on some architectures. Hence to be on the safer side we have made these 64 bit in the protocol. Refer to the comments in include/asm-generic/stat.h There are some additional fields: st_btime_sec, st_btime_nsec, st_gen, st_data_version apart from the bitmask, st_result_mask. Signed-off-by: M. Mohan Kumar Signed-off-by: Sripathi Kodi --- hw/virtio-9p-debug.c | 32 ++++++++++++++ hw/virtio-9p.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio-9p.h | 33 +++++++++++++++ 3 files changed, 177 insertions(+), 0 deletions(-) diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c index 030b3e6..6072491 100644 --- a/hw/virtio-9p-debug.c +++ b/hw/virtio-9p-debug.c @@ -178,6 +178,30 @@ static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) fprintf(llogfile, "}"); } +static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp, + const char *name) +{ + fprintf(llogfile, "%s={", name); + pprint_qid(pdu, rx, offsetp, "qid"); + pprint_int32(pdu, rx, offsetp, ", st_mode"); + pprint_int64(pdu, rx, offsetp, ", st_nlink"); + pprint_int32(pdu, rx, offsetp, ", st_uid"); + pprint_int32(pdu, rx, offsetp, ", st_gid"); + pprint_int64(pdu, rx, offsetp, ", st_rdev"); + pprint_int64(pdu, rx, offsetp, ", st_size"); + pprint_int64(pdu, rx, offsetp, ", st_blksize"); + pprint_int64(pdu, rx, offsetp, ", st_blocks"); + pprint_int64(pdu, rx, offsetp, ", atime"); + pprint_int64(pdu, rx, offsetp, ", atime_nsec"); + pprint_int64(pdu, rx, offsetp, ", mtime"); + pprint_int64(pdu, rx, offsetp, ", mtime_nsec"); + pprint_int64(pdu, rx, offsetp, ", ctime"); + pprint_int64(pdu, rx, offsetp, ", ctime_nsec"); + fprintf(llogfile, "}"); +} + + + static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) { int sg_count = get_sg_count(pdu, rx); @@ -351,6 +375,14 @@ void pprint_pdu(V9fsPDU *pdu) pprint_int32(pdu, 1, &offset, "msize"); pprint_str(pdu, 1, &offset, ", version"); break; + case P9_TGETATTR: + fprintf(llogfile, "TGETATTR: ("); + pprint_int32(pdu, 0, &offset, "fid"); + break; + case P9_RGETATTR: + fprintf(llogfile, "RGETATTR: ("); + pprint_stat_dotl(pdu, 1, &offset, "getattr"); + break; case P9_TAUTH: fprintf(llogfile, "TAUTH: ("); pprint_int32(pdu, 0, &offset, "afid"); diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index 00527c4..10cc003 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -736,6 +736,21 @@ static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) statp->n_gid, statp->n_muid); break; } + case 'A': { + V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *); + offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq", + statp->st_result_mask, + &statp->qid, statp->st_mode, + statp->st_uid, statp->st_gid, + statp->st_nlink, statp->st_rdev, + statp->st_size, statp->st_blksize, statp->st_blocks, + statp->st_atime_sec, statp->st_atime_nsec, + statp->st_mtime_sec, statp->st_mtime_nsec, + statp->st_ctime_sec, statp->st_ctime_nsec, + statp->st_btime_sec, statp->st_btime_nsec, + statp->st_gen, statp->st_data_version); + break; + } default: break; } @@ -963,6 +978,51 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name, return 0; } +#define P9_STATS_MODE 0x00000001ULL +#define P9_STATS_NLINK 0x00000002ULL +#define P9_STATS_UID 0x00000004ULL +#define P9_STATS_GID 0x00000008ULL +#define P9_STATS_RDEV 0x00000010ULL +#define P9_STATS_ATIME 0x00000020ULL +#define P9_STATS_MTIME 0x00000040ULL +#define P9_STATS_CTIME 0x00000080ULL +#define P9_STATS_INO 0x00000100ULL +#define P9_STATS_SIZE 0x00000200ULL +#define P9_STATS_BLOCKS 0x00000400ULL + +#define P9_STATS_BTIME 0x00000800ULL +#define P9_STATS_GEN 0x00001000ULL +#define P9_STATS_DATA_VERSION 0x00002000ULL + +#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ +#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */ + + +static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf, + V9fsStatDotl *v9lstat) +{ + memset(v9lstat, 0, sizeof(*v9lstat)); + + v9lstat->st_mode = stbuf->st_mode; + v9lstat->st_nlink = stbuf->st_nlink; + v9lstat->st_uid = stbuf->st_uid; + v9lstat->st_gid = stbuf->st_gid; + v9lstat->st_rdev = stbuf->st_rdev; + v9lstat->st_size = stbuf->st_size; + v9lstat->st_blksize = stbuf->st_blksize; + v9lstat->st_blocks = stbuf->st_blocks; + v9lstat->st_atime_sec = stbuf->st_atime; + v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec; + v9lstat->st_mtime_sec = stbuf->st_mtime; + v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec; + v9lstat->st_ctime_sec = stbuf->st_ctime; + v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec; + /* Currently we only support BASIC fields in stat */ + v9lstat->st_result_mask = P9_STATS_BASIC; + + stat_to_qid(stbuf, &v9lstat->qid); +} + static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt) { while (len && *iovcnt) { @@ -1129,6 +1189,57 @@ out: qemu_free(vs); } +static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs, + int err) +{ + if (err == -1) { + err = -errno; + goto out; + } + + stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl); + vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl); + err = vs->offset; + +out: + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu) +{ + int32_t fid; + V9fsStatStateDotl *vs; + ssize_t err = 0; + V9fsFidState *fidp; + uint64_t request_mask; + + vs = qemu_malloc(sizeof(*vs)); + vs->pdu = pdu; + vs->offset = 7; + + memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl)); + + pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask); + + fidp = lookup_fid(s, fid); + if (fidp == NULL) { + err = -ENOENT; + goto out; + } + + /* Currently we only support BASIC fields in stat, so there is no + * need to look at request_mask. + */ + err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf); + v9fs_getattr_post_lstat(s, vs, err); + return; + +out: + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err) { complete_pdu(s, vs->pdu, err); @@ -2392,6 +2503,7 @@ typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu); static pdu_handler_t *pdu_handlers[] = { [P9_TREADDIR] = v9fs_readdir, [P9_TSTATFS] = v9fs_statfs, + [P9_TGETATTR] = v9fs_getattr, [P9_TVERSION] = v9fs_version, [P9_TATTACH] = v9fs_attach, [P9_TSTAT] = v9fs_stat, diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h index 4ee3830..1feed82 100644 --- a/hw/virtio-9p.h +++ b/hw/virtio-9p.h @@ -15,6 +15,8 @@ enum { P9_TSTATFS = 8, P9_RSTATFS, + P9_TGETATTR = 24, + P9_RGETATTR, P9_TREADDIR = 40, P9_RREADDIR, P9_TVERSION = 100, @@ -185,6 +187,37 @@ typedef struct V9fsStatState { struct stat stbuf; } V9fsStatState; +typedef struct V9fsStatDotl { + uint64_t st_result_mask; + V9fsQID qid; + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_nlink; + uint64_t st_rdev; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_atime_sec; + uint64_t st_atime_nsec; + uint64_t st_mtime_sec; + uint64_t st_mtime_nsec; + uint64_t st_ctime_sec; + uint64_t st_ctime_nsec; + uint64_t st_btime_sec; + uint64_t st_btime_nsec; + uint64_t st_gen; + uint64_t st_data_version; +} V9fsStatDotl; + +typedef struct V9fsStatStateDotl { + V9fsPDU *pdu; + size_t offset; + V9fsStatDotl v9stat_dotl; + struct stat stbuf; +} V9fsStatStateDotl; + + typedef struct V9fsWalkState { V9fsPDU *pdu; size_t offset;