]> git.proxmox.com Git - mirror_qemu.git/blob - hw/9pfs/virtio-9p.c
Merge remote-tracking branch 'aneesh/for-upstream-1' into staging
[mirror_qemu.git] / hw / 9pfs / virtio-9p.c
1 /*
2 * Virtio 9p backend
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
12 */
13
14 #include "hw/virtio.h"
15 #include "hw/pc.h"
16 #include "qemu_socket.h"
17 #include "hw/virtio-pci.h"
18 #include "virtio-9p.h"
19 #include "fsdev/qemu-fsdev.h"
20 #include "virtio-9p-debug.h"
21 #include "virtio-9p-xattr.h"
22 #include "virtio-9p-coth.h"
23
24 int debug_9p_pdu;
25
26 enum {
27 Oread = 0x00,
28 Owrite = 0x01,
29 Ordwr = 0x02,
30 Oexec = 0x03,
31 Oexcl = 0x04,
32 Otrunc = 0x10,
33 Orexec = 0x20,
34 Orclose = 0x40,
35 Oappend = 0x80,
36 };
37
38 static int omode_to_uflags(int8_t mode)
39 {
40 int ret = 0;
41
42 switch (mode & 3) {
43 case Oread:
44 ret = O_RDONLY;
45 break;
46 case Ordwr:
47 ret = O_RDWR;
48 break;
49 case Owrite:
50 ret = O_WRONLY;
51 break;
52 case Oexec:
53 ret = O_RDONLY;
54 break;
55 }
56
57 if (mode & Otrunc) {
58 ret |= O_TRUNC;
59 }
60
61 if (mode & Oappend) {
62 ret |= O_APPEND;
63 }
64
65 if (mode & Oexcl) {
66 ret |= O_EXCL;
67 }
68
69 return ret;
70 }
71
72 void cred_init(FsCred *credp)
73 {
74 credp->fc_uid = -1;
75 credp->fc_gid = -1;
76 credp->fc_mode = -1;
77 credp->fc_rdev = -1;
78 }
79
80 static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
81 {
82 return s->ops->lstat(&s->ctx, path->data, stbuf);
83 }
84
85 static int v9fs_do_close(V9fsState *s, int fd)
86 {
87 return s->ops->close(&s->ctx, fd);
88 }
89
90 static int v9fs_do_closedir(V9fsState *s, DIR *dir)
91 {
92 return s->ops->closedir(&s->ctx, dir);
93 }
94
95 static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
96 {
97 return s->ops->open(&s->ctx, path->data, flags);
98 }
99
100 static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
101 {
102 return s->ops->opendir(&s->ctx, path->data);
103 }
104
105 static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
106 {
107 return s->ops->rewinddir(&s->ctx, dir);
108 }
109
110 static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
111 {
112 return s->ops->telldir(&s->ctx, dir);
113 }
114
115 static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
116 {
117 return s->ops->seekdir(&s->ctx, dir, off);
118 }
119
120 static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
121 int iovcnt, int64_t offset)
122 {
123 return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
124 }
125
126 static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
127 int iovcnt, int64_t offset)
128 {
129 return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
130 }
131
132 static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
133 {
134 FsCred cred;
135 cred_init(&cred);
136 cred.fc_mode = mode;
137 return s->ops->chmod(&s->ctx, path->data, &cred);
138 }
139
140 static int v9fs_do_mknod(V9fsState *s, char *name,
141 mode_t mode, dev_t dev, uid_t uid, gid_t gid)
142 {
143 FsCred cred;
144 cred_init(&cred);
145 cred.fc_uid = uid;
146 cred.fc_gid = gid;
147 cred.fc_mode = mode;
148 cred.fc_rdev = dev;
149 return s->ops->mknod(&s->ctx, name, &cred);
150 }
151
152 static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
153 {
154 return s->ops->fstat(&s->ctx, fd, stbuf);
155 }
156
157 static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
158 int flags, int mode)
159 {
160 FsCred cred;
161
162 cred_init(&cred);
163 cred.fc_uid = uid;
164 cred.fc_gid = gid;
165 cred.fc_mode = mode & 07777;
166
167 return s->ops->open2(&s->ctx, fullname, flags, &cred);
168 }
169
170 static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
171 const char *oldpath, const char *newpath, gid_t gid)
172 {
173 FsCred cred;
174 cred_init(&cred);
175 cred.fc_uid = fidp->uid;
176 cred.fc_gid = gid;
177 cred.fc_mode = 0777;
178
179 return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
180 }
181
182 static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
183 {
184 return s->ops->link(&s->ctx, oldpath->data, newpath->data);
185 }
186
187 static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
188 {
189 return s->ops->truncate(&s->ctx, path->data, size);
190 }
191
192 static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
193 {
194 FsCred cred;
195 cred_init(&cred);
196 cred.fc_uid = uid;
197 cred.fc_gid = gid;
198
199 return s->ops->chown(&s->ctx, path->data, &cred);
200 }
201
202 static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
203 const struct timespec times[2])
204 {
205 return s->ops->utimensat(&s->ctx, path->data, times);
206 }
207
208 static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
209 {
210 return s->ops->fsync(&s->ctx, fd, datasync);
211 }
212
213 static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
214 {
215 return s->ops->statfs(&s->ctx, path->data, stbuf);
216 }
217
218 static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
219 V9fsString *xattr_name,
220 void *value, size_t size, int flags)
221 {
222 return s->ops->lsetxattr(&s->ctx, path->data,
223 xattr_name->data, value, size, flags);
224 }
225
226 static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
227 V9fsString *xattr_name)
228 {
229 return s->ops->lremovexattr(&s->ctx, path->data,
230 xattr_name->data);
231 }
232
233
234 static void v9fs_string_init(V9fsString *str)
235 {
236 str->data = NULL;
237 str->size = 0;
238 }
239
240 static void v9fs_string_free(V9fsString *str)
241 {
242 qemu_free(str->data);
243 str->data = NULL;
244 str->size = 0;
245 }
246
247 static void v9fs_string_null(V9fsString *str)
248 {
249 v9fs_string_free(str);
250 }
251
252 static int number_to_string(void *arg, char type)
253 {
254 unsigned int ret = 0;
255
256 switch (type) {
257 case 'u': {
258 unsigned int num = *(unsigned int *)arg;
259
260 do {
261 ret++;
262 num = num/10;
263 } while (num);
264 break;
265 }
266 case 'U': {
267 unsigned long num = *(unsigned long *)arg;
268 do {
269 ret++;
270 num = num/10;
271 } while (num);
272 break;
273 }
274 default:
275 printf("Number_to_string: Unknown number format\n");
276 return -1;
277 }
278
279 return ret;
280 }
281
282 static int GCC_FMT_ATTR(2, 0)
283 v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
284 {
285 va_list ap2;
286 char *iter = (char *)fmt;
287 int len = 0;
288 int nr_args = 0;
289 char *arg_char_ptr;
290 unsigned int arg_uint;
291 unsigned long arg_ulong;
292
293 /* Find the number of %'s that denotes an argument */
294 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
295 nr_args++;
296 iter++;
297 }
298
299 len = strlen(fmt) - 2*nr_args;
300
301 if (!nr_args) {
302 goto alloc_print;
303 }
304
305 va_copy(ap2, ap);
306
307 iter = (char *)fmt;
308
309 /* Now parse the format string */
310 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
311 iter++;
312 switch (*iter) {
313 case 'u':
314 arg_uint = va_arg(ap2, unsigned int);
315 len += number_to_string((void *)&arg_uint, 'u');
316 break;
317 case 'l':
318 if (*++iter == 'u') {
319 arg_ulong = va_arg(ap2, unsigned long);
320 len += number_to_string((void *)&arg_ulong, 'U');
321 } else {
322 return -1;
323 }
324 break;
325 case 's':
326 arg_char_ptr = va_arg(ap2, char *);
327 len += strlen(arg_char_ptr);
328 break;
329 case 'c':
330 len += 1;
331 break;
332 default:
333 fprintf(stderr,
334 "v9fs_string_alloc_printf:Incorrect format %c", *iter);
335 return -1;
336 }
337 iter++;
338 }
339
340 alloc_print:
341 *strp = qemu_malloc((len + 1) * sizeof(**strp));
342
343 return vsprintf(*strp, fmt, ap);
344 }
345
346 static void GCC_FMT_ATTR(2, 3)
347 v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
348 {
349 va_list ap;
350 int err;
351
352 v9fs_string_free(str);
353
354 va_start(ap, fmt);
355 err = v9fs_string_alloc_printf(&str->data, fmt, ap);
356 BUG_ON(err == -1);
357 va_end(ap);
358
359 str->size = err;
360 }
361
362 static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
363 {
364 v9fs_string_free(lhs);
365 v9fs_string_sprintf(lhs, "%s", rhs->data);
366 }
367
368 /*
369 * Return TRUE if s1 is an ancestor of s2.
370 *
371 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
372 * As a special case, We treat s1 as ancestor of s2 if they are same!
373 */
374 static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
375 {
376 if (!strncmp(s1->data, s2->data, s1->size)) {
377 if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
378 return 1;
379 }
380 }
381 return 0;
382 }
383
384 static size_t v9fs_string_size(V9fsString *str)
385 {
386 return str->size;
387 }
388
389 static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
390 {
391 V9fsFidState *f;
392
393 for (f = s->fid_list; f; f = f->next) {
394 if (f->fid == fid) {
395 return f;
396 }
397 }
398
399 return NULL;
400 }
401
402 static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
403 {
404 V9fsFidState *f;
405
406 f = lookup_fid(s, fid);
407 if (f) {
408 return NULL;
409 }
410
411 f = qemu_mallocz(sizeof(V9fsFidState));
412
413 f->fid = fid;
414 f->fid_type = P9_FID_NONE;
415
416 f->next = s->fid_list;
417 s->fid_list = f;
418
419 return f;
420 }
421
422 static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
423 {
424 int retval = 0;
425
426 if (fidp->fs.xattr.copied_len == -1) {
427 /* getxattr/listxattr fid */
428 goto free_value;
429 }
430 /*
431 * if this is fid for setxattr. clunk should
432 * result in setxattr localcall
433 */
434 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
435 /* clunk after partial write */
436 retval = -EINVAL;
437 goto free_out;
438 }
439 if (fidp->fs.xattr.len) {
440 retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
441 fidp->fs.xattr.value,
442 fidp->fs.xattr.len,
443 fidp->fs.xattr.flags);
444 } else {
445 retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
446 }
447 free_out:
448 v9fs_string_free(&fidp->fs.xattr.name);
449 free_value:
450 if (fidp->fs.xattr.value) {
451 qemu_free(fidp->fs.xattr.value);
452 }
453 return retval;
454 }
455
456 static int free_fid(V9fsState *s, int32_t fid)
457 {
458 int retval = 0;
459 V9fsFidState **fidpp, *fidp;
460
461 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
462 if ((*fidpp)->fid == fid) {
463 break;
464 }
465 }
466
467 if (*fidpp == NULL) {
468 return -ENOENT;
469 }
470
471 fidp = *fidpp;
472 *fidpp = fidp->next;
473
474 if (fidp->fid_type == P9_FID_FILE) {
475 v9fs_do_close(s, fidp->fs.fd);
476 } else if (fidp->fid_type == P9_FID_DIR) {
477 v9fs_do_closedir(s, fidp->fs.dir);
478 } else if (fidp->fid_type == P9_FID_XATTR) {
479 retval = v9fs_xattr_fid_clunk(s, fidp);
480 }
481 v9fs_string_free(&fidp->path);
482 qemu_free(fidp);
483
484 return retval;
485 }
486
487 #define P9_QID_TYPE_DIR 0x80
488 #define P9_QID_TYPE_SYMLINK 0x02
489
490 #define P9_STAT_MODE_DIR 0x80000000
491 #define P9_STAT_MODE_APPEND 0x40000000
492 #define P9_STAT_MODE_EXCL 0x20000000
493 #define P9_STAT_MODE_MOUNT 0x10000000
494 #define P9_STAT_MODE_AUTH 0x08000000
495 #define P9_STAT_MODE_TMP 0x04000000
496 #define P9_STAT_MODE_SYMLINK 0x02000000
497 #define P9_STAT_MODE_LINK 0x01000000
498 #define P9_STAT_MODE_DEVICE 0x00800000
499 #define P9_STAT_MODE_NAMED_PIPE 0x00200000
500 #define P9_STAT_MODE_SOCKET 0x00100000
501 #define P9_STAT_MODE_SETUID 0x00080000
502 #define P9_STAT_MODE_SETGID 0x00040000
503 #define P9_STAT_MODE_SETVTX 0x00010000
504
505 #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
506 P9_STAT_MODE_SYMLINK | \
507 P9_STAT_MODE_LINK | \
508 P9_STAT_MODE_DEVICE | \
509 P9_STAT_MODE_NAMED_PIPE | \
510 P9_STAT_MODE_SOCKET)
511
512 /* This is the algorithm from ufs in spfs */
513 static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
514 {
515 size_t size;
516
517 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
518 memcpy(&qidp->path, &stbuf->st_ino, size);
519 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
520 qidp->type = 0;
521 if (S_ISDIR(stbuf->st_mode)) {
522 qidp->type |= P9_QID_TYPE_DIR;
523 }
524 if (S_ISLNK(stbuf->st_mode)) {
525 qidp->type |= P9_QID_TYPE_SYMLINK;
526 }
527 }
528
529 static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
530 {
531 struct stat stbuf;
532 int err;
533
534 err = v9fs_do_lstat(s, &fidp->path, &stbuf);
535 if (err) {
536 return err;
537 }
538
539 stat_to_qid(&stbuf, qidp);
540 return 0;
541 }
542
543 static V9fsPDU *alloc_pdu(V9fsState *s)
544 {
545 V9fsPDU *pdu = NULL;
546
547 if (!QLIST_EMPTY(&s->free_list)) {
548 pdu = QLIST_FIRST(&s->free_list);
549 QLIST_REMOVE(pdu, next);
550 }
551 return pdu;
552 }
553
554 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
555 {
556 if (pdu) {
557 if (debug_9p_pdu) {
558 pprint_pdu(pdu);
559 }
560 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
561 }
562 }
563
564 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
565 size_t offset, size_t size, int pack)
566 {
567 int i = 0;
568 size_t copied = 0;
569
570 for (i = 0; size && i < sg_count; i++) {
571 size_t len;
572 if (offset >= sg[i].iov_len) {
573 /* skip this sg */
574 offset -= sg[i].iov_len;
575 continue;
576 } else {
577 len = MIN(sg[i].iov_len - offset, size);
578 if (pack) {
579 memcpy(sg[i].iov_base + offset, addr, len);
580 } else {
581 memcpy(addr, sg[i].iov_base + offset, len);
582 }
583 size -= len;
584 copied += len;
585 addr += len;
586 if (size) {
587 offset = 0;
588 continue;
589 }
590 }
591 }
592
593 return copied;
594 }
595
596 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
597 {
598 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
599 offset, size, 0);
600 }
601
602 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
603 size_t size)
604 {
605 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
606 offset, size, 1);
607 }
608
609 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
610 {
611 size_t pos = 0;
612 int i, j;
613 struct iovec *src_sg;
614 unsigned int num;
615
616 if (rx) {
617 src_sg = pdu->elem.in_sg;
618 num = pdu->elem.in_num;
619 } else {
620 src_sg = pdu->elem.out_sg;
621 num = pdu->elem.out_num;
622 }
623
624 j = 0;
625 for (i = 0; i < num; i++) {
626 if (offset <= pos) {
627 sg[j].iov_base = src_sg[i].iov_base;
628 sg[j].iov_len = src_sg[i].iov_len;
629 j++;
630 } else if (offset < (src_sg[i].iov_len + pos)) {
631 sg[j].iov_base = src_sg[i].iov_base;
632 sg[j].iov_len = src_sg[i].iov_len;
633 sg[j].iov_base += (offset - pos);
634 sg[j].iov_len -= (offset - pos);
635 j++;
636 }
637 pos += src_sg[i].iov_len;
638 }
639
640 return j;
641 }
642
643 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
644 {
645 size_t old_offset = offset;
646 va_list ap;
647 int i;
648
649 va_start(ap, fmt);
650 for (i = 0; fmt[i]; i++) {
651 switch (fmt[i]) {
652 case 'b': {
653 uint8_t *valp = va_arg(ap, uint8_t *);
654 offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
655 break;
656 }
657 case 'w': {
658 uint16_t val, *valp;
659 valp = va_arg(ap, uint16_t *);
660 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
661 *valp = le16_to_cpu(val);
662 break;
663 }
664 case 'd': {
665 uint32_t val, *valp;
666 valp = va_arg(ap, uint32_t *);
667 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
668 *valp = le32_to_cpu(val);
669 break;
670 }
671 case 'q': {
672 uint64_t val, *valp;
673 valp = va_arg(ap, uint64_t *);
674 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
675 *valp = le64_to_cpu(val);
676 break;
677 }
678 case 'v': {
679 struct iovec *iov = va_arg(ap, struct iovec *);
680 int *iovcnt = va_arg(ap, int *);
681 *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
682 break;
683 }
684 case 's': {
685 V9fsString *str = va_arg(ap, V9fsString *);
686 offset += pdu_unmarshal(pdu, offset, "w", &str->size);
687 /* FIXME: sanity check str->size */
688 str->data = qemu_malloc(str->size + 1);
689 offset += pdu_unpack(str->data, pdu, offset, str->size);
690 str->data[str->size] = 0;
691 break;
692 }
693 case 'Q': {
694 V9fsQID *qidp = va_arg(ap, V9fsQID *);
695 offset += pdu_unmarshal(pdu, offset, "bdq",
696 &qidp->type, &qidp->version, &qidp->path);
697 break;
698 }
699 case 'S': {
700 V9fsStat *statp = va_arg(ap, V9fsStat *);
701 offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
702 &statp->size, &statp->type, &statp->dev,
703 &statp->qid, &statp->mode, &statp->atime,
704 &statp->mtime, &statp->length,
705 &statp->name, &statp->uid, &statp->gid,
706 &statp->muid, &statp->extension,
707 &statp->n_uid, &statp->n_gid,
708 &statp->n_muid);
709 break;
710 }
711 case 'I': {
712 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
713 offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
714 &iattr->valid, &iattr->mode,
715 &iattr->uid, &iattr->gid, &iattr->size,
716 &iattr->atime_sec, &iattr->atime_nsec,
717 &iattr->mtime_sec, &iattr->mtime_nsec);
718 break;
719 }
720 default:
721 break;
722 }
723 }
724
725 va_end(ap);
726
727 return offset - old_offset;
728 }
729
730 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
731 {
732 size_t old_offset = offset;
733 va_list ap;
734 int i;
735
736 va_start(ap, fmt);
737 for (i = 0; fmt[i]; i++) {
738 switch (fmt[i]) {
739 case 'b': {
740 uint8_t val = va_arg(ap, int);
741 offset += pdu_pack(pdu, offset, &val, sizeof(val));
742 break;
743 }
744 case 'w': {
745 uint16_t val;
746 cpu_to_le16w(&val, va_arg(ap, int));
747 offset += pdu_pack(pdu, offset, &val, sizeof(val));
748 break;
749 }
750 case 'd': {
751 uint32_t val;
752 cpu_to_le32w(&val, va_arg(ap, uint32_t));
753 offset += pdu_pack(pdu, offset, &val, sizeof(val));
754 break;
755 }
756 case 'q': {
757 uint64_t val;
758 cpu_to_le64w(&val, va_arg(ap, uint64_t));
759 offset += pdu_pack(pdu, offset, &val, sizeof(val));
760 break;
761 }
762 case 'v': {
763 struct iovec *iov = va_arg(ap, struct iovec *);
764 int *iovcnt = va_arg(ap, int *);
765 *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
766 break;
767 }
768 case 's': {
769 V9fsString *str = va_arg(ap, V9fsString *);
770 offset += pdu_marshal(pdu, offset, "w", str->size);
771 offset += pdu_pack(pdu, offset, str->data, str->size);
772 break;
773 }
774 case 'Q': {
775 V9fsQID *qidp = va_arg(ap, V9fsQID *);
776 offset += pdu_marshal(pdu, offset, "bdq",
777 qidp->type, qidp->version, qidp->path);
778 break;
779 }
780 case 'S': {
781 V9fsStat *statp = va_arg(ap, V9fsStat *);
782 offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
783 statp->size, statp->type, statp->dev,
784 &statp->qid, statp->mode, statp->atime,
785 statp->mtime, statp->length, &statp->name,
786 &statp->uid, &statp->gid, &statp->muid,
787 &statp->extension, statp->n_uid,
788 statp->n_gid, statp->n_muid);
789 break;
790 }
791 case 'A': {
792 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
793 offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
794 statp->st_result_mask,
795 &statp->qid, statp->st_mode,
796 statp->st_uid, statp->st_gid,
797 statp->st_nlink, statp->st_rdev,
798 statp->st_size, statp->st_blksize, statp->st_blocks,
799 statp->st_atime_sec, statp->st_atime_nsec,
800 statp->st_mtime_sec, statp->st_mtime_nsec,
801 statp->st_ctime_sec, statp->st_ctime_nsec,
802 statp->st_btime_sec, statp->st_btime_nsec,
803 statp->st_gen, statp->st_data_version);
804 break;
805 }
806 default:
807 break;
808 }
809 }
810 va_end(ap);
811
812 return offset - old_offset;
813 }
814
815 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
816 {
817 int8_t id = pdu->id + 1; /* Response */
818
819 if (len < 0) {
820 int err = -len;
821 len = 7;
822
823 if (s->proto_version != V9FS_PROTO_2000L) {
824 V9fsString str;
825
826 str.data = strerror(err);
827 str.size = strlen(str.data);
828
829 len += pdu_marshal(pdu, len, "s", &str);
830 id = P9_RERROR;
831 }
832
833 len += pdu_marshal(pdu, len, "d", err);
834
835 if (s->proto_version == V9FS_PROTO_2000L) {
836 id = P9_RLERROR;
837 }
838 }
839
840 /* fill out the header */
841 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
842
843 /* keep these in sync */
844 pdu->size = len;
845 pdu->id = id;
846
847 /* push onto queue and notify */
848 virtqueue_push(s->vq, &pdu->elem, len);
849
850 /* FIXME: we should batch these completions */
851 virtio_notify(&s->vdev, s->vq);
852
853 free_pdu(s, pdu);
854 }
855
856 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
857 {
858 mode_t ret;
859
860 ret = mode & 0777;
861 if (mode & P9_STAT_MODE_DIR) {
862 ret |= S_IFDIR;
863 }
864
865 if (mode & P9_STAT_MODE_SYMLINK) {
866 ret |= S_IFLNK;
867 }
868 if (mode & P9_STAT_MODE_SOCKET) {
869 ret |= S_IFSOCK;
870 }
871 if (mode & P9_STAT_MODE_NAMED_PIPE) {
872 ret |= S_IFIFO;
873 }
874 if (mode & P9_STAT_MODE_DEVICE) {
875 if (extension && extension->data[0] == 'c') {
876 ret |= S_IFCHR;
877 } else {
878 ret |= S_IFBLK;
879 }
880 }
881
882 if (!(ret&~0777)) {
883 ret |= S_IFREG;
884 }
885
886 if (mode & P9_STAT_MODE_SETUID) {
887 ret |= S_ISUID;
888 }
889 if (mode & P9_STAT_MODE_SETGID) {
890 ret |= S_ISGID;
891 }
892 if (mode & P9_STAT_MODE_SETVTX) {
893 ret |= S_ISVTX;
894 }
895
896 return ret;
897 }
898
899 static int donttouch_stat(V9fsStat *stat)
900 {
901 if (stat->type == -1 &&
902 stat->dev == -1 &&
903 stat->qid.type == -1 &&
904 stat->qid.version == -1 &&
905 stat->qid.path == -1 &&
906 stat->mode == -1 &&
907 stat->atime == -1 &&
908 stat->mtime == -1 &&
909 stat->length == -1 &&
910 !stat->name.size &&
911 !stat->uid.size &&
912 !stat->gid.size &&
913 !stat->muid.size &&
914 stat->n_uid == -1 &&
915 stat->n_gid == -1 &&
916 stat->n_muid == -1) {
917 return 1;
918 }
919
920 return 0;
921 }
922
923 static void v9fs_stat_free(V9fsStat *stat)
924 {
925 v9fs_string_free(&stat->name);
926 v9fs_string_free(&stat->uid);
927 v9fs_string_free(&stat->gid);
928 v9fs_string_free(&stat->muid);
929 v9fs_string_free(&stat->extension);
930 }
931
932 static uint32_t stat_to_v9mode(const struct stat *stbuf)
933 {
934 uint32_t mode;
935
936 mode = stbuf->st_mode & 0777;
937 if (S_ISDIR(stbuf->st_mode)) {
938 mode |= P9_STAT_MODE_DIR;
939 }
940
941 if (S_ISLNK(stbuf->st_mode)) {
942 mode |= P9_STAT_MODE_SYMLINK;
943 }
944
945 if (S_ISSOCK(stbuf->st_mode)) {
946 mode |= P9_STAT_MODE_SOCKET;
947 }
948
949 if (S_ISFIFO(stbuf->st_mode)) {
950 mode |= P9_STAT_MODE_NAMED_PIPE;
951 }
952
953 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
954 mode |= P9_STAT_MODE_DEVICE;
955 }
956
957 if (stbuf->st_mode & S_ISUID) {
958 mode |= P9_STAT_MODE_SETUID;
959 }
960
961 if (stbuf->st_mode & S_ISGID) {
962 mode |= P9_STAT_MODE_SETGID;
963 }
964
965 if (stbuf->st_mode & S_ISVTX) {
966 mode |= P9_STAT_MODE_SETVTX;
967 }
968
969 return mode;
970 }
971
972 static int stat_to_v9stat(V9fsState *s, V9fsString *name,
973 const struct stat *stbuf,
974 V9fsStat *v9stat)
975 {
976 int err;
977 const char *str;
978
979 memset(v9stat, 0, sizeof(*v9stat));
980
981 stat_to_qid(stbuf, &v9stat->qid);
982 v9stat->mode = stat_to_v9mode(stbuf);
983 v9stat->atime = stbuf->st_atime;
984 v9stat->mtime = stbuf->st_mtime;
985 v9stat->length = stbuf->st_size;
986
987 v9fs_string_null(&v9stat->uid);
988 v9fs_string_null(&v9stat->gid);
989 v9fs_string_null(&v9stat->muid);
990
991 v9stat->n_uid = stbuf->st_uid;
992 v9stat->n_gid = stbuf->st_gid;
993 v9stat->n_muid = 0;
994
995 v9fs_string_null(&v9stat->extension);
996
997 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
998 err = v9fs_co_readlink(s, name, &v9stat->extension);
999 if (err < 0) {
1000 return err;
1001 }
1002 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1003 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1004 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1005 major(stbuf->st_rdev), minor(stbuf->st_rdev));
1006 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1007 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1008 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1009 }
1010
1011 str = strrchr(name->data, '/');
1012 if (str) {
1013 str += 1;
1014 } else {
1015 str = name->data;
1016 }
1017
1018 v9fs_string_sprintf(&v9stat->name, "%s", str);
1019
1020 v9stat->size = 61 +
1021 v9fs_string_size(&v9stat->name) +
1022 v9fs_string_size(&v9stat->uid) +
1023 v9fs_string_size(&v9stat->gid) +
1024 v9fs_string_size(&v9stat->muid) +
1025 v9fs_string_size(&v9stat->extension);
1026 return 0;
1027 }
1028
1029 #define P9_STATS_MODE 0x00000001ULL
1030 #define P9_STATS_NLINK 0x00000002ULL
1031 #define P9_STATS_UID 0x00000004ULL
1032 #define P9_STATS_GID 0x00000008ULL
1033 #define P9_STATS_RDEV 0x00000010ULL
1034 #define P9_STATS_ATIME 0x00000020ULL
1035 #define P9_STATS_MTIME 0x00000040ULL
1036 #define P9_STATS_CTIME 0x00000080ULL
1037 #define P9_STATS_INO 0x00000100ULL
1038 #define P9_STATS_SIZE 0x00000200ULL
1039 #define P9_STATS_BLOCKS 0x00000400ULL
1040
1041 #define P9_STATS_BTIME 0x00000800ULL
1042 #define P9_STATS_GEN 0x00001000ULL
1043 #define P9_STATS_DATA_VERSION 0x00002000ULL
1044
1045 #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
1046 #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
1047
1048
1049 static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1050 V9fsStatDotl *v9lstat)
1051 {
1052 memset(v9lstat, 0, sizeof(*v9lstat));
1053
1054 v9lstat->st_mode = stbuf->st_mode;
1055 v9lstat->st_nlink = stbuf->st_nlink;
1056 v9lstat->st_uid = stbuf->st_uid;
1057 v9lstat->st_gid = stbuf->st_gid;
1058 v9lstat->st_rdev = stbuf->st_rdev;
1059 v9lstat->st_size = stbuf->st_size;
1060 v9lstat->st_blksize = stbuf->st_blksize;
1061 v9lstat->st_blocks = stbuf->st_blocks;
1062 v9lstat->st_atime_sec = stbuf->st_atime;
1063 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1064 v9lstat->st_mtime_sec = stbuf->st_mtime;
1065 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1066 v9lstat->st_ctime_sec = stbuf->st_ctime;
1067 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1068 /* Currently we only support BASIC fields in stat */
1069 v9lstat->st_result_mask = P9_STATS_BASIC;
1070
1071 stat_to_qid(stbuf, &v9lstat->qid);
1072 }
1073
1074 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1075 {
1076 while (len && *iovcnt) {
1077 if (len < sg->iov_len) {
1078 sg->iov_len -= len;
1079 sg->iov_base += len;
1080 len = 0;
1081 } else {
1082 len -= sg->iov_len;
1083 sg++;
1084 *iovcnt -= 1;
1085 }
1086 }
1087
1088 return sg;
1089 }
1090
1091 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1092 {
1093 int i;
1094 int total = 0;
1095
1096 for (i = 0; i < *cnt; i++) {
1097 if ((total + sg[i].iov_len) > cap) {
1098 sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1099 i++;
1100 break;
1101 }
1102 total += sg[i].iov_len;
1103 }
1104
1105 *cnt = i;
1106
1107 return sg;
1108 }
1109
1110 static void print_sg(struct iovec *sg, int cnt)
1111 {
1112 int i;
1113
1114 printf("sg[%d]: {", cnt);
1115 for (i = 0; i < cnt; i++) {
1116 if (i) {
1117 printf(", ");
1118 }
1119 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1120 }
1121 printf("}\n");
1122 }
1123
1124 static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1125 {
1126 V9fsString str;
1127 v9fs_string_init(&str);
1128 v9fs_string_copy(&str, dst);
1129 v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1130 v9fs_string_free(&str);
1131 }
1132
1133 static void v9fs_version(void *opaque)
1134 {
1135 V9fsPDU *pdu = opaque;
1136 V9fsState *s = pdu->s;
1137 V9fsString version;
1138 size_t offset = 7;
1139
1140 pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1141
1142 if (!strcmp(version.data, "9P2000.u")) {
1143 s->proto_version = V9FS_PROTO_2000U;
1144 } else if (!strcmp(version.data, "9P2000.L")) {
1145 s->proto_version = V9FS_PROTO_2000L;
1146 } else {
1147 v9fs_string_sprintf(&version, "unknown");
1148 }
1149
1150 offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1151 complete_pdu(s, pdu, offset);
1152
1153 v9fs_string_free(&version);
1154 return;
1155 }
1156
1157 static void v9fs_attach(void *opaque)
1158 {
1159 V9fsPDU *pdu = opaque;
1160 V9fsState *s = pdu->s;
1161 int32_t fid, afid, n_uname;
1162 V9fsString uname, aname;
1163 V9fsFidState *fidp;
1164 V9fsQID qid;
1165 size_t offset = 7;
1166 ssize_t err;
1167
1168 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1169
1170 fidp = alloc_fid(s, fid);
1171 if (fidp == NULL) {
1172 err = -EINVAL;
1173 goto out;
1174 }
1175
1176 fidp->uid = n_uname;
1177
1178 v9fs_string_sprintf(&fidp->path, "%s", "/");
1179 err = fid_to_qid(s, fidp, &qid);
1180 if (err) {
1181 err = -EINVAL;
1182 free_fid(s, fid);
1183 goto out;
1184 }
1185
1186 offset += pdu_marshal(pdu, offset, "Q", &qid);
1187
1188 err = offset;
1189 out:
1190 complete_pdu(s, pdu, err);
1191 v9fs_string_free(&uname);
1192 v9fs_string_free(&aname);
1193 }
1194
1195 static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1196 {
1197 if (err == -1) {
1198 err = -errno;
1199 goto out;
1200 }
1201
1202 err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1203 if (err) {
1204 goto out;
1205 }
1206 vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1207 err = vs->offset;
1208
1209 out:
1210 complete_pdu(s, vs->pdu, err);
1211 v9fs_stat_free(&vs->v9stat);
1212 qemu_free(vs);
1213 }
1214
1215 static void v9fs_stat(void *opaque)
1216 {
1217 V9fsPDU *pdu = opaque;
1218 V9fsState *s = pdu->s;
1219 int32_t fid;
1220 V9fsStatState *vs;
1221 ssize_t err = 0;
1222
1223 vs = qemu_malloc(sizeof(*vs));
1224 vs->pdu = pdu;
1225 vs->offset = 7;
1226
1227 memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1228
1229 pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1230
1231 vs->fidp = lookup_fid(s, fid);
1232 if (vs->fidp == NULL) {
1233 err = -ENOENT;
1234 goto out;
1235 }
1236
1237 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1238 v9fs_stat_post_lstat(s, vs, err);
1239 return;
1240
1241 out:
1242 complete_pdu(s, vs->pdu, err);
1243 v9fs_stat_free(&vs->v9stat);
1244 qemu_free(vs);
1245 }
1246
1247 static void v9fs_getattr(void *opaque)
1248 {
1249 int32_t fid;
1250 size_t offset = 7;
1251 ssize_t retval = 0;
1252 struct stat stbuf;
1253 V9fsFidState *fidp;
1254 uint64_t request_mask;
1255 V9fsStatDotl v9stat_dotl;
1256 V9fsPDU *pdu = opaque;
1257 V9fsState *s = pdu->s;
1258
1259 pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1260
1261 fidp = lookup_fid(s, fid);
1262 if (fidp == NULL) {
1263 retval = -ENOENT;
1264 goto out;
1265 }
1266 /*
1267 * Currently we only support BASIC fields in stat, so there is no
1268 * need to look at request_mask.
1269 */
1270 retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
1271 if (retval < 0) {
1272 goto out;
1273 }
1274 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1275 retval = offset;
1276 retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1277 out:
1278 complete_pdu(s, pdu, retval);
1279 }
1280
1281 /* From Linux kernel code */
1282 #define ATTR_MODE (1 << 0)
1283 #define ATTR_UID (1 << 1)
1284 #define ATTR_GID (1 << 2)
1285 #define ATTR_SIZE (1 << 3)
1286 #define ATTR_ATIME (1 << 4)
1287 #define ATTR_MTIME (1 << 5)
1288 #define ATTR_CTIME (1 << 6)
1289 #define ATTR_MASK 127
1290 #define ATTR_ATIME_SET (1 << 7)
1291 #define ATTR_MTIME_SET (1 << 8)
1292
1293 static void v9fs_setattr(void *opaque)
1294 {
1295 int err = 0;
1296 int32_t fid;
1297 V9fsFidState *fidp;
1298 size_t offset = 7;
1299 V9fsIattr v9iattr;
1300 V9fsPDU *pdu = opaque;
1301 V9fsState *s = pdu->s;
1302
1303 pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1304
1305 fidp = lookup_fid(s, fid);
1306 if (fidp == NULL) {
1307 err = -EINVAL;
1308 goto out;
1309 }
1310 if (v9iattr.valid & ATTR_MODE) {
1311 err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
1312 if (err < 0) {
1313 goto out;
1314 }
1315 }
1316 if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1317 struct timespec times[2];
1318 if (v9iattr.valid & ATTR_ATIME) {
1319 if (v9iattr.valid & ATTR_ATIME_SET) {
1320 times[0].tv_sec = v9iattr.atime_sec;
1321 times[0].tv_nsec = v9iattr.atime_nsec;
1322 } else {
1323 times[0].tv_nsec = UTIME_NOW;
1324 }
1325 } else {
1326 times[0].tv_nsec = UTIME_OMIT;
1327 }
1328 if (v9iattr.valid & ATTR_MTIME) {
1329 if (v9iattr.valid & ATTR_MTIME_SET) {
1330 times[1].tv_sec = v9iattr.mtime_sec;
1331 times[1].tv_nsec = v9iattr.mtime_nsec;
1332 } else {
1333 times[1].tv_nsec = UTIME_NOW;
1334 }
1335 } else {
1336 times[1].tv_nsec = UTIME_OMIT;
1337 }
1338 err = v9fs_co_utimensat(s, &fidp->path, times);
1339 if (err < 0) {
1340 goto out;
1341 }
1342 }
1343 /*
1344 * If the only valid entry in iattr is ctime we can call
1345 * chown(-1,-1) to update the ctime of the file
1346 */
1347 if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1348 ((v9iattr.valid & ATTR_CTIME)
1349 && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1350 if (!(v9iattr.valid & ATTR_UID)) {
1351 v9iattr.uid = -1;
1352 }
1353 if (!(v9iattr.valid & ATTR_GID)) {
1354 v9iattr.gid = -1;
1355 }
1356 err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
1357 v9iattr.gid);
1358 if (err < 0) {
1359 goto out;
1360 }
1361 }
1362 if (v9iattr.valid & (ATTR_SIZE)) {
1363 err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
1364 if (err < 0) {
1365 goto out;
1366 }
1367 }
1368 err = offset;
1369 out:
1370 complete_pdu(s, pdu, err);
1371 }
1372
1373 static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1374 {
1375 complete_pdu(s, vs->pdu, err);
1376
1377 if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
1378 for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1379 v9fs_string_free(&vs->wnames[vs->name_idx]);
1380 }
1381
1382 qemu_free(vs->wnames);
1383 qemu_free(vs->qids);
1384 }
1385 }
1386
1387 static void v9fs_walk_marshal(V9fsWalkState *vs)
1388 {
1389 int i;
1390 vs->offset = 7;
1391 vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1392
1393 for (i = 0; i < vs->nwnames; i++) {
1394 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1395 }
1396 }
1397
1398 static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1399 int err)
1400 {
1401 if (err == -1) {
1402 free_fid(s, vs->newfidp->fid);
1403 v9fs_string_free(&vs->path);
1404 err = -ENOENT;
1405 goto out;
1406 }
1407
1408 stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1409
1410 vs->name_idx++;
1411 if (vs->name_idx < vs->nwnames) {
1412 v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1413 vs->wnames[vs->name_idx].data);
1414 v9fs_string_copy(&vs->newfidp->path, &vs->path);
1415
1416 err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1417 v9fs_walk_post_newfid_lstat(s, vs, err);
1418 return;
1419 }
1420
1421 v9fs_string_free(&vs->path);
1422 v9fs_walk_marshal(vs);
1423 err = vs->offset;
1424 out:
1425 v9fs_walk_complete(s, vs, err);
1426 }
1427
1428 static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1429 int err)
1430 {
1431 if (err == -1) {
1432 v9fs_string_free(&vs->path);
1433 err = -ENOENT;
1434 goto out;
1435 }
1436
1437 stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1438 vs->name_idx++;
1439 if (vs->name_idx < vs->nwnames) {
1440
1441 v9fs_string_sprintf(&vs->path, "%s/%s",
1442 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1443 v9fs_string_copy(&vs->fidp->path, &vs->path);
1444
1445 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1446 v9fs_walk_post_oldfid_lstat(s, vs, err);
1447 return;
1448 }
1449
1450 v9fs_string_free(&vs->path);
1451 v9fs_walk_marshal(vs);
1452 err = vs->offset;
1453 out:
1454 v9fs_walk_complete(s, vs, err);
1455 }
1456
1457 static void v9fs_walk(void *opaque)
1458 {
1459 V9fsPDU *pdu = opaque;
1460 V9fsState *s = pdu->s;
1461 int32_t fid, newfid;
1462 V9fsWalkState *vs;
1463 int err = 0;
1464 int i;
1465
1466 vs = qemu_malloc(sizeof(*vs));
1467 vs->pdu = pdu;
1468 vs->wnames = NULL;
1469 vs->qids = NULL;
1470 vs->offset = 7;
1471
1472 vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1473 &newfid, &vs->nwnames);
1474
1475 if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
1476 vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1477
1478 vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1479
1480 for (i = 0; i < vs->nwnames; i++) {
1481 vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1482 &vs->wnames[i]);
1483 }
1484 } else if (vs->nwnames > P9_MAXWELEM) {
1485 err = -EINVAL;
1486 goto out;
1487 }
1488
1489 vs->fidp = lookup_fid(s, fid);
1490 if (vs->fidp == NULL) {
1491 err = -ENOENT;
1492 goto out;
1493 }
1494
1495 /* FIXME: is this really valid? */
1496 if (fid == newfid) {
1497
1498 BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1499 v9fs_string_init(&vs->path);
1500 vs->name_idx = 0;
1501
1502 if (vs->name_idx < vs->nwnames) {
1503 v9fs_string_sprintf(&vs->path, "%s/%s",
1504 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1505 v9fs_string_copy(&vs->fidp->path, &vs->path);
1506
1507 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1508 v9fs_walk_post_oldfid_lstat(s, vs, err);
1509 return;
1510 }
1511 } else {
1512 vs->newfidp = alloc_fid(s, newfid);
1513 if (vs->newfidp == NULL) {
1514 err = -EINVAL;
1515 goto out;
1516 }
1517
1518 vs->newfidp->uid = vs->fidp->uid;
1519 v9fs_string_init(&vs->path);
1520 vs->name_idx = 0;
1521 v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1522
1523 if (vs->name_idx < vs->nwnames) {
1524 v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1525 vs->wnames[vs->name_idx].data);
1526 v9fs_string_copy(&vs->newfidp->path, &vs->path);
1527
1528 err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1529 v9fs_walk_post_newfid_lstat(s, vs, err);
1530 return;
1531 }
1532 }
1533
1534 v9fs_walk_marshal(vs);
1535 err = vs->offset;
1536 out:
1537 v9fs_walk_complete(s, vs, err);
1538 }
1539
1540 static int32_t get_iounit(V9fsState *s, V9fsString *name)
1541 {
1542 struct statfs stbuf;
1543 int32_t iounit = 0;
1544
1545 /*
1546 * iounit should be multiples of f_bsize (host filesystem block size
1547 * and as well as less than (client msize - P9_IOHDRSZ))
1548 */
1549 if (!v9fs_do_statfs(s, name, &stbuf)) {
1550 iounit = stbuf.f_bsize;
1551 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1552 }
1553
1554 if (!iounit) {
1555 iounit = s->msize - P9_IOHDRSZ;
1556 }
1557 return iounit;
1558 }
1559
1560 static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1561 {
1562 if (vs->fidp->fs.dir == NULL) {
1563 err = -errno;
1564 goto out;
1565 }
1566 vs->fidp->fid_type = P9_FID_DIR;
1567 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1568 err = vs->offset;
1569 out:
1570 complete_pdu(s, vs->pdu, err);
1571 qemu_free(vs);
1572
1573 }
1574
1575 static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
1576 {
1577 int err;
1578 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
1579 err = vs->offset;
1580 complete_pdu(s, vs->pdu, err);
1581 qemu_free(vs);
1582 }
1583
1584 static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1585 {
1586 if (vs->fidp->fs.fd == -1) {
1587 err = -errno;
1588 goto out;
1589 }
1590 vs->fidp->fid_type = P9_FID_FILE;
1591 vs->iounit = get_iounit(s, &vs->fidp->path);
1592 v9fs_open_post_getiounit(s, vs);
1593 return;
1594 out:
1595 complete_pdu(s, vs->pdu, err);
1596 qemu_free(vs);
1597 }
1598
1599 static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1600 {
1601 int flags;
1602
1603 if (err) {
1604 err = -errno;
1605 goto out;
1606 }
1607
1608 stat_to_qid(&vs->stbuf, &vs->qid);
1609
1610 if (S_ISDIR(vs->stbuf.st_mode)) {
1611 vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
1612 v9fs_open_post_opendir(s, vs, err);
1613 } else {
1614 if (s->proto_version == V9FS_PROTO_2000L) {
1615 flags = vs->mode;
1616 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1617 /* Ignore direct disk access hint until the server supports it. */
1618 flags &= ~O_DIRECT;
1619 } else {
1620 flags = omode_to_uflags(vs->mode);
1621 }
1622 vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
1623 v9fs_open_post_open(s, vs, err);
1624 }
1625 return;
1626 out:
1627 complete_pdu(s, vs->pdu, err);
1628 qemu_free(vs);
1629 }
1630
1631 static void v9fs_open(void *opaque)
1632 {
1633 V9fsPDU *pdu = opaque;
1634 V9fsState *s = pdu->s;
1635 int32_t fid;
1636 V9fsOpenState *vs;
1637 ssize_t err = 0;
1638
1639 vs = qemu_malloc(sizeof(*vs));
1640 vs->pdu = pdu;
1641 vs->offset = 7;
1642 vs->mode = 0;
1643
1644 if (s->proto_version == V9FS_PROTO_2000L) {
1645 pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
1646 } else {
1647 pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1648 }
1649
1650 vs->fidp = lookup_fid(s, fid);
1651 if (vs->fidp == NULL) {
1652 err = -ENOENT;
1653 goto out;
1654 }
1655
1656 BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1657
1658 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1659
1660 v9fs_open_post_lstat(s, vs, err);
1661 return;
1662 out:
1663 complete_pdu(s, pdu, err);
1664 qemu_free(vs);
1665 }
1666
1667 static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
1668 {
1669 if (err == 0) {
1670 v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1671 stat_to_qid(&vs->stbuf, &vs->qid);
1672 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
1673 vs->iounit);
1674 err = vs->offset;
1675 } else {
1676 vs->fidp->fid_type = P9_FID_NONE;
1677 err = -errno;
1678 if (vs->fidp->fs.fd > 0) {
1679 close(vs->fidp->fs.fd);
1680 }
1681 }
1682
1683 complete_pdu(s, vs->pdu, err);
1684 v9fs_string_free(&vs->name);
1685 v9fs_string_free(&vs->fullname);
1686 qemu_free(vs);
1687 }
1688
1689 static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
1690 int err)
1691 {
1692 if (err) {
1693 err = -errno;
1694 goto out;
1695 }
1696 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1697
1698 out:
1699 v9fs_post_lcreate(s, vs, err);
1700 }
1701
1702 static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
1703 int err)
1704 {
1705 if (vs->fidp->fs.fd == -1) {
1706 err = -errno;
1707 goto out;
1708 }
1709 vs->fidp->fid_type = P9_FID_FILE;
1710 vs->iounit = get_iounit(s, &vs->fullname);
1711 v9fs_lcreate_post_get_iounit(s, vs, err);
1712 return;
1713
1714 out:
1715 v9fs_post_lcreate(s, vs, err);
1716 }
1717
1718 static void v9fs_lcreate(void *opaque)
1719 {
1720 V9fsPDU *pdu = opaque;
1721 V9fsState *s = pdu->s;
1722 int32_t dfid, flags, mode;
1723 gid_t gid;
1724 V9fsLcreateState *vs;
1725 ssize_t err = 0;
1726
1727 vs = qemu_malloc(sizeof(*vs));
1728 vs->pdu = pdu;
1729 vs->offset = 7;
1730
1731 v9fs_string_init(&vs->fullname);
1732
1733 pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
1734 &mode, &gid);
1735
1736 vs->fidp = lookup_fid(s, dfid);
1737 if (vs->fidp == NULL) {
1738 err = -ENOENT;
1739 goto out;
1740 }
1741
1742 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1743 vs->name.data);
1744
1745 /* Ignore direct disk access hint until the server supports it. */
1746 flags &= ~O_DIRECT;
1747
1748 vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
1749 gid, flags, mode);
1750 v9fs_lcreate_post_do_open2(s, vs, err);
1751 return;
1752
1753 out:
1754 complete_pdu(s, vs->pdu, err);
1755 v9fs_string_free(&vs->name);
1756 qemu_free(vs);
1757 }
1758
1759 static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
1760 {
1761 if (err == -1) {
1762 err = -errno;
1763 }
1764 complete_pdu(s, pdu, err);
1765 }
1766
1767 static void v9fs_fsync(void *opaque)
1768 {
1769 V9fsPDU *pdu = opaque;
1770 V9fsState *s = pdu->s;
1771 int32_t fid;
1772 size_t offset = 7;
1773 V9fsFidState *fidp;
1774 int datasync;
1775 int err;
1776
1777 pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1778 fidp = lookup_fid(s, fid);
1779 if (fidp == NULL) {
1780 err = -ENOENT;
1781 v9fs_post_do_fsync(s, pdu, err);
1782 return;
1783 }
1784 err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
1785 v9fs_post_do_fsync(s, pdu, err);
1786 }
1787
1788 static void v9fs_clunk(void *opaque)
1789 {
1790 V9fsPDU *pdu = opaque;
1791 V9fsState *s = pdu->s;
1792 int32_t fid;
1793 size_t offset = 7;
1794 int err;
1795
1796 pdu_unmarshal(pdu, offset, "d", &fid);
1797
1798 err = free_fid(s, fid);
1799 if (err < 0) {
1800 goto out;
1801 }
1802
1803 offset = 7;
1804 err = offset;
1805 out:
1806 complete_pdu(s, pdu, err);
1807 }
1808
1809 static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1810
1811 static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1812 {
1813 if (err) {
1814 goto out;
1815 }
1816 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1817 vs->offset += vs->count;
1818 err = vs->offset;
1819 out:
1820 complete_pdu(s, vs->pdu, err);
1821 v9fs_stat_free(&vs->v9stat);
1822 v9fs_string_free(&vs->name);
1823 qemu_free(vs);
1824 return;
1825 }
1826
1827 static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1828 ssize_t err)
1829 {
1830 if (err) {
1831 err = -errno;
1832 goto out;
1833 }
1834 err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1835 if (err) {
1836 goto out;
1837 }
1838
1839 vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1840 &vs->v9stat);
1841 if ((vs->len != (vs->v9stat.size + 2)) ||
1842 ((vs->count + vs->len) > vs->max_count)) {
1843 v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1844 v9fs_read_post_seekdir(s, vs, err);
1845 return;
1846 }
1847 vs->count += vs->len;
1848 v9fs_stat_free(&vs->v9stat);
1849 v9fs_string_free(&vs->name);
1850 vs->dir_pos = vs->dent->d_off;
1851 v9fs_co_readdir(s, vs->fidp, &vs->dent);
1852 v9fs_read_post_readdir(s, vs, err);
1853 return;
1854 out:
1855 v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1856 v9fs_read_post_seekdir(s, vs, err);
1857 return;
1858
1859 }
1860
1861 static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1862 {
1863 if (vs->dent) {
1864 memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1865 v9fs_string_init(&vs->name);
1866 v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1867 vs->dent->d_name);
1868 err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1869 v9fs_read_post_dir_lstat(s, vs, err);
1870 return;
1871 }
1872
1873 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1874 vs->offset += vs->count;
1875 err = vs->offset;
1876 complete_pdu(s, vs->pdu, err);
1877 qemu_free(vs);
1878 return;
1879 }
1880
1881 static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1882 {
1883 v9fs_co_readdir(s, vs->fidp, &vs->dent);
1884 v9fs_read_post_readdir(s, vs, err);
1885 return;
1886 }
1887
1888 static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1889 ssize_t err)
1890 {
1891 vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
1892 v9fs_read_post_telldir(s, vs, err);
1893 return;
1894 }
1895
1896 static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1897 {
1898 if (err < 0) {
1899 /* IO error return the error */
1900 err = -errno;
1901 goto out;
1902 }
1903 vs->total += vs->len;
1904 vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1905 if (vs->total < vs->count && vs->len > 0) {
1906 do {
1907 if (0) {
1908 print_sg(vs->sg, vs->cnt);
1909 }
1910 vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
1911 vs->off);
1912 if (vs->len > 0) {
1913 vs->off += vs->len;
1914 }
1915 } while (vs->len == -1 && errno == EINTR);
1916 if (vs->len == -1) {
1917 err = -errno;
1918 }
1919 v9fs_read_post_preadv(s, vs, err);
1920 return;
1921 }
1922 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1923 vs->offset += vs->count;
1924 err = vs->offset;
1925
1926 out:
1927 complete_pdu(s, vs->pdu, err);
1928 qemu_free(vs);
1929 }
1930
1931 static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
1932 {
1933 ssize_t err = 0;
1934 int read_count;
1935 int64_t xattr_len;
1936
1937 xattr_len = vs->fidp->fs.xattr.len;
1938 read_count = xattr_len - vs->off;
1939 if (read_count > vs->count) {
1940 read_count = vs->count;
1941 } else if (read_count < 0) {
1942 /*
1943 * read beyond XATTR value
1944 */
1945 read_count = 0;
1946 }
1947 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
1948 vs->offset += pdu_pack(vs->pdu, vs->offset,
1949 ((char *)vs->fidp->fs.xattr.value) + vs->off,
1950 read_count);
1951 err = vs->offset;
1952 complete_pdu(s, vs->pdu, err);
1953 qemu_free(vs);
1954 }
1955
1956 static void v9fs_read(void *opaque)
1957 {
1958 V9fsPDU *pdu = opaque;
1959 V9fsState *s = pdu->s;
1960 int32_t fid;
1961 V9fsReadState *vs;
1962 ssize_t err = 0;
1963
1964 vs = qemu_malloc(sizeof(*vs));
1965 vs->pdu = pdu;
1966 vs->offset = 7;
1967 vs->total = 0;
1968 vs->len = 0;
1969 vs->count = 0;
1970
1971 pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
1972
1973 vs->fidp = lookup_fid(s, fid);
1974 if (vs->fidp == NULL) {
1975 err = -EINVAL;
1976 goto out;
1977 }
1978
1979 if (vs->fidp->fid_type == P9_FID_DIR) {
1980 vs->max_count = vs->count;
1981 vs->count = 0;
1982 if (vs->off == 0) {
1983 v9fs_do_rewinddir(s, vs->fidp->fs.dir);
1984 }
1985 v9fs_read_post_rewinddir(s, vs, err);
1986 return;
1987 } else if (vs->fidp->fid_type == P9_FID_FILE) {
1988 vs->sg = vs->iov;
1989 pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
1990 vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1991 if (vs->total <= vs->count) {
1992 vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
1993 vs->off);
1994 if (vs->len > 0) {
1995 vs->off += vs->len;
1996 }
1997 err = vs->len;
1998 v9fs_read_post_preadv(s, vs, err);
1999 }
2000 return;
2001 } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2002 v9fs_xattr_read(s, vs);
2003 return;
2004 } else {
2005 err = -EINVAL;
2006 }
2007 out:
2008 complete_pdu(s, pdu, err);
2009 qemu_free(vs);
2010 }
2011
2012 static size_t v9fs_readdir_data_size(V9fsString *name)
2013 {
2014 /*
2015 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
2016 * size of type (1) + size of name.size (2) + strlen(name.data)
2017 */
2018 return 24 + v9fs_string_size(name);
2019 }
2020
2021 static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
2022 V9fsFidState *fidp, int32_t max_count)
2023 {
2024 size_t size;
2025 V9fsQID qid;
2026 V9fsString name;
2027 int len, err = 0;
2028 int32_t count = 0;
2029 off_t saved_dir_pos;
2030 struct dirent *dent;
2031
2032 /* save the directory position */
2033 saved_dir_pos = v9fs_co_telldir(s, fidp);
2034 if (saved_dir_pos < 0) {
2035 return saved_dir_pos;
2036 }
2037 while (1) {
2038 err = v9fs_co_readdir(s, fidp, &dent);
2039 if (err || !dent) {
2040 break;
2041 }
2042 v9fs_string_init(&name);
2043 v9fs_string_sprintf(&name, "%s", dent->d_name);
2044 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
2045 /* Ran out of buffer. Set dir back to old position and return */
2046 v9fs_co_seekdir(s, fidp, saved_dir_pos);
2047 v9fs_string_free(&name);
2048 return count;
2049 }
2050 /*
2051 * Fill up just the path field of qid because the client uses
2052 * only that. To fill the entire qid structure we will have
2053 * to stat each dirent found, which is expensive
2054 */
2055 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
2056 memcpy(&qid.path, &dent->d_ino, size);
2057 /* Fill the other fields with dummy values */
2058 qid.type = 0;
2059 qid.version = 0;
2060
2061 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
2062 len = pdu_marshal(pdu, 11 + count, "Qqbs",
2063 &qid, dent->d_off,
2064 dent->d_type, &name);
2065 count += len;
2066 v9fs_string_free(&name);
2067 saved_dir_pos = dent->d_off;
2068 }
2069 if (err < 0) {
2070 return err;
2071 }
2072 return count;
2073 }
2074
2075 static void v9fs_readdir(void *opaque)
2076 {
2077 int32_t fid;
2078 V9fsFidState *fidp;
2079 ssize_t retval = 0;
2080 size_t offset = 7;
2081 int64_t initial_offset;
2082 int32_t count, max_count;
2083 V9fsPDU *pdu = opaque;
2084 V9fsState *s = pdu->s;
2085
2086 pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
2087
2088 fidp = lookup_fid(s, fid);
2089 if (fidp == NULL || !fidp->fs.dir) {
2090 retval = -EINVAL;
2091 goto out;
2092 }
2093 if (initial_offset == 0) {
2094 v9fs_co_rewinddir(s, fidp);
2095 } else {
2096 v9fs_co_seekdir(s, fidp, initial_offset);
2097 }
2098 count = v9fs_do_readdir(s, pdu, fidp, max_count);
2099 if (count < 0) {
2100 retval = count;
2101 goto out;
2102 }
2103 retval = offset;
2104 retval += pdu_marshal(pdu, offset, "d", count);
2105 retval += count;
2106 out:
2107 complete_pdu(s, pdu, retval);
2108 }
2109
2110 static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
2111 ssize_t err)
2112 {
2113 if (err < 0) {
2114 /* IO error return the error */
2115 err = -errno;
2116 goto out;
2117 }
2118 vs->total += vs->len;
2119 vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2120 if (vs->total < vs->count && vs->len > 0) {
2121 do {
2122 if (0) {
2123 print_sg(vs->sg, vs->cnt);
2124 }
2125 vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2126 vs->off);
2127 if (vs->len > 0) {
2128 vs->off += vs->len;
2129 }
2130 } while (vs->len == -1 && errno == EINTR);
2131 if (vs->len == -1) {
2132 err = -errno;
2133 }
2134 v9fs_write_post_pwritev(s, vs, err);
2135 return;
2136 }
2137 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2138 err = vs->offset;
2139 out:
2140 complete_pdu(s, vs->pdu, err);
2141 qemu_free(vs);
2142 }
2143
2144 static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
2145 {
2146 int i, to_copy;
2147 ssize_t err = 0;
2148 int write_count;
2149 int64_t xattr_len;
2150
2151 xattr_len = vs->fidp->fs.xattr.len;
2152 write_count = xattr_len - vs->off;
2153 if (write_count > vs->count) {
2154 write_count = vs->count;
2155 } else if (write_count < 0) {
2156 /*
2157 * write beyond XATTR value len specified in
2158 * xattrcreate
2159 */
2160 err = -ENOSPC;
2161 goto out;
2162 }
2163 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
2164 err = vs->offset;
2165 vs->fidp->fs.xattr.copied_len += write_count;
2166 /*
2167 * Now copy the content from sg list
2168 */
2169 for (i = 0; i < vs->cnt; i++) {
2170 if (write_count > vs->sg[i].iov_len) {
2171 to_copy = vs->sg[i].iov_len;
2172 } else {
2173 to_copy = write_count;
2174 }
2175 memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
2176 vs->sg[i].iov_base, to_copy);
2177 /* updating vs->off since we are not using below */
2178 vs->off += to_copy;
2179 write_count -= to_copy;
2180 }
2181 out:
2182 complete_pdu(s, vs->pdu, err);
2183 qemu_free(vs);
2184 }
2185
2186 static void v9fs_write(void *opaque)
2187 {
2188 V9fsPDU *pdu = opaque;
2189 V9fsState *s = pdu->s;
2190 int32_t fid;
2191 V9fsWriteState *vs;
2192 ssize_t err;
2193
2194 vs = qemu_malloc(sizeof(*vs));
2195
2196 vs->pdu = pdu;
2197 vs->offset = 7;
2198 vs->sg = vs->iov;
2199 vs->total = 0;
2200 vs->len = 0;
2201
2202 pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
2203 vs->sg, &vs->cnt);
2204
2205 vs->fidp = lookup_fid(s, fid);
2206 if (vs->fidp == NULL) {
2207 err = -EINVAL;
2208 goto out;
2209 }
2210
2211 if (vs->fidp->fid_type == P9_FID_FILE) {
2212 if (vs->fidp->fs.fd == -1) {
2213 err = -EINVAL;
2214 goto out;
2215 }
2216 } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2217 /*
2218 * setxattr operation
2219 */
2220 v9fs_xattr_write(s, vs);
2221 return;
2222 } else {
2223 err = -EINVAL;
2224 goto out;
2225 }
2226 vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2227 if (vs->total <= vs->count) {
2228 vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
2229 if (vs->len > 0) {
2230 vs->off += vs->len;
2231 }
2232 err = vs->len;
2233 v9fs_write_post_pwritev(s, vs, err);
2234 }
2235 return;
2236 out:
2237 complete_pdu(s, vs->pdu, err);
2238 qemu_free(vs);
2239 }
2240
2241 static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
2242 {
2243 int err;
2244 v9fs_string_copy(&vs->fidp->path, &vs->fullname);
2245 stat_to_qid(&vs->stbuf, &vs->qid);
2246
2247 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
2248 err = vs->offset;
2249
2250 complete_pdu(s, vs->pdu, err);
2251 v9fs_string_free(&vs->name);
2252 v9fs_string_free(&vs->extension);
2253 v9fs_string_free(&vs->fullname);
2254 qemu_free(vs);
2255 }
2256
2257 static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
2258 {
2259 if (err == 0) {
2260 vs->iounit = get_iounit(s, &vs->fidp->path);
2261 v9fs_create_post_getiounit(s, vs);
2262 return;
2263 }
2264
2265 complete_pdu(s, vs->pdu, err);
2266 v9fs_string_free(&vs->name);
2267 v9fs_string_free(&vs->extension);
2268 v9fs_string_free(&vs->fullname);
2269 qemu_free(vs);
2270 }
2271
2272 static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
2273 {
2274 if (err) {
2275 err = -errno;
2276 }
2277 v9fs_post_create(s, vs, err);
2278 }
2279
2280 static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
2281 int err)
2282 {
2283 if (!vs->fidp->fs.dir) {
2284 err = -errno;
2285 }
2286 vs->fidp->fid_type = P9_FID_DIR;
2287 v9fs_post_create(s, vs, err);
2288 }
2289
2290 static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
2291 int err)
2292 {
2293 if (err) {
2294 err = -errno;
2295 goto out;
2296 }
2297
2298 vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
2299 v9fs_create_post_opendir(s, vs, err);
2300 return;
2301
2302 out:
2303 v9fs_post_create(s, vs, err);
2304 }
2305
2306 static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
2307 {
2308 if (err < 0) {
2309 goto out;
2310 }
2311
2312 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2313 v9fs_create_post_dir_lstat(s, vs, err);
2314 return;
2315
2316 out:
2317 v9fs_post_create(s, vs, err);
2318 }
2319
2320 static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
2321 {
2322 if (err) {
2323 vs->fidp->fid_type = P9_FID_NONE;
2324 close(vs->fidp->fs.fd);
2325 err = -errno;
2326 }
2327 v9fs_post_create(s, vs, err);
2328 return;
2329 }
2330
2331 static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
2332 {
2333 if (vs->fidp->fs.fd == -1) {
2334 err = -errno;
2335 goto out;
2336 }
2337 vs->fidp->fid_type = P9_FID_FILE;
2338 err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
2339 v9fs_create_post_fstat(s, vs, err);
2340
2341 return;
2342
2343 out:
2344 v9fs_post_create(s, vs, err);
2345
2346 }
2347
2348 static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
2349 {
2350
2351 if (err == 0 || errno != ENOENT) {
2352 err = -errno;
2353 goto out;
2354 }
2355
2356 if (vs->perm & P9_STAT_MODE_DIR) {
2357 err = v9fs_co_mkdir(s, vs->fullname.data, vs->perm & 0777,
2358 vs->fidp->uid, -1);
2359 v9fs_create_post_mkdir(s, vs, err);
2360 } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
2361 err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
2362 vs->fullname.data, -1);
2363 v9fs_create_post_perms(s, vs, err);
2364 } else if (vs->perm & P9_STAT_MODE_LINK) {
2365 int32_t nfid = atoi(vs->extension.data);
2366 V9fsFidState *nfidp = lookup_fid(s, nfid);
2367 if (nfidp == NULL) {
2368 err = -errno;
2369 v9fs_post_create(s, vs, err);
2370 }
2371 err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
2372 v9fs_create_post_perms(s, vs, err);
2373 } else if (vs->perm & P9_STAT_MODE_DEVICE) {
2374 char ctype;
2375 uint32_t major, minor;
2376 mode_t nmode = 0;
2377
2378 if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
2379 &minor) != 3) {
2380 err = -errno;
2381 v9fs_post_create(s, vs, err);
2382 }
2383
2384 switch (ctype) {
2385 case 'c':
2386 nmode = S_IFCHR;
2387 break;
2388 case 'b':
2389 nmode = S_IFBLK;
2390 break;
2391 default:
2392 err = -EIO;
2393 v9fs_post_create(s, vs, err);
2394 }
2395
2396 nmode |= vs->perm & 0777;
2397 err = v9fs_do_mknod(s, vs->fullname.data, nmode,
2398 makedev(major, minor), vs->fidp->uid, -1);
2399 v9fs_create_post_perms(s, vs, err);
2400 } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
2401 err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
2402 0, vs->fidp->uid, -1);
2403 v9fs_post_create(s, vs, err);
2404 } else if (vs->perm & P9_STAT_MODE_SOCKET) {
2405 err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
2406 0, vs->fidp->uid, -1);
2407 v9fs_post_create(s, vs, err);
2408 } else {
2409 vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
2410 -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
2411
2412 v9fs_create_post_open2(s, vs, err);
2413 }
2414
2415 return;
2416
2417 out:
2418 v9fs_post_create(s, vs, err);
2419 }
2420
2421 static void v9fs_create(void *opaque)
2422 {
2423 V9fsPDU *pdu = opaque;
2424 V9fsState *s = pdu->s;
2425 int32_t fid;
2426 V9fsCreateState *vs;
2427 int err = 0;
2428
2429 vs = qemu_malloc(sizeof(*vs));
2430 vs->pdu = pdu;
2431 vs->offset = 7;
2432
2433 v9fs_string_init(&vs->fullname);
2434
2435 pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
2436 &vs->perm, &vs->mode, &vs->extension);
2437
2438 vs->fidp = lookup_fid(s, fid);
2439 if (vs->fidp == NULL) {
2440 err = -EINVAL;
2441 goto out;
2442 }
2443
2444 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
2445 vs->name.data);
2446
2447 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2448 v9fs_create_post_lstat(s, vs, err);
2449 return;
2450
2451 out:
2452 complete_pdu(s, vs->pdu, err);
2453 v9fs_string_free(&vs->name);
2454 v9fs_string_free(&vs->extension);
2455 qemu_free(vs);
2456 }
2457
2458 static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
2459 {
2460 if (err == 0) {
2461 stat_to_qid(&vs->stbuf, &vs->qid);
2462 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
2463 err = vs->offset;
2464 } else {
2465 err = -errno;
2466 }
2467 complete_pdu(s, vs->pdu, err);
2468 v9fs_string_free(&vs->name);
2469 v9fs_string_free(&vs->symname);
2470 v9fs_string_free(&vs->fullname);
2471 qemu_free(vs);
2472 }
2473
2474 static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
2475 int err)
2476 {
2477 if (err) {
2478 goto out;
2479 }
2480 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2481 out:
2482 v9fs_post_symlink(s, vs, err);
2483 }
2484
2485 static void v9fs_symlink(void *opaque)
2486 {
2487 V9fsPDU *pdu = opaque;
2488 V9fsState *s = pdu->s;
2489 int32_t dfid;
2490 V9fsSymlinkState *vs;
2491 int err = 0;
2492 gid_t gid;
2493
2494 vs = qemu_malloc(sizeof(*vs));
2495 vs->pdu = pdu;
2496 vs->offset = 7;
2497
2498 v9fs_string_init(&vs->fullname);
2499
2500 pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
2501 &vs->symname, &gid);
2502
2503 vs->dfidp = lookup_fid(s, dfid);
2504 if (vs->dfidp == NULL) {
2505 err = -EINVAL;
2506 goto out;
2507 }
2508
2509 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
2510 vs->name.data);
2511 err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
2512 vs->fullname.data, gid);
2513 v9fs_symlink_post_do_symlink(s, vs, err);
2514 return;
2515
2516 out:
2517 complete_pdu(s, vs->pdu, err);
2518 v9fs_string_free(&vs->name);
2519 v9fs_string_free(&vs->symname);
2520 qemu_free(vs);
2521 }
2522
2523 static void v9fs_flush(void *opaque)
2524 {
2525 V9fsPDU *pdu = opaque;
2526 V9fsState *s = pdu->s;
2527 /* A nop call with no return */
2528 complete_pdu(s, pdu, 7);
2529 return;
2530 }
2531
2532 static void v9fs_link(void *opaque)
2533 {
2534 V9fsPDU *pdu = opaque;
2535 V9fsState *s = pdu->s;
2536 int32_t dfid, oldfid;
2537 V9fsFidState *dfidp, *oldfidp;
2538 V9fsString name, fullname;
2539 size_t offset = 7;
2540 int err = 0;
2541
2542 v9fs_string_init(&fullname);
2543
2544 pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2545
2546 dfidp = lookup_fid(s, dfid);
2547 if (dfidp == NULL) {
2548 err = -errno;
2549 goto out;
2550 }
2551
2552 oldfidp = lookup_fid(s, oldfid);
2553 if (oldfidp == NULL) {
2554 err = -errno;
2555 goto out;
2556 }
2557
2558 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2559 err = offset;
2560 err = v9fs_do_link(s, &oldfidp->path, &fullname);
2561 if (err) {
2562 err = -errno;
2563 }
2564 v9fs_string_free(&fullname);
2565
2566 out:
2567 v9fs_string_free(&name);
2568 complete_pdu(s, pdu, err);
2569 }
2570
2571 static void v9fs_remove(void *opaque)
2572 {
2573 int32_t fid;
2574 int err = 0;
2575 size_t offset = 7;
2576 V9fsFidState *fidp;
2577 V9fsPDU *pdu = opaque;
2578
2579 pdu_unmarshal(pdu, offset, "d", &fid);
2580
2581 fidp = lookup_fid(pdu->s, fid);
2582 if (fidp == NULL) {
2583 err = -EINVAL;
2584 goto out;
2585 }
2586 err = v9fs_co_remove(pdu->s, &fidp->path);
2587 if (!err) {
2588 err = offset;
2589 }
2590
2591 /* For TREMOVE we need to clunk the fid even on failed remove */
2592 free_fid(pdu->s, fidp->fid);
2593 out:
2594 complete_pdu(pdu->s, pdu, err);
2595 }
2596
2597 static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
2598 {
2599 if (err < 0) {
2600 goto out;
2601 }
2602
2603 err = vs->offset;
2604
2605 out:
2606 v9fs_stat_free(&vs->v9stat);
2607 complete_pdu(s, vs->pdu, err);
2608 qemu_free(vs);
2609 }
2610
2611 static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
2612 {
2613 if (err < 0) {
2614 goto out;
2615 }
2616 if (vs->v9stat.length != -1) {
2617 if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
2618 err = -errno;
2619 }
2620 }
2621 v9fs_wstat_post_truncate(s, vs, err);
2622 return;
2623
2624 out:
2625 v9fs_stat_free(&vs->v9stat);
2626 complete_pdu(s, vs->pdu, err);
2627 qemu_free(vs);
2628 }
2629
2630 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
2631 int32_t newdirfid, V9fsString *name)
2632 {
2633 char *end;
2634 int err = 0;
2635 char *old_name, *new_name;
2636
2637 if (newdirfid != -1) {
2638 V9fsFidState *dirfidp;
2639 dirfidp = lookup_fid(s, newdirfid);
2640 if (dirfidp == NULL) {
2641 err = -ENOENT;
2642 goto out;
2643 }
2644 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2645
2646 new_name = qemu_mallocz(dirfidp->path.size + name->size + 2);
2647
2648 strcpy(new_name, dirfidp->path.data);
2649 strcat(new_name, "/");
2650 strcat(new_name + dirfidp->path.size, name->data);
2651 } else {
2652 old_name = fidp->path.data;
2653 end = strrchr(old_name, '/');
2654 if (end) {
2655 end++;
2656 } else {
2657 end = old_name;
2658 }
2659 new_name = qemu_mallocz(end - old_name + name->size + 1);
2660
2661 strncat(new_name, old_name, end - old_name);
2662 strncat(new_name + (end - old_name), name->data, name->size);
2663 }
2664
2665 v9fs_string_free(name);
2666 name->data = new_name;
2667 name->size = strlen(new_name);
2668
2669 if (strcmp(new_name, fidp->path.data) != 0) {
2670 err = v9fs_co_rename(s, &fidp->path, name);
2671 if (err < 0) {
2672 goto out;
2673 }
2674 V9fsFidState *tfidp;
2675 /*
2676 * Fixup fid's pointing to the old name to
2677 * start pointing to the new name
2678 */
2679 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2680 if (fidp == tfidp) {
2681 /*
2682 * we replace name of this fid towards the end
2683 * so that our below strcmp will work
2684 */
2685 continue;
2686 }
2687 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2688 /* replace the name */
2689 v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
2690 }
2691 }
2692 v9fs_string_copy(&fidp->path, name);
2693 }
2694 out:
2695 return err;
2696 }
2697
2698 static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
2699 {
2700 if (err < 0) {
2701 goto out;
2702 }
2703
2704 if (vs->v9stat.name.size != 0) {
2705 err = v9fs_complete_rename(s, vs->fidp, -1, &vs->v9stat.name);
2706 }
2707 v9fs_wstat_post_rename(s, vs, err);
2708 return;
2709
2710 out:
2711 v9fs_stat_free(&vs->v9stat);
2712 complete_pdu(s, vs->pdu, err);
2713 qemu_free(vs);
2714 }
2715
2716 static void v9fs_rename(void *opaque)
2717 {
2718 int32_t fid;
2719 ssize_t err = 0;
2720 size_t offset = 7;
2721 V9fsString name;
2722 int32_t newdirfid;
2723 V9fsFidState *fidp;
2724 V9fsPDU *pdu = opaque;
2725 V9fsState *s = pdu->s;
2726
2727 pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2728
2729 fidp = lookup_fid(s, fid);
2730 if (fidp == NULL) {
2731 err = -ENOENT;
2732 goto out;
2733 }
2734 BUG_ON(fidp->fid_type != P9_FID_NONE);
2735
2736 err = v9fs_complete_rename(s, fidp, newdirfid, &name);
2737 if (!err) {
2738 err = offset;
2739 }
2740 out:
2741 complete_pdu(s, pdu, err);
2742 v9fs_string_free(&name);
2743 }
2744
2745 static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2746 {
2747 if (err < 0) {
2748 goto out;
2749 }
2750
2751 if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
2752 if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2753 vs->v9stat.n_gid)) {
2754 err = -errno;
2755 }
2756 }
2757 v9fs_wstat_post_chown(s, vs, err);
2758 return;
2759
2760 out:
2761 v9fs_stat_free(&vs->v9stat);
2762 complete_pdu(s, vs->pdu, err);
2763 qemu_free(vs);
2764 }
2765
2766 static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2767 {
2768 if (err < 0) {
2769 goto out;
2770 }
2771
2772 if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
2773 struct timespec times[2];
2774 if (vs->v9stat.atime != -1) {
2775 times[0].tv_sec = vs->v9stat.atime;
2776 times[0].tv_nsec = 0;
2777 } else {
2778 times[0].tv_nsec = UTIME_OMIT;
2779 }
2780 if (vs->v9stat.mtime != -1) {
2781 times[1].tv_sec = vs->v9stat.mtime;
2782 times[1].tv_nsec = 0;
2783 } else {
2784 times[1].tv_nsec = UTIME_OMIT;
2785 }
2786
2787 if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
2788 err = -errno;
2789 }
2790 }
2791
2792 v9fs_wstat_post_utime(s, vs, err);
2793 return;
2794
2795 out:
2796 v9fs_stat_free(&vs->v9stat);
2797 complete_pdu(s, vs->pdu, err);
2798 qemu_free(vs);
2799 }
2800
2801 static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2802 {
2803 if (err == -1) {
2804 err = -errno;
2805 }
2806 v9fs_stat_free(&vs->v9stat);
2807 complete_pdu(s, vs->pdu, err);
2808 qemu_free(vs);
2809 }
2810
2811 static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2812 {
2813 uint32_t v9_mode;
2814
2815 if (err == -1) {
2816 err = -errno;
2817 goto out;
2818 }
2819
2820 v9_mode = stat_to_v9mode(&vs->stbuf);
2821
2822 if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2823 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2824 /* Attempting to change the type */
2825 err = -EIO;
2826 goto out;
2827 }
2828
2829 if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2830 &vs->v9stat.extension))) {
2831 err = -errno;
2832 }
2833 v9fs_wstat_post_chmod(s, vs, err);
2834 return;
2835
2836 out:
2837 v9fs_stat_free(&vs->v9stat);
2838 complete_pdu(s, vs->pdu, err);
2839 qemu_free(vs);
2840 }
2841
2842 static void v9fs_wstat(void *opaque)
2843 {
2844 V9fsPDU *pdu = opaque;
2845 V9fsState *s = pdu->s;
2846 int32_t fid;
2847 V9fsWstatState *vs;
2848 int err = 0;
2849
2850 vs = qemu_malloc(sizeof(*vs));
2851 vs->pdu = pdu;
2852 vs->offset = 7;
2853
2854 pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
2855
2856 vs->fidp = lookup_fid(s, fid);
2857 if (vs->fidp == NULL) {
2858 err = -EINVAL;
2859 goto out;
2860 }
2861
2862 /* do we need to sync the file? */
2863 if (donttouch_stat(&vs->v9stat)) {
2864 err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
2865 v9fs_wstat_post_fsync(s, vs, err);
2866 return;
2867 }
2868
2869 if (vs->v9stat.mode != -1) {
2870 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2871 v9fs_wstat_post_lstat(s, vs, err);
2872 return;
2873 }
2874
2875 v9fs_wstat_post_chmod(s, vs, err);
2876 return;
2877
2878 out:
2879 v9fs_stat_free(&vs->v9stat);
2880 complete_pdu(s, vs->pdu, err);
2881 qemu_free(vs);
2882 }
2883
2884 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2885 {
2886 uint32_t f_type;
2887 uint32_t f_bsize;
2888 uint64_t f_blocks;
2889 uint64_t f_bfree;
2890 uint64_t f_bavail;
2891 uint64_t f_files;
2892 uint64_t f_ffree;
2893 uint64_t fsid_val;
2894 uint32_t f_namelen;
2895 size_t offset = 7;
2896 int32_t bsize_factor;
2897
2898 /*
2899 * compute bsize factor based on host file system block size
2900 * and client msize
2901 */
2902 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2903 if (!bsize_factor) {
2904 bsize_factor = 1;
2905 }
2906 f_type = stbuf->f_type;
2907 f_bsize = stbuf->f_bsize;
2908 f_bsize *= bsize_factor;
2909 /*
2910 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2911 * adjust(divide) the number of blocks, free blocks and available
2912 * blocks by bsize factor
2913 */
2914 f_blocks = stbuf->f_blocks/bsize_factor;
2915 f_bfree = stbuf->f_bfree/bsize_factor;
2916 f_bavail = stbuf->f_bavail/bsize_factor;
2917 f_files = stbuf->f_files;
2918 f_ffree = stbuf->f_ffree;
2919 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2920 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2921 f_namelen = stbuf->f_namelen;
2922
2923 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2924 f_type, f_bsize, f_blocks, f_bfree,
2925 f_bavail, f_files, f_ffree,
2926 fsid_val, f_namelen);
2927 }
2928
2929 static void v9fs_statfs(void *opaque)
2930 {
2931 int32_t fid;
2932 ssize_t retval = 0;
2933 size_t offset = 7;
2934 V9fsFidState *fidp;
2935 struct statfs stbuf;
2936 V9fsPDU *pdu = opaque;
2937 V9fsState *s = pdu->s;
2938
2939 pdu_unmarshal(pdu, offset, "d", &fid);
2940 fidp = lookup_fid(s, fid);
2941 if (fidp == NULL) {
2942 retval = -ENOENT;
2943 goto out;
2944 }
2945 retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2946 if (retval < 0) {
2947 goto out;
2948 }
2949 retval = offset;
2950 retval += v9fs_fill_statfs(s, pdu, &stbuf);
2951 out:
2952 complete_pdu(s, pdu, retval);
2953 return;
2954 }
2955
2956 static void v9fs_mknod(void *opaque)
2957 {
2958
2959 int mode;
2960 gid_t gid;
2961 int32_t fid;
2962 V9fsQID qid;
2963 int err = 0;
2964 int major, minor;
2965 size_t offset = 7;
2966 V9fsString name;
2967 struct stat stbuf;
2968 V9fsString fullname;
2969 V9fsFidState *fidp;
2970 V9fsPDU *pdu = opaque;
2971 V9fsState *s = pdu->s;
2972
2973 v9fs_string_init(&fullname);
2974 pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2975 &major, &minor, &gid);
2976
2977 fidp = lookup_fid(s, fid);
2978 if (fidp == NULL) {
2979 err = -ENOENT;
2980 goto out;
2981 }
2982 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2983 err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
2984 makedev(major, minor), mode);
2985 if (err < 0) {
2986 goto out;
2987 }
2988 err = v9fs_co_lstat(s, &fullname, &stbuf);
2989 if (err < 0) {
2990 goto out;
2991 }
2992 stat_to_qid(&stbuf, &qid);
2993 err = offset;
2994 err += pdu_marshal(pdu, offset, "Q", &qid);
2995 out:
2996 complete_pdu(s, pdu, err);
2997 v9fs_string_free(&fullname);
2998 v9fs_string_free(&name);
2999 }
3000
3001 /*
3002 * Implement posix byte range locking code
3003 * Server side handling of locking code is very simple, because 9p server in
3004 * QEMU can handle only one client. And most of the lock handling
3005 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
3006 * do any thing in * qemu 9p server side lock code path.
3007 * So when a TLOCK request comes, always return success
3008 */
3009
3010 static void v9fs_lock(void *opaque)
3011 {
3012 V9fsPDU *pdu = opaque;
3013 V9fsState *s = pdu->s;
3014 int32_t fid, err = 0;
3015 V9fsLockState *vs;
3016
3017 vs = qemu_mallocz(sizeof(*vs));
3018 vs->pdu = pdu;
3019 vs->offset = 7;
3020
3021 vs->flock = qemu_malloc(sizeof(*vs->flock));
3022 pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
3023 &vs->flock->flags, &vs->flock->start, &vs->flock->length,
3024 &vs->flock->proc_id, &vs->flock->client_id);
3025
3026 vs->status = P9_LOCK_ERROR;
3027
3028 /* We support only block flag now (that too ignored currently) */
3029 if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
3030 err = -EINVAL;
3031 goto out;
3032 }
3033 vs->fidp = lookup_fid(s, fid);
3034 if (vs->fidp == NULL) {
3035 err = -ENOENT;
3036 goto out;
3037 }
3038
3039 err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
3040 if (err < 0) {
3041 err = -errno;
3042 goto out;
3043 }
3044 vs->status = P9_LOCK_SUCCESS;
3045 out:
3046 vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
3047 complete_pdu(s, vs->pdu, err);
3048 qemu_free(vs->flock);
3049 qemu_free(vs);
3050 }
3051
3052 /*
3053 * When a TGETLOCK request comes, always return success because all lock
3054 * handling is done by client's VFS layer.
3055 */
3056
3057 static void v9fs_getlock(void *opaque)
3058 {
3059 V9fsPDU *pdu = opaque;
3060 V9fsState *s = pdu->s;
3061 int32_t fid, err = 0;
3062 V9fsGetlockState *vs;
3063
3064 vs = qemu_mallocz(sizeof(*vs));
3065 vs->pdu = pdu;
3066 vs->offset = 7;
3067
3068 vs->glock = qemu_malloc(sizeof(*vs->glock));
3069 pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
3070 &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
3071 &vs->glock->client_id);
3072
3073 vs->fidp = lookup_fid(s, fid);
3074 if (vs->fidp == NULL) {
3075 err = -ENOENT;
3076 goto out;
3077 }
3078
3079 err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
3080 if (err < 0) {
3081 err = -errno;
3082 goto out;
3083 }
3084 vs->glock->type = F_UNLCK;
3085 vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
3086 vs->glock->start, vs->glock->length, vs->glock->proc_id,
3087 &vs->glock->client_id);
3088 out:
3089 complete_pdu(s, vs->pdu, err);
3090 qemu_free(vs->glock);
3091 qemu_free(vs);
3092 }
3093
3094 static void v9fs_mkdir(void *opaque)
3095 {
3096 V9fsPDU *pdu = opaque;
3097 size_t offset = 7;
3098 int32_t fid;
3099 struct stat stbuf;
3100 V9fsString name, fullname;
3101 V9fsQID qid;
3102 V9fsFidState *fidp;
3103 gid_t gid;
3104 int mode;
3105 int err = 0;
3106
3107 v9fs_string_init(&fullname);
3108 pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3109
3110 fidp = lookup_fid(pdu->s, fid);
3111 if (fidp == NULL) {
3112 err = -ENOENT;
3113 goto out;
3114 }
3115 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
3116 err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
3117 if (err < 0) {
3118 goto out;
3119 }
3120 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
3121 if (err < 0) {
3122 goto out;
3123 }
3124 stat_to_qid(&stbuf, &qid);
3125 offset += pdu_marshal(pdu, offset, "Q", &qid);
3126 err = offset;
3127 out:
3128 complete_pdu(pdu->s, pdu, err);
3129 v9fs_string_free(&fullname);
3130 v9fs_string_free(&name);
3131 }
3132
3133 static void v9fs_xattrwalk(void *opaque)
3134 {
3135 int64_t size;
3136 V9fsString name;
3137 ssize_t err = 0;
3138 size_t offset = 7;
3139 int32_t fid, newfid;
3140 V9fsFidState *file_fidp;
3141 V9fsFidState *xattr_fidp;
3142 V9fsPDU *pdu = opaque;
3143 V9fsState *s = pdu->s;
3144
3145 pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3146 file_fidp = lookup_fid(s, fid);
3147 if (file_fidp == NULL) {
3148 err = -ENOENT;
3149 goto out;
3150 }
3151 xattr_fidp = alloc_fid(s, newfid);
3152 if (xattr_fidp == NULL) {
3153 err = -EINVAL;
3154 goto out;
3155 }
3156 v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
3157 if (name.data[0] == 0) {
3158 /*
3159 * listxattr request. Get the size first
3160 */
3161 size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
3162 if (size < 0) {
3163 err = size;
3164 free_fid(s, xattr_fidp->fid);
3165 goto out;
3166 }
3167 /*
3168 * Read the xattr value
3169 */
3170 xattr_fidp->fs.xattr.len = size;
3171 xattr_fidp->fid_type = P9_FID_XATTR;
3172 xattr_fidp->fs.xattr.copied_len = -1;
3173 if (size) {
3174 xattr_fidp->fs.xattr.value = qemu_malloc(size);
3175 err = v9fs_co_llistxattr(s, &xattr_fidp->path,
3176 xattr_fidp->fs.xattr.value,
3177 xattr_fidp->fs.xattr.len);
3178 if (err < 0) {
3179 free_fid(s, xattr_fidp->fid);
3180 goto out;
3181 }
3182 }
3183 offset += pdu_marshal(pdu, offset, "q", size);
3184 err = offset;
3185 } else {
3186 /*
3187 * specific xattr fid. We check for xattr
3188 * presence also collect the xattr size
3189 */
3190 size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
3191 &name, NULL, 0);
3192 if (size < 0) {
3193 err = size;
3194 free_fid(s, xattr_fidp->fid);
3195 goto out;
3196 }
3197 /*
3198 * Read the xattr value
3199 */
3200 xattr_fidp->fs.xattr.len = size;
3201 xattr_fidp->fid_type = P9_FID_XATTR;
3202 xattr_fidp->fs.xattr.copied_len = -1;
3203 if (size) {
3204 xattr_fidp->fs.xattr.value = qemu_malloc(size);
3205 err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
3206 &name, xattr_fidp->fs.xattr.value,
3207 xattr_fidp->fs.xattr.len);
3208 if (err < 0) {
3209 free_fid(s, xattr_fidp->fid);
3210 goto out;
3211 }
3212 }
3213 offset += pdu_marshal(pdu, offset, "q", size);
3214 err = offset;
3215 }
3216 out:
3217 complete_pdu(s, pdu, err);
3218 v9fs_string_free(&name);
3219 }
3220
3221 static void v9fs_xattrcreate(void *opaque)
3222 {
3223 int flags;
3224 int32_t fid;
3225 int64_t size;
3226 ssize_t err = 0;
3227 V9fsString name;
3228 size_t offset = 7;
3229 V9fsFidState *file_fidp;
3230 V9fsFidState *xattr_fidp;
3231 V9fsPDU *pdu = opaque;
3232 V9fsState *s = pdu->s;
3233
3234 pdu_unmarshal(pdu, offset, "dsqd",
3235 &fid, &name, &size, &flags);
3236
3237 file_fidp = lookup_fid(s, fid);
3238 if (file_fidp == NULL) {
3239 err = -EINVAL;
3240 goto out;
3241 }
3242 /* Make the file fid point to xattr */
3243 xattr_fidp = file_fidp;
3244 xattr_fidp->fid_type = P9_FID_XATTR;
3245 xattr_fidp->fs.xattr.copied_len = 0;
3246 xattr_fidp->fs.xattr.len = size;
3247 xattr_fidp->fs.xattr.flags = flags;
3248 v9fs_string_init(&xattr_fidp->fs.xattr.name);
3249 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3250 if (size) {
3251 xattr_fidp->fs.xattr.value = qemu_malloc(size);
3252 } else {
3253 xattr_fidp->fs.xattr.value = NULL;
3254 }
3255 err = offset;
3256 out:
3257 complete_pdu(s, pdu, err);
3258 v9fs_string_free(&name);
3259 }
3260
3261 static void v9fs_readlink(void *opaque)
3262 {
3263 V9fsPDU *pdu = opaque;
3264 size_t offset = 7;
3265 V9fsString target;
3266 int32_t fid;
3267 int err = 0;
3268 V9fsFidState *fidp;
3269
3270 pdu_unmarshal(pdu, offset, "d", &fid);
3271 fidp = lookup_fid(pdu->s, fid);
3272 if (fidp == NULL) {
3273 err = -ENOENT;
3274 goto out;
3275 }
3276
3277 v9fs_string_init(&target);
3278 err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
3279 if (err < 0) {
3280 goto out;
3281 }
3282 offset += pdu_marshal(pdu, offset, "s", &target);
3283 err = offset;
3284 v9fs_string_free(&target);
3285 out:
3286 complete_pdu(pdu->s, pdu, err);
3287 }
3288
3289 static CoroutineEntry *pdu_co_handlers[] = {
3290 [P9_TREADDIR] = v9fs_readdir,
3291 [P9_TSTATFS] = v9fs_statfs,
3292 [P9_TGETATTR] = v9fs_getattr,
3293 [P9_TSETATTR] = v9fs_setattr,
3294 [P9_TXATTRWALK] = v9fs_xattrwalk,
3295 [P9_TXATTRCREATE] = v9fs_xattrcreate,
3296 [P9_TMKNOD] = v9fs_mknod,
3297 [P9_TRENAME] = v9fs_rename,
3298 [P9_TLOCK] = v9fs_lock,
3299 [P9_TGETLOCK] = v9fs_getlock,
3300 [P9_TREADLINK] = v9fs_readlink,
3301 [P9_TMKDIR] = v9fs_mkdir,
3302 [P9_TVERSION] = v9fs_version,
3303 [P9_TLOPEN] = v9fs_open,
3304 [P9_TATTACH] = v9fs_attach,
3305 [P9_TSTAT] = v9fs_stat,
3306 [P9_TWALK] = v9fs_walk,
3307 [P9_TCLUNK] = v9fs_clunk,
3308 [P9_TFSYNC] = v9fs_fsync,
3309 [P9_TOPEN] = v9fs_open,
3310 [P9_TREAD] = v9fs_read,
3311 #if 0
3312 [P9_TAUTH] = v9fs_auth,
3313 #endif
3314 [P9_TFLUSH] = v9fs_flush,
3315 [P9_TLINK] = v9fs_link,
3316 [P9_TSYMLINK] = v9fs_symlink,
3317 [P9_TCREATE] = v9fs_create,
3318 [P9_TLCREATE] = v9fs_lcreate,
3319 [P9_TWRITE] = v9fs_write,
3320 [P9_TWSTAT] = v9fs_wstat,
3321 [P9_TREMOVE] = v9fs_remove,
3322 };
3323
3324 static void v9fs_op_not_supp(void *opaque)
3325 {
3326 V9fsPDU *pdu = opaque;
3327 complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3328 }
3329
3330 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3331 {
3332 Coroutine *co;
3333 CoroutineEntry *handler;
3334
3335 if (debug_9p_pdu) {
3336 pprint_pdu(pdu);
3337 }
3338 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3339 (pdu_co_handlers[pdu->id] == NULL)) {
3340 handler = v9fs_op_not_supp;
3341 } else {
3342 handler = pdu_co_handlers[pdu->id];
3343 }
3344 co = qemu_coroutine_create(handler);
3345 qemu_coroutine_enter(co, pdu);
3346 }
3347
3348 void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3349 {
3350 V9fsState *s = (V9fsState *)vdev;
3351 V9fsPDU *pdu;
3352 ssize_t len;
3353
3354 while ((pdu = alloc_pdu(s)) &&
3355 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3356 uint8_t *ptr;
3357 pdu->s = s;
3358 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3359 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3360
3361 ptr = pdu->elem.out_sg[0].iov_base;
3362
3363 memcpy(&pdu->size, ptr, 4);
3364 pdu->id = ptr[4];
3365 memcpy(&pdu->tag, ptr + 5, 2);
3366 submit_pdu(s, pdu);
3367 }
3368 free_pdu(s, pdu);
3369 }