xref: /kvmtool/virtio/9p.c (revision 4d2c017f41533b0e51e00f689050c26190a15318)
1 #include "kvm/virtio-pci-dev.h"
2 #include "kvm/ioport.h"
3 #include "kvm/util.h"
4 #include "kvm/threadpool.h"
5 #include "kvm/irq.h"
6 #include "kvm/virtio-9p.h"
7 #include "kvm/guest_compat.h"
8 #include "kvm/builtin-setup.h"
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <fcntl.h>
13 #include <sys/stat.h>
14 #include <sys/sysmacros.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <sys/vfs.h>
19 
20 #include <linux/virtio_ring.h>
21 #include <linux/virtio_9p.h>
22 #include <linux/9p.h>
23 
24 static LIST_HEAD(devs);
25 static int compat_id = -1;
26 
27 static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid);
find_or_create_fid(struct p9_dev * dev,u32 fid)28 static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid)
29 {
30 	struct rb_node *node = dev->fids.rb_node;
31 	struct p9_fid *pfid = NULL;
32 	size_t len;
33 
34 	while (node) {
35 		struct p9_fid *cur = rb_entry(node, struct p9_fid, node);
36 
37 		if (fid < cur->fid) {
38 			node = node->rb_left;
39 		} else if (fid > cur->fid) {
40 			node = node->rb_right;
41 		} else {
42 			return cur;
43 		}
44 	}
45 
46 	pfid = calloc(sizeof(*pfid), 1);
47 	if (!pfid)
48 		return NULL;
49 
50 	len = strlen(dev->root_dir);
51 	if (len >= sizeof(pfid->abs_path)) {
52 		free(pfid);
53 		return NULL;
54 	}
55 
56 	pfid->fid = fid;
57 	strcpy(pfid->abs_path, dev->root_dir);
58 	pfid->path = pfid->abs_path + strlen(pfid->abs_path);
59 
60 	insert_new_fid(dev, pfid);
61 
62 	return pfid;
63 }
64 
insert_new_fid(struct p9_dev * dev,struct p9_fid * fid)65 static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid)
66 {
67 	struct rb_node **node = &(dev->fids.rb_node), *parent = NULL;
68 
69 	while (*node) {
70 		int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid;
71 
72 		parent = *node;
73 		if (result < 0)
74 			node    = &((*node)->rb_left);
75 		else if (result > 0)
76 			node    = &((*node)->rb_right);
77 		else
78 			return -EEXIST;
79 	}
80 
81 	rb_link_node(&fid->node, parent, node);
82 	rb_insert_color(&fid->node, &dev->fids);
83 	return 0;
84 }
85 
get_fid(struct p9_dev * p9dev,int fid)86 static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
87 {
88 	struct p9_fid *new;
89 
90 	new = find_or_create_fid(p9dev, fid);
91 
92 	return new;
93 }
94 
stat2qid(struct stat * st,struct p9_qid * qid)95 static void stat2qid(struct stat *st, struct p9_qid *qid)
96 {
97 	*qid = (struct p9_qid) {
98 		.path		= st->st_ino,
99 		.version	= st->st_mtime,
100 	};
101 
102 	if (S_ISDIR(st->st_mode))
103 		qid->type	|= P9_QTDIR;
104 }
105 
close_fid(struct p9_dev * p9dev,u32 fid)106 static void close_fid(struct p9_dev *p9dev, u32 fid)
107 {
108 	struct p9_fid *pfid = get_fid(p9dev, fid);
109 
110 	if (pfid->fd > 0)
111 		close(pfid->fd);
112 
113 	if (pfid->dir)
114 		closedir(pfid->dir);
115 
116 	rb_erase(&pfid->node, &p9dev->fids);
117 	free(pfid);
118 }
119 
virtio_p9_set_reply_header(struct p9_pdu * pdu,u32 size)120 static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
121 {
122 	u8 cmd;
123 	u16 tag;
124 
125 	pdu->read_offset = sizeof(u32);
126 	virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
127 	pdu->write_offset = 0;
128 	/* cmd + 1 is the reply message */
129 	virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
130 }
131 
virtio_p9_update_iov_cnt(struct iovec iov[],u32 count,int iov_cnt)132 static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
133 {
134 	int i;
135 	u32 total = 0;
136 	for (i = 0; (i < iov_cnt) && (total < count); i++) {
137 		if (total + iov[i].iov_len > count) {
138 			/* we don't need this iov fully */
139 			iov[i].iov_len -= ((total + iov[i].iov_len) - count);
140 			i++;
141 			break;
142 		}
143 		total += iov[i].iov_len;
144 	}
145 	return i;
146 }
147 
virtio_p9_error_reply(struct p9_dev * p9dev,struct p9_pdu * pdu,int err,u32 * outlen)148 static void virtio_p9_error_reply(struct p9_dev *p9dev,
149 				  struct p9_pdu *pdu, int err, u32 *outlen)
150 {
151 	u16 tag;
152 
153 	/* EMFILE at server implies ENFILE for the VM */
154 	if (err == EMFILE)
155 		err = ENFILE;
156 
157 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
158 	virtio_p9_pdu_writef(pdu, "d", err);
159 	*outlen = pdu->write_offset;
160 
161 	/* read the tag from input */
162 	pdu->read_offset = sizeof(u32) + sizeof(u8);
163 	virtio_p9_pdu_readf(pdu, "w", &tag);
164 
165 	/* Update the header */
166 	pdu->write_offset = 0;
167 	virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
168 }
169 
virtio_p9_version(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)170 static void virtio_p9_version(struct p9_dev *p9dev,
171 			      struct p9_pdu *pdu, u32 *outlen)
172 {
173 	u32 msize;
174 	char *version;
175 	virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
176 	/*
177 	 * reply with the same msize the client sent us
178 	 * Error out if the request is not for 9P2000.L
179 	 */
180 	if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
181 		virtio_p9_pdu_writef(pdu, "ds", msize, version);
182 	else
183 		virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
184 
185 	*outlen = pdu->write_offset;
186 	virtio_p9_set_reply_header(pdu, *outlen);
187 	free(version);
188 	return;
189 }
190 
virtio_p9_clunk(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)191 static void virtio_p9_clunk(struct p9_dev *p9dev,
192 			    struct p9_pdu *pdu, u32 *outlen)
193 {
194 	u32 fid;
195 
196 	virtio_p9_pdu_readf(pdu, "d", &fid);
197 	close_fid(p9dev, fid);
198 
199 	*outlen = pdu->write_offset;
200 	virtio_p9_set_reply_header(pdu, *outlen);
201 	return;
202 }
203 
204 /*
205  * FIXME!! Need to map to protocol independent value. Upstream
206  * 9p also have the same BUG
207  */
virtio_p9_openflags(int flags)208 static int virtio_p9_openflags(int flags)
209 {
210 	flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
211 	flags |= O_NOFOLLOW;
212 	return flags;
213 }
214 
is_dir(struct p9_fid * fid)215 static bool is_dir(struct p9_fid *fid)
216 {
217 	struct stat st;
218 
219 	stat(fid->abs_path, &st);
220 
221 	return S_ISDIR(st.st_mode);
222 }
223 
is_reg(struct p9_fid * fid)224 static bool is_reg(struct p9_fid *fid)
225 {
226 	struct stat st;
227 
228 	stat(fid->abs_path, &st);
229 
230 	return S_ISREG(st.st_mode);
231 }
232 
233 /* path is always absolute */
path_is_illegal(const char * path)234 static bool path_is_illegal(const char *path)
235 {
236 	size_t len;
237 
238 	if (strstr(path, "/../") != NULL)
239 		return true;
240 
241 	len = strlen(path);
242 	if (len >= 3 && strcmp(path + len - 3, "/..") == 0)
243 		return true;
244 
245 	return false;
246 }
247 
get_full_path_helper(char * full_path,size_t size,const char * dirname,const char * name)248 static int get_full_path_helper(char *full_path, size_t size,
249 			 const char *dirname, const char *name)
250 {
251 	int ret;
252 
253 	ret = snprintf(full_path, size, "%s/%s", dirname, name);
254 	if (ret >= (int)size) {
255 		errno = ENAMETOOLONG;
256 		return -1;
257 	}
258 
259 	if (path_is_illegal(full_path)) {
260 		errno = EACCES;
261 		return -1;
262 	}
263 
264 	return 0;
265 }
266 
get_full_path(char * full_path,size_t size,struct p9_fid * fid,const char * name)267 static int get_full_path(char *full_path, size_t size, struct p9_fid *fid,
268 			 const char *name)
269 {
270 	return get_full_path_helper(full_path, size, fid->abs_path, name);
271 }
272 
stat_rel(struct p9_dev * p9dev,const char * path,struct stat * st)273 static int stat_rel(struct p9_dev *p9dev, const char *path, struct stat *st)
274 {
275 	char full_path[PATH_MAX];
276 
277 	if (get_full_path_helper(full_path, sizeof(full_path), p9dev->root_dir, path) != 0)
278 		return -1;
279 
280 	if (lstat(full_path, st) != 0)
281 		return -1;
282 
283 	return 0;
284 }
285 
virtio_p9_open(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)286 static void virtio_p9_open(struct p9_dev *p9dev,
287 			   struct p9_pdu *pdu, u32 *outlen)
288 {
289 	u32 fid, flags;
290 	struct stat st;
291 	struct p9_qid qid;
292 	struct p9_fid *new_fid;
293 
294 
295 	virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
296 	new_fid = get_fid(p9dev, fid);
297 
298 	if (lstat(new_fid->abs_path, &st) < 0)
299 		goto err_out;
300 
301 	stat2qid(&st, &qid);
302 
303 	if (is_dir(new_fid)) {
304 		new_fid->dir = opendir(new_fid->abs_path);
305 		if (!new_fid->dir)
306 			goto err_out;
307 	} else if (is_reg(new_fid)) {
308 		new_fid->fd  = open(new_fid->abs_path,
309 				    virtio_p9_openflags(flags));
310 		if (new_fid->fd < 0)
311 			goto err_out;
312 	} else {
313 		goto err_out;
314 	}
315 	/* FIXME!! need ot send proper iounit  */
316 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
317 
318 	*outlen = pdu->write_offset;
319 	virtio_p9_set_reply_header(pdu, *outlen);
320 	return;
321 err_out:
322 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
323 	return;
324 }
325 
virtio_p9_create(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)326 static void virtio_p9_create(struct p9_dev *p9dev,
327 			     struct p9_pdu *pdu, u32 *outlen)
328 {
329 	int fd, ret;
330 	char *name;
331 	size_t size;
332 	struct stat st;
333 	struct p9_qid qid;
334 	struct p9_fid *dfid;
335 	char full_path[PATH_MAX];
336 	char *tmp_path;
337 	u32 dfid_val, flags, mode, gid;
338 
339 	virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
340 			    &name, &flags, &mode, &gid);
341 	dfid = get_fid(p9dev, dfid_val);
342 
343 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
344 		goto err_out;
345 
346 	size = sizeof(dfid->abs_path) - (dfid->path - dfid->abs_path);
347 
348 	tmp_path = strdup(dfid->path);
349 	if (!tmp_path)
350 		goto err_out;
351 
352 	ret = snprintf(dfid->path, size, "%s/%s", tmp_path, name);
353 	free(tmp_path);
354 	if (ret >= (int)size) {
355 		errno = ENAMETOOLONG;
356 		if (size > 0)
357 			dfid->path[size] = '\x00';
358 		goto err_out;
359 	}
360 
361 	flags = virtio_p9_openflags(flags);
362 
363 	fd = open(full_path, flags | O_CREAT, mode);
364 	if (fd < 0)
365 		goto err_out;
366 	dfid->fd = fd;
367 
368 	if (lstat(full_path, &st) < 0)
369 		goto err_out;
370 
371 	ret = chmod(full_path, mode & 0777);
372 	if (ret < 0)
373 		goto err_out;
374 
375 	stat2qid(&st, &qid);
376 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
377 	*outlen = pdu->write_offset;
378 	virtio_p9_set_reply_header(pdu, *outlen);
379 	free(name);
380 	return;
381 err_out:
382 	free(name);
383 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
384 	return;
385 }
386 
virtio_p9_mkdir(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)387 static void virtio_p9_mkdir(struct p9_dev *p9dev,
388 			    struct p9_pdu *pdu, u32 *outlen)
389 {
390 	int ret;
391 	char *name;
392 	struct stat st;
393 	struct p9_qid qid;
394 	struct p9_fid *dfid;
395 	char full_path[PATH_MAX];
396 	u32 dfid_val, mode, gid;
397 
398 	virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
399 			    &name, &mode, &gid);
400 	dfid = get_fid(p9dev, dfid_val);
401 
402 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
403 		goto err_out;
404 
405 	ret = mkdir(full_path, mode);
406 	if (ret < 0)
407 		goto err_out;
408 
409 	if (lstat(full_path, &st) < 0)
410 		goto err_out;
411 
412 	ret = chmod(full_path, mode & 0777);
413 	if (ret < 0)
414 		goto err_out;
415 
416 	stat2qid(&st, &qid);
417 	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
418 	*outlen = pdu->write_offset;
419 	virtio_p9_set_reply_header(pdu, *outlen);
420 	free(name);
421 	return;
422 err_out:
423 	free(name);
424 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
425 	return;
426 }
427 
join_path(struct p9_fid * fid,const char * name)428 static int join_path(struct p9_fid *fid, const char *name)
429 {
430 	size_t len, size;
431 
432 	size = sizeof(fid->abs_path) - (fid->path - fid->abs_path);
433 	len = strlen(name);
434 	if (len >= size)
435 		return -1;
436 
437 	strncpy(fid->path, name, size);
438 	return 0;
439 }
440 
virtio_p9_walk(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)441 static void virtio_p9_walk(struct p9_dev *p9dev,
442 			   struct p9_pdu *pdu, u32 *outlen)
443 {
444 	u8 i;
445 	u16 nwqid;
446 	u16 nwname;
447 	struct p9_qid wqid;
448 	struct p9_fid *new_fid, *old_fid;
449 	u32 fid_val, newfid_val;
450 
451 
452 	virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
453 	new_fid	= get_fid(p9dev, newfid_val);
454 
455 	nwqid = 0;
456 	if (nwname) {
457 		struct p9_fid *fid = get_fid(p9dev, fid_val);
458 
459 		if (join_path(new_fid, fid->path) != 0) {
460 			errno = ENAMETOOLONG;
461 			goto err_out;
462 		}
463 
464 		/* skip the space for count */
465 		pdu->write_offset += sizeof(u16);
466 		for (i = 0; i < nwname; i++) {
467 			struct stat st;
468 			char tmp[PATH_MAX] = {0};
469 			char *str;
470 			int ret;
471 
472 			virtio_p9_pdu_readf(pdu, "s", &str);
473 
474 			/* Format the new path we're 'walk'ing into */
475 			ret = snprintf(tmp, sizeof(tmp), "%s/%s", new_fid->path, str);
476 			if (ret >= (int)sizeof(tmp)) {
477 				errno = ENAMETOOLONG;
478 				goto err_out;
479 			}
480 
481 			free(str);
482 
483 			if (stat_rel(p9dev, tmp, &st) != 0)
484 				goto err_out;
485 
486 			stat2qid(&st, &wqid);
487 			if (join_path(new_fid, tmp) != 0) {
488 				errno = ENAMETOOLONG;
489 				goto err_out;
490 			}
491 			new_fid->uid = fid->uid;
492 			nwqid++;
493 			virtio_p9_pdu_writef(pdu, "Q", &wqid);
494 		}
495 	} else {
496 		/*
497 		 * update write_offset so our outlen get correct value
498 		 */
499 		pdu->write_offset += sizeof(u16);
500 		old_fid = get_fid(p9dev, fid_val);
501 		if (join_path(new_fid, old_fid->path) != 0) {
502 			errno = ENAMETOOLONG;
503 			goto err_out;
504 		}
505 		new_fid->uid    = old_fid->uid;
506 	}
507 	*outlen = pdu->write_offset;
508 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
509 	virtio_p9_pdu_writef(pdu, "d", nwqid);
510 	virtio_p9_set_reply_header(pdu, *outlen);
511 	return;
512 err_out:
513 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
514 	return;
515 }
516 
virtio_p9_attach(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)517 static void virtio_p9_attach(struct p9_dev *p9dev,
518 			     struct p9_pdu *pdu, u32 *outlen)
519 {
520 	char *uname;
521 	char *aname;
522 	struct stat st;
523 	struct p9_qid qid;
524 	struct p9_fid *fid;
525 	u32 fid_val, afid, uid;
526 
527 	virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
528 			    &uname, &aname, &uid);
529 
530 	free(uname);
531 	free(aname);
532 
533 	if (lstat(p9dev->root_dir, &st) < 0)
534 		goto err_out;
535 
536 	stat2qid(&st, &qid);
537 
538 	fid = get_fid(p9dev, fid_val);
539 	fid->uid = uid;
540 	if (join_path(fid, "/") != 0) {
541 		errno = ENAMETOOLONG;
542 		goto err_out;
543 	}
544 
545 	virtio_p9_pdu_writef(pdu, "Q", &qid);
546 	*outlen = pdu->write_offset;
547 	virtio_p9_set_reply_header(pdu, *outlen);
548 	return;
549 err_out:
550 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
551 	return;
552 }
553 
virtio_p9_fill_stat(struct p9_dev * p9dev,struct stat * st,struct p9_stat_dotl * statl)554 static void virtio_p9_fill_stat(struct p9_dev *p9dev,
555 				struct stat *st, struct p9_stat_dotl *statl)
556 {
557 	memset(statl, 0, sizeof(*statl));
558 	statl->st_mode		= st->st_mode;
559 	statl->st_nlink		= st->st_nlink;
560 	statl->st_uid		= KUIDT_INIT(st->st_uid);
561 	statl->st_gid		= KGIDT_INIT(st->st_gid);
562 	statl->st_rdev		= st->st_rdev;
563 	statl->st_size		= st->st_size;
564 	statl->st_blksize	= st->st_blksize;
565 	statl->st_blocks	= st->st_blocks;
566 	statl->st_atime_sec	= st->st_atime;
567 	statl->st_atime_nsec	= st->st_atim.tv_nsec;
568 	statl->st_mtime_sec	= st->st_mtime;
569 	statl->st_mtime_nsec	= st->st_mtim.tv_nsec;
570 	statl->st_ctime_sec	= st->st_ctime;
571 	statl->st_ctime_nsec	= st->st_ctim.tv_nsec;
572 	/* Currently we only support BASIC fields in stat */
573 	statl->st_result_mask	= P9_STATS_BASIC;
574 	stat2qid(st, &statl->qid);
575 }
576 
virtio_p9_read(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)577 static void virtio_p9_read(struct p9_dev *p9dev,
578 			   struct p9_pdu *pdu, u32 *outlen)
579 {
580 	u64 offset;
581 	u32 fid_val;
582 	u16 iov_cnt;
583 	void *iov_base;
584 	size_t iov_len;
585 	u32 count, rcount;
586 	struct p9_fid *fid;
587 
588 
589 	rcount = 0;
590 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
591 	fid = get_fid(p9dev, fid_val);
592 
593 	iov_base = pdu->in_iov[0].iov_base;
594 	iov_len  = pdu->in_iov[0].iov_len;
595 	iov_cnt  = pdu->in_iov_cnt;
596 	pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
597 	pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
598 	pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
599 						   count,
600 						   pdu->in_iov_cnt);
601 	rcount = preadv(fid->fd, pdu->in_iov,
602 			pdu->in_iov_cnt, offset);
603 	if (rcount > count)
604 		rcount = count;
605 	/*
606 	 * Update the iov_base back, so that rest of
607 	 * pdu_writef works correctly.
608 	 */
609 	pdu->in_iov[0].iov_base = iov_base;
610 	pdu->in_iov[0].iov_len  = iov_len;
611 	pdu->in_iov_cnt         = iov_cnt;
612 
613 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
614 	virtio_p9_pdu_writef(pdu, "d", rcount);
615 	*outlen = pdu->write_offset + rcount;
616 	virtio_p9_set_reply_header(pdu, *outlen);
617 	return;
618 }
619 
virtio_p9_dentry_size(struct dirent * dent)620 static int virtio_p9_dentry_size(struct dirent *dent)
621 {
622 	/*
623 	 * Size of each dirent:
624 	 * qid(13) + offset(8) + type(1) + name_len(2) + name
625 	 */
626 	return 24 + strlen(dent->d_name);
627 }
628 
virtio_p9_readdir(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)629 static void virtio_p9_readdir(struct p9_dev *p9dev,
630 			      struct p9_pdu *pdu, u32 *outlen)
631 {
632 	u32 fid_val;
633 	u32 count, rcount;
634 	struct stat st;
635 	struct p9_fid *fid;
636 	struct dirent *dent;
637 	u64 offset, old_offset;
638 
639 	rcount = 0;
640 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
641 	fid = get_fid(p9dev, fid_val);
642 
643 	if (!is_dir(fid)) {
644 		errno = EINVAL;
645 		goto err_out;
646 	}
647 
648 	/* Move the offset specified */
649 	seekdir(fid->dir, offset);
650 
651 	old_offset = offset;
652 	/* If reading a dir, fill the buffer with p9_stat entries */
653 	dent = readdir(fid->dir);
654 
655 	/* Skip the space for writing count */
656 	pdu->write_offset += sizeof(u32);
657 	while (dent) {
658 		u32 read;
659 		struct p9_qid qid;
660 
661 		if ((rcount + virtio_p9_dentry_size(dent)) > count) {
662 			/* seek to the previous offset and return */
663 			seekdir(fid->dir, old_offset);
664 			break;
665 		}
666 		old_offset = dent->d_off;
667 		if (stat_rel(p9dev, dent->d_name, &st) != 0)
668 			memset(&st, -1, sizeof(st));
669 		stat2qid(&st, &qid);
670 		read = pdu->write_offset;
671 		virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
672 				     dent->d_type, dent->d_name);
673 		rcount += pdu->write_offset - read;
674 		dent = readdir(fid->dir);
675 	}
676 
677 	pdu->write_offset = VIRTIO_9P_HDR_LEN;
678 	virtio_p9_pdu_writef(pdu, "d", rcount);
679 	*outlen = pdu->write_offset + rcount;
680 	virtio_p9_set_reply_header(pdu, *outlen);
681 	return;
682 err_out:
683 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
684 	return;
685 }
686 
687 
virtio_p9_getattr(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)688 static void virtio_p9_getattr(struct p9_dev *p9dev,
689 			      struct p9_pdu *pdu, u32 *outlen)
690 {
691 	u32 fid_val;
692 	struct stat st;
693 	u64 request_mask;
694 	struct p9_fid *fid;
695 	struct p9_stat_dotl statl;
696 
697 	virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
698 	fid = get_fid(p9dev, fid_val);
699 	if (lstat(fid->abs_path, &st) < 0)
700 		goto err_out;
701 
702 	virtio_p9_fill_stat(p9dev, &st, &statl);
703 	virtio_p9_pdu_writef(pdu, "A", &statl);
704 	*outlen = pdu->write_offset;
705 	virtio_p9_set_reply_header(pdu, *outlen);
706 	return;
707 err_out:
708 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
709 	return;
710 }
711 
712 /* FIXME!! from linux/fs.h */
713 /*
714  * Attribute flags.  These should be or-ed together to figure out what
715  * has been changed!
716  */
717 #define ATTR_MODE	(1 << 0)
718 #define ATTR_UID	(1 << 1)
719 #define ATTR_GID	(1 << 2)
720 #define ATTR_SIZE	(1 << 3)
721 #define ATTR_ATIME	(1 << 4)
722 #define ATTR_MTIME	(1 << 5)
723 #define ATTR_CTIME	(1 << 6)
724 #define ATTR_ATIME_SET	(1 << 7)
725 #define ATTR_MTIME_SET	(1 << 8)
726 #define ATTR_FORCE	(1 << 9) /* Not a change, but a change it */
727 #define ATTR_ATTR_FLAG	(1 << 10)
728 #define ATTR_KILL_SUID	(1 << 11)
729 #define ATTR_KILL_SGID	(1 << 12)
730 #define ATTR_FILE	(1 << 13)
731 #define ATTR_KILL_PRIV	(1 << 14)
732 #define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
733 #define ATTR_TIMES_SET	(1 << 16)
734 
735 #define ATTR_MASK    127
736 
virtio_p9_setattr(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)737 static void virtio_p9_setattr(struct p9_dev *p9dev,
738 			      struct p9_pdu *pdu, u32 *outlen)
739 {
740 	int ret = 0;
741 	u32 fid_val;
742 	struct p9_fid *fid;
743 	struct p9_iattr_dotl p9attr;
744 
745 	virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
746 	fid = get_fid(p9dev, fid_val);
747 
748 	if (p9attr.valid & ATTR_MODE) {
749 		ret = chmod(fid->abs_path, p9attr.mode);
750 		if (ret < 0)
751 			goto err_out;
752 	}
753 	if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
754 		struct timespec times[2];
755 		if (p9attr.valid & ATTR_ATIME) {
756 			if (p9attr.valid & ATTR_ATIME_SET) {
757 				times[0].tv_sec = p9attr.atime_sec;
758 				times[0].tv_nsec = p9attr.atime_nsec;
759 			} else {
760 				times[0].tv_nsec = UTIME_NOW;
761 			}
762 		} else {
763 			times[0].tv_nsec = UTIME_OMIT;
764 		}
765 		if (p9attr.valid & ATTR_MTIME) {
766 			if (p9attr.valid & ATTR_MTIME_SET) {
767 				times[1].tv_sec = p9attr.mtime_sec;
768 				times[1].tv_nsec = p9attr.mtime_nsec;
769 			} else {
770 				times[1].tv_nsec = UTIME_NOW;
771 			}
772 		} else
773 			times[1].tv_nsec = UTIME_OMIT;
774 
775 		ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
776 		if (ret < 0)
777 			goto err_out;
778 	}
779 	/*
780 	 * If the only valid entry in iattr is ctime we can call
781 	 * chown(-1,-1) to update the ctime of the file
782 	 */
783 	if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
784 	    ((p9attr.valid & ATTR_CTIME)
785 	     && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
786 		if (!(p9attr.valid & ATTR_UID))
787 			p9attr.uid = KUIDT_INIT(-1);
788 
789 		if (!(p9attr.valid & ATTR_GID))
790 			p9attr.gid = KGIDT_INIT(-1);
791 
792 		ret = lchown(fid->abs_path, __kuid_val(p9attr.uid),
793 				__kgid_val(p9attr.gid));
794 		if (ret < 0)
795 			goto err_out;
796 	}
797 	if (p9attr.valid & (ATTR_SIZE)) {
798 		ret = truncate(fid->abs_path, p9attr.size);
799 		if (ret < 0)
800 			goto err_out;
801 	}
802 	*outlen = VIRTIO_9P_HDR_LEN;
803 	virtio_p9_set_reply_header(pdu, *outlen);
804 	return;
805 err_out:
806 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
807 	return;
808 }
809 
virtio_p9_write(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)810 static void virtio_p9_write(struct p9_dev *p9dev,
811 			    struct p9_pdu *pdu, u32 *outlen)
812 {
813 
814 	u64 offset;
815 	u32 fid_val;
816 	u32 count;
817 	ssize_t res;
818 	u16 iov_cnt;
819 	void *iov_base;
820 	size_t iov_len;
821 	struct p9_fid *fid;
822 	/* u32 fid + u64 offset + u32 count */
823 	int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
824 
825 	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
826 	fid = get_fid(p9dev, fid_val);
827 
828 	iov_base = pdu->out_iov[0].iov_base;
829 	iov_len  = pdu->out_iov[0].iov_len;
830 	iov_cnt  = pdu->out_iov_cnt;
831 
832 	/* Adjust the iovec to skip the header and meta data */
833 	pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
834 	pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
835 	pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
836 						    pdu->out_iov_cnt);
837 	res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
838 	/*
839 	 * Update the iov_base back, so that rest of
840 	 * pdu_readf works correctly.
841 	 */
842 	pdu->out_iov[0].iov_base = iov_base;
843 	pdu->out_iov[0].iov_len  = iov_len;
844 	pdu->out_iov_cnt         = iov_cnt;
845 
846 	if (res < 0)
847 		goto err_out;
848 	virtio_p9_pdu_writef(pdu, "d", res);
849 	*outlen = pdu->write_offset;
850 	virtio_p9_set_reply_header(pdu, *outlen);
851 	return;
852 err_out:
853 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
854 	return;
855 }
856 
virtio_p9_remove(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)857 static void virtio_p9_remove(struct p9_dev *p9dev,
858 			     struct p9_pdu *pdu, u32 *outlen)
859 {
860 	int ret;
861 	u32 fid_val;
862 	struct p9_fid *fid;
863 
864 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
865 	fid = get_fid(p9dev, fid_val);
866 
867 	ret = remove(fid->abs_path);
868 	if (ret < 0)
869 		goto err_out;
870 	*outlen = pdu->write_offset;
871 	virtio_p9_set_reply_header(pdu, *outlen);
872 	return;
873 
874 err_out:
875 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
876 	return;
877 }
878 
virtio_p9_rename(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)879 static void virtio_p9_rename(struct p9_dev *p9dev,
880 			     struct p9_pdu *pdu, u32 *outlen)
881 {
882 	int ret;
883 	u32 fid_val, new_fid_val;
884 	struct p9_fid *fid, *new_fid;
885 	char full_path[PATH_MAX], *new_name;
886 
887 	virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
888 	fid = get_fid(p9dev, fid_val);
889 	new_fid = get_fid(p9dev, new_fid_val);
890 
891 	if (get_full_path(full_path, sizeof(full_path), new_fid, new_name) != 0)
892 		goto err_out;
893 
894 	ret = rename(fid->abs_path, full_path);
895 	if (ret < 0)
896 		goto err_out;
897 	*outlen = pdu->write_offset;
898 	virtio_p9_set_reply_header(pdu, *outlen);
899 	return;
900 
901 err_out:
902 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
903 	return;
904 }
905 
virtio_p9_readlink(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)906 static void virtio_p9_readlink(struct p9_dev *p9dev,
907 			       struct p9_pdu *pdu, u32 *outlen)
908 {
909 	int ret;
910 	u32 fid_val;
911 	struct p9_fid *fid;
912 	char target_path[PATH_MAX];
913 
914 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
915 	fid = get_fid(p9dev, fid_val);
916 
917 	memset(target_path, 0, PATH_MAX);
918 	ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
919 	if (ret < 0)
920 		goto err_out;
921 
922 	virtio_p9_pdu_writef(pdu, "s", target_path);
923 	*outlen = pdu->write_offset;
924 	virtio_p9_set_reply_header(pdu, *outlen);
925 	return;
926 err_out:
927 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
928 	return;
929 }
930 
virtio_p9_statfs(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)931 static void virtio_p9_statfs(struct p9_dev *p9dev,
932 			     struct p9_pdu *pdu, u32 *outlen)
933 {
934 	int ret;
935 	u64 fsid;
936 	u32 fid_val;
937 	struct p9_fid *fid;
938 	struct statfs stat_buf;
939 
940 	virtio_p9_pdu_readf(pdu, "d", &fid_val);
941 	fid = get_fid(p9dev, fid_val);
942 
943 	ret = statfs(fid->abs_path, &stat_buf);
944 	if (ret < 0)
945 		goto err_out;
946 	/* FIXME!! f_blocks needs update based on client msize */
947 	fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
948 		(unsigned long long)stat_buf.f_fsid.__val[1] << 32;
949 	virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
950 			     stat_buf.f_bsize, stat_buf.f_blocks,
951 			     stat_buf.f_bfree, stat_buf.f_bavail,
952 			     stat_buf.f_files, stat_buf.f_ffree,
953 			     fsid, stat_buf.f_namelen);
954 	*outlen = pdu->write_offset;
955 	virtio_p9_set_reply_header(pdu, *outlen);
956 	return;
957 err_out:
958 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
959 	return;
960 }
961 
virtio_p9_mknod(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)962 static void virtio_p9_mknod(struct p9_dev *p9dev,
963 			    struct p9_pdu *pdu, u32 *outlen)
964 {
965 	int ret;
966 	char *name;
967 	struct stat st;
968 	struct p9_fid *dfid;
969 	struct p9_qid qid;
970 	char full_path[PATH_MAX];
971 	u32 fid_val, mode, major, minor, gid;
972 
973 	virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
974 			    &major, &minor, &gid);
975 
976 	dfid = get_fid(p9dev, fid_val);
977 
978 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
979 		goto err_out;
980 
981 	ret = mknod(full_path, mode, makedev(major, minor));
982 	if (ret < 0)
983 		goto err_out;
984 
985 	if (lstat(full_path, &st) < 0)
986 		goto err_out;
987 
988 	ret = chmod(full_path, mode & 0777);
989 	if (ret < 0)
990 		goto err_out;
991 
992 	stat2qid(&st, &qid);
993 	virtio_p9_pdu_writef(pdu, "Q", &qid);
994 	free(name);
995 	*outlen = pdu->write_offset;
996 	virtio_p9_set_reply_header(pdu, *outlen);
997 	return;
998 err_out:
999 	free(name);
1000 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1001 	return;
1002 }
1003 
virtio_p9_fsync(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1004 static void virtio_p9_fsync(struct p9_dev *p9dev,
1005 			    struct p9_pdu *pdu, u32 *outlen)
1006 {
1007 	int ret, fd;
1008 	struct p9_fid *fid;
1009 	u32 fid_val, datasync;
1010 
1011 	virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
1012 	fid = get_fid(p9dev, fid_val);
1013 
1014 	if (fid->dir)
1015 		fd = dirfd(fid->dir);
1016 	else
1017 		fd = fid->fd;
1018 
1019 	if (datasync)
1020 		ret = fdatasync(fd);
1021 	else
1022 		ret = fsync(fd);
1023 	if (ret < 0)
1024 		goto err_out;
1025 	*outlen = pdu->write_offset;
1026 	virtio_p9_set_reply_header(pdu, *outlen);
1027 	return;
1028 err_out:
1029 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1030 	return;
1031 }
1032 
virtio_p9_symlink(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1033 static void virtio_p9_symlink(struct p9_dev *p9dev,
1034 			      struct p9_pdu *pdu, u32 *outlen)
1035 {
1036 	int ret;
1037 	struct stat st;
1038 	u32 fid_val, gid;
1039 	struct p9_qid qid;
1040 	struct p9_fid *dfid;
1041 	char new_name[PATH_MAX];
1042 	char *old_path, *name;
1043 
1044 	virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
1045 
1046 	dfid = get_fid(p9dev, fid_val);
1047 
1048 	if (get_full_path(new_name, sizeof(new_name), dfid, name) != 0)
1049 		goto err_out;
1050 
1051 	ret = symlink(old_path, new_name);
1052 	if (ret < 0)
1053 		goto err_out;
1054 
1055 	if (lstat(new_name, &st) < 0)
1056 		goto err_out;
1057 
1058 	stat2qid(&st, &qid);
1059 	virtio_p9_pdu_writef(pdu, "Q", &qid);
1060 	free(name);
1061 	free(old_path);
1062 	*outlen = pdu->write_offset;
1063 	virtio_p9_set_reply_header(pdu, *outlen);
1064 	return;
1065 err_out:
1066 	free(name);
1067 	free(old_path);
1068 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1069 	return;
1070 }
1071 
virtio_p9_link(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1072 static void virtio_p9_link(struct p9_dev *p9dev,
1073 			   struct p9_pdu *pdu, u32 *outlen)
1074 {
1075 	int ret;
1076 	char *name;
1077 	u32 fid_val, dfid_val;
1078 	struct p9_fid *dfid, *fid;
1079 	char full_path[PATH_MAX];
1080 
1081 	virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
1082 
1083 	dfid = get_fid(p9dev, dfid_val);
1084 	fid =  get_fid(p9dev, fid_val);
1085 
1086 	if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
1087 		goto err_out;
1088 
1089 	ret = link(fid->abs_path, full_path);
1090 	if (ret < 0)
1091 		goto err_out;
1092 	free(name);
1093 	*outlen = pdu->write_offset;
1094 	virtio_p9_set_reply_header(pdu, *outlen);
1095 	return;
1096 err_out:
1097 	free(name);
1098 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1099 	return;
1100 
1101 }
1102 
virtio_p9_lock(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1103 static void virtio_p9_lock(struct p9_dev *p9dev,
1104 			   struct p9_pdu *pdu, u32 *outlen)
1105 {
1106 	u8 ret;
1107 	u32 fid_val;
1108 	struct p9_flock flock;
1109 
1110 	virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
1111 			    &flock.flags, &flock.start, &flock.length,
1112 			    &flock.proc_id, &flock.client_id);
1113 
1114 	/* Just return success */
1115 	ret = P9_LOCK_SUCCESS;
1116 	virtio_p9_pdu_writef(pdu, "d", ret);
1117 	*outlen = pdu->write_offset;
1118 	virtio_p9_set_reply_header(pdu, *outlen);
1119 	free(flock.client_id);
1120 	return;
1121 }
1122 
virtio_p9_getlock(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1123 static void virtio_p9_getlock(struct p9_dev *p9dev,
1124 			      struct p9_pdu *pdu, u32 *outlen)
1125 {
1126 	u32 fid_val;
1127 	struct p9_getlock glock;
1128 	virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
1129 			    &glock.start, &glock.length, &glock.proc_id,
1130 			    &glock.client_id);
1131 
1132 	/* Just return success */
1133 	glock.type = F_UNLCK;
1134 	virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
1135 			     glock.start, glock.length, glock.proc_id,
1136 			     glock.client_id);
1137 	*outlen = pdu->write_offset;
1138 	virtio_p9_set_reply_header(pdu, *outlen);
1139 	free(glock.client_id);
1140 	return;
1141 }
1142 
virtio_p9_ancestor(char * path,char * ancestor)1143 static int virtio_p9_ancestor(char *path, char *ancestor)
1144 {
1145 	int size = strlen(ancestor);
1146 	if (!strncmp(path, ancestor, size)) {
1147 		/*
1148 		 * Now check whether ancestor is a full name or
1149 		 * or directory component and not just part
1150 		 * of a name.
1151 		 */
1152 		if (path[size] == '\0' || path[size] == '/')
1153 			return 1;
1154 	}
1155 	return 0;
1156 }
1157 
virtio_p9_fix_path(struct p9_fid * fid,char * old_name,char * new_name)1158 static int virtio_p9_fix_path(struct p9_fid *fid, char *old_name, char *new_name)
1159 {
1160 	int ret;
1161 	char *p, tmp_name[PATH_MAX];
1162 	size_t rp_sz = strlen(old_name);
1163 
1164 	if (rp_sz == strlen(fid->path)) {
1165 		/* replace the full name */
1166 		p = new_name;
1167 	} else {
1168 		/* save the trailing path details */
1169 		ret = snprintf(tmp_name, sizeof(tmp_name), "%s%s", new_name, fid->path + rp_sz);
1170 		if (ret >= (int)sizeof(tmp_name))
1171 			return -1;
1172 		p = tmp_name;
1173 	}
1174 
1175 	return join_path(fid, p);
1176 }
1177 
rename_fids(struct p9_dev * p9dev,char * old_name,char * new_name)1178 static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name)
1179 {
1180 	struct rb_node *node = rb_first(&p9dev->fids);
1181 
1182 	while (node) {
1183 		struct p9_fid *fid = rb_entry(node, struct p9_fid, node);
1184 
1185 		if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) {
1186 				virtio_p9_fix_path(fid, old_name, new_name);
1187 		}
1188 		node = rb_next(node);
1189 	}
1190 }
1191 
virtio_p9_renameat(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1192 static void virtio_p9_renameat(struct p9_dev *p9dev,
1193 			       struct p9_pdu *pdu, u32 *outlen)
1194 {
1195 	int ret;
1196 	char *old_name, *new_name;
1197 	u32 old_dfid_val, new_dfid_val;
1198 	struct p9_fid *old_dfid, *new_dfid;
1199 	char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
1200 
1201 
1202 	virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
1203 			    &new_dfid_val, &new_name);
1204 
1205 	old_dfid = get_fid(p9dev, old_dfid_val);
1206 	new_dfid = get_fid(p9dev, new_dfid_val);
1207 
1208 	if (get_full_path(old_full_path, sizeof(old_full_path), old_dfid, old_name) != 0)
1209 		goto err_out;
1210 
1211 	if (get_full_path(new_full_path, sizeof(new_full_path), new_dfid, new_name) != 0)
1212 		goto err_out;
1213 
1214 	ret = rename(old_full_path, new_full_path);
1215 	if (ret < 0)
1216 		goto err_out;
1217 	/*
1218 	 * Now fix path in other fids, if the renamed path is part of
1219 	 * that.
1220 	 */
1221 	rename_fids(p9dev, old_name, new_name);
1222 	free(old_name);
1223 	free(new_name);
1224 	*outlen = pdu->write_offset;
1225 	virtio_p9_set_reply_header(pdu, *outlen);
1226 	return;
1227 err_out:
1228 	free(old_name);
1229 	free(new_name);
1230 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1231 	return;
1232 }
1233 
virtio_p9_unlinkat(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1234 static void virtio_p9_unlinkat(struct p9_dev *p9dev,
1235 			       struct p9_pdu *pdu, u32 *outlen)
1236 {
1237 	int ret;
1238 	char *name;
1239 	u32 fid_val, flags;
1240 	struct p9_fid *fid;
1241 	char full_path[PATH_MAX];
1242 
1243 	virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
1244 	fid = get_fid(p9dev, fid_val);
1245 
1246 	if (get_full_path(full_path, sizeof(full_path), fid, name) != 0)
1247 		goto err_out;
1248 
1249 	ret = remove(full_path);
1250 	if (ret < 0)
1251 		goto err_out;
1252 	free(name);
1253 	*outlen = pdu->write_offset;
1254 	virtio_p9_set_reply_header(pdu, *outlen);
1255 	return;
1256 err_out:
1257 	free(name);
1258 	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1259 	return;
1260 }
1261 
virtio_p9_flush(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1262 static void virtio_p9_flush(struct p9_dev *p9dev,
1263 				struct p9_pdu *pdu, u32 *outlen)
1264 {
1265 	u16 tag, oldtag;
1266 
1267 	virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag);
1268 	virtio_p9_pdu_writef(pdu, "w", tag);
1269 	*outlen = pdu->write_offset;
1270 	virtio_p9_set_reply_header(pdu, *outlen);
1271 
1272 	return;
1273 }
1274 
virtio_p9_eopnotsupp(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1275 static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
1276 				 struct p9_pdu *pdu, u32 *outlen)
1277 {
1278 	return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
1279 }
1280 
1281 typedef void p9_handler(struct p9_dev *p9dev,
1282 			struct p9_pdu *pdu, u32 *outlen);
1283 
1284 /* FIXME should be removed when merging with latest linus tree */
1285 #define P9_TRENAMEAT 74
1286 #define P9_TUNLINKAT 76
1287 
1288 static p9_handler *virtio_9p_dotl_handler [] = {
1289 	[P9_TREADDIR]     = virtio_p9_readdir,
1290 	[P9_TSTATFS]      = virtio_p9_statfs,
1291 	[P9_TGETATTR]     = virtio_p9_getattr,
1292 	[P9_TSETATTR]     = virtio_p9_setattr,
1293 	[P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
1294 	[P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
1295 	[P9_TMKNOD]       = virtio_p9_mknod,
1296 	[P9_TLOCK]        = virtio_p9_lock,
1297 	[P9_TGETLOCK]     = virtio_p9_getlock,
1298 	[P9_TRENAMEAT]    = virtio_p9_renameat,
1299 	[P9_TREADLINK]    = virtio_p9_readlink,
1300 	[P9_TUNLINKAT]    = virtio_p9_unlinkat,
1301 	[P9_TMKDIR]       = virtio_p9_mkdir,
1302 	[P9_TVERSION]     = virtio_p9_version,
1303 	[P9_TLOPEN]       = virtio_p9_open,
1304 	[P9_TATTACH]      = virtio_p9_attach,
1305 	[P9_TWALK]        = virtio_p9_walk,
1306 	[P9_TCLUNK]       = virtio_p9_clunk,
1307 	[P9_TFSYNC]       = virtio_p9_fsync,
1308 	[P9_TREAD]        = virtio_p9_read,
1309 	[P9_TFLUSH]       = virtio_p9_flush,
1310 	[P9_TLINK]        = virtio_p9_link,
1311 	[P9_TSYMLINK]     = virtio_p9_symlink,
1312 	[P9_TLCREATE]     = virtio_p9_create,
1313 	[P9_TWRITE]       = virtio_p9_write,
1314 	[P9_TREMOVE]      = virtio_p9_remove,
1315 	[P9_TRENAME]      = virtio_p9_rename,
1316 };
1317 
virtio_p9_pdu_init(struct kvm * kvm,struct virt_queue * vq)1318 static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
1319 {
1320 	struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
1321 	if (!pdu)
1322 		return NULL;
1323 
1324 	/* skip the pdu header p9_msg */
1325 	pdu->read_offset	= VIRTIO_9P_HDR_LEN;
1326 	pdu->write_offset	= VIRTIO_9P_HDR_LEN;
1327 	pdu->queue_head		= virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
1328 					pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
1329 	return pdu;
1330 }
1331 
virtio_p9_get_cmd(struct p9_pdu * pdu)1332 static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
1333 {
1334 	struct p9_msg *msg;
1335 	/*
1336 	 * we can peek directly into pdu for a u8
1337 	 * value. The host endianess won't be an issue
1338 	 */
1339 	msg = pdu->out_iov[0].iov_base;
1340 	return msg->cmd;
1341 }
1342 
virtio_p9_do_io_request(struct kvm * kvm,struct p9_dev_job * job)1343 static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
1344 {
1345 	u8 cmd;
1346 	u32 len = 0;
1347 	p9_handler *handler;
1348 	struct p9_dev *p9dev;
1349 	struct virt_queue *vq;
1350 	struct p9_pdu *p9pdu;
1351 
1352 	vq = job->vq;
1353 	p9dev = job->p9dev;
1354 
1355 	p9pdu = virtio_p9_pdu_init(kvm, vq);
1356 	cmd = virtio_p9_get_cmd(p9pdu);
1357 
1358 	if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
1359 	    !virtio_9p_dotl_handler[cmd])
1360 		handler = virtio_p9_eopnotsupp;
1361 	else
1362 		handler = virtio_9p_dotl_handler[cmd];
1363 
1364 	handler(p9dev, p9pdu, &len);
1365 	virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
1366 	free(p9pdu);
1367 	return true;
1368 }
1369 
virtio_p9_do_io(struct kvm * kvm,void * param)1370 static void virtio_p9_do_io(struct kvm *kvm, void *param)
1371 {
1372 	struct p9_dev_job *job = (struct p9_dev_job *)param;
1373 	struct p9_dev *p9dev   = job->p9dev;
1374 	struct virt_queue *vq  = job->vq;
1375 
1376 	while (virt_queue__available(vq)) {
1377 		virtio_p9_do_io_request(kvm, job);
1378 		p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
1379 	}
1380 }
1381 
get_config(struct kvm * kvm,void * dev)1382 static u8 *get_config(struct kvm *kvm, void *dev)
1383 {
1384 	struct p9_dev *p9dev = dev;
1385 
1386 	return ((u8 *)(p9dev->config));
1387 }
1388 
get_config_size(struct kvm * kvm,void * dev)1389 static size_t get_config_size(struct kvm *kvm, void *dev)
1390 {
1391 	struct p9_dev *p9dev = dev;
1392 
1393 	return p9dev->config_size;
1394 }
1395 
get_host_features(struct kvm * kvm,void * dev)1396 static u64 get_host_features(struct kvm *kvm, void *dev)
1397 {
1398 	return 1 << VIRTIO_9P_MOUNT_TAG;
1399 }
1400 
notify_status(struct kvm * kvm,void * dev,u32 status)1401 static void notify_status(struct kvm *kvm, void *dev, u32 status)
1402 {
1403 	struct p9_dev *p9dev = dev;
1404 	struct p9_fid *pfid, *next;
1405 
1406 	if (status & VIRTIO__STATUS_CONFIG)
1407 		p9dev->config->tag_len = virtio_host_to_guest_u16(p9dev->vdev.endian,
1408 								  p9dev->tag_len);
1409 
1410 	if (!(status & VIRTIO__STATUS_STOP))
1411 		return;
1412 
1413 	rbtree_postorder_for_each_entry_safe(pfid, next, &p9dev->fids, node)
1414 		close_fid(p9dev, pfid->fid);
1415 }
1416 
init_vq(struct kvm * kvm,void * dev,u32 vq)1417 static int init_vq(struct kvm *kvm, void *dev, u32 vq)
1418 {
1419 	struct p9_dev *p9dev = dev;
1420 	struct p9_dev_job *job;
1421 	struct virt_queue *queue;
1422 
1423 	compat__remove_message(compat_id);
1424 
1425 	queue		= &p9dev->vqs[vq];
1426 	job		= &p9dev->jobs[vq];
1427 
1428 	virtio_init_device_vq(kvm, &p9dev->vdev, queue, VIRTQUEUE_NUM);
1429 
1430 	*job		= (struct p9_dev_job) {
1431 		.vq		= queue,
1432 		.p9dev		= p9dev,
1433 	};
1434 	thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
1435 
1436 	return 0;
1437 }
1438 
exit_vq(struct kvm * kvm,void * dev,u32 vq)1439 static void exit_vq(struct kvm *kvm, void *dev, u32 vq)
1440 {
1441 	struct p9_dev *p9dev = dev;
1442 
1443 	thread_pool__cancel_job(&p9dev->jobs[vq].job_id);
1444 }
1445 
notify_vq(struct kvm * kvm,void * dev,u32 vq)1446 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
1447 {
1448 	struct p9_dev *p9dev = dev;
1449 
1450 	thread_pool__do_job(&p9dev->jobs[vq].job_id);
1451 
1452 	return 0;
1453 }
1454 
get_vq(struct kvm * kvm,void * dev,u32 vq)1455 static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
1456 {
1457 	struct p9_dev *p9dev = dev;
1458 
1459 	return &p9dev->vqs[vq];
1460 }
1461 
get_size_vq(struct kvm * kvm,void * dev,u32 vq)1462 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
1463 {
1464 	return VIRTQUEUE_NUM;
1465 }
1466 
set_size_vq(struct kvm * kvm,void * dev,u32 vq,int size)1467 static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
1468 {
1469 	/* FIXME: dynamic */
1470 	return size;
1471 }
1472 
get_vq_count(struct kvm * kvm,void * dev)1473 static unsigned int get_vq_count(struct kvm *kvm, void *dev)
1474 {
1475 	return NUM_VIRT_QUEUES;
1476 }
1477 
1478 struct virtio_ops p9_dev_virtio_ops = {
1479 	.get_config		= get_config,
1480 	.get_config_size	= get_config_size,
1481 	.get_host_features	= get_host_features,
1482 	.init_vq		= init_vq,
1483 	.exit_vq		= exit_vq,
1484 	.notify_status		= notify_status,
1485 	.notify_vq		= notify_vq,
1486 	.get_vq			= get_vq,
1487 	.get_size_vq		= get_size_vq,
1488 	.set_size_vq		= set_size_vq,
1489 	.get_vq_count		= get_vq_count,
1490 };
1491 
virtio_9p_rootdir_parser(const struct option * opt,const char * arg,int unset)1492 int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
1493 {
1494 	char *tag_name;
1495 	char tmp[PATH_MAX];
1496 	struct kvm *kvm = opt->ptr;
1497 
1498 	/*
1499 	 * 9p dir can be of the form dirname,tag_name or
1500 	 * just dirname. In the later case we use the
1501 	 * default tag name
1502 	 */
1503 	tag_name = strstr(arg, ",");
1504 	if (tag_name) {
1505 		*tag_name = '\0';
1506 		tag_name++;
1507 	}
1508 	if (realpath(arg, tmp)) {
1509 		if (virtio_9p__register(kvm, tmp, tag_name) < 0)
1510 			die("Unable to initialize virtio 9p");
1511 	} else
1512 		die("Failed resolving 9p path");
1513 	return 0;
1514 }
1515 
virtio_9p_img_name_parser(const struct option * opt,const char * arg,int unset)1516 int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset)
1517 {
1518 	char path[PATH_MAX];
1519 	struct stat st;
1520 	struct kvm *kvm = opt->ptr;
1521 
1522 	if (stat(arg, &st) == 0 &&
1523 	    S_ISDIR(st.st_mode)) {
1524 		char tmp[PATH_MAX];
1525 
1526 		if (kvm->cfg.using_rootfs)
1527 			die("Please use only one rootfs directory atmost");
1528 
1529 		if (realpath(arg, tmp) == 0 ||
1530 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1531 			die("Unable to initialize virtio 9p");
1532 		kvm->cfg.using_rootfs = 1;
1533 		return 0;
1534 	}
1535 
1536 	snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
1537 
1538 	if (stat(path, &st) == 0 &&
1539 	    S_ISDIR(st.st_mode)) {
1540 		char tmp[PATH_MAX];
1541 
1542 		if (kvm->cfg.using_rootfs)
1543 			die("Please use only one rootfs directory atmost");
1544 
1545 		if (realpath(path, tmp) == 0 ||
1546 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1547 			die("Unable to initialize virtio 9p");
1548 		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
1549 			die("Unable to initialize virtio 9p");
1550 		kvm_setup_resolv(arg);
1551 		kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1;
1552 		kvm->cfg.custom_rootfs_name = arg;
1553 		return 0;
1554 	}
1555 
1556 	return -1;
1557 }
1558 
virtio_9p__init(struct kvm * kvm)1559 int virtio_9p__init(struct kvm *kvm)
1560 {
1561 	struct p9_dev *p9dev;
1562 	int r;
1563 
1564 	list_for_each_entry(p9dev, &devs, list) {
1565 		r = virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
1566 				kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_9P,
1567 				VIRTIO_ID_9P, PCI_CLASS_9P);
1568 		if (r < 0)
1569 			return r;
1570 	}
1571 
1572 	return 0;
1573 }
1574 virtio_dev_init(virtio_9p__init);
1575 
virtio_9p__exit(struct kvm * kvm)1576 int virtio_9p__exit(struct kvm *kvm)
1577 {
1578 	struct p9_dev *p9dev, *tmp;
1579 
1580 	list_for_each_entry_safe(p9dev, tmp, &devs, list) {
1581 		list_del(&p9dev->list);
1582 		virtio_exit(kvm, &p9dev->vdev);
1583 		free(p9dev);
1584 	}
1585 
1586 	return 0;
1587 }
1588 virtio_dev_exit(virtio_9p__exit);
1589 
virtio_9p__register(struct kvm * kvm,const char * root,const char * tag_name)1590 int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
1591 {
1592 	struct p9_dev *p9dev;
1593 	size_t tag_length;
1594 	size_t config_size;
1595 	int err;
1596 
1597 	p9dev = calloc(1, sizeof(*p9dev));
1598 	if (!p9dev)
1599 		return -ENOMEM;
1600 
1601 	if (!tag_name)
1602 		tag_name = VIRTIO_9P_DEFAULT_TAG;
1603 
1604 	tag_length = strlen(tag_name);
1605 	/* The tag_name zero byte is intentionally excluded */
1606 	config_size = sizeof(*p9dev->config) + tag_length;
1607 
1608 	p9dev->config = calloc(1, config_size);
1609 	if (p9dev->config == NULL) {
1610 		err = -ENOMEM;
1611 		goto free_p9dev;
1612 	}
1613 	p9dev->config_size = config_size;
1614 
1615 	strncpy(p9dev->root_dir, root, sizeof(p9dev->root_dir));
1616 	p9dev->root_dir[sizeof(p9dev->root_dir)-1] = '\x00';
1617 
1618 	p9dev->tag_len = tag_length;
1619 	if (p9dev->tag_len > MAX_TAG_LEN) {
1620 		err = -EINVAL;
1621 		goto free_p9dev_config;
1622 	}
1623 
1624 	memcpy(&p9dev->config->tag, tag_name, tag_length);
1625 
1626 	list_add(&p9dev->list, &devs);
1627 
1628 	if (compat_id == -1)
1629 		compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO");
1630 
1631 	return 0;
1632 
1633 free_p9dev_config:
1634 	free(p9dev->config);
1635 free_p9dev:
1636 	free(p9dev);
1637 	return err;
1638 }
1639