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