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" 111c7850f9SSasha Levin 121c7850f9SSasha Levin #include <linux/virtio_ring.h> 131c7850f9SSasha Levin #include <linux/virtio_9p.h> 141c7850f9SSasha Levin #include <net/9p/9p.h> 151c7850f9SSasha Levin 161c7850f9SSasha Levin #include <fcntl.h> 171c7850f9SSasha Levin #include <sys/types.h> 181c7850f9SSasha Levin #include <sys/stat.h> 191c7850f9SSasha Levin #include <pthread.h> 201c7850f9SSasha Levin #include <dirent.h> 211c7850f9SSasha Levin 221c7850f9SSasha Levin #define NUM_VIRT_QUEUES 1 231c7850f9SSasha Levin #define VIRTIO_P9_QUEUE_SIZE 128 24*b4422bf3SAneesh Kumar K.V #define VIRTIO_P9_DEFAULT_TAG "kvm_9p" 251c7850f9SSasha Levin #define VIRTIO_P9_HDR_LEN (sizeof(u32)+sizeof(u8)+sizeof(u16)) 261c7850f9SSasha Levin #define VIRTIO_P9_MAX_FID 128 271c7850f9SSasha Levin #define VIRTIO_P9_VERSION "9P2000" 28*b4422bf3SAneesh Kumar K.V #define MAX_TAG_LEN 32 29*b4422bf3SAneesh Kumar K.V 301c7850f9SSasha Levin 311c7850f9SSasha Levin struct p9_msg { 321c7850f9SSasha Levin u32 size; 331c7850f9SSasha Levin u8 cmd; 341c7850f9SSasha Levin u16 tag; 351c7850f9SSasha Levin u8 msg[0]; 361c7850f9SSasha Levin } __attribute__((packed)); 371c7850f9SSasha Levin 381c7850f9SSasha Levin struct p9_fid { 391c7850f9SSasha Levin u32 fid; 401c7850f9SSasha Levin u8 is_dir; 411c7850f9SSasha Levin char abs_path[PATH_MAX]; 421c7850f9SSasha Levin char *path; 431c7850f9SSasha Levin DIR *dir; 441c7850f9SSasha Levin int fd; 451c7850f9SSasha Levin }; 461c7850f9SSasha Levin 47*b4422bf3SAneesh Kumar K.V struct p9_dev_job { 48*b4422bf3SAneesh Kumar K.V struct virt_queue *vq; 49*b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 50*b4422bf3SAneesh Kumar K.V void *job_id; 511c7850f9SSasha Levin }; 521c7850f9SSasha Levin 531c7850f9SSasha Levin struct p9_dev { 541c7850f9SSasha Levin u8 status; 551c7850f9SSasha Levin u8 isr; 561c7850f9SSasha Levin u16 config_vector; 571c7850f9SSasha Levin u32 features; 581c7850f9SSasha Levin struct virtio_9p_config *config; 59f884f920SSasha Levin u16 base_addr; 601c7850f9SSasha Levin 611c7850f9SSasha Levin /* virtio queue */ 621c7850f9SSasha Levin u16 queue_selector; 631c7850f9SSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 64*b4422bf3SAneesh Kumar K.V struct p9_dev_job jobs[NUM_VIRT_QUEUES]; 651c7850f9SSasha Levin struct p9_fid fids[VIRTIO_P9_MAX_FID]; 661c7850f9SSasha Levin char root_dir[PATH_MAX]; 67*b4422bf3SAneesh Kumar K.V struct pci_device_header pci_hdr; 681c7850f9SSasha Levin }; 691c7850f9SSasha Levin 701c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 71*b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 72*b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 731c7850f9SSasha Levin { 74*b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 751c7850f9SSasha Levin 761c7850f9SSasha Levin return abs_path; 771c7850f9SSasha Levin } 781c7850f9SSasha Levin 79*b4422bf3SAneesh Kumar K.V static bool virtio_p9_dev_in(struct p9_dev *p9dev, void *data, 80*b4422bf3SAneesh Kumar K.V unsigned long offset, 81*b4422bf3SAneesh Kumar K.V int size, u32 count) 821c7850f9SSasha Levin { 83*b4422bf3SAneesh Kumar K.V u8 *config_space = (u8 *) p9dev->config; 841c7850f9SSasha Levin 851c7850f9SSasha Levin if (size != 1 || count != 1) 861c7850f9SSasha Levin return false; 871c7850f9SSasha Levin 881c7850f9SSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 891c7850f9SSasha Levin 901c7850f9SSasha Levin return true; 911c7850f9SSasha Levin } 921c7850f9SSasha Levin 93*b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, 94*b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 951c7850f9SSasha Levin { 961c7850f9SSasha Levin bool ret = true; 97*b4422bf3SAneesh Kumar K.V unsigned long offset; 98*b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = ioport->priv; 991c7850f9SSasha Levin 100*b4422bf3SAneesh Kumar K.V 101*b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 1021c7850f9SSasha Levin 1031c7850f9SSasha Levin switch (offset) { 1041c7850f9SSasha Levin case VIRTIO_PCI_HOST_FEATURES: 105*b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->features); 1061c7850f9SSasha Levin ret = true; 1071c7850f9SSasha Levin break; 1081c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 1091c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 1101c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 1111c7850f9SSasha Levin ret = false; 1121c7850f9SSasha Levin break; 1131c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: 114*b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->vqs[p9dev->queue_selector].pfn); 1151c7850f9SSasha Levin break; 1161c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NUM: 1171c7850f9SSasha Levin ioport__write16(data, VIRTIO_P9_QUEUE_SIZE); 1181c7850f9SSasha Levin break; 1191c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 120*b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->status); 1211c7850f9SSasha Levin break; 1221c7850f9SSasha Levin case VIRTIO_PCI_ISR: 123*b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->isr); 124*b4422bf3SAneesh Kumar K.V kvm__irq_line(kvm, p9dev->pci_hdr.irq_line, VIRTIO_IRQ_LOW); 125*b4422bf3SAneesh Kumar K.V p9dev->isr = VIRTIO_IRQ_LOW; 1261c7850f9SSasha Levin break; 1271c7850f9SSasha Levin default: 128*b4422bf3SAneesh Kumar K.V ret = virtio_p9_dev_in(p9dev, data, offset, size, count); 1291c7850f9SSasha Levin break; 1301c7850f9SSasha Levin }; 1311c7850f9SSasha Levin 1321c7850f9SSasha Levin return ret; 1331c7850f9SSasha Levin } 1341c7850f9SSasha Levin 1351c7850f9SSasha Levin static int omode2uflags(u8 mode) 1361c7850f9SSasha Levin { 1371c7850f9SSasha Levin int ret = 0; 1381c7850f9SSasha Levin 1391c7850f9SSasha Levin /* Basic open modes are same as uflags */ 1401c7850f9SSasha Levin ret = mode & 3; 1411c7850f9SSasha Levin 1421c7850f9SSasha Levin /* Everything else is different */ 1431c7850f9SSasha Levin if (mode & P9_OTRUNC) 1441c7850f9SSasha Levin ret |= O_TRUNC; 1451c7850f9SSasha Levin 1461c7850f9SSasha Levin if (mode & P9_OAPPEND) 1471c7850f9SSasha Levin ret |= O_APPEND; 1481c7850f9SSasha Levin 1491c7850f9SSasha Levin if (mode & P9_OEXCL) 1501c7850f9SSasha Levin ret |= O_EXCL; 1511c7850f9SSasha Levin 1521c7850f9SSasha Levin return ret; 1531c7850f9SSasha Levin } 1541c7850f9SSasha Levin 1551c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid) 1561c7850f9SSasha Levin { 1571c7850f9SSasha Levin *qid = (struct p9_qid) { 1581c7850f9SSasha Levin .path = st->st_ino, 1591c7850f9SSasha Levin .version = st->st_mtime, 1601c7850f9SSasha Levin }; 1611c7850f9SSasha Levin 1621c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1631c7850f9SSasha Levin qid->type |= P9_QTDIR; 1641c7850f9SSasha Levin } 1651c7850f9SSasha Levin 166*b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1671c7850f9SSasha Levin { 168*b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 169*b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 170*b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 1711c7850f9SSasha Levin } 172*b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 173*b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 174*b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 1751c7850f9SSasha Levin } 1761c7850f9SSasha Levin } 1771c7850f9SSasha Levin 1781c7850f9SSasha Levin static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag) 1791c7850f9SSasha Levin { 1801c7850f9SSasha Levin *msg = (struct p9_msg) { 1811c7850f9SSasha Levin .size = size, 1821c7850f9SSasha Levin .tag = tag, 1831c7850f9SSasha Levin .cmd = cmd, 1841c7850f9SSasha Levin }; 1851c7850f9SSasha Levin } 1861c7850f9SSasha Levin 187*b4422bf3SAneesh Kumar K.V static bool virtio_p9_version(struct p9_dev *p9dev, struct p9_msg *msg, 188*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 189*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 1901c7850f9SSasha Levin { 1911c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 1921c7850f9SSasha Levin struct p9_rversion *rversion = (struct p9_rversion *)outmsg->msg; 1931c7850f9SSasha Levin 1941c7850f9SSasha Levin rversion->msize = 4096; 1951c7850f9SSasha Levin rversion->version.len = strlen(VIRTIO_P9_VERSION); 1961c7850f9SSasha Levin memcpy(&rversion->version.str, VIRTIO_P9_VERSION, rversion->version.len); 1971c7850f9SSasha Levin 198*b4422bf3SAneesh Kumar K.V *outlen = VIRTIO_P9_HDR_LEN + 199*b4422bf3SAneesh Kumar K.V rversion->version.len + sizeof(u16) + sizeof(u32); 2001c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RVERSION, msg->tag); 2011c7850f9SSasha Levin 2021c7850f9SSasha Levin return true; 2031c7850f9SSasha Levin } 2041c7850f9SSasha Levin 205*b4422bf3SAneesh Kumar K.V static bool virtio_p9_clunk(struct p9_dev *p9dev, struct p9_msg *msg, 206*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 207*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 2081c7850f9SSasha Levin { 2091c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 2101c7850f9SSasha Levin struct p9_tclunk *tclunk = (struct p9_tclunk *)msg->msg; 2111c7850f9SSasha Levin 212*b4422bf3SAneesh Kumar K.V close_fid(p9dev, tclunk->fid); 2131c7850f9SSasha Levin 2141c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 2151c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RCLUNK, msg->tag); 2161c7850f9SSasha Levin 2171c7850f9SSasha Levin return true; 2181c7850f9SSasha Levin } 2191c7850f9SSasha Levin 220*b4422bf3SAneesh Kumar K.V static bool virtio_p9_open(struct p9_dev *p9dev, struct p9_msg *msg, 221*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 222*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 2231c7850f9SSasha Levin { 2241c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 2251c7850f9SSasha Levin struct p9_topen *topen = (struct p9_topen *)msg->msg; 2261c7850f9SSasha Levin struct p9_ropen *ropen = (struct p9_ropen *)outmsg->msg; 227*b4422bf3SAneesh Kumar K.V struct p9_fid *new_fid = &p9dev->fids[topen->fid]; 2281c7850f9SSasha Levin struct stat st; 2291c7850f9SSasha Levin 2301c7850f9SSasha Levin if (stat(new_fid->abs_path, &st) < 0) 2311c7850f9SSasha Levin return false; 2321c7850f9SSasha Levin 2331c7850f9SSasha Levin st2qid(&st, &ropen->qid); 2341c7850f9SSasha Levin ropen->iounit = 0; 2351c7850f9SSasha Levin 2361c7850f9SSasha Levin if (new_fid->is_dir) 2371c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 2381c7850f9SSasha Levin else 2391c7850f9SSasha Levin new_fid->fd = open(new_fid->abs_path, omode2uflags(topen->mode)); 2401c7850f9SSasha Levin 2411c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*ropen); 2421c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_ROPEN, msg->tag); 2431c7850f9SSasha Levin 2441c7850f9SSasha Levin return true; 2451c7850f9SSasha Levin } 2461c7850f9SSasha Levin 247*b4422bf3SAneesh Kumar K.V static bool virtio_p9_create(struct p9_dev *p9dev, struct p9_msg *msg, 248*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 249*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 2501c7850f9SSasha Levin { 2511c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 2521c7850f9SSasha Levin struct p9_tcreate *tcreate = (struct p9_tcreate *)msg->msg; 2531c7850f9SSasha Levin struct p9_rcreate *rcreate = (struct p9_rcreate *)outmsg->msg; 254*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tcreate->fid]; 2551c7850f9SSasha Levin struct stat st; 2561c7850f9SSasha Levin u8 mode; 2571c7850f9SSasha Levin u32 perm; 2581c7850f9SSasha Levin 2591c7850f9SSasha Levin rcreate->iounit = 0; 2601c7850f9SSasha Levin 2611c7850f9SSasha Levin /* Get last byte of the variable length struct */ 2621c7850f9SSasha Levin mode = *((u8 *)msg + msg->size - 1); 2631c7850f9SSasha Levin perm = *(u32 *)((u8 *)msg + msg->size - 5); 2641c7850f9SSasha Levin 2651c7850f9SSasha Levin sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str); 2661c7850f9SSasha Levin 267*b4422bf3SAneesh Kumar K.V close_fid(p9dev, tcreate->fid); 2681c7850f9SSasha Levin 2691c7850f9SSasha Levin if (perm & P9_DMDIR) { 2701c7850f9SSasha Levin mkdir(fid->abs_path, perm & 0xFFFF); 2711c7850f9SSasha Levin fid->dir = opendir(fid->abs_path); 2721c7850f9SSasha Levin fid->is_dir = 1; 2731c7850f9SSasha Levin } else { 2741c7850f9SSasha Levin fid->fd = open(fid->abs_path, omode2uflags(mode) | O_CREAT, 0777); 2751c7850f9SSasha Levin } 2761c7850f9SSasha Levin 2771c7850f9SSasha Levin if (stat(fid->abs_path, &st) < 0) 2781c7850f9SSasha Levin return false; 2791c7850f9SSasha Levin 2801c7850f9SSasha Levin st2qid(&st, &rcreate->qid); 2811c7850f9SSasha Levin 2821c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rcreate); 2831c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RCREATE, msg->tag); 2841c7850f9SSasha Levin 2851c7850f9SSasha Levin return true; 2861c7850f9SSasha Levin } 2871c7850f9SSasha Levin 288*b4422bf3SAneesh Kumar K.V static bool virtio_p9_walk(struct p9_dev *p9dev, struct p9_msg *msg, 289*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 290*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 2911c7850f9SSasha Levin { 2921c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 2931c7850f9SSasha Levin struct p9_twalk *twalk = (struct p9_twalk *)msg->msg; 2941c7850f9SSasha Levin struct p9_rwalk *rwalk = (struct p9_rwalk *)outmsg->msg; 2951c7850f9SSasha Levin struct p9_str *str = twalk->wnames; 296*b4422bf3SAneesh Kumar K.V struct p9_fid *new_fid = &p9dev->fids[twalk->newfid]; 2971c7850f9SSasha Levin u8 i; 2981c7850f9SSasha Levin 2991c7850f9SSasha Levin rwalk->nwqid = 0; 3001c7850f9SSasha Levin if (twalk->nwname) { 301*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[twalk->fid]; 3021c7850f9SSasha Levin 3031c7850f9SSasha Levin for (i = 0; i < twalk->nwname; i++) { 3041c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3051c7850f9SSasha Levin char full_path[PATH_MAX]; 3061c7850f9SSasha Levin struct stat st; 3071c7850f9SSasha Levin 3081c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 3091c7850f9SSasha Levin sprintf(tmp, "%s/%.*s", fid->path, str->len, (char *)&str->str); 3101c7850f9SSasha Levin 311*b4422bf3SAneesh Kumar K.V if (stat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3121c7850f9SSasha Levin break; 3131c7850f9SSasha Levin 3141c7850f9SSasha Levin st2qid(&st, &rwalk->wqids[i]); 3151c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3161c7850f9SSasha Levin strcpy(new_fid->path, tmp); 3171c7850f9SSasha Levin new_fid->fid = twalk->newfid; 3181c7850f9SSasha Levin rwalk->nwqid++; 3191c7850f9SSasha Levin } 3201c7850f9SSasha Levin } else { 321*b4422bf3SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[twalk->fid].is_dir; 322*b4422bf3SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[twalk->fid].path); 3231c7850f9SSasha Levin new_fid->fid = twalk->newfid; 3241c7850f9SSasha Levin } 3251c7850f9SSasha Levin 3261c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u16) + sizeof(struct p9_qid) * rwalk->nwqid; 3271c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RWALK, msg->tag); 3281c7850f9SSasha Levin 3291c7850f9SSasha Levin return true; 3301c7850f9SSasha Levin } 3311c7850f9SSasha Levin 332*b4422bf3SAneesh Kumar K.V static bool virtio_p9_attach(struct p9_dev *p9dev, struct p9_msg *msg, 333*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 334*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 3351c7850f9SSasha Levin { 3361c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 3371c7850f9SSasha Levin struct p9_rattach *rattach = (struct p9_rattach *)outmsg->msg; 3381c7850f9SSasha Levin struct p9_tattach *tattach = (struct p9_tattach *)msg->msg; 3391c7850f9SSasha Levin struct stat st; 3401c7850f9SSasha Levin struct p9_fid *fid; 3411c7850f9SSasha Levin u32 i; 3421c7850f9SSasha Levin 3431c7850f9SSasha Levin /* Reset everything */ 3441c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 345*b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 3461c7850f9SSasha Levin 347*b4422bf3SAneesh Kumar K.V if (stat(p9dev->root_dir, &st) < 0) 3481c7850f9SSasha Levin return false; 3491c7850f9SSasha Levin 3501c7850f9SSasha Levin st2qid(&st, &rattach->qid); 3511c7850f9SSasha Levin 352*b4422bf3SAneesh Kumar K.V fid = &p9dev->fids[tattach->fid]; 3531c7850f9SSasha Levin fid->fid = tattach->fid; 3541c7850f9SSasha Levin fid->is_dir = 1; 3551c7850f9SSasha Levin strcpy(fid->path, "/"); 3561c7850f9SSasha Levin 3571c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rattach); 3581c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RATTACH, msg->tag); 3591c7850f9SSasha Levin 3601c7850f9SSasha Levin return true; 3611c7850f9SSasha Levin } 3621c7850f9SSasha Levin 363*b4422bf3SAneesh Kumar K.V static u32 virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, 364*b4422bf3SAneesh Kumar K.V struct stat *st, struct p9_rstat *rstat) 3651c7850f9SSasha Levin { 3661c7850f9SSasha Levin struct p9_str *str; 3671c7850f9SSasha Levin 3681c7850f9SSasha Levin rstat->stat.type = 0; 3691c7850f9SSasha Levin rstat->stat.dev = 0; 3701c7850f9SSasha Levin st2qid(st, &rstat->stat.qid); 3711c7850f9SSasha Levin rstat->stat.mode = st->st_mode; 3721c7850f9SSasha Levin rstat->stat.length = st->st_size; 3731c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) { 3741c7850f9SSasha Levin rstat->stat.length = 0; 3751c7850f9SSasha Levin rstat->stat.mode |= P9_DMDIR; 3761c7850f9SSasha Levin } 3771c7850f9SSasha Levin 3781c7850f9SSasha Levin rstat->stat.atime = st->st_atime; 3791c7850f9SSasha Levin rstat->stat.mtime = st->st_mtime; 3801c7850f9SSasha Levin 3811c7850f9SSasha Levin str = (struct p9_str *)&rstat->stat.name; 3821c7850f9SSasha Levin str->len = strlen(name); 3831c7850f9SSasha Levin memcpy(&str->str, name, str->len); 3841c7850f9SSasha Levin str = (void *)str + str->len + sizeof(u16); 3851c7850f9SSasha Levin 3861c7850f9SSasha Levin /* TODO: Pass usernames to the client */ 3871c7850f9SSasha Levin str->len = 0; 3881c7850f9SSasha Levin str = (void *)str + sizeof(u16); 3891c7850f9SSasha Levin str->len = 0; 3901c7850f9SSasha Levin str = (void *)str + sizeof(u16); 3911c7850f9SSasha Levin str->len = 0; 3921c7850f9SSasha Levin str = (void *)str + sizeof(u16); 3931c7850f9SSasha Levin 394*b4422bf3SAneesh Kumar K.V /* 395*b4422bf3SAneesh Kumar K.V * We subtract a u16 here because rstat->size 396*b4422bf3SAneesh Kumar K.V * doesn't include rstat->size itself 397*b4422bf3SAneesh Kumar K.V */ 3981c7850f9SSasha Levin rstat->stat.size = (void *)str - (void *)&rstat->stat - sizeof(u16); 3991c7850f9SSasha Levin 4001c7850f9SSasha Levin return rstat->stat.size + sizeof(u16); 4011c7850f9SSasha Levin } 4021c7850f9SSasha Levin 403*b4422bf3SAneesh Kumar K.V static bool virtio_p9_read(struct p9_dev *p9dev, struct p9_msg *msg, 404*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 405*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 4061c7850f9SSasha Levin { 4071c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 4081c7850f9SSasha Levin struct p9_tread *tread = (struct p9_tread *)msg->msg; 4091c7850f9SSasha Levin struct p9_rread *rread = (struct p9_rread *)outmsg->msg; 4101c7850f9SSasha Levin struct p9_rstat *rstat = (struct p9_rstat *)iov[1].iov_base; 411*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tread->fid]; 4121c7850f9SSasha Levin struct stat st; 4131c7850f9SSasha Levin 4141c7850f9SSasha Levin rread->count = 0; 4151c7850f9SSasha Levin 4161c7850f9SSasha Levin if (fid->is_dir) { 4171c7850f9SSasha Levin /* If reading a dir, fill the buffer with p9_stat entries */ 4181c7850f9SSasha Levin struct dirent *cur = readdir(fid->dir); 4191c7850f9SSasha Levin char full_path[PATH_MAX]; 4201c7850f9SSasha Levin 4211c7850f9SSasha Levin while (cur) { 4221c7850f9SSasha Levin u32 read; 4231c7850f9SSasha Levin 424*b4422bf3SAneesh Kumar K.V stat(rel_to_abs(p9dev, cur->d_name, full_path), &st); 425*b4422bf3SAneesh Kumar K.V read = virtio_p9_fill_stat(p9dev, cur->d_name, 426*b4422bf3SAneesh Kumar K.V &st, rstat); 4271c7850f9SSasha Levin rread->count += read; 4281c7850f9SSasha Levin rstat = (void *)rstat + read; 4291c7850f9SSasha Levin cur = readdir(fid->dir); 4301c7850f9SSasha Levin } 4311c7850f9SSasha Levin } else { 4321c7850f9SSasha Levin iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 4331c7850f9SSasha Levin iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 434*b4422bf3SAneesh Kumar K.V rread->count = preadv(fid->fd, iov, iniovcnt, tread->offset); 4351c7850f9SSasha Levin if (rread->count > tread->count) 4361c7850f9SSasha Levin rread->count = tread->count; 4371c7850f9SSasha Levin } 4381c7850f9SSasha Levin 4391c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32) + rread->count; 4401c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RREAD, msg->tag); 4411c7850f9SSasha Levin 4421c7850f9SSasha Levin return true; 4431c7850f9SSasha Levin } 4441c7850f9SSasha Levin 445*b4422bf3SAneesh Kumar K.V static bool virtio_p9_stat(struct p9_dev *p9dev, struct p9_msg *msg, 446*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 447*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 4481c7850f9SSasha Levin { 4491c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 4501c7850f9SSasha Levin struct p9_tstat *tstat = (struct p9_tstat *)msg->msg; 4511c7850f9SSasha Levin struct p9_rstat *rstat = (struct p9_rstat *)(outmsg->msg + sizeof(u16)); 4521c7850f9SSasha Levin struct stat st; 453*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tstat->fid]; 4541c7850f9SSasha Levin u32 ret; 4551c7850f9SSasha Levin 4561c7850f9SSasha Levin if (stat(fid->abs_path, &st) < 0) 4571c7850f9SSasha Levin return false; 4581c7850f9SSasha Levin 459*b4422bf3SAneesh Kumar K.V ret = virtio_p9_fill_stat(p9dev, fid->path, &st, rstat); 4601c7850f9SSasha Levin 4611c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16) * 2; 4621c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RSTAT, msg->tag); 4631c7850f9SSasha Levin return true; 4641c7850f9SSasha Levin } 4651c7850f9SSasha Levin 466*b4422bf3SAneesh Kumar K.V static bool virtio_p9_wstat(struct p9_dev *p9dev, struct p9_msg *msg, 467*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 468*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 4691c7850f9SSasha Levin { 4701c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 4711c7850f9SSasha Levin struct p9_twstat *twstat = (struct p9_twstat *)msg->msg; 4721c7850f9SSasha Levin struct p9_str *str; 473*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[twstat->fid]; 474aec426f0SCyrill Gorcunov int res = 0; 4751c7850f9SSasha Levin 4761c7850f9SSasha Levin if (twstat->stat.length != -1UL) 4771c7850f9SSasha Levin res = ftruncate(fid->fd, twstat->stat.length); 4781c7850f9SSasha Levin 4791c7850f9SSasha Levin if (twstat->stat.mode != -1U) 4801c7850f9SSasha Levin chmod(fid->abs_path, twstat->stat.mode & 0xFFFF); 4811c7850f9SSasha Levin 4821c7850f9SSasha Levin str = (void *)&twstat->stat.name + sizeof(u16); 4831c7850f9SSasha Levin if (str->len > 0) { 4841c7850f9SSasha Levin char new_name[PATH_MAX] = {0}; 4851c7850f9SSasha Levin char full_path[PATH_MAX]; 4861c7850f9SSasha Levin char *last_dir = strrchr(fid->path, '/'); 4871c7850f9SSasha Levin 4881c7850f9SSasha Levin /* We need to get the full file name out of twstat->name */ 4891c7850f9SSasha Levin if (last_dir) 4901c7850f9SSasha Levin strncpy(new_name, fid->path, last_dir - fid->path + 1); 4911c7850f9SSasha Levin 4921c7850f9SSasha Levin memcpy(new_name + strlen(new_name), &str->str, str->len); 4931c7850f9SSasha Levin 4941c7850f9SSasha Levin /* fid is reused for the new file */ 495*b4422bf3SAneesh Kumar K.V rename(fid->abs_path, rel_to_abs(p9dev, new_name, full_path)); 4961c7850f9SSasha Levin sprintf(fid->path, "%s", new_name); 4971c7850f9SSasha Levin } 4981c7850f9SSasha Levin 4991c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 5001c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RWSTAT, msg->tag); 501aec426f0SCyrill Gorcunov 502aec426f0SCyrill Gorcunov return res == 0; 5031c7850f9SSasha Levin } 5041c7850f9SSasha Levin 505*b4422bf3SAneesh Kumar K.V static bool virtio_p9_remove(struct p9_dev *p9dev, struct p9_msg *msg, 506*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 507*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 5081c7850f9SSasha Levin { 5091c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 5101c7850f9SSasha Levin struct p9_tremove *tremove = (struct p9_tremove *)msg->msg; 511*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[tremove->fid]; 5121c7850f9SSasha Levin 513*b4422bf3SAneesh Kumar K.V close_fid(p9dev, tremove->fid); 5141c7850f9SSasha Levin if (fid->is_dir) 5151c7850f9SSasha Levin rmdir(fid->abs_path); 5161c7850f9SSasha Levin else 5171c7850f9SSasha Levin unlink(fid->abs_path); 5181c7850f9SSasha Levin 5191c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 5201c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RREMOVE, msg->tag); 5211c7850f9SSasha Levin return true; 5221c7850f9SSasha Levin } 5231c7850f9SSasha Levin 524*b4422bf3SAneesh Kumar K.V static bool virtio_p9_write(struct p9_dev *p9dev, struct p9_msg *msg, 525*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 526*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen) 5271c7850f9SSasha Levin { 5281c7850f9SSasha Levin struct p9_msg *outmsg; 5291c7850f9SSasha Levin struct p9_rwrite *rwrite; 5301c7850f9SSasha Levin struct p9_twrite *twrite = (struct p9_twrite *)msg->msg; 531*b4422bf3SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[twrite->fid]; 5321c7850f9SSasha Levin 533*b4422bf3SAneesh Kumar K.V if (outiovcnt == 1) { 5341c7850f9SSasha Levin outmsg = iov[0].iov_base; 5351c7850f9SSasha Levin rwrite = (struct p9_rwrite *)outmsg->msg; 536*b4422bf3SAneesh Kumar K.V rwrite->count = pwrite(fid->fd, &twrite->data, 537*b4422bf3SAneesh Kumar K.V twrite->count, twrite->offset); 5381c7850f9SSasha Levin } else { 5391c7850f9SSasha Levin outmsg = iov[2].iov_base; 5401c7850f9SSasha Levin rwrite = (struct p9_rwrite *)outmsg->msg; 541*b4422bf3SAneesh Kumar K.V rwrite->count = pwrite(fid->fd, iov[1].iov_base, 542*b4422bf3SAneesh Kumar K.V twrite->count, twrite->offset); 5431c7850f9SSasha Levin } 5441c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32); 5451c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RWRITE, msg->tag); 5461c7850f9SSasha Levin 5471c7850f9SSasha Levin return true; 5481c7850f9SSasha Levin } 5491c7850f9SSasha Levin 550*b4422bf3SAneesh Kumar K.V typedef bool p9_handler(struct p9_dev *p9dev, struct p9_msg *msg, 551*b4422bf3SAneesh Kumar K.V u32 len, struct iovec *iov, 552*b4422bf3SAneesh Kumar K.V int outiovcnt, int iniovcnt, u32 *outlen); 553*b4422bf3SAneesh Kumar K.V 554*b4422bf3SAneesh Kumar K.V static p9_handler *virtio_9p_handler [] = { 555*b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 556*b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 557*b4422bf3SAneesh Kumar K.V [P9_TSTAT] = virtio_p9_stat, 558*b4422bf3SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 559*b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 560*b4422bf3SAneesh Kumar K.V [P9_TOPEN] = virtio_p9_open, 561*b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 562*b4422bf3SAneesh Kumar K.V [P9_TCREATE] = virtio_p9_create, 563*b4422bf3SAneesh Kumar K.V [P9_TWSTAT] = virtio_p9_wstat, 564*b4422bf3SAneesh Kumar K.V [P9_TREMOVE] = virtio_p9_remove, 565*b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 566*b4422bf3SAneesh Kumar K.V }; 567*b4422bf3SAneesh Kumar K.V 568*b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 5691c7850f9SSasha Levin { 570*b4422bf3SAneesh Kumar K.V u32 len = 0; 5711c7850f9SSasha Levin u16 out, in, head; 5721c7850f9SSasha Levin struct p9_msg *msg; 573*b4422bf3SAneesh Kumar K.V p9_handler *handler; 574*b4422bf3SAneesh Kumar K.V struct virt_queue *vq; 575*b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 576*b4422bf3SAneesh Kumar K.V struct iovec iov[VIRTIO_P9_QUEUE_SIZE]; 5771c7850f9SSasha Levin 578*b4422bf3SAneesh Kumar K.V vq = job->vq; 579*b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 580*b4422bf3SAneesh Kumar K.V head = virt_queue__get_iov(vq, iov, &out, &in, kvm); 5811c7850f9SSasha Levin msg = iov[0].iov_base; 5821c7850f9SSasha Levin 583*b4422bf3SAneesh Kumar K.V if (msg->cmd >= ARRAY_SIZE(virtio_9p_handler) || 584*b4422bf3SAneesh Kumar K.V !virtio_9p_handler[msg->cmd]) { 5851c7850f9SSasha Levin printf("Unsupported P9 message type: %u\n", msg->cmd); 5861c7850f9SSasha Levin 587*b4422bf3SAneesh Kumar K.V } else { 588*b4422bf3SAneesh Kumar K.V handler = virtio_9p_handler[msg->cmd]; 589*b4422bf3SAneesh Kumar K.V handler(p9dev, msg, iov[0].iov_len, iov+1, out, in, &len); 590*b4422bf3SAneesh Kumar K.V } 591*b4422bf3SAneesh Kumar K.V virt_queue__set_used_elem(vq, head, len); 5921c7850f9SSasha Levin return true; 5931c7850f9SSasha Levin } 5941c7850f9SSasha Levin 5951c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 5961c7850f9SSasha Levin { 597*b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 598*b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 599*b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 6001c7850f9SSasha Levin 6011c7850f9SSasha Levin while (virt_queue__available(vq)) { 602*b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 603*b4422bf3SAneesh Kumar K.V virt_queue__trigger_irq(vq, p9dev->pci_hdr.irq_line, 604*b4422bf3SAneesh Kumar K.V &p9dev->isr, kvm); 6051c7850f9SSasha Levin } 6061c7850f9SSasha Levin } 6071c7850f9SSasha Levin 608*b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, 609*b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 6101c7850f9SSasha Levin { 6111c7850f9SSasha Levin unsigned long offset; 6121c7850f9SSasha Levin bool ret = true; 613*b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 6141c7850f9SSasha Levin 615*b4422bf3SAneesh Kumar K.V p9dev = ioport->priv; 616*b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 6171c7850f9SSasha Levin 6181c7850f9SSasha Levin switch (offset) { 6191c7850f9SSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 6201c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 6211c7850f9SSasha Levin break; 6221c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 6231c7850f9SSasha Levin void *p; 624*b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 625*b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 6261c7850f9SSasha Levin 627*b4422bf3SAneesh Kumar K.V job = &p9dev->jobs[p9dev->queue_selector]; 628*b4422bf3SAneesh Kumar K.V queue = &p9dev->vqs[p9dev->queue_selector]; 6291c7850f9SSasha Levin queue->pfn = ioport__read32(data); 6301c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 6311c7850f9SSasha Levin 632*b4422bf3SAneesh Kumar K.V vring_init(&queue->vring, VIRTIO_P9_QUEUE_SIZE, p, 633*b4422bf3SAneesh Kumar K.V VIRTIO_PCI_VRING_ALIGN); 6341c7850f9SSasha Levin 635*b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 636*b4422bf3SAneesh Kumar K.V .vq = queue, 637*b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 638*b4422bf3SAneesh Kumar K.V }; 639*b4422bf3SAneesh Kumar K.V job->job_id = thread_pool__add_job(kvm, virtio_p9_do_io, job); 6401c7850f9SSasha Levin break; 6411c7850f9SSasha Levin } 6421c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 643*b4422bf3SAneesh Kumar K.V p9dev->queue_selector = ioport__read16(data); 6441c7850f9SSasha Levin break; 6451c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 6461c7850f9SSasha Levin u16 queue_index; 6471c7850f9SSasha Levin queue_index = ioport__read16(data); 648*b4422bf3SAneesh Kumar K.V thread_pool__do_job(p9dev->jobs[queue_index].job_id); 6491c7850f9SSasha Levin break; 6501c7850f9SSasha Levin } 6511c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 652*b4422bf3SAneesh Kumar K.V p9dev->status = ioport__read8(data); 6531c7850f9SSasha Levin break; 6541c7850f9SSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 655*b4422bf3SAneesh Kumar K.V p9dev->config_vector = VIRTIO_MSI_NO_VECTOR; 6561c7850f9SSasha Levin break; 6571c7850f9SSasha Levin default: 6581c7850f9SSasha Levin ret = false; 6591c7850f9SSasha Levin break; 6601c7850f9SSasha Levin }; 6611c7850f9SSasha Levin 6621c7850f9SSasha Levin return ret; 6631c7850f9SSasha Levin } 6641c7850f9SSasha Levin 6651c7850f9SSasha Levin static struct ioport_operations virtio_p9_io_ops = { 6661c7850f9SSasha Levin .io_in = virtio_p9_pci_io_in, 6671c7850f9SSasha Levin .io_out = virtio_p9_pci_io_out, 6681c7850f9SSasha Levin }; 6691c7850f9SSasha Levin 670*b4422bf3SAneesh Kumar K.V void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name) 6711c7850f9SSasha Levin { 6721c7850f9SSasha Levin u8 pin, line, dev; 6731c7850f9SSasha Levin u32 i, root_len; 674f884f920SSasha Levin u16 p9_base_addr; 675*b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 6761c7850f9SSasha Levin 677*b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 678*b4422bf3SAneesh Kumar K.V if (!p9dev) 6791c7850f9SSasha Levin return; 680*b4422bf3SAneesh Kumar K.V if (!tag_name) 681*b4422bf3SAneesh Kumar K.V tag_name = VIRTIO_P9_DEFAULT_TAG; 682*b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 683*b4422bf3SAneesh Kumar K.V if (p9dev->config == NULL) 684*b4422bf3SAneesh Kumar K.V goto free_p9dev; 6851c7850f9SSasha Levin 686*b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 6871c7850f9SSasha Levin root_len = strlen(root); 6881c7850f9SSasha Levin /* 6891c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 6901c7850f9SSasha Levin * absolute path of an fid without playing with strings. 6911c7850f9SSasha Levin */ 6921c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 693*b4422bf3SAneesh Kumar K.V strcpy(p9dev->fids[i].abs_path, root); 694*b4422bf3SAneesh Kumar K.V p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len; 6951c7850f9SSasha Levin } 696*b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 697*b4422bf3SAneesh Kumar K.V if (p9dev->config->tag_len > MAX_TAG_LEN) 698*b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 6991c7850f9SSasha Levin 700*b4422bf3SAneesh Kumar K.V memcpy(p9dev->config->tag, tag_name, strlen(tag_name)); 701*b4422bf3SAneesh Kumar K.V p9dev->features |= 1 << VIRTIO_9P_MOUNT_TAG; 7021c7850f9SSasha Levin 7031c7850f9SSasha Levin if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0) 704*b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 7051c7850f9SSasha Levin 706*b4422bf3SAneesh Kumar K.V p9_base_addr = ioport__register(IOPORT_EMPTY, 707*b4422bf3SAneesh Kumar K.V &virtio_p9_io_ops, 708*b4422bf3SAneesh Kumar K.V IOPORT_SIZE, p9dev); 709*b4422bf3SAneesh Kumar K.V p9dev->base_addr = p9_base_addr; 710*b4422bf3SAneesh Kumar K.V p9dev->pci_hdr = (struct pci_device_header) { 711*b4422bf3SAneesh Kumar K.V .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 712*b4422bf3SAneesh Kumar K.V .device_id = PCI_DEVICE_ID_VIRTIO_P9, 713*b4422bf3SAneesh Kumar K.V .header_type = PCI_HEADER_TYPE_NORMAL, 714*b4422bf3SAneesh Kumar K.V .revision_id = 0, 715*b4422bf3SAneesh Kumar K.V .class = 0x010000, 716*b4422bf3SAneesh Kumar K.V .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 717*b4422bf3SAneesh Kumar K.V .subsys_id = VIRTIO_ID_9P, 718*b4422bf3SAneesh Kumar K.V .irq_pin = pin, 719*b4422bf3SAneesh Kumar K.V .irq_line = line, 720*b4422bf3SAneesh Kumar K.V .bar[0] = p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO, 721*b4422bf3SAneesh Kumar K.V }; 722*b4422bf3SAneesh Kumar K.V pci__register(&p9dev->pci_hdr, dev); 723*b4422bf3SAneesh Kumar K.V 724*b4422bf3SAneesh Kumar K.V return; 725*b4422bf3SAneesh Kumar K.V free_p9dev_config: 726*b4422bf3SAneesh Kumar K.V free(p9dev->config); 727*b4422bf3SAneesh Kumar K.V free_p9dev: 728*b4422bf3SAneesh Kumar K.V free(p9dev); 7291c7850f9SSasha Levin } 730