1*1c7850f9SSasha Levin #include "kvm/virtio-9p.h" 2*1c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h" 3*1c7850f9SSasha Levin #include "kvm/virtio.h" 4*1c7850f9SSasha Levin #include "kvm/ioport.h" 5*1c7850f9SSasha Levin #include "kvm/mutex.h" 6*1c7850f9SSasha Levin #include "kvm/util.h" 7*1c7850f9SSasha Levin #include "kvm/kvm.h" 8*1c7850f9SSasha Levin #include "kvm/pci.h" 9*1c7850f9SSasha Levin #include "kvm/threadpool.h" 10*1c7850f9SSasha Levin #include "kvm/irq.h" 11*1c7850f9SSasha Levin 12*1c7850f9SSasha Levin #include <linux/virtio_ring.h> 13*1c7850f9SSasha Levin #include <linux/virtio_9p.h> 14*1c7850f9SSasha Levin #include <net/9p/9p.h> 15*1c7850f9SSasha Levin 16*1c7850f9SSasha Levin #include <fcntl.h> 17*1c7850f9SSasha Levin #include <sys/types.h> 18*1c7850f9SSasha Levin #include <sys/stat.h> 19*1c7850f9SSasha Levin #include <pthread.h> 20*1c7850f9SSasha Levin #include <dirent.h> 21*1c7850f9SSasha Levin 22*1c7850f9SSasha Levin #define NUM_VIRT_QUEUES 1 23*1c7850f9SSasha Levin #define VIRTIO_P9_QUEUE_SIZE 128 24*1c7850f9SSasha Levin #define VIRTIO_P9_TAG "kvm_9p" 25*1c7850f9SSasha Levin #define VIRTIO_P9_HDR_LEN (sizeof(u32)+sizeof(u8)+sizeof(u16)) 26*1c7850f9SSasha Levin #define VIRTIO_P9_MAX_FID 128 27*1c7850f9SSasha Levin #define VIRTIO_P9_VERSION "9P2000" 28*1c7850f9SSasha Levin 29*1c7850f9SSasha Levin struct p9_msg { 30*1c7850f9SSasha Levin u32 size; 31*1c7850f9SSasha Levin u8 cmd; 32*1c7850f9SSasha Levin u16 tag; 33*1c7850f9SSasha Levin u8 msg[0]; 34*1c7850f9SSasha Levin } __attribute__((packed)); 35*1c7850f9SSasha Levin 36*1c7850f9SSasha Levin struct p9_fid { 37*1c7850f9SSasha Levin u32 fid; 38*1c7850f9SSasha Levin u8 is_dir; 39*1c7850f9SSasha Levin char abs_path[PATH_MAX]; 40*1c7850f9SSasha Levin char *path; 41*1c7850f9SSasha Levin DIR *dir; 42*1c7850f9SSasha Levin int fd; 43*1c7850f9SSasha Levin }; 44*1c7850f9SSasha Levin 45*1c7850f9SSasha Levin static struct pci_device_header virtio_p9_pci_device = { 46*1c7850f9SSasha Levin .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 47*1c7850f9SSasha Levin .device_id = PCI_DEVICE_ID_VIRTIO_P9, 48*1c7850f9SSasha Levin .header_type = PCI_HEADER_TYPE_NORMAL, 49*1c7850f9SSasha Levin .revision_id = 0, 50*1c7850f9SSasha Levin .class = 0x010000, 51*1c7850f9SSasha Levin .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 52*1c7850f9SSasha Levin .subsys_id = VIRTIO_ID_9P, 53*1c7850f9SSasha Levin .bar[0] = IOPORT_VIRTIO_P9 | PCI_BASE_ADDRESS_SPACE_IO, 54*1c7850f9SSasha Levin }; 55*1c7850f9SSasha Levin 56*1c7850f9SSasha Levin struct p9_dev { 57*1c7850f9SSasha Levin u8 status; 58*1c7850f9SSasha Levin u8 isr; 59*1c7850f9SSasha Levin u16 config_vector; 60*1c7850f9SSasha Levin u32 features; 61*1c7850f9SSasha Levin struct virtio_9p_config *config; 62*1c7850f9SSasha Levin 63*1c7850f9SSasha Levin /* virtio queue */ 64*1c7850f9SSasha Levin u16 queue_selector; 65*1c7850f9SSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 66*1c7850f9SSasha Levin void *jobs[NUM_VIRT_QUEUES]; 67*1c7850f9SSasha Levin 68*1c7850f9SSasha Levin struct p9_fid fids[VIRTIO_P9_MAX_FID]; 69*1c7850f9SSasha Levin char root_dir[PATH_MAX]; 70*1c7850f9SSasha Levin }; 71*1c7850f9SSasha Levin 72*1c7850f9SSasha Levin static struct p9_dev p9dev; 73*1c7850f9SSasha Levin 74*1c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 75*1c7850f9SSasha Levin static const char *rel_to_abs(const char *path, char *abs_path) 76*1c7850f9SSasha Levin { 77*1c7850f9SSasha Levin sprintf(abs_path, "%s/%s", p9dev.root_dir, path); 78*1c7850f9SSasha Levin 79*1c7850f9SSasha Levin return abs_path; 80*1c7850f9SSasha Levin } 81*1c7850f9SSasha Levin 82*1c7850f9SSasha Levin static bool virtio_p9_dev_in(void *data, unsigned long offset, int size, u32 count) 83*1c7850f9SSasha Levin { 84*1c7850f9SSasha Levin u8 *config_space = (u8 *) p9dev.config; 85*1c7850f9SSasha Levin 86*1c7850f9SSasha Levin if (size != 1 || count != 1) 87*1c7850f9SSasha Levin return false; 88*1c7850f9SSasha Levin 89*1c7850f9SSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 90*1c7850f9SSasha Levin 91*1c7850f9SSasha Levin return true; 92*1c7850f9SSasha Levin } 93*1c7850f9SSasha Levin 94*1c7850f9SSasha Levin static bool virtio_p9_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count) 95*1c7850f9SSasha Levin { 96*1c7850f9SSasha Levin unsigned long offset; 97*1c7850f9SSasha Levin bool ret = true; 98*1c7850f9SSasha Levin 99*1c7850f9SSasha Levin offset = port - IOPORT_VIRTIO_P9; 100*1c7850f9SSasha Levin 101*1c7850f9SSasha Levin switch (offset) { 102*1c7850f9SSasha Levin case VIRTIO_PCI_HOST_FEATURES: 103*1c7850f9SSasha Levin ioport__write32(data, p9dev.features); 104*1c7850f9SSasha Levin ret = true; 105*1c7850f9SSasha Levin break; 106*1c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 107*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 108*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 109*1c7850f9SSasha Levin ret = false; 110*1c7850f9SSasha Levin break; 111*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: 112*1c7850f9SSasha Levin ioport__write32(data, p9dev.vqs[p9dev.queue_selector].pfn); 113*1c7850f9SSasha Levin break; 114*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NUM: 115*1c7850f9SSasha Levin ioport__write16(data, VIRTIO_P9_QUEUE_SIZE); 116*1c7850f9SSasha Levin break; 117*1c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 118*1c7850f9SSasha Levin ioport__write8(data, p9dev.status); 119*1c7850f9SSasha Levin break; 120*1c7850f9SSasha Levin case VIRTIO_PCI_ISR: 121*1c7850f9SSasha Levin ioport__write8(data, p9dev.isr); 122*1c7850f9SSasha Levin kvm__irq_line(kvm, virtio_p9_pci_device.irq_line, VIRTIO_IRQ_LOW); 123*1c7850f9SSasha Levin p9dev.isr = VIRTIO_IRQ_LOW; 124*1c7850f9SSasha Levin break; 125*1c7850f9SSasha Levin default: 126*1c7850f9SSasha Levin ret = virtio_p9_dev_in(data, offset, size, count); 127*1c7850f9SSasha Levin break; 128*1c7850f9SSasha Levin }; 129*1c7850f9SSasha Levin 130*1c7850f9SSasha Levin return ret; 131*1c7850f9SSasha Levin } 132*1c7850f9SSasha Levin 133*1c7850f9SSasha Levin static int omode2uflags(u8 mode) 134*1c7850f9SSasha Levin { 135*1c7850f9SSasha Levin int ret = 0; 136*1c7850f9SSasha Levin 137*1c7850f9SSasha Levin /* Basic open modes are same as uflags */ 138*1c7850f9SSasha Levin ret = mode & 3; 139*1c7850f9SSasha Levin 140*1c7850f9SSasha Levin /* Everything else is different */ 141*1c7850f9SSasha Levin if (mode & P9_OTRUNC) 142*1c7850f9SSasha Levin ret |= O_TRUNC; 143*1c7850f9SSasha Levin 144*1c7850f9SSasha Levin if (mode & P9_OAPPEND) 145*1c7850f9SSasha Levin ret |= O_APPEND; 146*1c7850f9SSasha Levin 147*1c7850f9SSasha Levin if (mode & P9_OEXCL) 148*1c7850f9SSasha Levin ret |= O_EXCL; 149*1c7850f9SSasha Levin 150*1c7850f9SSasha Levin return ret; 151*1c7850f9SSasha Levin } 152*1c7850f9SSasha Levin 153*1c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid) 154*1c7850f9SSasha Levin { 155*1c7850f9SSasha Levin *qid = (struct p9_qid) { 156*1c7850f9SSasha Levin .path = st->st_ino, 157*1c7850f9SSasha Levin .version = st->st_mtime, 158*1c7850f9SSasha Levin }; 159*1c7850f9SSasha Levin 160*1c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 161*1c7850f9SSasha Levin qid->type |= P9_QTDIR; 162*1c7850f9SSasha Levin } 163*1c7850f9SSasha Levin 164*1c7850f9SSasha Levin static void close_fid(u32 fid) 165*1c7850f9SSasha Levin { 166*1c7850f9SSasha Levin if (p9dev.fids[fid].fd > 0) { 167*1c7850f9SSasha Levin close(p9dev.fids[fid].fd); 168*1c7850f9SSasha Levin p9dev.fids[fid].fd = -1; 169*1c7850f9SSasha Levin } 170*1c7850f9SSasha Levin if (p9dev.fids[fid].dir) { 171*1c7850f9SSasha Levin closedir(p9dev.fids[fid].dir); 172*1c7850f9SSasha Levin p9dev.fids[fid].dir = NULL; 173*1c7850f9SSasha Levin } 174*1c7850f9SSasha Levin } 175*1c7850f9SSasha Levin 176*1c7850f9SSasha Levin static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag) 177*1c7850f9SSasha Levin { 178*1c7850f9SSasha Levin *msg = (struct p9_msg) { 179*1c7850f9SSasha Levin .size = size, 180*1c7850f9SSasha Levin .tag = tag, 181*1c7850f9SSasha Levin .cmd = cmd, 182*1c7850f9SSasha Levin }; 183*1c7850f9SSasha Levin } 184*1c7850f9SSasha Levin 185*1c7850f9SSasha Levin static bool virtio_p9_version(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 186*1c7850f9SSasha Levin { 187*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 188*1c7850f9SSasha Levin struct p9_rversion *rversion = (struct p9_rversion *)outmsg->msg; 189*1c7850f9SSasha Levin 190*1c7850f9SSasha Levin rversion->msize = 4096; 191*1c7850f9SSasha Levin rversion->version.len = strlen(VIRTIO_P9_VERSION); 192*1c7850f9SSasha Levin memcpy(&rversion->version.str, VIRTIO_P9_VERSION, rversion->version.len); 193*1c7850f9SSasha Levin 194*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + rversion->version.len + sizeof(u16) + sizeof(u32); 195*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RVERSION, msg->tag); 196*1c7850f9SSasha Levin 197*1c7850f9SSasha Levin return true; 198*1c7850f9SSasha Levin } 199*1c7850f9SSasha Levin 200*1c7850f9SSasha Levin static bool virtio_p9_clunk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 201*1c7850f9SSasha Levin { 202*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 203*1c7850f9SSasha Levin struct p9_tclunk *tclunk = (struct p9_tclunk *)msg->msg; 204*1c7850f9SSasha Levin 205*1c7850f9SSasha Levin close_fid(tclunk->fid); 206*1c7850f9SSasha Levin 207*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 208*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RCLUNK, msg->tag); 209*1c7850f9SSasha Levin 210*1c7850f9SSasha Levin return true; 211*1c7850f9SSasha Levin } 212*1c7850f9SSasha Levin 213*1c7850f9SSasha Levin static bool virtio_p9_open(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 214*1c7850f9SSasha Levin { 215*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 216*1c7850f9SSasha Levin struct p9_topen *topen = (struct p9_topen *)msg->msg; 217*1c7850f9SSasha Levin struct p9_ropen *ropen = (struct p9_ropen *)outmsg->msg; 218*1c7850f9SSasha Levin struct p9_fid *new_fid = &p9dev.fids[topen->fid]; 219*1c7850f9SSasha Levin struct stat st; 220*1c7850f9SSasha Levin 221*1c7850f9SSasha Levin if (stat(new_fid->abs_path, &st) < 0) 222*1c7850f9SSasha Levin return false; 223*1c7850f9SSasha Levin 224*1c7850f9SSasha Levin st2qid(&st, &ropen->qid); 225*1c7850f9SSasha Levin ropen->iounit = 0; 226*1c7850f9SSasha Levin 227*1c7850f9SSasha Levin if (new_fid->is_dir) 228*1c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 229*1c7850f9SSasha Levin else 230*1c7850f9SSasha Levin new_fid->fd = open(new_fid->abs_path, omode2uflags(topen->mode)); 231*1c7850f9SSasha Levin 232*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*ropen); 233*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_ROPEN, msg->tag); 234*1c7850f9SSasha Levin 235*1c7850f9SSasha Levin return true; 236*1c7850f9SSasha Levin } 237*1c7850f9SSasha Levin 238*1c7850f9SSasha Levin static bool virtio_p9_create(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 239*1c7850f9SSasha Levin { 240*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 241*1c7850f9SSasha Levin struct p9_tcreate *tcreate = (struct p9_tcreate *)msg->msg; 242*1c7850f9SSasha Levin struct p9_rcreate *rcreate = (struct p9_rcreate *)outmsg->msg; 243*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[tcreate->fid]; 244*1c7850f9SSasha Levin struct stat st; 245*1c7850f9SSasha Levin u8 mode; 246*1c7850f9SSasha Levin u32 perm; 247*1c7850f9SSasha Levin 248*1c7850f9SSasha Levin rcreate->iounit = 0; 249*1c7850f9SSasha Levin 250*1c7850f9SSasha Levin /* Get last byte of the variable length struct */ 251*1c7850f9SSasha Levin mode = *((u8 *)msg + msg->size - 1); 252*1c7850f9SSasha Levin perm = *(u32 *)((u8 *)msg + msg->size - 5); 253*1c7850f9SSasha Levin 254*1c7850f9SSasha Levin sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str); 255*1c7850f9SSasha Levin 256*1c7850f9SSasha Levin close_fid(tcreate->fid); 257*1c7850f9SSasha Levin 258*1c7850f9SSasha Levin if (perm & P9_DMDIR) { 259*1c7850f9SSasha Levin mkdir(fid->abs_path, perm & 0xFFFF); 260*1c7850f9SSasha Levin fid->dir = opendir(fid->abs_path); 261*1c7850f9SSasha Levin fid->is_dir = 1; 262*1c7850f9SSasha Levin } else { 263*1c7850f9SSasha Levin fid->fd = open(fid->abs_path, omode2uflags(mode) | O_CREAT, 0777); 264*1c7850f9SSasha Levin } 265*1c7850f9SSasha Levin 266*1c7850f9SSasha Levin if (stat(fid->abs_path, &st) < 0) 267*1c7850f9SSasha Levin return false; 268*1c7850f9SSasha Levin 269*1c7850f9SSasha Levin st2qid(&st, &rcreate->qid); 270*1c7850f9SSasha Levin 271*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rcreate); 272*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RCREATE, msg->tag); 273*1c7850f9SSasha Levin 274*1c7850f9SSasha Levin return true; 275*1c7850f9SSasha Levin } 276*1c7850f9SSasha Levin 277*1c7850f9SSasha Levin static bool virtio_p9_walk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 278*1c7850f9SSasha Levin { 279*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 280*1c7850f9SSasha Levin struct p9_twalk *twalk = (struct p9_twalk *)msg->msg; 281*1c7850f9SSasha Levin struct p9_rwalk *rwalk = (struct p9_rwalk *)outmsg->msg; 282*1c7850f9SSasha Levin struct p9_str *str = twalk->wnames; 283*1c7850f9SSasha Levin struct p9_fid *new_fid = &p9dev.fids[twalk->newfid]; 284*1c7850f9SSasha Levin u8 i; 285*1c7850f9SSasha Levin 286*1c7850f9SSasha Levin rwalk->nwqid = 0; 287*1c7850f9SSasha Levin if (twalk->nwname) { 288*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[twalk->fid]; 289*1c7850f9SSasha Levin 290*1c7850f9SSasha Levin for (i = 0; i < twalk->nwname; i++) { 291*1c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 292*1c7850f9SSasha Levin char full_path[PATH_MAX]; 293*1c7850f9SSasha Levin struct stat st; 294*1c7850f9SSasha Levin 295*1c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 296*1c7850f9SSasha Levin sprintf(tmp, "%s/%.*s", fid->path, str->len, (char *)&str->str); 297*1c7850f9SSasha Levin 298*1c7850f9SSasha Levin if (stat(rel_to_abs(tmp, full_path), &st) < 0) 299*1c7850f9SSasha Levin break; 300*1c7850f9SSasha Levin 301*1c7850f9SSasha Levin st2qid(&st, &rwalk->wqids[i]); 302*1c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 303*1c7850f9SSasha Levin strcpy(new_fid->path, tmp); 304*1c7850f9SSasha Levin new_fid->fid = twalk->newfid; 305*1c7850f9SSasha Levin rwalk->nwqid++; 306*1c7850f9SSasha Levin } 307*1c7850f9SSasha Levin } else { 308*1c7850f9SSasha Levin new_fid->is_dir = p9dev.fids[twalk->fid].is_dir; 309*1c7850f9SSasha Levin strcpy(new_fid->path, p9dev.fids[twalk->fid].path); 310*1c7850f9SSasha Levin new_fid->fid = twalk->newfid; 311*1c7850f9SSasha Levin } 312*1c7850f9SSasha Levin 313*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u16) + sizeof(struct p9_qid) * rwalk->nwqid; 314*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RWALK, msg->tag); 315*1c7850f9SSasha Levin 316*1c7850f9SSasha Levin return true; 317*1c7850f9SSasha Levin } 318*1c7850f9SSasha Levin 319*1c7850f9SSasha Levin static bool virtio_p9_attach(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 320*1c7850f9SSasha Levin { 321*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 322*1c7850f9SSasha Levin struct p9_rattach *rattach = (struct p9_rattach *)outmsg->msg; 323*1c7850f9SSasha Levin struct p9_tattach *tattach = (struct p9_tattach *)msg->msg; 324*1c7850f9SSasha Levin struct stat st; 325*1c7850f9SSasha Levin struct p9_fid *fid; 326*1c7850f9SSasha Levin u32 i; 327*1c7850f9SSasha Levin 328*1c7850f9SSasha Levin /* Reset everything */ 329*1c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 330*1c7850f9SSasha Levin p9dev.fids[i].fid = P9_NOFID; 331*1c7850f9SSasha Levin 332*1c7850f9SSasha Levin if (stat(p9dev.root_dir, &st) < 0) 333*1c7850f9SSasha Levin return false; 334*1c7850f9SSasha Levin 335*1c7850f9SSasha Levin st2qid(&st, &rattach->qid); 336*1c7850f9SSasha Levin 337*1c7850f9SSasha Levin fid = &p9dev.fids[tattach->fid]; 338*1c7850f9SSasha Levin fid->fid = tattach->fid; 339*1c7850f9SSasha Levin fid->is_dir = 1; 340*1c7850f9SSasha Levin strcpy(fid->path, "/"); 341*1c7850f9SSasha Levin 342*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rattach); 343*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RATTACH, msg->tag); 344*1c7850f9SSasha Levin 345*1c7850f9SSasha Levin return true; 346*1c7850f9SSasha Levin } 347*1c7850f9SSasha Levin 348*1c7850f9SSasha Levin static u32 virtio_p9_fill_stat(const char *name, struct stat *st, struct p9_rstat *rstat) 349*1c7850f9SSasha Levin { 350*1c7850f9SSasha Levin struct p9_str *str; 351*1c7850f9SSasha Levin 352*1c7850f9SSasha Levin rstat->stat.type = 0; 353*1c7850f9SSasha Levin rstat->stat.dev = 0; 354*1c7850f9SSasha Levin st2qid(st, &rstat->stat.qid); 355*1c7850f9SSasha Levin rstat->stat.mode = st->st_mode; 356*1c7850f9SSasha Levin rstat->stat.length = st->st_size; 357*1c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) { 358*1c7850f9SSasha Levin rstat->stat.length = 0; 359*1c7850f9SSasha Levin rstat->stat.mode |= P9_DMDIR; 360*1c7850f9SSasha Levin } 361*1c7850f9SSasha Levin 362*1c7850f9SSasha Levin rstat->stat.atime = st->st_atime; 363*1c7850f9SSasha Levin rstat->stat.mtime = st->st_mtime; 364*1c7850f9SSasha Levin 365*1c7850f9SSasha Levin str = (struct p9_str *)&rstat->stat.name; 366*1c7850f9SSasha Levin str->len = strlen(name); 367*1c7850f9SSasha Levin memcpy(&str->str, name, str->len); 368*1c7850f9SSasha Levin str = (void *)str + str->len + sizeof(u16); 369*1c7850f9SSasha Levin 370*1c7850f9SSasha Levin /* TODO: Pass usernames to the client */ 371*1c7850f9SSasha Levin str->len = 0; 372*1c7850f9SSasha Levin str = (void *)str + sizeof(u16); 373*1c7850f9SSasha Levin str->len = 0; 374*1c7850f9SSasha Levin str = (void *)str + sizeof(u16); 375*1c7850f9SSasha Levin str->len = 0; 376*1c7850f9SSasha Levin str = (void *)str + sizeof(u16); 377*1c7850f9SSasha Levin 378*1c7850f9SSasha Levin /* We subtract a u16 here because rstat->size doesn't include rstat->size itself */ 379*1c7850f9SSasha Levin rstat->stat.size = (void *)str - (void *)&rstat->stat - sizeof(u16); 380*1c7850f9SSasha Levin 381*1c7850f9SSasha Levin return rstat->stat.size + sizeof(u16); 382*1c7850f9SSasha Levin } 383*1c7850f9SSasha Levin 384*1c7850f9SSasha Levin static bool virtio_p9_read(struct p9_msg *msg, u32 len, struct iovec *iov, int iovcnt, u32 *outlen) 385*1c7850f9SSasha Levin { 386*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 387*1c7850f9SSasha Levin struct p9_tread *tread = (struct p9_tread *)msg->msg; 388*1c7850f9SSasha Levin struct p9_rread *rread = (struct p9_rread *)outmsg->msg; 389*1c7850f9SSasha Levin struct p9_rstat *rstat = (struct p9_rstat *)iov[1].iov_base; 390*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[tread->fid]; 391*1c7850f9SSasha Levin struct stat st; 392*1c7850f9SSasha Levin 393*1c7850f9SSasha Levin rread->count = 0; 394*1c7850f9SSasha Levin 395*1c7850f9SSasha Levin if (fid->is_dir) { 396*1c7850f9SSasha Levin /* If reading a dir, fill the buffer with p9_stat entries */ 397*1c7850f9SSasha Levin struct dirent *cur = readdir(fid->dir); 398*1c7850f9SSasha Levin char full_path[PATH_MAX]; 399*1c7850f9SSasha Levin 400*1c7850f9SSasha Levin while (cur) { 401*1c7850f9SSasha Levin u32 read; 402*1c7850f9SSasha Levin 403*1c7850f9SSasha Levin stat(rel_to_abs(cur->d_name, full_path), &st); 404*1c7850f9SSasha Levin read = virtio_p9_fill_stat(cur->d_name, &st, rstat); 405*1c7850f9SSasha Levin rread->count += read; 406*1c7850f9SSasha Levin rstat = (void *)rstat + read; 407*1c7850f9SSasha Levin cur = readdir(fid->dir); 408*1c7850f9SSasha Levin } 409*1c7850f9SSasha Levin } else { 410*1c7850f9SSasha Levin iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 411*1c7850f9SSasha Levin iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 412*1c7850f9SSasha Levin rread->count = preadv(fid->fd, iov, iovcnt, tread->offset); 413*1c7850f9SSasha Levin if (rread->count > tread->count) 414*1c7850f9SSasha Levin rread->count = tread->count; 415*1c7850f9SSasha Levin } 416*1c7850f9SSasha Levin 417*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32) + rread->count; 418*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RREAD, msg->tag); 419*1c7850f9SSasha Levin 420*1c7850f9SSasha Levin return true; 421*1c7850f9SSasha Levin } 422*1c7850f9SSasha Levin 423*1c7850f9SSasha Levin static bool virtio_p9_stat(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 424*1c7850f9SSasha Levin { 425*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 426*1c7850f9SSasha Levin struct p9_tstat *tstat = (struct p9_tstat *)msg->msg; 427*1c7850f9SSasha Levin struct p9_rstat *rstat = (struct p9_rstat *)(outmsg->msg + sizeof(u16)); 428*1c7850f9SSasha Levin struct stat st; 429*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[tstat->fid]; 430*1c7850f9SSasha Levin u32 ret; 431*1c7850f9SSasha Levin 432*1c7850f9SSasha Levin if (stat(fid->abs_path, &st) < 0) 433*1c7850f9SSasha Levin return false; 434*1c7850f9SSasha Levin 435*1c7850f9SSasha Levin ret = virtio_p9_fill_stat(fid->path, &st, rstat); 436*1c7850f9SSasha Levin 437*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16) * 2; 438*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RSTAT, msg->tag); 439*1c7850f9SSasha Levin return true; 440*1c7850f9SSasha Levin } 441*1c7850f9SSasha Levin 442*1c7850f9SSasha Levin static bool virtio_p9_wstat(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 443*1c7850f9SSasha Levin { 444*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 445*1c7850f9SSasha Levin struct p9_twstat *twstat = (struct p9_twstat *)msg->msg; 446*1c7850f9SSasha Levin struct p9_str *str; 447*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[twstat->fid]; 448*1c7850f9SSasha Levin int res; 449*1c7850f9SSasha Levin 450*1c7850f9SSasha Levin if (twstat->stat.length != -1UL) 451*1c7850f9SSasha Levin res = ftruncate(fid->fd, twstat->stat.length); 452*1c7850f9SSasha Levin 453*1c7850f9SSasha Levin if (twstat->stat.mode != -1U) 454*1c7850f9SSasha Levin chmod(fid->abs_path, twstat->stat.mode & 0xFFFF); 455*1c7850f9SSasha Levin 456*1c7850f9SSasha Levin str = (void *)&twstat->stat.name + sizeof(u16); 457*1c7850f9SSasha Levin if (str->len > 0) { 458*1c7850f9SSasha Levin char new_name[PATH_MAX] = {0}; 459*1c7850f9SSasha Levin char full_path[PATH_MAX]; 460*1c7850f9SSasha Levin char *last_dir = strrchr(fid->path, '/'); 461*1c7850f9SSasha Levin 462*1c7850f9SSasha Levin /* We need to get the full file name out of twstat->name */ 463*1c7850f9SSasha Levin if (last_dir) 464*1c7850f9SSasha Levin strncpy(new_name, fid->path, last_dir - fid->path + 1); 465*1c7850f9SSasha Levin 466*1c7850f9SSasha Levin memcpy(new_name + strlen(new_name), &str->str, str->len); 467*1c7850f9SSasha Levin 468*1c7850f9SSasha Levin /* fid is reused for the new file */ 469*1c7850f9SSasha Levin rename(fid->abs_path, rel_to_abs(new_name, full_path)); 470*1c7850f9SSasha Levin sprintf(fid->path, "%s", new_name); 471*1c7850f9SSasha Levin } 472*1c7850f9SSasha Levin 473*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 474*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RWSTAT, msg->tag); 475*1c7850f9SSasha Levin return true; 476*1c7850f9SSasha Levin } 477*1c7850f9SSasha Levin 478*1c7850f9SSasha Levin static bool virtio_p9_remove(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen) 479*1c7850f9SSasha Levin { 480*1c7850f9SSasha Levin struct p9_msg *outmsg = iov[0].iov_base; 481*1c7850f9SSasha Levin struct p9_tremove *tremove = (struct p9_tremove *)msg->msg; 482*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[tremove->fid]; 483*1c7850f9SSasha Levin 484*1c7850f9SSasha Levin close_fid(tremove->fid); 485*1c7850f9SSasha Levin if (fid->is_dir) 486*1c7850f9SSasha Levin rmdir(fid->abs_path); 487*1c7850f9SSasha Levin else 488*1c7850f9SSasha Levin unlink(fid->abs_path); 489*1c7850f9SSasha Levin 490*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 491*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RREMOVE, msg->tag); 492*1c7850f9SSasha Levin return true; 493*1c7850f9SSasha Levin } 494*1c7850f9SSasha Levin 495*1c7850f9SSasha Levin static bool virtio_p9_write(struct p9_msg *msg, u32 len, struct iovec *iov, int iovcnt, u32 *outlen) 496*1c7850f9SSasha Levin { 497*1c7850f9SSasha Levin struct p9_msg *outmsg; 498*1c7850f9SSasha Levin struct p9_rwrite *rwrite; 499*1c7850f9SSasha Levin struct p9_twrite *twrite = (struct p9_twrite *)msg->msg; 500*1c7850f9SSasha Levin struct p9_fid *fid = &p9dev.fids[twrite->fid]; 501*1c7850f9SSasha Levin 502*1c7850f9SSasha Levin if (iovcnt == 1) { 503*1c7850f9SSasha Levin outmsg = iov[0].iov_base; 504*1c7850f9SSasha Levin rwrite = (struct p9_rwrite *)outmsg->msg; 505*1c7850f9SSasha Levin rwrite->count = pwrite(fid->fd, &twrite->data, twrite->count, twrite->offset); 506*1c7850f9SSasha Levin } else { 507*1c7850f9SSasha Levin outmsg = iov[2].iov_base; 508*1c7850f9SSasha Levin rwrite = (struct p9_rwrite *)outmsg->msg; 509*1c7850f9SSasha Levin rwrite->count = pwrite(fid->fd, iov[1].iov_base, twrite->count, twrite->offset); 510*1c7850f9SSasha Levin } 511*1c7850f9SSasha Levin 512*1c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32); 513*1c7850f9SSasha Levin set_p9msg_hdr(outmsg, *outlen, P9_RWRITE, msg->tag); 514*1c7850f9SSasha Levin 515*1c7850f9SSasha Levin return true; 516*1c7850f9SSasha Levin } 517*1c7850f9SSasha Levin 518*1c7850f9SSasha Levin static bool virtio_p9_do_io_request(struct kvm *kvm, struct virt_queue *queue) 519*1c7850f9SSasha Levin { 520*1c7850f9SSasha Levin struct iovec iov[VIRTIO_P9_QUEUE_SIZE]; 521*1c7850f9SSasha Levin u16 out, in, head; 522*1c7850f9SSasha Levin struct p9_msg *msg; 523*1c7850f9SSasha Levin u32 len = 0; 524*1c7850f9SSasha Levin 525*1c7850f9SSasha Levin head = virt_queue__get_iov(queue, iov, &out, &in, kvm); 526*1c7850f9SSasha Levin msg = iov[0].iov_base; 527*1c7850f9SSasha Levin 528*1c7850f9SSasha Levin switch (msg->cmd) { 529*1c7850f9SSasha Levin case P9_TVERSION: 530*1c7850f9SSasha Levin virtio_p9_version(msg, iov[0].iov_len, iov+1, &len); 531*1c7850f9SSasha Levin break; 532*1c7850f9SSasha Levin case P9_TATTACH: 533*1c7850f9SSasha Levin virtio_p9_attach(msg, iov[0].iov_len, iov+1, &len); 534*1c7850f9SSasha Levin break; 535*1c7850f9SSasha Levin case P9_TSTAT: 536*1c7850f9SSasha Levin virtio_p9_stat(msg, iov[0].iov_len, iov+1, &len); 537*1c7850f9SSasha Levin break; 538*1c7850f9SSasha Levin case P9_TCLUNK: 539*1c7850f9SSasha Levin virtio_p9_clunk(msg, iov[0].iov_len, iov+1, &len); 540*1c7850f9SSasha Levin break; 541*1c7850f9SSasha Levin case P9_TWALK: 542*1c7850f9SSasha Levin virtio_p9_walk(msg, iov[0].iov_len, iov+1, &len); 543*1c7850f9SSasha Levin break; 544*1c7850f9SSasha Levin case P9_TOPEN: 545*1c7850f9SSasha Levin virtio_p9_open(msg, iov[0].iov_len, iov+1, &len); 546*1c7850f9SSasha Levin break; 547*1c7850f9SSasha Levin case P9_TREAD: 548*1c7850f9SSasha Levin virtio_p9_read(msg, iov[0].iov_len, iov+1, in, &len); 549*1c7850f9SSasha Levin break; 550*1c7850f9SSasha Levin case P9_TCREATE: 551*1c7850f9SSasha Levin virtio_p9_create(msg, iov[0].iov_len, iov+1, &len); 552*1c7850f9SSasha Levin break; 553*1c7850f9SSasha Levin case P9_TWSTAT: 554*1c7850f9SSasha Levin virtio_p9_wstat(msg, iov[0].iov_len, iov+1, &len); 555*1c7850f9SSasha Levin break; 556*1c7850f9SSasha Levin case P9_TREMOVE: 557*1c7850f9SSasha Levin virtio_p9_remove(msg, iov[0].iov_len, iov+1, &len); 558*1c7850f9SSasha Levin break; 559*1c7850f9SSasha Levin case P9_TWRITE: 560*1c7850f9SSasha Levin virtio_p9_write(msg, iov[0].iov_len, iov+1, out, &len); 561*1c7850f9SSasha Levin break; 562*1c7850f9SSasha Levin default: 563*1c7850f9SSasha Levin printf("Unsupported P9 message type: %u\n", msg->cmd); 564*1c7850f9SSasha Levin break; 565*1c7850f9SSasha Levin } 566*1c7850f9SSasha Levin virt_queue__set_used_elem(queue, head, len); 567*1c7850f9SSasha Levin 568*1c7850f9SSasha Levin return true; 569*1c7850f9SSasha Levin } 570*1c7850f9SSasha Levin 571*1c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 572*1c7850f9SSasha Levin { 573*1c7850f9SSasha Levin struct virt_queue *vq = param; 574*1c7850f9SSasha Levin 575*1c7850f9SSasha Levin while (virt_queue__available(vq)) { 576*1c7850f9SSasha Levin virtio_p9_do_io_request(kvm, vq); 577*1c7850f9SSasha Levin virt_queue__trigger_irq(vq, virtio_p9_pci_device.irq_line, &p9dev.isr, kvm); 578*1c7850f9SSasha Levin } 579*1c7850f9SSasha Levin } 580*1c7850f9SSasha Levin 581*1c7850f9SSasha Levin static bool virtio_p9_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count) 582*1c7850f9SSasha Levin { 583*1c7850f9SSasha Levin unsigned long offset; 584*1c7850f9SSasha Levin bool ret = true; 585*1c7850f9SSasha Levin 586*1c7850f9SSasha Levin offset = port - IOPORT_VIRTIO_P9; 587*1c7850f9SSasha Levin 588*1c7850f9SSasha Levin switch (offset) { 589*1c7850f9SSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 590*1c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 591*1c7850f9SSasha Levin break; 592*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 593*1c7850f9SSasha Levin struct virt_queue *queue; 594*1c7850f9SSasha Levin void *p; 595*1c7850f9SSasha Levin 596*1c7850f9SSasha Levin queue = &p9dev.vqs[p9dev.queue_selector]; 597*1c7850f9SSasha Levin queue->pfn = ioport__read32(data); 598*1c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 599*1c7850f9SSasha Levin 600*1c7850f9SSasha Levin vring_init(&queue->vring, VIRTIO_P9_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 601*1c7850f9SSasha Levin 602*1c7850f9SSasha Levin p9dev.jobs[p9dev.queue_selector] = thread_pool__add_job(kvm, virtio_p9_do_io, queue); 603*1c7850f9SSasha Levin 604*1c7850f9SSasha Levin break; 605*1c7850f9SSasha Levin } 606*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 607*1c7850f9SSasha Levin p9dev.queue_selector = ioport__read16(data); 608*1c7850f9SSasha Levin break; 609*1c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 610*1c7850f9SSasha Levin u16 queue_index; 611*1c7850f9SSasha Levin queue_index = ioport__read16(data); 612*1c7850f9SSasha Levin thread_pool__do_job(p9dev.jobs[queue_index]); 613*1c7850f9SSasha Levin break; 614*1c7850f9SSasha Levin } 615*1c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 616*1c7850f9SSasha Levin p9dev.status = ioport__read8(data); 617*1c7850f9SSasha Levin break; 618*1c7850f9SSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 619*1c7850f9SSasha Levin p9dev.config_vector = VIRTIO_MSI_NO_VECTOR; 620*1c7850f9SSasha Levin break; 621*1c7850f9SSasha Levin default: 622*1c7850f9SSasha Levin ret = false; 623*1c7850f9SSasha Levin break; 624*1c7850f9SSasha Levin }; 625*1c7850f9SSasha Levin 626*1c7850f9SSasha Levin return ret; 627*1c7850f9SSasha Levin } 628*1c7850f9SSasha Levin 629*1c7850f9SSasha Levin static struct ioport_operations virtio_p9_io_ops = { 630*1c7850f9SSasha Levin .io_in = virtio_p9_pci_io_in, 631*1c7850f9SSasha Levin .io_out = virtio_p9_pci_io_out, 632*1c7850f9SSasha Levin }; 633*1c7850f9SSasha Levin 634*1c7850f9SSasha Levin void virtio_9p__init(struct kvm *kvm, const char *root) 635*1c7850f9SSasha Levin { 636*1c7850f9SSasha Levin u8 pin, line, dev; 637*1c7850f9SSasha Levin u32 i, root_len; 638*1c7850f9SSasha Levin 639*1c7850f9SSasha Levin p9dev.config = calloc(1, sizeof(*p9dev.config) + sizeof(VIRTIO_P9_TAG)); 640*1c7850f9SSasha Levin if (p9dev.config == NULL) 641*1c7850f9SSasha Levin return; 642*1c7850f9SSasha Levin 643*1c7850f9SSasha Levin strcpy(p9dev.root_dir, root); 644*1c7850f9SSasha Levin root_len = strlen(root); 645*1c7850f9SSasha Levin 646*1c7850f9SSasha Levin /* 647*1c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 648*1c7850f9SSasha Levin * absolute path of an fid without playing with strings. 649*1c7850f9SSasha Levin */ 650*1c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 651*1c7850f9SSasha Levin strcpy(p9dev.fids[i].abs_path, root); 652*1c7850f9SSasha Levin p9dev.fids[i].path = p9dev.fids[i].abs_path + root_len; 653*1c7850f9SSasha Levin } 654*1c7850f9SSasha Levin 655*1c7850f9SSasha Levin p9dev.config->tag_len = strlen(VIRTIO_P9_TAG); 656*1c7850f9SSasha Levin memcpy(p9dev.config->tag, VIRTIO_P9_TAG, strlen(VIRTIO_P9_TAG)); 657*1c7850f9SSasha Levin p9dev.features |= 1 << VIRTIO_9P_MOUNT_TAG; 658*1c7850f9SSasha Levin 659*1c7850f9SSasha Levin if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0) 660*1c7850f9SSasha Levin return; 661*1c7850f9SSasha Levin 662*1c7850f9SSasha Levin virtio_p9_pci_device.irq_pin = pin; 663*1c7850f9SSasha Levin virtio_p9_pci_device.irq_line = line; 664*1c7850f9SSasha Levin pci__register(&virtio_p9_pci_device, dev); 665*1c7850f9SSasha Levin 666*1c7850f9SSasha Levin ioport__register(IOPORT_VIRTIO_P9, &virtio_p9_io_ops, IOPORT_VIRTIO_P9_SIZE); 667*1c7850f9SSasha Levin } 668