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