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" 8e59662b3SSasha Levin #include "kvm/guest_compat.h" 91c7850f9SSasha Levin 10bfc15268SAneesh Kumar K.V #include <stdio.h> 11bfc15268SAneesh Kumar K.V #include <stdlib.h> 121c7850f9SSasha Levin #include <fcntl.h> 131c7850f9SSasha Levin #include <sys/stat.h> 14bfc15268SAneesh Kumar K.V #include <unistd.h> 15bfc15268SAneesh Kumar K.V #include <string.h> 16bfc15268SAneesh Kumar K.V #include <errno.h> 171c7850f9SSasha Levin 182daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 192daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 202daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 212daa28d4SAneesh Kumar K.V 22*c7838fbdSSasha Levin static LIST_HEAD(devs); 23*c7838fbdSSasha Levin 241c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 25b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 26b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 271c7850f9SSasha Levin { 28b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 291c7850f9SSasha Levin 301c7850f9SSasha Levin return abs_path; 311c7850f9SSasha Levin } 321c7850f9SSasha Levin 331c7850f9SSasha Levin static int omode2uflags(u8 mode) 341c7850f9SSasha Levin { 351c7850f9SSasha Levin int ret = 0; 361c7850f9SSasha Levin 371c7850f9SSasha Levin /* Basic open modes are same as uflags */ 381c7850f9SSasha Levin ret = mode & 3; 391c7850f9SSasha Levin 401c7850f9SSasha Levin /* Everything else is different */ 411c7850f9SSasha Levin if (mode & P9_OTRUNC) 421c7850f9SSasha Levin ret |= O_TRUNC; 431c7850f9SSasha Levin 441c7850f9SSasha Levin if (mode & P9_OAPPEND) 451c7850f9SSasha Levin ret |= O_APPEND; 461c7850f9SSasha Levin 471c7850f9SSasha Levin if (mode & P9_OEXCL) 481c7850f9SSasha Levin ret |= O_EXCL; 491c7850f9SSasha Levin 501c7850f9SSasha Levin return ret; 511c7850f9SSasha Levin } 521c7850f9SSasha Levin 531c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid) 541c7850f9SSasha Levin { 551c7850f9SSasha Levin *qid = (struct p9_qid) { 561c7850f9SSasha Levin .path = st->st_ino, 571c7850f9SSasha Levin .version = st->st_mtime, 581c7850f9SSasha Levin }; 591c7850f9SSasha Levin 601c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 611c7850f9SSasha Levin qid->type |= P9_QTDIR; 621c7850f9SSasha Levin } 631c7850f9SSasha Levin 64b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 651c7850f9SSasha Levin { 66b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 67b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 68b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 691c7850f9SSasha Levin } 70b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 71b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 72b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 731c7850f9SSasha Levin } 741c7850f9SSasha Levin } 751c7850f9SSasha Levin 76bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 771c7850f9SSasha Levin { 78bfc15268SAneesh Kumar K.V u8 cmd; 79bfc15268SAneesh Kumar K.V u16 tag; 80bfc15268SAneesh Kumar K.V 81bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 82bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 83bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 84bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 85bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 861c7850f9SSasha Levin } 871c7850f9SSasha Levin 886b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 896b163a87SAneesh Kumar K.V { 906b163a87SAneesh Kumar K.V int i; 916b163a87SAneesh Kumar K.V u32 total = 0; 926b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 936b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 946b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 956b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 966b163a87SAneesh Kumar K.V i++; 976b163a87SAneesh Kumar K.V break; 986b163a87SAneesh Kumar K.V } 996b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1006b163a87SAneesh Kumar K.V } 1016b163a87SAneesh Kumar K.V return i; 1026b163a87SAneesh Kumar K.V } 1036b163a87SAneesh Kumar K.V 104eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 105eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 106eee1ba8eSAneesh Kumar K.V { 107bfc15268SAneesh Kumar K.V u16 tag; 108eee1ba8eSAneesh Kumar K.V char *err_str; 109eee1ba8eSAneesh Kumar K.V 110eee1ba8eSAneesh Kumar K.V err_str = strerror(err); 111bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 1125f900f6dSSasha Levin virtio_p9_pdu_writef(pdu, "sd", err_str, err); 113bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 114eee1ba8eSAneesh Kumar K.V 115bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 116bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 117bfc15268SAneesh Kumar K.V 118bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 119bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RERROR, tag); 120eee1ba8eSAneesh Kumar K.V } 121eee1ba8eSAneesh Kumar K.V 122ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 123af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1241c7850f9SSasha Levin { 125bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", 4096, VIRTIO_P9_VERSION); 1261c7850f9SSasha Levin 127bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 128bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 129ead43b01SAneesh Kumar K.V return; 1301c7850f9SSasha Levin } 1311c7850f9SSasha Levin 132ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 133af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1341c7850f9SSasha Levin { 135bfc15268SAneesh Kumar K.V u32 fid; 1361c7850f9SSasha Levin 137bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 138bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1391c7850f9SSasha Levin 140bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 141bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 142ead43b01SAneesh Kumar K.V return; 1431c7850f9SSasha Levin } 1441c7850f9SSasha Levin 145ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 146af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1471c7850f9SSasha Levin { 148bfc15268SAneesh Kumar K.V u8 mode; 149bfc15268SAneesh Kumar K.V u32 fid; 1501c7850f9SSasha Levin struct stat st; 151bfc15268SAneesh Kumar K.V struct p9_qid qid; 152bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 153bfc15268SAneesh Kumar K.V 154bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "db", &fid, &mode); 155bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[fid]; 1561c7850f9SSasha Levin 15730204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 158eee1ba8eSAneesh Kumar K.V goto err_out; 1591c7850f9SSasha Levin 160bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 1611c7850f9SSasha Levin 162eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 1631c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 164eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 165eee1ba8eSAneesh Kumar K.V goto err_out; 166eee1ba8eSAneesh Kumar K.V } else { 167eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 168bfc15268SAneesh Kumar K.V omode2uflags(mode) | O_NOFOLLOW); 169eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 170eee1ba8eSAneesh Kumar K.V goto err_out; 171eee1ba8eSAneesh Kumar K.V } 172bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 173bfc15268SAneesh Kumar K.V 174bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 175bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 176ead43b01SAneesh Kumar K.V return; 177eee1ba8eSAneesh Kumar K.V err_out: 178eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 179ead43b01SAneesh Kumar K.V return; 1801c7850f9SSasha Levin } 1811c7850f9SSasha Levin 182ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 183af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1841c7850f9SSasha Levin { 1854bc9734aSAneesh Kumar K.V DIR *dir; 1864bc9734aSAneesh Kumar K.V int fd; 1874bc9734aSAneesh Kumar K.V int res; 1881c7850f9SSasha Levin u8 mode; 1891c7850f9SSasha Levin u32 perm; 190bfc15268SAneesh Kumar K.V char *name; 1915f900f6dSSasha Levin char *ext = NULL; 192bfc15268SAneesh Kumar K.V u32 fid_val; 193af045e53SAneesh Kumar K.V struct stat st; 194bfc15268SAneesh Kumar K.V struct p9_qid qid; 195bfc15268SAneesh Kumar K.V struct p9_fid *fid; 1964bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 197af045e53SAneesh Kumar K.V 1985f900f6dSSasha Levin virtio_p9_pdu_readf(pdu, "dsdbs", &fid_val, &name, &perm, &mode, &ext); 199bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 2001c7850f9SSasha Levin 2014bc9734aSAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 2021c7850f9SSasha Levin if (perm & P9_DMDIR) { 2034bc9734aSAneesh Kumar K.V res = mkdir(full_path, perm & 0xFFFF); 2044bc9734aSAneesh Kumar K.V if (res < 0) 2054bc9734aSAneesh Kumar K.V goto err_out; 2064bc9734aSAneesh Kumar K.V dir = opendir(full_path); 2074bc9734aSAneesh Kumar K.V if (!dir) 2084bc9734aSAneesh Kumar K.V goto err_out; 2094bc9734aSAneesh Kumar K.V close_fid(p9dev, fid_val); 2104bc9734aSAneesh Kumar K.V fid->dir = dir; 2111c7850f9SSasha Levin fid->is_dir = 1; 2125f900f6dSSasha Levin } else if (perm & P9_DMSYMLINK) { 2135f900f6dSSasha Levin if (symlink(ext, full_path) < 0) 2145f900f6dSSasha Levin goto err_out; 2155f900f6dSSasha Levin } else if (perm & P9_DMLINK) { 2165f900f6dSSasha Levin int ext_fid = atoi(ext); 2175f900f6dSSasha Levin 2185f900f6dSSasha Levin if (link(p9dev->fids[ext_fid].abs_path, full_path) < 0) 2195f900f6dSSasha Levin goto err_out; 2201c7850f9SSasha Levin } else { 2214bc9734aSAneesh Kumar K.V fd = open(full_path, omode2uflags(mode) | O_CREAT, 0777); 2224bc9734aSAneesh Kumar K.V if (fd < 0) 2234bc9734aSAneesh Kumar K.V goto err_out; 2244bc9734aSAneesh Kumar K.V close_fid(p9dev, fid_val); 2254bc9734aSAneesh Kumar K.V fid->fd = fd; 2261c7850f9SSasha Levin } 2274bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 2286c8ca053SAneesh Kumar K.V goto err_out; 2291c7850f9SSasha Levin 2304bc9734aSAneesh Kumar K.V sprintf(fid->path, "%s/%s", fid->path, name); 231bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 232bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 233bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 234bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 2355f900f6dSSasha Levin 2365f900f6dSSasha Levin free(name); 2375f900f6dSSasha Levin free(ext); 2386c8ca053SAneesh Kumar K.V return; 2396c8ca053SAneesh Kumar K.V err_out: 2406c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 2415f900f6dSSasha Levin free(name); 2425f900f6dSSasha Levin free(ext); 243ead43b01SAneesh Kumar K.V return; 2441c7850f9SSasha Levin } 2451c7850f9SSasha Levin 246ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 247af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2481c7850f9SSasha Levin { 249af045e53SAneesh Kumar K.V u8 i; 250bfc15268SAneesh Kumar K.V u16 nwqid; 251bfc15268SAneesh Kumar K.V char *str; 252bfc15268SAneesh Kumar K.V u16 nwname; 253bfc15268SAneesh Kumar K.V u32 fid_val; 254bfc15268SAneesh Kumar K.V u32 newfid_val; 255bfc15268SAneesh Kumar K.V struct p9_qid wqid; 256bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 2575f900f6dSSasha Levin int ret; 2581c7850f9SSasha Levin 259bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 260bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[newfid_val]; 2611c7850f9SSasha Levin 262bfc15268SAneesh Kumar K.V nwqid = 0; 263bfc15268SAneesh Kumar K.V if (nwname) { 264bfc15268SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[fid_val]; 265bfc15268SAneesh Kumar K.V 266bfc15268SAneesh Kumar K.V /* skip the space for count */ 267bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 268bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 269bfc15268SAneesh Kumar K.V struct stat st; 2701c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 2711c7850f9SSasha Levin char full_path[PATH_MAX]; 272bfc15268SAneesh Kumar K.V 273bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 2741c7850f9SSasha Levin 2751c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 276bfc15268SAneesh Kumar K.V sprintf(tmp, "%s/%.*s", 277bfc15268SAneesh Kumar K.V fid->path, (int)strlen(str), str); 2785f900f6dSSasha Levin 2795f900f6dSSasha Levin ret = lstat(rel_to_abs(p9dev, tmp, full_path), &st); 2805f900f6dSSasha Levin if (ret < 0) 2816c8ca053SAneesh Kumar K.V goto err_out; 2821c7850f9SSasha Levin 283bfc15268SAneesh Kumar K.V st2qid(&st, &wqid); 2841c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 2851c7850f9SSasha Levin strcpy(new_fid->path, tmp); 286bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 287bfc15268SAneesh Kumar K.V nwqid++; 288bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 2891c7850f9SSasha Levin } 2901c7850f9SSasha Levin } else { 291bfc15268SAneesh Kumar K.V /* 292bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 293bfc15268SAneesh Kumar K.V */ 294bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 295bfc15268SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[fid_val].is_dir; 296bfc15268SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[fid_val].path); 297bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 2981c7850f9SSasha Levin } 299bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 300bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 301bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 302bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3036c8ca053SAneesh Kumar K.V return; 3046c8ca053SAneesh Kumar K.V err_out: 3056c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 306ead43b01SAneesh Kumar K.V return; 3071c7850f9SSasha Levin } 3081c7850f9SSasha Levin 309ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 310af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3111c7850f9SSasha Levin { 312af045e53SAneesh Kumar K.V u32 i; 313bfc15268SAneesh Kumar K.V u32 fid_val; 314bfc15268SAneesh Kumar K.V u32 afid; 315bfc15268SAneesh Kumar K.V char *uname; 316bfc15268SAneesh Kumar K.V char *aname; 3171c7850f9SSasha Levin struct stat st; 318bfc15268SAneesh Kumar K.V struct p9_qid qid; 3191c7850f9SSasha Levin struct p9_fid *fid; 320bfc15268SAneesh Kumar K.V 321bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddss", &fid_val, &afid, &uname, &aname); 3221c7850f9SSasha Levin 3231c7850f9SSasha Levin /* Reset everything */ 3241c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 325b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 3261c7850f9SSasha Levin 32730204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 3286c8ca053SAneesh Kumar K.V goto err_out; 3291c7850f9SSasha Levin 330bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 3311c7850f9SSasha Levin 332bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 333bfc15268SAneesh Kumar K.V fid->fid = fid_val; 3341c7850f9SSasha Levin fid->is_dir = 1; 3351c7850f9SSasha Levin strcpy(fid->path, "/"); 3361c7850f9SSasha Levin 337bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 338bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 339bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3405f900f6dSSasha Levin free(uname); 3415f900f6dSSasha Levin free(aname); 3426c8ca053SAneesh Kumar K.V return; 3436c8ca053SAneesh Kumar K.V err_out: 3445f900f6dSSasha Levin free(uname); 3455f900f6dSSasha Levin free(aname); 3466c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 347ead43b01SAneesh Kumar K.V return; 3481c7850f9SSasha Levin } 3491c7850f9SSasha Levin 3505f900f6dSSasha Levin static void virtio_p9_free_stat(struct p9_wstat *wstat) 3515f900f6dSSasha Levin { 3525f900f6dSSasha Levin free(wstat->extension); 3535f900f6dSSasha Levin free(wstat->name); 3545f900f6dSSasha Levin } 3555f900f6dSSasha Levin 356bfc15268SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, 357bfc15268SAneesh Kumar K.V struct stat *st, struct p9_wstat *wstat) 3581c7850f9SSasha Levin { 359bfc15268SAneesh Kumar K.V wstat->type = 0; 360bfc15268SAneesh Kumar K.V wstat->dev = 0; 361bfc15268SAneesh Kumar K.V st2qid(st, &wstat->qid); 362bfc15268SAneesh Kumar K.V wstat->mode = st->st_mode; 363bfc15268SAneesh Kumar K.V wstat->length = st->st_size; 3641c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) { 365bfc15268SAneesh Kumar K.V wstat->length = 0; 366bfc15268SAneesh Kumar K.V wstat->mode |= P9_DMDIR; 3671c7850f9SSasha Levin } 3685f900f6dSSasha Levin if (S_ISLNK(st->st_mode)) { 3695f900f6dSSasha Levin char tmp[PATH_MAX] = {0}, full_path[PATH_MAX] = {0}; 3705f900f6dSSasha Levin 3715f900f6dSSasha Levin rel_to_abs(p9dev, name, full_path); 3725f900f6dSSasha Levin 3735f900f6dSSasha Levin if (readlink(full_path, tmp, PATH_MAX) > 0) 3745f900f6dSSasha Levin wstat->extension = strdup(tmp); 3755f900f6dSSasha Levin wstat->mode |= P9_DMSYMLINK; 3765f900f6dSSasha Levin } else { 3775f900f6dSSasha Levin wstat->extension = NULL; 3785f900f6dSSasha Levin } 3791c7850f9SSasha Levin 380bfc15268SAneesh Kumar K.V wstat->atime = st->st_atime; 381bfc15268SAneesh Kumar K.V wstat->mtime = st->st_mtime; 3821c7850f9SSasha Levin 383bfc15268SAneesh Kumar K.V wstat->name = strdup(name); 384bfc15268SAneesh Kumar K.V wstat->uid = NULL; 385bfc15268SAneesh Kumar K.V wstat->gid = NULL; 386bfc15268SAneesh Kumar K.V wstat->muid = NULL; 3875f900f6dSSasha Levin wstat->n_uid = wstat->n_gid = wstat->n_muid = 0; 3881c7850f9SSasha Levin 3895f900f6dSSasha Levin /* 3905f900f6dSSasha Levin * NOTE: size shouldn't include its own length 3915f900f6dSSasha Levin * size[2] type[2] dev[4] qid[13] 3925f900f6dSSasha Levin * mode[4] atime[4] mtime[4] length[8] 3935f900f6dSSasha Levin * name[s] uid[s] gid[s] muid[s] 3945f900f6dSSasha Levin * ext[s] uid[4] gid[4] muid[4] 3955f900f6dSSasha Levin */ 3965f900f6dSSasha Levin wstat->size = 2+4+13+4+4+4+8+2+2+2+2+2+4+4+4; 397bfc15268SAneesh Kumar K.V if (wstat->name) 398bfc15268SAneesh Kumar K.V wstat->size += strlen(wstat->name); 3995f900f6dSSasha Levin if (wstat->extension) 4005f900f6dSSasha Levin wstat->size += strlen(wstat->extension); 4011c7850f9SSasha Levin } 4021c7850f9SSasha Levin 403ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 404af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4051c7850f9SSasha Levin { 406bfc15268SAneesh Kumar K.V u64 offset; 407bfc15268SAneesh Kumar K.V u32 fid_val; 408bfc15268SAneesh Kumar K.V u32 count, rcount; 4091c7850f9SSasha Levin struct stat st; 410bfc15268SAneesh Kumar K.V struct p9_fid *fid; 411bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 4121c7850f9SSasha Levin 413bfc15268SAneesh Kumar K.V rcount = 0; 414bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 415bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 4161c7850f9SSasha Levin if (fid->is_dir) { 4171c7850f9SSasha Levin /* If reading a dir, fill the buffer with p9_stat entries */ 4181c7850f9SSasha Levin char full_path[PATH_MAX]; 419bfc15268SAneesh Kumar K.V struct dirent *cur = readdir(fid->dir); 4201c7850f9SSasha Levin 421bfc15268SAneesh Kumar K.V /* Skip the space for writing count */ 422bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 4231c7850f9SSasha Levin while (cur) { 4241c7850f9SSasha Levin u32 read; 4251c7850f9SSasha Levin 42630204a77SAneesh Kumar K.V lstat(rel_to_abs(p9dev, cur->d_name, full_path), &st); 427bfc15268SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, cur->d_name, &st, &wstat); 428bfc15268SAneesh Kumar K.V 429bfc15268SAneesh Kumar K.V read = pdu->write_offset; 430bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "S", &wstat); 431bfc15268SAneesh Kumar K.V rcount += pdu->write_offset - read; 4325f900f6dSSasha Levin virtio_p9_free_stat(&wstat); 433bfc15268SAneesh Kumar K.V 4341c7850f9SSasha Levin cur = readdir(fid->dir); 4351c7850f9SSasha Levin } 4361c7850f9SSasha Levin } else { 43750c479e0SAneesh Kumar K.V u16 iov_cnt; 43850c479e0SAneesh Kumar K.V void *iov_base; 43950c479e0SAneesh Kumar K.V size_t iov_len; 44050c479e0SAneesh Kumar K.V 44150c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 44250c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 44350c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 44450c479e0SAneesh Kumar K.V 445af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 446af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 4476b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 448bfc15268SAneesh Kumar K.V count, 4496b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 450bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 451bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 452bfc15268SAneesh Kumar K.V if (rcount > count) 453bfc15268SAneesh Kumar K.V rcount = count; 454bfc15268SAneesh Kumar K.V /* 455bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 456bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 457bfc15268SAneesh Kumar K.V */ 45850c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 45950c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 46050c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 461bfc15268SAneesh Kumar K.V } 462bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 463bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 464bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 465bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4661c7850f9SSasha Levin 467ead43b01SAneesh Kumar K.V return; 4681c7850f9SSasha Levin } 4691c7850f9SSasha Levin 470ead43b01SAneesh Kumar K.V static void virtio_p9_stat(struct p9_dev *p9dev, 471af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4721c7850f9SSasha Levin { 473bfc15268SAneesh Kumar K.V u32 fid_val; 474af045e53SAneesh Kumar K.V struct stat st; 475bfc15268SAneesh Kumar K.V struct p9_fid *fid; 476bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 4771c7850f9SSasha Levin 478bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 479bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 48030204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 4816c8ca053SAneesh Kumar K.V goto err_out; 4821c7850f9SSasha Levin 483bfc15268SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, fid->path, &st, &wstat); 4841c7850f9SSasha Levin 485bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "wS", 0, &wstat); 486bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 4875f900f6dSSasha Levin virtio_p9_free_stat(&wstat); 488bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 489ead43b01SAneesh Kumar K.V return; 4906c8ca053SAneesh Kumar K.V err_out: 4916c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 4926c8ca053SAneesh Kumar K.V return; 4931c7850f9SSasha Levin } 4941c7850f9SSasha Levin 495ead43b01SAneesh Kumar K.V static void virtio_p9_wstat(struct p9_dev *p9dev, 496af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4971c7850f9SSasha Levin { 498aec426f0SCyrill Gorcunov int res = 0; 499bfc15268SAneesh Kumar K.V u32 fid_val; 500bfc15268SAneesh Kumar K.V u16 unused; 501bfc15268SAneesh Kumar K.V struct p9_fid *fid; 502bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 503af045e53SAneesh Kumar K.V 504bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dwS", &fid_val, &unused, &wstat); 505bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 5061c7850f9SSasha Levin 5074bc9734aSAneesh Kumar K.V if (wstat.length != -1UL) { 508c6fb59c4SAneesh Kumar K.V res = truncate(fid->abs_path, wstat.length); 5094bc9734aSAneesh Kumar K.V if (res < 0) 5104bc9734aSAneesh Kumar K.V goto err_out; 5114bc9734aSAneesh Kumar K.V } 5124bc9734aSAneesh Kumar K.V if (wstat.mode != -1U) { 5134bc9734aSAneesh Kumar K.V res = chmod(fid->abs_path, wstat.mode & 0xFFFF); 5144bc9734aSAneesh Kumar K.V if (res < 0) 5154bc9734aSAneesh Kumar K.V goto err_out; 5164bc9734aSAneesh Kumar K.V } 517bfc15268SAneesh Kumar K.V if (strlen(wstat.name) > 0) { 5181c7850f9SSasha Levin char new_name[PATH_MAX] = {0}; 5191c7850f9SSasha Levin char full_path[PATH_MAX]; 5201c7850f9SSasha Levin char *last_dir = strrchr(fid->path, '/'); 5211c7850f9SSasha Levin 5221c7850f9SSasha Levin /* We need to get the full file name out of twstat->name */ 5231c7850f9SSasha Levin if (last_dir) 5241c7850f9SSasha Levin strncpy(new_name, fid->path, last_dir - fid->path + 1); 5251c7850f9SSasha Levin 526bfc15268SAneesh Kumar K.V memcpy(new_name + strlen(new_name), 527bfc15268SAneesh Kumar K.V wstat.name, strlen(wstat.name)); 5281c7850f9SSasha Levin 5291c7850f9SSasha Levin /* fid is reused for the new file */ 5304bc9734aSAneesh Kumar K.V res = rename(fid->abs_path, 5314bc9734aSAneesh Kumar K.V rel_to_abs(p9dev, new_name, full_path)); 5324bc9734aSAneesh Kumar K.V if (res < 0) 5334bc9734aSAneesh Kumar K.V goto err_out; 5341c7850f9SSasha Levin sprintf(fid->path, "%s", new_name); 5351c7850f9SSasha Levin } 5361c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 537bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 538ead43b01SAneesh Kumar K.V return; 5394bc9734aSAneesh Kumar K.V err_out: 5404bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5414bc9734aSAneesh Kumar K.V return; 5421c7850f9SSasha Levin } 5431c7850f9SSasha Levin 544ead43b01SAneesh Kumar K.V static void virtio_p9_remove(struct p9_dev *p9dev, 545af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5461c7850f9SSasha Levin { 5474bc9734aSAneesh Kumar K.V int res; 548bfc15268SAneesh Kumar K.V u32 fid_val; 549bfc15268SAneesh Kumar K.V struct p9_fid *fid; 5501c7850f9SSasha Levin 551bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 552bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 553bfc15268SAneesh Kumar K.V close_fid(p9dev, fid_val); 5541c7850f9SSasha Levin if (fid->is_dir) 5554bc9734aSAneesh Kumar K.V res = rmdir(fid->abs_path); 5561c7850f9SSasha Levin else 5574bc9734aSAneesh Kumar K.V res = unlink(fid->abs_path); 5584bc9734aSAneesh Kumar K.V if (res < 0) 5594bc9734aSAneesh Kumar K.V goto err_out; 5601c7850f9SSasha Levin 5611c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 562bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 563ead43b01SAneesh Kumar K.V return; 5644bc9734aSAneesh Kumar K.V err_out: 5654bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5664bc9734aSAneesh Kumar K.V return; 5671c7850f9SSasha Levin } 5681c7850f9SSasha Levin 569ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 570af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5711c7850f9SSasha Levin { 5724bc9734aSAneesh Kumar K.V 573bfc15268SAneesh Kumar K.V u64 offset; 574bfc15268SAneesh Kumar K.V u32 fid_val; 5754bc9734aSAneesh Kumar K.V u32 count; 5764bc9734aSAneesh Kumar K.V ssize_t res; 57750c479e0SAneesh Kumar K.V u16 iov_cnt; 57850c479e0SAneesh Kumar K.V void *iov_base; 57950c479e0SAneesh Kumar K.V size_t iov_len; 580bfc15268SAneesh Kumar K.V struct p9_fid *fid; 581b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 582b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 5831c7850f9SSasha Levin 584bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 585bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 586af045e53SAneesh Kumar K.V 58750c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 58850c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 58950c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 59050c479e0SAneesh Kumar K.V 591bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 592b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 593b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 594bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 5956b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 5964bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 59750c479e0SAneesh Kumar K.V /* 59850c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 59950c479e0SAneesh Kumar K.V * pdu_readf works correctly. 60050c479e0SAneesh Kumar K.V */ 60150c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 60250c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 60350c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 6044bc9734aSAneesh Kumar K.V if (res < 0) 6054bc9734aSAneesh Kumar K.V goto err_out; 6064bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 607bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 608bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 609ead43b01SAneesh Kumar K.V return; 6104bc9734aSAneesh Kumar K.V err_out: 6114bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6124bc9734aSAneesh Kumar K.V return; 6131c7850f9SSasha Levin } 6141c7850f9SSasha Levin 615ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 616af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 617b4422bf3SAneesh Kumar K.V 618b4422bf3SAneesh Kumar K.V static p9_handler *virtio_9p_handler [] = { 619b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 620b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 621b4422bf3SAneesh Kumar K.V [P9_TSTAT] = virtio_p9_stat, 622b4422bf3SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 623b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 624b4422bf3SAneesh Kumar K.V [P9_TOPEN] = virtio_p9_open, 625b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 626b4422bf3SAneesh Kumar K.V [P9_TCREATE] = virtio_p9_create, 627b4422bf3SAneesh Kumar K.V [P9_TWSTAT] = virtio_p9_wstat, 628b4422bf3SAneesh Kumar K.V [P9_TREMOVE] = virtio_p9_remove, 629b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 630b4422bf3SAneesh Kumar K.V }; 631b4422bf3SAneesh Kumar K.V 632af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 633af045e53SAneesh Kumar K.V { 634af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 635af045e53SAneesh Kumar K.V if (!pdu) 636af045e53SAneesh Kumar K.V return NULL; 637af045e53SAneesh Kumar K.V 638bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 639bfc15268SAneesh Kumar K.V pdu->read_offset = VIRTIO_P9_HDR_LEN; 640bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 641af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 642af045e53SAneesh Kumar K.V pdu->out_iov, 643af045e53SAneesh Kumar K.V &pdu->in_iov_cnt, 644af045e53SAneesh Kumar K.V &pdu->out_iov_cnt); 645af045e53SAneesh Kumar K.V return pdu; 646af045e53SAneesh Kumar K.V } 647af045e53SAneesh Kumar K.V 648af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 649af045e53SAneesh Kumar K.V { 650af045e53SAneesh Kumar K.V struct p9_msg *msg; 651af045e53SAneesh Kumar K.V /* 652af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 653af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 654af045e53SAneesh Kumar K.V */ 655af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 656af045e53SAneesh Kumar K.V return msg->cmd; 657af045e53SAneesh Kumar K.V } 658af045e53SAneesh Kumar K.V 65997b408afSAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 66097b408afSAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 66197b408afSAneesh Kumar K.V { 66297b408afSAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 66397b408afSAneesh Kumar K.V } 66497b408afSAneesh Kumar K.V 665b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 6661c7850f9SSasha Levin { 667af045e53SAneesh Kumar K.V u8 cmd; 668b4422bf3SAneesh Kumar K.V u32 len = 0; 669b4422bf3SAneesh Kumar K.V p9_handler *handler; 670b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 671af045e53SAneesh Kumar K.V struct virt_queue *vq; 672af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 6731c7850f9SSasha Levin 674b4422bf3SAneesh Kumar K.V vq = job->vq; 675b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 6761c7850f9SSasha Levin 677af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 678af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 679af045e53SAneesh Kumar K.V 680af045e53SAneesh Kumar K.V if (cmd >= ARRAY_SIZE(virtio_9p_handler) || 681dd78d9eaSAneesh Kumar K.V !virtio_9p_handler[cmd]) 68297b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 683dd78d9eaSAneesh Kumar K.V else 684af045e53SAneesh Kumar K.V handler = virtio_9p_handler[cmd]; 685af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 686af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 687af045e53SAneesh Kumar K.V free(p9pdu); 6881c7850f9SSasha Levin return true; 6891c7850f9SSasha Levin } 6901c7850f9SSasha Levin 6911c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 6921c7850f9SSasha Levin { 693b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 694b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 695b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 6961c7850f9SSasha Levin 6971c7850f9SSasha Levin while (virt_queue__available(vq)) { 698b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 699*c7838fbdSSasha Levin virtio_pci__signal_vq(kvm, &p9dev->vpci, vq - p9dev->vqs); 7001c7850f9SSasha Levin } 7011c7850f9SSasha Levin } 7021c7850f9SSasha Levin 70360eb42d5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 70460eb42d5SSasha Levin { 70560eb42d5SSasha Levin struct p9_dev_job *job = param; 70660eb42d5SSasha Levin 707df0c7f57SSasha Levin thread_pool__do_job(&job->job_id); 70860eb42d5SSasha Levin } 70960eb42d5SSasha Levin 710*c7838fbdSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 7111c7850f9SSasha Levin { 712*c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 7131c7850f9SSasha Levin 714*c7838fbdSSasha Levin ((u8 *)(p9dev->config))[offset] = data; 715*c7838fbdSSasha Levin } 7161c7850f9SSasha Levin 717*c7838fbdSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 718*c7838fbdSSasha Levin { 719*c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 720*c7838fbdSSasha Levin 721*c7838fbdSSasha Levin return ((u8 *)(p9dev->config))[offset]; 722*c7838fbdSSasha Levin } 723*c7838fbdSSasha Levin 724*c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 725*c7838fbdSSasha Levin { 726*c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 727*c7838fbdSSasha Levin } 728*c7838fbdSSasha Levin 729*c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 730*c7838fbdSSasha Levin { 731*c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 732*c7838fbdSSasha Levin 733*c7838fbdSSasha Levin p9dev->features = features; 734*c7838fbdSSasha Levin } 735*c7838fbdSSasha Levin 736*c7838fbdSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 737*c7838fbdSSasha Levin { 738*c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 739b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 740b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 741*c7838fbdSSasha Levin void *p; 742*c7838fbdSSasha Levin struct ioevent ioevent; 7431c7850f9SSasha Levin 744e59662b3SSasha Levin compat__remove_message(p9dev->compat_id); 745e59662b3SSasha Levin 746*c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 747*c7838fbdSSasha Levin queue->pfn = pfn; 7481c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 749*c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 7501c7850f9SSasha Levin 751*c7838fbdSSasha Levin vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN); 7521c7850f9SSasha Levin 753b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 754b4422bf3SAneesh Kumar K.V .vq = queue, 755b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 756b4422bf3SAneesh Kumar K.V }; 757df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 75860eb42d5SSasha Levin 75960eb42d5SSasha Levin ioevent = (struct ioevent) { 760*c7838fbdSSasha Levin .io_addr = p9dev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 76160eb42d5SSasha Levin .io_len = sizeof(u16), 76260eb42d5SSasha Levin .fn = ioevent_callback, 763*c7838fbdSSasha Levin .fn_ptr = &p9dev->jobs[vq], 764*c7838fbdSSasha Levin .datamatch = vq, 76560eb42d5SSasha Levin .fn_kvm = kvm, 76660eb42d5SSasha Levin .fd = eventfd(0, 0), 76760eb42d5SSasha Levin }; 76860eb42d5SSasha Levin 76960eb42d5SSasha Levin ioeventfd__add_event(&ioevent); 77060eb42d5SSasha Levin 771*c7838fbdSSasha Levin return 0; 7721c7850f9SSasha Levin } 7731c7850f9SSasha Levin 774*c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 775*c7838fbdSSasha Levin { 776*c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 7771c7850f9SSasha Levin 778*c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 779*c7838fbdSSasha Levin 780*c7838fbdSSasha Levin return 0; 781*c7838fbdSSasha Levin } 782*c7838fbdSSasha Levin 783*c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 784*c7838fbdSSasha Levin { 785*c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 786*c7838fbdSSasha Levin 787*c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 788*c7838fbdSSasha Levin } 789*c7838fbdSSasha Levin 790*c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 791*c7838fbdSSasha Levin { 792*c7838fbdSSasha Levin return VIRTQUEUE_NUM; 793*c7838fbdSSasha Levin } 794*c7838fbdSSasha Levin 795*c7838fbdSSasha Levin int virtio_9p__init(struct kvm *kvm) 7961c7850f9SSasha Levin { 797b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 798*c7838fbdSSasha Levin 799*c7838fbdSSasha Levin list_for_each_entry(p9dev, &devs, list) { 800*c7838fbdSSasha Levin virtio_pci__init(kvm, &p9dev->vpci, p9dev, PCI_DEVICE_ID_VIRTIO_P9, VIRTIO_ID_9P); 801*c7838fbdSSasha Levin p9dev->vpci.ops = (struct virtio_pci_ops) { 802*c7838fbdSSasha Levin .set_config = set_config, 803*c7838fbdSSasha Levin .get_config = get_config, 804*c7838fbdSSasha Levin .get_host_features = get_host_features, 805*c7838fbdSSasha Levin .set_guest_features = set_guest_features, 806*c7838fbdSSasha Levin .init_vq = init_vq, 807*c7838fbdSSasha Levin .notify_vq = notify_vq, 808*c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 809*c7838fbdSSasha Levin .get_size_vq = get_size_vq, 810*c7838fbdSSasha Levin }; 811*c7838fbdSSasha Levin } 812*c7838fbdSSasha Levin 813*c7838fbdSSasha Levin return 0; 814*c7838fbdSSasha Levin } 815*c7838fbdSSasha Levin 816*c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 817*c7838fbdSSasha Levin { 818*c7838fbdSSasha Levin struct p9_dev *p9dev; 81954f6802dSPekka Enberg u32 i, root_len; 82054f6802dSPekka Enberg int err = 0; 8211c7850f9SSasha Levin 822b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 823b4422bf3SAneesh Kumar K.V if (!p9dev) 82454f6802dSPekka Enberg return -ENOMEM; 82554f6802dSPekka Enberg 826b4422bf3SAneesh Kumar K.V if (!tag_name) 827b4422bf3SAneesh Kumar K.V tag_name = VIRTIO_P9_DEFAULT_TAG; 82854f6802dSPekka Enberg 829b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 83054f6802dSPekka Enberg if (p9dev->config == NULL) { 83154f6802dSPekka Enberg err = -ENOMEM; 832b4422bf3SAneesh Kumar K.V goto free_p9dev; 83354f6802dSPekka Enberg } 8341c7850f9SSasha Levin 835b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 8361c7850f9SSasha Levin root_len = strlen(root); 8371c7850f9SSasha Levin /* 8381c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 8391c7850f9SSasha Levin * absolute path of an fid without playing with strings. 8401c7850f9SSasha Levin */ 8411c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 842b4422bf3SAneesh Kumar K.V strcpy(p9dev->fids[i].abs_path, root); 843b4422bf3SAneesh Kumar K.V p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len; 8441c7850f9SSasha Levin } 845b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 84654f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 84754f6802dSPekka Enberg err = -EINVAL; 848b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 84954f6802dSPekka Enberg } 8501c7850f9SSasha Levin 851*c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 8521c7850f9SSasha Levin 853*c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 854b4422bf3SAneesh Kumar K.V 855e59662b3SSasha Levin p9dev->compat_id = compat__add_message("virtio-9p device was not detected", 856e59662b3SSasha Levin "While you have requested a virtio-9p device, " 857e59662b3SSasha Levin "the guest kernel didn't seem to detect it.\n" 858e59662b3SSasha Levin "Please make sure that the kernel was compiled" 859e59662b3SSasha Levin "with CONFIG_NET_9P_VIRTIO."); 860e59662b3SSasha Levin 86154f6802dSPekka Enberg return err; 86254f6802dSPekka Enberg 863b4422bf3SAneesh Kumar K.V free_p9dev_config: 864b4422bf3SAneesh Kumar K.V free(p9dev->config); 865b4422bf3SAneesh Kumar K.V free_p9dev: 866b4422bf3SAneesh Kumar K.V free(p9dev); 86754f6802dSPekka Enberg return err; 8681c7850f9SSasha Levin } 869