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