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