11c7850f9SSasha Levin #include "kvm/virtio-9p.h" 21c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h" 31c7850f9SSasha Levin #include "kvm/virtio.h" 41c7850f9SSasha Levin #include "kvm/ioport.h" 51c7850f9SSasha Levin #include "kvm/mutex.h" 61c7850f9SSasha Levin #include "kvm/util.h" 71c7850f9SSasha Levin #include "kvm/kvm.h" 81c7850f9SSasha Levin #include "kvm/pci.h" 91c7850f9SSasha Levin #include "kvm/threadpool.h" 101c7850f9SSasha Levin #include "kvm/irq.h" 1160eb42d5SSasha Levin #include "kvm/ioeventfd.h" 121c7850f9SSasha Levin 131c7850f9SSasha Levin #include <fcntl.h> 141c7850f9SSasha Levin #include <sys/types.h> 151c7850f9SSasha Levin #include <sys/stat.h> 161c7850f9SSasha Levin #include <pthread.h> 171c7850f9SSasha Levin #include <dirent.h> 181c7850f9SSasha Levin 192daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 202daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 212daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 222daa28d4SAneesh Kumar K.V 231c7850f9SSasha Levin #define NUM_VIRT_QUEUES 1 24612038c5SAneesh Kumar K.V #define VIRTQUEUE_NUM 128 25b4422bf3SAneesh Kumar K.V #define VIRTIO_P9_DEFAULT_TAG "kvm_9p" 261c7850f9SSasha Levin #define VIRTIO_P9_HDR_LEN (sizeof(u32)+sizeof(u8)+sizeof(u16)) 271c7850f9SSasha Levin #define VIRTIO_P9_MAX_FID 128 281c7850f9SSasha Levin #define VIRTIO_P9_VERSION "9P2000" 29b4422bf3SAneesh Kumar K.V #define MAX_TAG_LEN 32 30b4422bf3SAneesh Kumar K.V 311c7850f9SSasha Levin 321c7850f9SSasha Levin struct p9_msg { 331c7850f9SSasha Levin u32 size; 341c7850f9SSasha Levin u8 cmd; 351c7850f9SSasha Levin u16 tag; 361c7850f9SSasha Levin u8 msg[0]; 371c7850f9SSasha Levin } __attribute__((packed)); 381c7850f9SSasha Levin 391c7850f9SSasha Levin struct p9_fid { 401c7850f9SSasha Levin u32 fid; 411c7850f9SSasha Levin u8 is_dir; 421c7850f9SSasha Levin char abs_path[PATH_MAX]; 431c7850f9SSasha Levin char *path; 441c7850f9SSasha Levin DIR *dir; 451c7850f9SSasha Levin int fd; 461c7850f9SSasha Levin }; 471c7850f9SSasha Levin 48b4422bf3SAneesh Kumar K.V struct p9_dev_job { 49b4422bf3SAneesh Kumar K.V struct virt_queue *vq; 50b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 51b4422bf3SAneesh Kumar K.V void *job_id; 521c7850f9SSasha Levin }; 531c7850f9SSasha Levin 541c7850f9SSasha Levin struct p9_dev { 551c7850f9SSasha Levin u8 status; 561c7850f9SSasha Levin u8 isr; 571c7850f9SSasha Levin u16 config_vector; 581c7850f9SSasha Levin u32 features; 591c7850f9SSasha Levin struct virtio_9p_config *config; 60f884f920SSasha Levin u16 base_addr; 611c7850f9SSasha Levin 621c7850f9SSasha Levin /* virtio queue */ 631c7850f9SSasha Levin u16 queue_selector; 641c7850f9SSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 65b4422bf3SAneesh Kumar K.V struct p9_dev_job jobs[NUM_VIRT_QUEUES]; 661c7850f9SSasha Levin struct p9_fid fids[VIRTIO_P9_MAX_FID]; 671c7850f9SSasha Levin char root_dir[PATH_MAX]; 68b4422bf3SAneesh Kumar K.V struct pci_device_header pci_hdr; 691c7850f9SSasha Levin }; 701c7850f9SSasha Levin 71af045e53SAneesh Kumar K.V struct p9_pdu { 72af045e53SAneesh Kumar K.V u32 queue_head; 73af045e53SAneesh Kumar K.V int offset; 74af045e53SAneesh Kumar K.V u16 out_iov_cnt; 75af045e53SAneesh Kumar K.V u16 in_iov_cnt; 76af045e53SAneesh Kumar K.V struct iovec in_iov[VIRTQUEUE_NUM]; 77af045e53SAneesh Kumar K.V struct iovec out_iov[VIRTQUEUE_NUM]; 78af045e53SAneesh Kumar K.V }; 79af045e53SAneesh Kumar K.V 801c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 81b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 82b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 831c7850f9SSasha Levin { 84b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 851c7850f9SSasha Levin 861c7850f9SSasha Levin return abs_path; 871c7850f9SSasha Levin } 881c7850f9SSasha Levin 89b4422bf3SAneesh Kumar K.V static bool virtio_p9_dev_in(struct p9_dev *p9dev, void *data, 90b4422bf3SAneesh Kumar K.V unsigned long offset, 91b4422bf3SAneesh Kumar K.V int size, u32 count) 921c7850f9SSasha Levin { 93b4422bf3SAneesh Kumar K.V u8 *config_space = (u8 *) p9dev->config; 941c7850f9SSasha Levin 951c7850f9SSasha Levin if (size != 1 || count != 1) 961c7850f9SSasha Levin return false; 971c7850f9SSasha Levin 981c7850f9SSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 991c7850f9SSasha Levin 1001c7850f9SSasha Levin return true; 1011c7850f9SSasha Levin } 1021c7850f9SSasha Levin 103b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, 104b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 1051c7850f9SSasha Levin { 1061c7850f9SSasha Levin bool ret = true; 107b4422bf3SAneesh Kumar K.V unsigned long offset; 108b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = ioport->priv; 1091c7850f9SSasha Levin 110b4422bf3SAneesh Kumar K.V 111b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 1121c7850f9SSasha Levin 1131c7850f9SSasha Levin switch (offset) { 1141c7850f9SSasha Levin case VIRTIO_PCI_HOST_FEATURES: 115b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->features); 1161c7850f9SSasha Levin ret = true; 1171c7850f9SSasha Levin break; 1181c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 1191c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 1201c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 1211c7850f9SSasha Levin ret = false; 1221c7850f9SSasha Levin break; 1231c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: 124b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->vqs[p9dev->queue_selector].pfn); 1251c7850f9SSasha Levin break; 1261c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NUM: 127612038c5SAneesh Kumar K.V ioport__write16(data, VIRTQUEUE_NUM); 1281c7850f9SSasha Levin break; 1291c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 130b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->status); 1311c7850f9SSasha Levin break; 1321c7850f9SSasha Levin case VIRTIO_PCI_ISR: 133b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->isr); 134b4422bf3SAneesh Kumar K.V kvm__irq_line(kvm, p9dev->pci_hdr.irq_line, VIRTIO_IRQ_LOW); 135b4422bf3SAneesh Kumar K.V p9dev->isr = VIRTIO_IRQ_LOW; 1361c7850f9SSasha Levin break; 1371c7850f9SSasha Levin default: 138b4422bf3SAneesh Kumar K.V ret = virtio_p9_dev_in(p9dev, data, offset, size, count); 1391c7850f9SSasha Levin break; 1401c7850f9SSasha Levin }; 1411c7850f9SSasha Levin 1421c7850f9SSasha Levin return ret; 1431c7850f9SSasha Levin } 1441c7850f9SSasha Levin 1451c7850f9SSasha Levin static int omode2uflags(u8 mode) 1461c7850f9SSasha Levin { 1471c7850f9SSasha Levin int ret = 0; 1481c7850f9SSasha Levin 1491c7850f9SSasha Levin /* Basic open modes are same as uflags */ 1501c7850f9SSasha Levin ret = mode & 3; 1511c7850f9SSasha Levin 1521c7850f9SSasha Levin /* Everything else is different */ 1531c7850f9SSasha Levin if (mode & P9_OTRUNC) 1541c7850f9SSasha Levin ret |= O_TRUNC; 1551c7850f9SSasha Levin 1561c7850f9SSasha Levin if (mode & P9_OAPPEND) 1571c7850f9SSasha Levin ret |= O_APPEND; 1581c7850f9SSasha Levin 1591c7850f9SSasha Levin if (mode & P9_OEXCL) 1601c7850f9SSasha Levin ret |= O_EXCL; 1611c7850f9SSasha Levin 1621c7850f9SSasha Levin return ret; 1631c7850f9SSasha Levin } 1641c7850f9SSasha Levin 1651c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid) 1661c7850f9SSasha Levin { 1671c7850f9SSasha Levin *qid = (struct p9_qid) { 1681c7850f9SSasha Levin .path = st->st_ino, 1691c7850f9SSasha Levin .version = st->st_mtime, 1701c7850f9SSasha Levin }; 1711c7850f9SSasha Levin 1721c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1731c7850f9SSasha Levin qid->type |= P9_QTDIR; 1741c7850f9SSasha Levin } 1751c7850f9SSasha Levin 176b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1771c7850f9SSasha Levin { 178b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 179b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 180b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 1811c7850f9SSasha Levin } 182b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 183b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 184b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 1851c7850f9SSasha Levin } 1861c7850f9SSasha Levin } 1871c7850f9SSasha Levin 1881c7850f9SSasha Levin static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag) 1891c7850f9SSasha Levin { 1901c7850f9SSasha Levin *msg = (struct p9_msg) { 1911c7850f9SSasha Levin .size = size, 1921c7850f9SSasha Levin .tag = tag, 1931c7850f9SSasha Levin .cmd = cmd, 1941c7850f9SSasha Levin }; 1951c7850f9SSasha Levin } 1961c7850f9SSasha Levin 1976b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1986b163a87SAneesh Kumar K.V { 1996b163a87SAneesh Kumar K.V int i; 2006b163a87SAneesh Kumar K.V u32 total = 0; 2016b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 2026b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 2036b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 2046b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 2056b163a87SAneesh Kumar K.V i++; 2066b163a87SAneesh Kumar K.V break; 2076b163a87SAneesh Kumar K.V } 2086b163a87SAneesh Kumar K.V total += iov[i].iov_len; 2096b163a87SAneesh Kumar K.V } 2106b163a87SAneesh Kumar K.V return i; 2116b163a87SAneesh Kumar K.V } 2126b163a87SAneesh Kumar K.V 213eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 214eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 215eee1ba8eSAneesh Kumar K.V { 216eee1ba8eSAneesh Kumar K.V char *err_str; 217eee1ba8eSAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 218eee1ba8eSAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 219eee1ba8eSAneesh Kumar K.V struct p9_rerror *rerror = (struct p9_rerror *)inmsg->msg; 220eee1ba8eSAneesh Kumar K.V 221eee1ba8eSAneesh Kumar K.V err_str = strerror(err); 222eee1ba8eSAneesh Kumar K.V rerror->error.len = strlen(err_str); 223eee1ba8eSAneesh Kumar K.V memcpy(&rerror->error.str, err_str, rerror->error.len); 224eee1ba8eSAneesh Kumar K.V 225eee1ba8eSAneesh Kumar K.V *outlen = VIRTIO_P9_HDR_LEN + rerror->error.len + sizeof(u16); 226eee1ba8eSAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RERROR, outmsg->tag); 227eee1ba8eSAneesh Kumar K.V } 228eee1ba8eSAneesh Kumar K.V 229ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 230af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2311c7850f9SSasha Levin { 232af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 233af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 234af045e53SAneesh Kumar K.V struct p9_rversion *rversion = (struct p9_rversion *)inmsg->msg; 2351c7850f9SSasha Levin 2361c7850f9SSasha Levin rversion->msize = 4096; 2371c7850f9SSasha Levin rversion->version.len = strlen(VIRTIO_P9_VERSION); 2381c7850f9SSasha Levin memcpy(&rversion->version.str, VIRTIO_P9_VERSION, rversion->version.len); 2391c7850f9SSasha Levin 240b4422bf3SAneesh Kumar K.V *outlen = VIRTIO_P9_HDR_LEN + 241b4422bf3SAneesh Kumar K.V rversion->version.len + sizeof(u16) + sizeof(u32); 242af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RVERSION, outmsg->tag); 2431c7850f9SSasha Levin 244ead43b01SAneesh Kumar K.V return; 2451c7850f9SSasha Levin } 2461c7850f9SSasha Levin 247ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 248af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2491c7850f9SSasha Levin { 250af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 251af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 252af045e53SAneesh Kumar K.V struct p9_tclunk *tclunk = (struct p9_tclunk *)outmsg->msg; 2531c7850f9SSasha Levin 254b4422bf3SAneesh Kumar K.V close_fid(p9dev, tclunk->fid); 2551c7850f9SSasha Levin 2561c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 257af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RCLUNK, outmsg->tag); 2581c7850f9SSasha Levin 259ead43b01SAneesh Kumar K.V return; 2601c7850f9SSasha Levin } 2611c7850f9SSasha Levin 262ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 263af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2641c7850f9SSasha Levin { 2651c7850f9SSasha Levin struct stat st; 266af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 267af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 268af045e53SAneesh Kumar K.V struct p9_topen *topen = (struct p9_topen *)outmsg->msg; 269af045e53SAneesh Kumar K.V struct p9_ropen *ropen = (struct p9_ropen *)inmsg->msg; 270af045e53SAneesh Kumar K.V struct p9_fid *new_fid = &p9dev->fids[topen->fid]; 2711c7850f9SSasha Levin 27230204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 273eee1ba8eSAneesh Kumar K.V goto err_out; 2741c7850f9SSasha Levin 2751c7850f9SSasha Levin st2qid(&st, &ropen->qid); 2761c7850f9SSasha Levin ropen->iounit = 0; 2771c7850f9SSasha Levin 278eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 2791c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 280eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 281eee1ba8eSAneesh Kumar K.V goto err_out; 282eee1ba8eSAneesh Kumar K.V } else { 283eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 284eee1ba8eSAneesh Kumar K.V omode2uflags(topen->mode) | O_NOFOLLOW); 285eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 286eee1ba8eSAneesh Kumar K.V goto err_out; 287eee1ba8eSAneesh Kumar K.V } 2881c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*ropen); 289af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_ROPEN, outmsg->tag); 290ead43b01SAneesh Kumar K.V return; 291eee1ba8eSAneesh Kumar K.V err_out: 292eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 293ead43b01SAneesh Kumar K.V return; 2941c7850f9SSasha Levin } 2951c7850f9SSasha Levin 296ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 297af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2981c7850f9SSasha Levin { 2991c7850f9SSasha Levin u8 mode; 3001c7850f9SSasha Levin u32 perm; 301af045e53SAneesh Kumar K.V struct stat st; 302af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 303af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 304af045e53SAneesh Kumar K.V struct p9_tcreate *tcreate = (struct p9_tcreate *)outmsg->msg; 305af045e53SAneesh Kumar K.V struct p9_rcreate *rcreate = (struct p9_rcreate *)inmsg->msg; 306af045e53SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tcreate->fid]; 307af045e53SAneesh Kumar K.V 3081c7850f9SSasha Levin 3091c7850f9SSasha Levin rcreate->iounit = 0; 3101c7850f9SSasha Levin 3111c7850f9SSasha Levin /* Get last byte of the variable length struct */ 312af045e53SAneesh Kumar K.V mode = *((u8 *)outmsg + outmsg->size - 1); 313af045e53SAneesh Kumar K.V perm = *(u32 *)((u8 *)outmsg + outmsg->size - 5); 3141c7850f9SSasha Levin 3151c7850f9SSasha Levin sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str); 3161c7850f9SSasha Levin 317b4422bf3SAneesh Kumar K.V close_fid(p9dev, tcreate->fid); 3181c7850f9SSasha Levin 3191c7850f9SSasha Levin if (perm & P9_DMDIR) { 3201c7850f9SSasha Levin mkdir(fid->abs_path, perm & 0xFFFF); 3211c7850f9SSasha Levin fid->dir = opendir(fid->abs_path); 3221c7850f9SSasha Levin fid->is_dir = 1; 3231c7850f9SSasha Levin } else { 3241c7850f9SSasha Levin fid->fd = open(fid->abs_path, omode2uflags(mode) | O_CREAT, 0777); 3251c7850f9SSasha Levin } 3261c7850f9SSasha Levin 32730204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 328*6c8ca053SAneesh Kumar K.V goto err_out; 3291c7850f9SSasha Levin 3301c7850f9SSasha Levin st2qid(&st, &rcreate->qid); 3311c7850f9SSasha Levin 3321c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rcreate); 333af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RCREATE, outmsg->tag); 334*6c8ca053SAneesh Kumar K.V return; 335*6c8ca053SAneesh Kumar K.V err_out: 336*6c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 337ead43b01SAneesh Kumar K.V return; 3381c7850f9SSasha Levin } 3391c7850f9SSasha Levin 340ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 341af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3421c7850f9SSasha Levin { 343af045e53SAneesh Kumar K.V u8 i; 344af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 345af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 346af045e53SAneesh Kumar K.V struct p9_twalk *twalk = (struct p9_twalk *)outmsg->msg; 347af045e53SAneesh Kumar K.V struct p9_rwalk *rwalk = (struct p9_rwalk *)inmsg->msg; 3481c7850f9SSasha Levin struct p9_str *str = twalk->wnames; 349b4422bf3SAneesh Kumar K.V struct p9_fid *new_fid = &p9dev->fids[twalk->newfid]; 350af045e53SAneesh Kumar K.V 3511c7850f9SSasha Levin 3521c7850f9SSasha Levin rwalk->nwqid = 0; 3531c7850f9SSasha Levin if (twalk->nwname) { 354b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[twalk->fid]; 3551c7850f9SSasha Levin 3561c7850f9SSasha Levin for (i = 0; i < twalk->nwname; i++) { 3571c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3581c7850f9SSasha Levin char full_path[PATH_MAX]; 3591c7850f9SSasha Levin struct stat st; 3601c7850f9SSasha Levin 3611c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 362af045e53SAneesh Kumar K.V sprintf(tmp, "%s/%.*s", fid->path, 363af045e53SAneesh Kumar K.V str->len, (char *)&str->str); 3641c7850f9SSasha Levin 36530204a77SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 366*6c8ca053SAneesh Kumar K.V goto err_out; 3671c7850f9SSasha Levin 3681c7850f9SSasha Levin st2qid(&st, &rwalk->wqids[i]); 3691c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3701c7850f9SSasha Levin strcpy(new_fid->path, tmp); 3711c7850f9SSasha Levin new_fid->fid = twalk->newfid; 3721c7850f9SSasha Levin rwalk->nwqid++; 3731c7850f9SSasha Levin } 3741c7850f9SSasha Levin } else { 375b4422bf3SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[twalk->fid].is_dir; 376b4422bf3SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[twalk->fid].path); 3771c7850f9SSasha Levin new_fid->fid = twalk->newfid; 3781c7850f9SSasha Levin } 3791c7850f9SSasha Levin 380af045e53SAneesh Kumar K.V *outlen = VIRTIO_P9_HDR_LEN + sizeof(u16) + 381af045e53SAneesh Kumar K.V sizeof(struct p9_qid)*rwalk->nwqid; 382af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RWALK, outmsg->tag); 383*6c8ca053SAneesh Kumar K.V return; 384*6c8ca053SAneesh Kumar K.V err_out: 385*6c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 386ead43b01SAneesh Kumar K.V return; 3871c7850f9SSasha Levin } 3881c7850f9SSasha Levin 389ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 390af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3911c7850f9SSasha Levin { 392af045e53SAneesh Kumar K.V u32 i; 3931c7850f9SSasha Levin struct stat st; 3941c7850f9SSasha Levin struct p9_fid *fid; 395af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 396af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 397af045e53SAneesh Kumar K.V struct p9_rattach *rattach = (struct p9_rattach *)inmsg->msg; 398af045e53SAneesh Kumar K.V struct p9_tattach *tattach = (struct p9_tattach *)outmsg->msg; 3991c7850f9SSasha Levin 4001c7850f9SSasha Levin /* Reset everything */ 4011c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 402b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 4031c7850f9SSasha Levin 40430204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 405*6c8ca053SAneesh Kumar K.V goto err_out; 4061c7850f9SSasha Levin 4071c7850f9SSasha Levin st2qid(&st, &rattach->qid); 4081c7850f9SSasha Levin 409b4422bf3SAneesh Kumar K.V fid = &p9dev->fids[tattach->fid]; 4101c7850f9SSasha Levin fid->fid = tattach->fid; 4111c7850f9SSasha Levin fid->is_dir = 1; 4121c7850f9SSasha Levin strcpy(fid->path, "/"); 4131c7850f9SSasha Levin 4141c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rattach); 415af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RATTACH, outmsg->tag); 416*6c8ca053SAneesh Kumar K.V return; 417*6c8ca053SAneesh Kumar K.V err_out: 418*6c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 419ead43b01SAneesh Kumar K.V return; 4201c7850f9SSasha Levin } 4211c7850f9SSasha Levin 422b4422bf3SAneesh Kumar K.V static u32 virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, 423b4422bf3SAneesh Kumar K.V struct stat *st, struct p9_rstat *rstat) 4241c7850f9SSasha Levin { 4251c7850f9SSasha Levin struct p9_str *str; 4261c7850f9SSasha Levin 4271c7850f9SSasha Levin rstat->stat.type = 0; 4281c7850f9SSasha Levin rstat->stat.dev = 0; 4291c7850f9SSasha Levin st2qid(st, &rstat->stat.qid); 4301c7850f9SSasha Levin rstat->stat.mode = st->st_mode; 4311c7850f9SSasha Levin rstat->stat.length = st->st_size; 4321c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) { 4331c7850f9SSasha Levin rstat->stat.length = 0; 4341c7850f9SSasha Levin rstat->stat.mode |= P9_DMDIR; 4351c7850f9SSasha Levin } 4361c7850f9SSasha Levin 4371c7850f9SSasha Levin rstat->stat.atime = st->st_atime; 4381c7850f9SSasha Levin rstat->stat.mtime = st->st_mtime; 4391c7850f9SSasha Levin 4401c7850f9SSasha Levin str = (struct p9_str *)&rstat->stat.name; 4411c7850f9SSasha Levin str->len = strlen(name); 4421c7850f9SSasha Levin memcpy(&str->str, name, str->len); 4431c7850f9SSasha Levin str = (void *)str + str->len + sizeof(u16); 4441c7850f9SSasha Levin 4451c7850f9SSasha Levin /* TODO: Pass usernames to the client */ 4461c7850f9SSasha Levin str->len = 0; 4471c7850f9SSasha Levin str = (void *)str + sizeof(u16); 4481c7850f9SSasha Levin str->len = 0; 4491c7850f9SSasha Levin str = (void *)str + sizeof(u16); 4501c7850f9SSasha Levin str->len = 0; 4511c7850f9SSasha Levin str = (void *)str + sizeof(u16); 4521c7850f9SSasha Levin 453b4422bf3SAneesh Kumar K.V /* 454b4422bf3SAneesh Kumar K.V * We subtract a u16 here because rstat->size 455b4422bf3SAneesh Kumar K.V * doesn't include rstat->size itself 456b4422bf3SAneesh Kumar K.V */ 4571c7850f9SSasha Levin rstat->stat.size = (void *)str - (void *)&rstat->stat - sizeof(u16); 4581c7850f9SSasha Levin 4591c7850f9SSasha Levin return rstat->stat.size + sizeof(u16); 4601c7850f9SSasha Levin } 4611c7850f9SSasha Levin 462ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 463af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4641c7850f9SSasha Levin { 465af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 466af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 467af045e53SAneesh Kumar K.V struct p9_tread *tread = (struct p9_tread *)outmsg->msg; 468af045e53SAneesh Kumar K.V struct p9_rread *rread = (struct p9_rread *)inmsg->msg; 469af045e53SAneesh Kumar K.V struct p9_rstat *rstat = (struct p9_rstat *)pdu->in_iov[1].iov_base; 470b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tread->fid]; 4711c7850f9SSasha Levin struct stat st; 4721c7850f9SSasha Levin 4731c7850f9SSasha Levin rread->count = 0; 4741c7850f9SSasha Levin 4751c7850f9SSasha Levin if (fid->is_dir) { 4761c7850f9SSasha Levin /* If reading a dir, fill the buffer with p9_stat entries */ 4771c7850f9SSasha Levin struct dirent *cur = readdir(fid->dir); 4781c7850f9SSasha Levin char full_path[PATH_MAX]; 4791c7850f9SSasha Levin 4801c7850f9SSasha Levin while (cur) { 4811c7850f9SSasha Levin u32 read; 4821c7850f9SSasha Levin 48330204a77SAneesh Kumar K.V lstat(rel_to_abs(p9dev, cur->d_name, full_path), &st); 484b4422bf3SAneesh Kumar K.V read = virtio_p9_fill_stat(p9dev, cur->d_name, 485b4422bf3SAneesh Kumar K.V &st, rstat); 4861c7850f9SSasha Levin rread->count += read; 4871c7850f9SSasha Levin rstat = (void *)rstat + read; 4881c7850f9SSasha Levin cur = readdir(fid->dir); 4891c7850f9SSasha Levin } 4901c7850f9SSasha Levin } else { 491af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 492af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 4936b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 4946b163a87SAneesh Kumar K.V tread->count, 4956b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 496af045e53SAneesh Kumar K.V rread->count = preadv(fid->fd, pdu->in_iov, 497af045e53SAneesh Kumar K.V pdu->in_iov_cnt, tread->offset); 4981c7850f9SSasha Levin if (rread->count > tread->count) 4991c7850f9SSasha Levin rread->count = tread->count; 5001c7850f9SSasha Levin } 5011c7850f9SSasha Levin 5021c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32) + rread->count; 503af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RREAD, outmsg->tag); 5041c7850f9SSasha Levin 505ead43b01SAneesh Kumar K.V return; 5061c7850f9SSasha Levin } 5071c7850f9SSasha Levin 508ead43b01SAneesh Kumar K.V static void virtio_p9_stat(struct p9_dev *p9dev, 509af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5101c7850f9SSasha Levin { 5111c7850f9SSasha Levin u32 ret; 512af045e53SAneesh Kumar K.V struct stat st; 513af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 514af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 515af045e53SAneesh Kumar K.V struct p9_tstat *tstat = (struct p9_tstat *)outmsg->msg; 516af045e53SAneesh Kumar K.V struct p9_rstat *rstat = (struct p9_rstat *)(inmsg->msg + sizeof(u16)); 517af045e53SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tstat->fid]; 5181c7850f9SSasha Levin 51930204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 520*6c8ca053SAneesh Kumar K.V goto err_out; 5211c7850f9SSasha Levin 522b4422bf3SAneesh Kumar K.V ret = virtio_p9_fill_stat(p9dev, fid->path, &st, rstat); 5231c7850f9SSasha Levin 524c81fc2c7SAneesh Kumar K.V *outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16); 525af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RSTAT, outmsg->tag); 526ead43b01SAneesh Kumar K.V return; 527*6c8ca053SAneesh Kumar K.V err_out: 528*6c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 529*6c8ca053SAneesh Kumar K.V return; 5301c7850f9SSasha Levin } 5311c7850f9SSasha Levin 532ead43b01SAneesh Kumar K.V static void virtio_p9_wstat(struct p9_dev *p9dev, 533af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5341c7850f9SSasha Levin { 535aec426f0SCyrill Gorcunov int res = 0; 536af045e53SAneesh Kumar K.V struct p9_str *str; 537af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 538af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 539af045e53SAneesh Kumar K.V struct p9_twstat *twstat = (struct p9_twstat *)outmsg->msg; 540af045e53SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[twstat->fid]; 541af045e53SAneesh Kumar K.V 5421c7850f9SSasha Levin 5431c7850f9SSasha Levin if (twstat->stat.length != -1UL) 5441c7850f9SSasha Levin res = ftruncate(fid->fd, twstat->stat.length); 5451c7850f9SSasha Levin 5461c7850f9SSasha Levin if (twstat->stat.mode != -1U) 5471c7850f9SSasha Levin chmod(fid->abs_path, twstat->stat.mode & 0xFFFF); 5481c7850f9SSasha Levin 5491c7850f9SSasha Levin str = (void *)&twstat->stat.name + sizeof(u16); 5501c7850f9SSasha Levin if (str->len > 0) { 5511c7850f9SSasha Levin char new_name[PATH_MAX] = {0}; 5521c7850f9SSasha Levin char full_path[PATH_MAX]; 5531c7850f9SSasha Levin char *last_dir = strrchr(fid->path, '/'); 5541c7850f9SSasha Levin 5551c7850f9SSasha Levin /* We need to get the full file name out of twstat->name */ 5561c7850f9SSasha Levin if (last_dir) 5571c7850f9SSasha Levin strncpy(new_name, fid->path, last_dir - fid->path + 1); 5581c7850f9SSasha Levin 5591c7850f9SSasha Levin memcpy(new_name + strlen(new_name), &str->str, str->len); 5601c7850f9SSasha Levin 5611c7850f9SSasha Levin /* fid is reused for the new file */ 562b4422bf3SAneesh Kumar K.V rename(fid->abs_path, rel_to_abs(p9dev, new_name, full_path)); 5631c7850f9SSasha Levin sprintf(fid->path, "%s", new_name); 5641c7850f9SSasha Levin } 5651c7850f9SSasha Levin 5661c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 567af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RWSTAT, outmsg->tag); 568aec426f0SCyrill Gorcunov 569ead43b01SAneesh Kumar K.V return; 5701c7850f9SSasha Levin } 5711c7850f9SSasha Levin 572ead43b01SAneesh Kumar K.V static void virtio_p9_remove(struct p9_dev *p9dev, 573af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5741c7850f9SSasha Levin { 575af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 576af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 577af045e53SAneesh Kumar K.V struct p9_tremove *tremove = (struct p9_tremove *)outmsg->msg; 578b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tremove->fid]; 5791c7850f9SSasha Levin 580b4422bf3SAneesh Kumar K.V close_fid(p9dev, tremove->fid); 5811c7850f9SSasha Levin if (fid->is_dir) 5821c7850f9SSasha Levin rmdir(fid->abs_path); 5831c7850f9SSasha Levin else 5841c7850f9SSasha Levin unlink(fid->abs_path); 5851c7850f9SSasha Levin 5861c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 587af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RREMOVE, outmsg->tag); 588ead43b01SAneesh Kumar K.V return; 5891c7850f9SSasha Levin } 5901c7850f9SSasha Levin 591ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 592af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5931c7850f9SSasha Levin { 594af045e53SAneesh Kumar K.V struct p9_msg *inmsg = pdu->in_iov[0].iov_base; 595af045e53SAneesh Kumar K.V struct p9_msg *outmsg = pdu->out_iov[0].iov_base; 596af045e53SAneesh Kumar K.V struct p9_twrite *twrite = (struct p9_twrite *)outmsg->msg; 597af045e53SAneesh Kumar K.V struct p9_rwrite *rwrite = (struct p9_rwrite *)inmsg->msg; 598b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[twrite->fid]; 5991c7850f9SSasha Levin 600af045e53SAneesh Kumar K.V 601af045e53SAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(*outmsg) + sizeof(*twrite)); 602af045e53SAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(*outmsg) + sizeof(*twrite)); 6036b163a87SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, twrite->count, 6046b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 605af045e53SAneesh Kumar K.V rwrite->count = pwritev(fid->fd, pdu->out_iov, 606af045e53SAneesh Kumar K.V pdu->out_iov_cnt, twrite->offset); 6071c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32); 608af045e53SAneesh Kumar K.V set_p9msg_hdr(inmsg, *outlen, P9_RWRITE, outmsg->tag); 6091c7850f9SSasha Levin 610ead43b01SAneesh Kumar K.V return; 6111c7850f9SSasha Levin } 6121c7850f9SSasha Levin 613ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 614af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 615b4422bf3SAneesh Kumar K.V 616b4422bf3SAneesh Kumar K.V static p9_handler *virtio_9p_handler [] = { 617b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 618b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 619b4422bf3SAneesh Kumar K.V [P9_TSTAT] = virtio_p9_stat, 620b4422bf3SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 621b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 622b4422bf3SAneesh Kumar K.V [P9_TOPEN] = virtio_p9_open, 623b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 624b4422bf3SAneesh Kumar K.V [P9_TCREATE] = virtio_p9_create, 625b4422bf3SAneesh Kumar K.V [P9_TWSTAT] = virtio_p9_wstat, 626b4422bf3SAneesh Kumar K.V [P9_TREMOVE] = virtio_p9_remove, 627b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 628b4422bf3SAneesh Kumar K.V }; 629b4422bf3SAneesh Kumar K.V 630af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 631af045e53SAneesh Kumar K.V { 632af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 633af045e53SAneesh Kumar K.V if (!pdu) 634af045e53SAneesh Kumar K.V return NULL; 635af045e53SAneesh Kumar K.V 636af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 637af045e53SAneesh Kumar K.V pdu->out_iov, 638af045e53SAneesh Kumar K.V &pdu->in_iov_cnt, 639af045e53SAneesh Kumar K.V &pdu->out_iov_cnt); 640af045e53SAneesh Kumar K.V return pdu; 641af045e53SAneesh Kumar K.V } 642af045e53SAneesh Kumar K.V 643af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 644af045e53SAneesh Kumar K.V { 645af045e53SAneesh Kumar K.V struct p9_msg *msg; 646af045e53SAneesh Kumar K.V /* 647af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 648af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 649af045e53SAneesh Kumar K.V */ 650af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 651af045e53SAneesh Kumar K.V return msg->cmd; 652af045e53SAneesh Kumar K.V } 653af045e53SAneesh Kumar K.V 654b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 6551c7850f9SSasha Levin { 656af045e53SAneesh Kumar K.V u8 cmd; 657b4422bf3SAneesh Kumar K.V u32 len = 0; 658b4422bf3SAneesh Kumar K.V p9_handler *handler; 659b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 660af045e53SAneesh Kumar K.V struct virt_queue *vq; 661af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 6621c7850f9SSasha Levin 663b4422bf3SAneesh Kumar K.V vq = job->vq; 664b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 6651c7850f9SSasha Levin 666af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 667af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 668af045e53SAneesh Kumar K.V 669af045e53SAneesh Kumar K.V if (cmd >= ARRAY_SIZE(virtio_9p_handler) || 670af045e53SAneesh Kumar K.V !virtio_9p_handler[cmd]) { 671af045e53SAneesh Kumar K.V printf("Unsupported P9 message type: %u\n", cmd); 6721c7850f9SSasha Levin 673b4422bf3SAneesh Kumar K.V } else { 674af045e53SAneesh Kumar K.V handler = virtio_9p_handler[cmd]; 675af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 676b4422bf3SAneesh Kumar K.V } 677af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 678af045e53SAneesh Kumar K.V free(p9pdu); 6791c7850f9SSasha Levin return true; 6801c7850f9SSasha Levin } 6811c7850f9SSasha Levin 6821c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 6831c7850f9SSasha Levin { 684b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 685b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 686b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 6871c7850f9SSasha Levin 6881c7850f9SSasha Levin while (virt_queue__available(vq)) { 689b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 690b4422bf3SAneesh Kumar K.V virt_queue__trigger_irq(vq, p9dev->pci_hdr.irq_line, 691b4422bf3SAneesh Kumar K.V &p9dev->isr, kvm); 6921c7850f9SSasha Levin } 6931c7850f9SSasha Levin } 6941c7850f9SSasha Levin 69560eb42d5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 69660eb42d5SSasha Levin { 69760eb42d5SSasha Levin struct p9_dev_job *job = param; 69860eb42d5SSasha Levin 69960eb42d5SSasha Levin thread_pool__do_job(job->job_id); 70060eb42d5SSasha Levin } 70160eb42d5SSasha Levin 702b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, 703b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 7041c7850f9SSasha Levin { 7051c7850f9SSasha Levin unsigned long offset; 7061c7850f9SSasha Levin bool ret = true; 707b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 70860eb42d5SSasha Levin struct ioevent ioevent; 7091c7850f9SSasha Levin 710b4422bf3SAneesh Kumar K.V p9dev = ioport->priv; 711b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 7121c7850f9SSasha Levin 7131c7850f9SSasha Levin switch (offset) { 7141c7850f9SSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 7151c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 7161c7850f9SSasha Levin break; 7171c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 7181c7850f9SSasha Levin void *p; 719b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 720b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 7211c7850f9SSasha Levin 722b4422bf3SAneesh Kumar K.V job = &p9dev->jobs[p9dev->queue_selector]; 723b4422bf3SAneesh Kumar K.V queue = &p9dev->vqs[p9dev->queue_selector]; 7241c7850f9SSasha Levin queue->pfn = ioport__read32(data); 7251c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 7261c7850f9SSasha Levin 727612038c5SAneesh Kumar K.V vring_init(&queue->vring, VIRTQUEUE_NUM, p, 728b4422bf3SAneesh Kumar K.V VIRTIO_PCI_VRING_ALIGN); 7291c7850f9SSasha Levin 730b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 731b4422bf3SAneesh Kumar K.V .vq = queue, 732b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 733b4422bf3SAneesh Kumar K.V }; 734b4422bf3SAneesh Kumar K.V job->job_id = thread_pool__add_job(kvm, virtio_p9_do_io, job); 73560eb42d5SSasha Levin 73660eb42d5SSasha Levin ioevent = (struct ioevent) { 73760eb42d5SSasha Levin .io_addr = p9dev->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 73860eb42d5SSasha Levin .io_len = sizeof(u16), 73960eb42d5SSasha Levin .fn = ioevent_callback, 74060eb42d5SSasha Levin .datamatch = p9dev->queue_selector, 74160eb42d5SSasha Levin .fn_ptr = &p9dev->jobs[p9dev->queue_selector], 74260eb42d5SSasha Levin .fn_kvm = kvm, 74360eb42d5SSasha Levin .fd = eventfd(0, 0), 74460eb42d5SSasha Levin }; 74560eb42d5SSasha Levin 74660eb42d5SSasha Levin ioeventfd__add_event(&ioevent); 74760eb42d5SSasha Levin 7481c7850f9SSasha Levin break; 7491c7850f9SSasha Levin } 7501c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 751b4422bf3SAneesh Kumar K.V p9dev->queue_selector = ioport__read16(data); 7521c7850f9SSasha Levin break; 7531c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 7541c7850f9SSasha Levin u16 queue_index; 75560eb42d5SSasha Levin 7561c7850f9SSasha Levin queue_index = ioport__read16(data); 757b4422bf3SAneesh Kumar K.V thread_pool__do_job(p9dev->jobs[queue_index].job_id); 7581c7850f9SSasha Levin break; 7591c7850f9SSasha Levin } 7601c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 761b4422bf3SAneesh Kumar K.V p9dev->status = ioport__read8(data); 7621c7850f9SSasha Levin break; 7631c7850f9SSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 764b4422bf3SAneesh Kumar K.V p9dev->config_vector = VIRTIO_MSI_NO_VECTOR; 7651c7850f9SSasha Levin break; 7661c7850f9SSasha Levin default: 7671c7850f9SSasha Levin ret = false; 7681c7850f9SSasha Levin break; 7691c7850f9SSasha Levin }; 7701c7850f9SSasha Levin 7711c7850f9SSasha Levin return ret; 7721c7850f9SSasha Levin } 7731c7850f9SSasha Levin 7741c7850f9SSasha Levin static struct ioport_operations virtio_p9_io_ops = { 7751c7850f9SSasha Levin .io_in = virtio_p9_pci_io_in, 7761c7850f9SSasha Levin .io_out = virtio_p9_pci_io_out, 7771c7850f9SSasha Levin }; 7781c7850f9SSasha Levin 779b4422bf3SAneesh Kumar K.V void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name) 7801c7850f9SSasha Levin { 7811c7850f9SSasha Levin u8 pin, line, dev; 7821c7850f9SSasha Levin u32 i, root_len; 783f884f920SSasha Levin u16 p9_base_addr; 784b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 7851c7850f9SSasha Levin 786b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 787b4422bf3SAneesh Kumar K.V if (!p9dev) 7881c7850f9SSasha Levin return; 789b4422bf3SAneesh Kumar K.V if (!tag_name) 790b4422bf3SAneesh Kumar K.V tag_name = VIRTIO_P9_DEFAULT_TAG; 791b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 792b4422bf3SAneesh Kumar K.V if (p9dev->config == NULL) 793b4422bf3SAneesh Kumar K.V goto free_p9dev; 7941c7850f9SSasha Levin 795b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 7961c7850f9SSasha Levin root_len = strlen(root); 7971c7850f9SSasha Levin /* 7981c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 7991c7850f9SSasha Levin * absolute path of an fid without playing with strings. 8001c7850f9SSasha Levin */ 8011c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 802b4422bf3SAneesh Kumar K.V strcpy(p9dev->fids[i].abs_path, root); 803b4422bf3SAneesh Kumar K.V p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len; 8041c7850f9SSasha Levin } 805b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 806b4422bf3SAneesh Kumar K.V if (p9dev->config->tag_len > MAX_TAG_LEN) 807b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 8081c7850f9SSasha Levin 809b4422bf3SAneesh Kumar K.V memcpy(p9dev->config->tag, tag_name, strlen(tag_name)); 810b4422bf3SAneesh Kumar K.V p9dev->features |= 1 << VIRTIO_9P_MOUNT_TAG; 8111c7850f9SSasha Levin 8121c7850f9SSasha Levin if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0) 813b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 8141c7850f9SSasha Levin 815b4422bf3SAneesh Kumar K.V p9_base_addr = ioport__register(IOPORT_EMPTY, 816b4422bf3SAneesh Kumar K.V &virtio_p9_io_ops, 817b4422bf3SAneesh Kumar K.V IOPORT_SIZE, p9dev); 818b4422bf3SAneesh Kumar K.V p9dev->base_addr = p9_base_addr; 819b4422bf3SAneesh Kumar K.V p9dev->pci_hdr = (struct pci_device_header) { 820b4422bf3SAneesh Kumar K.V .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 821b4422bf3SAneesh Kumar K.V .device_id = PCI_DEVICE_ID_VIRTIO_P9, 822b4422bf3SAneesh Kumar K.V .header_type = PCI_HEADER_TYPE_NORMAL, 823b4422bf3SAneesh Kumar K.V .revision_id = 0, 824b4422bf3SAneesh Kumar K.V .class = 0x010000, 825b4422bf3SAneesh Kumar K.V .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 826b4422bf3SAneesh Kumar K.V .subsys_id = VIRTIO_ID_9P, 827b4422bf3SAneesh Kumar K.V .irq_pin = pin, 828b4422bf3SAneesh Kumar K.V .irq_line = line, 829b4422bf3SAneesh Kumar K.V .bar[0] = p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO, 830b4422bf3SAneesh Kumar K.V }; 831b4422bf3SAneesh Kumar K.V pci__register(&p9dev->pci_hdr, dev); 832b4422bf3SAneesh Kumar K.V 833b4422bf3SAneesh Kumar K.V return; 834b4422bf3SAneesh Kumar K.V free_p9dev_config: 835b4422bf3SAneesh Kumar K.V free(p9dev->config); 836b4422bf3SAneesh Kumar K.V free_p9dev: 837b4422bf3SAneesh Kumar K.V free(p9dev); 8381c7850f9SSasha Levin } 839