xref: /kvmtool/virtio/9p.c (revision baac79a53c9baf32be60379f07e788da99c8b03f)
11c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h"
21c7850f9SSasha Levin #include "kvm/ioport.h"
31c7850f9SSasha Levin #include "kvm/util.h"
41c7850f9SSasha Levin #include "kvm/threadpool.h"
560eb42d5SSasha Levin #include "kvm/ioeventfd.h"
6bfc15268SAneesh Kumar K.V #include "kvm/irq.h"
7bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h"
8e59662b3SSasha Levin #include "kvm/guest_compat.h"
91c7850f9SSasha Levin 
10bfc15268SAneesh Kumar K.V #include <stdio.h>
11bfc15268SAneesh Kumar K.V #include <stdlib.h>
121c7850f9SSasha Levin #include <fcntl.h>
131c7850f9SSasha Levin #include <sys/stat.h>
14bfc15268SAneesh Kumar K.V #include <unistd.h>
15bfc15268SAneesh Kumar K.V #include <string.h>
16bfc15268SAneesh Kumar K.V #include <errno.h>
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>
212daa28d4SAneesh Kumar K.V #include <net/9p/9p.h>
222daa28d4SAneesh Kumar K.V 
23c7838fbdSSasha Levin static LIST_HEAD(devs);
24c7838fbdSSasha Levin 
251c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */
26b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev,
27b4422bf3SAneesh Kumar K.V 			      const char *path, char *abs_path)
281c7850f9SSasha Levin {
29b4422bf3SAneesh Kumar K.V 	sprintf(abs_path, "%s/%s", p9dev->root_dir, path);
301c7850f9SSasha Levin 
311c7850f9SSasha Levin 	return abs_path;
321c7850f9SSasha Levin }
331c7850f9SSasha Levin 
34c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid)
351c7850f9SSasha Levin {
361c7850f9SSasha Levin 	*qid = (struct p9_qid) {
371c7850f9SSasha Levin 		.path		= st->st_ino,
381c7850f9SSasha Levin 		.version	= st->st_mtime,
391c7850f9SSasha Levin 	};
401c7850f9SSasha Levin 
411c7850f9SSasha Levin 	if (S_ISDIR(st->st_mode))
421c7850f9SSasha Levin 		qid->type	|= P9_QTDIR;
431c7850f9SSasha Levin }
441c7850f9SSasha Levin 
45b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid)
461c7850f9SSasha Levin {
47b4422bf3SAneesh Kumar K.V 	if (p9dev->fids[fid].fd > 0) {
48b4422bf3SAneesh Kumar K.V 		close(p9dev->fids[fid].fd);
49b4422bf3SAneesh Kumar K.V 		p9dev->fids[fid].fd = -1;
501c7850f9SSasha Levin 	}
51b4422bf3SAneesh Kumar K.V 	if (p9dev->fids[fid].dir) {
52b4422bf3SAneesh Kumar K.V 		closedir(p9dev->fids[fid].dir);
53b4422bf3SAneesh Kumar K.V 		p9dev->fids[fid].dir = NULL;
541c7850f9SSasha Levin 	}
55c797b6c6SAneesh Kumar K.V 	p9dev->fids[fid].fid = P9_NOFID;
561c7850f9SSasha Levin }
571c7850f9SSasha Levin 
58bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
591c7850f9SSasha Levin {
60bfc15268SAneesh Kumar K.V 	u8 cmd;
61bfc15268SAneesh Kumar K.V 	u16 tag;
62bfc15268SAneesh Kumar K.V 
63bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32);
64bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
65bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
66bfc15268SAneesh Kumar K.V 	/* cmd + 1 is the reply message */
67bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
681c7850f9SSasha Levin }
691c7850f9SSasha Levin 
706b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
716b163a87SAneesh Kumar K.V {
726b163a87SAneesh Kumar K.V 	int i;
736b163a87SAneesh Kumar K.V 	u32 total = 0;
746b163a87SAneesh Kumar K.V 	for (i = 0; (i < iov_cnt) && (total < count); i++) {
756b163a87SAneesh Kumar K.V 		if (total + iov[i].iov_len > count) {
766b163a87SAneesh Kumar K.V 			/* we don't need this iov fully */
776b163a87SAneesh Kumar K.V 			iov[i].iov_len -= ((total + iov[i].iov_len) - count);
786b163a87SAneesh Kumar K.V 			i++;
796b163a87SAneesh Kumar K.V 			break;
806b163a87SAneesh Kumar K.V 		}
816b163a87SAneesh Kumar K.V 		total += iov[i].iov_len;
826b163a87SAneesh Kumar K.V 	}
836b163a87SAneesh Kumar K.V 	return i;
846b163a87SAneesh Kumar K.V }
856b163a87SAneesh Kumar K.V 
86eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev,
87eee1ba8eSAneesh Kumar K.V 				  struct p9_pdu *pdu, int err, u32 *outlen)
88eee1ba8eSAneesh Kumar K.V {
89bfc15268SAneesh Kumar K.V 	u16 tag;
90eee1ba8eSAneesh Kumar K.V 
91bfc15268SAneesh Kumar K.V 	pdu->write_offset = VIRTIO_P9_HDR_LEN;
92c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", err);
93bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
94eee1ba8eSAneesh Kumar K.V 
95c797b6c6SAneesh Kumar K.V 	/* read the tag from input */
96bfc15268SAneesh Kumar K.V 	pdu->read_offset = sizeof(u32) + sizeof(u8);
97bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "w", &tag);
98bfc15268SAneesh Kumar K.V 
99c797b6c6SAneesh Kumar K.V 	/* Update the header */
100bfc15268SAneesh Kumar K.V 	pdu->write_offset = 0;
101c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
102eee1ba8eSAneesh Kumar K.V }
103eee1ba8eSAneesh Kumar K.V 
104ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev,
105af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
1061c7850f9SSasha Levin {
107c797b6c6SAneesh Kumar K.V 	u32 msize;
108c797b6c6SAneesh Kumar K.V 	char *version;
109c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
110c797b6c6SAneesh Kumar K.V 	/*
111c797b6c6SAneesh Kumar K.V 	 * reply with the same msize the client sent us
112c797b6c6SAneesh Kumar K.V 	 * Error out if the request is not for 9P2000.L
113c797b6c6SAneesh Kumar K.V 	 */
114c797b6c6SAneesh Kumar K.V 	if (!strcmp(version, VIRTIO_P9_VERSION_DOTL))
115c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, version);
116c797b6c6SAneesh Kumar K.V 	else
117c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
1181c7850f9SSasha Levin 
119bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
120bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
121c797b6c6SAneesh Kumar K.V 	free(version);
122ead43b01SAneesh Kumar K.V 	return;
1231c7850f9SSasha Levin }
1241c7850f9SSasha Levin 
125ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev,
126af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
1271c7850f9SSasha Levin {
128bfc15268SAneesh Kumar K.V 	u32 fid;
1291c7850f9SSasha Levin 
130bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid);
131bfc15268SAneesh Kumar K.V 	close_fid(p9dev, fid);
1321c7850f9SSasha Levin 
133bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
134bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
135ead43b01SAneesh Kumar K.V 	return;
1361c7850f9SSasha Levin }
1371c7850f9SSasha Levin 
138c797b6c6SAneesh Kumar K.V /*
139c797b6c6SAneesh Kumar K.V  * FIXME!! Need to map to protocol independent value. Upstream
140c797b6c6SAneesh Kumar K.V  * 9p also have the same BUG
141c797b6c6SAneesh Kumar K.V  */
142c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags)
143c797b6c6SAneesh Kumar K.V {
144c797b6c6SAneesh Kumar K.V 	flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
145c797b6c6SAneesh Kumar K.V 	flags |= O_NOFOLLOW;
146c797b6c6SAneesh Kumar K.V 	return flags;
147c797b6c6SAneesh Kumar K.V }
148c797b6c6SAneesh Kumar K.V 
149ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev,
150af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
1511c7850f9SSasha Levin {
152c797b6c6SAneesh Kumar K.V 	u32 fid, flags;
1531c7850f9SSasha Levin 	struct stat st;
154bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
155bfc15268SAneesh Kumar K.V 	struct p9_fid *new_fid;
156bfc15268SAneesh Kumar K.V 
157c797b6c6SAneesh Kumar K.V 
158c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
159bfc15268SAneesh Kumar K.V 	new_fid = &p9dev->fids[fid];
1601c7850f9SSasha Levin 
16130204a77SAneesh Kumar K.V 	if (lstat(new_fid->abs_path, &st) < 0)
162eee1ba8eSAneesh Kumar K.V 		goto err_out;
1631c7850f9SSasha Levin 
164c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
1651c7850f9SSasha Levin 
166eee1ba8eSAneesh Kumar K.V 	if (new_fid->is_dir) {
1671c7850f9SSasha Levin 		new_fid->dir = opendir(new_fid->abs_path);
168eee1ba8eSAneesh Kumar K.V 		if (!new_fid->dir)
169eee1ba8eSAneesh Kumar K.V 			goto err_out;
170eee1ba8eSAneesh Kumar K.V 	} else {
171eee1ba8eSAneesh Kumar K.V 		new_fid->fd  = open(new_fid->abs_path,
172c797b6c6SAneesh Kumar K.V 				    virtio_p9_openflags(flags));
173eee1ba8eSAneesh Kumar K.V 		if (new_fid->fd < 0)
174eee1ba8eSAneesh Kumar K.V 			goto err_out;
175eee1ba8eSAneesh Kumar K.V 	}
176c797b6c6SAneesh Kumar K.V 	/* FIXME!! need ot send proper iounit  */
177bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
178bfc15268SAneesh Kumar K.V 
179bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
180bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
181ead43b01SAneesh Kumar K.V 	return;
182eee1ba8eSAneesh Kumar K.V err_out:
183eee1ba8eSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
184ead43b01SAneesh Kumar K.V 	return;
1851c7850f9SSasha Levin }
1861c7850f9SSasha Levin 
187ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev,
188af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
1891c7850f9SSasha Levin {
190c797b6c6SAneesh Kumar K.V 	int fd, ret;
191bfc15268SAneesh Kumar K.V 	char *name;
192af045e53SAneesh Kumar K.V 	struct stat st;
193bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
194c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
1954bc9734aSAneesh Kumar K.V 	char full_path[PATH_MAX];
196c797b6c6SAneesh Kumar K.V 	u32 dfid_val, flags, mode, gid;
197af045e53SAneesh Kumar K.V 
198c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
199c797b6c6SAneesh Kumar K.V 			    &name, &flags, &mode, &gid);
200c797b6c6SAneesh Kumar K.V 	dfid = &p9dev->fids[dfid_val];
2011c7850f9SSasha Levin 
202c797b6c6SAneesh Kumar K.V 	flags = virtio_p9_openflags(flags);
2035f900f6dSSasha Levin 
204c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
205c797b6c6SAneesh Kumar K.V 	fd = open(full_path, flags | O_CREAT, mode);
2064bc9734aSAneesh Kumar K.V 	if (fd < 0)
2074bc9734aSAneesh Kumar K.V 		goto err_out;
208c797b6c6SAneesh Kumar K.V 	close_fid(p9dev, dfid_val);
209c797b6c6SAneesh Kumar K.V 	dfid->fd = fd;
210c797b6c6SAneesh Kumar K.V 
2114bc9734aSAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
2126c8ca053SAneesh Kumar K.V 		goto err_out;
2131c7850f9SSasha Levin 
214c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
215c797b6c6SAneesh Kumar K.V 	if (ret < 0)
216c797b6c6SAneesh Kumar K.V 		goto err_out;
217c797b6c6SAneesh Kumar K.V 
218c797b6c6SAneesh Kumar K.V 	ret = lchown(full_path, dfid->uid, gid);
219c797b6c6SAneesh Kumar K.V 	if (ret < 0)
220c797b6c6SAneesh Kumar K.V 		goto err_out;
221c797b6c6SAneesh Kumar K.V 
222c797b6c6SAneesh Kumar K.V 	sprintf(dfid->path, "%s/%s", dfid->path, name);
223c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
224bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
225bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
226bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
2275f900f6dSSasha Levin 	free(name);
2286c8ca053SAneesh Kumar K.V 	return;
2296c8ca053SAneesh Kumar K.V err_out:
2305f900f6dSSasha Levin 	free(name);
231c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
232c797b6c6SAneesh Kumar K.V 	return;
233c797b6c6SAneesh Kumar K.V }
234c797b6c6SAneesh Kumar K.V 
235c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev,
236c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
237c797b6c6SAneesh Kumar K.V {
238c797b6c6SAneesh Kumar K.V 	int ret;
239c797b6c6SAneesh Kumar K.V 	char *name;
240c797b6c6SAneesh Kumar K.V 	struct stat st;
241c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
242c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
243c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
244c797b6c6SAneesh Kumar K.V 	u32 dfid_val, mode, gid;
245c797b6c6SAneesh Kumar K.V 
246c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
247c797b6c6SAneesh Kumar K.V 			    &name, &mode, &gid);
248c797b6c6SAneesh Kumar K.V 	dfid = &p9dev->fids[dfid_val];
249c797b6c6SAneesh Kumar K.V 
250c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
251c797b6c6SAneesh Kumar K.V 	ret = mkdir(full_path, mode);
252c797b6c6SAneesh Kumar K.V 	if (ret < 0)
253c797b6c6SAneesh Kumar K.V 		goto err_out;
254c797b6c6SAneesh Kumar K.V 
255c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
256c797b6c6SAneesh Kumar K.V 		goto err_out;
257c797b6c6SAneesh Kumar K.V 
258c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
259c797b6c6SAneesh Kumar K.V 	if (ret < 0)
260c797b6c6SAneesh Kumar K.V 		goto err_out;
261c797b6c6SAneesh Kumar K.V 
262c797b6c6SAneesh Kumar K.V 	ret = lchown(full_path, dfid->uid, gid);
263c797b6c6SAneesh Kumar K.V 	if (ret < 0)
264c797b6c6SAneesh Kumar K.V 		goto err_out;
265c797b6c6SAneesh Kumar K.V 
266c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
267c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
268c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
269c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
270c797b6c6SAneesh Kumar K.V 	free(name);
271c797b6c6SAneesh Kumar K.V 	return;
272c797b6c6SAneesh Kumar K.V err_out:
273c797b6c6SAneesh Kumar K.V 	free(name);
274c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
275ead43b01SAneesh Kumar K.V 	return;
2761c7850f9SSasha Levin }
2771c7850f9SSasha Levin 
278ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev,
279af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
2801c7850f9SSasha Levin {
281af045e53SAneesh Kumar K.V 	u8 i;
282bfc15268SAneesh Kumar K.V 	u16 nwqid;
283bfc15268SAneesh Kumar K.V 	char *str;
284bfc15268SAneesh Kumar K.V 	u16 nwname;
285bfc15268SAneesh Kumar K.V 	struct p9_qid wqid;
286bfc15268SAneesh Kumar K.V 	struct p9_fid *new_fid;
287c797b6c6SAneesh Kumar K.V 	u32 fid_val, newfid_val;
288c797b6c6SAneesh Kumar K.V 
2891c7850f9SSasha Levin 
290bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
291bfc15268SAneesh Kumar K.V 	new_fid	= &p9dev->fids[newfid_val];
2921c7850f9SSasha Levin 
293bfc15268SAneesh Kumar K.V 	nwqid = 0;
294bfc15268SAneesh Kumar K.V 	if (nwname) {
295bfc15268SAneesh Kumar K.V 		struct p9_fid *fid = &p9dev->fids[fid_val];
296bfc15268SAneesh Kumar K.V 
297*baac79a5SAneesh Kumar K.V 		strcpy(new_fid->path, fid->path);
298bfc15268SAneesh Kumar K.V 		/* skip the space for count */
299bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
300bfc15268SAneesh Kumar K.V 		for (i = 0; i < nwname; i++) {
301bfc15268SAneesh Kumar K.V 			struct stat st;
3021c7850f9SSasha Levin 			char tmp[PATH_MAX] = {0};
3031c7850f9SSasha Levin 			char full_path[PATH_MAX];
304bfc15268SAneesh Kumar K.V 
305bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_readf(pdu, "s", &str);
3061c7850f9SSasha Levin 
3071c7850f9SSasha Levin 			/* Format the new path we're 'walk'ing into */
308*baac79a5SAneesh Kumar K.V 			sprintf(tmp, "%s/%s", new_fid->path, str);
309c797b6c6SAneesh Kumar K.V 			if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0)
3106c8ca053SAneesh Kumar K.V 				goto err_out;
3111c7850f9SSasha Levin 
312c797b6c6SAneesh Kumar K.V 			stat2qid(&st, &wqid);
3131c7850f9SSasha Levin 			new_fid->is_dir = S_ISDIR(st.st_mode);
3141c7850f9SSasha Levin 			strcpy(new_fid->path, tmp);
315bfc15268SAneesh Kumar K.V 			new_fid->fid = newfid_val;
316c797b6c6SAneesh Kumar K.V 			new_fid->uid = fid->uid;
317bfc15268SAneesh Kumar K.V 			nwqid++;
318bfc15268SAneesh Kumar K.V 			virtio_p9_pdu_writef(pdu, "Q", &wqid);
3191c7850f9SSasha Levin 		}
3201c7850f9SSasha Levin 	} else {
321bfc15268SAneesh Kumar K.V 		/*
322bfc15268SAneesh Kumar K.V 		 * update write_offset so our outlen get correct value
323bfc15268SAneesh Kumar K.V 		 */
324bfc15268SAneesh Kumar K.V 		pdu->write_offset += sizeof(u16);
325bfc15268SAneesh Kumar K.V 		new_fid->is_dir = p9dev->fids[fid_val].is_dir;
326bfc15268SAneesh Kumar K.V 		strcpy(new_fid->path, p9dev->fids[fid_val].path);
327bfc15268SAneesh Kumar K.V 		new_fid->fid	= newfid_val;
328c797b6c6SAneesh Kumar K.V 		new_fid->uid    = p9dev->fids[fid_val].uid;
3291c7850f9SSasha Levin 	}
330bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
331bfc15268SAneesh Kumar K.V 	pdu->write_offset = VIRTIO_P9_HDR_LEN;
332bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", nwqid);
333bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
3346c8ca053SAneesh Kumar K.V 	return;
3356c8ca053SAneesh Kumar K.V err_out:
3366c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
337ead43b01SAneesh Kumar K.V 	return;
3381c7850f9SSasha Levin }
3391c7850f9SSasha Levin 
340ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev,
341af045e53SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
3421c7850f9SSasha Levin {
343c797b6c6SAneesh Kumar K.V 	int i;
344bfc15268SAneesh Kumar K.V 	char *uname;
345bfc15268SAneesh Kumar K.V 	char *aname;
3461c7850f9SSasha Levin 	struct stat st;
347bfc15268SAneesh Kumar K.V 	struct p9_qid qid;
3481c7850f9SSasha Levin 	struct p9_fid *fid;
349c797b6c6SAneesh Kumar K.V 	u32 fid_val, afid, uid;
350bfc15268SAneesh Kumar K.V 
351c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
352c797b6c6SAneesh Kumar K.V 			    &uname, &aname, &uid);
3531c7850f9SSasha Levin 
3541c7850f9SSasha Levin 	/* Reset everything */
3551c7850f9SSasha Levin 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++)
356b4422bf3SAneesh Kumar K.V 		p9dev->fids[i].fid = P9_NOFID;
3571c7850f9SSasha Levin 
35830204a77SAneesh Kumar K.V 	if (lstat(p9dev->root_dir, &st) < 0)
3596c8ca053SAneesh Kumar K.V 		goto err_out;
3601c7850f9SSasha Levin 
361c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
3621c7850f9SSasha Levin 
363bfc15268SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
364bfc15268SAneesh Kumar K.V 	fid->fid = fid_val;
365c797b6c6SAneesh Kumar K.V 	fid->uid = uid;
3661c7850f9SSasha Levin 	fid->is_dir = 1;
3671c7850f9SSasha Levin 	strcpy(fid->path, "/");
3681c7850f9SSasha Levin 
369bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
370bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
371bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
3726c8ca053SAneesh Kumar K.V 	return;
3736c8ca053SAneesh Kumar K.V err_out:
3746c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
375ead43b01SAneesh Kumar K.V 	return;
3761c7850f9SSasha Levin }
3771c7850f9SSasha Levin 
378c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev,
379c797b6c6SAneesh Kumar K.V 				struct stat *st, struct p9_stat_dotl *statl)
3805f900f6dSSasha Levin {
381c797b6c6SAneesh Kumar K.V 	memset(statl, 0, sizeof(*statl));
382c797b6c6SAneesh Kumar K.V 	statl->st_mode = st->st_mode;
383c797b6c6SAneesh Kumar K.V 	statl->st_nlink = st->st_nlink;
384c797b6c6SAneesh Kumar K.V 	statl->st_uid = st->st_uid;
385c797b6c6SAneesh Kumar K.V 	statl->st_gid = st->st_gid;
386c797b6c6SAneesh Kumar K.V 	statl->st_rdev = st->st_rdev;
387c797b6c6SAneesh Kumar K.V 	statl->st_size = st->st_size;
388c797b6c6SAneesh Kumar K.V 	statl->st_blksize = st->st_blksize;
389c797b6c6SAneesh Kumar K.V 	statl->st_blocks = st->st_blocks;
390c797b6c6SAneesh Kumar K.V 	statl->st_atime_sec = st->st_atime;
391c797b6c6SAneesh Kumar K.V 	statl->st_atime_nsec = st->st_atim.tv_nsec;
392c797b6c6SAneesh Kumar K.V 	statl->st_mtime_sec = st->st_mtime;
393c797b6c6SAneesh Kumar K.V 	statl->st_mtime_nsec = st->st_mtim.tv_nsec;
394c797b6c6SAneesh Kumar K.V 	statl->st_ctime_sec = st->st_ctime;
395c797b6c6SAneesh Kumar K.V 	statl->st_ctime_nsec = st->st_ctim.tv_nsec;
396c797b6c6SAneesh Kumar K.V 	/* Currently we only support BASIC fields in stat */
397c797b6c6SAneesh Kumar K.V 	statl->st_result_mask = P9_STATS_BASIC;
398c797b6c6SAneesh Kumar K.V 	stat2qid(st, &statl->qid);
3991c7850f9SSasha Levin }
4001c7850f9SSasha Levin 
401ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev,
402af045e53SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
4031c7850f9SSasha Levin {
404bfc15268SAneesh Kumar K.V 	u64 offset;
405bfc15268SAneesh Kumar K.V 	u32 fid_val;
406c797b6c6SAneesh Kumar K.V 	u16 iov_cnt;
407c797b6c6SAneesh Kumar K.V 	void *iov_base;
408c797b6c6SAneesh Kumar K.V 	size_t iov_len;
409bfc15268SAneesh Kumar K.V 	u32 count, rcount;
410bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
411c797b6c6SAneesh Kumar K.V 
4121c7850f9SSasha Levin 
413bfc15268SAneesh Kumar K.V 	rcount = 0;
414bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
415bfc15268SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
41650c479e0SAneesh Kumar K.V 
41750c479e0SAneesh Kumar K.V 	iov_base = pdu->in_iov[0].iov_base;
41850c479e0SAneesh Kumar K.V 	iov_len  = pdu->in_iov[0].iov_len;
41950c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->in_iov_cnt;
420af045e53SAneesh Kumar K.V 	pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32);
421af045e53SAneesh Kumar K.V 	pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32);
4226b163a87SAneesh Kumar K.V 	pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
423bfc15268SAneesh Kumar K.V 						   count,
4246b163a87SAneesh Kumar K.V 						   pdu->in_iov_cnt);
425bfc15268SAneesh Kumar K.V 	rcount = preadv(fid->fd, pdu->in_iov,
426bfc15268SAneesh Kumar K.V 			pdu->in_iov_cnt, offset);
427bfc15268SAneesh Kumar K.V 	if (rcount > count)
428bfc15268SAneesh Kumar K.V 		rcount = count;
429bfc15268SAneesh Kumar K.V 	/*
430bfc15268SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
431bfc15268SAneesh Kumar K.V 	 * pdu_writef works correctly.
432bfc15268SAneesh Kumar K.V 	 */
43350c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_base = iov_base;
43450c479e0SAneesh Kumar K.V 	pdu->in_iov[0].iov_len  = iov_len;
43550c479e0SAneesh Kumar K.V 	pdu->in_iov_cnt         = iov_cnt;
436c797b6c6SAneesh Kumar K.V 
437bfc15268SAneesh Kumar K.V 	pdu->write_offset = VIRTIO_P9_HDR_LEN;
438bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
439bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
440bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
441ead43b01SAneesh Kumar K.V 	return;
4421c7850f9SSasha Levin }
4431c7850f9SSasha Levin 
444c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent)
445c797b6c6SAneesh Kumar K.V {
446c797b6c6SAneesh Kumar K.V 	/*
447c797b6c6SAneesh Kumar K.V 	 * Size of each dirent:
448c797b6c6SAneesh Kumar K.V 	 * qid(13) + offset(8) + type(1) + name_len(2) + name
449c797b6c6SAneesh Kumar K.V 	 */
450c797b6c6SAneesh Kumar K.V 	return 24 + strlen(dent->d_name);
451c797b6c6SAneesh Kumar K.V }
452c797b6c6SAneesh Kumar K.V 
453c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev,
454c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
455c797b6c6SAneesh Kumar K.V {
456c797b6c6SAneesh Kumar K.V 	u32 fid_val;
457c797b6c6SAneesh Kumar K.V 	u32 count, rcount;
458c797b6c6SAneesh Kumar K.V 	struct stat st;
459c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
460c797b6c6SAneesh Kumar K.V 	struct dirent *dent;
461c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
462c797b6c6SAneesh Kumar K.V 	u64 offset, old_offset;
463c797b6c6SAneesh Kumar K.V 
464c797b6c6SAneesh Kumar K.V 	rcount = 0;
465c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
466c797b6c6SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
467c797b6c6SAneesh Kumar K.V 
468c797b6c6SAneesh Kumar K.V 	if (!fid->is_dir) {
469c797b6c6SAneesh Kumar K.V 		errno = -EINVAL;
470c797b6c6SAneesh Kumar K.V 		goto err_out;
471c797b6c6SAneesh Kumar K.V 	}
472c797b6c6SAneesh Kumar K.V 
473c797b6c6SAneesh Kumar K.V 	/* Move the offset specified */
474c797b6c6SAneesh Kumar K.V 	seekdir(fid->dir, offset);
475c797b6c6SAneesh Kumar K.V 
476c797b6c6SAneesh Kumar K.V 	old_offset = offset;
477c797b6c6SAneesh Kumar K.V 	/* If reading a dir, fill the buffer with p9_stat entries */
478c797b6c6SAneesh Kumar K.V 	dent = readdir(fid->dir);
479c797b6c6SAneesh Kumar K.V 
480c797b6c6SAneesh Kumar K.V 	/* Skip the space for writing count */
481c797b6c6SAneesh Kumar K.V 	pdu->write_offset += sizeof(u32);
482c797b6c6SAneesh Kumar K.V 	while (dent) {
483c797b6c6SAneesh Kumar K.V 		u32 read;
484c797b6c6SAneesh Kumar K.V 		struct p9_qid qid;
485c797b6c6SAneesh Kumar K.V 
486c797b6c6SAneesh Kumar K.V 		if ((rcount + virtio_p9_dentry_size(dent)) > count) {
487c797b6c6SAneesh Kumar K.V 			/* seek to the previous offset and return */
488c797b6c6SAneesh Kumar K.V 			seekdir(fid->dir, old_offset);
489c797b6c6SAneesh Kumar K.V 			break;
490c797b6c6SAneesh Kumar K.V 		}
491c797b6c6SAneesh Kumar K.V 		old_offset = dent->d_off;
492c797b6c6SAneesh Kumar K.V 		lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st);
493c797b6c6SAneesh Kumar K.V 		stat2qid(&st, &qid);
494c797b6c6SAneesh Kumar K.V 		read = pdu->write_offset;
495c797b6c6SAneesh Kumar K.V 		virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
496c797b6c6SAneesh Kumar K.V 				     dent->d_type, dent->d_name);
497c797b6c6SAneesh Kumar K.V 		rcount += pdu->write_offset - read;
498c797b6c6SAneesh Kumar K.V 		dent = readdir(fid->dir);
499c797b6c6SAneesh Kumar K.V 	}
500c797b6c6SAneesh Kumar K.V 
501c797b6c6SAneesh Kumar K.V 	pdu->write_offset = VIRTIO_P9_HDR_LEN;
502c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", rcount);
503c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset + rcount;
504c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
505c797b6c6SAneesh Kumar K.V 	return;
506c797b6c6SAneesh Kumar K.V err_out:
507c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
508c797b6c6SAneesh Kumar K.V 	return;
509c797b6c6SAneesh Kumar K.V }
510c797b6c6SAneesh Kumar K.V 
511c797b6c6SAneesh Kumar K.V 
512c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev,
513af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
5141c7850f9SSasha Levin {
515bfc15268SAneesh Kumar K.V 	u32 fid_val;
516af045e53SAneesh Kumar K.V 	struct stat st;
517c797b6c6SAneesh Kumar K.V 	u64 request_mask;
518bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
519c797b6c6SAneesh Kumar K.V 	struct p9_stat_dotl statl;
5201c7850f9SSasha Levin 
521c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
522bfc15268SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
52330204a77SAneesh Kumar K.V 	if (lstat(fid->abs_path, &st) < 0)
5246c8ca053SAneesh Kumar K.V 		goto err_out;
5251c7850f9SSasha Levin 
526c797b6c6SAneesh Kumar K.V 	virtio_p9_fill_stat(p9dev, &st, &statl);
527c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "A", &statl);
528bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
529bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
530ead43b01SAneesh Kumar K.V 	return;
5316c8ca053SAneesh Kumar K.V err_out:
5326c8ca053SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
5336c8ca053SAneesh Kumar K.V 	return;
5341c7850f9SSasha Levin }
5351c7850f9SSasha Levin 
536c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */
537c797b6c6SAneesh Kumar K.V /*
538c797b6c6SAneesh Kumar K.V  * Attribute flags.  These should be or-ed together to figure out what
539c797b6c6SAneesh Kumar K.V  * has been changed!
540c797b6c6SAneesh Kumar K.V  */
541c797b6c6SAneesh Kumar K.V #define ATTR_MODE	(1 << 0)
542c797b6c6SAneesh Kumar K.V #define ATTR_UID	(1 << 1)
543c797b6c6SAneesh Kumar K.V #define ATTR_GID	(1 << 2)
544c797b6c6SAneesh Kumar K.V #define ATTR_SIZE	(1 << 3)
545c797b6c6SAneesh Kumar K.V #define ATTR_ATIME	(1 << 4)
546c797b6c6SAneesh Kumar K.V #define ATTR_MTIME	(1 << 5)
547c797b6c6SAneesh Kumar K.V #define ATTR_CTIME	(1 << 6)
548c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET	(1 << 7)
549c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET	(1 << 8)
550c797b6c6SAneesh Kumar K.V #define ATTR_FORCE	(1 << 9) /* Not a change, but a change it */
551c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG	(1 << 10)
552c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID	(1 << 11)
553c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID	(1 << 12)
554c797b6c6SAneesh Kumar K.V #define ATTR_FILE	(1 << 13)
555c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV	(1 << 14)
556c797b6c6SAneesh Kumar K.V #define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
557c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET	(1 << 16)
558c797b6c6SAneesh Kumar K.V 
559c797b6c6SAneesh Kumar K.V #define ATTR_MASK    127
560c797b6c6SAneesh Kumar K.V 
561c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev,
562af045e53SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
5631c7850f9SSasha Levin {
564c797b6c6SAneesh Kumar K.V 	int ret = 0;
565bfc15268SAneesh Kumar K.V 	u32 fid_val;
566bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
567c797b6c6SAneesh Kumar K.V 	struct p9_iattr_dotl p9attr;
5681c7850f9SSasha Levin 
569c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
570bfc15268SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
5711c7850f9SSasha Levin 
572c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & ATTR_MODE) {
573c797b6c6SAneesh Kumar K.V 		ret = chmod(fid->abs_path, p9attr.mode);
574c797b6c6SAneesh Kumar K.V 		if (ret < 0)
575c797b6c6SAneesh Kumar K.V 			goto err_out;
576c797b6c6SAneesh Kumar K.V 	}
577c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
578c797b6c6SAneesh Kumar K.V 		struct timespec times[2];
579c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_ATIME) {
580c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_ATIME_SET) {
581c797b6c6SAneesh Kumar K.V 				times[0].tv_sec = p9attr.atime_sec;
582c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = p9attr.atime_nsec;
583c797b6c6SAneesh Kumar K.V 			} else {
584c797b6c6SAneesh Kumar K.V 				times[0].tv_nsec = UTIME_NOW;
585c797b6c6SAneesh Kumar K.V 			}
586c797b6c6SAneesh Kumar K.V 		} else {
587c797b6c6SAneesh Kumar K.V 			times[0].tv_nsec = UTIME_OMIT;
588c797b6c6SAneesh Kumar K.V 		}
589c797b6c6SAneesh Kumar K.V 		if (p9attr.valid & ATTR_MTIME) {
590c797b6c6SAneesh Kumar K.V 			if (p9attr.valid & ATTR_MTIME_SET) {
591c797b6c6SAneesh Kumar K.V 				times[1].tv_sec = p9attr.mtime_sec;
592c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = p9attr.mtime_nsec;
593c797b6c6SAneesh Kumar K.V 			} else {
594c797b6c6SAneesh Kumar K.V 				times[1].tv_nsec = UTIME_NOW;
595c797b6c6SAneesh Kumar K.V 			}
596c797b6c6SAneesh Kumar K.V 		} else
597c797b6c6SAneesh Kumar K.V 			times[1].tv_nsec = UTIME_OMIT;
598c797b6c6SAneesh Kumar K.V 
599c797b6c6SAneesh Kumar K.V 		ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
600c797b6c6SAneesh Kumar K.V 		if (ret < 0)
601c797b6c6SAneesh Kumar K.V 			goto err_out;
602c797b6c6SAneesh Kumar K.V 	}
603c797b6c6SAneesh Kumar K.V 	/*
604c797b6c6SAneesh Kumar K.V 	 * If the only valid entry in iattr is ctime we can call
605c797b6c6SAneesh Kumar K.V 	 * chown(-1,-1) to update the ctime of the file
606c797b6c6SAneesh Kumar K.V 	 */
607c797b6c6SAneesh Kumar K.V 	if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
608c797b6c6SAneesh Kumar K.V 	    ((p9attr.valid & ATTR_CTIME)
609c797b6c6SAneesh Kumar K.V 	     && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
610c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_UID))
611c797b6c6SAneesh Kumar K.V 			p9attr.uid = -1;
612c797b6c6SAneesh Kumar K.V 
613c797b6c6SAneesh Kumar K.V 		if (!(p9attr.valid & ATTR_GID))
614c797b6c6SAneesh Kumar K.V 			p9attr.gid = -1;
615c797b6c6SAneesh Kumar K.V 
616c797b6c6SAneesh Kumar K.V 		ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid);
617c797b6c6SAneesh Kumar K.V 		if (ret < 0)
618c797b6c6SAneesh Kumar K.V 			goto err_out;
619c797b6c6SAneesh Kumar K.V 	}
620c797b6c6SAneesh Kumar K.V 	if (p9attr.valid & (ATTR_SIZE)) {
621c797b6c6SAneesh Kumar K.V 		ret = truncate(fid->abs_path, p9attr.size);
622c797b6c6SAneesh Kumar K.V 		if (ret < 0)
623c797b6c6SAneesh Kumar K.V 			goto err_out;
624c797b6c6SAneesh Kumar K.V 	}
6251c7850f9SSasha Levin 	*outlen = VIRTIO_P9_HDR_LEN;
626bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
627ead43b01SAneesh Kumar K.V 	return;
6284bc9734aSAneesh Kumar K.V err_out:
6294bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
6304bc9734aSAneesh Kumar K.V 	return;
6311c7850f9SSasha Levin }
6321c7850f9SSasha Levin 
633ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev,
634af045e53SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
6351c7850f9SSasha Levin {
6364bc9734aSAneesh Kumar K.V 
637bfc15268SAneesh Kumar K.V 	u64 offset;
638bfc15268SAneesh Kumar K.V 	u32 fid_val;
6394bc9734aSAneesh Kumar K.V 	u32 count;
6404bc9734aSAneesh Kumar K.V 	ssize_t res;
64150c479e0SAneesh Kumar K.V 	u16 iov_cnt;
64250c479e0SAneesh Kumar K.V 	void *iov_base;
64350c479e0SAneesh Kumar K.V 	size_t iov_len;
644bfc15268SAneesh Kumar K.V 	struct p9_fid *fid;
645b064b05aSAneesh Kumar K.V 	/* u32 fid + u64 offset + u32 count */
646b064b05aSAneesh Kumar K.V 	int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
6471c7850f9SSasha Levin 
648bfc15268SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
649bfc15268SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
650af045e53SAneesh Kumar K.V 
65150c479e0SAneesh Kumar K.V 	iov_base = pdu->out_iov[0].iov_base;
65250c479e0SAneesh Kumar K.V 	iov_len  = pdu->out_iov[0].iov_len;
65350c479e0SAneesh Kumar K.V 	iov_cnt  = pdu->out_iov_cnt;
65450c479e0SAneesh Kumar K.V 
655bfc15268SAneesh Kumar K.V 	/* Adjust the iovec to skip the header and meta data */
656b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
657b064b05aSAneesh Kumar K.V 	pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
658bfc15268SAneesh Kumar K.V 	pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
6596b163a87SAneesh Kumar K.V 						    pdu->out_iov_cnt);
6604bc9734aSAneesh Kumar K.V 	res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
66150c479e0SAneesh Kumar K.V 	/*
66250c479e0SAneesh Kumar K.V 	 * Update the iov_base back, so that rest of
66350c479e0SAneesh Kumar K.V 	 * pdu_readf works correctly.
66450c479e0SAneesh Kumar K.V 	 */
66550c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_base = iov_base;
66650c479e0SAneesh Kumar K.V 	pdu->out_iov[0].iov_len  = iov_len;
66750c479e0SAneesh Kumar K.V 	pdu->out_iov_cnt         = iov_cnt;
668c797b6c6SAneesh Kumar K.V 
6694bc9734aSAneesh Kumar K.V 	if (res < 0)
6704bc9734aSAneesh Kumar K.V 		goto err_out;
6714bc9734aSAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", res);
672bfc15268SAneesh Kumar K.V 	*outlen = pdu->write_offset;
673bfc15268SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
674ead43b01SAneesh Kumar K.V 	return;
6754bc9734aSAneesh Kumar K.V err_out:
6764bc9734aSAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
6774bc9734aSAneesh Kumar K.V 	return;
6781c7850f9SSasha Levin }
6791c7850f9SSasha Levin 
680c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev,
681c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
682c797b6c6SAneesh Kumar K.V {
683c797b6c6SAneesh Kumar K.V 	int ret;
684c797b6c6SAneesh Kumar K.V 	u32 fid_val;
685c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
686c797b6c6SAneesh Kumar K.V 	char target_path[PATH_MAX];
687c797b6c6SAneesh Kumar K.V 
688c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
689c797b6c6SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
690c797b6c6SAneesh Kumar K.V 
691c797b6c6SAneesh Kumar K.V 	memset(target_path, 0, PATH_MAX);
692c797b6c6SAneesh Kumar K.V 	ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
693c797b6c6SAneesh Kumar K.V 	if (ret < 0)
694c797b6c6SAneesh Kumar K.V 		goto err_out;
695c797b6c6SAneesh Kumar K.V 
696c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "s", target_path);
697c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
698c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
699c797b6c6SAneesh Kumar K.V 	return;
700c797b6c6SAneesh Kumar K.V err_out:
701c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
702c797b6c6SAneesh Kumar K.V 	return;
703c797b6c6SAneesh Kumar K.V }
704c797b6c6SAneesh Kumar K.V 
705c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev,
706c797b6c6SAneesh Kumar K.V 			     struct p9_pdu *pdu, u32 *outlen)
707c797b6c6SAneesh Kumar K.V {
708c797b6c6SAneesh Kumar K.V 	int ret;
709c797b6c6SAneesh Kumar K.V 	u64 fsid;
710c797b6c6SAneesh Kumar K.V 	u32 fid_val;
711c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
712c797b6c6SAneesh Kumar K.V 	struct statfs stat_buf;
713c797b6c6SAneesh Kumar K.V 
714c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
715c797b6c6SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
716c797b6c6SAneesh Kumar K.V 
717c797b6c6SAneesh Kumar K.V 	ret = statfs(fid->abs_path, &stat_buf);
718c797b6c6SAneesh Kumar K.V 	if (ret < 0)
719c797b6c6SAneesh Kumar K.V 		goto err_out;
720c797b6c6SAneesh Kumar K.V 	/* FIXME!! f_blocks needs update based on client msize */
721c797b6c6SAneesh Kumar K.V 	fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
722c797b6c6SAneesh Kumar K.V 		(unsigned long long)stat_buf.f_fsid.__val[1] << 32;
723c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
724c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bsize, stat_buf.f_blocks,
725c797b6c6SAneesh Kumar K.V 			     stat_buf.f_bfree, stat_buf.f_bavail,
726c797b6c6SAneesh Kumar K.V 			     stat_buf.f_files, stat_buf.f_ffree,
727c797b6c6SAneesh Kumar K.V 			     fsid, stat_buf.f_namelen);
728c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
729c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
730c797b6c6SAneesh Kumar K.V 	return;
731c797b6c6SAneesh Kumar K.V err_out:
732c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
733c797b6c6SAneesh Kumar K.V 	return;
734c797b6c6SAneesh Kumar K.V }
735c797b6c6SAneesh Kumar K.V 
736c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev,
737c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
738c797b6c6SAneesh Kumar K.V {
739c797b6c6SAneesh Kumar K.V 	int ret;
740c797b6c6SAneesh Kumar K.V 	char *name;
741c797b6c6SAneesh Kumar K.V 	struct stat st;
742c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
743c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
744c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
745c797b6c6SAneesh Kumar K.V 	u32 fid_val, mode, major, minor, gid;
746c797b6c6SAneesh Kumar K.V 
747c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
748c797b6c6SAneesh Kumar K.V 			    &major, &minor, &gid);
749c797b6c6SAneesh Kumar K.V 
750c797b6c6SAneesh Kumar K.V 	dfid = &p9dev->fids[fid_val];
751c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
752c797b6c6SAneesh Kumar K.V 	ret = mknod(full_path, mode, makedev(major, minor));
753c797b6c6SAneesh Kumar K.V 	if (ret < 0)
754c797b6c6SAneesh Kumar K.V 		goto err_out;
755c797b6c6SAneesh Kumar K.V 
756c797b6c6SAneesh Kumar K.V 	if (lstat(full_path, &st) < 0)
757c797b6c6SAneesh Kumar K.V 		goto err_out;
758c797b6c6SAneesh Kumar K.V 
759c797b6c6SAneesh Kumar K.V 	ret = chmod(full_path, mode & 0777);
760c797b6c6SAneesh Kumar K.V 	if (ret < 0)
761c797b6c6SAneesh Kumar K.V 		goto err_out;
762c797b6c6SAneesh Kumar K.V 
763c797b6c6SAneesh Kumar K.V 	ret = lchown(full_path, dfid->uid, gid);
764c797b6c6SAneesh Kumar K.V 	if (ret < 0)
765c797b6c6SAneesh Kumar K.V 		goto err_out;
766c797b6c6SAneesh Kumar K.V 
767c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
768c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
769c797b6c6SAneesh Kumar K.V 	free(name);
770c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
771c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
772c797b6c6SAneesh Kumar K.V 	return;
773c797b6c6SAneesh Kumar K.V err_out:
774c797b6c6SAneesh Kumar K.V 	free(name);
775c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
776c797b6c6SAneesh Kumar K.V 	return;
777c797b6c6SAneesh Kumar K.V }
778c797b6c6SAneesh Kumar K.V 
779c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev,
780c797b6c6SAneesh Kumar K.V 			    struct p9_pdu *pdu, u32 *outlen)
781c797b6c6SAneesh Kumar K.V {
782c797b6c6SAneesh Kumar K.V 	int ret;
783c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
784c797b6c6SAneesh Kumar K.V 	u32 fid_val, datasync;
785c797b6c6SAneesh Kumar K.V 
786c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
787c797b6c6SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
788c797b6c6SAneesh Kumar K.V 
789c797b6c6SAneesh Kumar K.V 	if (datasync)
790c797b6c6SAneesh Kumar K.V 		ret = fdatasync(fid->fd);
791c797b6c6SAneesh Kumar K.V 	else
792c797b6c6SAneesh Kumar K.V 		ret = fsync(fid->fd);
793c797b6c6SAneesh Kumar K.V 	if (ret < 0)
794c797b6c6SAneesh Kumar K.V 		goto err_out;
795c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
796c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
797c797b6c6SAneesh Kumar K.V 	return;
798c797b6c6SAneesh Kumar K.V err_out:
799c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
800c797b6c6SAneesh Kumar K.V 	return;
801c797b6c6SAneesh Kumar K.V }
802c797b6c6SAneesh Kumar K.V 
803c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev,
804c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
805c797b6c6SAneesh Kumar K.V {
806c797b6c6SAneesh Kumar K.V 	int ret;
807c797b6c6SAneesh Kumar K.V 	struct stat st;
808c797b6c6SAneesh Kumar K.V 	u32 fid_val, gid;
809c797b6c6SAneesh Kumar K.V 	struct p9_qid qid;
810c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid;
811c797b6c6SAneesh Kumar K.V 	char new_name[PATH_MAX];
812c797b6c6SAneesh Kumar K.V 	char *old_path, *name;
813c797b6c6SAneesh Kumar K.V 
814c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
815c797b6c6SAneesh Kumar K.V 
816c797b6c6SAneesh Kumar K.V 	dfid = &p9dev->fids[fid_val];
817c797b6c6SAneesh Kumar K.V 	sprintf(new_name, "%s/%s", dfid->abs_path, name);
818c797b6c6SAneesh Kumar K.V 	ret = symlink(old_path, new_name);
819c797b6c6SAneesh Kumar K.V 	if (ret < 0)
820c797b6c6SAneesh Kumar K.V 		goto err_out;
821c797b6c6SAneesh Kumar K.V 
822c797b6c6SAneesh Kumar K.V 	if (lstat(new_name, &st) < 0)
823c797b6c6SAneesh Kumar K.V 		goto err_out;
824c797b6c6SAneesh Kumar K.V 
825c797b6c6SAneesh Kumar K.V 	ret = lchown(new_name, dfid->uid, gid);
826c797b6c6SAneesh Kumar K.V 	if (ret < 0)
827c797b6c6SAneesh Kumar K.V 		goto err_out;
828c797b6c6SAneesh Kumar K.V 
829c797b6c6SAneesh Kumar K.V 	stat2qid(&st, &qid);
830c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "Q", &qid);
831c797b6c6SAneesh Kumar K.V 	free(name);
832c797b6c6SAneesh Kumar K.V 	free(old_path);
833c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
834c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
835c797b6c6SAneesh Kumar K.V 	return;
836c797b6c6SAneesh Kumar K.V err_out:
837c797b6c6SAneesh Kumar K.V 	free(name);
838c797b6c6SAneesh Kumar K.V 	free(old_path);
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_link(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 	u32 fid_val, dfid_val;
849c797b6c6SAneesh Kumar K.V 	struct p9_fid *dfid, *fid;
850c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
851c797b6c6SAneesh Kumar K.V 
852c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
853c797b6c6SAneesh Kumar K.V 
854c797b6c6SAneesh Kumar K.V 	dfid = &p9dev->fids[dfid_val];
855c797b6c6SAneesh Kumar K.V 	fid =  &p9dev->fids[fid_val];
856c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", dfid->abs_path, name);
857c797b6c6SAneesh Kumar K.V 	ret = link(fid->abs_path, full_path);
858c797b6c6SAneesh Kumar K.V 	if (ret < 0)
859c797b6c6SAneesh Kumar K.V 		goto err_out;
860c797b6c6SAneesh Kumar K.V 	free(name);
861c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
862c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
863c797b6c6SAneesh Kumar K.V 	return;
864c797b6c6SAneesh Kumar K.V err_out:
865c797b6c6SAneesh Kumar K.V 	free(name);
866c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
867c797b6c6SAneesh Kumar K.V 	return;
868c797b6c6SAneesh Kumar K.V 
869c797b6c6SAneesh Kumar K.V }
870c797b6c6SAneesh Kumar K.V 
871c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev,
872c797b6c6SAneesh Kumar K.V 			   struct p9_pdu *pdu, u32 *outlen)
873c797b6c6SAneesh Kumar K.V {
874c797b6c6SAneesh Kumar K.V 	u8 ret;
875c797b6c6SAneesh Kumar K.V 	u32 fid_val;
876c797b6c6SAneesh Kumar K.V 	struct p9_flock flock;
877c797b6c6SAneesh Kumar K.V 
878c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
879c797b6c6SAneesh Kumar K.V 			    &flock.flags, &flock.start, &flock.length,
880c797b6c6SAneesh Kumar K.V 			    &flock.proc_id, &flock.client_id);
881c797b6c6SAneesh Kumar K.V 
882c797b6c6SAneesh Kumar K.V 	/* Just return success */
883c797b6c6SAneesh Kumar K.V 	ret = P9_LOCK_SUCCESS;
884c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "d", ret);
885c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
886c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
887c797b6c6SAneesh Kumar K.V 	free(flock.client_id);
888c797b6c6SAneesh Kumar K.V 	return;
889c797b6c6SAneesh Kumar K.V }
890c797b6c6SAneesh Kumar K.V 
891c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev,
892c797b6c6SAneesh Kumar K.V 			      struct p9_pdu *pdu, u32 *outlen)
893c797b6c6SAneesh Kumar K.V {
894c797b6c6SAneesh Kumar K.V 	u32 fid_val;
895c797b6c6SAneesh Kumar K.V 	struct p9_getlock glock;
896c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
897c797b6c6SAneesh Kumar K.V 			    &glock.start, &glock.length, &glock.proc_id,
898c797b6c6SAneesh Kumar K.V 			    &glock.client_id);
899c797b6c6SAneesh Kumar K.V 
900c797b6c6SAneesh Kumar K.V 	/* Just return success */
901c797b6c6SAneesh Kumar K.V 	glock.type = F_UNLCK;
902c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
903c797b6c6SAneesh Kumar K.V 			     glock.start, glock.length, glock.proc_id,
904c797b6c6SAneesh Kumar K.V 			     glock.client_id);
905c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
906c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
907c797b6c6SAneesh Kumar K.V 	free(glock.client_id);
908c797b6c6SAneesh Kumar K.V 	return;
909c797b6c6SAneesh Kumar K.V }
910c797b6c6SAneesh Kumar K.V 
911c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor)
912c797b6c6SAneesh Kumar K.V {
913c797b6c6SAneesh Kumar K.V 	int size = strlen(ancestor);
914c797b6c6SAneesh Kumar K.V 	if (!strncmp(path, ancestor, size)) {
915c797b6c6SAneesh Kumar K.V 		/*
916c797b6c6SAneesh Kumar K.V 		 * Now check whether ancestor is a full name or
917c797b6c6SAneesh Kumar K.V 		 * or directory component and not just part
918c797b6c6SAneesh Kumar K.V 		 * of a name.
919c797b6c6SAneesh Kumar K.V 		 */
920c797b6c6SAneesh Kumar K.V 		if (path[size] == '\0' || path[size] == '/')
921c797b6c6SAneesh Kumar K.V 			return 1;
922c797b6c6SAneesh Kumar K.V 	}
923c797b6c6SAneesh Kumar K.V 	return 0;
924c797b6c6SAneesh Kumar K.V }
925c797b6c6SAneesh Kumar K.V 
926c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name)
927c797b6c6SAneesh Kumar K.V {
928c797b6c6SAneesh Kumar K.V 	char tmp_name[PATH_MAX];
929c797b6c6SAneesh Kumar K.V 	size_t rp_sz = strlen(old_name);
930c797b6c6SAneesh Kumar K.V 
931c797b6c6SAneesh Kumar K.V 	if (rp_sz == strlen(fid_path)) {
932c797b6c6SAneesh Kumar K.V 		/* replace the full name */
933c797b6c6SAneesh Kumar K.V 		strcpy(fid_path, new_name);
934c797b6c6SAneesh Kumar K.V 		return;
935c797b6c6SAneesh Kumar K.V 	}
936c797b6c6SAneesh Kumar K.V 	/* save the trailing path details */
937c797b6c6SAneesh Kumar K.V 	strcpy(tmp_name, fid_path + rp_sz);
938c797b6c6SAneesh Kumar K.V 	sprintf(fid_path, "%s%s", new_name, tmp_name);
939c797b6c6SAneesh Kumar K.V 	return;
940c797b6c6SAneesh Kumar K.V }
941c797b6c6SAneesh Kumar K.V 
942c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev,
943c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
944c797b6c6SAneesh Kumar K.V {
945c797b6c6SAneesh Kumar K.V 	int i, ret;
946c797b6c6SAneesh Kumar K.V 	char *old_name, *new_name;
947c797b6c6SAneesh Kumar K.V 	u32 old_dfid_val, new_dfid_val;
948c797b6c6SAneesh Kumar K.V 	struct p9_fid *old_dfid, *new_dfid;
949c797b6c6SAneesh Kumar K.V 	char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
950c797b6c6SAneesh Kumar K.V 
951c797b6c6SAneesh Kumar K.V 
952c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
953c797b6c6SAneesh Kumar K.V 			    &new_dfid_val, &new_name);
954c797b6c6SAneesh Kumar K.V 
955c797b6c6SAneesh Kumar K.V 	old_dfid = &p9dev->fids[old_dfid_val];
956c797b6c6SAneesh Kumar K.V 	new_dfid = &p9dev->fids[new_dfid_val];
957c797b6c6SAneesh Kumar K.V 
958c797b6c6SAneesh Kumar K.V 	sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name);
959c797b6c6SAneesh Kumar K.V 	sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name);
960c797b6c6SAneesh Kumar K.V 	ret = rename(old_full_path, new_full_path);
961c797b6c6SAneesh Kumar K.V 	if (ret < 0)
962c797b6c6SAneesh Kumar K.V 		goto err_out;
963c797b6c6SAneesh Kumar K.V 	/*
964c797b6c6SAneesh Kumar K.V 	 * Now fix path in other fids, if the renamed path is part of
965c797b6c6SAneesh Kumar K.V 	 * that.
966c797b6c6SAneesh Kumar K.V 	 */
967c797b6c6SAneesh Kumar K.V 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++) {
968c797b6c6SAneesh Kumar K.V 		if (p9dev->fids[i].fid != P9_NOFID &&
969c797b6c6SAneesh Kumar K.V 		    virtio_p9_ancestor(p9dev->fids[i].path, old_name)) {
970c797b6c6SAneesh Kumar K.V 			virtio_p9_fix_path(p9dev->fids[i].path, old_name,
971c797b6c6SAneesh Kumar K.V 					   new_name);
972c797b6c6SAneesh Kumar K.V 		}
973c797b6c6SAneesh Kumar K.V 	}
974c797b6c6SAneesh Kumar K.V 	free(old_name);
975c797b6c6SAneesh Kumar K.V 	free(new_name);
976c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
977c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
978c797b6c6SAneesh Kumar K.V 	return;
979c797b6c6SAneesh Kumar K.V err_out:
980c797b6c6SAneesh Kumar K.V 	free(old_name);
981c797b6c6SAneesh Kumar K.V 	free(new_name);
982c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
983c797b6c6SAneesh Kumar K.V 	return;
984c797b6c6SAneesh Kumar K.V }
985c797b6c6SAneesh Kumar K.V 
986c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev,
987c797b6c6SAneesh Kumar K.V 			       struct p9_pdu *pdu, u32 *outlen)
988c797b6c6SAneesh Kumar K.V {
989c797b6c6SAneesh Kumar K.V 	int ret;
990c797b6c6SAneesh Kumar K.V 	char *name;
991c797b6c6SAneesh Kumar K.V 	u32 fid_val, flags;
992c797b6c6SAneesh Kumar K.V 	struct p9_fid *fid;
993c797b6c6SAneesh Kumar K.V 	char full_path[PATH_MAX];
994c797b6c6SAneesh Kumar K.V 
995c797b6c6SAneesh Kumar K.V 	virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
996c797b6c6SAneesh Kumar K.V 	fid = &p9dev->fids[fid_val];
997c797b6c6SAneesh Kumar K.V 
998c797b6c6SAneesh Kumar K.V 	sprintf(full_path, "%s/%s", fid->abs_path, name);
999c797b6c6SAneesh Kumar K.V 	ret = remove(full_path);
1000c797b6c6SAneesh Kumar K.V 	if (ret < 0)
1001c797b6c6SAneesh Kumar K.V 		goto err_out;
1002c797b6c6SAneesh Kumar K.V 	free(name);
1003c797b6c6SAneesh Kumar K.V 	*outlen = pdu->write_offset;
1004c797b6c6SAneesh Kumar K.V 	virtio_p9_set_reply_header(pdu, *outlen);
1005c797b6c6SAneesh Kumar K.V 	return;
1006c797b6c6SAneesh Kumar K.V err_out:
1007c797b6c6SAneesh Kumar K.V 	free(name);
1008c797b6c6SAneesh Kumar K.V 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1009c797b6c6SAneesh Kumar K.V 	return;
1010c797b6c6SAneesh Kumar K.V }
1011c797b6c6SAneesh Kumar K.V 
1012c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
1013c797b6c6SAneesh Kumar K.V 				 struct p9_pdu *pdu, u32 *outlen)
1014c797b6c6SAneesh Kumar K.V {
1015c797b6c6SAneesh Kumar K.V 	return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
1016c797b6c6SAneesh Kumar K.V }
1017c797b6c6SAneesh Kumar K.V 
1018ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev,
1019af045e53SAneesh Kumar K.V 			struct p9_pdu *pdu, u32 *outlen);
1020b4422bf3SAneesh Kumar K.V 
1021c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */
1022c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74
1023c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76
1024c797b6c6SAneesh Kumar K.V 
1025c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = {
1026c797b6c6SAneesh Kumar K.V 	[P9_TREADDIR]     = virtio_p9_readdir,
1027c797b6c6SAneesh Kumar K.V 	[P9_TSTATFS]      = virtio_p9_statfs,
1028c797b6c6SAneesh Kumar K.V 	[P9_TGETATTR]     = virtio_p9_getattr,
1029c797b6c6SAneesh Kumar K.V 	[P9_TSETATTR]     = virtio_p9_setattr,
1030c797b6c6SAneesh Kumar K.V 	[P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
1031c797b6c6SAneesh Kumar K.V 	[P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
1032c797b6c6SAneesh Kumar K.V 	[P9_TMKNOD]       = virtio_p9_mknod,
1033c797b6c6SAneesh Kumar K.V 	[P9_TLOCK]        = virtio_p9_lock,
1034c797b6c6SAneesh Kumar K.V 	[P9_TGETLOCK]     = virtio_p9_getlock,
1035c797b6c6SAneesh Kumar K.V 	[P9_TRENAMEAT]    = virtio_p9_renameat,
1036c797b6c6SAneesh Kumar K.V 	[P9_TREADLINK]    = virtio_p9_readlink,
1037c797b6c6SAneesh Kumar K.V 	[P9_TUNLINKAT]    = virtio_p9_unlinkat,
1038c797b6c6SAneesh Kumar K.V 	[P9_TMKDIR]       = virtio_p9_mkdir,
1039b4422bf3SAneesh Kumar K.V 	[P9_TVERSION]     = virtio_p9_version,
1040c797b6c6SAneesh Kumar K.V 	[P9_TLOPEN]       = virtio_p9_open,
1041b4422bf3SAneesh Kumar K.V 	[P9_TATTACH]      = virtio_p9_attach,
1042b4422bf3SAneesh Kumar K.V 	[P9_TWALK]        = virtio_p9_walk,
1043c797b6c6SAneesh Kumar K.V 	[P9_TCLUNK]       = virtio_p9_clunk,
1044c797b6c6SAneesh Kumar K.V 	[P9_TFSYNC]       = virtio_p9_fsync,
1045b4422bf3SAneesh Kumar K.V 	[P9_TREAD]        = virtio_p9_read,
1046c797b6c6SAneesh Kumar K.V 	[P9_TFLUSH]       = virtio_p9_eopnotsupp,
1047c797b6c6SAneesh Kumar K.V 	[P9_TLINK]        = virtio_p9_link,
1048c797b6c6SAneesh Kumar K.V 	[P9_TSYMLINK]     = virtio_p9_symlink,
1049c797b6c6SAneesh Kumar K.V 	[P9_TLCREATE]     = virtio_p9_create,
1050b4422bf3SAneesh Kumar K.V 	[P9_TWRITE]       = virtio_p9_write,
1051b4422bf3SAneesh Kumar K.V };
1052b4422bf3SAneesh Kumar K.V 
1053af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
1054af045e53SAneesh Kumar K.V {
1055af045e53SAneesh Kumar K.V 	struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
1056af045e53SAneesh Kumar K.V 	if (!pdu)
1057af045e53SAneesh Kumar K.V 		return NULL;
1058af045e53SAneesh Kumar K.V 
1059bfc15268SAneesh Kumar K.V 	/* skip the pdu header p9_msg */
1060bfc15268SAneesh Kumar K.V 	pdu->read_offset  = VIRTIO_P9_HDR_LEN;
1061bfc15268SAneesh Kumar K.V 	pdu->write_offset = VIRTIO_P9_HDR_LEN;
1062af045e53SAneesh Kumar K.V 	pdu->queue_head  = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
1063af045e53SAneesh Kumar K.V 						     pdu->out_iov,
1064af045e53SAneesh Kumar K.V 						     &pdu->in_iov_cnt,
1065af045e53SAneesh Kumar K.V 						     &pdu->out_iov_cnt);
1066af045e53SAneesh Kumar K.V 	return pdu;
1067af045e53SAneesh Kumar K.V }
1068af045e53SAneesh Kumar K.V 
1069af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
1070af045e53SAneesh Kumar K.V {
1071af045e53SAneesh Kumar K.V 	struct p9_msg *msg;
1072af045e53SAneesh Kumar K.V 	/*
1073af045e53SAneesh Kumar K.V 	 * we can peek directly into pdu for a u8
1074af045e53SAneesh Kumar K.V 	 * value. The host endianess won't be an issue
1075af045e53SAneesh Kumar K.V 	 */
1076af045e53SAneesh Kumar K.V 	msg = pdu->out_iov[0].iov_base;
1077af045e53SAneesh Kumar K.V 	return msg->cmd;
1078af045e53SAneesh Kumar K.V }
1079af045e53SAneesh Kumar K.V 
1080b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
10811c7850f9SSasha Levin {
1082af045e53SAneesh Kumar K.V 	u8 cmd;
1083b4422bf3SAneesh Kumar K.V 	u32 len = 0;
1084b4422bf3SAneesh Kumar K.V 	p9_handler *handler;
1085b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev;
1086af045e53SAneesh Kumar K.V 	struct virt_queue *vq;
1087af045e53SAneesh Kumar K.V 	struct p9_pdu *p9pdu;
10881c7850f9SSasha Levin 
1089b4422bf3SAneesh Kumar K.V 	vq = job->vq;
1090b4422bf3SAneesh Kumar K.V 	p9dev = job->p9dev;
10911c7850f9SSasha Levin 
1092af045e53SAneesh Kumar K.V 	p9pdu = virtio_p9_pdu_init(kvm, vq);
1093af045e53SAneesh Kumar K.V 	cmd = virtio_p9_get_cmd(p9pdu);
1094af045e53SAneesh Kumar K.V 
1095c797b6c6SAneesh Kumar K.V 	if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
1096c797b6c6SAneesh Kumar K.V 	    !virtio_9p_dotl_handler[cmd])
109797b408afSAneesh Kumar K.V 		handler = virtio_p9_eopnotsupp;
1098dd78d9eaSAneesh Kumar K.V 	else
1099c797b6c6SAneesh Kumar K.V 		handler = virtio_9p_dotl_handler[cmd];
1100c797b6c6SAneesh Kumar K.V 
1101af045e53SAneesh Kumar K.V 	handler(p9dev, p9pdu, &len);
1102af045e53SAneesh Kumar K.V 	virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
1103af045e53SAneesh Kumar K.V 	free(p9pdu);
11041c7850f9SSasha Levin 	return true;
11051c7850f9SSasha Levin }
11061c7850f9SSasha Levin 
11071c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param)
11081c7850f9SSasha Levin {
1109b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job = (struct p9_dev_job *)param;
1110b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev   = job->p9dev;
1111b4422bf3SAneesh Kumar K.V 	struct virt_queue *vq  = job->vq;
11121c7850f9SSasha Levin 
11131c7850f9SSasha Levin 	while (virt_queue__available(vq)) {
1114b4422bf3SAneesh Kumar K.V 		virtio_p9_do_io_request(kvm, job);
1115c7838fbdSSasha Levin 		virtio_pci__signal_vq(kvm, &p9dev->vpci, vq - p9dev->vqs);
11161c7850f9SSasha Levin 	}
11171c7850f9SSasha Levin }
11181c7850f9SSasha Levin 
111960eb42d5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param)
112060eb42d5SSasha Levin {
112160eb42d5SSasha Levin 	struct p9_dev_job *job = param;
112260eb42d5SSasha Levin 
1123df0c7f57SSasha Levin 	thread_pool__do_job(&job->job_id);
112460eb42d5SSasha Levin }
112560eb42d5SSasha Levin 
1126c7838fbdSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
11271c7850f9SSasha Levin {
1128c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
11291c7850f9SSasha Levin 
1130c7838fbdSSasha Levin 	((u8 *)(p9dev->config))[offset] = data;
1131c7838fbdSSasha Levin }
11321c7850f9SSasha Levin 
1133c7838fbdSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
1134c7838fbdSSasha Levin {
1135c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1136c7838fbdSSasha Levin 
1137c7838fbdSSasha Levin 	return ((u8 *)(p9dev->config))[offset];
1138c7838fbdSSasha Levin }
1139c7838fbdSSasha Levin 
1140c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev)
1141c7838fbdSSasha Levin {
1142c7838fbdSSasha Levin 	return 1 << VIRTIO_9P_MOUNT_TAG;
1143c7838fbdSSasha Levin }
1144c7838fbdSSasha Levin 
1145c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
1146c7838fbdSSasha Levin {
1147c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1148c7838fbdSSasha Levin 
1149c7838fbdSSasha Levin 	p9dev->features = features;
1150c7838fbdSSasha Levin }
1151c7838fbdSSasha Levin 
1152c7838fbdSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
1153c7838fbdSSasha Levin {
1154c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1155b4422bf3SAneesh Kumar K.V 	struct p9_dev_job *job;
1156b4422bf3SAneesh Kumar K.V 	struct virt_queue *queue;
1157c7838fbdSSasha Levin 	void *p;
1158c7838fbdSSasha Levin 	struct ioevent ioevent;
11591c7850f9SSasha Levin 
1160e59662b3SSasha Levin 	compat__remove_message(p9dev->compat_id);
1161e59662b3SSasha Levin 
1162c7838fbdSSasha Levin 	queue			= &p9dev->vqs[vq];
1163c7838fbdSSasha Levin 	queue->pfn		= pfn;
11641c7850f9SSasha Levin 	p			= guest_pfn_to_host(kvm, queue->pfn);
1165c7838fbdSSasha Levin 	job			= &p9dev->jobs[vq];
11661c7850f9SSasha Levin 
1167c7838fbdSSasha Levin 	vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN);
11681c7850f9SSasha Levin 
1169b4422bf3SAneesh Kumar K.V 	*job			= (struct p9_dev_job) {
1170b4422bf3SAneesh Kumar K.V 		.vq			= queue,
1171b4422bf3SAneesh Kumar K.V 		.p9dev			= p9dev,
1172b4422bf3SAneesh Kumar K.V 	};
1173df0c7f57SSasha Levin 	thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
117460eb42d5SSasha Levin 
117560eb42d5SSasha Levin 	ioevent = (struct ioevent) {
1176c7838fbdSSasha Levin 		.io_addr	= p9dev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
117760eb42d5SSasha Levin 		.io_len		= sizeof(u16),
117860eb42d5SSasha Levin 		.fn		= ioevent_callback,
1179c7838fbdSSasha Levin 		.fn_ptr		= &p9dev->jobs[vq],
1180c7838fbdSSasha Levin 		.datamatch	= vq,
118160eb42d5SSasha Levin 		.fn_kvm		= kvm,
118260eb42d5SSasha Levin 		.fd		= eventfd(0, 0),
118360eb42d5SSasha Levin 	};
118460eb42d5SSasha Levin 
118560eb42d5SSasha Levin 	ioeventfd__add_event(&ioevent);
118660eb42d5SSasha Levin 
1187c7838fbdSSasha Levin 	return 0;
11881c7850f9SSasha Levin }
11891c7850f9SSasha Levin 
1190c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
1191c7838fbdSSasha Levin {
1192c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
11931c7850f9SSasha Levin 
1194c7838fbdSSasha Levin 	thread_pool__do_job(&p9dev->jobs[vq].job_id);
1195c7838fbdSSasha Levin 
1196c7838fbdSSasha Levin 	return 0;
1197c7838fbdSSasha Levin }
1198c7838fbdSSasha Levin 
1199c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
1200c7838fbdSSasha Levin {
1201c7838fbdSSasha Levin 	struct p9_dev *p9dev = dev;
1202c7838fbdSSasha Levin 
1203c7838fbdSSasha Levin 	return p9dev->vqs[vq].pfn;
1204c7838fbdSSasha Levin }
1205c7838fbdSSasha Levin 
1206c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
1207c7838fbdSSasha Levin {
1208c7838fbdSSasha Levin 	return VIRTQUEUE_NUM;
1209c7838fbdSSasha Levin }
1210c7838fbdSSasha Levin 
1211c7838fbdSSasha Levin int virtio_9p__init(struct kvm *kvm)
12121c7850f9SSasha Levin {
1213b4422bf3SAneesh Kumar K.V 	struct p9_dev *p9dev;
1214c7838fbdSSasha Levin 
1215c7838fbdSSasha Levin 	list_for_each_entry(p9dev, &devs, list) {
1216c7838fbdSSasha Levin 		virtio_pci__init(kvm, &p9dev->vpci, p9dev, PCI_DEVICE_ID_VIRTIO_P9, VIRTIO_ID_9P);
1217c7838fbdSSasha Levin 		p9dev->vpci.ops = (struct virtio_pci_ops) {
1218c7838fbdSSasha Levin 			.set_config		= set_config,
1219c7838fbdSSasha Levin 			.get_config		= get_config,
1220c7838fbdSSasha Levin 			.get_host_features	= get_host_features,
1221c7838fbdSSasha Levin 			.set_guest_features	= set_guest_features,
1222c7838fbdSSasha Levin 			.init_vq		= init_vq,
1223c7838fbdSSasha Levin 			.notify_vq		= notify_vq,
1224c7838fbdSSasha Levin 			.get_pfn_vq		= get_pfn_vq,
1225c7838fbdSSasha Levin 			.get_size_vq		= get_size_vq,
1226c7838fbdSSasha Levin 		};
1227c7838fbdSSasha Levin 	}
1228c7838fbdSSasha Levin 
1229c7838fbdSSasha Levin 	return 0;
1230c7838fbdSSasha Levin }
1231c7838fbdSSasha Levin 
1232c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
1233c7838fbdSSasha Levin {
1234c7838fbdSSasha Levin 	struct p9_dev *p9dev;
123554f6802dSPekka Enberg 	u32 i, root_len;
123654f6802dSPekka Enberg 	int err = 0;
12371c7850f9SSasha Levin 
1238b4422bf3SAneesh Kumar K.V 	p9dev = calloc(1, sizeof(*p9dev));
1239b4422bf3SAneesh Kumar K.V 	if (!p9dev)
124054f6802dSPekka Enberg 		return -ENOMEM;
124154f6802dSPekka Enberg 
1242b4422bf3SAneesh Kumar K.V 	if (!tag_name)
1243b4422bf3SAneesh Kumar K.V 		tag_name = VIRTIO_P9_DEFAULT_TAG;
124454f6802dSPekka Enberg 
1245b4422bf3SAneesh Kumar K.V 	p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1);
124654f6802dSPekka Enberg 	if (p9dev->config == NULL) {
124754f6802dSPekka Enberg 		err = -ENOMEM;
1248b4422bf3SAneesh Kumar K.V 		goto free_p9dev;
124954f6802dSPekka Enberg 	}
12501c7850f9SSasha Levin 
1251b4422bf3SAneesh Kumar K.V 	strcpy(p9dev->root_dir, root);
12521c7850f9SSasha Levin 	root_len = strlen(root);
12531c7850f9SSasha Levin 	/*
12541c7850f9SSasha Levin 	 * We prefix the full path in all fids, This allows us to get the
12551c7850f9SSasha Levin 	 * absolute path of an fid without playing with strings.
12561c7850f9SSasha Levin 	 */
12571c7850f9SSasha Levin 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++) {
1258b4422bf3SAneesh Kumar K.V 		strcpy(p9dev->fids[i].abs_path, root);
1259b4422bf3SAneesh Kumar K.V 		p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len;
12601c7850f9SSasha Levin 	}
1261b4422bf3SAneesh Kumar K.V 	p9dev->config->tag_len = strlen(tag_name);
126254f6802dSPekka Enberg 	if (p9dev->config->tag_len > MAX_TAG_LEN) {
126354f6802dSPekka Enberg 		err = -EINVAL;
1264b4422bf3SAneesh Kumar K.V 		goto free_p9dev_config;
126554f6802dSPekka Enberg 	}
12661c7850f9SSasha Levin 
1267c7838fbdSSasha Levin 	memcpy(&p9dev->config->tag, tag_name, strlen(tag_name));
12681c7850f9SSasha Levin 
1269c7838fbdSSasha Levin 	list_add(&p9dev->list, &devs);
1270b4422bf3SAneesh Kumar K.V 
1271e59662b3SSasha Levin 	p9dev->compat_id = compat__add_message("virtio-9p device was not detected",
1272e59662b3SSasha Levin 						"While you have requested a virtio-9p device, "
1273e59662b3SSasha Levin 						"the guest kernel didn't seem to detect it.\n"
1274e59662b3SSasha Levin 						"Please make sure that the kernel was compiled"
1275e59662b3SSasha Levin 						"with CONFIG_NET_9P_VIRTIO.");
1276e59662b3SSasha Levin 
127754f6802dSPekka Enberg 	return err;
127854f6802dSPekka Enberg 
1279b4422bf3SAneesh Kumar K.V free_p9dev_config:
1280b4422bf3SAneesh Kumar K.V 	free(p9dev->config);
1281b4422bf3SAneesh Kumar K.V free_p9dev:
1282b4422bf3SAneesh Kumar K.V 	free(p9dev);
128354f6802dSPekka Enberg 	return err;
12841c7850f9SSasha Levin }
1285