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