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