11c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h" 21c7850f9SSasha Levin #include "kvm/ioport.h" 31c7850f9SSasha Levin #include "kvm/util.h" 41c7850f9SSasha Levin #include "kvm/threadpool.h" 560eb42d5SSasha Levin #include "kvm/ioeventfd.h" 6bfc15268SAneesh Kumar K.V #include "kvm/irq.h" 7bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h" 81c7850f9SSasha Levin 9bfc15268SAneesh Kumar K.V #include <stdio.h> 10bfc15268SAneesh Kumar K.V #include <stdlib.h> 111c7850f9SSasha Levin #include <fcntl.h> 121c7850f9SSasha Levin #include <sys/stat.h> 13bfc15268SAneesh Kumar K.V #include <unistd.h> 14bfc15268SAneesh Kumar K.V #include <string.h> 15bfc15268SAneesh Kumar K.V #include <errno.h> 161c7850f9SSasha Levin 172daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 182daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 192daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 202daa28d4SAneesh Kumar K.V 211c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 22b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 23b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 241c7850f9SSasha Levin { 25b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 261c7850f9SSasha Levin 271c7850f9SSasha Levin return abs_path; 281c7850f9SSasha Levin } 291c7850f9SSasha Levin 30b4422bf3SAneesh Kumar K.V static bool virtio_p9_dev_in(struct p9_dev *p9dev, void *data, 31b4422bf3SAneesh Kumar K.V unsigned long offset, 32b4422bf3SAneesh Kumar K.V int size, u32 count) 331c7850f9SSasha Levin { 34b4422bf3SAneesh Kumar K.V u8 *config_space = (u8 *) p9dev->config; 351c7850f9SSasha Levin 361c7850f9SSasha Levin if (size != 1 || count != 1) 371c7850f9SSasha Levin return false; 381c7850f9SSasha Levin 391c7850f9SSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 401c7850f9SSasha Levin 411c7850f9SSasha Levin return true; 421c7850f9SSasha Levin } 431c7850f9SSasha Levin 44b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, 45b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 461c7850f9SSasha Levin { 471c7850f9SSasha Levin bool ret = true; 48b4422bf3SAneesh Kumar K.V unsigned long offset; 49b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = ioport->priv; 501c7850f9SSasha Levin 51b4422bf3SAneesh Kumar K.V 52b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 531c7850f9SSasha Levin 541c7850f9SSasha Levin switch (offset) { 551c7850f9SSasha Levin case VIRTIO_PCI_HOST_FEATURES: 56b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->features); 571c7850f9SSasha Levin ret = true; 581c7850f9SSasha Levin break; 591c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 601c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 611c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 621c7850f9SSasha Levin ret = false; 631c7850f9SSasha Levin break; 641c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: 65b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->vqs[p9dev->queue_selector].pfn); 661c7850f9SSasha Levin break; 671c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NUM: 68612038c5SAneesh Kumar K.V ioport__write16(data, VIRTQUEUE_NUM); 691c7850f9SSasha Levin break; 701c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 71b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->status); 721c7850f9SSasha Levin break; 731c7850f9SSasha Levin case VIRTIO_PCI_ISR: 74b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->isr); 75b4422bf3SAneesh Kumar K.V kvm__irq_line(kvm, p9dev->pci_hdr.irq_line, VIRTIO_IRQ_LOW); 76b4422bf3SAneesh Kumar K.V p9dev->isr = VIRTIO_IRQ_LOW; 771c7850f9SSasha Levin break; 781c7850f9SSasha Levin default: 79b4422bf3SAneesh Kumar K.V ret = virtio_p9_dev_in(p9dev, data, offset, size, count); 801c7850f9SSasha Levin break; 811c7850f9SSasha Levin }; 821c7850f9SSasha Levin 831c7850f9SSasha Levin return ret; 841c7850f9SSasha Levin } 851c7850f9SSasha Levin 861c7850f9SSasha Levin static int omode2uflags(u8 mode) 871c7850f9SSasha Levin { 881c7850f9SSasha Levin int ret = 0; 891c7850f9SSasha Levin 901c7850f9SSasha Levin /* Basic open modes are same as uflags */ 911c7850f9SSasha Levin ret = mode & 3; 921c7850f9SSasha Levin 931c7850f9SSasha Levin /* Everything else is different */ 941c7850f9SSasha Levin if (mode & P9_OTRUNC) 951c7850f9SSasha Levin ret |= O_TRUNC; 961c7850f9SSasha Levin 971c7850f9SSasha Levin if (mode & P9_OAPPEND) 981c7850f9SSasha Levin ret |= O_APPEND; 991c7850f9SSasha Levin 1001c7850f9SSasha Levin if (mode & P9_OEXCL) 1011c7850f9SSasha Levin ret |= O_EXCL; 1021c7850f9SSasha Levin 1031c7850f9SSasha Levin return ret; 1041c7850f9SSasha Levin } 1051c7850f9SSasha Levin 1061c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid) 1071c7850f9SSasha Levin { 1081c7850f9SSasha Levin *qid = (struct p9_qid) { 1091c7850f9SSasha Levin .path = st->st_ino, 1101c7850f9SSasha Levin .version = st->st_mtime, 1111c7850f9SSasha Levin }; 1121c7850f9SSasha Levin 1131c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1141c7850f9SSasha Levin qid->type |= P9_QTDIR; 1151c7850f9SSasha Levin } 1161c7850f9SSasha Levin 117b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1181c7850f9SSasha Levin { 119b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 120b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 121b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 1221c7850f9SSasha Levin } 123b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 124b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 125b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 1261c7850f9SSasha Levin } 1271c7850f9SSasha Levin } 1281c7850f9SSasha Levin 129bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1301c7850f9SSasha Levin { 131bfc15268SAneesh Kumar K.V u8 cmd; 132bfc15268SAneesh Kumar K.V u16 tag; 133bfc15268SAneesh Kumar K.V 134bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 135bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 136bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 137bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 138bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1391c7850f9SSasha Levin } 1401c7850f9SSasha Levin 1416b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1426b163a87SAneesh Kumar K.V { 1436b163a87SAneesh Kumar K.V int i; 1446b163a87SAneesh Kumar K.V u32 total = 0; 1456b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1466b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1476b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1486b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1496b163a87SAneesh Kumar K.V i++; 1506b163a87SAneesh Kumar K.V break; 1516b163a87SAneesh Kumar K.V } 1526b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1536b163a87SAneesh Kumar K.V } 1546b163a87SAneesh Kumar K.V return i; 1556b163a87SAneesh Kumar K.V } 1566b163a87SAneesh Kumar K.V 157eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 158eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 159eee1ba8eSAneesh Kumar K.V { 160bfc15268SAneesh Kumar K.V u16 tag; 161eee1ba8eSAneesh Kumar K.V char *err_str; 162eee1ba8eSAneesh Kumar K.V 163eee1ba8eSAneesh Kumar K.V err_str = strerror(err); 164bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 165bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", err_str); 166bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 167eee1ba8eSAneesh Kumar K.V 168bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 169bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 170bfc15268SAneesh Kumar K.V 171bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 172bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RERROR, tag); 173eee1ba8eSAneesh Kumar K.V } 174eee1ba8eSAneesh Kumar K.V 175ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 176af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1771c7850f9SSasha Levin { 178bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", 4096, VIRTIO_P9_VERSION); 1791c7850f9SSasha Levin 180bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 181bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 182ead43b01SAneesh Kumar K.V return; 1831c7850f9SSasha Levin } 1841c7850f9SSasha Levin 185ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 186af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1871c7850f9SSasha Levin { 188bfc15268SAneesh Kumar K.V u32 fid; 1891c7850f9SSasha Levin 190bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 191bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1921c7850f9SSasha Levin 193bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 194bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 195ead43b01SAneesh Kumar K.V return; 1961c7850f9SSasha Levin } 1971c7850f9SSasha Levin 198ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 199af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2001c7850f9SSasha Levin { 201bfc15268SAneesh Kumar K.V u8 mode; 202bfc15268SAneesh Kumar K.V u32 fid; 2031c7850f9SSasha Levin struct stat st; 204bfc15268SAneesh Kumar K.V struct p9_qid qid; 205bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 206bfc15268SAneesh Kumar K.V 207bfc15268SAneesh Kumar K.V 208bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "db", &fid, &mode); 209bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[fid]; 2101c7850f9SSasha Levin 21130204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 212eee1ba8eSAneesh Kumar K.V goto err_out; 2131c7850f9SSasha Levin 214bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 2151c7850f9SSasha Levin 216eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 2171c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 218eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 219eee1ba8eSAneesh Kumar K.V goto err_out; 220eee1ba8eSAneesh Kumar K.V } else { 221eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 222bfc15268SAneesh Kumar K.V omode2uflags(mode) | O_NOFOLLOW); 223eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 224eee1ba8eSAneesh Kumar K.V goto err_out; 225eee1ba8eSAneesh Kumar K.V } 226bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 227bfc15268SAneesh Kumar K.V 228bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 229bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 230ead43b01SAneesh Kumar K.V return; 231eee1ba8eSAneesh Kumar K.V err_out: 232eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 233ead43b01SAneesh Kumar K.V return; 2341c7850f9SSasha Levin } 2351c7850f9SSasha Levin 236ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 237af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2381c7850f9SSasha Levin { 2394bc9734aSAneesh Kumar K.V DIR *dir; 2404bc9734aSAneesh Kumar K.V int fd; 2414bc9734aSAneesh Kumar K.V int res; 2421c7850f9SSasha Levin u8 mode; 2431c7850f9SSasha Levin u32 perm; 244bfc15268SAneesh Kumar K.V char *name; 245bfc15268SAneesh Kumar K.V u32 fid_val; 246af045e53SAneesh Kumar K.V struct stat st; 247bfc15268SAneesh Kumar K.V struct p9_qid qid; 248bfc15268SAneesh Kumar K.V struct p9_fid *fid; 2494bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 250af045e53SAneesh Kumar K.V 251bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdb", &fid_val, &name, &perm, &mode); 252bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 2531c7850f9SSasha Levin 2544bc9734aSAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 2551c7850f9SSasha Levin if (perm & P9_DMDIR) { 2564bc9734aSAneesh Kumar K.V res = mkdir(full_path, perm & 0xFFFF); 2574bc9734aSAneesh Kumar K.V if (res < 0) 2584bc9734aSAneesh Kumar K.V goto err_out; 2594bc9734aSAneesh Kumar K.V dir = opendir(full_path); 2604bc9734aSAneesh Kumar K.V if (!dir) 2614bc9734aSAneesh Kumar K.V goto err_out; 2624bc9734aSAneesh Kumar K.V close_fid(p9dev, fid_val); 2634bc9734aSAneesh Kumar K.V fid->dir = dir; 2641c7850f9SSasha Levin fid->is_dir = 1; 2651c7850f9SSasha Levin } else { 2664bc9734aSAneesh Kumar K.V fd = open(full_path, omode2uflags(mode) | O_CREAT, 0777); 2674bc9734aSAneesh Kumar K.V if (fd < 0) 2684bc9734aSAneesh Kumar K.V goto err_out; 2694bc9734aSAneesh Kumar K.V close_fid(p9dev, fid_val); 2704bc9734aSAneesh Kumar K.V fid->fd = fd; 2711c7850f9SSasha Levin } 2724bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 2736c8ca053SAneesh Kumar K.V goto err_out; 2741c7850f9SSasha Levin 2754bc9734aSAneesh Kumar K.V sprintf(fid->path, "%s/%s", fid->path, name); 276bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 277bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 278bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 279bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 2806c8ca053SAneesh Kumar K.V return; 2816c8ca053SAneesh Kumar K.V err_out: 2826c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 283ead43b01SAneesh Kumar K.V return; 2841c7850f9SSasha Levin } 2851c7850f9SSasha Levin 286ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 287af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2881c7850f9SSasha Levin { 289af045e53SAneesh Kumar K.V u8 i; 290bfc15268SAneesh Kumar K.V u16 nwqid; 291bfc15268SAneesh Kumar K.V char *str; 292bfc15268SAneesh Kumar K.V u16 nwname; 293bfc15268SAneesh Kumar K.V u32 fid_val; 294bfc15268SAneesh Kumar K.V u32 newfid_val; 295bfc15268SAneesh Kumar K.V struct p9_qid wqid; 296bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 297af045e53SAneesh Kumar K.V 2981c7850f9SSasha Levin 299bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 300bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[newfid_val]; 3011c7850f9SSasha Levin 302bfc15268SAneesh Kumar K.V nwqid = 0; 303bfc15268SAneesh Kumar K.V if (nwname) { 304bfc15268SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[fid_val]; 305bfc15268SAneesh Kumar K.V 306bfc15268SAneesh Kumar K.V /* skip the space for count */ 307bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 308bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 309bfc15268SAneesh Kumar K.V struct stat st; 3101c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3111c7850f9SSasha Levin char full_path[PATH_MAX]; 312bfc15268SAneesh Kumar K.V 313bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3141c7850f9SSasha Levin 3151c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 316bfc15268SAneesh Kumar K.V sprintf(tmp, "%s/%.*s", 317bfc15268SAneesh Kumar K.V fid->path, (int)strlen(str), str); 31830204a77SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3196c8ca053SAneesh Kumar K.V goto err_out; 3201c7850f9SSasha Levin 321bfc15268SAneesh Kumar K.V st2qid(&st, &wqid); 3221c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3231c7850f9SSasha Levin strcpy(new_fid->path, tmp); 324bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 325bfc15268SAneesh Kumar K.V nwqid++; 326bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 3271c7850f9SSasha Levin } 3281c7850f9SSasha Levin } else { 329bfc15268SAneesh Kumar K.V /* 330bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 331bfc15268SAneesh Kumar K.V */ 332bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 333bfc15268SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[fid_val].is_dir; 334bfc15268SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[fid_val].path); 335bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 3361c7850f9SSasha Levin } 337bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 338bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 339bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 340bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3416c8ca053SAneesh Kumar K.V return; 3426c8ca053SAneesh Kumar K.V err_out: 3436c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 344ead43b01SAneesh Kumar K.V return; 3451c7850f9SSasha Levin } 3461c7850f9SSasha Levin 347ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 348af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3491c7850f9SSasha Levin { 350af045e53SAneesh Kumar K.V u32 i; 351bfc15268SAneesh Kumar K.V u32 fid_val; 352bfc15268SAneesh Kumar K.V u32 afid; 353bfc15268SAneesh Kumar K.V char *uname; 354bfc15268SAneesh Kumar K.V char *aname; 3551c7850f9SSasha Levin struct stat st; 356bfc15268SAneesh Kumar K.V struct p9_qid qid; 3571c7850f9SSasha Levin struct p9_fid *fid; 358bfc15268SAneesh Kumar K.V 359bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddss", &fid_val, &afid, &uname, &aname); 3601c7850f9SSasha Levin 3611c7850f9SSasha Levin /* Reset everything */ 3621c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 363b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 3641c7850f9SSasha Levin 36530204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 3666c8ca053SAneesh Kumar K.V goto err_out; 3671c7850f9SSasha Levin 368bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 3691c7850f9SSasha Levin 370bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 371bfc15268SAneesh Kumar K.V fid->fid = fid_val; 3721c7850f9SSasha Levin fid->is_dir = 1; 3731c7850f9SSasha Levin strcpy(fid->path, "/"); 3741c7850f9SSasha Levin 375bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 376bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 377bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3786c8ca053SAneesh Kumar K.V return; 3796c8ca053SAneesh Kumar K.V err_out: 3806c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 381ead43b01SAneesh Kumar K.V return; 3821c7850f9SSasha Levin } 3831c7850f9SSasha Levin 384bfc15268SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, 385bfc15268SAneesh Kumar K.V struct stat *st, struct p9_wstat *wstat) 3861c7850f9SSasha Levin { 387bfc15268SAneesh Kumar K.V wstat->type = 0; 388bfc15268SAneesh Kumar K.V wstat->dev = 0; 389bfc15268SAneesh Kumar K.V st2qid(st, &wstat->qid); 390bfc15268SAneesh Kumar K.V wstat->mode = st->st_mode; 391bfc15268SAneesh Kumar K.V wstat->length = st->st_size; 3921c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) { 393bfc15268SAneesh Kumar K.V wstat->length = 0; 394bfc15268SAneesh Kumar K.V wstat->mode |= P9_DMDIR; 3951c7850f9SSasha Levin } 3961c7850f9SSasha Levin 397bfc15268SAneesh Kumar K.V wstat->atime = st->st_atime; 398bfc15268SAneesh Kumar K.V wstat->mtime = st->st_mtime; 3991c7850f9SSasha Levin 400bfc15268SAneesh Kumar K.V wstat->name = strdup(name); 401bfc15268SAneesh Kumar K.V wstat->uid = NULL; 402bfc15268SAneesh Kumar K.V wstat->gid = NULL; 403bfc15268SAneesh Kumar K.V wstat->muid = NULL; 4041c7850f9SSasha Levin 405bfc15268SAneesh Kumar K.V /* NOTE: size shouldn't include its own length */ 406bfc15268SAneesh Kumar K.V /* size[2] type[2] dev[4] qid[13] */ 407bfc15268SAneesh Kumar K.V /* mode[4] atime[4] mtime[4] length[8]*/ 408bfc15268SAneesh Kumar K.V /* name[s] uid[s] gid[s] muid[s] */ 409bfc15268SAneesh Kumar K.V wstat->size = 2+4+13+4+4+4+8+2+2+2+2; 410bfc15268SAneesh Kumar K.V if (wstat->name) 411bfc15268SAneesh Kumar K.V wstat->size += strlen(wstat->name); 4121c7850f9SSasha Levin } 4131c7850f9SSasha Levin 414ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 415af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4161c7850f9SSasha Levin { 417bfc15268SAneesh Kumar K.V u64 offset; 418bfc15268SAneesh Kumar K.V u32 fid_val; 419bfc15268SAneesh Kumar K.V u32 count, rcount; 4201c7850f9SSasha Levin struct stat st; 421bfc15268SAneesh Kumar K.V struct p9_fid *fid; 422bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 4231c7850f9SSasha Levin 424bfc15268SAneesh Kumar K.V rcount = 0; 425bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 426bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 4271c7850f9SSasha Levin if (fid->is_dir) { 4281c7850f9SSasha Levin /* If reading a dir, fill the buffer with p9_stat entries */ 4291c7850f9SSasha Levin char full_path[PATH_MAX]; 430bfc15268SAneesh Kumar K.V struct dirent *cur = readdir(fid->dir); 4311c7850f9SSasha Levin 432bfc15268SAneesh Kumar K.V /* Skip the space for writing count */ 433bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 4341c7850f9SSasha Levin while (cur) { 4351c7850f9SSasha Levin u32 read; 4361c7850f9SSasha Levin 43730204a77SAneesh Kumar K.V lstat(rel_to_abs(p9dev, cur->d_name, full_path), &st); 438bfc15268SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, cur->d_name, &st, &wstat); 439bfc15268SAneesh Kumar K.V 440bfc15268SAneesh Kumar K.V read = pdu->write_offset; 441bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "S", &wstat); 442bfc15268SAneesh Kumar K.V rcount += pdu->write_offset - read; 443bfc15268SAneesh Kumar K.V 4441c7850f9SSasha Levin cur = readdir(fid->dir); 4451c7850f9SSasha Levin } 4461c7850f9SSasha Levin } else { 447af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 448af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 4496b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 450bfc15268SAneesh Kumar K.V count, 4516b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 452bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 453bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 454bfc15268SAneesh Kumar K.V if (rcount > count) 455bfc15268SAneesh Kumar K.V rcount = count; 456bfc15268SAneesh Kumar K.V /* 457bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 458bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 459bfc15268SAneesh Kumar K.V */ 460bfc15268SAneesh Kumar K.V pdu->in_iov[0].iov_base -= VIRTIO_P9_HDR_LEN + sizeof(u32); 461bfc15268SAneesh Kumar K.V pdu->in_iov[0].iov_len += VIRTIO_P9_HDR_LEN + sizeof(u32); 4621c7850f9SSasha Levin 463bfc15268SAneesh Kumar K.V } 464bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 465bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 466bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 467bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4681c7850f9SSasha Levin 469ead43b01SAneesh Kumar K.V return; 4701c7850f9SSasha Levin } 4711c7850f9SSasha Levin 472ead43b01SAneesh Kumar K.V static void virtio_p9_stat(struct p9_dev *p9dev, 473af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4741c7850f9SSasha Levin { 475bfc15268SAneesh Kumar K.V u32 fid_val; 476af045e53SAneesh Kumar K.V struct stat st; 477bfc15268SAneesh Kumar K.V struct p9_fid *fid; 478bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 4791c7850f9SSasha Levin 480bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 481bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 48230204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 4836c8ca053SAneesh Kumar K.V goto err_out; 4841c7850f9SSasha Levin 485bfc15268SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, fid->path, &st, &wstat); 4861c7850f9SSasha Levin 487bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "wS", 0, &wstat); 488bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 489bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 490ead43b01SAneesh Kumar K.V return; 4916c8ca053SAneesh Kumar K.V err_out: 4926c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 4936c8ca053SAneesh Kumar K.V return; 4941c7850f9SSasha Levin } 4951c7850f9SSasha Levin 496ead43b01SAneesh Kumar K.V static void virtio_p9_wstat(struct p9_dev *p9dev, 497af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4981c7850f9SSasha Levin { 499aec426f0SCyrill Gorcunov int res = 0; 500bfc15268SAneesh Kumar K.V u32 fid_val; 501bfc15268SAneesh Kumar K.V u16 unused; 502bfc15268SAneesh Kumar K.V struct p9_fid *fid; 503bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 504af045e53SAneesh Kumar K.V 505bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dwS", &fid_val, &unused, &wstat); 506bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 5071c7850f9SSasha Levin 5084bc9734aSAneesh Kumar K.V if (wstat.length != -1UL) { 509c6fb59c4SAneesh Kumar K.V res = truncate(fid->abs_path, wstat.length); 5104bc9734aSAneesh Kumar K.V if (res < 0) 5114bc9734aSAneesh Kumar K.V goto err_out; 5124bc9734aSAneesh Kumar K.V } 5134bc9734aSAneesh Kumar K.V if (wstat.mode != -1U) { 5144bc9734aSAneesh Kumar K.V res = chmod(fid->abs_path, wstat.mode & 0xFFFF); 5154bc9734aSAneesh Kumar K.V if (res < 0) 5164bc9734aSAneesh Kumar K.V goto err_out; 5174bc9734aSAneesh Kumar K.V } 518bfc15268SAneesh Kumar K.V if (strlen(wstat.name) > 0) { 5191c7850f9SSasha Levin char new_name[PATH_MAX] = {0}; 5201c7850f9SSasha Levin char full_path[PATH_MAX]; 5211c7850f9SSasha Levin char *last_dir = strrchr(fid->path, '/'); 5221c7850f9SSasha Levin 5231c7850f9SSasha Levin /* We need to get the full file name out of twstat->name */ 5241c7850f9SSasha Levin if (last_dir) 5251c7850f9SSasha Levin strncpy(new_name, fid->path, last_dir - fid->path + 1); 5261c7850f9SSasha Levin 527bfc15268SAneesh Kumar K.V memcpy(new_name + strlen(new_name), 528bfc15268SAneesh Kumar K.V wstat.name, strlen(wstat.name)); 5291c7850f9SSasha Levin 5301c7850f9SSasha Levin /* fid is reused for the new file */ 5314bc9734aSAneesh Kumar K.V res = rename(fid->abs_path, 5324bc9734aSAneesh Kumar K.V rel_to_abs(p9dev, new_name, full_path)); 5334bc9734aSAneesh Kumar K.V if (res < 0) 5344bc9734aSAneesh Kumar K.V goto err_out; 5351c7850f9SSasha Levin sprintf(fid->path, "%s", new_name); 5361c7850f9SSasha Levin } 5371c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 538bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 539ead43b01SAneesh Kumar K.V return; 5404bc9734aSAneesh Kumar K.V err_out: 5414bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5424bc9734aSAneesh Kumar K.V return; 5431c7850f9SSasha Levin } 5441c7850f9SSasha Levin 545ead43b01SAneesh Kumar K.V static void virtio_p9_remove(struct p9_dev *p9dev, 546af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5471c7850f9SSasha Levin { 5484bc9734aSAneesh Kumar K.V int res; 549bfc15268SAneesh Kumar K.V u32 fid_val; 550bfc15268SAneesh Kumar K.V struct p9_fid *fid; 5511c7850f9SSasha Levin 552bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 553bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 554bfc15268SAneesh Kumar K.V close_fid(p9dev, fid_val); 5551c7850f9SSasha Levin if (fid->is_dir) 5564bc9734aSAneesh Kumar K.V res = rmdir(fid->abs_path); 5571c7850f9SSasha Levin else 5584bc9734aSAneesh Kumar K.V res = unlink(fid->abs_path); 5594bc9734aSAneesh Kumar K.V if (res < 0) 5604bc9734aSAneesh Kumar K.V goto err_out; 5611c7850f9SSasha Levin 5621c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 563bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 564ead43b01SAneesh Kumar K.V return; 5654bc9734aSAneesh Kumar K.V err_out: 5664bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5674bc9734aSAneesh Kumar K.V return; 5681c7850f9SSasha Levin } 5691c7850f9SSasha Levin 570ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 571af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5721c7850f9SSasha Levin { 5734bc9734aSAneesh Kumar K.V 574bfc15268SAneesh Kumar K.V u64 offset; 575bfc15268SAneesh Kumar K.V u32 fid_val; 5764bc9734aSAneesh Kumar K.V u32 count; 5774bc9734aSAneesh Kumar K.V ssize_t res; 578bfc15268SAneesh Kumar K.V struct p9_fid *fid; 579*b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 580*b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 5811c7850f9SSasha Levin 582bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 583bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 584af045e53SAneesh Kumar K.V 585bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 586*b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 587*b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 588bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 5896b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 5904bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 5914bc9734aSAneesh Kumar K.V if (res < 0) 5924bc9734aSAneesh Kumar K.V goto err_out; 5934bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 594bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 595bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 596ead43b01SAneesh Kumar K.V return; 5974bc9734aSAneesh Kumar K.V err_out: 5984bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5994bc9734aSAneesh Kumar K.V return; 6001c7850f9SSasha Levin } 6011c7850f9SSasha Levin 602ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 603af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 604b4422bf3SAneesh Kumar K.V 605b4422bf3SAneesh Kumar K.V static p9_handler *virtio_9p_handler [] = { 606b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 607b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 608b4422bf3SAneesh Kumar K.V [P9_TSTAT] = virtio_p9_stat, 609b4422bf3SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 610b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 611b4422bf3SAneesh Kumar K.V [P9_TOPEN] = virtio_p9_open, 612b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 613b4422bf3SAneesh Kumar K.V [P9_TCREATE] = virtio_p9_create, 614b4422bf3SAneesh Kumar K.V [P9_TWSTAT] = virtio_p9_wstat, 615b4422bf3SAneesh Kumar K.V [P9_TREMOVE] = virtio_p9_remove, 616b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 617b4422bf3SAneesh Kumar K.V }; 618b4422bf3SAneesh Kumar K.V 619af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 620af045e53SAneesh Kumar K.V { 621af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 622af045e53SAneesh Kumar K.V if (!pdu) 623af045e53SAneesh Kumar K.V return NULL; 624af045e53SAneesh Kumar K.V 625bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 626bfc15268SAneesh Kumar K.V pdu->read_offset = VIRTIO_P9_HDR_LEN; 627bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 628af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 629af045e53SAneesh Kumar K.V pdu->out_iov, 630af045e53SAneesh Kumar K.V &pdu->in_iov_cnt, 631af045e53SAneesh Kumar K.V &pdu->out_iov_cnt); 632af045e53SAneesh Kumar K.V return pdu; 633af045e53SAneesh Kumar K.V } 634af045e53SAneesh Kumar K.V 635af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 636af045e53SAneesh Kumar K.V { 637af045e53SAneesh Kumar K.V struct p9_msg *msg; 638af045e53SAneesh Kumar K.V /* 639af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 640af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 641af045e53SAneesh Kumar K.V */ 642af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 643af045e53SAneesh Kumar K.V return msg->cmd; 644af045e53SAneesh Kumar K.V } 645af045e53SAneesh Kumar K.V 64697b408afSAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 64797b408afSAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 64897b408afSAneesh Kumar K.V { 64997b408afSAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 65097b408afSAneesh Kumar K.V } 65197b408afSAneesh Kumar K.V 652b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 6531c7850f9SSasha Levin { 654af045e53SAneesh Kumar K.V u8 cmd; 655b4422bf3SAneesh Kumar K.V u32 len = 0; 656b4422bf3SAneesh Kumar K.V p9_handler *handler; 657b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 658af045e53SAneesh Kumar K.V struct virt_queue *vq; 659af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 6601c7850f9SSasha Levin 661b4422bf3SAneesh Kumar K.V vq = job->vq; 662b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 6631c7850f9SSasha Levin 664af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 665af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 666af045e53SAneesh Kumar K.V 667af045e53SAneesh Kumar K.V if (cmd >= ARRAY_SIZE(virtio_9p_handler) || 668af045e53SAneesh Kumar K.V !virtio_9p_handler[cmd]) { 66997b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 670b4422bf3SAneesh Kumar K.V } else { 671af045e53SAneesh Kumar K.V handler = virtio_9p_handler[cmd]; 672af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 673b4422bf3SAneesh Kumar K.V } 674af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 675af045e53SAneesh Kumar K.V free(p9pdu); 6761c7850f9SSasha Levin return true; 6771c7850f9SSasha Levin } 6781c7850f9SSasha Levin 6791c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 6801c7850f9SSasha Levin { 681b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 682b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 683b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 6841c7850f9SSasha Levin 6851c7850f9SSasha Levin while (virt_queue__available(vq)) { 686b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 687b4422bf3SAneesh Kumar K.V virt_queue__trigger_irq(vq, p9dev->pci_hdr.irq_line, 688b4422bf3SAneesh Kumar K.V &p9dev->isr, kvm); 6891c7850f9SSasha Levin } 6901c7850f9SSasha Levin } 6911c7850f9SSasha Levin 69260eb42d5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 69360eb42d5SSasha Levin { 69460eb42d5SSasha Levin struct p9_dev_job *job = param; 69560eb42d5SSasha Levin 696df0c7f57SSasha Levin thread_pool__do_job(&job->job_id); 69760eb42d5SSasha Levin } 69860eb42d5SSasha Levin 699b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, 700b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 7011c7850f9SSasha Levin { 7021c7850f9SSasha Levin unsigned long offset; 7031c7850f9SSasha Levin bool ret = true; 704b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 70560eb42d5SSasha Levin struct ioevent ioevent; 7061c7850f9SSasha Levin 707b4422bf3SAneesh Kumar K.V p9dev = ioport->priv; 708b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 7091c7850f9SSasha Levin 7101c7850f9SSasha Levin switch (offset) { 7111c7850f9SSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 7121c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 7131c7850f9SSasha Levin break; 7141c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 7151c7850f9SSasha Levin void *p; 716b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 717b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 7181c7850f9SSasha Levin 719b4422bf3SAneesh Kumar K.V job = &p9dev->jobs[p9dev->queue_selector]; 720b4422bf3SAneesh Kumar K.V queue = &p9dev->vqs[p9dev->queue_selector]; 7211c7850f9SSasha Levin queue->pfn = ioport__read32(data); 7221c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 7231c7850f9SSasha Levin 724612038c5SAneesh Kumar K.V vring_init(&queue->vring, VIRTQUEUE_NUM, p, 725b4422bf3SAneesh Kumar K.V VIRTIO_PCI_VRING_ALIGN); 7261c7850f9SSasha Levin 727b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 728b4422bf3SAneesh Kumar K.V .vq = queue, 729b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 730b4422bf3SAneesh Kumar K.V }; 731df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 73260eb42d5SSasha Levin 73360eb42d5SSasha Levin ioevent = (struct ioevent) { 73460eb42d5SSasha Levin .io_addr = p9dev->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 73560eb42d5SSasha Levin .io_len = sizeof(u16), 73660eb42d5SSasha Levin .fn = ioevent_callback, 73760eb42d5SSasha Levin .datamatch = p9dev->queue_selector, 73860eb42d5SSasha Levin .fn_ptr = &p9dev->jobs[p9dev->queue_selector], 73960eb42d5SSasha Levin .fn_kvm = kvm, 74060eb42d5SSasha Levin .fd = eventfd(0, 0), 74160eb42d5SSasha Levin }; 74260eb42d5SSasha Levin 74360eb42d5SSasha Levin ioeventfd__add_event(&ioevent); 74460eb42d5SSasha Levin 7451c7850f9SSasha Levin break; 7461c7850f9SSasha Levin } 7471c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 748b4422bf3SAneesh Kumar K.V p9dev->queue_selector = ioport__read16(data); 7491c7850f9SSasha Levin break; 7501c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 7511c7850f9SSasha Levin u16 queue_index; 75260eb42d5SSasha Levin 7531c7850f9SSasha Levin queue_index = ioport__read16(data); 754df0c7f57SSasha Levin thread_pool__do_job(&p9dev->jobs[queue_index].job_id); 7551c7850f9SSasha Levin break; 7561c7850f9SSasha Levin } 7571c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 758b4422bf3SAneesh Kumar K.V p9dev->status = ioport__read8(data); 7591c7850f9SSasha Levin break; 7601c7850f9SSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 761b4422bf3SAneesh Kumar K.V p9dev->config_vector = VIRTIO_MSI_NO_VECTOR; 7621c7850f9SSasha Levin break; 7631c7850f9SSasha Levin default: 7641c7850f9SSasha Levin ret = false; 7651c7850f9SSasha Levin break; 7661c7850f9SSasha Levin }; 7671c7850f9SSasha Levin 7681c7850f9SSasha Levin return ret; 7691c7850f9SSasha Levin } 7701c7850f9SSasha Levin 7711c7850f9SSasha Levin static struct ioport_operations virtio_p9_io_ops = { 7721c7850f9SSasha Levin .io_in = virtio_p9_pci_io_in, 7731c7850f9SSasha Levin .io_out = virtio_p9_pci_io_out, 7741c7850f9SSasha Levin }; 7751c7850f9SSasha Levin 776b4422bf3SAneesh Kumar K.V void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name) 7771c7850f9SSasha Levin { 7781c7850f9SSasha Levin u8 pin, line, dev; 7791c7850f9SSasha Levin u32 i, root_len; 780f884f920SSasha Levin u16 p9_base_addr; 781b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 7821c7850f9SSasha Levin 783b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 784b4422bf3SAneesh Kumar K.V if (!p9dev) 7851c7850f9SSasha Levin return; 786b4422bf3SAneesh Kumar K.V if (!tag_name) 787b4422bf3SAneesh Kumar K.V tag_name = VIRTIO_P9_DEFAULT_TAG; 788b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 789b4422bf3SAneesh Kumar K.V if (p9dev->config == NULL) 790b4422bf3SAneesh Kumar K.V goto free_p9dev; 7911c7850f9SSasha Levin 792b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 7931c7850f9SSasha Levin root_len = strlen(root); 7941c7850f9SSasha Levin /* 7951c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 7961c7850f9SSasha Levin * absolute path of an fid without playing with strings. 7971c7850f9SSasha Levin */ 7981c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 799b4422bf3SAneesh Kumar K.V strcpy(p9dev->fids[i].abs_path, root); 800b4422bf3SAneesh Kumar K.V p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len; 8011c7850f9SSasha Levin } 802b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 803b4422bf3SAneesh Kumar K.V if (p9dev->config->tag_len > MAX_TAG_LEN) 804b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 8051c7850f9SSasha Levin 806b4422bf3SAneesh Kumar K.V memcpy(p9dev->config->tag, tag_name, strlen(tag_name)); 807b4422bf3SAneesh Kumar K.V p9dev->features |= 1 << VIRTIO_9P_MOUNT_TAG; 8081c7850f9SSasha Levin 8091c7850f9SSasha Levin if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0) 810b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 8111c7850f9SSasha Levin 812b4422bf3SAneesh Kumar K.V p9_base_addr = ioport__register(IOPORT_EMPTY, 813b4422bf3SAneesh Kumar K.V &virtio_p9_io_ops, 814b4422bf3SAneesh Kumar K.V IOPORT_SIZE, p9dev); 815b4422bf3SAneesh Kumar K.V p9dev->base_addr = p9_base_addr; 816b4422bf3SAneesh Kumar K.V p9dev->pci_hdr = (struct pci_device_header) { 817b4422bf3SAneesh Kumar K.V .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 818b4422bf3SAneesh Kumar K.V .device_id = PCI_DEVICE_ID_VIRTIO_P9, 819b4422bf3SAneesh Kumar K.V .header_type = PCI_HEADER_TYPE_NORMAL, 820b4422bf3SAneesh Kumar K.V .revision_id = 0, 821b4422bf3SAneesh Kumar K.V .class = 0x010000, 822b4422bf3SAneesh Kumar K.V .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 823b4422bf3SAneesh Kumar K.V .subsys_id = VIRTIO_ID_9P, 824b4422bf3SAneesh Kumar K.V .irq_pin = pin, 825b4422bf3SAneesh Kumar K.V .irq_line = line, 826b4422bf3SAneesh Kumar K.V .bar[0] = p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO, 827b4422bf3SAneesh Kumar K.V }; 828b4422bf3SAneesh Kumar K.V pci__register(&p9dev->pci_hdr, dev); 829b4422bf3SAneesh Kumar K.V 830b4422bf3SAneesh Kumar K.V return; 831b4422bf3SAneesh Kumar K.V free_p9dev_config: 832b4422bf3SAneesh Kumar K.V free(p9dev->config); 833b4422bf3SAneesh Kumar K.V free_p9dev: 834b4422bf3SAneesh Kumar K.V free(p9dev); 8351c7850f9SSasha Levin } 836