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