xref: /kvmtool/virtio/9p.c (revision d97dadecbd7744cd7fc1cac470e09a22b0a7ebef)
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"
8cac9e8fdSSasha Levin #include "kvm/builtin-setup.h"
91c7850f9SSasha Levin 
10bfc15268SAneesh Kumar K.V #include <stdio.h>
11bfc15268SAneesh Kumar K.V #include <stdlib.h>
121c7850f9SSasha Levin #include <fcntl.h>
131c7850f9SSasha Levin #include <sys/stat.h>
14bfc15268SAneesh Kumar K.V #include <unistd.h>
15bfc15268SAneesh Kumar K.V #include <string.h>
16bfc15268SAneesh Kumar K.V #include <errno.h>
17c797b6c6SAneesh Kumar K.V #include <sys/vfs.h>
181c7850f9SSasha Levin 
192daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h>
202daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h>
21623682beSMarc Zyngier #include <linux/uidgid.h>
222daa28d4SAneesh Kumar K.V #include <net/9p/9p.h>
232daa28d4SAneesh Kumar K.V 
24c7838fbdSSasha Levin static LIST_HEAD(devs);
25312c62d1SSasha Levin static int compat_id = -1;
26c7838fbdSSasha Levin 
27e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid);
28e2341580SSasha Levin static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid)
29e2341580SSasha Levin {
30e2341580SSasha Levin 	struct rb_node *node = dev->fids.rb_node;
31e2341580SSasha Levin 	struct p9_fid *pfid = NULL;
32e2341580SSasha Levin 
33e2341580SSasha Levin 	while (node) {
34e2341580SSasha Levin 		struct p9_fid *cur = rb_entry(node, struct p9_fid, node);
35e2341580SSasha Levin 
36e2341580SSasha Levin 		if (fid < cur->fid) {
37e2341580SSasha Levin 			node = node->rb_left;
38e2341580SSasha Levin 		} else if (fid > cur->fid) {
39e2341580SSasha Levin 			node = node->rb_right;
40e2341580SSasha Levin 		} else {
41e2341580SSasha Levin 			return cur;
42e2341580SSasha Levin 		}
43e2341580SSasha Levin 	}
44e2341580SSasha Levin 
45e2341580SSasha Levin 	pfid = calloc(sizeof(*pfid), 1);
46e2341580SSasha Levin 	if (!pfid)
47e2341580SSasha Levin 		return NULL;
48e2341580SSasha Levin 
49e2341580SSasha Levin 	pfid->fid = fid;
50e2341580SSasha Levin 	strcpy(pfid->abs_path, dev->root_dir);
51e2341580SSasha Levin 	pfid->path = pfid->abs_path + strlen(dev->root_dir);
52e2341580SSasha Levin 
53e2341580SSasha Levin 	insert_new_fid(dev, pfid);
54e2341580SSasha Levin 
55e2341580SSasha Levin 	return pfid;
56e2341580SSasha Levin }
57e2341580SSasha Levin 
58e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid)
59e2341580SSasha Levin {
60e2341580SSasha Levin 	struct rb_node **node = &(dev->fids.rb_node), *parent = NULL;
61e2341580SSasha Levin 
62e2341580SSasha Levin 	while (*node) {
63e2341580SSasha Levin 		int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid;
64e2341580SSasha Levin 
65e2341580SSasha Levin 		parent = *node;
66e2341580SSasha Levin 		if (result < 0)
67e2341580SSasha Levin 			node    = &((*node)->rb_left);
68e2341580SSasha Levin 		else if (result > 0)
69e2341580SSasha Levin 			node    = &((*node)->rb_right);
70e2341580SSasha Levin 		else
71e2341580SSasha Levin 			return -EEXIST;
72e2341580SSasha Levin 	}
73e2341580SSasha Levin 
74e2341580SSasha Levin 	rb_link_node(&fid->node, parent, node);
75e2341580SSasha Levin 	rb_insert_color(&fid->node, &dev->fids);
76e2341580SSasha Levin 	return 0;
77e2341580SSasha Levin }
78e2341580SSasha Levin 
7931a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
8031a6fb8dSSasha Levin {
81e2341580SSasha Levin 	struct p9_fid *new;
8231a6fb8dSSasha Levin 
83e2341580SSasha Levin 	new = find_or_create_fid(p9dev, fid);
84e2341580SSasha Levin 
85e2341580SSasha Levin 	return new;
8631a6fb8dSSasha Levin }
8731a6fb8dSSasha Levin 
881c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */
89b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev,
90b4422bf3SAneesh Kumar K.V 			      const char *path, char *abs_path)
911c7850f9SSasha Levin {
92b4422bf3SAneesh Kumar K.V 	sprintf(abs_path, "%s/%s", p9dev->root_dir, path);
931c7850f9SSasha Levin 
941c7850f9SSasha Levin 	return abs_path;
951c7850f9SSasha Levin }
961c7850f9SSasha Levin 
97c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid)
981c7850f9SSasha Levin {
991c7850f9SSasha Levin 	*qid = (struct p9_qid) {
1001c7850f9SSasha Levin 		.path		= st->st_ino,
1011c7850f9SSasha Levin 		.version	= st->st_mtime,
1021c7850f9SSasha Levin 	};
1031c7850f9SSasha Levin 
1041c7850f9SSasha Levin 	if (S_ISDIR(st->st_mode))
1051c7850f9SSasha Levin 		qid->type	|= P9_QTDIR;
1061c7850f9SSasha Levin }
1071c7850f9SSasha Levin 
108b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid)
1091c7850f9SSasha Levin {
110e2341580SSasha Levin 	struct p9_fid *pfid = get_fid(p9dev, fid);
111e2341580SSasha Levin 
112e2341580SSasha Levin 	if (pfid->fd > 0)
113e2341580SSasha Levin 		close(pfid->fd);
114e2341580SSasha Levin 
115e2341580SSasha Levin 	if (pfid->dir)
116e2341580SSasha Levin 		closedir(pfid->dir);
117e2341580SSasha Levin 
118e2341580SSasha Levin 	rb_erase(&pfid->node, &p9dev->fids);
119e2341580SSasha Levin 	free(pfid);
1201c7850f9SSasha Levin }
121e2341580SSasha Levin 
122bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
1231c7850f9SSasha Levin {
124bfc15268SAneesh Kumar K.V 	u8 cmd;
125bfc15268SAneesh Kumar K.V 	u16 tag;
126bfc15268SAneesh Kumar K.V 
127bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32);
128bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
129bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
130bfc15268SAneesh Kumar K.V 	/* cmd + 1 is the reply message */
131bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
1321c7850f9SSasha Levin }
1331c7850f9SSasha Levin 
1346b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
1356b163a87SAneesh Kumar K.V {
1366b163a87SAneesh Kumar K.V 	int i;
1376b163a87SAneesh Kumar K.V 	u32 total = 0;
1386b163a87SAneesh Kumar K.V 	for (i = 0; (i < iov_cnt) && (total < count); i++) {
1396b163a87SAneesh Kumar K.V 		if (total + iov[i].iov_len > count) {
1406b163a87SAneesh Kumar K.V 			/* we don't need this iov fully */
1416b163a87SAneesh Kumar K.V 			iov[i].iov_len -= ((total + iov[i].iov_len) - count);
1426b163a87SAneesh Kumar K.V 			i++;
1436b163a87SAneesh Kumar K.V 			break;
1446b163a87SAneesh Kumar K.V 		}
1456b163a87SAneesh Kumar K.V 		total += iov[i].iov_len;
1466b163a87SAneesh Kumar K.V 	}
1476b163a87SAneesh Kumar K.V 	return i;
1486b163a87SAneesh Kumar K.V }
1496b163a87SAneesh Kumar K.V 
150eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev,
151eee1ba8eSAneesh Kumar K.V 				  struct p9_pdu *pdu, int err, u32 *outlen)
152eee1ba8eSAneesh Kumar K.V {
153bfc15268SAneesh Kumar K.V 	u16 tag;
154eee1ba8eSAneesh Kumar K.V 
1555529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
156c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", err);
157bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
158eee1ba8eSAneesh Kumar K.V 
159c797b6c6SAneesh Kumar K.V 	/* read the tag from input */
160bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32) + sizeof(u8);
161bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "w", &tag);
162bfc15268SAneesh Kumar K.V 
163c797b6c6SAneesh Kumar K.V 	/* Update the header */
164bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
165c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
166eee1ba8eSAneesh Kumar K.V }
167eee1ba8eSAneesh Kumar K.V 
168ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev,
169af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
1701c7850f9SSasha Levin {
171c797b6c6SAneesh Kumar K.V 	u32 msize;
172c797b6c6SAneesh Kumar K.V 	char *version;
173c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
174c797b6c6SAneesh Kumar K.V 	/*
175c797b6c6SAneesh Kumar K.V 	 * reply with the same msize the client sent us
176c797b6c6SAneesh Kumar K.V 	 * Error out if the request is not for 9P2000.L
177c797b6c6SAneesh Kumar K.V 	 */
1785529bcd7SAsias He 	if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
179c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, version);
180c797b6c6SAneesh Kumar K.V 	else
181c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
1821c7850f9SSasha Levin 
183bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
184bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
185c797b6c6SAneesh Kumar K.V 	free(version);
186ead43b01SAneesh Kumar K.V 	return;
1871c7850f9SSasha Levin }
1881c7850f9SSasha Levin 
189ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev,
190af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
1911c7850f9SSasha Levin {
192bfc15268SAneesh Kumar K.V 	u32 fid;
1931c7850f9SSasha Levin 
194bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid);
195bfc15268SAneesh Kumar K.V 	close_fid(p9dev, fid);
1961c7850f9SSasha Levin 
197bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
198bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
199ead43b01SAneesh Kumar K.V 	return;
2001c7850f9SSasha Levin }
2011c7850f9SSasha Levin 
202c797b6c6SAneesh Kumar K.V /*
203c797b6c6SAneesh Kumar K.V  * FIXME!! Need to map to protocol independent value. Upstream
204c797b6c6SAneesh Kumar K.V  * 9p also have the same BUG
205c797b6c6SAneesh Kumar K.V  */
206c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags)
207c797b6c6SAneesh Kumar K.V {
208c797b6c6SAneesh Kumar K.V 	flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
209c797b6c6SAneesh Kumar K.V 	flags |= O_NOFOLLOW;
210c797b6c6SAneesh Kumar K.V 	return flags;
211c797b6c6SAneesh Kumar K.V }
212c797b6c6SAneesh Kumar K.V 
21332585666SSasha Levin static bool is_dir(struct p9_fid *fid)
21432585666SSasha Levin {
21532585666SSasha Levin 	struct stat st;
21632585666SSasha Levin 
21732585666SSasha Levin 	stat(fid->abs_path, &st);
21832585666SSasha Levin 
21932585666SSasha Levin 	return S_ISDIR(st.st_mode);
22032585666SSasha Levin }
22132585666SSasha Levin 
222ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev,
223af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
2241c7850f9SSasha Levin {
225c797b6c6SAneesh Kumar K.V 	u32 fid, flags;
2261c7850f9SSasha Levin 	struct stat st;
227bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
228bfc15268SAneesh Kumar K.V 	struct p9_fid *new_fid;
229bfc15268SAneesh Kumar K.V 
230c797b6c6SAneesh Kumar K.V 
231c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
23231a6fb8dSSasha Levin 	new_fid = get_fid(p9dev, fid);
2331c7850f9SSasha Levin 
23430204a77SAneesh Kumar K.V 	if (lstat(new_fid->abs_path, &st) < 0)
235eee1ba8eSAneesh Kumar K.V 		goto err_out;
2361c7850f9SSasha Levin 
237c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
2381c7850f9SSasha Levin 
23932585666SSasha Levin 	if (is_dir(new_fid)) {
2401c7850f9SSasha Levin 		new_fid->dir = opendir(new_fid->abs_path);
241eee1ba8eSAneesh Kumar K.V 		if (!new_fid->dir)
242eee1ba8eSAneesh Kumar K.V 			goto err_out;
243eee1ba8eSAneesh Kumar K.V 	} else {
244eee1ba8eSAneesh Kumar K.V 		new_fid->fd  = open(new_fid->abs_path,
245c797b6c6SAneesh Kumar K.V 				    virtio_p9_openflags(flags));
246eee1ba8eSAneesh Kumar K.V 		if (new_fid->fd < 0)
247eee1ba8eSAneesh Kumar K.V 			goto err_out;
248eee1ba8eSAneesh Kumar K.V 	}
249c797b6c6SAneesh Kumar K.V 	/* FIXME!! need ot send proper iounit  */
250bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
251bfc15268SAneesh Kumar K.V 
252bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
253bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
254ead43b01SAneesh Kumar K.V 	return;
255eee1ba8eSAneesh Kumar K.V err_out:
256eee1ba8eSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
257ead43b01SAneesh Kumar K.V 	return;
2581c7850f9SSasha Levin }
2591c7850f9SSasha Levin 
260ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev,
261af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
2621c7850f9SSasha Levin {
263c797b6c6SAneesh Kumar K.V 	int fd, ret;
264bfc15268SAneesh Kumar K.V 	char *name;
265af045e53SAneesh Kumar K.V 	struct stat st;
266bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
267c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
2684bc9734aSAneesh Kumar K.V 	char full_path[PATH_MAX];
269c797b6c6SAneesh Kumar K.V 	u32 dfid_val, flags, mode, gid;
270af045e53SAneesh Kumar K.V 
271c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
272c797b6c6SAneesh Kumar K.V 			    &name, &flags, &mode, &gid);
27331a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
2741c7850f9SSasha Levin 
275c797b6c6SAneesh Kumar K.V 	flags = virtio_p9_openflags(flags);
2765f900f6dSSasha Levin 
277c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
278c797b6c6SAneesh Kumar K.V 	fd = open(full_path, flags | O_CREAT, mode);
2794bc9734aSAneesh Kumar K.V 	if (fd < 0)
2804bc9734aSAneesh Kumar K.V 		goto err_out;
281c797b6c6SAneesh Kumar K.V 	dfid->fd = fd;
282c797b6c6SAneesh Kumar K.V 
2834bc9734aSAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
2846c8ca053SAneesh Kumar K.V 		goto err_out;
2851c7850f9SSasha Levin 
286c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
287c797b6c6SAneesh Kumar K.V 	if (ret < 0)
288c797b6c6SAneesh Kumar K.V 		goto err_out;
289c797b6c6SAneesh Kumar K.V 
290c797b6c6SAneesh Kumar K.V 	sprintf(dfid->path, "%s/%s", dfid->path, name);
291c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
292bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
293bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
294bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
2955f900f6dSSasha Levin 	free(name);
2966c8ca053SAneesh Kumar K.V 	return;
2976c8ca053SAneesh Kumar K.V err_out:
2985f900f6dSSasha Levin 	free(name);
299c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
300c797b6c6SAneesh Kumar K.V 	return;
301c797b6c6SAneesh Kumar K.V }
302c797b6c6SAneesh Kumar K.V 
303c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev,
304c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
305c797b6c6SAneesh Kumar K.V {
306c797b6c6SAneesh Kumar K.V 	int ret;
307c797b6c6SAneesh Kumar K.V 	char *name;
308c797b6c6SAneesh Kumar K.V 	struct stat st;
309c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
310c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
311c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
312c797b6c6SAneesh Kumar K.V 	u32 dfid_val, mode, gid;
313c797b6c6SAneesh Kumar K.V 
314c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
315c797b6c6SAneesh Kumar K.V 			    &name, &mode, &gid);
31631a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
317c797b6c6SAneesh Kumar K.V 
318c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
319c797b6c6SAneesh Kumar K.V 	ret = mkdir(full_path, mode);
320c797b6c6SAneesh Kumar K.V 	if (ret < 0)
321c797b6c6SAneesh Kumar K.V 		goto err_out;
322c797b6c6SAneesh Kumar K.V 
323c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
324c797b6c6SAneesh Kumar K.V 		goto err_out;
325c797b6c6SAneesh Kumar K.V 
326c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
327c797b6c6SAneesh Kumar K.V 	if (ret < 0)
328c797b6c6SAneesh Kumar K.V 		goto err_out;
329c797b6c6SAneesh Kumar K.V 
330c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
331c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
332c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
333c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
334c797b6c6SAneesh Kumar K.V 	free(name);
335c797b6c6SAneesh Kumar K.V 	return;
336c797b6c6SAneesh Kumar K.V err_out:
337c797b6c6SAneesh Kumar K.V 	free(name);
338c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
339ead43b01SAneesh Kumar K.V 	return;
3401c7850f9SSasha Levin }
3411c7850f9SSasha Levin 
342ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev,
343af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
3441c7850f9SSasha Levin {
345af045e53SAneesh Kumar K.V 	u8 i;
346bfc15268SAneesh Kumar K.V 	u16 nwqid;
347bfc15268SAneesh Kumar K.V 	u16 nwname;
348bfc15268SAneesh Kumar K.V 	struct p9_qid wqid;
349e2341580SSasha Levin 	struct p9_fid *new_fid, *old_fid;
350c797b6c6SAneesh Kumar K.V 	u32 fid_val, newfid_val;
351c797b6c6SAneesh Kumar K.V 
3521c7850f9SSasha Levin 
353bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
35431a6fb8dSSasha Levin 	new_fid	= get_fid(p9dev, newfid_val);
3551c7850f9SSasha Levin 
356bfc15268SAneesh Kumar K.V 	nwqid = 0;
357bfc15268SAneesh Kumar K.V 	if (nwname) {
35831a6fb8dSSasha Levin 		struct p9_fid *fid = get_fid(p9dev, fid_val);
359bfc15268SAneesh Kumar K.V 
360baac79a5SAneesh Kumar K.V 		strcpy(new_fid->path, fid->path);
361bfc15268SAneesh Kumar K.V 		/* skip the space for count */
362bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
363bfc15268SAneesh Kumar K.V 		for (i = 0; i < nwname; i++) {
364bfc15268SAneesh Kumar K.V 			struct stat st;
3651c7850f9SSasha Levin 			char tmp[PATH_MAX] = {0};
3661c7850f9SSasha Levin 			char full_path[PATH_MAX];
367e55ed135SPekka Enberg 			char *str;
368bfc15268SAneesh Kumar K.V 
369bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_readf(pdu, "s", &str);
3701c7850f9SSasha Levin 
3711c7850f9SSasha Levin 			/* Format the new path we're 'walk'ing into */
372baac79a5SAneesh Kumar K.V 			sprintf(tmp, "%s/%s", new_fid->path, str);
373e55ed135SPekka Enberg 
374e55ed135SPekka Enberg 			free(str);
375e55ed135SPekka Enberg 
376c797b6c6SAneesh Kumar K.V 			if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0)
3776c8ca053SAneesh Kumar K.V 				goto err_out;
3781c7850f9SSasha Levin 
379c797b6c6SAneesh Kumar K.V 			stat2qid(&st, &wqid);
3801c7850f9SSasha Levin 			strcpy(new_fid->path, tmp);
381c797b6c6SAneesh Kumar K.V 			new_fid->uid = fid->uid;
382bfc15268SAneesh Kumar K.V 			nwqid++;
383bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_writef(pdu, "Q", &wqid);
3841c7850f9SSasha Levin 		}
3851c7850f9SSasha Levin 	} else {
386bfc15268SAneesh Kumar K.V 		/*
387bfc15268SAneesh Kumar K.V 		 * update write_offset so our outlen get correct value
388bfc15268SAneesh Kumar K.V 		 */
389bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
390e2341580SSasha Levin 		old_fid = get_fid(p9dev, fid_val);
391e2341580SSasha Levin 		strcpy(new_fid->path, old_fid->path);
392e2341580SSasha Levin 		new_fid->uid    = old_fid->uid;
3931c7850f9SSasha Levin 	}
394bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
3955529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
396bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", nwqid);
397bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
3986c8ca053SAneesh Kumar K.V 	return;
3996c8ca053SAneesh Kumar K.V err_out:
4006c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
401ead43b01SAneesh Kumar K.V 	return;
4021c7850f9SSasha Levin }
4031c7850f9SSasha Levin 
404ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev,
405af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
4061c7850f9SSasha Levin {
407bfc15268SAneesh Kumar K.V 	char *uname;
408bfc15268SAneesh Kumar K.V 	char *aname;
4091c7850f9SSasha Levin 	struct stat st;
410bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
4111c7850f9SSasha Levin 	struct p9_fid *fid;
412c797b6c6SAneesh Kumar K.V 	u32 fid_val, afid, uid;
413bfc15268SAneesh Kumar K.V 
414c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
415c797b6c6SAneesh Kumar K.V 			    &uname, &aname, &uid);
4161c7850f9SSasha Levin 
41739257180SPekka Enberg 	free(uname);
41839257180SPekka Enberg 	free(aname);
41939257180SPekka Enberg 
42030204a77SAneesh Kumar K.V 	if (lstat(p9dev->root_dir, &st) < 0)
4216c8ca053SAneesh Kumar K.V 		goto err_out;
4221c7850f9SSasha Levin 
423c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
4241c7850f9SSasha Levin 
42531a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
426c797b6c6SAneesh Kumar K.V 	fid->uid = uid;
4271c7850f9SSasha Levin 	strcpy(fid->path, "/");
4281c7850f9SSasha Levin 
429bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
430bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
431bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
4326c8ca053SAneesh Kumar K.V 	return;
4336c8ca053SAneesh Kumar K.V err_out:
4346c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
435ead43b01SAneesh Kumar K.V 	return;
4361c7850f9SSasha Levin }
4371c7850f9SSasha Levin 
438c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev,
439c797b6c6SAneesh Kumar K.V 				struct stat *st, struct p9_stat_dotl *statl)
4405f900f6dSSasha Levin {
441c797b6c6SAneesh Kumar K.V 	memset(statl, 0, sizeof(*statl));
442c797b6c6SAneesh Kumar K.V 	statl->st_mode		= st->st_mode;
443c797b6c6SAneesh Kumar K.V 	statl->st_nlink		= st->st_nlink;
444c797b6c6SAneesh Kumar K.V 	statl->st_uid		= st->st_uid;
445c797b6c6SAneesh Kumar K.V 	statl->st_gid		= st->st_gid;
446c797b6c6SAneesh Kumar K.V 	statl->st_rdev		= st->st_rdev;
447c797b6c6SAneesh Kumar K.V 	statl->st_size		= st->st_size;
448c797b6c6SAneesh Kumar K.V 	statl->st_blksize	= st->st_blksize;
449c797b6c6SAneesh Kumar K.V 	statl->st_blocks	= st->st_blocks;
450c797b6c6SAneesh Kumar K.V 	statl->st_atime_sec	= st->st_atime;
451c797b6c6SAneesh Kumar K.V 	statl->st_atime_nsec	= st->st_atim.tv_nsec;
452c797b6c6SAneesh Kumar K.V 	statl->st_mtime_sec	= st->st_mtime;
453c797b6c6SAneesh Kumar K.V 	statl->st_mtime_nsec	= st->st_mtim.tv_nsec;
454c797b6c6SAneesh Kumar K.V 	statl->st_ctime_sec	= st->st_ctime;
455c797b6c6SAneesh Kumar K.V 	statl->st_ctime_nsec	= st->st_ctim.tv_nsec;
456c797b6c6SAneesh Kumar K.V 	/* Currently we only support BASIC fields in stat */
457c797b6c6SAneesh Kumar K.V 	statl->st_result_mask	= P9_STATS_BASIC;
458c797b6c6SAneesh Kumar K.V 	stat2qid(st, &statl->qid);
4591c7850f9SSasha Levin }
4601c7850f9SSasha Levin 
461ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev,
462af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
4631c7850f9SSasha Levin {
464bfc15268SAneesh Kumar K.V 	u64 offset;
465bfc15268SAneesh Kumar K.V 	u32 fid_val;
466c797b6c6SAneesh Kumar K.V 	u16 iov_cnt;
467c797b6c6SAneesh Kumar K.V 	void *iov_base;
468c797b6c6SAneesh Kumar K.V 	size_t iov_len;
469bfc15268SAneesh Kumar K.V 	u32 count, rcount;
470bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
471c797b6c6SAneesh Kumar K.V 
4721c7850f9SSasha Levin 
473bfc15268SAneesh Kumar K.V 	rcount = 0;
474bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
47531a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
47650c479e0SAneesh Kumar K.V 
47750c479e0SAneesh Kumar K.V 	iov_base = pdu->in_iov[0].iov_base;
47850c479e0SAneesh Kumar K.V 	iov_len  = pdu->in_iov[0].iov_len;
47950c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->in_iov_cnt;
4805529bcd7SAsias He 	pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
4815529bcd7SAsias He 	pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
4826b163a87SAneesh Kumar K.V 	pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
483bfc15268SAneesh Kumar K.V 						   count,
4846b163a87SAneesh Kumar K.V 						   pdu->in_iov_cnt);
485bfc15268SAneesh Kumar K.V 	rcount = preadv(fid->fd, pdu->in_iov,
486bfc15268SAneesh Kumar K.V 			pdu->in_iov_cnt, offset);
487bfc15268SAneesh Kumar K.V 	if (rcount > count)
488bfc15268SAneesh Kumar K.V 		rcount = count;
489bfc15268SAneesh Kumar K.V 	/*
490bfc15268SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
491bfc15268SAneesh Kumar K.V 	 * pdu_writef works correctly.
492bfc15268SAneesh Kumar K.V 	 */
49350c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_base = iov_base;
49450c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_len  = iov_len;
49550c479e0SAneesh Kumar K.V 	pdu->in_iov_cnt         = iov_cnt;
496c797b6c6SAneesh Kumar K.V 
4975529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
498bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
499bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
500bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
501ead43b01SAneesh Kumar K.V 	return;
5021c7850f9SSasha Levin }
5031c7850f9SSasha Levin 
504c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent)
505c797b6c6SAneesh Kumar K.V {
506c797b6c6SAneesh Kumar K.V 	/*
507c797b6c6SAneesh Kumar K.V 	 * Size of each dirent:
508c797b6c6SAneesh Kumar K.V 	 * qid(13) + offset(8) + type(1) + name_len(2) + name
509c797b6c6SAneesh Kumar K.V 	 */
510c797b6c6SAneesh Kumar K.V 	return 24 + strlen(dent->d_name);
511c797b6c6SAneesh Kumar K.V }
512c797b6c6SAneesh Kumar K.V 
513c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev,
514c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
515c797b6c6SAneesh Kumar K.V {
516c797b6c6SAneesh Kumar K.V 	u32 fid_val;
517c797b6c6SAneesh Kumar K.V 	u32 count, rcount;
518c797b6c6SAneesh Kumar K.V 	struct stat st;
519c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
520c797b6c6SAneesh Kumar K.V 	struct dirent *dent;
521c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
522c797b6c6SAneesh Kumar K.V 	u64 offset, old_offset;
523c797b6c6SAneesh Kumar K.V 
524c797b6c6SAneesh Kumar K.V 	rcount = 0;
525c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
52631a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
527c797b6c6SAneesh Kumar K.V 
52832585666SSasha Levin 	if (!is_dir(fid)) {
52969bb4278SSasha Levin 		errno = EINVAL;
530c797b6c6SAneesh Kumar K.V 		goto err_out;
531c797b6c6SAneesh Kumar K.V 	}
532c797b6c6SAneesh Kumar K.V 
533c797b6c6SAneesh Kumar K.V 	/* Move the offset specified */
534c797b6c6SAneesh Kumar K.V 	seekdir(fid->dir, offset);
535c797b6c6SAneesh Kumar K.V 
536c797b6c6SAneesh Kumar K.V 	old_offset = offset;
537c797b6c6SAneesh Kumar K.V 	/* If reading a dir, fill the buffer with p9_stat entries */
538c797b6c6SAneesh Kumar K.V 	dent = readdir(fid->dir);
539c797b6c6SAneesh Kumar K.V 
540c797b6c6SAneesh Kumar K.V 	/* Skip the space for writing count */
541c797b6c6SAneesh Kumar K.V 	pdu->write_offset += sizeof(u32);
542c797b6c6SAneesh Kumar K.V 	while (dent) {
543c797b6c6SAneesh Kumar K.V 		u32 read;
544c797b6c6SAneesh Kumar K.V 		struct p9_qid qid;
545c797b6c6SAneesh Kumar K.V 
546c797b6c6SAneesh Kumar K.V 		if ((rcount + virtio_p9_dentry_size(dent)) > count) {
547c797b6c6SAneesh Kumar K.V 			/* seek to the previous offset and return */
548c797b6c6SAneesh Kumar K.V 			seekdir(fid->dir, old_offset);
549c797b6c6SAneesh Kumar K.V 			break;
550c797b6c6SAneesh Kumar K.V 		}
551c797b6c6SAneesh Kumar K.V 		old_offset = dent->d_off;
552c797b6c6SAneesh Kumar K.V 		lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st);
553c797b6c6SAneesh Kumar K.V 		stat2qid(&st, &qid);
554c797b6c6SAneesh Kumar K.V 		read = pdu->write_offset;
555c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
556c797b6c6SAneesh Kumar K.V 				     dent->d_type, dent->d_name);
557c797b6c6SAneesh Kumar K.V 		rcount += pdu->write_offset - read;
558c797b6c6SAneesh Kumar K.V 		dent = readdir(fid->dir);
559c797b6c6SAneesh Kumar K.V 	}
560c797b6c6SAneesh Kumar K.V 
5615529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
562c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
563c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
564c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
565c797b6c6SAneesh Kumar K.V 	return;
566c797b6c6SAneesh Kumar K.V err_out:
567c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
568c797b6c6SAneesh Kumar K.V 	return;
569c797b6c6SAneesh Kumar K.V }
570c797b6c6SAneesh Kumar K.V 
571c797b6c6SAneesh Kumar K.V 
572c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev,
573af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
5741c7850f9SSasha Levin {
575bfc15268SAneesh Kumar K.V 	u32 fid_val;
576af045e53SAneesh Kumar K.V 	struct stat st;
577c797b6c6SAneesh Kumar K.V 	u64 request_mask;
578bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
579c797b6c6SAneesh Kumar K.V 	struct p9_stat_dotl statl;
5801c7850f9SSasha Levin 
581c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
58231a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
58330204a77SAneesh Kumar K.V 	if (lstat(fid->abs_path, &st) < 0)
5846c8ca053SAneesh Kumar K.V 		goto err_out;
5851c7850f9SSasha Levin 
586c797b6c6SAneesh Kumar K.V 	virtio_p9_fill_stat(p9dev, &st, &statl);
587c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "A", &statl);
588bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
589bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
590ead43b01SAneesh Kumar K.V 	return;
5916c8ca053SAneesh Kumar K.V err_out:
5926c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
5936c8ca053SAneesh Kumar K.V 	return;
5941c7850f9SSasha Levin }
5951c7850f9SSasha Levin 
596c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */
597c797b6c6SAneesh Kumar K.V /*
598c797b6c6SAneesh Kumar K.V  * Attribute flags.  These should be or-ed together to figure out what
599c797b6c6SAneesh Kumar K.V  * has been changed!
600c797b6c6SAneesh Kumar K.V  */
601c797b6c6SAneesh Kumar K.V #define ATTR_MODE	(1 << 0)
602c797b6c6SAneesh Kumar K.V #define ATTR_UID	(1 << 1)
603c797b6c6SAneesh Kumar K.V #define ATTR_GID	(1 << 2)
604c797b6c6SAneesh Kumar K.V #define ATTR_SIZE	(1 << 3)
605c797b6c6SAneesh Kumar K.V #define ATTR_ATIME	(1 << 4)
606c797b6c6SAneesh Kumar K.V #define ATTR_MTIME	(1 << 5)
607c797b6c6SAneesh Kumar K.V #define ATTR_CTIME	(1 << 6)
608c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET	(1 << 7)
609c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET	(1 << 8)
610c797b6c6SAneesh Kumar K.V #define ATTR_FORCE	(1 << 9) /* Not a change, but a change it */
611c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG	(1 << 10)
612c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID	(1 << 11)
613c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID	(1 << 12)
614c797b6c6SAneesh Kumar K.V #define ATTR_FILE	(1 << 13)
615c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV	(1 << 14)
616c797b6c6SAneesh Kumar K.V #define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
617c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET	(1 << 16)
618c797b6c6SAneesh Kumar K.V 
619c797b6c6SAneesh Kumar K.V #define ATTR_MASK    127
620c797b6c6SAneesh Kumar K.V 
621c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev,
622af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
6231c7850f9SSasha Levin {
624c797b6c6SAneesh Kumar K.V 	int ret = 0;
625bfc15268SAneesh Kumar K.V 	u32 fid_val;
626bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
627c797b6c6SAneesh Kumar K.V 	struct p9_iattr_dotl p9attr;
6281c7850f9SSasha Levin 
629c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
63031a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
6311c7850f9SSasha Levin 
632c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & ATTR_MODE) {
633c797b6c6SAneesh Kumar K.V 		ret = chmod(fid->abs_path, p9attr.mode);
634c797b6c6SAneesh Kumar K.V 		if (ret < 0)
635c797b6c6SAneesh Kumar K.V 			goto err_out;
636c797b6c6SAneesh Kumar K.V 	}
637c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
638c797b6c6SAneesh Kumar K.V 		struct timespec times[2];
639c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_ATIME) {
640c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_ATIME_SET) {
641c797b6c6SAneesh Kumar K.V 				times[0].tv_sec = p9attr.atime_sec;
642c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = p9attr.atime_nsec;
643c797b6c6SAneesh Kumar K.V 			} else {
644c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = UTIME_NOW;
645c797b6c6SAneesh Kumar K.V 			}
646c797b6c6SAneesh Kumar K.V 		} else {
647c797b6c6SAneesh Kumar K.V 			times[0].tv_nsec = UTIME_OMIT;
648c797b6c6SAneesh Kumar K.V 		}
649c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_MTIME) {
650c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_MTIME_SET) {
651c797b6c6SAneesh Kumar K.V 				times[1].tv_sec = p9attr.mtime_sec;
652c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = p9attr.mtime_nsec;
653c797b6c6SAneesh Kumar K.V 			} else {
654c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = UTIME_NOW;
655c797b6c6SAneesh Kumar K.V 			}
656c797b6c6SAneesh Kumar K.V 		} else
657c797b6c6SAneesh Kumar K.V 			times[1].tv_nsec = UTIME_OMIT;
658c797b6c6SAneesh Kumar K.V 
659c797b6c6SAneesh Kumar K.V 		ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
660c797b6c6SAneesh Kumar K.V 		if (ret < 0)
661c797b6c6SAneesh Kumar K.V 			goto err_out;
662c797b6c6SAneesh Kumar K.V 	}
663c797b6c6SAneesh Kumar K.V 	/*
664c797b6c6SAneesh Kumar K.V 	 * If the only valid entry in iattr is ctime we can call
665c797b6c6SAneesh Kumar K.V 	 * chown(-1,-1) to update the ctime of the file
666c797b6c6SAneesh Kumar K.V 	 */
667c797b6c6SAneesh Kumar K.V 	if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
668c797b6c6SAneesh Kumar K.V 	    ((p9attr.valid & ATTR_CTIME)
669c797b6c6SAneesh Kumar K.V 	     && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
670c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_UID))
671c797b6c6SAneesh Kumar K.V 			p9attr.uid = -1;
672c797b6c6SAneesh Kumar K.V 
673c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_GID))
674c797b6c6SAneesh Kumar K.V 			p9attr.gid = -1;
675c797b6c6SAneesh Kumar K.V 
676c797b6c6SAneesh Kumar K.V 		ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid);
677c797b6c6SAneesh Kumar K.V 		if (ret < 0)
678c797b6c6SAneesh Kumar K.V 			goto err_out;
679c797b6c6SAneesh Kumar K.V 	}
680c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_SIZE)) {
681c797b6c6SAneesh Kumar K.V 		ret = truncate(fid->abs_path, p9attr.size);
682c797b6c6SAneesh Kumar K.V 		if (ret < 0)
683c797b6c6SAneesh Kumar K.V 			goto err_out;
684c797b6c6SAneesh Kumar K.V 	}
6855529bcd7SAsias He 	*outlen = VIRTIO_9P_HDR_LEN;
686bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
687ead43b01SAneesh Kumar K.V 	return;
6884bc9734aSAneesh Kumar K.V err_out:
6894bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
6904bc9734aSAneesh Kumar K.V 	return;
6911c7850f9SSasha Levin }
6921c7850f9SSasha Levin 
693ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev,
694af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
6951c7850f9SSasha Levin {
6964bc9734aSAneesh Kumar K.V 
697bfc15268SAneesh Kumar K.V 	u64 offset;
698bfc15268SAneesh Kumar K.V 	u32 fid_val;
6994bc9734aSAneesh Kumar K.V 	u32 count;
7004bc9734aSAneesh Kumar K.V 	ssize_t res;
70150c479e0SAneesh Kumar K.V 	u16 iov_cnt;
70250c479e0SAneesh Kumar K.V 	void *iov_base;
70350c479e0SAneesh Kumar K.V 	size_t iov_len;
704bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
705b064b05aSAneesh Kumar K.V 	/* u32 fid + u64 offset + u32 count */
706b064b05aSAneesh Kumar K.V 	int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
7071c7850f9SSasha Levin 
708bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
70931a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
710af045e53SAneesh Kumar K.V 
71150c479e0SAneesh Kumar K.V 	iov_base = pdu->out_iov[0].iov_base;
71250c479e0SAneesh Kumar K.V 	iov_len  = pdu->out_iov[0].iov_len;
71350c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->out_iov_cnt;
71450c479e0SAneesh Kumar K.V 
715bfc15268SAneesh Kumar K.V 	/* Adjust the iovec to skip the header and meta data */
716b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
717b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
718bfc15268SAneesh Kumar K.V 	pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
7196b163a87SAneesh Kumar K.V 						    pdu->out_iov_cnt);
7204bc9734aSAneesh Kumar K.V 	res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
72150c479e0SAneesh Kumar K.V 	/*
72250c479e0SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
72350c479e0SAneesh Kumar K.V 	 * pdu_readf works correctly.
72450c479e0SAneesh Kumar K.V 	 */
72550c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_base = iov_base;
72650c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_len  = iov_len;
72750c479e0SAneesh Kumar K.V 	pdu->out_iov_cnt         = iov_cnt;
728c797b6c6SAneesh Kumar K.V 
7294bc9734aSAneesh Kumar K.V 	if (res < 0)
7304bc9734aSAneesh Kumar K.V 		goto err_out;
7314bc9734aSAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", res);
732bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
733bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
734ead43b01SAneesh Kumar K.V 	return;
7354bc9734aSAneesh Kumar K.V err_out:
7364bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
7374bc9734aSAneesh Kumar K.V 	return;
7381c7850f9SSasha Levin }
7391c7850f9SSasha Levin 
7406fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev,
7416fc5cd9bSSasha Levin 			     struct p9_pdu *pdu, u32 *outlen)
7426fc5cd9bSSasha Levin {
7436fc5cd9bSSasha Levin 	int ret;
7446fc5cd9bSSasha Levin 	u32 fid_val;
7456fc5cd9bSSasha Levin 	struct p9_fid *fid;
7466fc5cd9bSSasha Levin 
7476fc5cd9bSSasha Levin 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
74831a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
7496fc5cd9bSSasha Levin 
7509b604a9cSSasha Levin 	ret = remove(fid->abs_path);
7516fc5cd9bSSasha Levin 	if (ret < 0)
7526fc5cd9bSSasha Levin 		goto err_out;
7536fc5cd9bSSasha Levin 	*outlen = pdu->write_offset;
7546fc5cd9bSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
7556fc5cd9bSSasha Levin 	return;
7566fc5cd9bSSasha Levin 
7576fc5cd9bSSasha Levin err_out:
7586fc5cd9bSSasha Levin 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
7596fc5cd9bSSasha Levin 	return;
7606fc5cd9bSSasha Levin }
7616fc5cd9bSSasha Levin 
762f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev,
763f161f28bSSasha Levin 			     struct p9_pdu *pdu, u32 *outlen)
764f161f28bSSasha Levin {
765f161f28bSSasha Levin 	int ret;
766f161f28bSSasha Levin 	u32 fid_val, new_fid_val;
767f161f28bSSasha Levin 	struct p9_fid *fid, *new_fid;
768f161f28bSSasha Levin 	char full_path[PATH_MAX], *new_name;
769f161f28bSSasha Levin 
770f161f28bSSasha Levin 	virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
77131a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
77231a6fb8dSSasha Levin 	new_fid = get_fid(p9dev, new_fid_val);
773f161f28bSSasha Levin 
774f161f28bSSasha Levin 	sprintf(full_path, "%s/%s", new_fid->abs_path, new_name);
775f161f28bSSasha Levin 	ret = rename(fid->abs_path, full_path);
776f161f28bSSasha Levin 	if (ret < 0)
777f161f28bSSasha Levin 		goto err_out;
778f161f28bSSasha Levin 	*outlen = pdu->write_offset;
779f161f28bSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
780f161f28bSSasha Levin 	return;
781f161f28bSSasha Levin 
782f161f28bSSasha Levin err_out:
783f161f28bSSasha Levin 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
784f161f28bSSasha Levin 	return;
785f161f28bSSasha Levin }
786f161f28bSSasha Levin 
787c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev,
788c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
789c797b6c6SAneesh Kumar K.V {
790c797b6c6SAneesh Kumar K.V 	int ret;
791c797b6c6SAneesh Kumar K.V 	u32 fid_val;
792c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
793c797b6c6SAneesh Kumar K.V 	char target_path[PATH_MAX];
794c797b6c6SAneesh Kumar K.V 
795c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
79631a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
797c797b6c6SAneesh Kumar K.V 
798c797b6c6SAneesh Kumar K.V 	memset(target_path, 0, PATH_MAX);
799c797b6c6SAneesh Kumar K.V 	ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
800c797b6c6SAneesh Kumar K.V 	if (ret < 0)
801c797b6c6SAneesh Kumar K.V 		goto err_out;
802c797b6c6SAneesh Kumar K.V 
803c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "s", target_path);
804c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
805c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
806c797b6c6SAneesh Kumar K.V 	return;
807c797b6c6SAneesh Kumar K.V err_out:
808c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
809c797b6c6SAneesh Kumar K.V 	return;
810c797b6c6SAneesh Kumar K.V }
811c797b6c6SAneesh Kumar K.V 
812c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev,
813c797b6c6SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
814c797b6c6SAneesh Kumar K.V {
815c797b6c6SAneesh Kumar K.V 	int ret;
816c797b6c6SAneesh Kumar K.V 	u64 fsid;
817c797b6c6SAneesh Kumar K.V 	u32 fid_val;
818c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
819c797b6c6SAneesh Kumar K.V 	struct statfs stat_buf;
820c797b6c6SAneesh Kumar K.V 
821c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
82231a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
823c797b6c6SAneesh Kumar K.V 
824c797b6c6SAneesh Kumar K.V 	ret = statfs(fid->abs_path, &stat_buf);
825c797b6c6SAneesh Kumar K.V 	if (ret < 0)
826c797b6c6SAneesh Kumar K.V 		goto err_out;
827c797b6c6SAneesh Kumar K.V 	/* FIXME!! f_blocks needs update based on client msize */
828c797b6c6SAneesh Kumar K.V 	fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
829c797b6c6SAneesh Kumar K.V 		(unsigned long long)stat_buf.f_fsid.__val[1] << 32;
830c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
831c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bsize, stat_buf.f_blocks,
832c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bfree, stat_buf.f_bavail,
833c797b6c6SAneesh Kumar K.V 			     stat_buf.f_files, stat_buf.f_ffree,
834c797b6c6SAneesh Kumar K.V 			     fsid, stat_buf.f_namelen);
835c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
836c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
837c797b6c6SAneesh Kumar K.V 	return;
838c797b6c6SAneesh Kumar K.V err_out:
839c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
840c797b6c6SAneesh Kumar K.V 	return;
841c797b6c6SAneesh Kumar K.V }
842c797b6c6SAneesh Kumar K.V 
843c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev,
844c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
845c797b6c6SAneesh Kumar K.V {
846c797b6c6SAneesh Kumar K.V 	int ret;
847c797b6c6SAneesh Kumar K.V 	char *name;
848c797b6c6SAneesh Kumar K.V 	struct stat st;
849c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
850c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
851c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
852c797b6c6SAneesh Kumar K.V 	u32 fid_val, mode, major, minor, gid;
853c797b6c6SAneesh Kumar K.V 
854c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
855c797b6c6SAneesh Kumar K.V 			    &major, &minor, &gid);
856c797b6c6SAneesh Kumar K.V 
85731a6fb8dSSasha Levin 	dfid = get_fid(p9dev, fid_val);
858c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
859c797b6c6SAneesh Kumar K.V 	ret = mknod(full_path, mode, makedev(major, minor));
860c797b6c6SAneesh Kumar K.V 	if (ret < 0)
861c797b6c6SAneesh Kumar K.V 		goto err_out;
862c797b6c6SAneesh Kumar K.V 
863c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
864c797b6c6SAneesh Kumar K.V 		goto err_out;
865c797b6c6SAneesh Kumar K.V 
866c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
867c797b6c6SAneesh Kumar K.V 	if (ret < 0)
868c797b6c6SAneesh Kumar K.V 		goto err_out;
869c797b6c6SAneesh Kumar K.V 
870c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
871c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
872c797b6c6SAneesh Kumar K.V 	free(name);
873c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
874c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
875c797b6c6SAneesh Kumar K.V 	return;
876c797b6c6SAneesh Kumar K.V err_out:
877c797b6c6SAneesh Kumar K.V 	free(name);
878c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
879c797b6c6SAneesh Kumar K.V 	return;
880c797b6c6SAneesh Kumar K.V }
881c797b6c6SAneesh Kumar K.V 
882c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev,
883c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
884c797b6c6SAneesh Kumar K.V {
885c797b6c6SAneesh Kumar K.V 	int ret;
886c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
887c797b6c6SAneesh Kumar K.V 	u32 fid_val, datasync;
888c797b6c6SAneesh Kumar K.V 
889c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
89031a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
891c797b6c6SAneesh Kumar K.V 
892c797b6c6SAneesh Kumar K.V 	if (datasync)
893c797b6c6SAneesh Kumar K.V 		ret = fdatasync(fid->fd);
894c797b6c6SAneesh Kumar K.V 	else
895c797b6c6SAneesh Kumar K.V 		ret = fsync(fid->fd);
896c797b6c6SAneesh Kumar K.V 	if (ret < 0)
897c797b6c6SAneesh Kumar K.V 		goto err_out;
898c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
899c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
900c797b6c6SAneesh Kumar K.V 	return;
901c797b6c6SAneesh Kumar K.V err_out:
902c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
903c797b6c6SAneesh Kumar K.V 	return;
904c797b6c6SAneesh Kumar K.V }
905c797b6c6SAneesh Kumar K.V 
906c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev,
907c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
908c797b6c6SAneesh Kumar K.V {
909c797b6c6SAneesh Kumar K.V 	int ret;
910c797b6c6SAneesh Kumar K.V 	struct stat st;
911c797b6c6SAneesh Kumar K.V 	u32 fid_val, gid;
912c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
913c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
914c797b6c6SAneesh Kumar K.V 	char new_name[PATH_MAX];
915c797b6c6SAneesh Kumar K.V 	char *old_path, *name;
916c797b6c6SAneesh Kumar K.V 
917c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
918c797b6c6SAneesh Kumar K.V 
91931a6fb8dSSasha Levin 	dfid = get_fid(p9dev, fid_val);
920c797b6c6SAneesh Kumar K.V 	sprintf(new_name, "%s/%s", dfid->abs_path, name);
921c797b6c6SAneesh Kumar K.V 	ret = symlink(old_path, new_name);
922c797b6c6SAneesh Kumar K.V 	if (ret < 0)
923c797b6c6SAneesh Kumar K.V 		goto err_out;
924c797b6c6SAneesh Kumar K.V 
925c797b6c6SAneesh Kumar K.V 	if (lstat(new_name, &st) < 0)
926c797b6c6SAneesh Kumar K.V 		goto err_out;
927c797b6c6SAneesh Kumar K.V 
928c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
929c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
930c797b6c6SAneesh Kumar K.V 	free(name);
931c797b6c6SAneesh Kumar K.V 	free(old_path);
932c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
933c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
934c797b6c6SAneesh Kumar K.V 	return;
935c797b6c6SAneesh Kumar K.V err_out:
936c797b6c6SAneesh Kumar K.V 	free(name);
937c797b6c6SAneesh Kumar K.V 	free(old_path);
938c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
939c797b6c6SAneesh Kumar K.V 	return;
940c797b6c6SAneesh Kumar K.V }
941c797b6c6SAneesh Kumar K.V 
942c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev,
943c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
944c797b6c6SAneesh Kumar K.V {
945c797b6c6SAneesh Kumar K.V 	int ret;
946c797b6c6SAneesh Kumar K.V 	char *name;
947c797b6c6SAneesh Kumar K.V 	u32 fid_val, dfid_val;
948c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid, *fid;
949c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
950c797b6c6SAneesh Kumar K.V 
951c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
952c797b6c6SAneesh Kumar K.V 
95331a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
95431a6fb8dSSasha Levin 	fid =  get_fid(p9dev, fid_val);
955c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
956c797b6c6SAneesh Kumar K.V 	ret = link(fid->abs_path, full_path);
957c797b6c6SAneesh Kumar K.V 	if (ret < 0)
958c797b6c6SAneesh Kumar K.V 		goto err_out;
959c797b6c6SAneesh Kumar K.V 	free(name);
960c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
961c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
962c797b6c6SAneesh Kumar K.V 	return;
963c797b6c6SAneesh Kumar K.V err_out:
964c797b6c6SAneesh Kumar K.V 	free(name);
965c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
966c797b6c6SAneesh Kumar K.V 	return;
967c797b6c6SAneesh Kumar K.V 
968c797b6c6SAneesh Kumar K.V }
969c797b6c6SAneesh Kumar K.V 
970c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev,
971c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
972c797b6c6SAneesh Kumar K.V {
973c797b6c6SAneesh Kumar K.V 	u8 ret;
974c797b6c6SAneesh Kumar K.V 	u32 fid_val;
975c797b6c6SAneesh Kumar K.V 	struct p9_flock flock;
976c797b6c6SAneesh Kumar K.V 
977c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
978c797b6c6SAneesh Kumar K.V 			    &flock.flags, &flock.start, &flock.length,
979c797b6c6SAneesh Kumar K.V 			    &flock.proc_id, &flock.client_id);
980c797b6c6SAneesh Kumar K.V 
981c797b6c6SAneesh Kumar K.V 	/* Just return success */
982c797b6c6SAneesh Kumar K.V 	ret = P9_LOCK_SUCCESS;
983c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", ret);
984c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
985c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
986c797b6c6SAneesh Kumar K.V 	free(flock.client_id);
987c797b6c6SAneesh Kumar K.V 	return;
988c797b6c6SAneesh Kumar K.V }
989c797b6c6SAneesh Kumar K.V 
990c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev,
991c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
992c797b6c6SAneesh Kumar K.V {
993c797b6c6SAneesh Kumar K.V 	u32 fid_val;
994c797b6c6SAneesh Kumar K.V 	struct p9_getlock glock;
995c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
996c797b6c6SAneesh Kumar K.V 			    &glock.start, &glock.length, &glock.proc_id,
997c797b6c6SAneesh Kumar K.V 			    &glock.client_id);
998c797b6c6SAneesh Kumar K.V 
999c797b6c6SAneesh Kumar K.V 	/* Just return success */
1000c797b6c6SAneesh Kumar K.V 	glock.type = F_UNLCK;
1001c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
1002c797b6c6SAneesh Kumar K.V 			     glock.start, glock.length, glock.proc_id,
1003c797b6c6SAneesh Kumar K.V 			     glock.client_id);
1004c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1005c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1006c797b6c6SAneesh Kumar K.V 	free(glock.client_id);
1007c797b6c6SAneesh Kumar K.V 	return;
1008c797b6c6SAneesh Kumar K.V }
1009c797b6c6SAneesh Kumar K.V 
1010c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor)
1011c797b6c6SAneesh Kumar K.V {
1012c797b6c6SAneesh Kumar K.V 	int size = strlen(ancestor);
1013c797b6c6SAneesh Kumar K.V 	if (!strncmp(path, ancestor, size)) {
1014c797b6c6SAneesh Kumar K.V 		/*
1015c797b6c6SAneesh Kumar K.V 		 * Now check whether ancestor is a full name or
1016c797b6c6SAneesh Kumar K.V 		 * or directory component and not just part
1017c797b6c6SAneesh Kumar K.V 		 * of a name.
1018c797b6c6SAneesh Kumar K.V 		 */
1019c797b6c6SAneesh Kumar K.V 		if (path[size] == '\0' || path[size] == '/')
1020c797b6c6SAneesh Kumar K.V 			return 1;
1021c797b6c6SAneesh Kumar K.V 	}
1022c797b6c6SAneesh Kumar K.V 	return 0;
1023c797b6c6SAneesh Kumar K.V }
1024c797b6c6SAneesh Kumar K.V 
1025c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name)
1026c797b6c6SAneesh Kumar K.V {
1027c797b6c6SAneesh Kumar K.V 	char tmp_name[PATH_MAX];
1028c797b6c6SAneesh Kumar K.V 	size_t rp_sz = strlen(old_name);
1029c797b6c6SAneesh Kumar K.V 
1030c797b6c6SAneesh Kumar K.V 	if (rp_sz == strlen(fid_path)) {
1031c797b6c6SAneesh Kumar K.V 		/* replace the full name */
1032c797b6c6SAneesh Kumar K.V 		strcpy(fid_path, new_name);
1033c797b6c6SAneesh Kumar K.V 		return;
1034c797b6c6SAneesh Kumar K.V 	}
1035c797b6c6SAneesh Kumar K.V 	/* save the trailing path details */
1036c797b6c6SAneesh Kumar K.V 	strcpy(tmp_name, fid_path + rp_sz);
1037c797b6c6SAneesh Kumar K.V 	sprintf(fid_path, "%s%s", new_name, tmp_name);
1038c797b6c6SAneesh Kumar K.V 	return;
1039c797b6c6SAneesh Kumar K.V }
1040c797b6c6SAneesh Kumar K.V 
1041e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name)
1042e2341580SSasha Levin {
1043e2341580SSasha Levin 	struct rb_node *node = rb_first(&p9dev->fids);
1044e2341580SSasha Levin 
1045e2341580SSasha Levin 	while (node) {
1046e2341580SSasha Levin 		struct p9_fid *fid = rb_entry(node, struct p9_fid, node);
1047e2341580SSasha Levin 
1048e2341580SSasha Levin 		if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) {
1049e2341580SSasha Levin 				virtio_p9_fix_path(fid->path, old_name, new_name);
1050e2341580SSasha Levin 		}
1051e2341580SSasha Levin 		node = rb_next(node);
1052e2341580SSasha Levin 	}
1053e2341580SSasha Levin }
1054e2341580SSasha Levin 
1055c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev,
1056c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
1057c797b6c6SAneesh Kumar K.V {
1058e2341580SSasha Levin 	int ret;
1059c797b6c6SAneesh Kumar K.V 	char *old_name, *new_name;
1060c797b6c6SAneesh Kumar K.V 	u32 old_dfid_val, new_dfid_val;
1061c797b6c6SAneesh Kumar K.V 	struct p9_fid *old_dfid, *new_dfid;
1062c797b6c6SAneesh Kumar K.V 	char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
1063c797b6c6SAneesh Kumar K.V 
1064c797b6c6SAneesh Kumar K.V 
1065c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
1066c797b6c6SAneesh Kumar K.V 			    &new_dfid_val, &new_name);
1067c797b6c6SAneesh Kumar K.V 
106831a6fb8dSSasha Levin 	old_dfid = get_fid(p9dev, old_dfid_val);
106931a6fb8dSSasha Levin 	new_dfid = get_fid(p9dev, new_dfid_val);
1070c797b6c6SAneesh Kumar K.V 
1071c797b6c6SAneesh Kumar K.V 	sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name);
1072c797b6c6SAneesh Kumar K.V 	sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name);
1073c797b6c6SAneesh Kumar K.V 	ret = rename(old_full_path, new_full_path);
1074c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1075c797b6c6SAneesh Kumar K.V 		goto err_out;
1076c797b6c6SAneesh Kumar K.V 	/*
1077c797b6c6SAneesh Kumar K.V 	 * Now fix path in other fids, if the renamed path is part of
1078c797b6c6SAneesh Kumar K.V 	 * that.
1079c797b6c6SAneesh Kumar K.V 	 */
1080e2341580SSasha Levin 	rename_fids(p9dev, old_name, new_name);
1081c797b6c6SAneesh Kumar K.V 	free(old_name);
1082c797b6c6SAneesh Kumar K.V 	free(new_name);
1083c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1084c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1085c797b6c6SAneesh Kumar K.V 	return;
1086c797b6c6SAneesh Kumar K.V err_out:
1087c797b6c6SAneesh Kumar K.V 	free(old_name);
1088c797b6c6SAneesh Kumar K.V 	free(new_name);
1089c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1090c797b6c6SAneesh Kumar K.V 	return;
1091c797b6c6SAneesh Kumar K.V }
1092c797b6c6SAneesh Kumar K.V 
1093c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev,
1094c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
1095c797b6c6SAneesh Kumar K.V {
1096c797b6c6SAneesh Kumar K.V 	int ret;
1097c797b6c6SAneesh Kumar K.V 	char *name;
1098c797b6c6SAneesh Kumar K.V 	u32 fid_val, flags;
1099c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
1100c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
1101c797b6c6SAneesh Kumar K.V 
1102c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
110331a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
1104c797b6c6SAneesh Kumar K.V 
1105c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", fid->abs_path, name);
1106c797b6c6SAneesh Kumar K.V 	ret = remove(full_path);
1107c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1108c797b6c6SAneesh Kumar K.V 		goto err_out;
1109c797b6c6SAneesh Kumar K.V 	free(name);
1110c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1111c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1112c797b6c6SAneesh Kumar K.V 	return;
1113c797b6c6SAneesh Kumar K.V err_out:
1114c797b6c6SAneesh Kumar K.V 	free(name);
1115c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1116c797b6c6SAneesh Kumar K.V 	return;
1117c797b6c6SAneesh Kumar K.V }
1118c797b6c6SAneesh Kumar K.V 
11195cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev,
11205cc808aaSSasha Levin 				struct p9_pdu *pdu, u32 *outlen)
11215cc808aaSSasha Levin {
11225cc808aaSSasha Levin 	u16 tag, oldtag;
11235cc808aaSSasha Levin 
11245cc808aaSSasha Levin 	virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag);
11255cc808aaSSasha Levin 	virtio_p9_pdu_writef(pdu, "w", tag);
11265cc808aaSSasha Levin 	*outlen = pdu->write_offset;
11275cc808aaSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
11285cc808aaSSasha Levin 
11295cc808aaSSasha Levin 	return;
11305cc808aaSSasha Levin }
11315cc808aaSSasha Levin 
1132c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
1133c797b6c6SAneesh Kumar K.V 				 struct p9_pdu *pdu, u32 *outlen)
1134c797b6c6SAneesh Kumar K.V {
1135c797b6c6SAneesh Kumar K.V 	return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
1136c797b6c6SAneesh Kumar K.V }
1137c797b6c6SAneesh Kumar K.V 
1138ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev,
1139af045e53SAneesh Kumar K.V 			struct p9_pdu *pdu, u32 *outlen);
1140b4422bf3SAneesh Kumar K.V 
1141c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */
1142c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74
1143c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76
1144c797b6c6SAneesh Kumar K.V 
1145c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = {
1146c797b6c6SAneesh Kumar K.V 	[P9_TREADDIR]     = virtio_p9_readdir,
1147c797b6c6SAneesh Kumar K.V 	[P9_TSTATFS]      = virtio_p9_statfs,
1148c797b6c6SAneesh Kumar K.V 	[P9_TGETATTR]     = virtio_p9_getattr,
1149c797b6c6SAneesh Kumar K.V 	[P9_TSETATTR]     = virtio_p9_setattr,
1150c797b6c6SAneesh Kumar K.V 	[P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
1151c797b6c6SAneesh Kumar K.V 	[P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
1152c797b6c6SAneesh Kumar K.V 	[P9_TMKNOD]       = virtio_p9_mknod,
1153c797b6c6SAneesh Kumar K.V 	[P9_TLOCK]        = virtio_p9_lock,
1154c797b6c6SAneesh Kumar K.V 	[P9_TGETLOCK]     = virtio_p9_getlock,
1155c797b6c6SAneesh Kumar K.V 	[P9_TRENAMEAT]    = virtio_p9_renameat,
1156c797b6c6SAneesh Kumar K.V 	[P9_TREADLINK]    = virtio_p9_readlink,
1157c797b6c6SAneesh Kumar K.V 	[P9_TUNLINKAT]    = virtio_p9_unlinkat,
1158c797b6c6SAneesh Kumar K.V 	[P9_TMKDIR]       = virtio_p9_mkdir,
1159b4422bf3SAneesh Kumar K.V 	[P9_TVERSION]     = virtio_p9_version,
1160c797b6c6SAneesh Kumar K.V 	[P9_TLOPEN]       = virtio_p9_open,
1161b4422bf3SAneesh Kumar K.V 	[P9_TATTACH]      = virtio_p9_attach,
1162b4422bf3SAneesh Kumar K.V 	[P9_TWALK]        = virtio_p9_walk,
1163c797b6c6SAneesh Kumar K.V 	[P9_TCLUNK]       = virtio_p9_clunk,
1164c797b6c6SAneesh Kumar K.V 	[P9_TFSYNC]       = virtio_p9_fsync,
1165b4422bf3SAneesh Kumar K.V 	[P9_TREAD]        = virtio_p9_read,
11665cc808aaSSasha Levin 	[P9_TFLUSH]       = virtio_p9_flush,
1167c797b6c6SAneesh Kumar K.V 	[P9_TLINK]        = virtio_p9_link,
1168c797b6c6SAneesh Kumar K.V 	[P9_TSYMLINK]     = virtio_p9_symlink,
1169c797b6c6SAneesh Kumar K.V 	[P9_TLCREATE]     = virtio_p9_create,
1170b4422bf3SAneesh Kumar K.V 	[P9_TWRITE]       = virtio_p9_write,
11716fc5cd9bSSasha Levin 	[P9_TREMOVE]      = virtio_p9_remove,
1172f161f28bSSasha Levin 	[P9_TRENAME]      = virtio_p9_rename,
1173b4422bf3SAneesh Kumar K.V };
1174b4422bf3SAneesh Kumar K.V 
1175af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
1176af045e53SAneesh Kumar K.V {
1177af045e53SAneesh Kumar K.V 	struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
1178af045e53SAneesh Kumar K.V 	if (!pdu)
1179af045e53SAneesh Kumar K.V 		return NULL;
1180af045e53SAneesh Kumar K.V 
1181bfc15268SAneesh Kumar K.V 	/* skip the pdu header p9_msg */
11825529bcd7SAsias He 	pdu->read_offset	= VIRTIO_9P_HDR_LEN;
11835529bcd7SAsias He 	pdu->write_offset	= VIRTIO_9P_HDR_LEN;
1184af045e53SAneesh Kumar K.V 	pdu->queue_head		= virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
1185a8a44649SAsias He 					pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
1186af045e53SAneesh Kumar K.V 	return pdu;
1187af045e53SAneesh Kumar K.V }
1188af045e53SAneesh Kumar K.V 
1189af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
1190af045e53SAneesh Kumar K.V {
1191af045e53SAneesh Kumar K.V 	struct p9_msg *msg;
1192af045e53SAneesh Kumar K.V 	/*
1193af045e53SAneesh Kumar K.V 	 * we can peek directly into pdu for a u8
1194af045e53SAneesh Kumar K.V 	 * value. The host endianess won't be an issue
1195af045e53SAneesh Kumar K.V 	 */
1196af045e53SAneesh Kumar K.V 	msg = pdu->out_iov[0].iov_base;
1197af045e53SAneesh Kumar K.V 	return msg->cmd;
1198af045e53SAneesh Kumar K.V }
1199af045e53SAneesh Kumar K.V 
1200b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
12011c7850f9SSasha Levin {
1202af045e53SAneesh Kumar K.V 	u8 cmd;
1203b4422bf3SAneesh Kumar K.V 	u32 len = 0;
1204b4422bf3SAneesh Kumar K.V 	p9_handler *handler;
1205b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev;
1206af045e53SAneesh Kumar K.V 	struct virt_queue *vq;
1207af045e53SAneesh Kumar K.V 	struct p9_pdu *p9pdu;
12081c7850f9SSasha Levin 
1209b4422bf3SAneesh Kumar K.V 	vq = job->vq;
1210b4422bf3SAneesh Kumar K.V 	p9dev = job->p9dev;
12111c7850f9SSasha Levin 
1212af045e53SAneesh Kumar K.V 	p9pdu = virtio_p9_pdu_init(kvm, vq);
1213af045e53SAneesh Kumar K.V 	cmd = virtio_p9_get_cmd(p9pdu);
1214af045e53SAneesh Kumar K.V 
1215c797b6c6SAneesh Kumar K.V 	if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
1216c797b6c6SAneesh Kumar K.V 	    !virtio_9p_dotl_handler[cmd])
121797b408afSAneesh Kumar K.V 		handler = virtio_p9_eopnotsupp;
1218dd78d9eaSAneesh Kumar K.V 	else
1219c797b6c6SAneesh Kumar K.V 		handler = virtio_9p_dotl_handler[cmd];
1220c797b6c6SAneesh Kumar K.V 
1221af045e53SAneesh Kumar K.V 	handler(p9dev, p9pdu, &len);
1222af045e53SAneesh Kumar K.V 	virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
1223af045e53SAneesh Kumar K.V 	free(p9pdu);
12241c7850f9SSasha Levin 	return true;
12251c7850f9SSasha Levin }
12261c7850f9SSasha Levin 
12271c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param)
12281c7850f9SSasha Levin {
1229b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job = (struct p9_dev_job *)param;
1230b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev   = job->p9dev;
1231b4422bf3SAneesh Kumar K.V 	struct virt_queue *vq  = job->vq;
12321c7850f9SSasha Levin 
12331c7850f9SSasha Levin 	while (virt_queue__available(vq)) {
1234b4422bf3SAneesh Kumar K.V 		virtio_p9_do_io_request(kvm, job);
123502eca50cSAsias He 		p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
12361c7850f9SSasha Levin 	}
12371c7850f9SSasha Levin }
12381c7850f9SSasha Levin 
1239c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev)
12401c7850f9SSasha Levin {
1241c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
12421c7850f9SSasha Levin 
1243c5ae742bSSasha Levin 	return ((u8 *)(p9dev->config));
1244c7838fbdSSasha Levin }
1245c7838fbdSSasha Levin 
1246c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev)
1247c7838fbdSSasha Levin {
1248c7838fbdSSasha Levin 	return 1 << VIRTIO_9P_MOUNT_TAG;
1249c7838fbdSSasha Levin }
1250c7838fbdSSasha Levin 
1251c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
1252c7838fbdSSasha Levin {
1253c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1254c7838fbdSSasha Levin 
1255c7838fbdSSasha Levin 	p9dev->features = features;
1256c7838fbdSSasha Levin }
1257c7838fbdSSasha Levin 
1258c59ba304SWill Deacon static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
1259c59ba304SWill Deacon 		   u32 pfn)
1260c7838fbdSSasha Levin {
1261c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1262b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job;
1263b4422bf3SAneesh Kumar K.V 	struct virt_queue *queue;
1264c7838fbdSSasha Levin 	void *p;
12651c7850f9SSasha Levin 
1266312c62d1SSasha Levin 	compat__remove_message(compat_id);
1267e59662b3SSasha Levin 
1268c7838fbdSSasha Levin 	queue		= &p9dev->vqs[vq];
1269c7838fbdSSasha Levin 	queue->pfn	= pfn;
1270e7e2950aSSasha Levin 	p		= virtio_get_vq(kvm, queue->pfn, page_size);
1271c7838fbdSSasha Levin 	job		= &p9dev->jobs[vq];
12721c7850f9SSasha Levin 
1273c59ba304SWill Deacon 	vring_init(&queue->vring, VIRTQUEUE_NUM, p, align);
12741c7850f9SSasha Levin 
1275b4422bf3SAneesh Kumar K.V 	*job		= (struct p9_dev_job) {
1276b4422bf3SAneesh Kumar K.V 		.vq		= queue,
1277b4422bf3SAneesh Kumar K.V 		.p9dev		= p9dev,
1278b4422bf3SAneesh Kumar K.V 	};
1279df0c7f57SSasha Levin 	thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
128060eb42d5SSasha Levin 
1281c7838fbdSSasha Levin 	return 0;
12821c7850f9SSasha Levin }
12831c7850f9SSasha Levin 
1284c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
1285c7838fbdSSasha Levin {
1286c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
12871c7850f9SSasha Levin 
1288c7838fbdSSasha Levin 	thread_pool__do_job(&p9dev->jobs[vq].job_id);
1289c7838fbdSSasha Levin 
1290c7838fbdSSasha Levin 	return 0;
1291c7838fbdSSasha Levin }
1292c7838fbdSSasha Levin 
1293c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
1294c7838fbdSSasha Levin {
1295c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1296c7838fbdSSasha Levin 
1297c7838fbdSSasha Levin 	return p9dev->vqs[vq].pfn;
1298c7838fbdSSasha Levin }
1299c7838fbdSSasha Levin 
1300c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
1301c7838fbdSSasha Levin {
1302c7838fbdSSasha Levin 	return VIRTQUEUE_NUM;
1303c7838fbdSSasha Levin }
1304c7838fbdSSasha Levin 
13057aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
13067aba29c1SWill Deacon {
13077aba29c1SWill Deacon 	/* FIXME: dynamic */
13087aba29c1SWill Deacon 	return size;
13097aba29c1SWill Deacon }
13107aba29c1SWill Deacon 
13111c47ce69SSasha Levin struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) {
1312c7838fbdSSasha Levin 	.get_config		= get_config,
1313c7838fbdSSasha Levin 	.get_host_features	= get_host_features,
1314c7838fbdSSasha Levin 	.set_guest_features	= set_guest_features,
1315c7838fbdSSasha Levin 	.init_vq		= init_vq,
1316c7838fbdSSasha Levin 	.notify_vq		= notify_vq,
1317c7838fbdSSasha Levin 	.get_pfn_vq		= get_pfn_vq,
1318c7838fbdSSasha Levin 	.get_size_vq		= get_size_vq,
13197aba29c1SWill Deacon 	.set_size_vq		= set_size_vq,
1320c7838fbdSSasha Levin };
13211c47ce69SSasha Levin 
1322cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
1323cac9e8fdSSasha Levin {
1324cac9e8fdSSasha Levin 	char *tag_name;
1325cac9e8fdSSasha Levin 	char tmp[PATH_MAX];
1326cac9e8fdSSasha Levin 	struct kvm *kvm = opt->ptr;
1327cac9e8fdSSasha Levin 
1328cac9e8fdSSasha Levin 	/*
1329cac9e8fdSSasha Levin 	 * 9p dir can be of the form dirname,tag_name or
1330cac9e8fdSSasha Levin 	 * just dirname. In the later case we use the
1331cac9e8fdSSasha Levin 	 * default tag name
1332cac9e8fdSSasha Levin 	 */
1333cac9e8fdSSasha Levin 	tag_name = strstr(arg, ",");
1334cac9e8fdSSasha Levin 	if (tag_name) {
1335cac9e8fdSSasha Levin 		*tag_name = '\0';
1336cac9e8fdSSasha Levin 		tag_name++;
1337cac9e8fdSSasha Levin 	}
1338cac9e8fdSSasha Levin 	if (realpath(arg, tmp)) {
1339cac9e8fdSSasha Levin 		if (virtio_9p__register(kvm, tmp, tag_name) < 0)
1340cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1341cac9e8fdSSasha Levin 	} else
1342cac9e8fdSSasha Levin 		die("Failed resolving 9p path");
1343cac9e8fdSSasha Levin 	return 0;
1344cac9e8fdSSasha Levin }
1345cac9e8fdSSasha Levin 
1346cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset)
1347cac9e8fdSSasha Levin {
1348cac9e8fdSSasha Levin 	char path[PATH_MAX];
1349cac9e8fdSSasha Levin 	struct stat st;
1350cac9e8fdSSasha Levin 	struct kvm *kvm = opt->ptr;
1351cac9e8fdSSasha Levin 
1352cac9e8fdSSasha Levin 	if (stat(arg, &st) == 0 &&
1353cac9e8fdSSasha Levin 	    S_ISDIR(st.st_mode)) {
1354cac9e8fdSSasha Levin 		char tmp[PATH_MAX];
1355cac9e8fdSSasha Levin 
1356cac9e8fdSSasha Levin 		if (kvm->cfg.using_rootfs)
1357cac9e8fdSSasha Levin 			die("Please use only one rootfs directory atmost");
1358cac9e8fdSSasha Levin 
1359cac9e8fdSSasha Levin 		if (realpath(arg, tmp) == 0 ||
1360cac9e8fdSSasha Levin 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1361cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1362cac9e8fdSSasha Levin 		kvm->cfg.using_rootfs = 1;
1363cac9e8fdSSasha Levin 		return 0;
1364cac9e8fdSSasha Levin 	}
1365cac9e8fdSSasha Levin 
1366cac9e8fdSSasha Levin 	snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
1367cac9e8fdSSasha Levin 
1368cac9e8fdSSasha Levin 	if (stat(path, &st) == 0 &&
1369cac9e8fdSSasha Levin 	    S_ISDIR(st.st_mode)) {
1370cac9e8fdSSasha Levin 		char tmp[PATH_MAX];
1371cac9e8fdSSasha Levin 
1372cac9e8fdSSasha Levin 		if (kvm->cfg.using_rootfs)
1373cac9e8fdSSasha Levin 			die("Please use only one rootfs directory atmost");
1374cac9e8fdSSasha Levin 
1375cac9e8fdSSasha Levin 		if (realpath(path, tmp) == 0 ||
1376cac9e8fdSSasha Levin 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1377cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1378cac9e8fdSSasha Levin 		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
1379cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1380cac9e8fdSSasha Levin 		kvm_setup_resolv(arg);
1381cac9e8fdSSasha Levin 		kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1;
1382cac9e8fdSSasha Levin 		kvm->cfg.custom_rootfs_name = arg;
1383cac9e8fdSSasha Levin 		return 0;
1384cac9e8fdSSasha Levin 	}
1385cac9e8fdSSasha Levin 
1386cac9e8fdSSasha Levin 	return -1;
1387cac9e8fdSSasha Levin }
1388cac9e8fdSSasha Levin 
13891c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm)
13901c47ce69SSasha Levin {
13911c47ce69SSasha Levin 	struct p9_dev *p9dev;
13921c47ce69SSasha Levin 
13931c47ce69SSasha Levin 	list_for_each_entry(p9dev, &devs, list) {
139402eca50cSAsias He 		virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
1395*d97dadecSWill Deacon 			    VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_9P,
1396ae06ce71SWill Deacon 			    VIRTIO_ID_9P, PCI_CLASS_9P);
1397c7838fbdSSasha Levin 	}
1398c7838fbdSSasha Levin 
1399c7838fbdSSasha Levin 	return 0;
1400c7838fbdSSasha Levin }
140149a8afd1SSasha Levin virtio_dev_init(virtio_9p__init);
1402c7838fbdSSasha Levin 
1403c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
1404c7838fbdSSasha Levin {
1405c7838fbdSSasha Levin 	struct p9_dev *p9dev;
140654f6802dSPekka Enberg 	int err = 0;
14071c7850f9SSasha Levin 
1408b4422bf3SAneesh Kumar K.V 	p9dev = calloc(1, sizeof(*p9dev));
1409b4422bf3SAneesh Kumar K.V 	if (!p9dev)
141054f6802dSPekka Enberg 		return -ENOMEM;
141154f6802dSPekka Enberg 
1412b4422bf3SAneesh Kumar K.V 	if (!tag_name)
14135529bcd7SAsias He 		tag_name = VIRTIO_9P_DEFAULT_TAG;
141454f6802dSPekka Enberg 
1415b4422bf3SAneesh Kumar K.V 	p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1);
141654f6802dSPekka Enberg 	if (p9dev->config == NULL) {
141754f6802dSPekka Enberg 		err = -ENOMEM;
1418b4422bf3SAneesh Kumar K.V 		goto free_p9dev;
141954f6802dSPekka Enberg 	}
14201c7850f9SSasha Levin 
1421b4422bf3SAneesh Kumar K.V 	strcpy(p9dev->root_dir, root);
1422b4422bf3SAneesh Kumar K.V 	p9dev->config->tag_len = strlen(tag_name);
142354f6802dSPekka Enberg 	if (p9dev->config->tag_len > MAX_TAG_LEN) {
142454f6802dSPekka Enberg 		err = -EINVAL;
1425b4422bf3SAneesh Kumar K.V 		goto free_p9dev_config;
142654f6802dSPekka Enberg 	}
14271c7850f9SSasha Levin 
1428c7838fbdSSasha Levin 	memcpy(&p9dev->config->tag, tag_name, strlen(tag_name));
14291c7850f9SSasha Levin 
1430c7838fbdSSasha Levin 	list_add(&p9dev->list, &devs);
1431b4422bf3SAneesh Kumar K.V 
1432d278197dSAsias He 	if (compat_id == -1)
143352f34d2cSAsias He 		compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO");
1434e59662b3SSasha Levin 
143554f6802dSPekka Enberg 	return err;
143654f6802dSPekka Enberg 
1437b4422bf3SAneesh Kumar K.V free_p9dev_config:
1438b4422bf3SAneesh Kumar K.V 	free(p9dev->config);
1439b4422bf3SAneesh Kumar K.V free_p9dev:
1440b4422bf3SAneesh Kumar K.V 	free(p9dev);
144154f6802dSPekka Enberg 	return err;
14421c7850f9SSasha Levin }
1443