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