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