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