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