xref: /kvmtool/virtio/9p.c (revision 867b15ccd7dae9ba7a174f97d4fe76e90a79d957)
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>
14c0a98553SJeremy Linton #include <sys/sysmacros.h>
15bfc15268SAneesh Kumar K.V #include <unistd.h>
16bfc15268SAneesh Kumar K.V #include <string.h>
17bfc15268SAneesh Kumar K.V #include <errno.h>
18c797b6c6SAneesh Kumar K.V #include <sys/vfs.h>
191c7850f9SSasha Levin 
202daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h>
212daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h>
22c6cb7c75SAndre Przywara #include <linux/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;
32e277a1b4SG. Campana 	size_t len;
33e2341580SSasha Levin 
34e2341580SSasha Levin 	while (node) {
35e2341580SSasha Levin 		struct p9_fid *cur = rb_entry(node, struct p9_fid, node);
36e2341580SSasha Levin 
37e2341580SSasha Levin 		if (fid < cur->fid) {
38e2341580SSasha Levin 			node = node->rb_left;
39e2341580SSasha Levin 		} else if (fid > cur->fid) {
40e2341580SSasha Levin 			node = node->rb_right;
41e2341580SSasha Levin 		} else {
42e2341580SSasha Levin 			return cur;
43e2341580SSasha Levin 		}
44e2341580SSasha Levin 	}
45e2341580SSasha Levin 
46e2341580SSasha Levin 	pfid = calloc(sizeof(*pfid), 1);
47e2341580SSasha Levin 	if (!pfid)
48e2341580SSasha Levin 		return NULL;
49e2341580SSasha Levin 
50e277a1b4SG. Campana 	len = strlen(dev->root_dir);
51e277a1b4SG. Campana 	if (len >= sizeof(pfid->abs_path)) {
52e277a1b4SG. Campana 		free(pfid);
53e277a1b4SG. Campana 		return NULL;
54e277a1b4SG. Campana 	}
55e277a1b4SG. Campana 
56e2341580SSasha Levin 	pfid->fid = fid;
57e2341580SSasha Levin 	strcpy(pfid->abs_path, dev->root_dir);
58e277a1b4SG. Campana 	pfid->path = pfid->abs_path + strlen(pfid->abs_path);
59e2341580SSasha Levin 
60e2341580SSasha Levin 	insert_new_fid(dev, pfid);
61e2341580SSasha Levin 
62e2341580SSasha Levin 	return pfid;
63e2341580SSasha Levin }
64e2341580SSasha Levin 
65e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid)
66e2341580SSasha Levin {
67e2341580SSasha Levin 	struct rb_node **node = &(dev->fids.rb_node), *parent = NULL;
68e2341580SSasha Levin 
69e2341580SSasha Levin 	while (*node) {
70e2341580SSasha Levin 		int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid;
71e2341580SSasha Levin 
72e2341580SSasha Levin 		parent = *node;
73e2341580SSasha Levin 		if (result < 0)
74e2341580SSasha Levin 			node    = &((*node)->rb_left);
75e2341580SSasha Levin 		else if (result > 0)
76e2341580SSasha Levin 			node    = &((*node)->rb_right);
77e2341580SSasha Levin 		else
78e2341580SSasha Levin 			return -EEXIST;
79e2341580SSasha Levin 	}
80e2341580SSasha Levin 
81e2341580SSasha Levin 	rb_link_node(&fid->node, parent, node);
82e2341580SSasha Levin 	rb_insert_color(&fid->node, &dev->fids);
83e2341580SSasha Levin 	return 0;
84e2341580SSasha Levin }
85e2341580SSasha Levin 
8631a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
8731a6fb8dSSasha Levin {
88e2341580SSasha Levin 	struct p9_fid *new;
8931a6fb8dSSasha Levin 
90e2341580SSasha Levin 	new = find_or_create_fid(p9dev, fid);
91e2341580SSasha Levin 
92e2341580SSasha Levin 	return new;
9331a6fb8dSSasha Levin }
9431a6fb8dSSasha Levin 
95c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid)
961c7850f9SSasha Levin {
971c7850f9SSasha Levin 	*qid = (struct p9_qid) {
981c7850f9SSasha Levin 		.path		= st->st_ino,
991c7850f9SSasha Levin 		.version	= st->st_mtime,
1001c7850f9SSasha Levin 	};
1011c7850f9SSasha Levin 
1021c7850f9SSasha Levin 	if (S_ISDIR(st->st_mode))
1031c7850f9SSasha Levin 		qid->type	|= P9_QTDIR;
1041c7850f9SSasha Levin }
1051c7850f9SSasha Levin 
106b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid)
1071c7850f9SSasha Levin {
108e2341580SSasha Levin 	struct p9_fid *pfid = get_fid(p9dev, fid);
109e2341580SSasha Levin 
110e2341580SSasha Levin 	if (pfid->fd > 0)
111e2341580SSasha Levin 		close(pfid->fd);
112e2341580SSasha Levin 
113e2341580SSasha Levin 	if (pfid->dir)
114e2341580SSasha Levin 		closedir(pfid->dir);
115e2341580SSasha Levin 
116e2341580SSasha Levin 	rb_erase(&pfid->node, &p9dev->fids);
117e2341580SSasha Levin 	free(pfid);
1181c7850f9SSasha Levin }
119e2341580SSasha Levin 
120bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
1211c7850f9SSasha Levin {
122bfc15268SAneesh Kumar K.V 	u8 cmd;
123bfc15268SAneesh Kumar K.V 	u16 tag;
124bfc15268SAneesh Kumar K.V 
125bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32);
126bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
127bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
128bfc15268SAneesh Kumar K.V 	/* cmd + 1 is the reply message */
129bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
1301c7850f9SSasha Levin }
1311c7850f9SSasha Levin 
1326b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
1336b163a87SAneesh Kumar K.V {
1346b163a87SAneesh Kumar K.V 	int i;
1356b163a87SAneesh Kumar K.V 	u32 total = 0;
1366b163a87SAneesh Kumar K.V 	for (i = 0; (i < iov_cnt) && (total < count); i++) {
1376b163a87SAneesh Kumar K.V 		if (total + iov[i].iov_len > count) {
1386b163a87SAneesh Kumar K.V 			/* we don't need this iov fully */
1396b163a87SAneesh Kumar K.V 			iov[i].iov_len -= ((total + iov[i].iov_len) - count);
1406b163a87SAneesh Kumar K.V 			i++;
1416b163a87SAneesh Kumar K.V 			break;
1426b163a87SAneesh Kumar K.V 		}
1436b163a87SAneesh Kumar K.V 		total += iov[i].iov_len;
1446b163a87SAneesh Kumar K.V 	}
1456b163a87SAneesh Kumar K.V 	return i;
1466b163a87SAneesh Kumar K.V }
1476b163a87SAneesh Kumar K.V 
148eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev,
149eee1ba8eSAneesh Kumar K.V 				  struct p9_pdu *pdu, int err, u32 *outlen)
150eee1ba8eSAneesh Kumar K.V {
151bfc15268SAneesh Kumar K.V 	u16 tag;
152eee1ba8eSAneesh Kumar K.V 
1539c2e1d1aSSuzuki K. Poulose 	/* EMFILE at server implies ENFILE for the VM */
1549c2e1d1aSSuzuki K. Poulose 	if (err == EMFILE)
1559c2e1d1aSSuzuki K. Poulose 		err = ENFILE;
1569c2e1d1aSSuzuki K. Poulose 
1575529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
158c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", err);
159bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
160eee1ba8eSAneesh Kumar K.V 
161c797b6c6SAneesh Kumar K.V 	/* read the tag from input */
162bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32) + sizeof(u8);
163bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "w", &tag);
164bfc15268SAneesh Kumar K.V 
165c797b6c6SAneesh Kumar K.V 	/* Update the header */
166bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
167c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
168eee1ba8eSAneesh Kumar K.V }
169eee1ba8eSAneesh Kumar K.V 
170ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev,
171af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
1721c7850f9SSasha Levin {
173c797b6c6SAneesh Kumar K.V 	u32 msize;
174c797b6c6SAneesh Kumar K.V 	char *version;
175c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
176c797b6c6SAneesh Kumar K.V 	/*
177c797b6c6SAneesh Kumar K.V 	 * reply with the same msize the client sent us
178c797b6c6SAneesh Kumar K.V 	 * Error out if the request is not for 9P2000.L
179c797b6c6SAneesh Kumar K.V 	 */
1805529bcd7SAsias He 	if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
181c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, version);
182c797b6c6SAneesh Kumar K.V 	else
183c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
1841c7850f9SSasha Levin 
185bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
186bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
187c797b6c6SAneesh Kumar K.V 	free(version);
188ead43b01SAneesh Kumar K.V 	return;
1891c7850f9SSasha Levin }
1901c7850f9SSasha Levin 
191ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev,
192af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
1931c7850f9SSasha Levin {
194bfc15268SAneesh Kumar K.V 	u32 fid;
1951c7850f9SSasha Levin 
196bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid);
197bfc15268SAneesh Kumar K.V 	close_fid(p9dev, fid);
1981c7850f9SSasha Levin 
199bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
200bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
201ead43b01SAneesh Kumar K.V 	return;
2021c7850f9SSasha Levin }
2031c7850f9SSasha Levin 
204c797b6c6SAneesh Kumar K.V /*
205c797b6c6SAneesh Kumar K.V  * FIXME!! Need to map to protocol independent value. Upstream
206c797b6c6SAneesh Kumar K.V  * 9p also have the same BUG
207c797b6c6SAneesh Kumar K.V  */
208c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags)
209c797b6c6SAneesh Kumar K.V {
210c797b6c6SAneesh Kumar K.V 	flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
211c797b6c6SAneesh Kumar K.V 	flags |= O_NOFOLLOW;
212c797b6c6SAneesh Kumar K.V 	return flags;
213c797b6c6SAneesh Kumar K.V }
214c797b6c6SAneesh Kumar K.V 
21532585666SSasha Levin static bool is_dir(struct p9_fid *fid)
21632585666SSasha Levin {
21732585666SSasha Levin 	struct stat st;
21832585666SSasha Levin 
21932585666SSasha Levin 	stat(fid->abs_path, &st);
22032585666SSasha Levin 
22132585666SSasha Levin 	return S_ISDIR(st.st_mode);
22232585666SSasha Levin }
22332585666SSasha Levin 
2249bb99a82SG. Campana /* path is always absolute */
2259bb99a82SG. Campana static bool path_is_illegal(const char *path)
2269bb99a82SG. Campana {
2279bb99a82SG. Campana 	size_t len;
2289bb99a82SG. Campana 
2299bb99a82SG. Campana 	if (strstr(path, "/../") != NULL)
2309bb99a82SG. Campana 		return true;
2319bb99a82SG. Campana 
2329bb99a82SG. Campana 	len = strlen(path);
2339bb99a82SG. Campana 	if (len >= 3 && strcmp(path + len - 3, "/..") == 0)
2349bb99a82SG. Campana 		return true;
2359bb99a82SG. Campana 
2369bb99a82SG. Campana 	return false;
2379bb99a82SG. Campana }
2389bb99a82SG. Campana 
239d4727f2bSG. Campana static int get_full_path_helper(char *full_path, size_t size,
240d4727f2bSG. Campana 			 const char *dirname, const char *name)
241d4727f2bSG. Campana {
242d4727f2bSG. Campana 	int ret;
243d4727f2bSG. Campana 
244d4727f2bSG. Campana 	ret = snprintf(full_path, size, "%s/%s", dirname, name);
245716b2944SG. Campana 	if (ret >= (int)size) {
246d4727f2bSG. Campana 		errno = ENAMETOOLONG;
247d4727f2bSG. Campana 		return -1;
248d4727f2bSG. Campana 	}
249d4727f2bSG. Campana 
250d4727f2bSG. Campana 	if (path_is_illegal(full_path)) {
251d4727f2bSG. Campana 		errno = EACCES;
252d4727f2bSG. Campana 		return -1;
253d4727f2bSG. Campana 	}
254d4727f2bSG. Campana 
255d4727f2bSG. Campana 	return 0;
256d4727f2bSG. Campana }
257d4727f2bSG. Campana 
258d4727f2bSG. Campana static int get_full_path(char *full_path, size_t size, struct p9_fid *fid,
259d4727f2bSG. Campana 			 const char *name)
260d4727f2bSG. Campana {
261d4727f2bSG. Campana 	return get_full_path_helper(full_path, size, fid->abs_path, name);
262d4727f2bSG. Campana }
263d4727f2bSG. Campana 
264b0922422SG. Campana static int stat_rel(struct p9_dev *p9dev, const char *path, struct stat *st)
265b0922422SG. Campana {
266b0922422SG. Campana 	char full_path[PATH_MAX];
267b0922422SG. Campana 
268b0922422SG. Campana 	if (get_full_path_helper(full_path, sizeof(full_path), p9dev->root_dir, path) != 0)
269b0922422SG. Campana 		return -1;
270b0922422SG. Campana 
271b0922422SG. Campana 	if (lstat(full_path, st) != 0)
272b0922422SG. Campana 		return -1;
273b0922422SG. Campana 
274b0922422SG. Campana 	return 0;
275b0922422SG. Campana }
276b0922422SG. Campana 
277ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev,
278af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
2791c7850f9SSasha Levin {
280c797b6c6SAneesh Kumar K.V 	u32 fid, flags;
2811c7850f9SSasha Levin 	struct stat st;
282bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
283bfc15268SAneesh Kumar K.V 	struct p9_fid *new_fid;
284bfc15268SAneesh Kumar K.V 
285c797b6c6SAneesh Kumar K.V 
286c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
28731a6fb8dSSasha Levin 	new_fid = get_fid(p9dev, fid);
2881c7850f9SSasha Levin 
28930204a77SAneesh Kumar K.V 	if (lstat(new_fid->abs_path, &st) < 0)
290eee1ba8eSAneesh Kumar K.V 		goto err_out;
2911c7850f9SSasha Levin 
292c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
2931c7850f9SSasha Levin 
29432585666SSasha Levin 	if (is_dir(new_fid)) {
2951c7850f9SSasha Levin 		new_fid->dir = opendir(new_fid->abs_path);
296eee1ba8eSAneesh Kumar K.V 		if (!new_fid->dir)
297eee1ba8eSAneesh Kumar K.V 			goto err_out;
298eee1ba8eSAneesh Kumar K.V 	} else {
299eee1ba8eSAneesh Kumar K.V 		new_fid->fd  = open(new_fid->abs_path,
300c797b6c6SAneesh Kumar K.V 				    virtio_p9_openflags(flags));
301eee1ba8eSAneesh Kumar K.V 		if (new_fid->fd < 0)
302eee1ba8eSAneesh Kumar K.V 			goto err_out;
303eee1ba8eSAneesh Kumar K.V 	}
304c797b6c6SAneesh Kumar K.V 	/* FIXME!! need ot send proper iounit  */
305bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
306bfc15268SAneesh Kumar K.V 
307bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
308bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
309ead43b01SAneesh Kumar K.V 	return;
310eee1ba8eSAneesh Kumar K.V err_out:
311eee1ba8eSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
312ead43b01SAneesh Kumar K.V 	return;
3131c7850f9SSasha Levin }
3141c7850f9SSasha Levin 
315ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev,
316af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
3171c7850f9SSasha Levin {
318c797b6c6SAneesh Kumar K.V 	int fd, ret;
319bfc15268SAneesh Kumar K.V 	char *name;
32032832dd1SG. Campana 	size_t size;
321af045e53SAneesh Kumar K.V 	struct stat st;
322bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
323c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
3244bc9734aSAneesh Kumar K.V 	char full_path[PATH_MAX];
32504d604b6SAnisse Astier 	char *tmp_path;
326c797b6c6SAneesh Kumar K.V 	u32 dfid_val, flags, mode, gid;
327af045e53SAneesh Kumar K.V 
328c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
329c797b6c6SAneesh Kumar K.V 			    &name, &flags, &mode, &gid);
33031a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
3311c7850f9SSasha Levin 
332d4727f2bSG. Campana 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
33332832dd1SG. Campana 		goto err_out;
3349bb99a82SG. Campana 
33532832dd1SG. Campana 	size = sizeof(dfid->abs_path) - (dfid->path - dfid->abs_path);
33604d604b6SAnisse Astier 
33704d604b6SAnisse Astier 	tmp_path = strdup(dfid->path);
33804d604b6SAnisse Astier 	if (!tmp_path)
33904d604b6SAnisse Astier 		goto err_out;
34004d604b6SAnisse Astier 
34104d604b6SAnisse Astier 	ret = snprintf(dfid->path, size, "%s/%s", tmp_path, name);
34204d604b6SAnisse Astier 	free(tmp_path);
34332832dd1SG. Campana 	if (ret >= (int)size) {
34432832dd1SG. Campana 		errno = ENAMETOOLONG;
34532832dd1SG. Campana 		if (size > 0)
34632832dd1SG. Campana 			dfid->path[size] = '\x00';
34732832dd1SG. Campana 		goto err_out;
34832832dd1SG. Campana 	}
34932832dd1SG. Campana 
350d4727f2bSG. Campana 	flags = virtio_p9_openflags(flags);
351d4727f2bSG. Campana 
352c797b6c6SAneesh Kumar K.V 	fd = open(full_path, flags | O_CREAT, mode);
3534bc9734aSAneesh Kumar K.V 	if (fd < 0)
3544bc9734aSAneesh Kumar K.V 		goto err_out;
355c797b6c6SAneesh Kumar K.V 	dfid->fd = fd;
356c797b6c6SAneesh Kumar K.V 
3574bc9734aSAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
3586c8ca053SAneesh Kumar K.V 		goto err_out;
3591c7850f9SSasha Levin 
360c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
361c797b6c6SAneesh Kumar K.V 	if (ret < 0)
362c797b6c6SAneesh Kumar K.V 		goto err_out;
363c797b6c6SAneesh Kumar K.V 
364c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
365bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
366bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
367bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
3685f900f6dSSasha Levin 	free(name);
3696c8ca053SAneesh Kumar K.V 	return;
3706c8ca053SAneesh Kumar K.V err_out:
3715f900f6dSSasha Levin 	free(name);
372c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
373c797b6c6SAneesh Kumar K.V 	return;
374c797b6c6SAneesh Kumar K.V }
375c797b6c6SAneesh Kumar K.V 
376c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev,
377c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
378c797b6c6SAneesh Kumar K.V {
379c797b6c6SAneesh Kumar K.V 	int ret;
380c797b6c6SAneesh Kumar K.V 	char *name;
381c797b6c6SAneesh Kumar K.V 	struct stat st;
382c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
383c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
384c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
385c797b6c6SAneesh Kumar K.V 	u32 dfid_val, mode, gid;
386c797b6c6SAneesh Kumar K.V 
387c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
388c797b6c6SAneesh Kumar K.V 			    &name, &mode, &gid);
38931a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
390c797b6c6SAneesh Kumar K.V 
391d4727f2bSG. Campana 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
39232832dd1SG. Campana 		goto err_out;
3939bb99a82SG. Campana 
394c797b6c6SAneesh Kumar K.V 	ret = mkdir(full_path, mode);
395c797b6c6SAneesh Kumar K.V 	if (ret < 0)
396c797b6c6SAneesh Kumar K.V 		goto err_out;
397c797b6c6SAneesh Kumar K.V 
398c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
399c797b6c6SAneesh Kumar K.V 		goto err_out;
400c797b6c6SAneesh Kumar K.V 
401c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
402c797b6c6SAneesh Kumar K.V 	if (ret < 0)
403c797b6c6SAneesh Kumar K.V 		goto err_out;
404c797b6c6SAneesh Kumar K.V 
405c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
406c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
407c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
408c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
409c797b6c6SAneesh Kumar K.V 	free(name);
410c797b6c6SAneesh Kumar K.V 	return;
411c797b6c6SAneesh Kumar K.V err_out:
412c797b6c6SAneesh Kumar K.V 	free(name);
413c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
414ead43b01SAneesh Kumar K.V 	return;
4151c7850f9SSasha Levin }
4161c7850f9SSasha Levin 
417e277a1b4SG. Campana static int join_path(struct p9_fid *fid, const char *name)
418e277a1b4SG. Campana {
419e277a1b4SG. Campana 	size_t len, size;
420e277a1b4SG. Campana 
421e277a1b4SG. Campana 	size = sizeof(fid->abs_path) - (fid->path - fid->abs_path);
422e277a1b4SG. Campana 	len = strlen(name);
423e277a1b4SG. Campana 	if (len >= size)
424e277a1b4SG. Campana 		return -1;
425e277a1b4SG. Campana 
426e277a1b4SG. Campana 	strncpy(fid->path, name, size);
427e277a1b4SG. Campana 	return 0;
428e277a1b4SG. Campana }
429e277a1b4SG. Campana 
430ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev,
431af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
4321c7850f9SSasha Levin {
433af045e53SAneesh Kumar K.V 	u8 i;
434bfc15268SAneesh Kumar K.V 	u16 nwqid;
435bfc15268SAneesh Kumar K.V 	u16 nwname;
436bfc15268SAneesh Kumar K.V 	struct p9_qid wqid;
437e2341580SSasha Levin 	struct p9_fid *new_fid, *old_fid;
438c797b6c6SAneesh Kumar K.V 	u32 fid_val, newfid_val;
439c797b6c6SAneesh Kumar K.V 
4401c7850f9SSasha Levin 
441bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
44231a6fb8dSSasha Levin 	new_fid	= get_fid(p9dev, newfid_val);
4431c7850f9SSasha Levin 
444bfc15268SAneesh Kumar K.V 	nwqid = 0;
445bfc15268SAneesh Kumar K.V 	if (nwname) {
44631a6fb8dSSasha Levin 		struct p9_fid *fid = get_fid(p9dev, fid_val);
447bfc15268SAneesh Kumar K.V 
448e277a1b4SG. Campana 		if (join_path(new_fid, fid->path) != 0) {
449e277a1b4SG. Campana 			errno = ENAMETOOLONG;
450e277a1b4SG. Campana 			goto err_out;
451e277a1b4SG. Campana 		}
452e277a1b4SG. Campana 
453bfc15268SAneesh Kumar K.V 		/* skip the space for count */
454bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
455bfc15268SAneesh Kumar K.V 		for (i = 0; i < nwname; i++) {
456bfc15268SAneesh Kumar K.V 			struct stat st;
4571c7850f9SSasha Levin 			char tmp[PATH_MAX] = {0};
458e55ed135SPekka Enberg 			char *str;
45932832dd1SG. Campana 			int ret;
460bfc15268SAneesh Kumar K.V 
461bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_readf(pdu, "s", &str);
4621c7850f9SSasha Levin 
4631c7850f9SSasha Levin 			/* Format the new path we're 'walk'ing into */
46432832dd1SG. Campana 			ret = snprintf(tmp, sizeof(tmp), "%s/%s", new_fid->path, str);
46532832dd1SG. Campana 			if (ret >= (int)sizeof(tmp)) {
46632832dd1SG. Campana 				errno = ENAMETOOLONG;
46732832dd1SG. Campana 				goto err_out;
46832832dd1SG. Campana 			}
469e55ed135SPekka Enberg 
470e55ed135SPekka Enberg 			free(str);
471e55ed135SPekka Enberg 
472b0922422SG. Campana 			if (stat_rel(p9dev, tmp, &st) != 0)
4736c8ca053SAneesh Kumar K.V 				goto err_out;
4741c7850f9SSasha Levin 
475c797b6c6SAneesh Kumar K.V 			stat2qid(&st, &wqid);
476e277a1b4SG. Campana 			if (join_path(new_fid, tmp) != 0) {
477e277a1b4SG. Campana 				errno = ENAMETOOLONG;
478e277a1b4SG. Campana 				goto err_out;
479e277a1b4SG. Campana 			}
480c797b6c6SAneesh Kumar K.V 			new_fid->uid = fid->uid;
481bfc15268SAneesh Kumar K.V 			nwqid++;
482bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_writef(pdu, "Q", &wqid);
4831c7850f9SSasha Levin 		}
4841c7850f9SSasha Levin 	} else {
485bfc15268SAneesh Kumar K.V 		/*
486bfc15268SAneesh Kumar K.V 		 * update write_offset so our outlen get correct value
487bfc15268SAneesh Kumar K.V 		 */
488bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
489e2341580SSasha Levin 		old_fid = get_fid(p9dev, fid_val);
490e277a1b4SG. Campana 		if (join_path(new_fid, old_fid->path) != 0) {
491e277a1b4SG. Campana 			errno = ENAMETOOLONG;
492e277a1b4SG. Campana 			goto err_out;
493e277a1b4SG. Campana 		}
494e2341580SSasha Levin 		new_fid->uid    = old_fid->uid;
4951c7850f9SSasha Levin 	}
496bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
4975529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
498bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", nwqid);
499bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
5006c8ca053SAneesh Kumar K.V 	return;
5016c8ca053SAneesh Kumar K.V err_out:
5026c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
503ead43b01SAneesh Kumar K.V 	return;
5041c7850f9SSasha Levin }
5051c7850f9SSasha Levin 
506ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev,
507af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
5081c7850f9SSasha Levin {
509bfc15268SAneesh Kumar K.V 	char *uname;
510bfc15268SAneesh Kumar K.V 	char *aname;
5111c7850f9SSasha Levin 	struct stat st;
512bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
5131c7850f9SSasha Levin 	struct p9_fid *fid;
514c797b6c6SAneesh Kumar K.V 	u32 fid_val, afid, uid;
515bfc15268SAneesh Kumar K.V 
516c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
517c797b6c6SAneesh Kumar K.V 			    &uname, &aname, &uid);
5181c7850f9SSasha Levin 
51939257180SPekka Enberg 	free(uname);
52039257180SPekka Enberg 	free(aname);
52139257180SPekka Enberg 
52230204a77SAneesh Kumar K.V 	if (lstat(p9dev->root_dir, &st) < 0)
5236c8ca053SAneesh Kumar K.V 		goto err_out;
5241c7850f9SSasha Levin 
525c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
5261c7850f9SSasha Levin 
52731a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
528c797b6c6SAneesh Kumar K.V 	fid->uid = uid;
529e277a1b4SG. Campana 	if (join_path(fid, "/") != 0) {
530e277a1b4SG. Campana 		errno = ENAMETOOLONG;
531e277a1b4SG. Campana 		goto err_out;
532e277a1b4SG. Campana 	}
5331c7850f9SSasha Levin 
534bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
535bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
536bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
5376c8ca053SAneesh Kumar K.V 	return;
5386c8ca053SAneesh Kumar K.V err_out:
5396c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
540ead43b01SAneesh Kumar K.V 	return;
5411c7850f9SSasha Levin }
5421c7850f9SSasha Levin 
543c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev,
544c797b6c6SAneesh Kumar K.V 				struct stat *st, struct p9_stat_dotl *statl)
5455f900f6dSSasha Levin {
546c797b6c6SAneesh Kumar K.V 	memset(statl, 0, sizeof(*statl));
547c797b6c6SAneesh Kumar K.V 	statl->st_mode		= st->st_mode;
548c797b6c6SAneesh Kumar K.V 	statl->st_nlink		= st->st_nlink;
549506fd90bSSasha Levin 	statl->st_uid		= KUIDT_INIT(st->st_uid);
550506fd90bSSasha Levin 	statl->st_gid		= KGIDT_INIT(st->st_gid);
551c797b6c6SAneesh Kumar K.V 	statl->st_rdev		= st->st_rdev;
552c797b6c6SAneesh Kumar K.V 	statl->st_size		= st->st_size;
553c797b6c6SAneesh Kumar K.V 	statl->st_blksize	= st->st_blksize;
554c797b6c6SAneesh Kumar K.V 	statl->st_blocks	= st->st_blocks;
555c797b6c6SAneesh Kumar K.V 	statl->st_atime_sec	= st->st_atime;
556c797b6c6SAneesh Kumar K.V 	statl->st_atime_nsec	= st->st_atim.tv_nsec;
557c797b6c6SAneesh Kumar K.V 	statl->st_mtime_sec	= st->st_mtime;
558c797b6c6SAneesh Kumar K.V 	statl->st_mtime_nsec	= st->st_mtim.tv_nsec;
559c797b6c6SAneesh Kumar K.V 	statl->st_ctime_sec	= st->st_ctime;
560c797b6c6SAneesh Kumar K.V 	statl->st_ctime_nsec	= st->st_ctim.tv_nsec;
561c797b6c6SAneesh Kumar K.V 	/* Currently we only support BASIC fields in stat */
562c797b6c6SAneesh Kumar K.V 	statl->st_result_mask	= P9_STATS_BASIC;
563c797b6c6SAneesh Kumar K.V 	stat2qid(st, &statl->qid);
5641c7850f9SSasha Levin }
5651c7850f9SSasha Levin 
566ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev,
567af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
5681c7850f9SSasha Levin {
569bfc15268SAneesh Kumar K.V 	u64 offset;
570bfc15268SAneesh Kumar K.V 	u32 fid_val;
571c797b6c6SAneesh Kumar K.V 	u16 iov_cnt;
572c797b6c6SAneesh Kumar K.V 	void *iov_base;
573c797b6c6SAneesh Kumar K.V 	size_t iov_len;
574bfc15268SAneesh Kumar K.V 	u32 count, rcount;
575bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
576c797b6c6SAneesh Kumar K.V 
5771c7850f9SSasha Levin 
578bfc15268SAneesh Kumar K.V 	rcount = 0;
579bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
58031a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
58150c479e0SAneesh Kumar K.V 
58250c479e0SAneesh Kumar K.V 	iov_base = pdu->in_iov[0].iov_base;
58350c479e0SAneesh Kumar K.V 	iov_len  = pdu->in_iov[0].iov_len;
58450c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->in_iov_cnt;
5855529bcd7SAsias He 	pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
5865529bcd7SAsias He 	pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
5876b163a87SAneesh Kumar K.V 	pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
588bfc15268SAneesh Kumar K.V 						   count,
5896b163a87SAneesh Kumar K.V 						   pdu->in_iov_cnt);
590bfc15268SAneesh Kumar K.V 	rcount = preadv(fid->fd, pdu->in_iov,
591bfc15268SAneesh Kumar K.V 			pdu->in_iov_cnt, offset);
592bfc15268SAneesh Kumar K.V 	if (rcount > count)
593bfc15268SAneesh Kumar K.V 		rcount = count;
594bfc15268SAneesh Kumar K.V 	/*
595bfc15268SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
596bfc15268SAneesh Kumar K.V 	 * pdu_writef works correctly.
597bfc15268SAneesh Kumar K.V 	 */
59850c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_base = iov_base;
59950c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_len  = iov_len;
60050c479e0SAneesh Kumar K.V 	pdu->in_iov_cnt         = iov_cnt;
601c797b6c6SAneesh Kumar K.V 
6025529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
603bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
604bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
605bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
606ead43b01SAneesh Kumar K.V 	return;
6071c7850f9SSasha Levin }
6081c7850f9SSasha Levin 
609c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent)
610c797b6c6SAneesh Kumar K.V {
611c797b6c6SAneesh Kumar K.V 	/*
612c797b6c6SAneesh Kumar K.V 	 * Size of each dirent:
613c797b6c6SAneesh Kumar K.V 	 * qid(13) + offset(8) + type(1) + name_len(2) + name
614c797b6c6SAneesh Kumar K.V 	 */
615c797b6c6SAneesh Kumar K.V 	return 24 + strlen(dent->d_name);
616c797b6c6SAneesh Kumar K.V }
617c797b6c6SAneesh Kumar K.V 
618c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev,
619c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
620c797b6c6SAneesh Kumar K.V {
621c797b6c6SAneesh Kumar K.V 	u32 fid_val;
622c797b6c6SAneesh Kumar K.V 	u32 count, rcount;
623c797b6c6SAneesh Kumar K.V 	struct stat st;
624c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
625c797b6c6SAneesh Kumar K.V 	struct dirent *dent;
626c797b6c6SAneesh Kumar K.V 	u64 offset, old_offset;
627c797b6c6SAneesh Kumar K.V 
628c797b6c6SAneesh Kumar K.V 	rcount = 0;
629c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
63031a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
631c797b6c6SAneesh Kumar K.V 
63232585666SSasha Levin 	if (!is_dir(fid)) {
63369bb4278SSasha Levin 		errno = EINVAL;
634c797b6c6SAneesh Kumar K.V 		goto err_out;
635c797b6c6SAneesh Kumar K.V 	}
636c797b6c6SAneesh Kumar K.V 
637c797b6c6SAneesh Kumar K.V 	/* Move the offset specified */
638c797b6c6SAneesh Kumar K.V 	seekdir(fid->dir, offset);
639c797b6c6SAneesh Kumar K.V 
640c797b6c6SAneesh Kumar K.V 	old_offset = offset;
641c797b6c6SAneesh Kumar K.V 	/* If reading a dir, fill the buffer with p9_stat entries */
642c797b6c6SAneesh Kumar K.V 	dent = readdir(fid->dir);
643c797b6c6SAneesh Kumar K.V 
644c797b6c6SAneesh Kumar K.V 	/* Skip the space for writing count */
645c797b6c6SAneesh Kumar K.V 	pdu->write_offset += sizeof(u32);
646c797b6c6SAneesh Kumar K.V 	while (dent) {
647c797b6c6SAneesh Kumar K.V 		u32 read;
648c797b6c6SAneesh Kumar K.V 		struct p9_qid qid;
649c797b6c6SAneesh Kumar K.V 
650c797b6c6SAneesh Kumar K.V 		if ((rcount + virtio_p9_dentry_size(dent)) > count) {
651c797b6c6SAneesh Kumar K.V 			/* seek to the previous offset and return */
652c797b6c6SAneesh Kumar K.V 			seekdir(fid->dir, old_offset);
653c797b6c6SAneesh Kumar K.V 			break;
654c797b6c6SAneesh Kumar K.V 		}
655c797b6c6SAneesh Kumar K.V 		old_offset = dent->d_off;
656b0922422SG. Campana 		if (stat_rel(p9dev, dent->d_name, &st) != 0)
657b0922422SG. Campana 			memset(&st, -1, sizeof(st));
658c797b6c6SAneesh Kumar K.V 		stat2qid(&st, &qid);
659c797b6c6SAneesh Kumar K.V 		read = pdu->write_offset;
660c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
661c797b6c6SAneesh Kumar K.V 				     dent->d_type, dent->d_name);
662c797b6c6SAneesh Kumar K.V 		rcount += pdu->write_offset - read;
663c797b6c6SAneesh Kumar K.V 		dent = readdir(fid->dir);
664c797b6c6SAneesh Kumar K.V 	}
665c797b6c6SAneesh Kumar K.V 
6665529bcd7SAsias He 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
667c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
668c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
669c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
670c797b6c6SAneesh Kumar K.V 	return;
671c797b6c6SAneesh Kumar K.V err_out:
672c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
673c797b6c6SAneesh Kumar K.V 	return;
674c797b6c6SAneesh Kumar K.V }
675c797b6c6SAneesh Kumar K.V 
676c797b6c6SAneesh Kumar K.V 
677c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev,
678af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
6791c7850f9SSasha Levin {
680bfc15268SAneesh Kumar K.V 	u32 fid_val;
681af045e53SAneesh Kumar K.V 	struct stat st;
682c797b6c6SAneesh Kumar K.V 	u64 request_mask;
683bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
684c797b6c6SAneesh Kumar K.V 	struct p9_stat_dotl statl;
6851c7850f9SSasha Levin 
686c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
68731a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
68830204a77SAneesh Kumar K.V 	if (lstat(fid->abs_path, &st) < 0)
6896c8ca053SAneesh Kumar K.V 		goto err_out;
6901c7850f9SSasha Levin 
691c797b6c6SAneesh Kumar K.V 	virtio_p9_fill_stat(p9dev, &st, &statl);
692c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "A", &statl);
693bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
694bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
695ead43b01SAneesh Kumar K.V 	return;
6966c8ca053SAneesh Kumar K.V err_out:
6976c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
6986c8ca053SAneesh Kumar K.V 	return;
6991c7850f9SSasha Levin }
7001c7850f9SSasha Levin 
701c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */
702c797b6c6SAneesh Kumar K.V /*
703c797b6c6SAneesh Kumar K.V  * Attribute flags.  These should be or-ed together to figure out what
704c797b6c6SAneesh Kumar K.V  * has been changed!
705c797b6c6SAneesh Kumar K.V  */
706c797b6c6SAneesh Kumar K.V #define ATTR_MODE	(1 << 0)
707c797b6c6SAneesh Kumar K.V #define ATTR_UID	(1 << 1)
708c797b6c6SAneesh Kumar K.V #define ATTR_GID	(1 << 2)
709c797b6c6SAneesh Kumar K.V #define ATTR_SIZE	(1 << 3)
710c797b6c6SAneesh Kumar K.V #define ATTR_ATIME	(1 << 4)
711c797b6c6SAneesh Kumar K.V #define ATTR_MTIME	(1 << 5)
712c797b6c6SAneesh Kumar K.V #define ATTR_CTIME	(1 << 6)
713c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET	(1 << 7)
714c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET	(1 << 8)
715c797b6c6SAneesh Kumar K.V #define ATTR_FORCE	(1 << 9) /* Not a change, but a change it */
716c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG	(1 << 10)
717c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID	(1 << 11)
718c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID	(1 << 12)
719c797b6c6SAneesh Kumar K.V #define ATTR_FILE	(1 << 13)
720c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV	(1 << 14)
721c797b6c6SAneesh Kumar K.V #define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
722c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET	(1 << 16)
723c797b6c6SAneesh Kumar K.V 
724c797b6c6SAneesh Kumar K.V #define ATTR_MASK    127
725c797b6c6SAneesh Kumar K.V 
726c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev,
727af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
7281c7850f9SSasha Levin {
729c797b6c6SAneesh Kumar K.V 	int ret = 0;
730bfc15268SAneesh Kumar K.V 	u32 fid_val;
731bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
732c797b6c6SAneesh Kumar K.V 	struct p9_iattr_dotl p9attr;
7331c7850f9SSasha Levin 
734c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
73531a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
7361c7850f9SSasha Levin 
737c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & ATTR_MODE) {
738c797b6c6SAneesh Kumar K.V 		ret = chmod(fid->abs_path, p9attr.mode);
739c797b6c6SAneesh Kumar K.V 		if (ret < 0)
740c797b6c6SAneesh Kumar K.V 			goto err_out;
741c797b6c6SAneesh Kumar K.V 	}
742c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
743c797b6c6SAneesh Kumar K.V 		struct timespec times[2];
744c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_ATIME) {
745c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_ATIME_SET) {
746c797b6c6SAneesh Kumar K.V 				times[0].tv_sec = p9attr.atime_sec;
747c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = p9attr.atime_nsec;
748c797b6c6SAneesh Kumar K.V 			} else {
749c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = UTIME_NOW;
750c797b6c6SAneesh Kumar K.V 			}
751c797b6c6SAneesh Kumar K.V 		} else {
752c797b6c6SAneesh Kumar K.V 			times[0].tv_nsec = UTIME_OMIT;
753c797b6c6SAneesh Kumar K.V 		}
754c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_MTIME) {
755c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_MTIME_SET) {
756c797b6c6SAneesh Kumar K.V 				times[1].tv_sec = p9attr.mtime_sec;
757c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = p9attr.mtime_nsec;
758c797b6c6SAneesh Kumar K.V 			} else {
759c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = UTIME_NOW;
760c797b6c6SAneesh Kumar K.V 			}
761c797b6c6SAneesh Kumar K.V 		} else
762c797b6c6SAneesh Kumar K.V 			times[1].tv_nsec = UTIME_OMIT;
763c797b6c6SAneesh Kumar K.V 
764c797b6c6SAneesh Kumar K.V 		ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
765c797b6c6SAneesh Kumar K.V 		if (ret < 0)
766c797b6c6SAneesh Kumar K.V 			goto err_out;
767c797b6c6SAneesh Kumar K.V 	}
768c797b6c6SAneesh Kumar K.V 	/*
769c797b6c6SAneesh Kumar K.V 	 * If the only valid entry in iattr is ctime we can call
770c797b6c6SAneesh Kumar K.V 	 * chown(-1,-1) to update the ctime of the file
771c797b6c6SAneesh Kumar K.V 	 */
772c797b6c6SAneesh Kumar K.V 	if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
773c797b6c6SAneesh Kumar K.V 	    ((p9attr.valid & ATTR_CTIME)
774c797b6c6SAneesh Kumar K.V 	     && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
775c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_UID))
776506fd90bSSasha Levin 			p9attr.uid = KUIDT_INIT(-1);
777c797b6c6SAneesh Kumar K.V 
778c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_GID))
779506fd90bSSasha Levin 			p9attr.gid = KGIDT_INIT(-1);
780c797b6c6SAneesh Kumar K.V 
781506fd90bSSasha Levin 		ret = lchown(fid->abs_path, __kuid_val(p9attr.uid),
782506fd90bSSasha Levin 				__kgid_val(p9attr.gid));
783c797b6c6SAneesh Kumar K.V 		if (ret < 0)
784c797b6c6SAneesh Kumar K.V 			goto err_out;
785c797b6c6SAneesh Kumar K.V 	}
786c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_SIZE)) {
787c797b6c6SAneesh Kumar K.V 		ret = truncate(fid->abs_path, p9attr.size);
788c797b6c6SAneesh Kumar K.V 		if (ret < 0)
789c797b6c6SAneesh Kumar K.V 			goto err_out;
790c797b6c6SAneesh Kumar K.V 	}
7915529bcd7SAsias He 	*outlen = VIRTIO_9P_HDR_LEN;
792bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
793ead43b01SAneesh Kumar K.V 	return;
7944bc9734aSAneesh Kumar K.V err_out:
7954bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
7964bc9734aSAneesh Kumar K.V 	return;
7971c7850f9SSasha Levin }
7981c7850f9SSasha Levin 
799ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev,
800af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
8011c7850f9SSasha Levin {
8024bc9734aSAneesh Kumar K.V 
803bfc15268SAneesh Kumar K.V 	u64 offset;
804bfc15268SAneesh Kumar K.V 	u32 fid_val;
8054bc9734aSAneesh Kumar K.V 	u32 count;
8064bc9734aSAneesh Kumar K.V 	ssize_t res;
80750c479e0SAneesh Kumar K.V 	u16 iov_cnt;
80850c479e0SAneesh Kumar K.V 	void *iov_base;
80950c479e0SAneesh Kumar K.V 	size_t iov_len;
810bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
811b064b05aSAneesh Kumar K.V 	/* u32 fid + u64 offset + u32 count */
812b064b05aSAneesh Kumar K.V 	int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
8131c7850f9SSasha Levin 
814bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
81531a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
816af045e53SAneesh Kumar K.V 
81750c479e0SAneesh Kumar K.V 	iov_base = pdu->out_iov[0].iov_base;
81850c479e0SAneesh Kumar K.V 	iov_len  = pdu->out_iov[0].iov_len;
81950c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->out_iov_cnt;
82050c479e0SAneesh Kumar K.V 
821bfc15268SAneesh Kumar K.V 	/* Adjust the iovec to skip the header and meta data */
822b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
823b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
824bfc15268SAneesh Kumar K.V 	pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
8256b163a87SAneesh Kumar K.V 						    pdu->out_iov_cnt);
8264bc9734aSAneesh Kumar K.V 	res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
82750c479e0SAneesh Kumar K.V 	/*
82850c479e0SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
82950c479e0SAneesh Kumar K.V 	 * pdu_readf works correctly.
83050c479e0SAneesh Kumar K.V 	 */
83150c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_base = iov_base;
83250c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_len  = iov_len;
83350c479e0SAneesh Kumar K.V 	pdu->out_iov_cnt         = iov_cnt;
834c797b6c6SAneesh Kumar K.V 
8354bc9734aSAneesh Kumar K.V 	if (res < 0)
8364bc9734aSAneesh Kumar K.V 		goto err_out;
8374bc9734aSAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", res);
838bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
839bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
840ead43b01SAneesh Kumar K.V 	return;
8414bc9734aSAneesh Kumar K.V err_out:
8424bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
8434bc9734aSAneesh Kumar K.V 	return;
8441c7850f9SSasha Levin }
8451c7850f9SSasha Levin 
8466fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev,
8476fc5cd9bSSasha Levin 			     struct p9_pdu *pdu, u32 *outlen)
8486fc5cd9bSSasha Levin {
8496fc5cd9bSSasha Levin 	int ret;
8506fc5cd9bSSasha Levin 	u32 fid_val;
8516fc5cd9bSSasha Levin 	struct p9_fid *fid;
8526fc5cd9bSSasha Levin 
8536fc5cd9bSSasha Levin 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
85431a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
8556fc5cd9bSSasha Levin 
8569b604a9cSSasha Levin 	ret = remove(fid->abs_path);
8576fc5cd9bSSasha Levin 	if (ret < 0)
8586fc5cd9bSSasha Levin 		goto err_out;
8596fc5cd9bSSasha Levin 	*outlen = pdu->write_offset;
8606fc5cd9bSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
8616fc5cd9bSSasha Levin 	return;
8626fc5cd9bSSasha Levin 
8636fc5cd9bSSasha Levin err_out:
8646fc5cd9bSSasha Levin 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
8656fc5cd9bSSasha Levin 	return;
8666fc5cd9bSSasha Levin }
8676fc5cd9bSSasha Levin 
868f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev,
869f161f28bSSasha Levin 			     struct p9_pdu *pdu, u32 *outlen)
870f161f28bSSasha Levin {
871f161f28bSSasha Levin 	int ret;
872f161f28bSSasha Levin 	u32 fid_val, new_fid_val;
873f161f28bSSasha Levin 	struct p9_fid *fid, *new_fid;
874f161f28bSSasha Levin 	char full_path[PATH_MAX], *new_name;
875f161f28bSSasha Levin 
876f161f28bSSasha Levin 	virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
87731a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
87831a6fb8dSSasha Levin 	new_fid = get_fid(p9dev, new_fid_val);
879f161f28bSSasha Levin 
880d4727f2bSG. Campana 	if (get_full_path(full_path, sizeof(full_path), new_fid, new_name) != 0)
88132832dd1SG. Campana 		goto err_out;
8829bb99a82SG. Campana 
883f161f28bSSasha Levin 	ret = rename(fid->abs_path, full_path);
884f161f28bSSasha Levin 	if (ret < 0)
885f161f28bSSasha Levin 		goto err_out;
886f161f28bSSasha Levin 	*outlen = pdu->write_offset;
887f161f28bSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
888f161f28bSSasha Levin 	return;
889f161f28bSSasha Levin 
890f161f28bSSasha Levin err_out:
891f161f28bSSasha Levin 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
892f161f28bSSasha Levin 	return;
893f161f28bSSasha Levin }
894f161f28bSSasha Levin 
895c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev,
896c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
897c797b6c6SAneesh Kumar K.V {
898c797b6c6SAneesh Kumar K.V 	int ret;
899c797b6c6SAneesh Kumar K.V 	u32 fid_val;
900c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
901c797b6c6SAneesh Kumar K.V 	char target_path[PATH_MAX];
902c797b6c6SAneesh Kumar K.V 
903c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
90431a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
905c797b6c6SAneesh Kumar K.V 
906c797b6c6SAneesh Kumar K.V 	memset(target_path, 0, PATH_MAX);
907c797b6c6SAneesh Kumar K.V 	ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
908c797b6c6SAneesh Kumar K.V 	if (ret < 0)
909c797b6c6SAneesh Kumar K.V 		goto err_out;
910c797b6c6SAneesh Kumar K.V 
911c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "s", target_path);
912c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
913c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
914c797b6c6SAneesh Kumar K.V 	return;
915c797b6c6SAneesh Kumar K.V err_out:
916c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
917c797b6c6SAneesh Kumar K.V 	return;
918c797b6c6SAneesh Kumar K.V }
919c797b6c6SAneesh Kumar K.V 
920c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev,
921c797b6c6SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
922c797b6c6SAneesh Kumar K.V {
923c797b6c6SAneesh Kumar K.V 	int ret;
924c797b6c6SAneesh Kumar K.V 	u64 fsid;
925c797b6c6SAneesh Kumar K.V 	u32 fid_val;
926c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
927c797b6c6SAneesh Kumar K.V 	struct statfs stat_buf;
928c797b6c6SAneesh Kumar K.V 
929c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
93031a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
931c797b6c6SAneesh Kumar K.V 
932c797b6c6SAneesh Kumar K.V 	ret = statfs(fid->abs_path, &stat_buf);
933c797b6c6SAneesh Kumar K.V 	if (ret < 0)
934c797b6c6SAneesh Kumar K.V 		goto err_out;
935c797b6c6SAneesh Kumar K.V 	/* FIXME!! f_blocks needs update based on client msize */
936c797b6c6SAneesh Kumar K.V 	fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
937c797b6c6SAneesh Kumar K.V 		(unsigned long long)stat_buf.f_fsid.__val[1] << 32;
938c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
939c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bsize, stat_buf.f_blocks,
940c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bfree, stat_buf.f_bavail,
941c797b6c6SAneesh Kumar K.V 			     stat_buf.f_files, stat_buf.f_ffree,
942c797b6c6SAneesh Kumar K.V 			     fsid, stat_buf.f_namelen);
943c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
944c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
945c797b6c6SAneesh Kumar K.V 	return;
946c797b6c6SAneesh Kumar K.V err_out:
947c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
948c797b6c6SAneesh Kumar K.V 	return;
949c797b6c6SAneesh Kumar K.V }
950c797b6c6SAneesh Kumar K.V 
951c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev,
952c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
953c797b6c6SAneesh Kumar K.V {
954c797b6c6SAneesh Kumar K.V 	int ret;
955c797b6c6SAneesh Kumar K.V 	char *name;
956c797b6c6SAneesh Kumar K.V 	struct stat st;
957c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
958c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
959c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
960c797b6c6SAneesh Kumar K.V 	u32 fid_val, mode, major, minor, gid;
961c797b6c6SAneesh Kumar K.V 
962c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
963c797b6c6SAneesh Kumar K.V 			    &major, &minor, &gid);
964c797b6c6SAneesh Kumar K.V 
96531a6fb8dSSasha Levin 	dfid = get_fid(p9dev, fid_val);
96632832dd1SG. Campana 
967d4727f2bSG. Campana 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
9689bb99a82SG. Campana 		goto err_out;
9699bb99a82SG. Campana 
970c797b6c6SAneesh Kumar K.V 	ret = mknod(full_path, mode, makedev(major, minor));
971c797b6c6SAneesh Kumar K.V 	if (ret < 0)
972c797b6c6SAneesh Kumar K.V 		goto err_out;
973c797b6c6SAneesh Kumar K.V 
974c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
975c797b6c6SAneesh Kumar K.V 		goto err_out;
976c797b6c6SAneesh Kumar K.V 
977c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
978c797b6c6SAneesh Kumar K.V 	if (ret < 0)
979c797b6c6SAneesh Kumar K.V 		goto err_out;
980c797b6c6SAneesh Kumar K.V 
981c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
982c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
983c797b6c6SAneesh Kumar K.V 	free(name);
984c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
985c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
986c797b6c6SAneesh Kumar K.V 	return;
987c797b6c6SAneesh Kumar K.V err_out:
988c797b6c6SAneesh Kumar K.V 	free(name);
989c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
990c797b6c6SAneesh Kumar K.V 	return;
991c797b6c6SAneesh Kumar K.V }
992c797b6c6SAneesh Kumar K.V 
993c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev,
994c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
995c797b6c6SAneesh Kumar K.V {
996644140efSRussell King 	int ret, fd;
997c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
998c797b6c6SAneesh Kumar K.V 	u32 fid_val, datasync;
999c797b6c6SAneesh Kumar K.V 
1000c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
100131a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
1002c797b6c6SAneesh Kumar K.V 
1003644140efSRussell King 	if (fid->dir)
1004644140efSRussell King 		fd = dirfd(fid->dir);
1005c797b6c6SAneesh Kumar K.V 	else
1006644140efSRussell King 		fd = fid->fd;
1007644140efSRussell King 
1008644140efSRussell King 	if (datasync)
1009644140efSRussell King 		ret = fdatasync(fd);
1010644140efSRussell King 	else
1011644140efSRussell King 		ret = fsync(fd);
1012c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1013c797b6c6SAneesh Kumar K.V 		goto err_out;
1014c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1015c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1016c797b6c6SAneesh Kumar K.V 	return;
1017c797b6c6SAneesh Kumar K.V err_out:
1018c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1019c797b6c6SAneesh Kumar K.V 	return;
1020c797b6c6SAneesh Kumar K.V }
1021c797b6c6SAneesh Kumar K.V 
1022c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev,
1023c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
1024c797b6c6SAneesh Kumar K.V {
1025c797b6c6SAneesh Kumar K.V 	int ret;
1026c797b6c6SAneesh Kumar K.V 	struct stat st;
1027c797b6c6SAneesh Kumar K.V 	u32 fid_val, gid;
1028c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
1029c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
1030c797b6c6SAneesh Kumar K.V 	char new_name[PATH_MAX];
1031c797b6c6SAneesh Kumar K.V 	char *old_path, *name;
1032c797b6c6SAneesh Kumar K.V 
1033c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
1034c797b6c6SAneesh Kumar K.V 
103531a6fb8dSSasha Levin 	dfid = get_fid(p9dev, fid_val);
103632832dd1SG. Campana 
1037d4727f2bSG. Campana 	if (get_full_path(new_name, sizeof(new_name), dfid, name) != 0)
10389bb99a82SG. Campana 		goto err_out;
10399bb99a82SG. Campana 
1040c797b6c6SAneesh Kumar K.V 	ret = symlink(old_path, new_name);
1041c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1042c797b6c6SAneesh Kumar K.V 		goto err_out;
1043c797b6c6SAneesh Kumar K.V 
1044c797b6c6SAneesh Kumar K.V 	if (lstat(new_name, &st) < 0)
1045c797b6c6SAneesh Kumar K.V 		goto err_out;
1046c797b6c6SAneesh Kumar K.V 
1047c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
1048c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
1049c797b6c6SAneesh Kumar K.V 	free(name);
1050c797b6c6SAneesh Kumar K.V 	free(old_path);
1051c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1052c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1053c797b6c6SAneesh Kumar K.V 	return;
1054c797b6c6SAneesh Kumar K.V err_out:
1055c797b6c6SAneesh Kumar K.V 	free(name);
1056c797b6c6SAneesh Kumar K.V 	free(old_path);
1057c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1058c797b6c6SAneesh Kumar K.V 	return;
1059c797b6c6SAneesh Kumar K.V }
1060c797b6c6SAneesh Kumar K.V 
1061c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev,
1062c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
1063c797b6c6SAneesh Kumar K.V {
1064c797b6c6SAneesh Kumar K.V 	int ret;
1065c797b6c6SAneesh Kumar K.V 	char *name;
1066c797b6c6SAneesh Kumar K.V 	u32 fid_val, dfid_val;
1067c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid, *fid;
1068c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
1069c797b6c6SAneesh Kumar K.V 
1070c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
1071c797b6c6SAneesh Kumar K.V 
107231a6fb8dSSasha Levin 	dfid = get_fid(p9dev, dfid_val);
107331a6fb8dSSasha Levin 	fid =  get_fid(p9dev, fid_val);
107432832dd1SG. Campana 
1075d4727f2bSG. Campana 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
10769bb99a82SG. Campana 		goto err_out;
10779bb99a82SG. Campana 
1078c797b6c6SAneesh Kumar K.V 	ret = link(fid->abs_path, full_path);
1079c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1080c797b6c6SAneesh Kumar K.V 		goto err_out;
1081c797b6c6SAneesh Kumar K.V 	free(name);
1082c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1083c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1084c797b6c6SAneesh Kumar K.V 	return;
1085c797b6c6SAneesh Kumar K.V err_out:
1086c797b6c6SAneesh Kumar K.V 	free(name);
1087c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1088c797b6c6SAneesh Kumar K.V 	return;
1089c797b6c6SAneesh Kumar K.V 
1090c797b6c6SAneesh Kumar K.V }
1091c797b6c6SAneesh Kumar K.V 
1092c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev,
1093c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
1094c797b6c6SAneesh Kumar K.V {
1095c797b6c6SAneesh Kumar K.V 	u8 ret;
1096c797b6c6SAneesh Kumar K.V 	u32 fid_val;
1097c797b6c6SAneesh Kumar K.V 	struct p9_flock flock;
1098c797b6c6SAneesh Kumar K.V 
1099c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
1100c797b6c6SAneesh Kumar K.V 			    &flock.flags, &flock.start, &flock.length,
1101c797b6c6SAneesh Kumar K.V 			    &flock.proc_id, &flock.client_id);
1102c797b6c6SAneesh Kumar K.V 
1103c797b6c6SAneesh Kumar K.V 	/* Just return success */
1104c797b6c6SAneesh Kumar K.V 	ret = P9_LOCK_SUCCESS;
1105c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", ret);
1106c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1107c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1108c797b6c6SAneesh Kumar K.V 	free(flock.client_id);
1109c797b6c6SAneesh Kumar K.V 	return;
1110c797b6c6SAneesh Kumar K.V }
1111c797b6c6SAneesh Kumar K.V 
1112c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev,
1113c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
1114c797b6c6SAneesh Kumar K.V {
1115c797b6c6SAneesh Kumar K.V 	u32 fid_val;
1116c797b6c6SAneesh Kumar K.V 	struct p9_getlock glock;
1117c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
1118c797b6c6SAneesh Kumar K.V 			    &glock.start, &glock.length, &glock.proc_id,
1119c797b6c6SAneesh Kumar K.V 			    &glock.client_id);
1120c797b6c6SAneesh Kumar K.V 
1121c797b6c6SAneesh Kumar K.V 	/* Just return success */
1122c797b6c6SAneesh Kumar K.V 	glock.type = F_UNLCK;
1123c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
1124c797b6c6SAneesh Kumar K.V 			     glock.start, glock.length, glock.proc_id,
1125c797b6c6SAneesh Kumar K.V 			     glock.client_id);
1126c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1127c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1128c797b6c6SAneesh Kumar K.V 	free(glock.client_id);
1129c797b6c6SAneesh Kumar K.V 	return;
1130c797b6c6SAneesh Kumar K.V }
1131c797b6c6SAneesh Kumar K.V 
1132c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor)
1133c797b6c6SAneesh Kumar K.V {
1134c797b6c6SAneesh Kumar K.V 	int size = strlen(ancestor);
1135c797b6c6SAneesh Kumar K.V 	if (!strncmp(path, ancestor, size)) {
1136c797b6c6SAneesh Kumar K.V 		/*
1137c797b6c6SAneesh Kumar K.V 		 * Now check whether ancestor is a full name or
1138c797b6c6SAneesh Kumar K.V 		 * or directory component and not just part
1139c797b6c6SAneesh Kumar K.V 		 * of a name.
1140c797b6c6SAneesh Kumar K.V 		 */
1141c797b6c6SAneesh Kumar K.V 		if (path[size] == '\0' || path[size] == '/')
1142c797b6c6SAneesh Kumar K.V 			return 1;
1143c797b6c6SAneesh Kumar K.V 	}
1144c797b6c6SAneesh Kumar K.V 	return 0;
1145c797b6c6SAneesh Kumar K.V }
1146c797b6c6SAneesh Kumar K.V 
1147e277a1b4SG. Campana static int virtio_p9_fix_path(struct p9_fid *fid, char *old_name, char *new_name)
1148c797b6c6SAneesh Kumar K.V {
1149e277a1b4SG. Campana 	int ret;
1150e277a1b4SG. Campana 	char *p, tmp_name[PATH_MAX];
1151c797b6c6SAneesh Kumar K.V 	size_t rp_sz = strlen(old_name);
1152c797b6c6SAneesh Kumar K.V 
1153e277a1b4SG. Campana 	if (rp_sz == strlen(fid->path)) {
1154c797b6c6SAneesh Kumar K.V 		/* replace the full name */
1155e277a1b4SG. Campana 		p = new_name;
1156e277a1b4SG. Campana 	} else {
1157c797b6c6SAneesh Kumar K.V 		/* save the trailing path details */
1158e277a1b4SG. Campana 		ret = snprintf(tmp_name, sizeof(tmp_name), "%s%s", new_name, fid->path + rp_sz);
1159e277a1b4SG. Campana 		if (ret >= (int)sizeof(tmp_name))
1160e277a1b4SG. Campana 			return -1;
1161e277a1b4SG. Campana 		p = tmp_name;
1162e277a1b4SG. Campana 	}
1163e277a1b4SG. Campana 
1164e277a1b4SG. Campana 	return join_path(fid, p);
1165c797b6c6SAneesh Kumar K.V }
1166c797b6c6SAneesh Kumar K.V 
1167e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name)
1168e2341580SSasha Levin {
1169e2341580SSasha Levin 	struct rb_node *node = rb_first(&p9dev->fids);
1170e2341580SSasha Levin 
1171e2341580SSasha Levin 	while (node) {
1172e2341580SSasha Levin 		struct p9_fid *fid = rb_entry(node, struct p9_fid, node);
1173e2341580SSasha Levin 
1174e2341580SSasha Levin 		if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) {
1175e277a1b4SG. Campana 				virtio_p9_fix_path(fid, old_name, new_name);
1176e2341580SSasha Levin 		}
1177e2341580SSasha Levin 		node = rb_next(node);
1178e2341580SSasha Levin 	}
1179e2341580SSasha Levin }
1180e2341580SSasha Levin 
1181c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev,
1182c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
1183c797b6c6SAneesh Kumar K.V {
1184e2341580SSasha Levin 	int ret;
1185c797b6c6SAneesh Kumar K.V 	char *old_name, *new_name;
1186c797b6c6SAneesh Kumar K.V 	u32 old_dfid_val, new_dfid_val;
1187c797b6c6SAneesh Kumar K.V 	struct p9_fid *old_dfid, *new_dfid;
1188c797b6c6SAneesh Kumar K.V 	char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
1189c797b6c6SAneesh Kumar K.V 
1190c797b6c6SAneesh Kumar K.V 
1191c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
1192c797b6c6SAneesh Kumar K.V 			    &new_dfid_val, &new_name);
1193c797b6c6SAneesh Kumar K.V 
119431a6fb8dSSasha Levin 	old_dfid = get_fid(p9dev, old_dfid_val);
119531a6fb8dSSasha Levin 	new_dfid = get_fid(p9dev, new_dfid_val);
1196c797b6c6SAneesh Kumar K.V 
1197d4727f2bSG. Campana 	if (get_full_path(old_full_path, sizeof(old_full_path), old_dfid, old_name) != 0)
119832832dd1SG. Campana 		goto err_out;
119932832dd1SG. Campana 
1200d4727f2bSG. Campana 	if (get_full_path(new_full_path, sizeof(new_full_path), new_dfid, new_name) != 0)
120132832dd1SG. Campana 		goto err_out;
12029bb99a82SG. Campana 
1203c797b6c6SAneesh Kumar K.V 	ret = rename(old_full_path, new_full_path);
1204c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1205c797b6c6SAneesh Kumar K.V 		goto err_out;
1206c797b6c6SAneesh Kumar K.V 	/*
1207c797b6c6SAneesh Kumar K.V 	 * Now fix path in other fids, if the renamed path is part of
1208c797b6c6SAneesh Kumar K.V 	 * that.
1209c797b6c6SAneesh Kumar K.V 	 */
1210e2341580SSasha Levin 	rename_fids(p9dev, old_name, new_name);
1211c797b6c6SAneesh Kumar K.V 	free(old_name);
1212c797b6c6SAneesh Kumar K.V 	free(new_name);
1213c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1214c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1215c797b6c6SAneesh Kumar K.V 	return;
1216c797b6c6SAneesh Kumar K.V err_out:
1217c797b6c6SAneesh Kumar K.V 	free(old_name);
1218c797b6c6SAneesh Kumar K.V 	free(new_name);
1219c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1220c797b6c6SAneesh Kumar K.V 	return;
1221c797b6c6SAneesh Kumar K.V }
1222c797b6c6SAneesh Kumar K.V 
1223c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev,
1224c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
1225c797b6c6SAneesh Kumar K.V {
1226c797b6c6SAneesh Kumar K.V 	int ret;
1227c797b6c6SAneesh Kumar K.V 	char *name;
1228c797b6c6SAneesh Kumar K.V 	u32 fid_val, flags;
1229c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
1230c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
1231c797b6c6SAneesh Kumar K.V 
1232c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
123331a6fb8dSSasha Levin 	fid = get_fid(p9dev, fid_val);
1234c797b6c6SAneesh Kumar K.V 
1235d4727f2bSG. Campana 	if (get_full_path(full_path, sizeof(full_path), fid, name) != 0)
123632832dd1SG. Campana 		goto err_out;
12379bb99a82SG. Campana 
1238c797b6c6SAneesh Kumar K.V 	ret = remove(full_path);
1239c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1240c797b6c6SAneesh Kumar K.V 		goto err_out;
1241c797b6c6SAneesh Kumar K.V 	free(name);
1242c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1243c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1244c797b6c6SAneesh Kumar K.V 	return;
1245c797b6c6SAneesh Kumar K.V err_out:
1246c797b6c6SAneesh Kumar K.V 	free(name);
1247c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1248c797b6c6SAneesh Kumar K.V 	return;
1249c797b6c6SAneesh Kumar K.V }
1250c797b6c6SAneesh Kumar K.V 
12515cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev,
12525cc808aaSSasha Levin 				struct p9_pdu *pdu, u32 *outlen)
12535cc808aaSSasha Levin {
12545cc808aaSSasha Levin 	u16 tag, oldtag;
12555cc808aaSSasha Levin 
12565cc808aaSSasha Levin 	virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag);
12575cc808aaSSasha Levin 	virtio_p9_pdu_writef(pdu, "w", tag);
12585cc808aaSSasha Levin 	*outlen = pdu->write_offset;
12595cc808aaSSasha Levin 	virtio_p9_set_reply_header(pdu, *outlen);
12605cc808aaSSasha Levin 
12615cc808aaSSasha Levin 	return;
12625cc808aaSSasha Levin }
12635cc808aaSSasha Levin 
1264c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
1265c797b6c6SAneesh Kumar K.V 				 struct p9_pdu *pdu, u32 *outlen)
1266c797b6c6SAneesh Kumar K.V {
1267c797b6c6SAneesh Kumar K.V 	return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
1268c797b6c6SAneesh Kumar K.V }
1269c797b6c6SAneesh Kumar K.V 
1270ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev,
1271af045e53SAneesh Kumar K.V 			struct p9_pdu *pdu, u32 *outlen);
1272b4422bf3SAneesh Kumar K.V 
1273c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */
1274c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74
1275c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76
1276c797b6c6SAneesh Kumar K.V 
1277c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = {
1278c797b6c6SAneesh Kumar K.V 	[P9_TREADDIR]     = virtio_p9_readdir,
1279c797b6c6SAneesh Kumar K.V 	[P9_TSTATFS]      = virtio_p9_statfs,
1280c797b6c6SAneesh Kumar K.V 	[P9_TGETATTR]     = virtio_p9_getattr,
1281c797b6c6SAneesh Kumar K.V 	[P9_TSETATTR]     = virtio_p9_setattr,
1282c797b6c6SAneesh Kumar K.V 	[P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
1283c797b6c6SAneesh Kumar K.V 	[P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
1284c797b6c6SAneesh Kumar K.V 	[P9_TMKNOD]       = virtio_p9_mknod,
1285c797b6c6SAneesh Kumar K.V 	[P9_TLOCK]        = virtio_p9_lock,
1286c797b6c6SAneesh Kumar K.V 	[P9_TGETLOCK]     = virtio_p9_getlock,
1287c797b6c6SAneesh Kumar K.V 	[P9_TRENAMEAT]    = virtio_p9_renameat,
1288c797b6c6SAneesh Kumar K.V 	[P9_TREADLINK]    = virtio_p9_readlink,
1289c797b6c6SAneesh Kumar K.V 	[P9_TUNLINKAT]    = virtio_p9_unlinkat,
1290c797b6c6SAneesh Kumar K.V 	[P9_TMKDIR]       = virtio_p9_mkdir,
1291b4422bf3SAneesh Kumar K.V 	[P9_TVERSION]     = virtio_p9_version,
1292c797b6c6SAneesh Kumar K.V 	[P9_TLOPEN]       = virtio_p9_open,
1293b4422bf3SAneesh Kumar K.V 	[P9_TATTACH]      = virtio_p9_attach,
1294b4422bf3SAneesh Kumar K.V 	[P9_TWALK]        = virtio_p9_walk,
1295c797b6c6SAneesh Kumar K.V 	[P9_TCLUNK]       = virtio_p9_clunk,
1296c797b6c6SAneesh Kumar K.V 	[P9_TFSYNC]       = virtio_p9_fsync,
1297b4422bf3SAneesh Kumar K.V 	[P9_TREAD]        = virtio_p9_read,
12985cc808aaSSasha Levin 	[P9_TFLUSH]       = virtio_p9_flush,
1299c797b6c6SAneesh Kumar K.V 	[P9_TLINK]        = virtio_p9_link,
1300c797b6c6SAneesh Kumar K.V 	[P9_TSYMLINK]     = virtio_p9_symlink,
1301c797b6c6SAneesh Kumar K.V 	[P9_TLCREATE]     = virtio_p9_create,
1302b4422bf3SAneesh Kumar K.V 	[P9_TWRITE]       = virtio_p9_write,
13036fc5cd9bSSasha Levin 	[P9_TREMOVE]      = virtio_p9_remove,
1304f161f28bSSasha Levin 	[P9_TRENAME]      = virtio_p9_rename,
1305b4422bf3SAneesh Kumar K.V };
1306b4422bf3SAneesh Kumar K.V 
1307af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
1308af045e53SAneesh Kumar K.V {
1309af045e53SAneesh Kumar K.V 	struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
1310af045e53SAneesh Kumar K.V 	if (!pdu)
1311af045e53SAneesh Kumar K.V 		return NULL;
1312af045e53SAneesh Kumar K.V 
1313bfc15268SAneesh Kumar K.V 	/* skip the pdu header p9_msg */
13145529bcd7SAsias He 	pdu->read_offset	= VIRTIO_9P_HDR_LEN;
13155529bcd7SAsias He 	pdu->write_offset	= VIRTIO_9P_HDR_LEN;
1316af045e53SAneesh Kumar K.V 	pdu->queue_head		= virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
1317a8a44649SAsias He 					pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
1318af045e53SAneesh Kumar K.V 	return pdu;
1319af045e53SAneesh Kumar K.V }
1320af045e53SAneesh Kumar K.V 
1321af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
1322af045e53SAneesh Kumar K.V {
1323af045e53SAneesh Kumar K.V 	struct p9_msg *msg;
1324af045e53SAneesh Kumar K.V 	/*
1325af045e53SAneesh Kumar K.V 	 * we can peek directly into pdu for a u8
1326af045e53SAneesh Kumar K.V 	 * value. The host endianess won't be an issue
1327af045e53SAneesh Kumar K.V 	 */
1328af045e53SAneesh Kumar K.V 	msg = pdu->out_iov[0].iov_base;
1329af045e53SAneesh Kumar K.V 	return msg->cmd;
1330af045e53SAneesh Kumar K.V }
1331af045e53SAneesh Kumar K.V 
1332b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
13331c7850f9SSasha Levin {
1334af045e53SAneesh Kumar K.V 	u8 cmd;
1335b4422bf3SAneesh Kumar K.V 	u32 len = 0;
1336b4422bf3SAneesh Kumar K.V 	p9_handler *handler;
1337b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev;
1338af045e53SAneesh Kumar K.V 	struct virt_queue *vq;
1339af045e53SAneesh Kumar K.V 	struct p9_pdu *p9pdu;
13401c7850f9SSasha Levin 
1341b4422bf3SAneesh Kumar K.V 	vq = job->vq;
1342b4422bf3SAneesh Kumar K.V 	p9dev = job->p9dev;
13431c7850f9SSasha Levin 
1344af045e53SAneesh Kumar K.V 	p9pdu = virtio_p9_pdu_init(kvm, vq);
1345af045e53SAneesh Kumar K.V 	cmd = virtio_p9_get_cmd(p9pdu);
1346af045e53SAneesh Kumar K.V 
1347c797b6c6SAneesh Kumar K.V 	if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
1348c797b6c6SAneesh Kumar K.V 	    !virtio_9p_dotl_handler[cmd])
134997b408afSAneesh Kumar K.V 		handler = virtio_p9_eopnotsupp;
1350dd78d9eaSAneesh Kumar K.V 	else
1351c797b6c6SAneesh Kumar K.V 		handler = virtio_9p_dotl_handler[cmd];
1352c797b6c6SAneesh Kumar K.V 
1353af045e53SAneesh Kumar K.V 	handler(p9dev, p9pdu, &len);
1354af045e53SAneesh Kumar K.V 	virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
1355af045e53SAneesh Kumar K.V 	free(p9pdu);
13561c7850f9SSasha Levin 	return true;
13571c7850f9SSasha Levin }
13581c7850f9SSasha Levin 
13591c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param)
13601c7850f9SSasha Levin {
1361b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job = (struct p9_dev_job *)param;
1362b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev   = job->p9dev;
1363b4422bf3SAneesh Kumar K.V 	struct virt_queue *vq  = job->vq;
13641c7850f9SSasha Levin 
13651c7850f9SSasha Levin 	while (virt_queue__available(vq)) {
1366b4422bf3SAneesh Kumar K.V 		virtio_p9_do_io_request(kvm, job);
136702eca50cSAsias He 		p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
13681c7850f9SSasha Levin 	}
13691c7850f9SSasha Levin }
13701c7850f9SSasha Levin 
1371c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev)
13721c7850f9SSasha Levin {
1373c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
13741c7850f9SSasha Levin 
1375c5ae742bSSasha Levin 	return ((u8 *)(p9dev->config));
1376c7838fbdSSasha Levin }
1377c7838fbdSSasha Levin 
1378e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev)
1379e4730284SMartin Radev {
1380e4730284SMartin Radev 	struct p9_dev *p9dev = dev;
1381e4730284SMartin Radev 
1382e4730284SMartin Radev 	return p9dev->config_size;
1383e4730284SMartin Radev }
1384e4730284SMartin Radev 
1385c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev)
1386c7838fbdSSasha Levin {
1387c7838fbdSSasha Levin 	return 1 << VIRTIO_9P_MOUNT_TAG;
1388c7838fbdSSasha Levin }
1389c7838fbdSSasha Levin 
1390c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
1391c7838fbdSSasha Levin {
1392c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1393c7838fbdSSasha Levin 
1394c7838fbdSSasha Levin 	p9dev->features = features;
1395c7838fbdSSasha Levin }
1396c7838fbdSSasha Levin 
139795242e44SJean-Philippe Brucker static void notify_status(struct kvm *kvm, void *dev, u32 status)
139895242e44SJean-Philippe Brucker {
13998003ede4SJean-Philippe Brucker 	struct p9_dev *p9dev = dev;
14008003ede4SJean-Philippe Brucker 	struct p9_fid *pfid, *next;
14018003ede4SJean-Philippe Brucker 
1402*867b15ccSJean-Philippe Brucker 	if (status & VIRTIO__STATUS_CONFIG)
1403*867b15ccSJean-Philippe Brucker 		p9dev->config->tag_len = virtio_host_to_guest_u16(&p9dev->vdev,
1404*867b15ccSJean-Philippe Brucker 								  p9dev->tag_len);
1405*867b15ccSJean-Philippe Brucker 
14068003ede4SJean-Philippe Brucker 	if (!(status & VIRTIO__STATUS_STOP))
14078003ede4SJean-Philippe Brucker 		return;
14088003ede4SJean-Philippe Brucker 
14098003ede4SJean-Philippe Brucker 	rbtree_postorder_for_each_entry_safe(pfid, next, &p9dev->fids, node)
14108003ede4SJean-Philippe Brucker 		close_fid(p9dev, pfid->fid);
141195242e44SJean-Philippe Brucker }
141295242e44SJean-Philippe Brucker 
1413609ee906SJean-Philippe Brucker static int init_vq(struct kvm *kvm, void *dev, u32 vq)
1414c7838fbdSSasha Levin {
1415c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1416b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job;
1417b4422bf3SAneesh Kumar K.V 	struct virt_queue *queue;
14181c7850f9SSasha Levin 
1419312c62d1SSasha Levin 	compat__remove_message(compat_id);
1420e59662b3SSasha Levin 
1421c7838fbdSSasha Levin 	queue		= &p9dev->vqs[vq];
1422c7838fbdSSasha Levin 	job		= &p9dev->jobs[vq];
14231c7850f9SSasha Levin 
1424609ee906SJean-Philippe Brucker 	virtio_init_device_vq(kvm, &p9dev->vdev, queue, VIRTQUEUE_NUM);
14251c7850f9SSasha Levin 
1426b4422bf3SAneesh Kumar K.V 	*job		= (struct p9_dev_job) {
1427b4422bf3SAneesh Kumar K.V 		.vq		= queue,
1428b4422bf3SAneesh Kumar K.V 		.p9dev		= p9dev,
1429b4422bf3SAneesh Kumar K.V 	};
1430df0c7f57SSasha Levin 	thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
143160eb42d5SSasha Levin 
1432c7838fbdSSasha Levin 	return 0;
14331c7850f9SSasha Levin }
14341c7850f9SSasha Levin 
14358003ede4SJean-Philippe Brucker static void exit_vq(struct kvm *kvm, void *dev, u32 vq)
14368003ede4SJean-Philippe Brucker {
14378003ede4SJean-Philippe Brucker 	struct p9_dev *p9dev = dev;
14388003ede4SJean-Philippe Brucker 
14398003ede4SJean-Philippe Brucker 	thread_pool__cancel_job(&p9dev->jobs[vq].job_id);
14408003ede4SJean-Philippe Brucker }
14418003ede4SJean-Philippe Brucker 
1442c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
1443c7838fbdSSasha Levin {
1444c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
14451c7850f9SSasha Levin 
1446c7838fbdSSasha Levin 	thread_pool__do_job(&p9dev->jobs[vq].job_id);
1447c7838fbdSSasha Levin 
1448c7838fbdSSasha Levin 	return 0;
1449c7838fbdSSasha Levin }
1450c7838fbdSSasha Levin 
145153fbb17bSJean-Philippe Brucker static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
1452c7838fbdSSasha Levin {
1453c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1454c7838fbdSSasha Levin 
145553fbb17bSJean-Philippe Brucker 	return &p9dev->vqs[vq];
1456c7838fbdSSasha Levin }
1457c7838fbdSSasha Levin 
1458c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
1459c7838fbdSSasha Levin {
1460c7838fbdSSasha Levin 	return VIRTQUEUE_NUM;
1461c7838fbdSSasha Levin }
1462c7838fbdSSasha Levin 
14637aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
14647aba29c1SWill Deacon {
14657aba29c1SWill Deacon 	/* FIXME: dynamic */
14667aba29c1SWill Deacon 	return size;
14677aba29c1SWill Deacon }
14687aba29c1SWill Deacon 
146931e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev)
1470b98ac591SJean-Philippe Brucker {
1471b98ac591SJean-Philippe Brucker 	return NUM_VIRT_QUEUES;
1472b98ac591SJean-Philippe Brucker }
1473b98ac591SJean-Philippe Brucker 
147415542babSAndre Przywara struct virtio_ops p9_dev_virtio_ops = {
1475c7838fbdSSasha Levin 	.get_config		= get_config,
1476e4730284SMartin Radev 	.get_config_size	= get_config_size,
1477c7838fbdSSasha Levin 	.get_host_features	= get_host_features,
1478c7838fbdSSasha Levin 	.set_guest_features	= set_guest_features,
1479c7838fbdSSasha Levin 	.init_vq		= init_vq,
14808003ede4SJean-Philippe Brucker 	.exit_vq		= exit_vq,
148195242e44SJean-Philippe Brucker 	.notify_status		= notify_status,
1482c7838fbdSSasha Levin 	.notify_vq		= notify_vq,
148353fbb17bSJean-Philippe Brucker 	.get_vq			= get_vq,
1484c7838fbdSSasha Levin 	.get_size_vq		= get_size_vq,
14857aba29c1SWill Deacon 	.set_size_vq		= set_size_vq,
1486b98ac591SJean-Philippe Brucker 	.get_vq_count		= get_vq_count,
1487c7838fbdSSasha Levin };
14881c47ce69SSasha Levin 
1489cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
1490cac9e8fdSSasha Levin {
1491cac9e8fdSSasha Levin 	char *tag_name;
1492cac9e8fdSSasha Levin 	char tmp[PATH_MAX];
1493cac9e8fdSSasha Levin 	struct kvm *kvm = opt->ptr;
1494cac9e8fdSSasha Levin 
1495cac9e8fdSSasha Levin 	/*
1496cac9e8fdSSasha Levin 	 * 9p dir can be of the form dirname,tag_name or
1497cac9e8fdSSasha Levin 	 * just dirname. In the later case we use the
1498cac9e8fdSSasha Levin 	 * default tag name
1499cac9e8fdSSasha Levin 	 */
1500cac9e8fdSSasha Levin 	tag_name = strstr(arg, ",");
1501cac9e8fdSSasha Levin 	if (tag_name) {
1502cac9e8fdSSasha Levin 		*tag_name = '\0';
1503cac9e8fdSSasha Levin 		tag_name++;
1504cac9e8fdSSasha Levin 	}
1505cac9e8fdSSasha Levin 	if (realpath(arg, tmp)) {
1506cac9e8fdSSasha Levin 		if (virtio_9p__register(kvm, tmp, tag_name) < 0)
1507cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1508cac9e8fdSSasha Levin 	} else
1509cac9e8fdSSasha Levin 		die("Failed resolving 9p path");
1510cac9e8fdSSasha Levin 	return 0;
1511cac9e8fdSSasha Levin }
1512cac9e8fdSSasha Levin 
1513cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset)
1514cac9e8fdSSasha Levin {
1515cac9e8fdSSasha Levin 	char path[PATH_MAX];
1516cac9e8fdSSasha Levin 	struct stat st;
1517cac9e8fdSSasha Levin 	struct kvm *kvm = opt->ptr;
1518cac9e8fdSSasha Levin 
1519cac9e8fdSSasha Levin 	if (stat(arg, &st) == 0 &&
1520cac9e8fdSSasha Levin 	    S_ISDIR(st.st_mode)) {
1521cac9e8fdSSasha Levin 		char tmp[PATH_MAX];
1522cac9e8fdSSasha Levin 
1523cac9e8fdSSasha Levin 		if (kvm->cfg.using_rootfs)
1524cac9e8fdSSasha Levin 			die("Please use only one rootfs directory atmost");
1525cac9e8fdSSasha Levin 
1526cac9e8fdSSasha Levin 		if (realpath(arg, tmp) == 0 ||
1527cac9e8fdSSasha Levin 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1528cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1529cac9e8fdSSasha Levin 		kvm->cfg.using_rootfs = 1;
1530cac9e8fdSSasha Levin 		return 0;
1531cac9e8fdSSasha Levin 	}
1532cac9e8fdSSasha Levin 
1533cac9e8fdSSasha Levin 	snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
1534cac9e8fdSSasha Levin 
1535cac9e8fdSSasha Levin 	if (stat(path, &st) == 0 &&
1536cac9e8fdSSasha Levin 	    S_ISDIR(st.st_mode)) {
1537cac9e8fdSSasha Levin 		char tmp[PATH_MAX];
1538cac9e8fdSSasha Levin 
1539cac9e8fdSSasha Levin 		if (kvm->cfg.using_rootfs)
1540cac9e8fdSSasha Levin 			die("Please use only one rootfs directory atmost");
1541cac9e8fdSSasha Levin 
1542cac9e8fdSSasha Levin 		if (realpath(path, tmp) == 0 ||
1543cac9e8fdSSasha Levin 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1544cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1545cac9e8fdSSasha Levin 		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
1546cac9e8fdSSasha Levin 			die("Unable to initialize virtio 9p");
1547cac9e8fdSSasha Levin 		kvm_setup_resolv(arg);
1548cac9e8fdSSasha Levin 		kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1;
1549cac9e8fdSSasha Levin 		kvm->cfg.custom_rootfs_name = arg;
1550cac9e8fdSSasha Levin 		return 0;
1551cac9e8fdSSasha Levin 	}
1552cac9e8fdSSasha Levin 
1553cac9e8fdSSasha Levin 	return -1;
1554cac9e8fdSSasha Levin }
1555cac9e8fdSSasha Levin 
15561c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm)
15571c47ce69SSasha Levin {
15581c47ce69SSasha Levin 	struct p9_dev *p9dev;
1559db927775SAlexandru Elisei 	int r;
15601c47ce69SSasha Levin 
15611c47ce69SSasha Levin 	list_for_each_entry(p9dev, &devs, list) {
1562db927775SAlexandru Elisei 		r = virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
1563d97dadecSWill Deacon 				VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_9P,
1564ae06ce71SWill Deacon 				VIRTIO_ID_9P, PCI_CLASS_9P);
1565db927775SAlexandru Elisei 		if (r < 0)
1566db927775SAlexandru Elisei 			return r;
1567c7838fbdSSasha Levin 	}
1568c7838fbdSSasha Levin 
1569c7838fbdSSasha Levin 	return 0;
1570c7838fbdSSasha Levin }
157149a8afd1SSasha Levin virtio_dev_init(virtio_9p__init);
1572c7838fbdSSasha Levin 
1573c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
1574c7838fbdSSasha Levin {
1575c7838fbdSSasha Levin 	struct p9_dev *p9dev;
1576e4730284SMartin Radev 	size_t tag_length;
1577e4730284SMartin Radev 	size_t config_size;
1578e4730284SMartin Radev 	int err;
15791c7850f9SSasha Levin 
1580b4422bf3SAneesh Kumar K.V 	p9dev = calloc(1, sizeof(*p9dev));
1581b4422bf3SAneesh Kumar K.V 	if (!p9dev)
158254f6802dSPekka Enberg 		return -ENOMEM;
158354f6802dSPekka Enberg 
1584b4422bf3SAneesh Kumar K.V 	if (!tag_name)
15855529bcd7SAsias He 		tag_name = VIRTIO_9P_DEFAULT_TAG;
158654f6802dSPekka Enberg 
1587e4730284SMartin Radev 	tag_length = strlen(tag_name);
1588e4730284SMartin Radev 	/* The tag_name zero byte is intentionally excluded */
1589e4730284SMartin Radev 	config_size = sizeof(*p9dev->config) + tag_length;
1590e4730284SMartin Radev 
1591e4730284SMartin Radev 	p9dev->config = calloc(1, config_size);
159254f6802dSPekka Enberg 	if (p9dev->config == NULL) {
159354f6802dSPekka Enberg 		err = -ENOMEM;
1594b4422bf3SAneesh Kumar K.V 		goto free_p9dev;
159554f6802dSPekka Enberg 	}
1596e4730284SMartin Radev 	p9dev->config_size = config_size;
15971c7850f9SSasha Levin 
1598e277a1b4SG. Campana 	strncpy(p9dev->root_dir, root, sizeof(p9dev->root_dir));
1599e277a1b4SG. Campana 	p9dev->root_dir[sizeof(p9dev->root_dir)-1] = '\x00';
1600e277a1b4SG. Campana 
1601*867b15ccSJean-Philippe Brucker 	p9dev->tag_len = tag_length;
1602*867b15ccSJean-Philippe Brucker 	if (p9dev->tag_len > MAX_TAG_LEN) {
160354f6802dSPekka Enberg 		err = -EINVAL;
1604b4422bf3SAneesh Kumar K.V 		goto free_p9dev_config;
160554f6802dSPekka Enberg 	}
16061c7850f9SSasha Levin 
1607e4730284SMartin Radev 	memcpy(&p9dev->config->tag, tag_name, tag_length);
16081c7850f9SSasha Levin 
1609c7838fbdSSasha Levin 	list_add(&p9dev->list, &devs);
1610b4422bf3SAneesh Kumar K.V 
1611d278197dSAsias He 	if (compat_id == -1)
161252f34d2cSAsias He 		compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO");
1613e59662b3SSasha Levin 
1614e4730284SMartin Radev 	return 0;
161554f6802dSPekka Enberg 
1616b4422bf3SAneesh Kumar K.V free_p9dev_config:
1617b4422bf3SAneesh Kumar K.V 	free(p9dev->config);
1618b4422bf3SAneesh Kumar K.V free_p9dev:
1619b4422bf3SAneesh Kumar K.V 	free(p9dev);
162054f6802dSPekka Enberg 	return err;
16211c7850f9SSasha Levin }
1622