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