diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2010-04-29 17:44:44 +0530 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2010-05-03 12:17:37 -0500 |
commit | 9f10751365b26b13b8a9b67e0e90536ae3d282df (patch) | |
tree | 276d00f1b535d02d22e3a20a45582239240c5977 /hw/virtio-9p-debug.c | |
parent | 74db920c32cea5b52a91b81f2bfd467fc070e942 (diff) |
virtio-9p: Add a virtio 9p device to qemu
This patch doesn't implement the 9p protocol handling
code. It adds a simple device which dump the protocol data.
[jvrao@linux.vnet.ibm.com: Little-Endian to host format conversion]
[aneesh.kumar@linux.vnet.ibm.com: Multiple-mounts support]
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/virtio-9p-debug.c')
-rw-r--r-- | hw/virtio-9p-debug.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c new file mode 100644 index 0000000000..2fb2673d93 --- /dev/null +++ b/hw/virtio-9p-debug.c @@ -0,0 +1,484 @@ +/* + * Virtio 9p PDU debug + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include "virtio.h" +#include "pc.h" +#include "virtio-9p.h" +#include "virtio-9p-debug.h" + +#define BUG_ON(cond) assert(!(cond)) + +static FILE *llogfile; + +static struct iovec *get_sg(V9fsPDU *pdu, int rx) +{ + if (rx) { + return pdu->elem.in_sg; + } + return pdu->elem.out_sg; +} + +static int get_sg_count(V9fsPDU *pdu, int rx) +{ + if (rx) { + return pdu->elem.in_num; + } + return pdu->elem.out_num; + +} + +static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp, + const char *name) +{ + size_t copied; + int count = get_sg_count(pdu, rx); + size_t offset = *offsetp; + struct iovec *sg = get_sg(pdu, rx); + int8_t value; + + copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); + + BUG_ON(copied != sizeof(value)); + offset += sizeof(value); + fprintf(llogfile, "%s=0x%x", name, value); + *offsetp = offset; +} + +static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp, + const char *name) +{ + size_t copied; + int count = get_sg_count(pdu, rx); + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + int16_t value; + + + copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); + + BUG_ON(copied != sizeof(value)); + offset += sizeof(value); + fprintf(llogfile, "%s=0x%x", name, value); + *offsetp = offset; +} + +static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp, + const char *name) +{ + size_t copied; + int count = get_sg_count(pdu, rx); + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + int32_t value; + + + copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); + + BUG_ON(copied != sizeof(value)); + offset += sizeof(value); + fprintf(llogfile, "%s=0x%x", name, value); + *offsetp = offset; +} + +static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp, + const char *name) +{ + size_t copied; + int count = get_sg_count(pdu, rx); + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + int64_t value; + + + copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); + + BUG_ON(copied != sizeof(value)); + offset += sizeof(value); + fprintf(llogfile, "%s=0x%" PRIx64, name, value); + *offsetp = offset; +} + +static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + int sg_count = get_sg_count(pdu, rx); + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + uint16_t tmp_size, size; + size_t result; + size_t copied = 0; + int i = 0; + + /* get the size */ + copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size)); + BUG_ON(copied != sizeof(tmp_size)); + size = le16_to_cpupu(&tmp_size); + offset += copied; + + fprintf(llogfile, "%s=", name); + for (i = 0; size && i < sg_count; i++) { + size_t len; + if (offset >= sg[i].iov_len) { + /* skip this sg */ + offset -= sg[i].iov_len; + continue; + } else { + len = MIN(sg[i].iov_len - offset, size); + result = fwrite(sg[i].iov_base + offset, 1, len, llogfile); + BUG_ON(result != len); + size -= len; + copied += len; + if (size) { + offset = 0; + continue; + } + } + } + *offsetp += copied; +} + +static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + fprintf(llogfile, "%s={", name); + pprint_int8(pdu, rx, offsetp, "type"); + pprint_int32(pdu, rx, offsetp, ", version"); + pprint_int64(pdu, rx, offsetp, ", path"); + fprintf(llogfile, "}"); +} + +static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + fprintf(llogfile, "%s={", name); + pprint_int16(pdu, rx, offsetp, "size"); + pprint_int16(pdu, rx, offsetp, ", type"); + pprint_int32(pdu, rx, offsetp, ", dev"); + pprint_qid(pdu, rx, offsetp, ", qid"); + pprint_int32(pdu, rx, offsetp, ", mode"); + pprint_int32(pdu, rx, offsetp, ", atime"); + pprint_int32(pdu, rx, offsetp, ", mtime"); + pprint_int64(pdu, rx, offsetp, ", length"); + pprint_str(pdu, rx, offsetp, ", name"); + pprint_str(pdu, rx, offsetp, ", uid"); + pprint_str(pdu, rx, offsetp, ", gid"); + pprint_str(pdu, rx, offsetp, ", muid"); + if (dotu) { + pprint_str(pdu, rx, offsetp, ", extension"); + pprint_int32(pdu, rx, offsetp, ", uid"); + pprint_int32(pdu, rx, offsetp, ", gid"); + pprint_int32(pdu, rx, offsetp, ", muid"); + } + fprintf(llogfile, "}"); +} + +static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + int sg_count = get_sg_count(pdu, rx); + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + uint16_t tmp_count, count, i; + size_t copied = 0; + + fprintf(llogfile, "%s={", name); + + /* Get the count */ + copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); + BUG_ON(copied != sizeof(tmp_count)); + count = le16_to_cpupu(&tmp_count); + offset += copied; + + for (i = 0; i < count; i++) { + char str[512]; + if (i) { + fprintf(llogfile, ", "); + } + snprintf(str, sizeof(str), "[%d]", i); + pprint_str(pdu, rx, &offset, str); + } + + fprintf(llogfile, "}"); + + *offsetp = offset; +} + +static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + int sg_count = get_sg_count(pdu, rx); + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + uint16_t tmp_count, count, i; + size_t copied = 0; + + fprintf(llogfile, "%s={", name); + + copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); + BUG_ON(copied != sizeof(tmp_count)); + count = le16_to_cpupu(&tmp_count); + offset += copied; + + for (i = 0; i < count; i++) { + char str[512]; + if (i) { + fprintf(llogfile, ", "); + } + snprintf(str, sizeof(str), "[%d]", i); + pprint_qid(pdu, rx, &offset, str); + } + + fprintf(llogfile, "}"); + + *offsetp = offset; +} + +static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + struct iovec *sg = get_sg(pdu, rx); + unsigned int count; + int i; + + if (rx) { + count = pdu->elem.in_num; + } else { + count = pdu->elem.out_num; + } + + fprintf(llogfile, "%s={", name); + for (i = 0; i < count; i++) { + if (i) { + fprintf(llogfile, ", "); + } + fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len); + } + fprintf(llogfile, "}"); +} + +/* FIXME: read from a directory fid returns serialized stat_t's */ +#ifdef DEBUG_DATA +static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) +{ + struct iovec *sg = get_sg(pdu, rx); + size_t offset = *offsetp; + unsigned int count; + int32_t size; + int total, i, j; + ssize_t len; + + if (rx) { + count = pdu->elem.in_num; + } else + count = pdu->elem.out_num; + } + + BUG_ON((offset + sizeof(size)) > sg[0].iov_len); + + memcpy(&size, sg[0].iov_base + offset, sizeof(size)); + offset += sizeof(size); + + fprintf(llogfile, "size: %x\n", size); + + sg[0].iov_base += 11; /* skip header */ + sg[0].iov_len -= 11; + + total = 0; + for (i = 0; i < count; i++) { + total += sg[i].iov_len; + if (total >= size) { + /* trim sg list so writev does the right thing */ + sg[i].iov_len -= (total - size); + i++; + break; + } + } + + fprintf(llogfile, "%s={\"", name); + fflush(llogfile); + for (j = 0; j < i; j++) { + if (j) { + fprintf(llogfile, "\", \""); + fflush(llogfile); + } + + do { + len = writev(fileno(llogfile), &sg[j], 1); + } while (len == -1 && errno == EINTR); + fprintf(llogfile, "len == %ld: %m\n", len); + BUG_ON(len != sg[j].iov_len); + } + fprintf(llogfile, "\"}"); + + sg[0].iov_base -= 11; + sg[0].iov_len += 11; + +} +#endif + +void pprint_pdu(V9fsPDU *pdu) +{ + size_t offset = 7; + + if (llogfile == NULL) { + llogfile = fopen("/tmp/pdu.log", "w"); + } + + switch (pdu->id) { + case P9_TVERSION: + fprintf(llogfile, "TVERSION: ("); + pprint_int32(pdu, 0, &offset, "msize"); + pprint_str(pdu, 0, &offset, ", version"); + break; + case P9_RVERSION: + fprintf(llogfile, "RVERSION: ("); + pprint_int32(pdu, 1, &offset, "msize"); + pprint_str(pdu, 1, &offset, ", version"); + break; + case P9_TAUTH: + fprintf(llogfile, "TAUTH: ("); + pprint_int32(pdu, 0, &offset, "afid"); + pprint_str(pdu, 0, &offset, ", uname"); + pprint_str(pdu, 0, &offset, ", aname"); + if (dotu) { + pprint_int32(pdu, 0, &offset, ", n_uname"); + } + break; + case P9_RAUTH: + fprintf(llogfile, "RAUTH: ("); + pprint_qid(pdu, 1, &offset, "qid"); + break; + case P9_TATTACH: + fprintf(llogfile, "TATTACH: ("); + pprint_int32(pdu, 0, &offset, "fid"); + pprint_int32(pdu, 0, &offset, ", afid"); + pprint_str(pdu, 0, &offset, ", uname"); + pprint_str(pdu, 0, &offset, ", aname"); + if (dotu) { + pprint_int32(pdu, 0, &offset, ", n_uname"); + } + break; + case P9_RATTACH: + fprintf(llogfile, "RATTACH: ("); + pprint_qid(pdu, 1, &offset, "qid"); + break; + case P9_TERROR: + fprintf(llogfile, "TERROR: ("); + break; + case P9_RERROR: + fprintf(llogfile, "RERROR: ("); + pprint_str(pdu, 1, &offset, "ename"); + if (dotu) { + pprint_int32(pdu, 1, &offset, ", ecode"); + } + break; + case P9_TFLUSH: + fprintf(llogfile, "TFLUSH: ("); + pprint_int16(pdu, 0, &offset, "oldtag"); + break; + case P9_RFLUSH: + fprintf(llogfile, "RFLUSH: ("); + break; + case P9_TWALK: + fprintf(llogfile, "TWALK: ("); + pprint_int32(pdu, 0, &offset, "fid"); + pprint_int32(pdu, 0, &offset, ", newfid"); + pprint_strs(pdu, 0, &offset, ", wnames"); + break; + case P9_RWALK: + fprintf(llogfile, "RWALK: ("); + pprint_qids(pdu, 1, &offset, "wqids"); + break; + case P9_TOPEN: + fprintf(llogfile, "TOPEN: ("); + pprint_int32(pdu, 0, &offset, "fid"); + pprint_int8(pdu, 0, &offset, ", mode"); + break; + case P9_ROPEN: + fprintf(llogfile, "ROPEN: ("); + pprint_qid(pdu, 1, &offset, "qid"); + pprint_int32(pdu, 1, &offset, ", iounit"); + break; + case P9_TCREATE: + fprintf(llogfile, "TCREATE: ("); + pprint_int32(pdu, 0, &offset, "fid"); + pprint_str(pdu, 0, &offset, ", name"); + pprint_int32(pdu, 0, &offset, ", perm"); + pprint_int8(pdu, 0, &offset, ", mode"); + if (dotu) { + pprint_str(pdu, 0, &offset, ", extension"); + } + break; + case P9_RCREATE: + fprintf(llogfile, "RCREATE: ("); + pprint_qid(pdu, 1, &offset, "qid"); + pprint_int32(pdu, 1, &offset, ", iounit"); + break; + case P9_TREAD: + fprintf(llogfile, "TREAD: ("); + pprint_int32(pdu, 0, &offset, "fid"); + pprint_int64(pdu, 0, &offset, ", offset"); + pprint_int32(pdu, 0, &offset, ", count"); + pprint_sg(pdu, 0, &offset, ", sg"); + break; + case P9_RREAD: + fprintf(llogfile, "RREAD: ("); + pprint_int32(pdu, 1, &offset, "count"); + pprint_sg(pdu, 1, &offset, ", sg"); + offset = 7; +#ifdef DEBUG_DATA + pprint_data(pdu, 1, &offset, ", data"); +#endif + break; + case P9_TWRITE: + fprintf(llogfile, "TWRITE: ("); + pprint_int32(pdu, 0, &offset, "fid"); + pprint_int64(pdu, 0, &offset, ", offset"); + pprint_int32(pdu, 0, &offset, ", count"); + break; + case P9_RWRITE: + fprintf(llogfile, "RWRITE: ("); + pprint_int32(pdu, 1, &offset, "count"); + break; + case P9_TCLUNK: + fprintf(llogfile, "TCLUNK: ("); + pprint_int32(pdu, 0, &offset, "fid"); + break; + case P9_RCLUNK: + fprintf(llogfile, "RCLUNK: ("); + break; + case P9_TREMOVE: + fprintf(llogfile, "TREMOVE: ("); + pprint_int32(pdu, 0, &offset, "fid"); + break; + case P9_RREMOVE: + fprintf(llogfile, "RREMOVE: ("); + break; + case P9_TSTAT: + fprintf(llogfile, "TSTAT: ("); + pprint_int32(pdu, 0, &offset, "fid"); + break; + case P9_RSTAT: + fprintf(llogfile, "RSTAT: ("); + offset += 2; /* ignored */ + pprint_stat(pdu, 1, &offset, "stat"); + break; + case P9_TWSTAT: + fprintf(llogfile, "TWSTAT: ("); + pprint_int32(pdu, 0, &offset, "fid"); + offset += 2; /* ignored */ + pprint_stat(pdu, 0, &offset, ", stat"); + break; + case P9_RWSTAT: + fprintf(llogfile, "RWSTAT: ("); + break; + default: + fprintf(llogfile, "unknown(%d): (", pdu->id); + break; + } + + fprintf(llogfile, ")\n"); +} |