xref: /kvmtool/virtio/9p.c (revision a8a44649837abadde3fafc1c05bc2694e215abc3)
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"
5bfc15268SAneesh Kumar K.V #include "kvm/irq.h"
6bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h"
7e59662b3SSasha Levin #include "kvm/guest_compat.h"
81c7850f9SSasha Levin 
9bfc15268SAneesh Kumar K.V #include <stdio.h>
10bfc15268SAneesh Kumar K.V #include <stdlib.h>
111c7850f9SSasha Levin #include <fcntl.h>
121c7850f9SSasha Levin #include <sys/stat.h>
13bfc15268SAneesh Kumar K.V #include <unistd.h>
14bfc15268SAneesh Kumar K.V #include <string.h>
15bfc15268SAneesh Kumar K.V #include <errno.h>
16c797b6c6SAneesh Kumar K.V #include <sys/vfs.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 
22c7838fbdSSasha Levin static LIST_HEAD(devs);
23312c62d1SSasha Levin static int compat_id = -1;
24c7838fbdSSasha Levin 
2531a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
2631a6fb8dSSasha Levin {
2731a6fb8dSSasha Levin 	if (fid >= VIRTIO_9P_MAX_FID)
2831a6fb8dSSasha Levin 		die("virtio-9p max FID (%u) reached!", VIRTIO_9P_MAX_FID);
2931a6fb8dSSasha Levin 
3031a6fb8dSSasha Levin 	return &p9dev->fids[fid];
3131a6fb8dSSasha Levin }
3231a6fb8dSSasha Levin 
331c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */
34b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev,
35b4422bf3SAneesh Kumar K.V 			      const char *path, char *abs_path)
361c7850f9SSasha Levin {
37b4422bf3SAneesh Kumar K.V 	sprintf(abs_path, "%s/%s", p9dev->root_dir, path);
381c7850f9SSasha Levin 
391c7850f9SSasha Levin 	return abs_path;
401c7850f9SSasha Levin }
411c7850f9SSasha Levin 
42c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid)
431c7850f9SSasha Levin {
441c7850f9SSasha Levin 	*qid = (struct p9_qid) {
451c7850f9SSasha Levin 		.path		= st->st_ino,
461c7850f9SSasha Levin 		.version	= st->st_mtime,
471c7850f9SSasha Levin 	};
481c7850f9SSasha Levin 
491c7850f9SSasha Levin 	if (S_ISDIR(st->st_mode))
501c7850f9SSasha Levin 		qid->type	|= P9_QTDIR;
511c7850f9SSasha Levin }
521c7850f9SSasha Levin 
53b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid)
541c7850f9SSasha Levin {
55b4422bf3SAneesh Kumar K.V 	if (p9dev->fids[fid].fd > 0) {
56b4422bf3SAneesh Kumar K.V 		close(p9dev->fids[fid].fd);
57b4422bf3SAneesh Kumar K.V 		p9dev->fids[fid].fd = -1;
581c7850f9SSasha Levin 	}
59b4422bf3SAneesh Kumar K.V 	if (p9dev->fids[fid].dir) {
60b4422bf3SAneesh Kumar K.V 		closedir(p9dev->fids[fid].dir);
61b4422bf3SAneesh Kumar K.V 		p9dev->fids[fid].dir = NULL;
621c7850f9SSasha Levin 	}
63c797b6c6SAneesh Kumar K.V 	p9dev->fids[fid].fid = P9_NOFID;
641c7850f9SSasha Levin }
651c7850f9SSasha Levin 
66bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
671c7850f9SSasha Levin {
68bfc15268SAneesh Kumar K.V 	u8 cmd;
69bfc15268SAneesh Kumar K.V 	u16 tag;
70bfc15268SAneesh Kumar K.V 
71bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32);
72bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
73bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
74bfc15268SAneesh Kumar K.V 	/* cmd + 1 is the reply message */
75bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
761c7850f9SSasha Levin }
771c7850f9SSasha Levin 
786b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
796b163a87SAneesh Kumar K.V {
806b163a87SAneesh Kumar K.V 	int i;
816b163a87SAneesh Kumar K.V 	u32 total = 0;
826b163a87SAneesh Kumar K.V 	for (i = 0; (i < iov_cnt) && (total < count); i++) {
836b163a87SAneesh Kumar K.V 		if (total + iov[i].iov_len > count) {
846b163a87SAneesh Kumar K.V 			/* we don't need this iov fully */
856b163a87SAneesh Kumar K.V 			iov[i].iov_len -= ((total + iov[i].iov_len) - count);
866b163a87SAneesh Kumar K.V 			i++;
876b163a87SAneesh Kumar K.V 			break;
886b163a87SAneesh Kumar K.V 		}
896b163a87SAneesh Kumar K.V 		total += iov[i].iov_len;
906b163a87SAneesh Kumar K.V 	}
916b163a87SAneesh Kumar K.V 	return i;
926b163a87SAneesh Kumar K.V }
936b163a87SAneesh Kumar K.V 
94eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev,
95eee1ba8eSAneesh Kumar K.V 				  struct p9_pdu *pdu, int err, u32 *outlen)
96eee1ba8eSAneesh Kumar K.V {
97bfc15268SAneesh Kumar K.V 	u16 tag;
98eee1ba8eSAneesh Kumar K.V 
995529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
100c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", err);
101bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
102eee1ba8eSAneesh Kumar K.V 
103c797b6c6SAneesh Kumar K.V 	/* read the tag from input */
104bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32) + sizeof(u8);
105bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "w", &tag);
106bfc15268SAneesh Kumar K.V 
107c797b6c6SAneesh Kumar K.V 	/* Update the header */
108bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
109c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
110eee1ba8eSAneesh Kumar K.V }
111eee1ba8eSAneesh Kumar K.V 
112ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev,
113af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
1141c7850f9SSasha Levin {
115c797b6c6SAneesh Kumar K.V 	u32 msize;
116c797b6c6SAneesh Kumar K.V 	char *version;
117c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
118c797b6c6SAneesh Kumar K.V 	/*
119c797b6c6SAneesh Kumar K.V 	 * reply with the same msize the client sent us
120c797b6c6SAneesh Kumar K.V 	 * Error out if the request is not for 9P2000.L
121c797b6c6SAneesh Kumar K.V 	 */
1225529bcd7SAsias He 	if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
123c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, version);
124c797b6c6SAneesh Kumar K.V 	else
125c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
1261c7850f9SSasha Levin 
127bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
128bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
129c797b6c6SAneesh Kumar K.V 	free(version);
130ead43b01SAneesh Kumar K.V 	return;
1311c7850f9SSasha Levin }
1321c7850f9SSasha Levin 
133ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev,
134af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
1351c7850f9SSasha Levin {
136bfc15268SAneesh Kumar K.V 	u32 fid;
1371c7850f9SSasha Levin 
138bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid);
139bfc15268SAneesh Kumar K.V 	close_fid(p9dev, fid);
1401c7850f9SSasha Levin 
141bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
142bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
143ead43b01SAneesh Kumar K.V 	return;
1441c7850f9SSasha Levin }
1451c7850f9SSasha Levin 
146c797b6c6SAneesh Kumar K.V /*
147c797b6c6SAneesh Kumar K.V  * FIXME!! Need to map to protocol independent value. Upstream
148c797b6c6SAneesh Kumar K.V  * 9p also have the same BUG
149c797b6c6SAneesh Kumar K.V  */
150c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags)
151c797b6c6SAneesh Kumar K.V {
152c797b6c6SAneesh Kumar K.V 	flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
153c797b6c6SAneesh Kumar K.V 	flags |= O_NOFOLLOW;
154c797b6c6SAneesh Kumar K.V 	return flags;
155c797b6c6SAneesh Kumar K.V }
156c797b6c6SAneesh Kumar K.V 
157ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev,
158af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
1591c7850f9SSasha Levin {
160c797b6c6SAneesh Kumar K.V 	u32 fid, flags;
1611c7850f9SSasha Levin 	struct stat st;
162bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
163bfc15268SAneesh Kumar K.V 	struct p9_fid *new_fid;
164bfc15268SAneesh Kumar K.V 
165c797b6c6SAneesh Kumar K.V 
166c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
16731a6fb8dSSasha Levin 	new_fid = get_fid(p9dev, fid);
1681c7850f9SSasha Levin 
16930204a77SAneesh Kumar K.V 	if (lstat(new_fid->abs_path, &st) < 0)
170eee1ba8eSAneesh Kumar K.V 		goto err_out;
1711c7850f9SSasha Levin 
172c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
1731c7850f9SSasha Levin 
174eee1ba8eSAneesh Kumar K.V 	if (new_fid->is_dir) {
1751c7850f9SSasha Levin 		new_fid->dir = opendir(new_fid->abs_path);
176eee1ba8eSAneesh Kumar K.V 		if (!new_fid->dir)
177eee1ba8eSAneesh Kumar K.V 			goto err_out;
178eee1ba8eSAneesh Kumar K.V 	} else {
179eee1ba8eSAneesh Kumar K.V 		new_fid->fd  = open(new_fid->abs_path,
180c797b6c6SAneesh Kumar K.V 				    virtio_p9_openflags(flags));
181eee1ba8eSAneesh Kumar K.V 		if (new_fid->fd < 0)
182eee1ba8eSAneesh Kumar K.V 			goto err_out;
183eee1ba8eSAneesh Kumar K.V 	}
184c797b6c6SAneesh Kumar K.V 	/* FIXME!! need ot send proper iounit  */
185bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
186bfc15268SAneesh Kumar K.V 
187bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
188bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
189ead43b01SAneesh Kumar K.V 	return;
190eee1ba8eSAneesh Kumar K.V err_out:
191eee1ba8eSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
192ead43b01SAneesh Kumar K.V 	return;
1931c7850f9SSasha Levin }
1941c7850f9SSasha Levin 
195ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev,
196af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
1971c7850f9SSasha Levin {
198c797b6c6SAneesh Kumar K.V 	int fd, ret;
199bfc15268SAneesh Kumar K.V 	char *name;
200af045e53SAneesh Kumar K.V 	struct stat st;
201bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
202c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
2034bc9734aSAneesh Kumar K.V 	char full_path[PATH_MAX];
204c797b6c6SAneesh Kumar K.V 	u32 dfid_val, flags, mode, gid;
205af045e53SAneesh Kumar K.V 
206c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
207c797b6c6SAneesh Kumar K.V 			    &name, &flags, &mode, &gid);
20831a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
2091c7850f9SSasha Levin 
210c797b6c6SAneesh Kumar K.V 	flags = virtio_p9_openflags(flags);
2115f900f6dSSasha Levin 
212c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
213c797b6c6SAneesh Kumar K.V 	fd = open(full_path, flags | O_CREAT, mode);
2144bc9734aSAneesh Kumar K.V 	if (fd < 0)
2154bc9734aSAneesh Kumar K.V 		goto err_out;
216c797b6c6SAneesh Kumar K.V 	close_fid(p9dev, dfid_val);
217c797b6c6SAneesh Kumar K.V 	dfid->fd = fd;
218c797b6c6SAneesh Kumar K.V 
2194bc9734aSAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
2206c8ca053SAneesh Kumar K.V 		goto err_out;
2211c7850f9SSasha Levin 
222c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
223c797b6c6SAneesh Kumar K.V 	if (ret < 0)
224c797b6c6SAneesh Kumar K.V 		goto err_out;
225c797b6c6SAneesh Kumar K.V 
226c797b6c6SAneesh Kumar K.V 	ret = lchown(full_path, dfid->uid, gid);
227c797b6c6SAneesh Kumar K.V 	if (ret < 0)
228c797b6c6SAneesh Kumar K.V 		goto err_out;
229c797b6c6SAneesh Kumar K.V 
230c797b6c6SAneesh Kumar K.V 	sprintf(dfid->path, "%s/%s", dfid->path, name);
231c797b6c6SAneesh Kumar K.V 	stat2qid(&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 	free(name);
2366c8ca053SAneesh Kumar K.V 	return;
2376c8ca053SAneesh Kumar K.V err_out:
2385f900f6dSSasha Levin 	free(name);
239c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
240c797b6c6SAneesh Kumar K.V 	return;
241c797b6c6SAneesh Kumar K.V }
242c797b6c6SAneesh Kumar K.V 
243c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev,
244c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
245c797b6c6SAneesh Kumar K.V {
246c797b6c6SAneesh Kumar K.V 	int ret;
247c797b6c6SAneesh Kumar K.V 	char *name;
248c797b6c6SAneesh Kumar K.V 	struct stat st;
249c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
250c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
251c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
252c797b6c6SAneesh Kumar K.V 	u32 dfid_val, mode, gid;
253c797b6c6SAneesh Kumar K.V 
254c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
255c797b6c6SAneesh Kumar K.V 			    &name, &mode, &gid);
25631a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
257c797b6c6SAneesh Kumar K.V 
258c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
259c797b6c6SAneesh Kumar K.V 	ret = mkdir(full_path, mode);
260c797b6c6SAneesh Kumar K.V 	if (ret < 0)
261c797b6c6SAneesh Kumar K.V 		goto err_out;
262c797b6c6SAneesh Kumar K.V 
263c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
264c797b6c6SAneesh Kumar K.V 		goto err_out;
265c797b6c6SAneesh Kumar K.V 
266c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
267c797b6c6SAneesh Kumar K.V 	if (ret < 0)
268c797b6c6SAneesh Kumar K.V 		goto err_out;
269c797b6c6SAneesh Kumar K.V 
270c797b6c6SAneesh Kumar K.V 	ret = lchown(full_path, dfid->uid, gid);
271c797b6c6SAneesh Kumar K.V 	if (ret < 0)
272c797b6c6SAneesh Kumar K.V 		goto err_out;
273c797b6c6SAneesh Kumar K.V 
274c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
275c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
276c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
277c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
278c797b6c6SAneesh Kumar K.V 	free(name);
279c797b6c6SAneesh Kumar K.V 	return;
280c797b6c6SAneesh Kumar K.V err_out:
281c797b6c6SAneesh Kumar K.V 	free(name);
282c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
283ead43b01SAneesh Kumar K.V 	return;
2841c7850f9SSasha Levin }
2851c7850f9SSasha Levin 
286ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev,
287af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
2881c7850f9SSasha Levin {
289af045e53SAneesh Kumar K.V 	u8 i;
290bfc15268SAneesh Kumar K.V 	u16 nwqid;
291bfc15268SAneesh Kumar K.V 	u16 nwname;
292bfc15268SAneesh Kumar K.V 	struct p9_qid wqid;
293bfc15268SAneesh Kumar K.V 	struct p9_fid *new_fid;
294c797b6c6SAneesh Kumar K.V 	u32 fid_val, newfid_val;
295c797b6c6SAneesh Kumar K.V 
2961c7850f9SSasha Levin 
297bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
29831a6fb8dSSasha Levin 	new_fid	= get_fid(p9dev, newfid_val);
2991c7850f9SSasha Levin 
300bfc15268SAneesh Kumar K.V 	nwqid = 0;
301bfc15268SAneesh Kumar K.V 	if (nwname) {
30231a6fb8dSSasha Levin 		struct p9_fid *fid = get_fid(p9dev, fid_val);
303bfc15268SAneesh Kumar K.V 
304baac79a5SAneesh Kumar K.V 		strcpy(new_fid->path, fid->path);
305bfc15268SAneesh Kumar K.V 		/* skip the space for count */
306bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
307bfc15268SAneesh Kumar K.V 		for (i = 0; i < nwname; i++) {
308bfc15268SAneesh Kumar K.V 			struct stat st;
3091c7850f9SSasha Levin 			char tmp[PATH_MAX] = {0};
3101c7850f9SSasha Levin 			char full_path[PATH_MAX];
311e55ed135SPekka Enberg 			char *str;
312bfc15268SAneesh Kumar K.V 
313bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_readf(pdu, "s", &str);
3141c7850f9SSasha Levin 
3151c7850f9SSasha Levin 			/* Format the new path we're 'walk'ing into */
316baac79a5SAneesh Kumar K.V 			sprintf(tmp, "%s/%s", new_fid->path, str);
317e55ed135SPekka Enberg 
318e55ed135SPekka Enberg 			free(str);
319e55ed135SPekka Enberg 
320c797b6c6SAneesh Kumar K.V 			if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0)
3216c8ca053SAneesh Kumar K.V 				goto err_out;
3221c7850f9SSasha Levin 
323c797b6c6SAneesh Kumar K.V 			stat2qid(&st, &wqid);
3241c7850f9SSasha Levin 			new_fid->is_dir = S_ISDIR(st.st_mode);
3251c7850f9SSasha Levin 			strcpy(new_fid->path, tmp);
326bfc15268SAneesh Kumar K.V 			new_fid->fid = newfid_val;
327c797b6c6SAneesh Kumar K.V 			new_fid->uid = fid->uid;
328bfc15268SAneesh Kumar K.V 			nwqid++;
329bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_writef(pdu, "Q", &wqid);
3301c7850f9SSasha Levin 		}
3311c7850f9SSasha Levin 	} else {
332bfc15268SAneesh Kumar K.V 		/*
333bfc15268SAneesh Kumar K.V 		 * update write_offset so our outlen get correct value
334bfc15268SAneesh Kumar K.V 		 */
335bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
336bfc15268SAneesh Kumar K.V 		new_fid->is_dir = p9dev->fids[fid_val].is_dir;
337bfc15268SAneesh Kumar K.V 		strcpy(new_fid->path, p9dev->fids[fid_val].path);
338bfc15268SAneesh Kumar K.V 		new_fid->fid	= newfid_val;
339c797b6c6SAneesh Kumar K.V 		new_fid->uid    = p9dev->fids[fid_val].uid;
3401c7850f9SSasha Levin 	}
341bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
3425529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
343bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", nwqid);
344bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
3456c8ca053SAneesh Kumar K.V 	return;
3466c8ca053SAneesh Kumar K.V err_out:
3476c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
348ead43b01SAneesh Kumar K.V 	return;
3491c7850f9SSasha Levin }
3501c7850f9SSasha Levin 
351ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev,
352af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
3531c7850f9SSasha Levin {
354c797b6c6SAneesh Kumar K.V 	int i;
355bfc15268SAneesh Kumar K.V 	char *uname;
356bfc15268SAneesh Kumar K.V 	char *aname;
3571c7850f9SSasha Levin 	struct stat st;
358bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
3591c7850f9SSasha Levin 	struct p9_fid *fid;
360c797b6c6SAneesh Kumar K.V 	u32 fid_val, afid, uid;
361bfc15268SAneesh Kumar K.V 
362c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
363c797b6c6SAneesh Kumar K.V 			    &uname, &aname, &uid);
3641c7850f9SSasha Levin 
36539257180SPekka Enberg 	free(uname);
36639257180SPekka Enberg 	free(aname);
36739257180SPekka Enberg 
3681c7850f9SSasha Levin 	/* Reset everything */
3695529bcd7SAsias He 	for (i = 0; i < VIRTIO_9P_MAX_FID; i++)
370b4422bf3SAneesh Kumar K.V 		p9dev->fids[i].fid = P9_NOFID;
3711c7850f9SSasha Levin 
37230204a77SAneesh Kumar K.V 	if (lstat(p9dev->root_dir, &st) < 0)
3736c8ca053SAneesh Kumar K.V 		goto err_out;
3741c7850f9SSasha Levin 
375c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
3761c7850f9SSasha Levin 
37731a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
378bfc15268SAneesh Kumar K.V 	fid->fid = fid_val;
379c797b6c6SAneesh Kumar K.V 	fid->uid = uid;
3801c7850f9SSasha Levin 	fid->is_dir = 1;
3811c7850f9SSasha Levin 	strcpy(fid->path, "/");
3821c7850f9SSasha Levin 
383bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
384bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
385bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
3866c8ca053SAneesh Kumar K.V 	return;
3876c8ca053SAneesh Kumar K.V err_out:
3886c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
389ead43b01SAneesh Kumar K.V 	return;
3901c7850f9SSasha Levin }
3911c7850f9SSasha Levin 
392c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev,
393c797b6c6SAneesh Kumar K.V 				struct stat *st, struct p9_stat_dotl *statl)
3945f900f6dSSasha Levin {
395c797b6c6SAneesh Kumar K.V 	memset(statl, 0, sizeof(*statl));
396c797b6c6SAneesh Kumar K.V 	statl->st_mode		= st->st_mode;
397c797b6c6SAneesh Kumar K.V 	statl->st_nlink		= st->st_nlink;
398c797b6c6SAneesh Kumar K.V 	statl->st_uid		= st->st_uid;
399c797b6c6SAneesh Kumar K.V 	statl->st_gid		= st->st_gid;
400c797b6c6SAneesh Kumar K.V 	statl->st_rdev		= st->st_rdev;
401c797b6c6SAneesh Kumar K.V 	statl->st_size		= st->st_size;
402c797b6c6SAneesh Kumar K.V 	statl->st_blksize	= st->st_blksize;
403c797b6c6SAneesh Kumar K.V 	statl->st_blocks	= st->st_blocks;
404c797b6c6SAneesh Kumar K.V 	statl->st_atime_sec	= st->st_atime;
405c797b6c6SAneesh Kumar K.V 	statl->st_atime_nsec	= st->st_atim.tv_nsec;
406c797b6c6SAneesh Kumar K.V 	statl->st_mtime_sec	= st->st_mtime;
407c797b6c6SAneesh Kumar K.V 	statl->st_mtime_nsec	= st->st_mtim.tv_nsec;
408c797b6c6SAneesh Kumar K.V 	statl->st_ctime_sec	= st->st_ctime;
409c797b6c6SAneesh Kumar K.V 	statl->st_ctime_nsec	= st->st_ctim.tv_nsec;
410c797b6c6SAneesh Kumar K.V 	/* Currently we only support BASIC fields in stat */
411c797b6c6SAneesh Kumar K.V 	statl->st_result_mask	= P9_STATS_BASIC;
412c797b6c6SAneesh Kumar K.V 	stat2qid(st, &statl->qid);
4131c7850f9SSasha Levin }
4141c7850f9SSasha Levin 
415ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev,
416af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
4171c7850f9SSasha Levin {
418bfc15268SAneesh Kumar K.V 	u64 offset;
419bfc15268SAneesh Kumar K.V 	u32 fid_val;
420c797b6c6SAneesh Kumar K.V 	u16 iov_cnt;
421c797b6c6SAneesh Kumar K.V 	void *iov_base;
422c797b6c6SAneesh Kumar K.V 	size_t iov_len;
423bfc15268SAneesh Kumar K.V 	u32 count, rcount;
424bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
425c797b6c6SAneesh Kumar K.V 
4261c7850f9SSasha Levin 
427bfc15268SAneesh Kumar K.V 	rcount = 0;
428bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
42931a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
43050c479e0SAneesh Kumar K.V 
43150c479e0SAneesh Kumar K.V 	iov_base = pdu->in_iov[0].iov_base;
43250c479e0SAneesh Kumar K.V 	iov_len  = pdu->in_iov[0].iov_len;
43350c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->in_iov_cnt;
4345529bcd7SAsias He 	pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
4355529bcd7SAsias He 	pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
4366b163a87SAneesh Kumar K.V 	pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
437bfc15268SAneesh Kumar K.V 						   count,
4386b163a87SAneesh Kumar K.V 						   pdu->in_iov_cnt);
439bfc15268SAneesh Kumar K.V 	rcount = preadv(fid->fd, pdu->in_iov,
440bfc15268SAneesh Kumar K.V 			pdu->in_iov_cnt, offset);
441bfc15268SAneesh Kumar K.V 	if (rcount > count)
442bfc15268SAneesh Kumar K.V 		rcount = count;
443bfc15268SAneesh Kumar K.V 	/*
444bfc15268SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
445bfc15268SAneesh Kumar K.V 	 * pdu_writef works correctly.
446bfc15268SAneesh Kumar K.V 	 */
44750c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_base = iov_base;
44850c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_len  = iov_len;
44950c479e0SAneesh Kumar K.V 	pdu->in_iov_cnt         = iov_cnt;
450c797b6c6SAneesh Kumar K.V 
4515529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
452bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
453bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
454bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
455ead43b01SAneesh Kumar K.V 	return;
4561c7850f9SSasha Levin }
4571c7850f9SSasha Levin 
458c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent)
459c797b6c6SAneesh Kumar K.V {
460c797b6c6SAneesh Kumar K.V 	/*
461c797b6c6SAneesh Kumar K.V 	 * Size of each dirent:
462c797b6c6SAneesh Kumar K.V 	 * qid(13) + offset(8) + type(1) + name_len(2) + name
463c797b6c6SAneesh Kumar K.V 	 */
464c797b6c6SAneesh Kumar K.V 	return 24 + strlen(dent->d_name);
465c797b6c6SAneesh Kumar K.V }
466c797b6c6SAneesh Kumar K.V 
467c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev,
468c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
469c797b6c6SAneesh Kumar K.V {
470c797b6c6SAneesh Kumar K.V 	u32 fid_val;
471c797b6c6SAneesh Kumar K.V 	u32 count, rcount;
472c797b6c6SAneesh Kumar K.V 	struct stat st;
473c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
474c797b6c6SAneesh Kumar K.V 	struct dirent *dent;
475c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
476c797b6c6SAneesh Kumar K.V 	u64 offset, old_offset;
477c797b6c6SAneesh Kumar K.V 
478c797b6c6SAneesh Kumar K.V 	rcount = 0;
479c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
48031a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
481c797b6c6SAneesh Kumar K.V 
482c797b6c6SAneesh Kumar K.V 	if (!fid->is_dir) {
483c797b6c6SAneesh Kumar K.V 		errno = -EINVAL;
484c797b6c6SAneesh Kumar K.V 		goto err_out;
485c797b6c6SAneesh Kumar K.V 	}
486c797b6c6SAneesh Kumar K.V 
487c797b6c6SAneesh Kumar K.V 	/* Move the offset specified */
488c797b6c6SAneesh Kumar K.V 	seekdir(fid->dir, offset);
489c797b6c6SAneesh Kumar K.V 
490c797b6c6SAneesh Kumar K.V 	old_offset = offset;
491c797b6c6SAneesh Kumar K.V 	/* If reading a dir, fill the buffer with p9_stat entries */
492c797b6c6SAneesh Kumar K.V 	dent = readdir(fid->dir);
493c797b6c6SAneesh Kumar K.V 
494c797b6c6SAneesh Kumar K.V 	/* Skip the space for writing count */
495c797b6c6SAneesh Kumar K.V 	pdu->write_offset += sizeof(u32);
496c797b6c6SAneesh Kumar K.V 	while (dent) {
497c797b6c6SAneesh Kumar K.V 		u32 read;
498c797b6c6SAneesh Kumar K.V 		struct p9_qid qid;
499c797b6c6SAneesh Kumar K.V 
500c797b6c6SAneesh Kumar K.V 		if ((rcount + virtio_p9_dentry_size(dent)) > count) {
501c797b6c6SAneesh Kumar K.V 			/* seek to the previous offset and return */
502c797b6c6SAneesh Kumar K.V 			seekdir(fid->dir, old_offset);
503c797b6c6SAneesh Kumar K.V 			break;
504c797b6c6SAneesh Kumar K.V 		}
505c797b6c6SAneesh Kumar K.V 		old_offset = dent->d_off;
506c797b6c6SAneesh Kumar K.V 		lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st);
507c797b6c6SAneesh Kumar K.V 		stat2qid(&st, &qid);
508c797b6c6SAneesh Kumar K.V 		read = pdu->write_offset;
509c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
510c797b6c6SAneesh Kumar K.V 				     dent->d_type, dent->d_name);
511c797b6c6SAneesh Kumar K.V 		rcount += pdu->write_offset - read;
512c797b6c6SAneesh Kumar K.V 		dent = readdir(fid->dir);
513c797b6c6SAneesh Kumar K.V 	}
514c797b6c6SAneesh Kumar K.V 
5155529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
516c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
517c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
518c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
519c797b6c6SAneesh Kumar K.V 	return;
520c797b6c6SAneesh Kumar K.V err_out:
521c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
522c797b6c6SAneesh Kumar K.V 	return;
523c797b6c6SAneesh Kumar K.V }
524c797b6c6SAneesh Kumar K.V 
525c797b6c6SAneesh Kumar K.V 
526c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev,
527af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
5281c7850f9SSasha Levin {
529bfc15268SAneesh Kumar K.V 	u32 fid_val;
530af045e53SAneesh Kumar K.V 	struct stat st;
531c797b6c6SAneesh Kumar K.V 	u64 request_mask;
532bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
533c797b6c6SAneesh Kumar K.V 	struct p9_stat_dotl statl;
5341c7850f9SSasha Levin 
535c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
53631a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
53730204a77SAneesh Kumar K.V 	if (lstat(fid->abs_path, &st) < 0)
5386c8ca053SAneesh Kumar K.V 		goto err_out;
5391c7850f9SSasha Levin 
540c797b6c6SAneesh Kumar K.V 	virtio_p9_fill_stat(p9dev, &st, &statl);
541c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "A", &statl);
542bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
543bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
544ead43b01SAneesh Kumar K.V 	return;
5456c8ca053SAneesh Kumar K.V err_out:
5466c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
5476c8ca053SAneesh Kumar K.V 	return;
5481c7850f9SSasha Levin }
5491c7850f9SSasha Levin 
550c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */
551c797b6c6SAneesh Kumar K.V /*
552c797b6c6SAneesh Kumar K.V  * Attribute flags.  These should be or-ed together to figure out what
553c797b6c6SAneesh Kumar K.V  * has been changed!
554c797b6c6SAneesh Kumar K.V  */
555c797b6c6SAneesh Kumar K.V #define ATTR_MODE	(1 << 0)
556c797b6c6SAneesh Kumar K.V #define ATTR_UID	(1 << 1)
557c797b6c6SAneesh Kumar K.V #define ATTR_GID	(1 << 2)
558c797b6c6SAneesh Kumar K.V #define ATTR_SIZE	(1 << 3)
559c797b6c6SAneesh Kumar K.V #define ATTR_ATIME	(1 << 4)
560c797b6c6SAneesh Kumar K.V #define ATTR_MTIME	(1 << 5)
561c797b6c6SAneesh Kumar K.V #define ATTR_CTIME	(1 << 6)
562c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET	(1 << 7)
563c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET	(1 << 8)
564c797b6c6SAneesh Kumar K.V #define ATTR_FORCE	(1 << 9) /* Not a change, but a change it */
565c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG	(1 << 10)
566c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID	(1 << 11)
567c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID	(1 << 12)
568c797b6c6SAneesh Kumar K.V #define ATTR_FILE	(1 << 13)
569c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV	(1 << 14)
570c797b6c6SAneesh Kumar K.V #define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
571c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET	(1 << 16)
572c797b6c6SAneesh Kumar K.V 
573c797b6c6SAneesh Kumar K.V #define ATTR_MASK    127
574c797b6c6SAneesh Kumar K.V 
575c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev,
576af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
5771c7850f9SSasha Levin {
578c797b6c6SAneesh Kumar K.V 	int ret = 0;
579bfc15268SAneesh Kumar K.V 	u32 fid_val;
580bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
581c797b6c6SAneesh Kumar K.V 	struct p9_iattr_dotl p9attr;
5821c7850f9SSasha Levin 
583c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
58431a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
5851c7850f9SSasha Levin 
586c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & ATTR_MODE) {
587c797b6c6SAneesh Kumar K.V 		ret = chmod(fid->abs_path, p9attr.mode);
588c797b6c6SAneesh Kumar K.V 		if (ret < 0)
589c797b6c6SAneesh Kumar K.V 			goto err_out;
590c797b6c6SAneesh Kumar K.V 	}
591c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
592c797b6c6SAneesh Kumar K.V 		struct timespec times[2];
593c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_ATIME) {
594c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_ATIME_SET) {
595c797b6c6SAneesh Kumar K.V 				times[0].tv_sec = p9attr.atime_sec;
596c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = p9attr.atime_nsec;
597c797b6c6SAneesh Kumar K.V 			} else {
598c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = UTIME_NOW;
599c797b6c6SAneesh Kumar K.V 			}
600c797b6c6SAneesh Kumar K.V 		} else {
601c797b6c6SAneesh Kumar K.V 			times[0].tv_nsec = UTIME_OMIT;
602c797b6c6SAneesh Kumar K.V 		}
603c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_MTIME) {
604c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_MTIME_SET) {
605c797b6c6SAneesh Kumar K.V 				times[1].tv_sec = p9attr.mtime_sec;
606c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = p9attr.mtime_nsec;
607c797b6c6SAneesh Kumar K.V 			} else {
608c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = UTIME_NOW;
609c797b6c6SAneesh Kumar K.V 			}
610c797b6c6SAneesh Kumar K.V 		} else
611c797b6c6SAneesh Kumar K.V 			times[1].tv_nsec = UTIME_OMIT;
612c797b6c6SAneesh Kumar K.V 
613c797b6c6SAneesh Kumar K.V 		ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
614c797b6c6SAneesh Kumar K.V 		if (ret < 0)
615c797b6c6SAneesh Kumar K.V 			goto err_out;
616c797b6c6SAneesh Kumar K.V 	}
617c797b6c6SAneesh Kumar K.V 	/*
618c797b6c6SAneesh Kumar K.V 	 * If the only valid entry in iattr is ctime we can call
619c797b6c6SAneesh Kumar K.V 	 * chown(-1,-1) to update the ctime of the file
620c797b6c6SAneesh Kumar K.V 	 */
621c797b6c6SAneesh Kumar K.V 	if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
622c797b6c6SAneesh Kumar K.V 	    ((p9attr.valid & ATTR_CTIME)
623c797b6c6SAneesh Kumar K.V 	     && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
624c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_UID))
625c797b6c6SAneesh Kumar K.V 			p9attr.uid = -1;
626c797b6c6SAneesh Kumar K.V 
627c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_GID))
628c797b6c6SAneesh Kumar K.V 			p9attr.gid = -1;
629c797b6c6SAneesh Kumar K.V 
630c797b6c6SAneesh Kumar K.V 		ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid);
631c797b6c6SAneesh Kumar K.V 		if (ret < 0)
632c797b6c6SAneesh Kumar K.V 			goto err_out;
633c797b6c6SAneesh Kumar K.V 	}
634c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_SIZE)) {
635c797b6c6SAneesh Kumar K.V 		ret = truncate(fid->abs_path, p9attr.size);
636c797b6c6SAneesh Kumar K.V 		if (ret < 0)
637c797b6c6SAneesh Kumar K.V 			goto err_out;
638c797b6c6SAneesh Kumar K.V 	}
6395529bcd7SAsias He 	*outlen = VIRTIO_9P_HDR_LEN;
640bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
641ead43b01SAneesh Kumar K.V 	return;
6424bc9734aSAneesh Kumar K.V err_out:
6434bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
6444bc9734aSAneesh Kumar K.V 	return;
6451c7850f9SSasha Levin }
6461c7850f9SSasha Levin 
647ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev,
648af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
6491c7850f9SSasha Levin {
6504bc9734aSAneesh Kumar K.V 
651bfc15268SAneesh Kumar K.V 	u64 offset;
652bfc15268SAneesh Kumar K.V 	u32 fid_val;
6534bc9734aSAneesh Kumar K.V 	u32 count;
6544bc9734aSAneesh Kumar K.V 	ssize_t res;
65550c479e0SAneesh Kumar K.V 	u16 iov_cnt;
65650c479e0SAneesh Kumar K.V 	void *iov_base;
65750c479e0SAneesh Kumar K.V 	size_t iov_len;
658bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
659b064b05aSAneesh Kumar K.V 	/* u32 fid + u64 offset + u32 count */
660b064b05aSAneesh Kumar K.V 	int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
6611c7850f9SSasha Levin 
662bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
66331a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
664af045e53SAneesh Kumar K.V 
66550c479e0SAneesh Kumar K.V 	iov_base = pdu->out_iov[0].iov_base;
66650c479e0SAneesh Kumar K.V 	iov_len  = pdu->out_iov[0].iov_len;
66750c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->out_iov_cnt;
66850c479e0SAneesh Kumar K.V 
669bfc15268SAneesh Kumar K.V 	/* Adjust the iovec to skip the header and meta data */
670b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
671b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
672bfc15268SAneesh Kumar K.V 	pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
6736b163a87SAneesh Kumar K.V 						    pdu->out_iov_cnt);
6744bc9734aSAneesh Kumar K.V 	res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
67550c479e0SAneesh Kumar K.V 	/*
67650c479e0SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
67750c479e0SAneesh Kumar K.V 	 * pdu_readf works correctly.
67850c479e0SAneesh Kumar K.V 	 */
67950c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_base = iov_base;
68050c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_len  = iov_len;
68150c479e0SAneesh Kumar K.V 	pdu->out_iov_cnt         = iov_cnt;
682c797b6c6SAneesh Kumar K.V 
6834bc9734aSAneesh Kumar K.V 	if (res < 0)
6844bc9734aSAneesh Kumar K.V 		goto err_out;
6854bc9734aSAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", res);
686bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
687bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
688ead43b01SAneesh Kumar K.V 	return;
6894bc9734aSAneesh Kumar K.V err_out:
6904bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
6914bc9734aSAneesh Kumar K.V 	return;
6921c7850f9SSasha Levin }
6931c7850f9SSasha Levin 
6946fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev,
6956fc5cd9bSSasha Levin 			     struct p9_pdu *pdu, u32 *outlen)
6966fc5cd9bSSasha Levin {
6976fc5cd9bSSasha Levin 	int ret;
6986fc5cd9bSSasha Levin 	u32 fid_val;
6996fc5cd9bSSasha Levin 	struct p9_fid *fid;
7006fc5cd9bSSasha Levin 
7016fc5cd9bSSasha Levin 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
70231a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
7036fc5cd9bSSasha Levin 
7049b604a9cSSasha Levin 	ret = remove(fid->abs_path);
7056fc5cd9bSSasha Levin 	if (ret < 0)
7066fc5cd9bSSasha Levin 		goto err_out;
7076fc5cd9bSSasha Levin 	*outlen = pdu->write_offset;
7086fc5cd9bSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
7096fc5cd9bSSasha Levin 	return;
7106fc5cd9bSSasha Levin 
7116fc5cd9bSSasha Levin err_out:
7126fc5cd9bSSasha Levin 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
7136fc5cd9bSSasha Levin 	return;
7146fc5cd9bSSasha Levin }
7156fc5cd9bSSasha Levin 
716f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev,
717f161f28bSSasha Levin 			     struct p9_pdu *pdu, u32 *outlen)
718f161f28bSSasha Levin {
719f161f28bSSasha Levin 	int ret;
720f161f28bSSasha Levin 	u32 fid_val, new_fid_val;
721f161f28bSSasha Levin 	struct p9_fid *fid, *new_fid;
722f161f28bSSasha Levin 	char full_path[PATH_MAX], *new_name;
723f161f28bSSasha Levin 
724f161f28bSSasha Levin 	virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
72531a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
72631a6fb8dSSasha Levin 	new_fid = get_fid(p9dev, new_fid_val);
727f161f28bSSasha Levin 
728f161f28bSSasha Levin 	sprintf(full_path, "%s/%s", new_fid->abs_path, new_name);
729f161f28bSSasha Levin 	ret = rename(fid->abs_path, full_path);
730f161f28bSSasha Levin 	if (ret < 0)
731f161f28bSSasha Levin 		goto err_out;
732f161f28bSSasha Levin 	close_fid(p9dev, fid_val);
733f161f28bSSasha Levin 	*outlen = pdu->write_offset;
734f161f28bSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
735f161f28bSSasha Levin 	return;
736f161f28bSSasha Levin 
737f161f28bSSasha Levin err_out:
738f161f28bSSasha Levin 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
739f161f28bSSasha Levin 	return;
740f161f28bSSasha Levin }
741f161f28bSSasha Levin 
742c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev,
743c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
744c797b6c6SAneesh Kumar K.V {
745c797b6c6SAneesh Kumar K.V 	int ret;
746c797b6c6SAneesh Kumar K.V 	u32 fid_val;
747c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
748c797b6c6SAneesh Kumar K.V 	char target_path[PATH_MAX];
749c797b6c6SAneesh Kumar K.V 
750c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
75131a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
752c797b6c6SAneesh Kumar K.V 
753c797b6c6SAneesh Kumar K.V 	memset(target_path, 0, PATH_MAX);
754c797b6c6SAneesh Kumar K.V 	ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
755c797b6c6SAneesh Kumar K.V 	if (ret < 0)
756c797b6c6SAneesh Kumar K.V 		goto err_out;
757c797b6c6SAneesh Kumar K.V 
758c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "s", target_path);
759c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
760c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
761c797b6c6SAneesh Kumar K.V 	return;
762c797b6c6SAneesh Kumar K.V err_out:
763c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
764c797b6c6SAneesh Kumar K.V 	return;
765c797b6c6SAneesh Kumar K.V }
766c797b6c6SAneesh Kumar K.V 
767c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev,
768c797b6c6SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
769c797b6c6SAneesh Kumar K.V {
770c797b6c6SAneesh Kumar K.V 	int ret;
771c797b6c6SAneesh Kumar K.V 	u64 fsid;
772c797b6c6SAneesh Kumar K.V 	u32 fid_val;
773c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
774c797b6c6SAneesh Kumar K.V 	struct statfs stat_buf;
775c797b6c6SAneesh Kumar K.V 
776c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
77731a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
778c797b6c6SAneesh Kumar K.V 
779c797b6c6SAneesh Kumar K.V 	ret = statfs(fid->abs_path, &stat_buf);
780c797b6c6SAneesh Kumar K.V 	if (ret < 0)
781c797b6c6SAneesh Kumar K.V 		goto err_out;
782c797b6c6SAneesh Kumar K.V 	/* FIXME!! f_blocks needs update based on client msize */
783c797b6c6SAneesh Kumar K.V 	fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
784c797b6c6SAneesh Kumar K.V 		(unsigned long long)stat_buf.f_fsid.__val[1] << 32;
785c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
786c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bsize, stat_buf.f_blocks,
787c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bfree, stat_buf.f_bavail,
788c797b6c6SAneesh Kumar K.V 			     stat_buf.f_files, stat_buf.f_ffree,
789c797b6c6SAneesh Kumar K.V 			     fsid, stat_buf.f_namelen);
790c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
791c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
792c797b6c6SAneesh Kumar K.V 	return;
793c797b6c6SAneesh Kumar K.V err_out:
794c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
795c797b6c6SAneesh Kumar K.V 	return;
796c797b6c6SAneesh Kumar K.V }
797c797b6c6SAneesh Kumar K.V 
798c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev,
799c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
800c797b6c6SAneesh Kumar K.V {
801c797b6c6SAneesh Kumar K.V 	int ret;
802c797b6c6SAneesh Kumar K.V 	char *name;
803c797b6c6SAneesh Kumar K.V 	struct stat st;
804c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
805c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
806c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
807c797b6c6SAneesh Kumar K.V 	u32 fid_val, mode, major, minor, gid;
808c797b6c6SAneesh Kumar K.V 
809c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
810c797b6c6SAneesh Kumar K.V 			    &major, &minor, &gid);
811c797b6c6SAneesh Kumar K.V 
81231a6fb8dSSasha Levin 	dfid = get_fid(p9dev, fid_val);
813c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
814c797b6c6SAneesh Kumar K.V 	ret = mknod(full_path, mode, makedev(major, minor));
815c797b6c6SAneesh Kumar K.V 	if (ret < 0)
816c797b6c6SAneesh Kumar K.V 		goto err_out;
817c797b6c6SAneesh Kumar K.V 
818c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
819c797b6c6SAneesh Kumar K.V 		goto err_out;
820c797b6c6SAneesh Kumar K.V 
821c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
822c797b6c6SAneesh Kumar K.V 	if (ret < 0)
823c797b6c6SAneesh Kumar K.V 		goto err_out;
824c797b6c6SAneesh Kumar K.V 
825c797b6c6SAneesh Kumar K.V 	ret = lchown(full_path, dfid->uid, gid);
826c797b6c6SAneesh Kumar K.V 	if (ret < 0)
827c797b6c6SAneesh Kumar K.V 		goto err_out;
828c797b6c6SAneesh Kumar K.V 
829c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
830c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
831c797b6c6SAneesh Kumar K.V 	free(name);
832c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
833c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
834c797b6c6SAneesh Kumar K.V 	return;
835c797b6c6SAneesh Kumar K.V err_out:
836c797b6c6SAneesh Kumar K.V 	free(name);
837c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
838c797b6c6SAneesh Kumar K.V 	return;
839c797b6c6SAneesh Kumar K.V }
840c797b6c6SAneesh Kumar K.V 
841c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev,
842c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
843c797b6c6SAneesh Kumar K.V {
844c797b6c6SAneesh Kumar K.V 	int ret;
845c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
846c797b6c6SAneesh Kumar K.V 	u32 fid_val, datasync;
847c797b6c6SAneesh Kumar K.V 
848c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
84931a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
850c797b6c6SAneesh Kumar K.V 
851c797b6c6SAneesh Kumar K.V 	if (datasync)
852c797b6c6SAneesh Kumar K.V 		ret = fdatasync(fid->fd);
853c797b6c6SAneesh Kumar K.V 	else
854c797b6c6SAneesh Kumar K.V 		ret = fsync(fid->fd);
855c797b6c6SAneesh Kumar K.V 	if (ret < 0)
856c797b6c6SAneesh Kumar K.V 		goto err_out;
857c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
858c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
859c797b6c6SAneesh Kumar K.V 	return;
860c797b6c6SAneesh Kumar K.V err_out:
861c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
862c797b6c6SAneesh Kumar K.V 	return;
863c797b6c6SAneesh Kumar K.V }
864c797b6c6SAneesh Kumar K.V 
865c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev,
866c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
867c797b6c6SAneesh Kumar K.V {
868c797b6c6SAneesh Kumar K.V 	int ret;
869c797b6c6SAneesh Kumar K.V 	struct stat st;
870c797b6c6SAneesh Kumar K.V 	u32 fid_val, gid;
871c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
872c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
873c797b6c6SAneesh Kumar K.V 	char new_name[PATH_MAX];
874c797b6c6SAneesh Kumar K.V 	char *old_path, *name;
875c797b6c6SAneesh Kumar K.V 
876c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
877c797b6c6SAneesh Kumar K.V 
87831a6fb8dSSasha Levin 	dfid = get_fid(p9dev, fid_val);
879c797b6c6SAneesh Kumar K.V 	sprintf(new_name, "%s/%s", dfid->abs_path, name);
880c797b6c6SAneesh Kumar K.V 	ret = symlink(old_path, new_name);
881c797b6c6SAneesh Kumar K.V 	if (ret < 0)
882c797b6c6SAneesh Kumar K.V 		goto err_out;
883c797b6c6SAneesh Kumar K.V 
884c797b6c6SAneesh Kumar K.V 	if (lstat(new_name, &st) < 0)
885c797b6c6SAneesh Kumar K.V 		goto err_out;
886c797b6c6SAneesh Kumar K.V 
887c797b6c6SAneesh Kumar K.V 	ret = lchown(new_name, dfid->uid, gid);
888c797b6c6SAneesh Kumar K.V 	if (ret < 0)
889c797b6c6SAneesh Kumar K.V 		goto err_out;
890c797b6c6SAneesh Kumar K.V 
891c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
892c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
893c797b6c6SAneesh Kumar K.V 	free(name);
894c797b6c6SAneesh Kumar K.V 	free(old_path);
895c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
896c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
897c797b6c6SAneesh Kumar K.V 	return;
898c797b6c6SAneesh Kumar K.V err_out:
899c797b6c6SAneesh Kumar K.V 	free(name);
900c797b6c6SAneesh Kumar K.V 	free(old_path);
901c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
902c797b6c6SAneesh Kumar K.V 	return;
903c797b6c6SAneesh Kumar K.V }
904c797b6c6SAneesh Kumar K.V 
905c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev,
906c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
907c797b6c6SAneesh Kumar K.V {
908c797b6c6SAneesh Kumar K.V 	int ret;
909c797b6c6SAneesh Kumar K.V 	char *name;
910c797b6c6SAneesh Kumar K.V 	u32 fid_val, dfid_val;
911c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid, *fid;
912c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
913c797b6c6SAneesh Kumar K.V 
914c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
915c797b6c6SAneesh Kumar K.V 
91631a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
91731a6fb8dSSasha Levin 	fid =  get_fid(p9dev, fid_val);
918c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
919c797b6c6SAneesh Kumar K.V 	ret = link(fid->abs_path, full_path);
920c797b6c6SAneesh Kumar K.V 	if (ret < 0)
921c797b6c6SAneesh Kumar K.V 		goto err_out;
922c797b6c6SAneesh Kumar K.V 	free(name);
923c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
924c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
925c797b6c6SAneesh Kumar K.V 	return;
926c797b6c6SAneesh Kumar K.V err_out:
927c797b6c6SAneesh Kumar K.V 	free(name);
928c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
929c797b6c6SAneesh Kumar K.V 	return;
930c797b6c6SAneesh Kumar K.V 
931c797b6c6SAneesh Kumar K.V }
932c797b6c6SAneesh Kumar K.V 
933c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev,
934c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
935c797b6c6SAneesh Kumar K.V {
936c797b6c6SAneesh Kumar K.V 	u8 ret;
937c797b6c6SAneesh Kumar K.V 	u32 fid_val;
938c797b6c6SAneesh Kumar K.V 	struct p9_flock flock;
939c797b6c6SAneesh Kumar K.V 
940c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
941c797b6c6SAneesh Kumar K.V 			    &flock.flags, &flock.start, &flock.length,
942c797b6c6SAneesh Kumar K.V 			    &flock.proc_id, &flock.client_id);
943c797b6c6SAneesh Kumar K.V 
944c797b6c6SAneesh Kumar K.V 	/* Just return success */
945c797b6c6SAneesh Kumar K.V 	ret = P9_LOCK_SUCCESS;
946c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", ret);
947c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
948c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
949c797b6c6SAneesh Kumar K.V 	free(flock.client_id);
950c797b6c6SAneesh Kumar K.V 	return;
951c797b6c6SAneesh Kumar K.V }
952c797b6c6SAneesh Kumar K.V 
953c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev,
954c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
955c797b6c6SAneesh Kumar K.V {
956c797b6c6SAneesh Kumar K.V 	u32 fid_val;
957c797b6c6SAneesh Kumar K.V 	struct p9_getlock glock;
958c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
959c797b6c6SAneesh Kumar K.V 			    &glock.start, &glock.length, &glock.proc_id,
960c797b6c6SAneesh Kumar K.V 			    &glock.client_id);
961c797b6c6SAneesh Kumar K.V 
962c797b6c6SAneesh Kumar K.V 	/* Just return success */
963c797b6c6SAneesh Kumar K.V 	glock.type = F_UNLCK;
964c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
965c797b6c6SAneesh Kumar K.V 			     glock.start, glock.length, glock.proc_id,
966c797b6c6SAneesh Kumar K.V 			     glock.client_id);
967c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
968c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
969c797b6c6SAneesh Kumar K.V 	free(glock.client_id);
970c797b6c6SAneesh Kumar K.V 	return;
971c797b6c6SAneesh Kumar K.V }
972c797b6c6SAneesh Kumar K.V 
973c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor)
974c797b6c6SAneesh Kumar K.V {
975c797b6c6SAneesh Kumar K.V 	int size = strlen(ancestor);
976c797b6c6SAneesh Kumar K.V 	if (!strncmp(path, ancestor, size)) {
977c797b6c6SAneesh Kumar K.V 		/*
978c797b6c6SAneesh Kumar K.V 		 * Now check whether ancestor is a full name or
979c797b6c6SAneesh Kumar K.V 		 * or directory component and not just part
980c797b6c6SAneesh Kumar K.V 		 * of a name.
981c797b6c6SAneesh Kumar K.V 		 */
982c797b6c6SAneesh Kumar K.V 		if (path[size] == '\0' || path[size] == '/')
983c797b6c6SAneesh Kumar K.V 			return 1;
984c797b6c6SAneesh Kumar K.V 	}
985c797b6c6SAneesh Kumar K.V 	return 0;
986c797b6c6SAneesh Kumar K.V }
987c797b6c6SAneesh Kumar K.V 
988c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name)
989c797b6c6SAneesh Kumar K.V {
990c797b6c6SAneesh Kumar K.V 	char tmp_name[PATH_MAX];
991c797b6c6SAneesh Kumar K.V 	size_t rp_sz = strlen(old_name);
992c797b6c6SAneesh Kumar K.V 
993c797b6c6SAneesh Kumar K.V 	if (rp_sz == strlen(fid_path)) {
994c797b6c6SAneesh Kumar K.V 		/* replace the full name */
995c797b6c6SAneesh Kumar K.V 		strcpy(fid_path, new_name);
996c797b6c6SAneesh Kumar K.V 		return;
997c797b6c6SAneesh Kumar K.V 	}
998c797b6c6SAneesh Kumar K.V 	/* save the trailing path details */
999c797b6c6SAneesh Kumar K.V 	strcpy(tmp_name, fid_path + rp_sz);
1000c797b6c6SAneesh Kumar K.V 	sprintf(fid_path, "%s%s", new_name, tmp_name);
1001c797b6c6SAneesh Kumar K.V 	return;
1002c797b6c6SAneesh Kumar K.V }
1003c797b6c6SAneesh Kumar K.V 
1004c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev,
1005c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
1006c797b6c6SAneesh Kumar K.V {
1007c797b6c6SAneesh Kumar K.V 	int i, ret;
1008c797b6c6SAneesh Kumar K.V 	char *old_name, *new_name;
1009c797b6c6SAneesh Kumar K.V 	u32 old_dfid_val, new_dfid_val;
1010c797b6c6SAneesh Kumar K.V 	struct p9_fid *old_dfid, *new_dfid;
1011c797b6c6SAneesh Kumar K.V 	char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
1012c797b6c6SAneesh Kumar K.V 
1013c797b6c6SAneesh Kumar K.V 
1014c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
1015c797b6c6SAneesh Kumar K.V 			    &new_dfid_val, &new_name);
1016c797b6c6SAneesh Kumar K.V 
101731a6fb8dSSasha Levin 	old_dfid = get_fid(p9dev, old_dfid_val);
101831a6fb8dSSasha Levin 	new_dfid = get_fid(p9dev, new_dfid_val);
1019c797b6c6SAneesh Kumar K.V 
1020c797b6c6SAneesh Kumar K.V 	sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name);
1021c797b6c6SAneesh Kumar K.V 	sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name);
1022c797b6c6SAneesh Kumar K.V 	ret = rename(old_full_path, new_full_path);
1023c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1024c797b6c6SAneesh Kumar K.V 		goto err_out;
1025c797b6c6SAneesh Kumar K.V 	/*
1026c797b6c6SAneesh Kumar K.V 	 * Now fix path in other fids, if the renamed path is part of
1027c797b6c6SAneesh Kumar K.V 	 * that.
1028c797b6c6SAneesh Kumar K.V 	 */
10295529bcd7SAsias He 	for (i = 0; i < VIRTIO_9P_MAX_FID; i++) {
103031a6fb8dSSasha Levin 		if (get_fid(p9dev, i)->fid != P9_NOFID &&
103131a6fb8dSSasha Levin 		    virtio_p9_ancestor(get_fid(p9dev, i)->path, old_name)) {
103231a6fb8dSSasha Levin 			virtio_p9_fix_path(get_fid(p9dev, i)->path, old_name,
1033c797b6c6SAneesh Kumar K.V 					   new_name);
1034c797b6c6SAneesh Kumar K.V 		}
1035c797b6c6SAneesh Kumar K.V 	}
1036c797b6c6SAneesh Kumar K.V 	free(old_name);
1037c797b6c6SAneesh Kumar K.V 	free(new_name);
1038c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1039c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1040c797b6c6SAneesh Kumar K.V 	return;
1041c797b6c6SAneesh Kumar K.V err_out:
1042c797b6c6SAneesh Kumar K.V 	free(old_name);
1043c797b6c6SAneesh Kumar K.V 	free(new_name);
1044c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1045c797b6c6SAneesh Kumar K.V 	return;
1046c797b6c6SAneesh Kumar K.V }
1047c797b6c6SAneesh Kumar K.V 
1048c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev,
1049c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
1050c797b6c6SAneesh Kumar K.V {
1051c797b6c6SAneesh Kumar K.V 	int ret;
1052c797b6c6SAneesh Kumar K.V 	char *name;
1053c797b6c6SAneesh Kumar K.V 	u32 fid_val, flags;
1054c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
1055c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
1056c797b6c6SAneesh Kumar K.V 
1057c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
105831a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
1059c797b6c6SAneesh Kumar K.V 
1060c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", fid->abs_path, name);
1061c797b6c6SAneesh Kumar K.V 	ret = remove(full_path);
1062c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1063c797b6c6SAneesh Kumar K.V 		goto err_out;
1064c797b6c6SAneesh Kumar K.V 	free(name);
1065c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1066c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1067c797b6c6SAneesh Kumar K.V 	return;
1068c797b6c6SAneesh Kumar K.V err_out:
1069c797b6c6SAneesh Kumar K.V 	free(name);
1070c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1071c797b6c6SAneesh Kumar K.V 	return;
1072c797b6c6SAneesh Kumar K.V }
1073c797b6c6SAneesh Kumar K.V 
1074c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
1075c797b6c6SAneesh Kumar K.V 				 struct p9_pdu *pdu, u32 *outlen)
1076c797b6c6SAneesh Kumar K.V {
1077c797b6c6SAneesh Kumar K.V 	return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
1078c797b6c6SAneesh Kumar K.V }
1079c797b6c6SAneesh Kumar K.V 
1080ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev,
1081af045e53SAneesh Kumar K.V 			struct p9_pdu *pdu, u32 *outlen);
1082b4422bf3SAneesh Kumar K.V 
1083c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */
1084c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74
1085c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76
1086c797b6c6SAneesh Kumar K.V 
1087c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = {
1088c797b6c6SAneesh Kumar K.V 	[P9_TREADDIR]     = virtio_p9_readdir,
1089c797b6c6SAneesh Kumar K.V 	[P9_TSTATFS]      = virtio_p9_statfs,
1090c797b6c6SAneesh Kumar K.V 	[P9_TGETATTR]     = virtio_p9_getattr,
1091c797b6c6SAneesh Kumar K.V 	[P9_TSETATTR]     = virtio_p9_setattr,
1092c797b6c6SAneesh Kumar K.V 	[P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
1093c797b6c6SAneesh Kumar K.V 	[P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
1094c797b6c6SAneesh Kumar K.V 	[P9_TMKNOD]       = virtio_p9_mknod,
1095c797b6c6SAneesh Kumar K.V 	[P9_TLOCK]        = virtio_p9_lock,
1096c797b6c6SAneesh Kumar K.V 	[P9_TGETLOCK]     = virtio_p9_getlock,
1097c797b6c6SAneesh Kumar K.V 	[P9_TRENAMEAT]    = virtio_p9_renameat,
1098c797b6c6SAneesh Kumar K.V 	[P9_TREADLINK]    = virtio_p9_readlink,
1099c797b6c6SAneesh Kumar K.V 	[P9_TUNLINKAT]    = virtio_p9_unlinkat,
1100c797b6c6SAneesh Kumar K.V 	[P9_TMKDIR]       = virtio_p9_mkdir,
1101b4422bf3SAneesh Kumar K.V 	[P9_TVERSION]     = virtio_p9_version,
1102c797b6c6SAneesh Kumar K.V 	[P9_TLOPEN]       = virtio_p9_open,
1103b4422bf3SAneesh Kumar K.V 	[P9_TATTACH]      = virtio_p9_attach,
1104b4422bf3SAneesh Kumar K.V 	[P9_TWALK]        = virtio_p9_walk,
1105c797b6c6SAneesh Kumar K.V 	[P9_TCLUNK]       = virtio_p9_clunk,
1106c797b6c6SAneesh Kumar K.V 	[P9_TFSYNC]       = virtio_p9_fsync,
1107b4422bf3SAneesh Kumar K.V 	[P9_TREAD]        = virtio_p9_read,
1108c797b6c6SAneesh Kumar K.V 	[P9_TFLUSH]       = virtio_p9_eopnotsupp,
1109c797b6c6SAneesh Kumar K.V 	[P9_TLINK]        = virtio_p9_link,
1110c797b6c6SAneesh Kumar K.V 	[P9_TSYMLINK]     = virtio_p9_symlink,
1111c797b6c6SAneesh Kumar K.V 	[P9_TLCREATE]     = virtio_p9_create,
1112b4422bf3SAneesh Kumar K.V 	[P9_TWRITE]       = virtio_p9_write,
11136fc5cd9bSSasha Levin 	[P9_TREMOVE]      = virtio_p9_remove,
1114f161f28bSSasha Levin 	[P9_TRENAME]      = virtio_p9_rename,
1115b4422bf3SAneesh Kumar K.V };
1116b4422bf3SAneesh Kumar K.V 
1117af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
1118af045e53SAneesh Kumar K.V {
1119af045e53SAneesh Kumar K.V 	struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
1120af045e53SAneesh Kumar K.V 	if (!pdu)
1121af045e53SAneesh Kumar K.V 		return NULL;
1122af045e53SAneesh Kumar K.V 
1123bfc15268SAneesh Kumar K.V 	/* skip the pdu header p9_msg */
11245529bcd7SAsias He 	pdu->read_offset	= VIRTIO_9P_HDR_LEN;
11255529bcd7SAsias He 	pdu->write_offset	= VIRTIO_9P_HDR_LEN;
1126af045e53SAneesh Kumar K.V 	pdu->queue_head		= virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
1127*a8a44649SAsias He 					pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
1128af045e53SAneesh Kumar K.V 	return pdu;
1129af045e53SAneesh Kumar K.V }
1130af045e53SAneesh Kumar K.V 
1131af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
1132af045e53SAneesh Kumar K.V {
1133af045e53SAneesh Kumar K.V 	struct p9_msg *msg;
1134af045e53SAneesh Kumar K.V 	/*
1135af045e53SAneesh Kumar K.V 	 * we can peek directly into pdu for a u8
1136af045e53SAneesh Kumar K.V 	 * value. The host endianess won't be an issue
1137af045e53SAneesh Kumar K.V 	 */
1138af045e53SAneesh Kumar K.V 	msg = pdu->out_iov[0].iov_base;
1139af045e53SAneesh Kumar K.V 	return msg->cmd;
1140af045e53SAneesh Kumar K.V }
1141af045e53SAneesh Kumar K.V 
1142b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
11431c7850f9SSasha Levin {
1144af045e53SAneesh Kumar K.V 	u8 cmd;
1145b4422bf3SAneesh Kumar K.V 	u32 len = 0;
1146b4422bf3SAneesh Kumar K.V 	p9_handler *handler;
1147b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev;
1148af045e53SAneesh Kumar K.V 	struct virt_queue *vq;
1149af045e53SAneesh Kumar K.V 	struct p9_pdu *p9pdu;
11501c7850f9SSasha Levin 
1151b4422bf3SAneesh Kumar K.V 	vq = job->vq;
1152b4422bf3SAneesh Kumar K.V 	p9dev = job->p9dev;
11531c7850f9SSasha Levin 
1154af045e53SAneesh Kumar K.V 	p9pdu = virtio_p9_pdu_init(kvm, vq);
1155af045e53SAneesh Kumar K.V 	cmd = virtio_p9_get_cmd(p9pdu);
1156af045e53SAneesh Kumar K.V 
1157c797b6c6SAneesh Kumar K.V 	if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
1158c797b6c6SAneesh Kumar K.V 	    !virtio_9p_dotl_handler[cmd])
115997b408afSAneesh Kumar K.V 		handler = virtio_p9_eopnotsupp;
1160dd78d9eaSAneesh Kumar K.V 	else
1161c797b6c6SAneesh Kumar K.V 		handler = virtio_9p_dotl_handler[cmd];
1162c797b6c6SAneesh Kumar K.V 
1163af045e53SAneesh Kumar K.V 	handler(p9dev, p9pdu, &len);
1164af045e53SAneesh Kumar K.V 	virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
1165af045e53SAneesh Kumar K.V 	free(p9pdu);
11661c7850f9SSasha Levin 	return true;
11671c7850f9SSasha Levin }
11681c7850f9SSasha Levin 
11691c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param)
11701c7850f9SSasha Levin {
1171b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job = (struct p9_dev_job *)param;
1172b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev   = job->p9dev;
1173b4422bf3SAneesh Kumar K.V 	struct virt_queue *vq  = job->vq;
11741c7850f9SSasha Levin 
11751c7850f9SSasha Levin 	while (virt_queue__available(vq)) {
1176b4422bf3SAneesh Kumar K.V 		virtio_p9_do_io_request(kvm, job);
117702eca50cSAsias He 		p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
11781c7850f9SSasha Levin 	}
11791c7850f9SSasha Levin }
11801c7850f9SSasha Levin 
1181c7838fbdSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
11821c7850f9SSasha Levin {
1183c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
11841c7850f9SSasha Levin 
1185c7838fbdSSasha Levin 	((u8 *)(p9dev->config))[offset] = data;
1186c7838fbdSSasha Levin }
11871c7850f9SSasha Levin 
1188c7838fbdSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
1189c7838fbdSSasha Levin {
1190c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1191c7838fbdSSasha Levin 
1192c7838fbdSSasha Levin 	return ((u8 *)(p9dev->config))[offset];
1193c7838fbdSSasha Levin }
1194c7838fbdSSasha Levin 
1195c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev)
1196c7838fbdSSasha Levin {
1197c7838fbdSSasha Levin 	return 1 << VIRTIO_9P_MOUNT_TAG;
1198c7838fbdSSasha Levin }
1199c7838fbdSSasha Levin 
1200c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
1201c7838fbdSSasha Levin {
1202c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1203c7838fbdSSasha Levin 
1204c7838fbdSSasha Levin 	p9dev->features = features;
1205c7838fbdSSasha Levin }
1206c7838fbdSSasha Levin 
1207c7838fbdSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
1208c7838fbdSSasha Levin {
1209c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1210b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job;
1211b4422bf3SAneesh Kumar K.V 	struct virt_queue *queue;
1212c7838fbdSSasha Levin 	void *p;
12131c7850f9SSasha Levin 
1214312c62d1SSasha Levin 	compat__remove_message(compat_id);
1215e59662b3SSasha Levin 
1216c7838fbdSSasha Levin 	queue		= &p9dev->vqs[vq];
1217c7838fbdSSasha Levin 	queue->pfn	= pfn;
12181c7850f9SSasha Levin 	p		= guest_pfn_to_host(kvm, queue->pfn);
1219c7838fbdSSasha Levin 	job		= &p9dev->jobs[vq];
12201c7850f9SSasha Levin 
1221c7838fbdSSasha Levin 	vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN);
12221c7850f9SSasha Levin 
1223b4422bf3SAneesh Kumar K.V 	*job		= (struct p9_dev_job) {
1224b4422bf3SAneesh Kumar K.V 		.vq		= queue,
1225b4422bf3SAneesh Kumar K.V 		.p9dev		= p9dev,
1226b4422bf3SAneesh Kumar K.V 	};
1227df0c7f57SSasha Levin 	thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
122860eb42d5SSasha Levin 
1229c7838fbdSSasha Levin 	return 0;
12301c7850f9SSasha Levin }
12311c7850f9SSasha Levin 
1232c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
1233c7838fbdSSasha Levin {
1234c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
12351c7850f9SSasha Levin 
1236c7838fbdSSasha Levin 	thread_pool__do_job(&p9dev->jobs[vq].job_id);
1237c7838fbdSSasha Levin 
1238c7838fbdSSasha Levin 	return 0;
1239c7838fbdSSasha Levin }
1240c7838fbdSSasha Levin 
1241c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
1242c7838fbdSSasha Levin {
1243c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1244c7838fbdSSasha Levin 
1245c7838fbdSSasha Levin 	return p9dev->vqs[vq].pfn;
1246c7838fbdSSasha Levin }
1247c7838fbdSSasha Levin 
1248c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
1249c7838fbdSSasha Levin {
1250c7838fbdSSasha Levin 	return VIRTQUEUE_NUM;
1251c7838fbdSSasha Levin }
1252c7838fbdSSasha Levin 
12531c47ce69SSasha Levin struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) {
1254c7838fbdSSasha Levin 	.set_config		= set_config,
1255c7838fbdSSasha Levin 	.get_config		= get_config,
1256c7838fbdSSasha Levin 	.get_host_features	= get_host_features,
1257c7838fbdSSasha Levin 	.set_guest_features	= set_guest_features,
1258c7838fbdSSasha Levin 	.init_vq		= init_vq,
1259c7838fbdSSasha Levin 	.notify_vq		= notify_vq,
1260c7838fbdSSasha Levin 	.get_pfn_vq		= get_pfn_vq,
1261c7838fbdSSasha Levin 	.get_size_vq		= get_size_vq,
1262c7838fbdSSasha Levin };
12631c47ce69SSasha Levin 
12641c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm)
12651c47ce69SSasha Levin {
12661c47ce69SSasha Levin 	struct p9_dev *p9dev;
12671c47ce69SSasha Levin 
12681c47ce69SSasha Levin 	list_for_each_entry(p9dev, &devs, list) {
126902eca50cSAsias He 		virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
12705529bcd7SAsias He 			    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_9P, VIRTIO_ID_9P, PCI_CLASS_9P);
1271c7838fbdSSasha Levin 	}
1272c7838fbdSSasha Levin 
1273c7838fbdSSasha Levin 	return 0;
1274c7838fbdSSasha Levin }
1275c7838fbdSSasha Levin 
1276c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
1277c7838fbdSSasha Levin {
1278c7838fbdSSasha Levin 	struct p9_dev *p9dev;
127954f6802dSPekka Enberg 	u32 i, root_len;
128054f6802dSPekka Enberg 	int err = 0;
12811c7850f9SSasha Levin 
1282b4422bf3SAneesh Kumar K.V 	p9dev = calloc(1, sizeof(*p9dev));
1283b4422bf3SAneesh Kumar K.V 	if (!p9dev)
128454f6802dSPekka Enberg 		return -ENOMEM;
128554f6802dSPekka Enberg 
1286b4422bf3SAneesh Kumar K.V 	if (!tag_name)
12875529bcd7SAsias He 		tag_name = VIRTIO_9P_DEFAULT_TAG;
128854f6802dSPekka Enberg 
1289b4422bf3SAneesh Kumar K.V 	p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1);
129054f6802dSPekka Enberg 	if (p9dev->config == NULL) {
129154f6802dSPekka Enberg 		err = -ENOMEM;
1292b4422bf3SAneesh Kumar K.V 		goto free_p9dev;
129354f6802dSPekka Enberg 	}
12941c7850f9SSasha Levin 
1295b4422bf3SAneesh Kumar K.V 	strcpy(p9dev->root_dir, root);
12961c7850f9SSasha Levin 	root_len = strlen(root);
12971c7850f9SSasha Levin 	/*
12981c7850f9SSasha Levin 	 * We prefix the full path in all fids, This allows us to get the
12991c7850f9SSasha Levin 	 * absolute path of an fid without playing with strings.
13001c7850f9SSasha Levin 	 */
13015529bcd7SAsias He 	for (i = 0; i < VIRTIO_9P_MAX_FID; i++) {
130231a6fb8dSSasha Levin 		strcpy(get_fid(p9dev, i)->abs_path, root);
130331a6fb8dSSasha Levin 		get_fid(p9dev, i)->path = get_fid(p9dev, i)->abs_path + root_len;
13041c7850f9SSasha Levin 	}
1305b4422bf3SAneesh Kumar K.V 	p9dev->config->tag_len = strlen(tag_name);
130654f6802dSPekka Enberg 	if (p9dev->config->tag_len > MAX_TAG_LEN) {
130754f6802dSPekka Enberg 		err = -EINVAL;
1308b4422bf3SAneesh Kumar K.V 		goto free_p9dev_config;
130954f6802dSPekka Enberg 	}
13101c7850f9SSasha Levin 
1311c7838fbdSSasha Levin 	memcpy(&p9dev->config->tag, tag_name, strlen(tag_name));
13121c7850f9SSasha Levin 
1313c7838fbdSSasha Levin 	list_add(&p9dev->list, &devs);
1314b4422bf3SAneesh Kumar K.V 
1315312c62d1SSasha Levin 	if (compat_id != -1)
1316312c62d1SSasha Levin 		compat_id = compat__add_message("virtio-9p device was not detected",
1317e59662b3SSasha Levin 						"While you have requested a virtio-9p device, "
1318fc835ab3SSasha Levin 						"the guest kernel did not initialize it.\n"
1319fc835ab3SSasha Levin 						"Please make sure that the guest kernel was "
1320fc835ab3SSasha Levin 						"compiled with CONFIG_NET_9P_VIRTIO=y enabled "
1321fc835ab3SSasha Levin 						"in its .config");
1322e59662b3SSasha Levin 
132354f6802dSPekka Enberg 	return err;
132454f6802dSPekka Enberg 
1325b4422bf3SAneesh Kumar K.V free_p9dev_config:
1326b4422bf3SAneesh Kumar K.V 	free(p9dev->config);
1327b4422bf3SAneesh Kumar K.V free_p9dev:
1328b4422bf3SAneesh Kumar K.V 	free(p9dev);
132954f6802dSPekka Enberg 	return err;
13301c7850f9SSasha Levin }
1331