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