]> Git Repo - qemu.git/blob - hw/9pfs/virtio-9p.c
Merge branch 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
[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_complete_pdu(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 out:
1336     put_fid(pdu, fidp);
1337 out_nofid:
1338     trace_v9fs_attach_return(pdu->tag, pdu->id,
1339                              qid.type, qid.version, qid.path);
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     v9fs_stat_free(&v9stat);
1375 out:
1376     put_fid(pdu, fidp);
1377 out_nofid:
1378     trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
1379                            v9stat.atime, v9stat.mtime, v9stat.length);
1380
1381     complete_pdu(s, pdu, err);
1382 }
1383
1384 static void v9fs_getattr(void *opaque)
1385 {
1386     int32_t fid;
1387     size_t offset = 7;
1388     ssize_t retval = 0;
1389     struct stat stbuf;
1390     V9fsFidState *fidp;
1391     uint64_t request_mask;
1392     V9fsStatDotl v9stat_dotl;
1393     V9fsPDU *pdu = opaque;
1394     V9fsState *s = pdu->s;
1395
1396     pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1397     trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
1398
1399     fidp = get_fid(pdu, fid);
1400     if (fidp == NULL) {
1401         retval = -ENOENT;
1402         goto out_nofid;
1403     }
1404     /*
1405      * Currently we only support BASIC fields in stat, so there is no
1406      * need to look at request_mask.
1407      */
1408     retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1409     if (retval < 0) {
1410         goto out;
1411     }
1412     stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1413
1414     /*  fill st_gen if requested and supported by underlying fs */
1415     if (request_mask & P9_STATS_GEN) {
1416         retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
1417         if (retval < 0) {
1418             goto out;
1419         }
1420         v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1421     }
1422     retval = offset;
1423     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1424 out:
1425     put_fid(pdu, fidp);
1426 out_nofid:
1427     trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1428                               v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1429                               v9stat_dotl.st_gid);
1430
1431     complete_pdu(s, pdu, retval);
1432 }
1433
1434 /* From Linux kernel code */
1435 #define ATTR_MODE    (1 << 0)
1436 #define ATTR_UID     (1 << 1)
1437 #define ATTR_GID     (1 << 2)
1438 #define ATTR_SIZE    (1 << 3)
1439 #define ATTR_ATIME   (1 << 4)
1440 #define ATTR_MTIME   (1 << 5)
1441 #define ATTR_CTIME   (1 << 6)
1442 #define ATTR_MASK    127
1443 #define ATTR_ATIME_SET  (1 << 7)
1444 #define ATTR_MTIME_SET  (1 << 8)
1445
1446 static void v9fs_setattr(void *opaque)
1447 {
1448     int err = 0;
1449     int32_t fid;
1450     V9fsFidState *fidp;
1451     size_t offset = 7;
1452     V9fsIattr v9iattr;
1453     V9fsPDU *pdu = opaque;
1454     V9fsState *s = pdu->s;
1455
1456     pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1457
1458     fidp = get_fid(pdu, fid);
1459     if (fidp == NULL) {
1460         err = -EINVAL;
1461         goto out_nofid;
1462     }
1463     if (v9iattr.valid & ATTR_MODE) {
1464         err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
1465         if (err < 0) {
1466             goto out;
1467         }
1468     }
1469     if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1470         struct timespec times[2];
1471         if (v9iattr.valid & ATTR_ATIME) {
1472             if (v9iattr.valid & ATTR_ATIME_SET) {
1473                 times[0].tv_sec = v9iattr.atime_sec;
1474                 times[0].tv_nsec = v9iattr.atime_nsec;
1475             } else {
1476                 times[0].tv_nsec = UTIME_NOW;
1477             }
1478         } else {
1479             times[0].tv_nsec = UTIME_OMIT;
1480         }
1481         if (v9iattr.valid & ATTR_MTIME) {
1482             if (v9iattr.valid & ATTR_MTIME_SET) {
1483                 times[1].tv_sec = v9iattr.mtime_sec;
1484                 times[1].tv_nsec = v9iattr.mtime_nsec;
1485             } else {
1486                 times[1].tv_nsec = UTIME_NOW;
1487             }
1488         } else {
1489             times[1].tv_nsec = UTIME_OMIT;
1490         }
1491         err = v9fs_co_utimensat(pdu, &fidp->path, times);
1492         if (err < 0) {
1493             goto out;
1494         }
1495     }
1496     /*
1497      * If the only valid entry in iattr is ctime we can call
1498      * chown(-1,-1) to update the ctime of the file
1499      */
1500     if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1501         ((v9iattr.valid & ATTR_CTIME)
1502          && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1503         if (!(v9iattr.valid & ATTR_UID)) {
1504             v9iattr.uid = -1;
1505         }
1506         if (!(v9iattr.valid & ATTR_GID)) {
1507             v9iattr.gid = -1;
1508         }
1509         err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
1510                             v9iattr.gid);
1511         if (err < 0) {
1512             goto out;
1513         }
1514     }
1515     if (v9iattr.valid & (ATTR_SIZE)) {
1516         err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
1517         if (err < 0) {
1518             goto out;
1519         }
1520     }
1521     err = offset;
1522 out:
1523     put_fid(pdu, fidp);
1524 out_nofid:
1525     complete_pdu(s, pdu, err);
1526 }
1527
1528 static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1529 {
1530     int i;
1531     size_t offset = 7;
1532     offset += pdu_marshal(pdu, offset, "w", nwnames);
1533     for (i = 0; i < nwnames; i++) {
1534         offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
1535     }
1536     return offset;
1537 }
1538
1539 static void v9fs_walk(void *opaque)
1540 {
1541     int name_idx;
1542     V9fsQID *qids = NULL;
1543     int i, err = 0;
1544     V9fsPath dpath, path;
1545     uint16_t nwnames;
1546     struct stat stbuf;
1547     size_t offset = 7;
1548     int32_t fid, newfid;
1549     V9fsString *wnames = NULL;
1550     V9fsFidState *fidp;
1551     V9fsFidState *newfidp = NULL;;
1552     V9fsPDU *pdu = opaque;
1553     V9fsState *s = pdu->s;
1554
1555     offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
1556                             &newfid, &nwnames);
1557
1558     trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1559
1560     if (nwnames && nwnames <= P9_MAXWELEM) {
1561         wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1562         qids   = g_malloc0(sizeof(qids[0]) * nwnames);
1563         for (i = 0; i < nwnames; i++) {
1564             offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1565         }
1566     } else if (nwnames > P9_MAXWELEM) {
1567         err = -EINVAL;
1568         goto out_nofid;
1569     }
1570     fidp = get_fid(pdu, fid);
1571     if (fidp == NULL) {
1572         err = -ENOENT;
1573         goto out_nofid;
1574     }
1575     v9fs_path_init(&dpath);
1576     v9fs_path_init(&path);
1577     /*
1578      * Both dpath and path initially poin to fidp.
1579      * Needed to handle request with nwnames == 0
1580      */
1581     v9fs_path_copy(&dpath, &fidp->path);
1582     v9fs_path_copy(&path, &fidp->path);
1583     for (name_idx = 0; name_idx < nwnames; name_idx++) {
1584         err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
1585         if (err < 0) {
1586             goto out;
1587         }
1588         err = v9fs_co_lstat(pdu, &path, &stbuf);
1589         if (err < 0) {
1590             goto out;
1591         }
1592         stat_to_qid(&stbuf, &qids[name_idx]);
1593         v9fs_path_copy(&dpath, &path);
1594     }
1595     if (fid == newfid) {
1596         BUG_ON(fidp->fid_type != P9_FID_NONE);
1597         v9fs_path_copy(&fidp->path, &path);
1598     } else {
1599         newfidp = alloc_fid(s, newfid);
1600         if (newfidp == NULL) {
1601             err = -EINVAL;
1602             goto out;
1603         }
1604         newfidp->uid = fidp->uid;
1605         v9fs_path_copy(&newfidp->path, &path);
1606     }
1607     err = v9fs_walk_marshal(pdu, nwnames, qids);
1608 out:
1609     put_fid(pdu, fidp);
1610     if (newfidp) {
1611         put_fid(pdu, newfidp);
1612     }
1613     v9fs_path_free(&dpath);
1614     v9fs_path_free(&path);
1615 out_nofid:
1616     trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
1617     complete_pdu(s, pdu, err);
1618     if (nwnames && nwnames <= P9_MAXWELEM) {
1619         for (name_idx = 0; name_idx < nwnames; name_idx++) {
1620             v9fs_string_free(&wnames[name_idx]);
1621         }
1622         g_free(wnames);
1623         g_free(qids);
1624     }
1625     return;
1626 }
1627
1628 static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
1629 {
1630     struct statfs stbuf;
1631     int32_t iounit = 0;
1632     V9fsState *s = pdu->s;
1633
1634     /*
1635      * iounit should be multiples of f_bsize (host filesystem block size
1636      * and as well as less than (client msize - P9_IOHDRSZ))
1637      */
1638     if (!v9fs_co_statfs(pdu, path, &stbuf)) {
1639         iounit = stbuf.f_bsize;
1640         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1641     }
1642     if (!iounit) {
1643         iounit = s->msize - P9_IOHDRSZ;
1644     }
1645     return iounit;
1646 }
1647
1648 static void v9fs_open(void *opaque)
1649 {
1650     int flags;
1651     int iounit;
1652     int32_t fid;
1653     int32_t mode;
1654     V9fsQID qid;
1655     ssize_t err = 0;
1656     size_t offset = 7;
1657     struct stat stbuf;
1658     V9fsFidState *fidp;
1659     V9fsPDU *pdu = opaque;
1660     V9fsState *s = pdu->s;
1661
1662     if (s->proto_version == V9FS_PROTO_2000L) {
1663         pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1664     } else {
1665         pdu_unmarshal(pdu, offset, "db", &fid, &mode);
1666     }
1667     trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1668
1669     fidp = get_fid(pdu, fid);
1670     if (fidp == NULL) {
1671         err = -ENOENT;
1672         goto out_nofid;
1673     }
1674     BUG_ON(fidp->fid_type != P9_FID_NONE);
1675
1676     err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1677     if (err < 0) {
1678         goto out;
1679     }
1680     stat_to_qid(&stbuf, &qid);
1681     if (S_ISDIR(stbuf.st_mode)) {
1682         err = v9fs_co_opendir(pdu, fidp);
1683         if (err < 0) {
1684             goto out;
1685         }
1686         fidp->fid_type = P9_FID_DIR;
1687         offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
1688         err = offset;
1689     } else {
1690         if (s->proto_version == V9FS_PROTO_2000L) {
1691             flags = get_dotl_openflags(s, mode);
1692         } else {
1693             flags = omode_to_uflags(mode);
1694         }
1695         err = v9fs_co_open(pdu, fidp, flags);
1696         if (err < 0) {
1697             goto out;
1698         }
1699         fidp->fid_type = P9_FID_FILE;
1700         fidp->open_flags = flags;
1701         if (flags & O_EXCL) {
1702             /*
1703              * We let the host file system do O_EXCL check
1704              * We should not reclaim such fd
1705              */
1706             fidp->flags |= FID_NON_RECLAIMABLE;
1707         }
1708         iounit = get_iounit(pdu, &fidp->path);
1709         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1710         err = offset;
1711     }
1712 out:
1713     put_fid(pdu, fidp);
1714 out_nofid:
1715     trace_v9fs_open_return(pdu->tag, pdu->id,
1716                            qid.type, qid.version, qid.path, iounit);
1717     complete_pdu(s, pdu, err);
1718 }
1719
1720 static void v9fs_lcreate(void *opaque)
1721 {
1722     int32_t dfid, flags, mode;
1723     gid_t gid;
1724     ssize_t err = 0;
1725     ssize_t offset = 7;
1726     V9fsString name;
1727     V9fsFidState *fidp;
1728     struct stat stbuf;
1729     V9fsQID qid;
1730     int32_t iounit;
1731     V9fsPDU *pdu = opaque;
1732
1733     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
1734                   &mode, &gid);
1735     trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
1736
1737     fidp = get_fid(pdu, dfid);
1738     if (fidp == NULL) {
1739         err = -ENOENT;
1740         goto out_nofid;
1741     }
1742
1743     flags = get_dotl_openflags(pdu->s, flags);
1744     err = v9fs_co_open2(pdu, fidp, &name, gid,
1745                         flags | O_CREAT, mode, &stbuf);
1746     if (err < 0) {
1747         goto out;
1748     }
1749     fidp->fid_type = P9_FID_FILE;
1750     fidp->open_flags = flags;
1751     if (flags & O_EXCL) {
1752         /*
1753          * We let the host file system do O_EXCL check
1754          * We should not reclaim such fd
1755          */
1756         fidp->flags |= FID_NON_RECLAIMABLE;
1757     }
1758     iounit =  get_iounit(pdu, &fidp->path);
1759     stat_to_qid(&stbuf, &qid);
1760     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1761     err = offset;
1762 out:
1763     put_fid(pdu, fidp);
1764 out_nofid:
1765     trace_v9fs_lcreate_return(pdu->tag, pdu->id,
1766                               qid.type, qid.version, qid.path, iounit);
1767     complete_pdu(pdu->s, pdu, err);
1768     v9fs_string_free(&name);
1769 }
1770
1771 static void v9fs_fsync(void *opaque)
1772 {
1773     int err;
1774     int32_t fid;
1775     int datasync;
1776     size_t offset = 7;
1777     V9fsFidState *fidp;
1778     V9fsPDU *pdu = opaque;
1779     V9fsState *s = pdu->s;
1780
1781     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1782     trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
1783
1784     fidp = get_fid(pdu, fid);
1785     if (fidp == NULL) {
1786         err = -ENOENT;
1787         goto out_nofid;
1788     }
1789     err = v9fs_co_fsync(pdu, fidp, datasync);
1790     if (!err) {
1791         err = offset;
1792     }
1793     put_fid(pdu, fidp);
1794 out_nofid:
1795     complete_pdu(s, pdu, err);
1796 }
1797
1798 static void v9fs_clunk(void *opaque)
1799 {
1800     int err;
1801     int32_t fid;
1802     size_t offset = 7;
1803     V9fsFidState *fidp;
1804     V9fsPDU *pdu = opaque;
1805     V9fsState *s = pdu->s;
1806
1807     pdu_unmarshal(pdu, offset, "d", &fid);
1808     trace_v9fs_clunk(pdu->tag, pdu->id, fid);
1809
1810     fidp = clunk_fid(s, fid);
1811     if (fidp == NULL) {
1812         err = -ENOENT;
1813         goto out_nofid;
1814     }
1815     /*
1816      * Bump the ref so that put_fid will
1817      * free the fid.
1818      */
1819     fidp->ref++;
1820     err = offset;
1821
1822     put_fid(pdu, fidp);
1823 out_nofid:
1824     complete_pdu(s, pdu, err);
1825 }
1826
1827 static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
1828                            V9fsFidState *fidp, int64_t off, int32_t max_count)
1829 {
1830     size_t offset = 7;
1831     int read_count;
1832     int64_t xattr_len;
1833
1834     xattr_len = fidp->fs.xattr.len;
1835     read_count = xattr_len - off;
1836     if (read_count > max_count) {
1837         read_count = max_count;
1838     } else if (read_count < 0) {
1839         /*
1840          * read beyond XATTR value
1841          */
1842         read_count = 0;
1843     }
1844     offset += pdu_marshal(pdu, offset, "d", read_count);
1845     offset += pdu_pack(pdu, offset,
1846                        ((char *)fidp->fs.xattr.value) + off,
1847                        read_count);
1848     return offset;
1849 }
1850
1851 static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
1852                                      V9fsFidState *fidp, int32_t max_count)
1853 {
1854     V9fsPath path;
1855     V9fsStat v9stat;
1856     int len, err = 0;
1857     int32_t count = 0;
1858     struct stat stbuf;
1859     off_t saved_dir_pos;
1860     struct dirent *dent, *result;
1861
1862     /* save the directory position */
1863     saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1864     if (saved_dir_pos < 0) {
1865         return saved_dir_pos;
1866     }
1867
1868     dent = g_malloc(sizeof(struct dirent));
1869
1870     while (1) {
1871         v9fs_path_init(&path);
1872         err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
1873         if (err || !result) {
1874             break;
1875         }
1876         err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
1877         if (err < 0) {
1878             goto out;
1879         }
1880         err = v9fs_co_lstat(pdu, &path, &stbuf);
1881         if (err < 0) {
1882             goto out;
1883         }
1884         err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
1885         if (err < 0) {
1886             goto out;
1887         }
1888         /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1889         len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1890         if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1891             /* Ran out of buffer. Set dir back to old position and return */
1892             v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1893             v9fs_stat_free(&v9stat);
1894             v9fs_path_free(&path);
1895             g_free(dent);
1896             return count;
1897         }
1898         count += len;
1899         v9fs_stat_free(&v9stat);
1900         v9fs_path_free(&path);
1901         saved_dir_pos = dent->d_off;
1902     }
1903 out:
1904     g_free(dent);
1905     v9fs_path_free(&path);
1906     if (err < 0) {
1907         return err;
1908     }
1909     return count;
1910 }
1911
1912 static void v9fs_read(void *opaque)
1913 {
1914     int32_t fid;
1915     int64_t off;
1916     ssize_t err = 0;
1917     int32_t count = 0;
1918     size_t offset = 7;
1919     int32_t max_count;
1920     V9fsFidState *fidp;
1921     V9fsPDU *pdu = opaque;
1922     V9fsState *s = pdu->s;
1923
1924     pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1925     trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
1926
1927     fidp = get_fid(pdu, fid);
1928     if (fidp == NULL) {
1929         err = -EINVAL;
1930         goto out_nofid;
1931     }
1932     if (fidp->fid_type == P9_FID_DIR) {
1933
1934         if (off == 0) {
1935             v9fs_co_rewinddir(pdu, fidp);
1936         }
1937         count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
1938         if (count < 0) {
1939             err = count;
1940             goto out;
1941         }
1942         err = offset;
1943         err += pdu_marshal(pdu, offset, "d", count);
1944         err += count;
1945     } else if (fidp->fid_type == P9_FID_FILE) {
1946         int32_t cnt;
1947         int32_t len;
1948         struct iovec *sg;
1949         struct iovec iov[128]; /* FIXME: bad, bad, bad */
1950
1951         sg = iov;
1952         pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
1953         sg = cap_sg(sg, max_count, &cnt);
1954         do {
1955             if (0) {
1956                 print_sg(sg, cnt);
1957             }
1958             /* Loop in case of EINTR */
1959             do {
1960                 len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
1961                 if (len >= 0) {
1962                     off   += len;
1963                     count += len;
1964                 }
1965             } while (len == -EINTR && !pdu->cancelled);
1966             if (len < 0) {
1967                 /* IO error return the error */
1968                 err = len;
1969                 goto out;
1970             }
1971             sg = adjust_sg(sg, len, &cnt);
1972         } while (count < max_count && len > 0);
1973         err = offset;
1974         err += pdu_marshal(pdu, offset, "d", count);
1975         err += count;
1976     } else if (fidp->fid_type == P9_FID_XATTR) {
1977         err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1978     } else {
1979         err = -EINVAL;
1980     }
1981 out:
1982     put_fid(pdu, fidp);
1983 out_nofid:
1984     trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
1985     complete_pdu(s, pdu, err);
1986 }
1987
1988 static size_t v9fs_readdir_data_size(V9fsString *name)
1989 {
1990     /*
1991      * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1992      * size of type (1) + size of name.size (2) + strlen(name.data)
1993      */
1994     return 24 + v9fs_string_size(name);
1995 }
1996
1997 static int v9fs_do_readdir(V9fsPDU *pdu,
1998                            V9fsFidState *fidp, int32_t max_count)
1999 {
2000     size_t size;
2001     V9fsQID qid;
2002     V9fsString name;
2003     int len, err = 0;
2004     int32_t count = 0;
2005     off_t saved_dir_pos;
2006     struct dirent *dent, *result;
2007
2008     /* save the directory position */
2009     saved_dir_pos = v9fs_co_telldir(pdu, fidp);
2010     if (saved_dir_pos < 0) {
2011         return saved_dir_pos;
2012     }
2013
2014     dent = g_malloc(sizeof(struct dirent));
2015
2016     while (1) {
2017         err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
2018         if (err || !result) {
2019             break;
2020         }
2021         v9fs_string_init(&name);
2022         v9fs_string_sprintf(&name, "%s", dent->d_name);
2023         if ((count + v9fs_readdir_data_size(&name)) > max_count) {
2024             /* Ran out of buffer. Set dir back to old position and return */
2025             v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
2026             v9fs_string_free(&name);
2027             g_free(dent);
2028             return count;
2029         }
2030         /*
2031          * Fill up just the path field of qid because the client uses
2032          * only that. To fill the entire qid structure we will have
2033          * to stat each dirent found, which is expensive
2034          */
2035         size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
2036         memcpy(&qid.path, &dent->d_ino, size);
2037         /* Fill the other fields with dummy values */
2038         qid.type = 0;
2039         qid.version = 0;
2040
2041         /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
2042         len = pdu_marshal(pdu, 11 + count, "Qqbs",
2043                           &qid, dent->d_off,
2044                           dent->d_type, &name);
2045         count += len;
2046         v9fs_string_free(&name);
2047         saved_dir_pos = dent->d_off;
2048     }
2049     g_free(dent);
2050     if (err < 0) {
2051         return err;
2052     }
2053     return count;
2054 }
2055
2056 static void v9fs_readdir(void *opaque)
2057 {
2058     int32_t fid;
2059     V9fsFidState *fidp;
2060     ssize_t retval = 0;
2061     size_t offset = 7;
2062     int64_t initial_offset;
2063     int32_t count, max_count;
2064     V9fsPDU *pdu = opaque;
2065     V9fsState *s = pdu->s;
2066
2067     pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
2068
2069     trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
2070
2071     fidp = get_fid(pdu, fid);
2072     if (fidp == NULL) {
2073         retval = -EINVAL;
2074         goto out_nofid;
2075     }
2076     if (!fidp->fs.dir) {
2077         retval = -EINVAL;
2078         goto out;
2079     }
2080     if (initial_offset == 0) {
2081         v9fs_co_rewinddir(pdu, fidp);
2082     } else {
2083         v9fs_co_seekdir(pdu, fidp, initial_offset);
2084     }
2085     count = v9fs_do_readdir(pdu, fidp, max_count);
2086     if (count < 0) {
2087         retval = count;
2088         goto out;
2089     }
2090     retval = offset;
2091     retval += pdu_marshal(pdu, offset, "d", count);
2092     retval += count;
2093 out:
2094     put_fid(pdu, fidp);
2095 out_nofid:
2096     trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
2097     complete_pdu(s, pdu, retval);
2098 }
2099
2100 static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
2101                             int64_t off, int32_t count,
2102                             struct iovec *sg, int cnt)
2103 {
2104     int i, to_copy;
2105     ssize_t err = 0;
2106     int write_count;
2107     int64_t xattr_len;
2108     size_t offset = 7;
2109
2110
2111     xattr_len = fidp->fs.xattr.len;
2112     write_count = xattr_len - off;
2113     if (write_count > count) {
2114         write_count = count;
2115     } else if (write_count < 0) {
2116         /*
2117          * write beyond XATTR value len specified in
2118          * xattrcreate
2119          */
2120         err = -ENOSPC;
2121         goto out;
2122     }
2123     offset += pdu_marshal(pdu, offset, "d", write_count);
2124     err = offset;
2125     fidp->fs.xattr.copied_len += write_count;
2126     /*
2127      * Now copy the content from sg list
2128      */
2129     for (i = 0; i < cnt; i++) {
2130         if (write_count > sg[i].iov_len) {
2131             to_copy = sg[i].iov_len;
2132         } else {
2133             to_copy = write_count;
2134         }
2135         memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
2136         /* updating vs->off since we are not using below */
2137         off += to_copy;
2138         write_count -= to_copy;
2139     }
2140 out:
2141     return err;
2142 }
2143
2144 static void v9fs_write(void *opaque)
2145 {
2146     int cnt;
2147     ssize_t err;
2148     int32_t fid;
2149     int64_t off;
2150     int32_t count;
2151     int32_t len = 0;
2152     int32_t total = 0;
2153     size_t offset = 7;
2154     V9fsFidState *fidp;
2155     struct iovec iov[128]; /* FIXME: bad, bad, bad */
2156     struct iovec *sg = iov;
2157     V9fsPDU *pdu = opaque;
2158     V9fsState *s = pdu->s;
2159
2160     pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
2161     trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt);
2162
2163     fidp = get_fid(pdu, fid);
2164     if (fidp == NULL) {
2165         err = -EINVAL;
2166         goto out_nofid;
2167     }
2168     if (fidp->fid_type == P9_FID_FILE) {
2169         if (fidp->fs.fd == -1) {
2170             err = -EINVAL;
2171             goto out;
2172         }
2173     } else if (fidp->fid_type == P9_FID_XATTR) {
2174         /*
2175          * setxattr operation
2176          */
2177         err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
2178         goto out;
2179     } else {
2180         err = -EINVAL;
2181         goto out;
2182     }
2183     sg = cap_sg(sg, count, &cnt);
2184     do {
2185         if (0) {
2186             print_sg(sg, cnt);
2187         }
2188         /* Loop in case of EINTR */
2189         do {
2190             len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
2191             if (len >= 0) {
2192                 off   += len;
2193                 total += len;
2194             }
2195         } while (len == -EINTR && !pdu->cancelled);
2196         if (len < 0) {
2197             /* IO error return the error */
2198             err = len;
2199             goto out;
2200         }
2201         sg = adjust_sg(sg, len, &cnt);
2202     } while (total < count && len > 0);
2203     offset += pdu_marshal(pdu, offset, "d", total);
2204     err = offset;
2205 out:
2206     put_fid(pdu, fidp);
2207 out_nofid:
2208     trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
2209     complete_pdu(s, pdu, err);
2210 }
2211
2212 static void v9fs_create(void *opaque)
2213 {
2214     int32_t fid;
2215     int err = 0;
2216     size_t offset = 7;
2217     V9fsFidState *fidp;
2218     V9fsQID qid;
2219     int32_t perm;
2220     int8_t mode;
2221     V9fsPath path;
2222     struct stat stbuf;
2223     V9fsString name;
2224     V9fsString extension;
2225     int iounit;
2226     V9fsPDU *pdu = opaque;
2227
2228     v9fs_path_init(&path);
2229
2230     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2231                   &perm, &mode, &extension);
2232
2233     trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2234
2235     fidp = get_fid(pdu, fid);
2236     if (fidp == NULL) {
2237         err = -EINVAL;
2238         goto out_nofid;
2239     }
2240     if (perm & P9_STAT_MODE_DIR) {
2241         err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
2242                             fidp->uid, -1, &stbuf);
2243         if (err < 0) {
2244             goto out;
2245         }
2246         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2247         if (err < 0) {
2248             goto out;
2249         }
2250         v9fs_path_copy(&fidp->path, &path);
2251         err = v9fs_co_opendir(pdu, fidp);
2252         if (err < 0) {
2253             goto out;
2254         }
2255         fidp->fid_type = P9_FID_DIR;
2256     } else if (perm & P9_STAT_MODE_SYMLINK) {
2257         err = v9fs_co_symlink(pdu, fidp, &name,
2258                               extension.data, -1 , &stbuf);
2259         if (err < 0) {
2260             goto out;
2261         }
2262         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2263         if (err < 0) {
2264             goto out;
2265         }
2266         v9fs_path_copy(&fidp->path, &path);
2267     } else if (perm & P9_STAT_MODE_LINK) {
2268         int32_t ofid = atoi(extension.data);
2269         V9fsFidState *ofidp = get_fid(pdu, ofid);
2270         if (ofidp == NULL) {
2271             err = -EINVAL;
2272             goto out;
2273         }
2274         err = v9fs_co_link(pdu, ofidp, fidp, &name);
2275         put_fid(pdu, ofidp);
2276         if (err < 0) {
2277             goto out;
2278         }
2279         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2280         if (err < 0) {
2281             fidp->fid_type = P9_FID_NONE;
2282             goto out;
2283         }
2284         v9fs_path_copy(&fidp->path, &path);
2285         err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2286         if (err < 0) {
2287             fidp->fid_type = P9_FID_NONE;
2288             goto out;
2289         }
2290     } else if (perm & P9_STAT_MODE_DEVICE) {
2291         char ctype;
2292         uint32_t major, minor;
2293         mode_t nmode = 0;
2294
2295         if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2296             err = -errno;
2297             goto out;
2298         }
2299
2300         switch (ctype) {
2301         case 'c':
2302             nmode = S_IFCHR;
2303             break;
2304         case 'b':
2305             nmode = S_IFBLK;
2306             break;
2307         default:
2308             err = -EIO;
2309             goto out;
2310         }
2311
2312         nmode |= perm & 0777;
2313         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2314                             makedev(major, minor), nmode, &stbuf);
2315         if (err < 0) {
2316             goto out;
2317         }
2318         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2319         if (err < 0) {
2320             goto out;
2321         }
2322         v9fs_path_copy(&fidp->path, &path);
2323     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2324         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2325                             0, S_IFIFO | (perm & 0777), &stbuf);
2326         if (err < 0) {
2327             goto out;
2328         }
2329         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2330         if (err < 0) {
2331             goto out;
2332         }
2333         v9fs_path_copy(&fidp->path, &path);
2334     } else if (perm & P9_STAT_MODE_SOCKET) {
2335         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2336                             0, S_IFSOCK | (perm & 0777), &stbuf);
2337         if (err < 0) {
2338             goto out;
2339         }
2340         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2341         if (err < 0) {
2342             goto out;
2343         }
2344         v9fs_path_copy(&fidp->path, &path);
2345     } else {
2346         err = v9fs_co_open2(pdu, fidp, &name, -1,
2347                             omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
2348         if (err < 0) {
2349             goto out;
2350         }
2351         fidp->fid_type = P9_FID_FILE;
2352         fidp->open_flags = omode_to_uflags(mode);
2353         if (fidp->open_flags & O_EXCL) {
2354             /*
2355              * We let the host file system do O_EXCL check
2356              * We should not reclaim such fd
2357              */
2358             fidp->flags |= FID_NON_RECLAIMABLE;
2359         }
2360     }
2361     iounit = get_iounit(pdu, &fidp->path);
2362     stat_to_qid(&stbuf, &qid);
2363     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2364     err = offset;
2365 out:
2366     put_fid(pdu, fidp);
2367 out_nofid:
2368    trace_v9fs_create_return(pdu->tag, pdu->id,
2369                             qid.type, qid.version, qid.path, iounit);
2370    complete_pdu(pdu->s, pdu, err);
2371    v9fs_string_free(&name);
2372    v9fs_string_free(&extension);
2373    v9fs_path_free(&path);
2374 }
2375
2376 static void v9fs_symlink(void *opaque)
2377 {
2378     V9fsPDU *pdu = opaque;
2379     V9fsString name;
2380     V9fsString symname;
2381     V9fsFidState *dfidp;
2382     V9fsQID qid;
2383     struct stat stbuf;
2384     int32_t dfid;
2385     int err = 0;
2386     gid_t gid;
2387     size_t offset = 7;
2388
2389     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2390     trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
2391
2392     dfidp = get_fid(pdu, dfid);
2393     if (dfidp == NULL) {
2394         err = -EINVAL;
2395         goto out_nofid;
2396     }
2397     err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
2398     if (err < 0) {
2399         goto out;
2400     }
2401     stat_to_qid(&stbuf, &qid);
2402     offset += pdu_marshal(pdu, offset, "Q", &qid);
2403     err = offset;
2404 out:
2405     put_fid(pdu, dfidp);
2406 out_nofid:
2407     trace_v9fs_symlink_return(pdu->tag, pdu->id,
2408                               qid.type, qid.version, qid.path);
2409     complete_pdu(pdu->s, pdu, err);
2410     v9fs_string_free(&name);
2411     v9fs_string_free(&symname);
2412 }
2413
2414 static void v9fs_flush(void *opaque)
2415 {
2416     int16_t tag;
2417     size_t offset = 7;
2418     V9fsPDU *cancel_pdu;
2419     V9fsPDU *pdu = opaque;
2420     V9fsState *s = pdu->s;
2421
2422     pdu_unmarshal(pdu, offset, "w", &tag);
2423     trace_v9fs_flush(pdu->tag, pdu->id, tag);
2424
2425     QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2426         if (cancel_pdu->tag == tag) {
2427             break;
2428         }
2429     }
2430     if (cancel_pdu) {
2431         cancel_pdu->cancelled = 1;
2432         /*
2433          * Wait for pdu to complete.
2434          */
2435         qemu_co_queue_wait(&cancel_pdu->complete);
2436         cancel_pdu->cancelled = 0;
2437         free_pdu(pdu->s, cancel_pdu);
2438     }
2439     complete_pdu(s, pdu, 7);
2440     return;
2441 }
2442
2443 static void v9fs_link(void *opaque)
2444 {
2445     V9fsPDU *pdu = opaque;
2446     V9fsState *s = pdu->s;
2447     int32_t dfid, oldfid;
2448     V9fsFidState *dfidp, *oldfidp;
2449     V9fsString name;;
2450     size_t offset = 7;
2451     int err = 0;
2452
2453     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2454     trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
2455
2456     dfidp = get_fid(pdu, dfid);
2457     if (dfidp == NULL) {
2458         err = -ENOENT;
2459         goto out_nofid;
2460     }
2461
2462     oldfidp = get_fid(pdu, oldfid);
2463     if (oldfidp == NULL) {
2464         err = -ENOENT;
2465         goto out;
2466     }
2467     err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
2468     if (!err) {
2469         err = offset;
2470     }
2471 out:
2472     put_fid(pdu, dfidp);
2473 out_nofid:
2474     v9fs_string_free(&name);
2475     complete_pdu(s, pdu, err);
2476 }
2477
2478 /* Only works with path name based fid */
2479 static void v9fs_remove(void *opaque)
2480 {
2481     int32_t fid;
2482     int err = 0;
2483     size_t offset = 7;
2484     V9fsFidState *fidp;
2485     V9fsPDU *pdu = opaque;
2486
2487     pdu_unmarshal(pdu, offset, "d", &fid);
2488     trace_v9fs_remove(pdu->tag, pdu->id, fid);
2489
2490     fidp = get_fid(pdu, fid);
2491     if (fidp == NULL) {
2492         err = -EINVAL;
2493         goto out_nofid;
2494     }
2495     /* if fs driver is not path based, return EOPNOTSUPP */
2496     if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2497         err = -EOPNOTSUPP;
2498         goto out_err;
2499     }
2500     /*
2501      * IF the file is unlinked, we cannot reopen
2502      * the file later. So don't reclaim fd
2503      */
2504     err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
2505     if (err < 0) {
2506         goto out_err;
2507     }
2508     err = v9fs_co_remove(pdu, &fidp->path);
2509     if (!err) {
2510         err = offset;
2511     }
2512 out_err:
2513     /* For TREMOVE we need to clunk the fid even on failed remove */
2514     clunk_fid(pdu->s, fidp->fid);
2515     put_fid(pdu, fidp);
2516 out_nofid:
2517     complete_pdu(pdu->s, pdu, err);
2518 }
2519
2520 static void v9fs_unlinkat(void *opaque)
2521 {
2522     int err = 0;
2523     V9fsString name;
2524     int32_t dfid, flags;
2525     size_t offset = 7;
2526     V9fsPath path;
2527     V9fsFidState *dfidp;
2528     V9fsPDU *pdu = opaque;
2529
2530     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2531     flags = dotl_to_at_flags(flags);
2532
2533     dfidp = get_fid(pdu, dfid);
2534     if (dfidp == NULL) {
2535         err = -EINVAL;
2536         goto out_nofid;
2537     }
2538     /*
2539      * IF the file is unlinked, we cannot reopen
2540      * the file later. So don't reclaim fd
2541      */
2542     v9fs_path_init(&path);
2543     err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
2544     if (err < 0) {
2545         goto out_err;
2546     }
2547     err = v9fs_mark_fids_unreclaim(pdu, &path);
2548     if (err < 0) {
2549         goto out_err;
2550     }
2551     err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
2552     if (!err) {
2553         err = offset;
2554     }
2555 out_err:
2556     put_fid(pdu, dfidp);
2557     v9fs_path_free(&path);
2558 out_nofid:
2559     complete_pdu(pdu->s, pdu, err);
2560     v9fs_string_free(&name);
2561 }
2562
2563
2564 /* Only works with path name based fid */
2565 static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
2566                                 int32_t newdirfid, V9fsString *name)
2567 {
2568     char *end;
2569     int err = 0;
2570     V9fsPath new_path;
2571     V9fsFidState *tfidp;
2572     V9fsState *s = pdu->s;
2573     V9fsFidState *dirfidp = NULL;
2574     char *old_name, *new_name;
2575
2576     v9fs_path_init(&new_path);
2577     if (newdirfid != -1) {
2578         dirfidp = get_fid(pdu, newdirfid);
2579         if (dirfidp == NULL) {
2580             err = -ENOENT;
2581             goto out_nofid;
2582         }
2583         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2584         v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
2585     } else {
2586         old_name = fidp->path.data;
2587         end = strrchr(old_name, '/');
2588         if (end) {
2589             end++;
2590         } else {
2591             end = old_name;
2592         }
2593         new_name = g_malloc0(end - old_name + name->size + 1);
2594         strncat(new_name, old_name, end - old_name);
2595         strncat(new_name + (end - old_name), name->data, name->size);
2596         v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
2597         g_free(new_name);
2598     }
2599     err = v9fs_co_rename(pdu, &fidp->path, &new_path);
2600     if (err < 0) {
2601         goto out;
2602     }
2603     /*
2604      * Fixup fid's pointing to the old name to
2605      * start pointing to the new name
2606      */
2607     for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2608         if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2609             /* replace the name */
2610             v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
2611         }
2612     }
2613 out:
2614     if (dirfidp) {
2615         put_fid(pdu, dirfidp);
2616     }
2617     v9fs_path_free(&new_path);
2618 out_nofid:
2619     return err;
2620 }
2621
2622 /* Only works with path name based fid */
2623 static void v9fs_rename(void *opaque)
2624 {
2625     int32_t fid;
2626     ssize_t err = 0;
2627     size_t offset = 7;
2628     V9fsString name;
2629     int32_t newdirfid;
2630     V9fsFidState *fidp;
2631     V9fsPDU *pdu = opaque;
2632     V9fsState *s = pdu->s;
2633
2634     pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2635
2636     fidp = get_fid(pdu, fid);
2637     if (fidp == NULL) {
2638         err = -ENOENT;
2639         goto out_nofid;
2640     }
2641     BUG_ON(fidp->fid_type != P9_FID_NONE);
2642     /* if fs driver is not path based, return EOPNOTSUPP */
2643     if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2644         err = -EOPNOTSUPP;
2645         goto out;
2646     }
2647     v9fs_path_write_lock(s);
2648     err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
2649     v9fs_path_unlock(s);
2650     if (!err) {
2651         err = offset;
2652     }
2653 out:
2654     put_fid(pdu, fidp);
2655 out_nofid:
2656     complete_pdu(s, pdu, err);
2657     v9fs_string_free(&name);
2658 }
2659
2660 static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
2661                                V9fsString *old_name, V9fsPath *newdir,
2662                                V9fsString *new_name)
2663 {
2664     V9fsFidState *tfidp;
2665     V9fsPath oldpath, newpath;
2666     V9fsState *s = pdu->s;
2667
2668
2669     v9fs_path_init(&oldpath);
2670     v9fs_path_init(&newpath);
2671     v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
2672     v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
2673
2674     /*
2675      * Fixup fid's pointing to the old name to
2676      * start pointing to the new name
2677      */
2678     for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2679         if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
2680             /* replace the name */
2681             v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
2682         }
2683     }
2684     v9fs_path_free(&oldpath);
2685     v9fs_path_free(&newpath);
2686 }
2687
2688 static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
2689                                   V9fsString *old_name, int32_t newdirfid,
2690                                   V9fsString *new_name)
2691 {
2692     int err = 0;
2693     V9fsState *s = pdu->s;
2694     V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2695
2696     olddirfidp = get_fid(pdu, olddirfid);
2697     if (olddirfidp == NULL) {
2698         err = -ENOENT;
2699         goto out;
2700     }
2701     if (newdirfid != -1) {
2702         newdirfidp = get_fid(pdu, newdirfid);
2703         if (newdirfidp == NULL) {
2704             err = -ENOENT;
2705             goto out;
2706         }
2707     } else {
2708         newdirfidp = get_fid(pdu, olddirfid);
2709     }
2710
2711     err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
2712                            &newdirfidp->path, new_name);
2713     if (err < 0) {
2714         goto out;
2715     }
2716     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
2717         /* Only for path based fid  we need to do the below fixup */
2718         v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
2719                            &newdirfidp->path, new_name);
2720     }
2721 out:
2722     if (olddirfidp) {
2723         put_fid(pdu, olddirfidp);
2724     }
2725     if (newdirfidp) {
2726         put_fid(pdu, newdirfidp);
2727     }
2728     return err;
2729 }
2730
2731 static void v9fs_renameat(void *opaque)
2732 {
2733     ssize_t err = 0;
2734     size_t offset = 7;
2735     V9fsPDU *pdu = opaque;
2736     V9fsState *s = pdu->s;
2737     int32_t olddirfid, newdirfid;
2738     V9fsString old_name, new_name;
2739
2740     pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2741                   &old_name, &newdirfid, &new_name);
2742
2743     v9fs_path_write_lock(s);
2744     err = v9fs_complete_renameat(pdu, olddirfid,
2745                                  &old_name, newdirfid, &new_name);
2746     v9fs_path_unlock(s);
2747     if (!err) {
2748         err = offset;
2749     }
2750     complete_pdu(s, pdu, err);
2751     v9fs_string_free(&old_name);
2752     v9fs_string_free(&new_name);
2753 }
2754
2755 static void v9fs_wstat(void *opaque)
2756 {
2757     int32_t fid;
2758     int err = 0;
2759     int16_t unused;
2760     V9fsStat v9stat;
2761     size_t offset = 7;
2762     struct stat stbuf;
2763     V9fsFidState *fidp;
2764     V9fsPDU *pdu = opaque;
2765     V9fsState *s = pdu->s;
2766
2767     pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2768     trace_v9fs_wstat(pdu->tag, pdu->id, fid,
2769                      v9stat.mode, v9stat.atime, v9stat.mtime);
2770
2771     fidp = get_fid(pdu, fid);
2772     if (fidp == NULL) {
2773         err = -EINVAL;
2774         goto out_nofid;
2775     }
2776     /* do we need to sync the file? */
2777     if (donttouch_stat(&v9stat)) {
2778         err = v9fs_co_fsync(pdu, fidp, 0);
2779         goto out;
2780     }
2781     if (v9stat.mode != -1) {
2782         uint32_t v9_mode;
2783         err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2784         if (err < 0) {
2785             goto out;
2786         }
2787         v9_mode = stat_to_v9mode(&stbuf);
2788         if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2789             (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2790             /* Attempting to change the type */
2791             err = -EIO;
2792             goto out;
2793         }
2794         err = v9fs_co_chmod(pdu, &fidp->path,
2795                             v9mode_to_mode(v9stat.mode,
2796                                            &v9stat.extension));
2797         if (err < 0) {
2798             goto out;
2799         }
2800     }
2801     if (v9stat.mtime != -1 || v9stat.atime != -1) {
2802         struct timespec times[2];
2803         if (v9stat.atime != -1) {
2804             times[0].tv_sec = v9stat.atime;
2805             times[0].tv_nsec = 0;
2806         } else {
2807             times[0].tv_nsec = UTIME_OMIT;
2808         }
2809         if (v9stat.mtime != -1) {
2810             times[1].tv_sec = v9stat.mtime;
2811             times[1].tv_nsec = 0;
2812         } else {
2813             times[1].tv_nsec = UTIME_OMIT;
2814         }
2815         err = v9fs_co_utimensat(pdu, &fidp->path, times);
2816         if (err < 0) {
2817             goto out;
2818         }
2819     }
2820     if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2821         err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2822         if (err < 0) {
2823             goto out;
2824         }
2825     }
2826     if (v9stat.name.size != 0) {
2827         err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
2828         if (err < 0) {
2829             goto out;
2830         }
2831     }
2832     if (v9stat.length != -1) {
2833         err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
2834         if (err < 0) {
2835             goto out;
2836         }
2837     }
2838     err = offset;
2839 out:
2840     put_fid(pdu, fidp);
2841 out_nofid:
2842     v9fs_stat_free(&v9stat);
2843     complete_pdu(s, pdu, err);
2844 }
2845
2846 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2847 {
2848     uint32_t f_type;
2849     uint32_t f_bsize;
2850     uint64_t f_blocks;
2851     uint64_t f_bfree;
2852     uint64_t f_bavail;
2853     uint64_t f_files;
2854     uint64_t f_ffree;
2855     uint64_t fsid_val;
2856     uint32_t f_namelen;
2857     size_t offset = 7;
2858     int32_t bsize_factor;
2859
2860     /*
2861      * compute bsize factor based on host file system block size
2862      * and client msize
2863      */
2864     bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2865     if (!bsize_factor) {
2866         bsize_factor = 1;
2867     }
2868     f_type  = stbuf->f_type;
2869     f_bsize = stbuf->f_bsize;
2870     f_bsize *= bsize_factor;
2871     /*
2872      * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2873      * adjust(divide) the number of blocks, free blocks and available
2874      * blocks by bsize factor
2875      */
2876     f_blocks = stbuf->f_blocks/bsize_factor;
2877     f_bfree  = stbuf->f_bfree/bsize_factor;
2878     f_bavail = stbuf->f_bavail/bsize_factor;
2879     f_files  = stbuf->f_files;
2880     f_ffree  = stbuf->f_ffree;
2881     fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2882                (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2883     f_namelen = stbuf->f_namelen;
2884
2885     return pdu_marshal(pdu, offset, "ddqqqqqqd",
2886                        f_type, f_bsize, f_blocks, f_bfree,
2887                        f_bavail, f_files, f_ffree,
2888                        fsid_val, f_namelen);
2889 }
2890
2891 static void v9fs_statfs(void *opaque)
2892 {
2893     int32_t fid;
2894     ssize_t retval = 0;
2895     size_t offset = 7;
2896     V9fsFidState *fidp;
2897     struct statfs stbuf;
2898     V9fsPDU *pdu = opaque;
2899     V9fsState *s = pdu->s;
2900
2901     pdu_unmarshal(pdu, offset, "d", &fid);
2902     fidp = get_fid(pdu, fid);
2903     if (fidp == NULL) {
2904         retval = -ENOENT;
2905         goto out_nofid;
2906     }
2907     retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
2908     if (retval < 0) {
2909         goto out;
2910     }
2911     retval = offset;
2912     retval += v9fs_fill_statfs(s, pdu, &stbuf);
2913 out:
2914     put_fid(pdu, fidp);
2915 out_nofid:
2916     complete_pdu(s, pdu, retval);
2917     return;
2918 }
2919
2920 static void v9fs_mknod(void *opaque)
2921 {
2922
2923     int mode;
2924     gid_t gid;
2925     int32_t fid;
2926     V9fsQID qid;
2927     int err = 0;
2928     int major, minor;
2929     size_t offset = 7;
2930     V9fsString name;
2931     struct stat stbuf;
2932     V9fsFidState *fidp;
2933     V9fsPDU *pdu = opaque;
2934     V9fsState *s = pdu->s;
2935
2936     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2937                   &major, &minor, &gid);
2938     trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
2939
2940     fidp = get_fid(pdu, fid);
2941     if (fidp == NULL) {
2942         err = -ENOENT;
2943         goto out_nofid;
2944     }
2945     err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
2946                         makedev(major, minor), mode, &stbuf);
2947     if (err < 0) {
2948         goto out;
2949     }
2950     stat_to_qid(&stbuf, &qid);
2951     err = offset;
2952     err += pdu_marshal(pdu, offset, "Q", &qid);
2953 out:
2954     put_fid(pdu, fidp);
2955 out_nofid:
2956     trace_v9fs_mknod_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path);
2957     complete_pdu(s, pdu, err);
2958     v9fs_string_free(&name);
2959 }
2960
2961 /*
2962  * Implement posix byte range locking code
2963  * Server side handling of locking code is very simple, because 9p server in
2964  * QEMU can handle only one client. And most of the lock handling
2965  * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2966  * do any thing in * qemu 9p server side lock code path.
2967  * So when a TLOCK request comes, always return success
2968  */
2969 static void v9fs_lock(void *opaque)
2970 {
2971     int8_t status;
2972     V9fsFlock *flock;
2973     size_t offset = 7;
2974     struct stat stbuf;
2975     V9fsFidState *fidp;
2976     int32_t fid, err = 0;
2977     V9fsPDU *pdu = opaque;
2978     V9fsState *s = pdu->s;
2979
2980     flock = g_malloc(sizeof(*flock));
2981     pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
2982                   &flock->flags, &flock->start, &flock->length,
2983                   &flock->proc_id, &flock->client_id);
2984
2985     trace_v9fs_lock(pdu->tag, pdu->id, fid,
2986                     flock->type, flock->start, flock->length);
2987
2988     status = P9_LOCK_ERROR;
2989
2990     /* We support only block flag now (that too ignored currently) */
2991     if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
2992         err = -EINVAL;
2993         goto out_nofid;
2994     }
2995     fidp = get_fid(pdu, fid);
2996     if (fidp == NULL) {
2997         err = -ENOENT;
2998         goto out_nofid;
2999     }
3000     err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
3001     if (err < 0) {
3002         goto out;
3003     }
3004     status = P9_LOCK_SUCCESS;
3005 out:
3006     put_fid(pdu, fidp);
3007 out_nofid:
3008     err = offset;
3009     err += pdu_marshal(pdu, offset, "b", status);
3010     trace_v9fs_lock_return(pdu->tag, pdu->id, status);
3011     complete_pdu(s, pdu, err);
3012     v9fs_string_free(&flock->client_id);
3013     g_free(flock);
3014 }
3015
3016 /*
3017  * When a TGETLOCK request comes, always return success because all lock
3018  * handling is done by client's VFS layer.
3019  */
3020 static void v9fs_getlock(void *opaque)
3021 {
3022     size_t offset = 7;
3023     struct stat stbuf;
3024     V9fsFidState *fidp;
3025     V9fsGetlock *glock;
3026     int32_t fid, err = 0;
3027     V9fsPDU *pdu = opaque;
3028     V9fsState *s = pdu->s;
3029
3030     glock = g_malloc(sizeof(*glock));
3031     pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
3032                   &glock->start, &glock->length, &glock->proc_id,
3033                   &glock->client_id);
3034
3035     trace_v9fs_getlock(pdu->tag, pdu->id, fid,
3036                        glock->type, glock->start, glock->length);
3037
3038     fidp = get_fid(pdu, fid);
3039     if (fidp == NULL) {
3040         err = -ENOENT;
3041         goto out_nofid;
3042     }
3043     err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
3044     if (err < 0) {
3045         goto out;
3046     }
3047     glock->type = P9_LOCK_TYPE_UNLCK;
3048     offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
3049                           glock->start, glock->length, glock->proc_id,
3050                           &glock->client_id);
3051     err = offset;
3052 out:
3053     put_fid(pdu, fidp);
3054 out_nofid:
3055     trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
3056                               glock->length, glock->proc_id);
3057
3058     complete_pdu(s, pdu, err);
3059     v9fs_string_free(&glock->client_id);
3060     g_free(glock);
3061 }
3062
3063 static void v9fs_mkdir(void *opaque)
3064 {
3065     V9fsPDU *pdu = opaque;
3066     size_t offset = 7;
3067     int32_t fid;
3068     struct stat stbuf;
3069     V9fsQID qid;
3070     V9fsString name;
3071     V9fsFidState *fidp;
3072     gid_t gid;
3073     int mode;
3074     int err = 0;
3075
3076     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3077
3078     trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
3079
3080     fidp = get_fid(pdu, fid);
3081     if (fidp == NULL) {
3082         err = -ENOENT;
3083         goto out_nofid;
3084     }
3085     err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
3086     if (err < 0) {
3087         goto out;
3088     }
3089     stat_to_qid(&stbuf, &qid);
3090     offset += pdu_marshal(pdu, offset, "Q", &qid);
3091     err = offset;
3092 out:
3093     put_fid(pdu, fidp);
3094 out_nofid:
3095     trace_v9fs_mkdir_return(pdu->tag, pdu->id,
3096                             qid.type, qid.version, qid.path, err);
3097     complete_pdu(pdu->s, pdu, err);
3098     v9fs_string_free(&name);
3099 }
3100
3101 static void v9fs_xattrwalk(void *opaque)
3102 {
3103     int64_t size;
3104     V9fsString name;
3105     ssize_t err = 0;
3106     size_t offset = 7;
3107     int32_t fid, newfid;
3108     V9fsFidState *file_fidp;
3109     V9fsFidState *xattr_fidp = NULL;
3110     V9fsPDU *pdu = opaque;
3111     V9fsState *s = pdu->s;
3112
3113     pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3114     trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
3115
3116     file_fidp = get_fid(pdu, fid);
3117     if (file_fidp == NULL) {
3118         err = -ENOENT;
3119         goto out_nofid;
3120     }
3121     xattr_fidp = alloc_fid(s, newfid);
3122     if (xattr_fidp == NULL) {
3123         err = -EINVAL;
3124         goto out;
3125     }
3126     v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
3127     if (name.data[0] == 0) {
3128         /*
3129          * listxattr request. Get the size first
3130          */
3131         size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
3132         if (size < 0) {
3133             err = size;
3134             clunk_fid(s, xattr_fidp->fid);
3135             goto out;
3136         }
3137         /*
3138          * Read the xattr value
3139          */
3140         xattr_fidp->fs.xattr.len = size;
3141         xattr_fidp->fid_type = P9_FID_XATTR;
3142         xattr_fidp->fs.xattr.copied_len = -1;
3143         if (size) {
3144             xattr_fidp->fs.xattr.value = g_malloc(size);
3145             err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
3146                                      xattr_fidp->fs.xattr.value,
3147                                      xattr_fidp->fs.xattr.len);
3148             if (err < 0) {
3149                 clunk_fid(s, xattr_fidp->fid);
3150                 goto out;
3151             }
3152         }
3153         offset += pdu_marshal(pdu, offset, "q", size);
3154         err = offset;
3155     } else {
3156         /*
3157          * specific xattr fid. We check for xattr
3158          * presence also collect the xattr size
3159          */
3160         size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3161                                  &name, NULL, 0);
3162         if (size < 0) {
3163             err = size;
3164             clunk_fid(s, xattr_fidp->fid);
3165             goto out;
3166         }
3167         /*
3168          * Read the xattr value
3169          */
3170         xattr_fidp->fs.xattr.len = size;
3171         xattr_fidp->fid_type = P9_FID_XATTR;
3172         xattr_fidp->fs.xattr.copied_len = -1;
3173         if (size) {
3174             xattr_fidp->fs.xattr.value = g_malloc(size);
3175             err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3176                                     &name, xattr_fidp->fs.xattr.value,
3177                                     xattr_fidp->fs.xattr.len);
3178             if (err < 0) {
3179                 clunk_fid(s, xattr_fidp->fid);
3180                 goto out;
3181             }
3182         }
3183         offset += pdu_marshal(pdu, offset, "q", size);
3184         err = offset;
3185     }
3186 out:
3187     put_fid(pdu, file_fidp);
3188     if (xattr_fidp) {
3189         put_fid(pdu, xattr_fidp);
3190     }
3191 out_nofid:
3192     trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
3193     complete_pdu(s, pdu, err);
3194     v9fs_string_free(&name);
3195 }
3196
3197 static void v9fs_xattrcreate(void *opaque)
3198 {
3199     int flags;
3200     int32_t fid;
3201     int64_t size;
3202     ssize_t err = 0;
3203     V9fsString name;
3204     size_t offset = 7;
3205     V9fsFidState *file_fidp;
3206     V9fsFidState *xattr_fidp;
3207     V9fsPDU *pdu = opaque;
3208     V9fsState *s = pdu->s;
3209
3210     pdu_unmarshal(pdu, offset, "dsqd",
3211                   &fid, &name, &size, &flags);
3212     trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
3213
3214     file_fidp = get_fid(pdu, fid);
3215     if (file_fidp == NULL) {
3216         err = -EINVAL;
3217         goto out_nofid;
3218     }
3219     /* Make the file fid point to xattr */
3220     xattr_fidp = file_fidp;
3221     xattr_fidp->fid_type = P9_FID_XATTR;
3222     xattr_fidp->fs.xattr.copied_len = 0;
3223     xattr_fidp->fs.xattr.len = size;
3224     xattr_fidp->fs.xattr.flags = flags;
3225     v9fs_string_init(&xattr_fidp->fs.xattr.name);
3226     v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3227     if (size) {
3228         xattr_fidp->fs.xattr.value = g_malloc(size);
3229     } else {
3230         xattr_fidp->fs.xattr.value = NULL;
3231     }
3232     err = offset;
3233     put_fid(pdu, file_fidp);
3234 out_nofid:
3235     complete_pdu(s, pdu, err);
3236     v9fs_string_free(&name);
3237 }
3238
3239 static void v9fs_readlink(void *opaque)
3240 {
3241     V9fsPDU *pdu = opaque;
3242     size_t offset = 7;
3243     V9fsString target;
3244     int32_t fid;
3245     int err = 0;
3246     V9fsFidState *fidp;
3247
3248     pdu_unmarshal(pdu, offset, "d", &fid);
3249     trace_v9fs_readlink(pdu->tag, pdu->id, fid);
3250     fidp = get_fid(pdu, fid);
3251     if (fidp == NULL) {
3252         err = -ENOENT;
3253         goto out_nofid;
3254     }
3255
3256     v9fs_string_init(&target);
3257     err = v9fs_co_readlink(pdu, &fidp->path, &target);
3258     if (err < 0) {
3259         goto out;
3260     }
3261     offset += pdu_marshal(pdu, offset, "s", &target);
3262     err = offset;
3263     v9fs_string_free(&target);
3264 out:
3265     put_fid(pdu, fidp);
3266 out_nofid:
3267     trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
3268     complete_pdu(pdu->s, pdu, err);
3269 }
3270
3271 static CoroutineEntry *pdu_co_handlers[] = {
3272     [P9_TREADDIR] = v9fs_readdir,
3273     [P9_TSTATFS] = v9fs_statfs,
3274     [P9_TGETATTR] = v9fs_getattr,
3275     [P9_TSETATTR] = v9fs_setattr,
3276     [P9_TXATTRWALK] = v9fs_xattrwalk,
3277     [P9_TXATTRCREATE] = v9fs_xattrcreate,
3278     [P9_TMKNOD] = v9fs_mknod,
3279     [P9_TRENAME] = v9fs_rename,
3280     [P9_TLOCK] = v9fs_lock,
3281     [P9_TGETLOCK] = v9fs_getlock,
3282     [P9_TRENAMEAT] = v9fs_renameat,
3283     [P9_TREADLINK] = v9fs_readlink,
3284     [P9_TUNLINKAT] = v9fs_unlinkat,
3285     [P9_TMKDIR] = v9fs_mkdir,
3286     [P9_TVERSION] = v9fs_version,
3287     [P9_TLOPEN] = v9fs_open,
3288     [P9_TATTACH] = v9fs_attach,
3289     [P9_TSTAT] = v9fs_stat,
3290     [P9_TWALK] = v9fs_walk,
3291     [P9_TCLUNK] = v9fs_clunk,
3292     [P9_TFSYNC] = v9fs_fsync,
3293     [P9_TOPEN] = v9fs_open,
3294     [P9_TREAD] = v9fs_read,
3295 #if 0
3296     [P9_TAUTH] = v9fs_auth,
3297 #endif
3298     [P9_TFLUSH] = v9fs_flush,
3299     [P9_TLINK] = v9fs_link,
3300     [P9_TSYMLINK] = v9fs_symlink,
3301     [P9_TCREATE] = v9fs_create,
3302     [P9_TLCREATE] = v9fs_lcreate,
3303     [P9_TWRITE] = v9fs_write,
3304     [P9_TWSTAT] = v9fs_wstat,
3305     [P9_TREMOVE] = v9fs_remove,
3306 };
3307
3308 static void v9fs_op_not_supp(void *opaque)
3309 {
3310     V9fsPDU *pdu = opaque;
3311     complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3312 }
3313
3314 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3315 {
3316     Coroutine *co;
3317     CoroutineEntry *handler;
3318
3319     if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3320         (pdu_co_handlers[pdu->id] == NULL)) {
3321         handler = v9fs_op_not_supp;
3322     } else {
3323         handler = pdu_co_handlers[pdu->id];
3324     }
3325     co = qemu_coroutine_create(handler);
3326     qemu_coroutine_enter(co, pdu);
3327 }
3328
3329 void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3330 {
3331     V9fsState *s = (V9fsState *)vdev;
3332     V9fsPDU *pdu;
3333     ssize_t len;
3334
3335     while ((pdu = alloc_pdu(s)) &&
3336             (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3337         uint8_t *ptr;
3338         pdu->s = s;
3339         BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3340         BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3341
3342         ptr = pdu->elem.out_sg[0].iov_base;
3343
3344         memcpy(&pdu->size, ptr, 4);
3345         pdu->id = ptr[4];
3346         memcpy(&pdu->tag, ptr + 5, 2);
3347         qemu_co_queue_init(&pdu->complete);
3348         submit_pdu(s, pdu);
3349     }
3350     free_pdu(s, pdu);
3351 }
3352
3353 void virtio_9p_set_fd_limit(void)
3354 {
3355     struct rlimit rlim;
3356     if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3357         fprintf(stderr, "Failed to get the resource limit\n");
3358         exit(1);
3359     }
3360     open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3361     open_fd_rc = rlim.rlim_cur/2;
3362 }
This page took 0.21119 seconds and 4 git commands to generate.