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