xref: /kvmtool/virtio/9p.c (revision 3d62dea656058a6bc9248124521c6fc81efc6474)
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
241c7850f9SSasha Levin #define	VIRTIO_P9_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"
281c7850f9SSasha Levin 
291c7850f9SSasha Levin struct p9_msg {
301c7850f9SSasha Levin 	u32			size;
311c7850f9SSasha Levin 	u8			cmd;
321c7850f9SSasha Levin 	u16			tag;
331c7850f9SSasha Levin 	u8			msg[0];
341c7850f9SSasha Levin } __attribute__((packed));
351c7850f9SSasha Levin 
361c7850f9SSasha Levin struct p9_fid {
371c7850f9SSasha Levin 	u32			fid;
381c7850f9SSasha Levin 	u8			is_dir;
391c7850f9SSasha Levin 	char			abs_path[PATH_MAX];
401c7850f9SSasha Levin 	char			*path;
411c7850f9SSasha Levin 	DIR			*dir;
421c7850f9SSasha Levin 	int			fd;
431c7850f9SSasha Levin };
441c7850f9SSasha Levin 
451c7850f9SSasha Levin static struct pci_device_header virtio_p9_pci_device = {
461c7850f9SSasha Levin 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
471c7850f9SSasha Levin 	.device_id		= PCI_DEVICE_ID_VIRTIO_P9,
481c7850f9SSasha Levin 	.header_type		= PCI_HEADER_TYPE_NORMAL,
491c7850f9SSasha Levin 	.revision_id		= 0,
501c7850f9SSasha Levin 	.class			= 0x010000,
511c7850f9SSasha Levin 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
521c7850f9SSasha Levin 	.subsys_id		= VIRTIO_ID_9P,
531c7850f9SSasha Levin 	.bar[0]			= IOPORT_VIRTIO_P9 | PCI_BASE_ADDRESS_SPACE_IO,
541c7850f9SSasha Levin };
551c7850f9SSasha Levin 
561c7850f9SSasha Levin struct p9_dev {
571c7850f9SSasha Levin 	u8			status;
581c7850f9SSasha Levin 	u8			isr;
591c7850f9SSasha Levin 	u16			config_vector;
601c7850f9SSasha Levin 	u32			features;
611c7850f9SSasha Levin 	struct virtio_9p_config	*config;
621c7850f9SSasha Levin 
631c7850f9SSasha Levin 	/* virtio queue */
641c7850f9SSasha Levin 	u16			queue_selector;
651c7850f9SSasha Levin 	struct virt_queue	vqs[NUM_VIRT_QUEUES];
661c7850f9SSasha Levin 	void			*jobs[NUM_VIRT_QUEUES];
671c7850f9SSasha Levin 
681c7850f9SSasha Levin 	struct p9_fid		fids[VIRTIO_P9_MAX_FID];
691c7850f9SSasha Levin 	char			root_dir[PATH_MAX];
701c7850f9SSasha Levin };
711c7850f9SSasha Levin 
721c7850f9SSasha Levin static struct p9_dev p9dev;
731c7850f9SSasha Levin 
741c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */
751c7850f9SSasha Levin static const char *rel_to_abs(const char *path, char *abs_path)
761c7850f9SSasha Levin {
771c7850f9SSasha Levin 	sprintf(abs_path, "%s/%s", p9dev.root_dir, path);
781c7850f9SSasha Levin 
791c7850f9SSasha Levin 	return abs_path;
801c7850f9SSasha Levin }
811c7850f9SSasha Levin 
821c7850f9SSasha Levin static bool virtio_p9_dev_in(void *data, unsigned long offset, int size, u32 count)
831c7850f9SSasha Levin {
841c7850f9SSasha Levin 	u8 *config_space = (u8 *) p9dev.config;
851c7850f9SSasha Levin 
861c7850f9SSasha Levin 	if (size != 1 || count != 1)
871c7850f9SSasha Levin 		return false;
881c7850f9SSasha Levin 
891c7850f9SSasha Levin 	ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]);
901c7850f9SSasha Levin 
911c7850f9SSasha Levin 	return true;
921c7850f9SSasha Levin }
931c7850f9SSasha Levin 
94*3d62dea6SSasha Levin static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
951c7850f9SSasha Levin {
961c7850f9SSasha Levin 	unsigned long offset;
971c7850f9SSasha Levin 	bool ret = true;
981c7850f9SSasha Levin 
991c7850f9SSasha Levin 	offset = port - IOPORT_VIRTIO_P9;
1001c7850f9SSasha Levin 
1011c7850f9SSasha Levin 	switch (offset) {
1021c7850f9SSasha Levin 	case VIRTIO_PCI_HOST_FEATURES:
1031c7850f9SSasha Levin 		ioport__write32(data, p9dev.features);
1041c7850f9SSasha Levin 		ret = true;
1051c7850f9SSasha Levin 		break;
1061c7850f9SSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
1071c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
1081c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY:
1091c7850f9SSasha Levin 		ret = false;
1101c7850f9SSasha Levin 		break;
1111c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
1121c7850f9SSasha Levin 		ioport__write32(data, p9dev.vqs[p9dev.queue_selector].pfn);
1131c7850f9SSasha Levin 		break;
1141c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_NUM:
1151c7850f9SSasha Levin 		ioport__write16(data, VIRTIO_P9_QUEUE_SIZE);
1161c7850f9SSasha Levin 		break;
1171c7850f9SSasha Levin 	case VIRTIO_PCI_STATUS:
1181c7850f9SSasha Levin 		ioport__write8(data, p9dev.status);
1191c7850f9SSasha Levin 		break;
1201c7850f9SSasha Levin 	case VIRTIO_PCI_ISR:
1211c7850f9SSasha Levin 		ioport__write8(data, p9dev.isr);
1221c7850f9SSasha Levin 		kvm__irq_line(kvm, virtio_p9_pci_device.irq_line, VIRTIO_IRQ_LOW);
1231c7850f9SSasha Levin 		p9dev.isr = VIRTIO_IRQ_LOW;
1241c7850f9SSasha Levin 		break;
1251c7850f9SSasha Levin 	default:
1261c7850f9SSasha Levin 		ret = virtio_p9_dev_in(data, offset, size, count);
1271c7850f9SSasha Levin 		break;
1281c7850f9SSasha Levin 	};
1291c7850f9SSasha Levin 
1301c7850f9SSasha Levin 	return ret;
1311c7850f9SSasha Levin }
1321c7850f9SSasha Levin 
1331c7850f9SSasha Levin static int omode2uflags(u8 mode)
1341c7850f9SSasha Levin {
1351c7850f9SSasha Levin 	int ret = 0;
1361c7850f9SSasha Levin 
1371c7850f9SSasha Levin 	/* Basic open modes are same as uflags */
1381c7850f9SSasha Levin 	ret = mode & 3;
1391c7850f9SSasha Levin 
1401c7850f9SSasha Levin 	/* Everything else is different */
1411c7850f9SSasha Levin 	if (mode & P9_OTRUNC)
1421c7850f9SSasha Levin 		ret |= O_TRUNC;
1431c7850f9SSasha Levin 
1441c7850f9SSasha Levin 	if (mode & P9_OAPPEND)
1451c7850f9SSasha Levin 		ret |= O_APPEND;
1461c7850f9SSasha Levin 
1471c7850f9SSasha Levin 	if (mode & P9_OEXCL)
1481c7850f9SSasha Levin 		ret |= O_EXCL;
1491c7850f9SSasha Levin 
1501c7850f9SSasha Levin 	return ret;
1511c7850f9SSasha Levin }
1521c7850f9SSasha Levin 
1531c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid)
1541c7850f9SSasha Levin {
1551c7850f9SSasha Levin 	*qid = (struct p9_qid) {
1561c7850f9SSasha Levin 		.path		= st->st_ino,
1571c7850f9SSasha Levin 		.version	= st->st_mtime,
1581c7850f9SSasha Levin 	};
1591c7850f9SSasha Levin 
1601c7850f9SSasha Levin 	if (S_ISDIR(st->st_mode))
1611c7850f9SSasha Levin 		qid->type	|= P9_QTDIR;
1621c7850f9SSasha Levin }
1631c7850f9SSasha Levin 
1641c7850f9SSasha Levin static void close_fid(u32 fid)
1651c7850f9SSasha Levin {
1661c7850f9SSasha Levin 	if (p9dev.fids[fid].fd > 0) {
1671c7850f9SSasha Levin 		close(p9dev.fids[fid].fd);
1681c7850f9SSasha Levin 		p9dev.fids[fid].fd = -1;
1691c7850f9SSasha Levin 	}
1701c7850f9SSasha Levin 	if (p9dev.fids[fid].dir) {
1711c7850f9SSasha Levin 		closedir(p9dev.fids[fid].dir);
1721c7850f9SSasha Levin 		p9dev.fids[fid].dir = NULL;
1731c7850f9SSasha Levin 	}
1741c7850f9SSasha Levin }
1751c7850f9SSasha Levin 
1761c7850f9SSasha Levin static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag)
1771c7850f9SSasha Levin {
1781c7850f9SSasha Levin 	*msg = (struct p9_msg) {
1791c7850f9SSasha Levin 		.size	= size,
1801c7850f9SSasha Levin 		.tag	= tag,
1811c7850f9SSasha Levin 		.cmd	= cmd,
1821c7850f9SSasha Levin 	};
1831c7850f9SSasha Levin }
1841c7850f9SSasha Levin 
1851c7850f9SSasha Levin static bool virtio_p9_version(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
1861c7850f9SSasha Levin {
1871c7850f9SSasha Levin 	struct p9_msg *outmsg = iov[0].iov_base;
1881c7850f9SSasha Levin 	struct p9_rversion *rversion = (struct p9_rversion *)outmsg->msg;
1891c7850f9SSasha Levin 
1901c7850f9SSasha Levin 	rversion->msize		= 4096;
1911c7850f9SSasha Levin 	rversion->version.len	= strlen(VIRTIO_P9_VERSION);
1921c7850f9SSasha Levin 	memcpy(&rversion->version.str, VIRTIO_P9_VERSION, rversion->version.len);
1931c7850f9SSasha Levin 
1941c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + rversion->version.len + sizeof(u16) + sizeof(u32);
1951c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RVERSION, msg->tag);
1961c7850f9SSasha Levin 
1971c7850f9SSasha Levin 	return true;
1981c7850f9SSasha Levin }
1991c7850f9SSasha Levin 
2001c7850f9SSasha Levin static bool virtio_p9_clunk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
2011c7850f9SSasha Levin {
2021c7850f9SSasha Levin 	struct p9_msg *outmsg = iov[0].iov_base;
2031c7850f9SSasha Levin 	struct p9_tclunk *tclunk = (struct p9_tclunk *)msg->msg;
2041c7850f9SSasha Levin 
2051c7850f9SSasha Levin 	close_fid(tclunk->fid);
2061c7850f9SSasha Levin 
2071c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN;
2081c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RCLUNK, msg->tag);
2091c7850f9SSasha Levin 
2101c7850f9SSasha Levin 	return true;
2111c7850f9SSasha Levin }
2121c7850f9SSasha Levin 
2131c7850f9SSasha Levin static bool virtio_p9_open(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
2141c7850f9SSasha Levin {
2151c7850f9SSasha Levin 	struct p9_msg *outmsg	= iov[0].iov_base;
2161c7850f9SSasha Levin 	struct p9_topen *topen	= (struct p9_topen *)msg->msg;
2171c7850f9SSasha Levin 	struct p9_ropen *ropen	= (struct p9_ropen *)outmsg->msg;
2181c7850f9SSasha Levin 	struct p9_fid *new_fid	= &p9dev.fids[topen->fid];
2191c7850f9SSasha Levin 	struct stat st;
2201c7850f9SSasha Levin 
2211c7850f9SSasha Levin 	if (stat(new_fid->abs_path, &st) < 0)
2221c7850f9SSasha Levin 		return false;
2231c7850f9SSasha Levin 
2241c7850f9SSasha Levin 	st2qid(&st, &ropen->qid);
2251c7850f9SSasha Levin 	ropen->iounit = 0;
2261c7850f9SSasha Levin 
2271c7850f9SSasha Levin 	if (new_fid->is_dir)
2281c7850f9SSasha Levin 		new_fid->dir	= opendir(new_fid->abs_path);
2291c7850f9SSasha Levin 	else
2301c7850f9SSasha Levin 		new_fid->fd	= open(new_fid->abs_path, omode2uflags(topen->mode));
2311c7850f9SSasha Levin 
2321c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(*ropen);
2331c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_ROPEN, msg->tag);
2341c7850f9SSasha Levin 
2351c7850f9SSasha Levin 	return true;
2361c7850f9SSasha Levin }
2371c7850f9SSasha Levin 
2381c7850f9SSasha Levin static bool virtio_p9_create(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
2391c7850f9SSasha Levin {
2401c7850f9SSasha Levin 	struct p9_msg *outmsg		= iov[0].iov_base;
2411c7850f9SSasha Levin 	struct p9_tcreate *tcreate	= (struct p9_tcreate *)msg->msg;
2421c7850f9SSasha Levin 	struct p9_rcreate *rcreate	= (struct p9_rcreate *)outmsg->msg;
2431c7850f9SSasha Levin 	struct p9_fid *fid		= &p9dev.fids[tcreate->fid];
2441c7850f9SSasha Levin 	struct stat st;
2451c7850f9SSasha Levin 	u8 mode;
2461c7850f9SSasha Levin 	u32 perm;
2471c7850f9SSasha Levin 
2481c7850f9SSasha Levin 	rcreate->iounit = 0;
2491c7850f9SSasha Levin 
2501c7850f9SSasha Levin 	/* Get last byte of the variable length struct */
2511c7850f9SSasha Levin 	mode = *((u8 *)msg + msg->size - 1);
2521c7850f9SSasha Levin 	perm = *(u32 *)((u8 *)msg + msg->size - 5);
2531c7850f9SSasha Levin 
2541c7850f9SSasha Levin 	sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str);
2551c7850f9SSasha Levin 
2561c7850f9SSasha Levin 	close_fid(tcreate->fid);
2571c7850f9SSasha Levin 
2581c7850f9SSasha Levin 	if (perm & P9_DMDIR) {
2591c7850f9SSasha Levin 		mkdir(fid->abs_path, perm & 0xFFFF);
2601c7850f9SSasha Levin 		fid->dir = opendir(fid->abs_path);
2611c7850f9SSasha Levin 		fid->is_dir = 1;
2621c7850f9SSasha Levin 	} else {
2631c7850f9SSasha Levin 		fid->fd = open(fid->abs_path, omode2uflags(mode) | O_CREAT, 0777);
2641c7850f9SSasha Levin 	}
2651c7850f9SSasha Levin 
2661c7850f9SSasha Levin 	if (stat(fid->abs_path, &st) < 0)
2671c7850f9SSasha Levin 		return false;
2681c7850f9SSasha Levin 
2691c7850f9SSasha Levin 	st2qid(&st, &rcreate->qid);
2701c7850f9SSasha Levin 
2711c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(*rcreate);
2721c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RCREATE, msg->tag);
2731c7850f9SSasha Levin 
2741c7850f9SSasha Levin 	return true;
2751c7850f9SSasha Levin }
2761c7850f9SSasha Levin 
2771c7850f9SSasha Levin static bool virtio_p9_walk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
2781c7850f9SSasha Levin {
2791c7850f9SSasha Levin 	struct p9_msg *outmsg	= iov[0].iov_base;
2801c7850f9SSasha Levin 	struct p9_twalk *twalk	= (struct p9_twalk *)msg->msg;
2811c7850f9SSasha Levin 	struct p9_rwalk *rwalk	= (struct p9_rwalk *)outmsg->msg;
2821c7850f9SSasha Levin 	struct p9_str *str	= twalk->wnames;
2831c7850f9SSasha Levin 	struct p9_fid *new_fid	= &p9dev.fids[twalk->newfid];
2841c7850f9SSasha Levin 	u8 i;
2851c7850f9SSasha Levin 
2861c7850f9SSasha Levin 	rwalk->nwqid = 0;
2871c7850f9SSasha Levin 	if (twalk->nwname) {
2881c7850f9SSasha Levin 		struct p9_fid *fid = &p9dev.fids[twalk->fid];
2891c7850f9SSasha Levin 
2901c7850f9SSasha Levin 		for (i = 0; i < twalk->nwname; i++) {
2911c7850f9SSasha Levin 			char tmp[PATH_MAX] = {0};
2921c7850f9SSasha Levin 			char full_path[PATH_MAX];
2931c7850f9SSasha Levin 			struct stat st;
2941c7850f9SSasha Levin 
2951c7850f9SSasha Levin 			/* Format the new path we're 'walk'ing into */
2961c7850f9SSasha Levin 			sprintf(tmp, "%s/%.*s", fid->path, str->len, (char *)&str->str);
2971c7850f9SSasha Levin 
2981c7850f9SSasha Levin 			if (stat(rel_to_abs(tmp, full_path), &st) < 0)
2991c7850f9SSasha Levin 				break;
3001c7850f9SSasha Levin 
3011c7850f9SSasha Levin 			st2qid(&st, &rwalk->wqids[i]);
3021c7850f9SSasha Levin 			new_fid->is_dir = S_ISDIR(st.st_mode);
3031c7850f9SSasha Levin 			strcpy(new_fid->path, tmp);
3041c7850f9SSasha Levin 			new_fid->fid = twalk->newfid;
3051c7850f9SSasha Levin 			rwalk->nwqid++;
3061c7850f9SSasha Levin 		}
3071c7850f9SSasha Levin 	} else {
3081c7850f9SSasha Levin 		new_fid->is_dir = p9dev.fids[twalk->fid].is_dir;
3091c7850f9SSasha Levin 		strcpy(new_fid->path, p9dev.fids[twalk->fid].path);
3101c7850f9SSasha Levin 		new_fid->fid	= twalk->newfid;
3111c7850f9SSasha Levin 	}
3121c7850f9SSasha Levin 
3131c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(u16) + sizeof(struct p9_qid) * rwalk->nwqid;
3141c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RWALK, msg->tag);
3151c7850f9SSasha Levin 
3161c7850f9SSasha Levin 	return true;
3171c7850f9SSasha Levin }
3181c7850f9SSasha Levin 
3191c7850f9SSasha Levin static bool virtio_p9_attach(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
3201c7850f9SSasha Levin {
3211c7850f9SSasha Levin 	struct p9_msg *outmsg = iov[0].iov_base;
3221c7850f9SSasha Levin 	struct p9_rattach *rattach = (struct p9_rattach *)outmsg->msg;
3231c7850f9SSasha Levin 	struct p9_tattach *tattach = (struct p9_tattach *)msg->msg;
3241c7850f9SSasha Levin 	struct stat st;
3251c7850f9SSasha Levin 	struct p9_fid *fid;
3261c7850f9SSasha Levin 	u32 i;
3271c7850f9SSasha Levin 
3281c7850f9SSasha Levin 	/* Reset everything */
3291c7850f9SSasha Levin 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++)
3301c7850f9SSasha Levin 		p9dev.fids[i].fid = P9_NOFID;
3311c7850f9SSasha Levin 
3321c7850f9SSasha Levin 	if (stat(p9dev.root_dir, &st) < 0)
3331c7850f9SSasha Levin 		return false;
3341c7850f9SSasha Levin 
3351c7850f9SSasha Levin 	st2qid(&st, &rattach->qid);
3361c7850f9SSasha Levin 
3371c7850f9SSasha Levin 	fid = &p9dev.fids[tattach->fid];
3381c7850f9SSasha Levin 	fid->fid = tattach->fid;
3391c7850f9SSasha Levin 	fid->is_dir = 1;
3401c7850f9SSasha Levin 	strcpy(fid->path, "/");
3411c7850f9SSasha Levin 
3421c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(*rattach);
3431c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RATTACH, msg->tag);
3441c7850f9SSasha Levin 
3451c7850f9SSasha Levin 	return true;
3461c7850f9SSasha Levin }
3471c7850f9SSasha Levin 
3481c7850f9SSasha Levin static u32 virtio_p9_fill_stat(const char *name, struct stat *st, struct p9_rstat *rstat)
3491c7850f9SSasha Levin {
3501c7850f9SSasha Levin 	struct p9_str *str;
3511c7850f9SSasha Levin 
3521c7850f9SSasha Levin 	rstat->stat.type = 0;
3531c7850f9SSasha Levin 	rstat->stat.dev = 0;
3541c7850f9SSasha Levin 	st2qid(st, &rstat->stat.qid);
3551c7850f9SSasha Levin 	rstat->stat.mode = st->st_mode;
3561c7850f9SSasha Levin 	rstat->stat.length = st->st_size;
3571c7850f9SSasha Levin 	if (S_ISDIR(st->st_mode)) {
3581c7850f9SSasha Levin 		rstat->stat.length = 0;
3591c7850f9SSasha Levin 		rstat->stat.mode |= P9_DMDIR;
3601c7850f9SSasha Levin 	}
3611c7850f9SSasha Levin 
3621c7850f9SSasha Levin 	rstat->stat.atime = st->st_atime;
3631c7850f9SSasha Levin 	rstat->stat.mtime = st->st_mtime;
3641c7850f9SSasha Levin 
3651c7850f9SSasha Levin 	str = (struct p9_str *)&rstat->stat.name;
3661c7850f9SSasha Levin 	str->len = strlen(name);
3671c7850f9SSasha Levin 	memcpy(&str->str, name, str->len);
3681c7850f9SSasha Levin 	str = (void *)str + str->len + sizeof(u16);
3691c7850f9SSasha Levin 
3701c7850f9SSasha Levin 	/* TODO: Pass usernames to the client */
3711c7850f9SSasha Levin 	str->len = 0;
3721c7850f9SSasha Levin 	str = (void *)str + sizeof(u16);
3731c7850f9SSasha Levin 	str->len = 0;
3741c7850f9SSasha Levin 	str = (void *)str + sizeof(u16);
3751c7850f9SSasha Levin 	str->len = 0;
3761c7850f9SSasha Levin 	str = (void *)str + sizeof(u16);
3771c7850f9SSasha Levin 
3781c7850f9SSasha Levin 	/* We subtract a u16 here because rstat->size doesn't include rstat->size itself */
3791c7850f9SSasha Levin 	rstat->stat.size = (void *)str - (void *)&rstat->stat - sizeof(u16);
3801c7850f9SSasha Levin 
3811c7850f9SSasha Levin 	return rstat->stat.size + sizeof(u16);
3821c7850f9SSasha Levin }
3831c7850f9SSasha Levin 
3841c7850f9SSasha Levin static bool virtio_p9_read(struct p9_msg *msg, u32 len, struct iovec *iov, int iovcnt, u32 *outlen)
3851c7850f9SSasha Levin {
3861c7850f9SSasha Levin 	struct p9_msg *outmsg	= iov[0].iov_base;
3871c7850f9SSasha Levin 	struct p9_tread *tread	= (struct p9_tread *)msg->msg;
3881c7850f9SSasha Levin 	struct p9_rread *rread	= (struct p9_rread *)outmsg->msg;
3891c7850f9SSasha Levin 	struct p9_rstat *rstat	= (struct p9_rstat *)iov[1].iov_base;
3901c7850f9SSasha Levin 	struct p9_fid *fid	= &p9dev.fids[tread->fid];
3911c7850f9SSasha Levin 	struct stat st;
3921c7850f9SSasha Levin 
3931c7850f9SSasha Levin 	rread->count = 0;
3941c7850f9SSasha Levin 
3951c7850f9SSasha Levin 	if (fid->is_dir) {
3961c7850f9SSasha Levin 		/* If reading a dir, fill the buffer with p9_stat entries */
3971c7850f9SSasha Levin 		struct dirent *cur = readdir(fid->dir);
3981c7850f9SSasha Levin 		char full_path[PATH_MAX];
3991c7850f9SSasha Levin 
4001c7850f9SSasha Levin 		while (cur) {
4011c7850f9SSasha Levin 			u32 read;
4021c7850f9SSasha Levin 
4031c7850f9SSasha Levin 			stat(rel_to_abs(cur->d_name, full_path), &st);
4041c7850f9SSasha Levin 			read = virtio_p9_fill_stat(cur->d_name, &st, rstat);
4051c7850f9SSasha Levin 			rread->count += read;
4061c7850f9SSasha Levin 			rstat = (void *)rstat + read;
4071c7850f9SSasha Levin 			cur = readdir(fid->dir);
4081c7850f9SSasha Levin 		}
4091c7850f9SSasha Levin 	} else {
4101c7850f9SSasha Levin 		iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32);
4111c7850f9SSasha Levin 		iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32);
4121c7850f9SSasha Levin 		rread->count = preadv(fid->fd, iov, iovcnt, tread->offset);
4131c7850f9SSasha Levin 		if (rread->count > tread->count)
4141c7850f9SSasha Levin 			rread->count = tread->count;
4151c7850f9SSasha Levin 	}
4161c7850f9SSasha Levin 
4171c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(u32) + rread->count;
4181c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RREAD, msg->tag);
4191c7850f9SSasha Levin 
4201c7850f9SSasha Levin 	return true;
4211c7850f9SSasha Levin }
4221c7850f9SSasha Levin 
4231c7850f9SSasha Levin static bool virtio_p9_stat(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
4241c7850f9SSasha Levin {
4251c7850f9SSasha Levin 	struct p9_msg *outmsg = iov[0].iov_base;
4261c7850f9SSasha Levin 	struct p9_tstat *tstat = (struct p9_tstat *)msg->msg;
4271c7850f9SSasha Levin 	struct p9_rstat *rstat = (struct p9_rstat *)(outmsg->msg + sizeof(u16));
4281c7850f9SSasha Levin 	struct stat st;
4291c7850f9SSasha Levin 	struct p9_fid *fid = &p9dev.fids[tstat->fid];
4301c7850f9SSasha Levin 	u32 ret;
4311c7850f9SSasha Levin 
4321c7850f9SSasha Levin 	if (stat(fid->abs_path, &st) < 0)
4331c7850f9SSasha Levin 		return false;
4341c7850f9SSasha Levin 
4351c7850f9SSasha Levin 	ret = virtio_p9_fill_stat(fid->path, &st, rstat);
4361c7850f9SSasha Levin 
4371c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16) * 2;
4381c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RSTAT, msg->tag);
4391c7850f9SSasha Levin 	return true;
4401c7850f9SSasha Levin }
4411c7850f9SSasha Levin 
4421c7850f9SSasha Levin static bool virtio_p9_wstat(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
4431c7850f9SSasha Levin {
4441c7850f9SSasha Levin 	struct p9_msg *outmsg = iov[0].iov_base;
4451c7850f9SSasha Levin 	struct p9_twstat *twstat = (struct p9_twstat *)msg->msg;
4461c7850f9SSasha Levin 	struct p9_str *str;
4471c7850f9SSasha Levin 	struct p9_fid *fid = &p9dev.fids[twstat->fid];
448aec426f0SCyrill Gorcunov 	int res = 0;
4491c7850f9SSasha Levin 
4501c7850f9SSasha Levin 	if (twstat->stat.length != -1UL)
4511c7850f9SSasha Levin 		res = ftruncate(fid->fd, twstat->stat.length);
4521c7850f9SSasha Levin 
4531c7850f9SSasha Levin 	if (twstat->stat.mode != -1U)
4541c7850f9SSasha Levin 		chmod(fid->abs_path, twstat->stat.mode & 0xFFFF);
4551c7850f9SSasha Levin 
4561c7850f9SSasha Levin 	str = (void *)&twstat->stat.name + sizeof(u16);
4571c7850f9SSasha Levin 	if (str->len > 0) {
4581c7850f9SSasha Levin 		char new_name[PATH_MAX] = {0};
4591c7850f9SSasha Levin 		char full_path[PATH_MAX];
4601c7850f9SSasha Levin 		char *last_dir = strrchr(fid->path, '/');
4611c7850f9SSasha Levin 
4621c7850f9SSasha Levin 		/* We need to get the full file name out of twstat->name */
4631c7850f9SSasha Levin 		if (last_dir)
4641c7850f9SSasha Levin 			strncpy(new_name, fid->path, last_dir - fid->path + 1);
4651c7850f9SSasha Levin 
4661c7850f9SSasha Levin 		memcpy(new_name + strlen(new_name), &str->str, str->len);
4671c7850f9SSasha Levin 
4681c7850f9SSasha Levin 		/* fid is reused for the new file */
4691c7850f9SSasha Levin 		rename(fid->abs_path, rel_to_abs(new_name, full_path));
4701c7850f9SSasha Levin 		sprintf(fid->path, "%s", new_name);
4711c7850f9SSasha Levin 	}
4721c7850f9SSasha Levin 
4731c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN;
4741c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RWSTAT, msg->tag);
475aec426f0SCyrill Gorcunov 
476aec426f0SCyrill Gorcunov 	return res == 0;
4771c7850f9SSasha Levin }
4781c7850f9SSasha Levin 
4791c7850f9SSasha Levin static bool virtio_p9_remove(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
4801c7850f9SSasha Levin {
4811c7850f9SSasha Levin 	struct p9_msg *outmsg = iov[0].iov_base;
4821c7850f9SSasha Levin 	struct p9_tremove *tremove = (struct p9_tremove *)msg->msg;
4831c7850f9SSasha Levin 	struct p9_fid *fid = &p9dev.fids[tremove->fid];
4841c7850f9SSasha Levin 
4851c7850f9SSasha Levin 	close_fid(tremove->fid);
4861c7850f9SSasha Levin 	if (fid->is_dir)
4871c7850f9SSasha Levin 		rmdir(fid->abs_path);
4881c7850f9SSasha Levin 	else
4891c7850f9SSasha Levin 		unlink(fid->abs_path);
4901c7850f9SSasha Levin 
4911c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN;
4921c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RREMOVE, msg->tag);
4931c7850f9SSasha Levin 	return true;
4941c7850f9SSasha Levin }
4951c7850f9SSasha Levin 
4961c7850f9SSasha Levin static bool virtio_p9_write(struct p9_msg *msg, u32 len, struct iovec *iov, int iovcnt, u32 *outlen)
4971c7850f9SSasha Levin {
4981c7850f9SSasha Levin 	struct p9_msg *outmsg;
4991c7850f9SSasha Levin 	struct p9_rwrite *rwrite;
5001c7850f9SSasha Levin 	struct p9_twrite *twrite = (struct p9_twrite *)msg->msg;
5011c7850f9SSasha Levin 	struct p9_fid *fid = &p9dev.fids[twrite->fid];
5021c7850f9SSasha Levin 
5031c7850f9SSasha Levin 	if (iovcnt == 1) {
5041c7850f9SSasha Levin 		outmsg = iov[0].iov_base;
5051c7850f9SSasha Levin 		rwrite = (struct p9_rwrite *)outmsg->msg;
5061c7850f9SSasha Levin 		rwrite->count = pwrite(fid->fd, &twrite->data, twrite->count, twrite->offset);
5071c7850f9SSasha Levin 	} else {
5081c7850f9SSasha Levin 		outmsg = iov[2].iov_base;
5091c7850f9SSasha Levin 		rwrite = (struct p9_rwrite *)outmsg->msg;
5101c7850f9SSasha Levin 		rwrite->count = pwrite(fid->fd, iov[1].iov_base, twrite->count, twrite->offset);
5111c7850f9SSasha Levin 	}
5121c7850f9SSasha Levin 
5131c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(u32);
5141c7850f9SSasha Levin 	set_p9msg_hdr(outmsg, *outlen, P9_RWRITE, msg->tag);
5151c7850f9SSasha Levin 
5161c7850f9SSasha Levin 	return true;
5171c7850f9SSasha Levin }
5181c7850f9SSasha Levin 
5191c7850f9SSasha Levin static bool virtio_p9_do_io_request(struct kvm *kvm, struct virt_queue *queue)
5201c7850f9SSasha Levin {
5211c7850f9SSasha Levin 	struct iovec iov[VIRTIO_P9_QUEUE_SIZE];
5221c7850f9SSasha Levin 	u16 out, in, head;
5231c7850f9SSasha Levin 	struct p9_msg *msg;
5241c7850f9SSasha Levin 	u32 len = 0;
5251c7850f9SSasha Levin 
5261c7850f9SSasha Levin 	head		= virt_queue__get_iov(queue, iov, &out, &in, kvm);
5271c7850f9SSasha Levin 	msg		= iov[0].iov_base;
5281c7850f9SSasha Levin 
5291c7850f9SSasha Levin 	switch (msg->cmd) {
5301c7850f9SSasha Levin 	case P9_TVERSION:
5311c7850f9SSasha Levin 		virtio_p9_version(msg, iov[0].iov_len, iov+1, &len);
5321c7850f9SSasha Levin 		break;
5331c7850f9SSasha Levin 	case P9_TATTACH:
5341c7850f9SSasha Levin 		virtio_p9_attach(msg, iov[0].iov_len, iov+1, &len);
5351c7850f9SSasha Levin 		break;
5361c7850f9SSasha Levin 	case P9_TSTAT:
5371c7850f9SSasha Levin 		virtio_p9_stat(msg, iov[0].iov_len, iov+1, &len);
5381c7850f9SSasha Levin 		break;
5391c7850f9SSasha Levin 	case P9_TCLUNK:
5401c7850f9SSasha Levin 		virtio_p9_clunk(msg, iov[0].iov_len, iov+1, &len);
5411c7850f9SSasha Levin 		break;
5421c7850f9SSasha Levin 	case P9_TWALK:
5431c7850f9SSasha Levin 		virtio_p9_walk(msg, iov[0].iov_len, iov+1, &len);
5441c7850f9SSasha Levin 		break;
5451c7850f9SSasha Levin 	case P9_TOPEN:
5461c7850f9SSasha Levin 		virtio_p9_open(msg, iov[0].iov_len, iov+1, &len);
5471c7850f9SSasha Levin 		break;
5481c7850f9SSasha Levin 	case P9_TREAD:
5491c7850f9SSasha Levin 		virtio_p9_read(msg, iov[0].iov_len, iov+1, in, &len);
5501c7850f9SSasha Levin 		break;
5511c7850f9SSasha Levin 	case P9_TCREATE:
5521c7850f9SSasha Levin 		virtio_p9_create(msg, iov[0].iov_len, iov+1, &len);
5531c7850f9SSasha Levin 		break;
5541c7850f9SSasha Levin 	case P9_TWSTAT:
5551c7850f9SSasha Levin 		virtio_p9_wstat(msg, iov[0].iov_len, iov+1, &len);
5561c7850f9SSasha Levin 		break;
5571c7850f9SSasha Levin 	case P9_TREMOVE:
5581c7850f9SSasha Levin 		virtio_p9_remove(msg, iov[0].iov_len, iov+1, &len);
5591c7850f9SSasha Levin 		break;
5601c7850f9SSasha Levin 	case P9_TWRITE:
5611c7850f9SSasha Levin 		virtio_p9_write(msg, iov[0].iov_len, iov+1, out, &len);
5621c7850f9SSasha Levin 		break;
5631c7850f9SSasha Levin 	default:
5641c7850f9SSasha Levin 		printf("Unsupported P9 message type: %u\n", msg->cmd);
5651c7850f9SSasha Levin 		break;
5661c7850f9SSasha Levin 	}
5671c7850f9SSasha Levin 	virt_queue__set_used_elem(queue, head, len);
5681c7850f9SSasha Levin 
5691c7850f9SSasha Levin 	return true;
5701c7850f9SSasha Levin }
5711c7850f9SSasha Levin 
5721c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param)
5731c7850f9SSasha Levin {
5741c7850f9SSasha Levin 	struct virt_queue *vq = param;
5751c7850f9SSasha Levin 
5761c7850f9SSasha Levin 	while (virt_queue__available(vq)) {
5771c7850f9SSasha Levin 		virtio_p9_do_io_request(kvm, vq);
5781c7850f9SSasha Levin 		virt_queue__trigger_irq(vq, virtio_p9_pci_device.irq_line, &p9dev.isr, kvm);
5791c7850f9SSasha Levin 	}
5801c7850f9SSasha Levin }
5811c7850f9SSasha Levin 
582*3d62dea6SSasha Levin static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
5831c7850f9SSasha Levin {
5841c7850f9SSasha Levin 	unsigned long offset;
5851c7850f9SSasha Levin 	bool ret = true;
5861c7850f9SSasha Levin 
5871c7850f9SSasha Levin 	offset		= port - IOPORT_VIRTIO_P9;
5881c7850f9SSasha Levin 
5891c7850f9SSasha Levin 	switch (offset) {
5901c7850f9SSasha Levin 	case VIRTIO_MSI_QUEUE_VECTOR:
5911c7850f9SSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
5921c7850f9SSasha Levin 		break;
5931c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN: {
5941c7850f9SSasha Levin 		struct virt_queue *queue;
5951c7850f9SSasha Levin 		void *p;
5961c7850f9SSasha Levin 
5971c7850f9SSasha Levin 		queue			= &p9dev.vqs[p9dev.queue_selector];
5981c7850f9SSasha Levin 		queue->pfn		= ioport__read32(data);
5991c7850f9SSasha Levin 		p			= guest_pfn_to_host(kvm, queue->pfn);
6001c7850f9SSasha Levin 
6011c7850f9SSasha Levin 		vring_init(&queue->vring, VIRTIO_P9_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
6021c7850f9SSasha Levin 
6031c7850f9SSasha Levin 		p9dev.jobs[p9dev.queue_selector] = thread_pool__add_job(kvm, virtio_p9_do_io, queue);
6041c7850f9SSasha Levin 
6051c7850f9SSasha Levin 		break;
6061c7850f9SSasha Levin 	}
6071c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
6081c7850f9SSasha Levin 		p9dev.queue_selector	= ioport__read16(data);
6091c7850f9SSasha Levin 		break;
6101c7850f9SSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY: {
6111c7850f9SSasha Levin 		u16 queue_index;
6121c7850f9SSasha Levin 		queue_index		= ioport__read16(data);
6131c7850f9SSasha Levin 		thread_pool__do_job(p9dev.jobs[queue_index]);
6141c7850f9SSasha Levin 		break;
6151c7850f9SSasha Levin 	}
6161c7850f9SSasha Levin 	case VIRTIO_PCI_STATUS:
6171c7850f9SSasha Levin 		p9dev.status		= ioport__read8(data);
6181c7850f9SSasha Levin 		break;
6191c7850f9SSasha Levin 	case VIRTIO_MSI_CONFIG_VECTOR:
6201c7850f9SSasha Levin 		p9dev.config_vector	= VIRTIO_MSI_NO_VECTOR;
6211c7850f9SSasha Levin 		break;
6221c7850f9SSasha Levin 	default:
6231c7850f9SSasha Levin 		ret			= false;
6241c7850f9SSasha Levin 		break;
6251c7850f9SSasha Levin 	};
6261c7850f9SSasha Levin 
6271c7850f9SSasha Levin 	return ret;
6281c7850f9SSasha Levin }
6291c7850f9SSasha Levin 
6301c7850f9SSasha Levin static struct ioport_operations virtio_p9_io_ops = {
6311c7850f9SSasha Levin 	.io_in				= virtio_p9_pci_io_in,
6321c7850f9SSasha Levin 	.io_out				= virtio_p9_pci_io_out,
6331c7850f9SSasha Levin };
6341c7850f9SSasha Levin 
6351c7850f9SSasha Levin void virtio_9p__init(struct kvm *kvm, const char *root)
6361c7850f9SSasha Levin {
6371c7850f9SSasha Levin 	u8 pin, line, dev;
6381c7850f9SSasha Levin 	u32 i, root_len;
6391c7850f9SSasha Levin 
6401c7850f9SSasha Levin 	p9dev.config = calloc(1, sizeof(*p9dev.config) + sizeof(VIRTIO_P9_TAG));
6411c7850f9SSasha Levin 	if (p9dev.config == NULL)
6421c7850f9SSasha Levin 		return;
6431c7850f9SSasha Levin 
6441c7850f9SSasha Levin 	strcpy(p9dev.root_dir, root);
6451c7850f9SSasha Levin 	root_len = strlen(root);
6461c7850f9SSasha Levin 
6471c7850f9SSasha Levin 	/*
6481c7850f9SSasha Levin 	 * We prefix the full path in all fids, This allows us to get the
6491c7850f9SSasha Levin 	 * absolute path of an fid without playing with strings.
6501c7850f9SSasha Levin 	 */
6511c7850f9SSasha Levin 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++) {
6521c7850f9SSasha Levin 		strcpy(p9dev.fids[i].abs_path, root);
6531c7850f9SSasha Levin 		p9dev.fids[i].path = p9dev.fids[i].abs_path + root_len;
6541c7850f9SSasha Levin 	}
6551c7850f9SSasha Levin 
6561c7850f9SSasha Levin 	p9dev.config->tag_len = strlen(VIRTIO_P9_TAG);
6571c7850f9SSasha Levin 	memcpy(p9dev.config->tag, VIRTIO_P9_TAG, strlen(VIRTIO_P9_TAG));
6581c7850f9SSasha Levin 	p9dev.features |= 1 << VIRTIO_9P_MOUNT_TAG;
6591c7850f9SSasha Levin 
6601c7850f9SSasha Levin 	if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0)
6611c7850f9SSasha Levin 		return;
6621c7850f9SSasha Levin 
6631c7850f9SSasha Levin 	virtio_p9_pci_device.irq_pin	= pin;
6641c7850f9SSasha Levin 	virtio_p9_pci_device.irq_line	= line;
6651c7850f9SSasha Levin 	pci__register(&virtio_p9_pci_device, dev);
6661c7850f9SSasha Levin 
667*3d62dea6SSasha Levin 	ioport__register(IOPORT_VIRTIO_P9, &virtio_p9_io_ops, IOPORT_VIRTIO_P9_SIZE, NULL);
6681c7850f9SSasha Levin }
669