MAINTAINERS: add tracing subsystem
[qemu/ar7.git] / hw / 9pfs / virtio-9p.c
blobd28edb799a05a3d148013ba52f54bc06b02ddb64
1 /*
2 * Virtio 9p backend
4 * Copyright IBM, Corp. 2010
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
14 #include "hw/virtio.h"
15 #include "hw/pc.h"
16 #include "qemu_socket.h"
17 #include "hw/virtio-pci.h"
18 #include "virtio-9p.h"
19 #include "fsdev/qemu-fsdev.h"
20 #include "virtio-9p-debug.h"
21 #include "virtio-9p-xattr.h"
22 #include "virtio-9p-coth.h"
24 int debug_9p_pdu;
25 int open_fd_hw;
26 int total_open_fd;
27 static int open_fd_rc;
29 enum {
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,
41 static int omode_to_uflags(int8_t mode)
43 int ret = 0;
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;
60 if (mode & Otrunc) {
61 ret |= O_TRUNC;
64 if (mode & Oappend) {
65 ret |= O_APPEND;
68 if (mode & Oexcl) {
69 ret |= O_EXCL;
72 return ret;
75 void cred_init(FsCred *credp)
77 credp->fc_uid = -1;
78 credp->fc_gid = -1;
79 credp->fc_mode = -1;
80 credp->fc_rdev = -1;
83 static void v9fs_string_init(V9fsString *str)
85 str->data = NULL;
86 str->size = 0;
89 static void v9fs_string_free(V9fsString *str)
91 g_free(str->data);
92 str->data = NULL;
93 str->size = 0;
96 static void v9fs_string_null(V9fsString *str)
98 v9fs_string_free(str);
101 static int number_to_string(void *arg, char type)
103 unsigned int ret = 0;
105 switch (type) {
106 case 'u': {
107 unsigned int num = *(unsigned int *)arg;
109 do {
110 ret++;
111 num = num/10;
112 } while (num);
113 break;
115 case 'U': {
116 unsigned long num = *(unsigned long *)arg;
117 do {
118 ret++;
119 num = num/10;
120 } while (num);
121 break;
123 default:
124 printf("Number_to_string: Unknown number format\n");
125 return -1;
128 return ret;
131 static int GCC_FMT_ATTR(2, 0)
132 v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
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;
140 unsigned long arg_ulong;
142 /* Find the number of %'s that denotes an argument */
143 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
144 nr_args++;
145 iter++;
148 len = strlen(fmt) - 2*nr_args;
150 if (!nr_args) {
151 goto alloc_print;
154 va_copy(ap2, ap);
156 iter = (char *)fmt;
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;
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;
173 break;
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;
186 iter++;
189 alloc_print:
190 *strp = g_malloc((len + 1) * sizeof(**strp));
192 return vsprintf(*strp, fmt, ap);
195 static void GCC_FMT_ATTR(2, 3)
196 v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
198 va_list ap;
199 int err;
201 v9fs_string_free(str);
203 va_start(ap, fmt);
204 err = v9fs_string_alloc_printf(&str->data, fmt, ap);
205 BUG_ON(err == -1);
206 va_end(ap);
208 str->size = err;
211 static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
213 v9fs_string_free(lhs);
214 v9fs_string_sprintf(lhs, "%s", rhs->data);
218 * Return TRUE if s1 is an ancestor of s2.
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!
223 static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
225 if (!strncmp(s1->data, s2->data, s1->size)) {
226 if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
227 return 1;
230 return 0;
233 static size_t v9fs_string_size(V9fsString *str)
235 return str->size;
239 * returns 0 if fid got re-opened, 1 if not, < 0 on error */
240 static int v9fs_reopen_fid(V9fsState *s, V9fsFidState *f)
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);
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);
256 return err;
259 static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
261 int err;
262 V9fsFidState *f;
264 for (f = s->fid_list; f; f = f->next) {
265 BUG_ON(f->clunked);
266 if (f->fid == fid) {
268 * Update the fid ref upfront so that
269 * we don't get reclaimed when we yield
270 * in open later.
272 f->ref++;
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.
279 err = v9fs_reopen_fid(s, f);
280 if (err < 0) {
281 f->ref--;
282 return NULL;
285 * Mark the fid as referenced so that the LRU
286 * reclaim won't close the file descriptor
288 f->flags |= FID_REFERENCED;
289 return f;
292 return NULL;
295 static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
297 V9fsFidState *f;
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;
306 f = g_malloc0(sizeof(V9fsFidState));
307 f->fid = fid;
308 f->fid_type = P9_FID_NONE;
309 f->ref = 1;
311 * Mark the fid as referenced so that the LRU
312 * reclaim won't close the file descriptor
314 f->flags |= FID_REFERENCED;
315 f->next = s->fid_list;
316 s->fid_list = f;
318 return f;
321 static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
323 int retval = 0;
325 if (fidp->fs.xattr.copied_len == -1) {
326 /* getxattr/listxattr fid */
327 goto free_value;
330 * if this is fid for setxattr. clunk should
331 * result in setxattr localcall
333 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
334 /* clunk after partial write */
335 retval = -EINVAL;
336 goto free_out;
338 if (fidp->fs.xattr.len) {
339 retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
340 fidp->fs.xattr.value,
341 fidp->fs.xattr.len,
342 fidp->fs.xattr.flags);
343 } else {
344 retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
346 free_out:
347 v9fs_string_free(&fidp->fs.xattr.name);
348 free_value:
349 if (fidp->fs.xattr.value) {
350 g_free(fidp->fs.xattr.value);
352 return retval;
355 static int free_fid(V9fsState *s, V9fsFidState *fidp)
357 int retval = 0;
359 if (fidp->fid_type == P9_FID_FILE) {
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);
364 } else if (fidp->fid_type == P9_FID_DIR) {
365 if (fidp->fs.dir != NULL) {
366 retval = v9fs_co_closedir(s, fidp->fs.dir);
368 } else if (fidp->fid_type == P9_FID_XATTR) {
369 retval = v9fs_xattr_fid_clunk(s, fidp);
371 v9fs_string_free(&fidp->path);
372 g_free(fidp);
373 return retval;
376 static void put_fid(V9fsState *s, V9fsFidState *fidp)
378 BUG_ON(!fidp->ref);
379 fidp->ref--;
381 * Don't free the fid if it is in reclaim list
383 if (!fidp->ref && fidp->clunked) {
384 free_fid(s, fidp);
388 static int clunk_fid(V9fsState *s, int32_t fid)
390 V9fsFidState **fidpp, *fidp;
392 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
393 if ((*fidpp)->fid == fid) {
394 break;
398 if (*fidpp == NULL) {
399 return -ENOENT;
401 fidp = *fidpp;
402 *fidpp = fidp->next;
403 fidp->clunked = 1;
404 return 0;
407 void v9fs_reclaim_fd(V9fsState *s)
409 int reclaim_count = 0;
410 V9fsFidState *f, *reclaim_list = NULL;
412 for (f = s->fid_list; f; f = f->next) {
414 * Unlink fids cannot be reclaimed. Check
415 * for them and skip them. Also skip fids
416 * currently being operated on.
418 if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
419 continue;
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)
428 if (f->flags & FID_REFERENCED) {
429 f->flags &= ~FID_REFERENCED;
430 continue;
433 * Add fids to reclaim list.
435 if (f->fid_type == P9_FID_FILE) {
436 if (f->fs.fd != -1) {
438 * Up the reference count so that
439 * a clunk request won't free this fid
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++;
448 } else if (f->fid_type == P9_FID_DIR) {
449 if (f->fs.dir != NULL) {
451 * Up the reference count so that
452 * a clunk request won't free this fid
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++;
462 if (reclaim_count >= open_fd_rc) {
463 break;
467 * Now close the fid in reclaim list. Free them if they
468 * are already clunked.
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);
475 } else if (f->fid_type == P9_FID_DIR) {
476 v9fs_co_closedir(s, f->fs_reclaim.dir);
478 f->rclm_lst = NULL;
480 * Now drop the fid reference, free it
481 * if clunked.
483 put_fid(s, f);
487 static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
489 int err;
490 V9fsFidState *fidp, head_fid;
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;
498 /* reopen the file/dir if already closed */
499 err = v9fs_reopen_fid(s, fidp);
500 if (err < 0) {
501 return -1;
504 * Go back to head of fid list because
505 * the list could have got updated when
506 * switched to the worker thread
508 if (err == 0) {
509 fidp = &head_fid;
513 return 0;
516 #define P9_QID_TYPE_DIR 0x80
517 #define P9_QID_TYPE_SYMLINK 0x02
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
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)
541 /* This is the algorithm from ufs in spfs */
542 static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
544 size_t size;
546 memset(&qidp->path, 0, sizeof(qidp->path));
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;
554 if (S_ISLNK(stbuf->st_mode)) {
555 qidp->type |= P9_QID_TYPE_SYMLINK;
559 static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
561 struct stat stbuf;
562 int err;
564 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
565 if (err < 0) {
566 return err;
568 stat_to_qid(&stbuf, qidp);
569 return 0;
572 static V9fsPDU *alloc_pdu(V9fsState *s)
574 V9fsPDU *pdu = NULL;
576 if (!QLIST_EMPTY(&s->free_list)) {
577 pdu = QLIST_FIRST(&s->free_list);
578 QLIST_REMOVE(pdu, next);
580 return pdu;
583 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
585 if (pdu) {
586 if (debug_9p_pdu) {
587 pprint_pdu(pdu);
589 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
593 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
594 size_t offset, size_t size, int pack)
596 int i = 0;
597 size_t copied = 0;
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);
612 size -= len;
613 copied += len;
614 addr += len;
615 if (size) {
616 offset = 0;
617 continue;
622 return copied;
625 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
627 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
628 offset, size, 0);
631 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
632 size_t size)
634 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
635 offset, size, 1);
638 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
640 size_t pos = 0;
641 int i, j;
642 struct iovec *src_sg;
643 unsigned int num;
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;
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++;
666 pos += src_sg[i].iov_len;
669 return j;
672 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
674 size_t old_offset = offset;
675 va_list ap;
676 int i;
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;
686 case 'w': {
687 uint16_t val, *valp;
688 valp = va_arg(ap, uint16_t *);
689 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
690 *valp = le16_to_cpu(val);
691 break;
693 case 'd': {
694 uint32_t val, *valp;
695 valp = va_arg(ap, uint32_t *);
696 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
697 *valp = le32_to_cpu(val);
698 break;
700 case 'q': {
701 uint64_t val, *valp;
702 valp = va_arg(ap, uint64_t *);
703 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
704 *valp = le64_to_cpu(val);
705 break;
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;
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 */
717 str->data = g_malloc(str->size + 1);
718 offset += pdu_unpack(str->data, pdu, offset, str->size);
719 str->data[str->size] = 0;
720 break;
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;
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;
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;
749 default:
750 break;
754 va_end(ap);
756 return offset - old_offset;
759 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
761 size_t old_offset = offset;
762 va_list ap;
763 int i;
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;
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;
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;
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;
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;
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;
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;
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;
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;
835 default:
836 break;
839 va_end(ap);
841 return offset - old_offset;
844 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
846 int8_t id = pdu->id + 1; /* Response */
848 if (len < 0) {
849 int err = -len;
850 len = 7;
852 if (s->proto_version != V9FS_PROTO_2000L) {
853 V9fsString str;
855 str.data = strerror(err);
856 str.size = strlen(str.data);
858 len += pdu_marshal(pdu, len, "s", &str);
859 id = P9_RERROR;
862 len += pdu_marshal(pdu, len, "d", err);
864 if (s->proto_version == V9FS_PROTO_2000L) {
865 id = P9_RLERROR;
869 /* fill out the header */
870 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
872 /* keep these in sync */
873 pdu->size = len;
874 pdu->id = id;
876 /* push onto queue and notify */
877 virtqueue_push(s->vq, &pdu->elem, len);
879 /* FIXME: we should batch these completions */
880 virtio_notify(&s->vdev, s->vq);
882 free_pdu(s, pdu);
885 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
887 mode_t ret;
889 ret = mode & 0777;
890 if (mode & P9_STAT_MODE_DIR) {
891 ret |= S_IFDIR;
894 if (mode & P9_STAT_MODE_SYMLINK) {
895 ret |= S_IFLNK;
897 if (mode & P9_STAT_MODE_SOCKET) {
898 ret |= S_IFSOCK;
900 if (mode & P9_STAT_MODE_NAMED_PIPE) {
901 ret |= S_IFIFO;
903 if (mode & P9_STAT_MODE_DEVICE) {
904 if (extension && extension->data[0] == 'c') {
905 ret |= S_IFCHR;
906 } else {
907 ret |= S_IFBLK;
911 if (!(ret&~0777)) {
912 ret |= S_IFREG;
915 if (mode & P9_STAT_MODE_SETUID) {
916 ret |= S_ISUID;
918 if (mode & P9_STAT_MODE_SETGID) {
919 ret |= S_ISGID;
921 if (mode & P9_STAT_MODE_SETVTX) {
922 ret |= S_ISVTX;
925 return ret;
928 static int donttouch_stat(V9fsStat *stat)
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;
949 return 0;
952 static void v9fs_stat_free(V9fsStat *stat)
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);
961 static uint32_t stat_to_v9mode(const struct stat *stbuf)
963 uint32_t mode;
965 mode = stbuf->st_mode & 0777;
966 if (S_ISDIR(stbuf->st_mode)) {
967 mode |= P9_STAT_MODE_DIR;
970 if (S_ISLNK(stbuf->st_mode)) {
971 mode |= P9_STAT_MODE_SYMLINK;
974 if (S_ISSOCK(stbuf->st_mode)) {
975 mode |= P9_STAT_MODE_SOCKET;
978 if (S_ISFIFO(stbuf->st_mode)) {
979 mode |= P9_STAT_MODE_NAMED_PIPE;
982 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
983 mode |= P9_STAT_MODE_DEVICE;
986 if (stbuf->st_mode & S_ISUID) {
987 mode |= P9_STAT_MODE_SETUID;
990 if (stbuf->st_mode & S_ISGID) {
991 mode |= P9_STAT_MODE_SETGID;
994 if (stbuf->st_mode & S_ISVTX) {
995 mode |= P9_STAT_MODE_SETVTX;
998 return mode;
1001 static int stat_to_v9stat(V9fsState *s, V9fsString *name,
1002 const struct stat *stbuf,
1003 V9fsStat *v9stat)
1005 int err;
1006 const char *str;
1008 memset(v9stat, 0, sizeof(*v9stat));
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;
1016 v9fs_string_null(&v9stat->uid);
1017 v9fs_string_null(&v9stat->gid);
1018 v9fs_string_null(&v9stat->muid);
1020 v9stat->n_uid = stbuf->st_uid;
1021 v9stat->n_gid = stbuf->st_gid;
1022 v9stat->n_muid = 0;
1024 v9fs_string_null(&v9stat->extension);
1026 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1027 err = v9fs_co_readlink(s, name, &v9stat->extension);
1028 if (err < 0) {
1029 return err;
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)) {
1036 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1037 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1040 str = strrchr(name->data, '/');
1041 if (str) {
1042 str += 1;
1043 } else {
1044 str = name->data;
1047 v9fs_string_sprintf(&v9stat->name, "%s", str);
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;
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
1070 #define P9_STATS_BTIME 0x00000800ULL
1071 #define P9_STATS_GEN 0x00001000ULL
1072 #define P9_STATS_DATA_VERSION 0x00002000ULL
1074 #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
1075 #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
1078 static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1079 V9fsStatDotl *v9lstat)
1081 memset(v9lstat, 0, sizeof(*v9lstat));
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;
1100 stat_to_qid(stbuf, &v9lstat->qid);
1103 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
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;
1117 return sg;
1120 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1122 int i;
1123 int total = 0;
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;
1131 total += sg[i].iov_len;
1134 *cnt = i;
1136 return sg;
1139 static void print_sg(struct iovec *sg, int cnt)
1141 int i;
1143 printf("sg[%d]: {", cnt);
1144 for (i = 0; i < cnt; i++) {
1145 if (i) {
1146 printf(", ");
1148 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1150 printf("}\n");
1153 static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
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);
1162 static void v9fs_version(void *opaque)
1164 V9fsPDU *pdu = opaque;
1165 V9fsState *s = pdu->s;
1166 V9fsString version;
1167 size_t offset = 7;
1169 pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
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 {
1176 v9fs_string_sprintf(&version, "unknown");
1179 offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1180 complete_pdu(s, pdu, offset);
1182 v9fs_string_free(&version);
1183 return;
1186 static void v9fs_attach(void *opaque)
1188 V9fsPDU *pdu = opaque;
1189 V9fsState *s = pdu->s;
1190 int32_t fid, afid, n_uname;
1191 V9fsString uname, aname;
1192 V9fsFidState *fidp;
1193 size_t offset = 7;
1194 V9fsQID qid;
1195 ssize_t err;
1197 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1199 fidp = alloc_fid(s, fid);
1200 if (fidp == NULL) {
1201 err = -EINVAL;
1202 goto out_nofid;
1204 fidp->uid = n_uname;
1205 v9fs_string_sprintf(&fidp->path, "%s", "/");
1206 err = fid_to_qid(s, fidp, &qid);
1207 if (err < 0) {
1208 err = -EINVAL;
1209 clunk_fid(s, fid);
1210 goto out;
1212 offset += pdu_marshal(pdu, offset, "Q", &qid);
1213 err = offset;
1214 out:
1215 put_fid(s, fidp);
1216 out_nofid:
1217 complete_pdu(s, pdu, err);
1218 v9fs_string_free(&uname);
1219 v9fs_string_free(&aname);
1222 static void v9fs_stat(void *opaque)
1224 int32_t fid;
1225 V9fsStat v9stat;
1226 ssize_t err = 0;
1227 size_t offset = 7;
1228 struct stat stbuf;
1229 V9fsFidState *fidp;
1230 V9fsPDU *pdu = opaque;
1231 V9fsState *s = pdu->s;
1233 pdu_unmarshal(pdu, offset, "d", &fid);
1235 fidp = get_fid(s, fid);
1236 if (fidp == NULL) {
1237 err = -ENOENT;
1238 goto out_nofid;
1240 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1241 if (err < 0) {
1242 goto out;
1244 err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
1245 if (err < 0) {
1246 goto out;
1248 offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1249 err = offset;
1250 v9fs_stat_free(&v9stat);
1251 out:
1252 put_fid(s, fidp);
1253 out_nofid:
1254 complete_pdu(s, pdu, err);
1257 static void v9fs_getattr(void *opaque)
1259 int32_t fid;
1260 size_t offset = 7;
1261 ssize_t retval = 0;
1262 struct stat stbuf;
1263 V9fsFidState *fidp;
1264 uint64_t request_mask;
1265 V9fsStatDotl v9stat_dotl;
1266 V9fsPDU *pdu = opaque;
1267 V9fsState *s = pdu->s;
1269 pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1271 fidp = get_fid(s, fid);
1272 if (fidp == NULL) {
1273 retval = -ENOENT;
1274 goto out_nofid;
1277 * Currently we only support BASIC fields in stat, so there is no
1278 * need to look at request_mask.
1280 retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
1281 if (retval < 0) {
1282 goto out;
1284 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1285 retval = offset;
1286 retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1287 out:
1288 put_fid(s, fidp);
1289 out_nofid:
1290 complete_pdu(s, pdu, retval);
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)
1305 static void v9fs_setattr(void *opaque)
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;
1315 pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1317 fidp = get_fid(s, fid);
1318 if (fidp == NULL) {
1319 err = -EINVAL;
1320 goto out_nofid;
1322 if (v9iattr.valid & ATTR_MODE) {
1323 err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
1324 if (err < 0) {
1325 goto out;
1328 if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1329 struct timespec times[2];
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;
1334 } else {
1335 times[0].tv_nsec = UTIME_NOW;
1337 } else {
1338 times[0].tv_nsec = UTIME_OMIT;
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;
1344 } else {
1345 times[1].tv_nsec = UTIME_NOW;
1347 } else {
1348 times[1].tv_nsec = UTIME_OMIT;
1350 err = v9fs_co_utimensat(s, &fidp->path, times);
1351 if (err < 0) {
1352 goto out;
1356 * If the only valid entry in iattr is ctime we can call
1357 * chown(-1,-1) to update the ctime of the file
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;
1365 if (!(v9iattr.valid & ATTR_GID)) {
1366 v9iattr.gid = -1;
1368 err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
1369 v9iattr.gid);
1370 if (err < 0) {
1371 goto out;
1374 if (v9iattr.valid & (ATTR_SIZE)) {
1375 err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
1376 if (err < 0) {
1377 goto out;
1380 err = offset;
1381 out:
1382 put_fid(s, fidp);
1383 out_nofid:
1384 complete_pdu(s, pdu, err);
1387 static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1389 int i;
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]);
1395 return offset;
1398 static void v9fs_walk(void *opaque)
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;
1410 V9fsFidState *newfidp = NULL;;
1411 V9fsPDU *pdu = opaque;
1412 V9fsState *s = pdu->s;
1414 offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
1415 &newfid, &nwnames);
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]);
1424 } else if (nwnames > P9_MAXWELEM) {
1425 err = -EINVAL;
1426 goto out_nofid;
1428 fidp = get_fid(s, fid);
1429 if (fidp == NULL) {
1430 err = -ENOENT;
1431 goto out_nofid;
1433 if (fid == newfid) {
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);
1441 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1442 if (err < 0) {
1443 v9fs_string_free(&path);
1444 goto out;
1446 stat_to_qid(&stbuf, &qids[name_idx]);
1448 v9fs_string_free(&path);
1449 } else {
1450 newfidp = alloc_fid(s, newfid);
1451 if (newfidp == NULL) {
1452 err = -EINVAL;
1453 goto out;
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) {
1464 clunk_fid(s, newfidp->fid);
1465 v9fs_string_free(&path);
1466 goto out;
1468 stat_to_qid(&stbuf, &qids[name_idx]);
1470 v9fs_string_free(&path);
1472 err = v9fs_walk_marshal(pdu, nwnames, qids);
1473 out:
1474 put_fid(s, fidp);
1475 if (newfidp) {
1476 put_fid(s, newfidp);
1478 out_nofid:
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]);
1484 g_free(wnames);
1485 g_free(qids);
1489 static int32_t get_iounit(V9fsState *s, V9fsString *name)
1491 struct statfs stbuf;
1492 int32_t iounit = 0;
1495 * iounit should be multiples of f_bsize (host filesystem block size
1496 * and as well as less than (client msize - P9_IOHDRSZ))
1498 if (!v9fs_co_statfs(s, name, &stbuf)) {
1499 iounit = stbuf.f_bsize;
1500 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1502 if (!iounit) {
1503 iounit = s->msize - P9_IOHDRSZ;
1505 return iounit;
1508 static void v9fs_open(void *opaque)
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;
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);
1527 fidp = get_fid(s, fid);
1528 if (fidp == NULL) {
1529 err = -ENOENT;
1530 goto out_nofid;
1532 BUG_ON(fidp->fid_type != P9_FID_NONE);
1534 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1535 if (err < 0) {
1536 goto out;
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;
1544 fidp->fid_type = P9_FID_DIR;
1545 offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
1546 err = offset;
1547 } else {
1548 if (s->proto_version == V9FS_PROTO_2000L) {
1549 flags = mode;
1550 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1551 /* Ignore direct disk access hint until the server supports it. */
1552 flags &= ~O_DIRECT;
1553 } else {
1554 flags = omode_to_uflags(mode);
1556 err = v9fs_co_open(s, fidp, flags);
1557 if (err < 0) {
1558 goto out;
1560 fidp->fid_type = P9_FID_FILE;
1561 fidp->open_flags = flags;
1562 if (flags & O_EXCL) {
1564 * We let the host file system do O_EXCL check
1565 * We should not reclaim such fd
1567 fidp->flags |= FID_NON_RECLAIMABLE;
1569 iounit = get_iounit(s, &fidp->path);
1570 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1571 err = offset;
1573 out:
1574 put_fid(s, fidp);
1575 out_nofid:
1576 complete_pdu(s, pdu, err);
1579 static void v9fs_lcreate(void *opaque)
1581 int32_t dfid, flags, mode;
1582 gid_t gid;
1583 ssize_t err = 0;
1584 ssize_t offset = 7;
1585 V9fsString fullname;
1586 V9fsString name;
1587 V9fsFidState *fidp;
1588 struct stat stbuf;
1589 V9fsQID qid;
1590 int32_t iounit;
1591 V9fsPDU *pdu = opaque;
1593 v9fs_string_init(&fullname);
1594 pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
1595 &mode, &gid);
1597 fidp = get_fid(pdu->s, dfid);
1598 if (fidp == NULL) {
1599 err = -ENOENT;
1600 goto out_nofid;
1602 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
1604 /* Ignore direct disk access hint until the server supports it. */
1605 flags &= ~O_DIRECT;
1607 err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
1608 if (err < 0) {
1609 goto out;
1611 fidp->fid_type = P9_FID_FILE;
1612 fidp->open_flags = flags;
1613 if (flags & O_EXCL) {
1615 * We let the host file system do O_EXCL check
1616 * We should not reclaim such fd
1618 fidp->flags |= FID_NON_RECLAIMABLE;
1620 iounit = get_iounit(pdu->s, &fullname);
1622 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
1623 if (err < 0) {
1624 fidp->fid_type = P9_FID_NONE;
1625 if (fidp->fs.fd > 0) {
1626 v9fs_co_close(pdu->s, fidp->fs.fd);
1628 goto out;
1630 v9fs_string_copy(&fidp->path, &fullname);
1631 stat_to_qid(&stbuf, &qid);
1632 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1633 err = offset;
1634 out:
1635 put_fid(pdu->s, fidp);
1636 out_nofid:
1637 complete_pdu(pdu->s, pdu, err);
1638 v9fs_string_free(&name);
1639 v9fs_string_free(&fullname);
1642 static void v9fs_fsync(void *opaque)
1644 int err;
1645 int32_t fid;
1646 int datasync;
1647 size_t offset = 7;
1648 V9fsFidState *fidp;
1649 V9fsPDU *pdu = opaque;
1650 V9fsState *s = pdu->s;
1652 pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1653 fidp = get_fid(s, fid);
1654 if (fidp == NULL) {
1655 err = -ENOENT;
1656 goto out_nofid;
1658 err = v9fs_co_fsync(s, fidp, datasync);
1659 if (!err) {
1660 err = offset;
1662 put_fid(s, fidp);
1663 out_nofid:
1664 complete_pdu(s, pdu, err);
1667 static void v9fs_clunk(void *opaque)
1669 int err;
1670 int32_t fid;
1671 size_t offset = 7;
1672 V9fsFidState *fidp;
1673 V9fsPDU *pdu = opaque;
1674 V9fsState *s = pdu->s;
1676 pdu_unmarshal(pdu, offset, "d", &fid);
1678 fidp = get_fid(s, fid);
1679 if (fidp == NULL) {
1680 err = -ENOENT;
1681 goto out_nofid;
1683 err = clunk_fid(s, fidp->fid);
1684 if (err < 0) {
1685 goto out;
1687 err = offset;
1688 out:
1689 put_fid(s, fidp);
1690 out_nofid:
1691 complete_pdu(s, pdu, err);
1694 static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
1695 V9fsFidState *fidp, int64_t off, int32_t max_count)
1697 size_t offset = 7;
1698 int read_count;
1699 int64_t xattr_len;
1701 xattr_len = fidp->fs.xattr.len;
1702 read_count = xattr_len - off;
1703 if (read_count > max_count) {
1704 read_count = max_count;
1705 } else if (read_count < 0) {
1707 * read beyond XATTR value
1709 read_count = 0;
1711 offset += pdu_marshal(pdu, offset, "d", read_count);
1712 offset += pdu_pack(pdu, offset,
1713 ((char *)fidp->fs.xattr.value) + off,
1714 read_count);
1715 return offset;
1718 static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
1719 V9fsFidState *fidp, int32_t max_count)
1721 V9fsString name;
1722 V9fsStat v9stat;
1723 int len, err = 0;
1724 int32_t count = 0;
1725 struct stat stbuf;
1726 off_t saved_dir_pos;
1727 struct dirent *dent, *result;
1729 /* save the directory position */
1730 saved_dir_pos = v9fs_co_telldir(s, fidp);
1731 if (saved_dir_pos < 0) {
1732 return saved_dir_pos;
1735 dent = g_malloc(sizeof(struct dirent));
1737 while (1) {
1738 v9fs_string_init(&name);
1739 err = v9fs_co_readdir_r(s, fidp, dent, &result);
1740 if (err || !result) {
1741 break;
1743 v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
1744 err = v9fs_co_lstat(s, &name, &stbuf);
1745 if (err < 0) {
1746 goto out;
1748 err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
1749 if (err < 0) {
1750 goto out;
1752 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1753 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1754 if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1755 /* Ran out of buffer. Set dir back to old position and return */
1756 v9fs_co_seekdir(s, fidp, saved_dir_pos);
1757 v9fs_stat_free(&v9stat);
1758 v9fs_string_free(&name);
1759 g_free(dent);
1760 return count;
1762 count += len;
1763 v9fs_stat_free(&v9stat);
1764 v9fs_string_free(&name);
1765 saved_dir_pos = dent->d_off;
1767 out:
1768 g_free(dent);
1769 v9fs_string_free(&name);
1770 if (err < 0) {
1771 return err;
1773 return count;
1776 static void v9fs_read(void *opaque)
1778 int32_t fid;
1779 int64_t off;
1780 ssize_t err = 0;
1781 int32_t count = 0;
1782 size_t offset = 7;
1783 int32_t max_count;
1784 V9fsFidState *fidp;
1785 V9fsPDU *pdu = opaque;
1786 V9fsState *s = pdu->s;
1788 pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1790 fidp = get_fid(s, fid);
1791 if (fidp == NULL) {
1792 err = -EINVAL;
1793 goto out_nofid;
1795 if (fidp->fid_type == P9_FID_DIR) {
1797 if (off == 0) {
1798 v9fs_co_rewinddir(s, fidp);
1800 count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
1801 if (count < 0) {
1802 err = count;
1803 goto out;
1805 err = offset;
1806 err += pdu_marshal(pdu, offset, "d", count);
1807 err += count;
1808 } else if (fidp->fid_type == P9_FID_FILE) {
1809 int32_t cnt;
1810 int32_t len;
1811 struct iovec *sg;
1812 struct iovec iov[128]; /* FIXME: bad, bad, bad */
1814 sg = iov;
1815 pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
1816 sg = cap_sg(sg, max_count, &cnt);
1817 do {
1818 if (0) {
1819 print_sg(sg, cnt);
1821 /* Loop in case of EINTR */
1822 do {
1823 len = v9fs_co_preadv(s, fidp, sg, cnt, off);
1824 if (len >= 0) {
1825 off += len;
1826 count += len;
1828 } while (len == -EINTR);
1829 if (len < 0) {
1830 /* IO error return the error */
1831 err = len;
1832 goto out;
1834 sg = adjust_sg(sg, len, &cnt);
1835 } while (count < max_count && len > 0);
1836 err = offset;
1837 err += pdu_marshal(pdu, offset, "d", count);
1838 err += count;
1839 } else if (fidp->fid_type == P9_FID_XATTR) {
1840 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1841 } else {
1842 err = -EINVAL;
1844 out:
1845 put_fid(s, fidp);
1846 out_nofid:
1847 complete_pdu(s, pdu, err);
1850 static size_t v9fs_readdir_data_size(V9fsString *name)
1853 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1854 * size of type (1) + size of name.size (2) + strlen(name.data)
1856 return 24 + v9fs_string_size(name);
1859 static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
1860 V9fsFidState *fidp, int32_t max_count)
1862 size_t size;
1863 V9fsQID qid;
1864 V9fsString name;
1865 int len, err = 0;
1866 int32_t count = 0;
1867 off_t saved_dir_pos;
1868 struct dirent *dent, *result;
1870 /* save the directory position */
1871 saved_dir_pos = v9fs_co_telldir(s, fidp);
1872 if (saved_dir_pos < 0) {
1873 return saved_dir_pos;
1876 dent = g_malloc(sizeof(struct dirent));
1878 while (1) {
1879 err = v9fs_co_readdir_r(s, fidp, dent, &result);
1880 if (err || !result) {
1881 break;
1883 v9fs_string_init(&name);
1884 v9fs_string_sprintf(&name, "%s", dent->d_name);
1885 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1886 /* Ran out of buffer. Set dir back to old position and return */
1887 v9fs_co_seekdir(s, fidp, saved_dir_pos);
1888 v9fs_string_free(&name);
1889 g_free(dent);
1890 return count;
1893 * Fill up just the path field of qid because the client uses
1894 * only that. To fill the entire qid structure we will have
1895 * to stat each dirent found, which is expensive
1897 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1898 memcpy(&qid.path, &dent->d_ino, size);
1899 /* Fill the other fields with dummy values */
1900 qid.type = 0;
1901 qid.version = 0;
1903 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1904 len = pdu_marshal(pdu, 11 + count, "Qqbs",
1905 &qid, dent->d_off,
1906 dent->d_type, &name);
1907 count += len;
1908 v9fs_string_free(&name);
1909 saved_dir_pos = dent->d_off;
1911 g_free(dent);
1912 if (err < 0) {
1913 return err;
1915 return count;
1918 static void v9fs_readdir(void *opaque)
1920 int32_t fid;
1921 V9fsFidState *fidp;
1922 ssize_t retval = 0;
1923 size_t offset = 7;
1924 int64_t initial_offset;
1925 int32_t count, max_count;
1926 V9fsPDU *pdu = opaque;
1927 V9fsState *s = pdu->s;
1929 pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
1931 fidp = get_fid(s, fid);
1932 if (fidp == NULL) {
1933 retval = -EINVAL;
1934 goto out_nofid;
1936 if (!fidp->fs.dir) {
1937 retval = -EINVAL;
1938 goto out;
1940 if (initial_offset == 0) {
1941 v9fs_co_rewinddir(s, fidp);
1942 } else {
1943 v9fs_co_seekdir(s, fidp, initial_offset);
1945 count = v9fs_do_readdir(s, pdu, fidp, max_count);
1946 if (count < 0) {
1947 retval = count;
1948 goto out;
1950 retval = offset;
1951 retval += pdu_marshal(pdu, offset, "d", count);
1952 retval += count;
1953 out:
1954 put_fid(s, fidp);
1955 out_nofid:
1956 complete_pdu(s, pdu, retval);
1959 static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1960 int64_t off, int32_t count,
1961 struct iovec *sg, int cnt)
1963 int i, to_copy;
1964 ssize_t err = 0;
1965 int write_count;
1966 int64_t xattr_len;
1967 size_t offset = 7;
1970 xattr_len = fidp->fs.xattr.len;
1971 write_count = xattr_len - off;
1972 if (write_count > count) {
1973 write_count = count;
1974 } else if (write_count < 0) {
1976 * write beyond XATTR value len specified in
1977 * xattrcreate
1979 err = -ENOSPC;
1980 goto out;
1982 offset += pdu_marshal(pdu, offset, "d", write_count);
1983 err = offset;
1984 fidp->fs.xattr.copied_len += write_count;
1986 * Now copy the content from sg list
1988 for (i = 0; i < cnt; i++) {
1989 if (write_count > sg[i].iov_len) {
1990 to_copy = sg[i].iov_len;
1991 } else {
1992 to_copy = write_count;
1994 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
1995 /* updating vs->off since we are not using below */
1996 off += to_copy;
1997 write_count -= to_copy;
1999 out:
2000 return err;
2003 static void v9fs_write(void *opaque)
2005 int cnt;
2006 ssize_t err;
2007 int32_t fid;
2008 int64_t off;
2009 int32_t count;
2010 int32_t len = 0;
2011 int32_t total = 0;
2012 size_t offset = 7;
2013 V9fsFidState *fidp;
2014 struct iovec iov[128]; /* FIXME: bad, bad, bad */
2015 struct iovec *sg = iov;
2016 V9fsPDU *pdu = opaque;
2017 V9fsState *s = pdu->s;
2019 pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
2021 fidp = get_fid(s, fid);
2022 if (fidp == NULL) {
2023 err = -EINVAL;
2024 goto out_nofid;
2026 if (fidp->fid_type == P9_FID_FILE) {
2027 if (fidp->fs.fd == -1) {
2028 err = -EINVAL;
2029 goto out;
2031 } else if (fidp->fid_type == P9_FID_XATTR) {
2033 * setxattr operation
2035 err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
2036 goto out;
2037 } else {
2038 err = -EINVAL;
2039 goto out;
2041 sg = cap_sg(sg, count, &cnt);
2042 do {
2043 if (0) {
2044 print_sg(sg, cnt);
2046 /* Loop in case of EINTR */
2047 do {
2048 len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
2049 if (len >= 0) {
2050 off += len;
2051 total += len;
2053 } while (len == -EINTR);
2054 if (len < 0) {
2055 /* IO error return the error */
2056 err = len;
2057 goto out;
2059 sg = adjust_sg(sg, len, &cnt);
2060 } while (total < count && len > 0);
2061 offset += pdu_marshal(pdu, offset, "d", total);
2062 err = offset;
2063 out:
2064 put_fid(s, fidp);
2065 out_nofid:
2066 complete_pdu(s, pdu, err);
2069 static void v9fs_create(void *opaque)
2071 int32_t fid;
2072 int err = 0;
2073 size_t offset = 7;
2074 V9fsFidState *fidp;
2075 V9fsQID qid;
2076 int32_t perm;
2077 int8_t mode;
2078 struct stat stbuf;
2079 V9fsString name;
2080 V9fsString extension;
2081 V9fsString fullname;
2082 int iounit;
2083 V9fsPDU *pdu = opaque;
2085 v9fs_string_init(&fullname);
2087 pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2088 &perm, &mode, &extension);
2090 fidp = get_fid(pdu->s, fid);
2091 if (fidp == NULL) {
2092 err = -EINVAL;
2093 goto out_nofid;
2096 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2097 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2098 if (!err) {
2099 err = -EEXIST;
2100 goto out;
2101 } else if (err != -ENOENT) {
2102 goto out;
2104 if (perm & P9_STAT_MODE_DIR) {
2105 err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
2106 fidp->uid, -1);
2107 if (err < 0) {
2108 goto out;
2110 v9fs_string_copy(&fidp->path, &fullname);
2111 err = v9fs_co_opendir(pdu->s, fidp);
2112 if (err < 0) {
2113 goto out;
2115 fidp->fid_type = P9_FID_DIR;
2116 } else if (perm & P9_STAT_MODE_SYMLINK) {
2117 err = v9fs_co_symlink(pdu->s, fidp, extension.data,
2118 fullname.data, -1);
2119 if (err < 0) {
2120 goto out;
2122 } else if (perm & P9_STAT_MODE_LINK) {
2123 int32_t nfid = atoi(extension.data);
2124 V9fsFidState *nfidp = get_fid(pdu->s, nfid);
2125 if (nfidp == NULL) {
2126 err = -EINVAL;
2127 goto out;
2129 err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
2130 if (err < 0) {
2131 put_fid(pdu->s, nfidp);
2132 goto out;
2134 put_fid(pdu->s, nfidp);
2135 } else if (perm & P9_STAT_MODE_DEVICE) {
2136 char ctype;
2137 uint32_t major, minor;
2138 mode_t nmode = 0;
2140 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2141 err = -errno;
2142 goto out;
2145 switch (ctype) {
2146 case 'c':
2147 nmode = S_IFCHR;
2148 break;
2149 case 'b':
2150 nmode = S_IFBLK;
2151 break;
2152 default:
2153 err = -EIO;
2154 goto out;
2157 nmode |= perm & 0777;
2158 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2159 makedev(major, minor), nmode);
2160 if (err < 0) {
2161 goto out;
2163 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2164 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2165 0, S_IFIFO | (perm & 0777));
2166 if (err < 0) {
2167 goto out;
2169 } else if (perm & P9_STAT_MODE_SOCKET) {
2170 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2171 0, S_IFSOCK | (perm & 0777));
2172 if (err < 0) {
2173 goto out;
2175 } else {
2176 err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
2177 omode_to_uflags(mode)|O_CREAT, perm);
2178 if (err < 0) {
2179 goto out;
2181 fidp->fid_type = P9_FID_FILE;
2182 fidp->open_flags = omode_to_uflags(mode);
2183 if (fidp->open_flags & O_EXCL) {
2185 * We let the host file system do O_EXCL check
2186 * We should not reclaim such fd
2188 fidp->flags |= FID_NON_RECLAIMABLE;
2191 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2192 if (err < 0) {
2193 fidp->fid_type = P9_FID_NONE;
2194 if (fidp->fs.fd) {
2195 v9fs_co_close(pdu->s, fidp->fs.fd);
2197 goto out;
2199 iounit = get_iounit(pdu->s, &fidp->path);
2200 v9fs_string_copy(&fidp->path, &fullname);
2201 stat_to_qid(&stbuf, &qid);
2202 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2203 err = offset;
2204 out:
2205 put_fid(pdu->s, fidp);
2206 out_nofid:
2207 complete_pdu(pdu->s, pdu, err);
2208 v9fs_string_free(&name);
2209 v9fs_string_free(&extension);
2210 v9fs_string_free(&fullname);
2213 static void v9fs_symlink(void *opaque)
2215 V9fsPDU *pdu = opaque;
2216 V9fsString name;
2217 V9fsString symname;
2218 V9fsString fullname;
2219 V9fsFidState *dfidp;
2220 V9fsQID qid;
2221 struct stat stbuf;
2222 int32_t dfid;
2223 int err = 0;
2224 gid_t gid;
2225 size_t offset = 7;
2227 v9fs_string_init(&fullname);
2228 pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2230 dfidp = get_fid(pdu->s, dfid);
2231 if (dfidp == NULL) {
2232 err = -EINVAL;
2233 goto out_nofid;
2236 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2237 err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
2238 if (err < 0) {
2239 goto out;
2241 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2242 if (err < 0) {
2243 goto out;
2245 stat_to_qid(&stbuf, &qid);
2246 offset += pdu_marshal(pdu, offset, "Q", &qid);
2247 err = offset;
2248 out:
2249 put_fid(pdu->s, dfidp);
2250 out_nofid:
2251 complete_pdu(pdu->s, pdu, err);
2252 v9fs_string_free(&name);
2253 v9fs_string_free(&symname);
2254 v9fs_string_free(&fullname);
2257 static void v9fs_flush(void *opaque)
2259 V9fsPDU *pdu = opaque;
2260 V9fsState *s = pdu->s;
2261 /* A nop call with no return */
2262 complete_pdu(s, pdu, 7);
2263 return;
2266 static void v9fs_link(void *opaque)
2268 V9fsPDU *pdu = opaque;
2269 V9fsState *s = pdu->s;
2270 int32_t dfid, oldfid;
2271 V9fsFidState *dfidp, *oldfidp;
2272 V9fsString name, fullname;
2273 size_t offset = 7;
2274 int err = 0;
2276 v9fs_string_init(&fullname);
2278 pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2280 dfidp = get_fid(s, dfid);
2281 if (dfidp == NULL) {
2282 err = -ENOENT;
2283 goto out_nofid;
2286 oldfidp = get_fid(s, oldfid);
2287 if (oldfidp == NULL) {
2288 err = -ENOENT;
2289 goto out;
2292 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2293 err = v9fs_co_link(s, &oldfidp->path, &fullname);
2294 if (!err) {
2295 err = offset;
2297 v9fs_string_free(&fullname);
2299 out:
2300 put_fid(s, dfidp);
2301 out_nofid:
2302 v9fs_string_free(&name);
2303 complete_pdu(s, pdu, err);
2306 static void v9fs_remove(void *opaque)
2308 int32_t fid;
2309 int err = 0;
2310 size_t offset = 7;
2311 V9fsFidState *fidp;
2312 V9fsPDU *pdu = opaque;
2314 pdu_unmarshal(pdu, offset, "d", &fid);
2316 fidp = get_fid(pdu->s, fid);
2317 if (fidp == NULL) {
2318 err = -EINVAL;
2319 goto out_nofid;
2322 * IF the file is unlinked, we cannot reopen
2323 * the file later. So don't reclaim fd
2325 err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
2326 if (err < 0) {
2327 goto out_err;
2329 err = v9fs_co_remove(pdu->s, &fidp->path);
2330 if (!err) {
2331 err = offset;
2333 out_err:
2334 /* For TREMOVE we need to clunk the fid even on failed remove */
2335 clunk_fid(pdu->s, fidp->fid);
2336 put_fid(pdu->s, fidp);
2337 out_nofid:
2338 complete_pdu(pdu->s, pdu, err);
2341 static void v9fs_unlinkat(void *opaque)
2343 int err = 0;
2344 V9fsString name;
2345 int32_t dfid, flags;
2346 size_t offset = 7;
2347 V9fsFidState *dfidp;
2348 V9fsPDU *pdu = opaque;
2349 V9fsString full_name;
2351 pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2353 dfidp = get_fid(pdu->s, dfid);
2354 if (dfidp == NULL) {
2355 err = -EINVAL;
2356 goto out_nofid;
2358 v9fs_string_init(&full_name);
2359 v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data);
2361 * IF the file is unlinked, we cannot reopen
2362 * the file later. So don't reclaim fd
2364 err = v9fs_mark_fids_unreclaim(pdu->s, &full_name);
2365 if (err < 0) {
2366 goto out_err;
2368 err = v9fs_co_remove(pdu->s, &full_name);
2369 if (!err) {
2370 err = offset;
2372 out_err:
2373 put_fid(pdu->s, dfidp);
2374 v9fs_string_free(&full_name);
2375 out_nofid:
2376 complete_pdu(pdu->s, pdu, err);
2377 v9fs_string_free(&name);
2380 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
2381 int32_t newdirfid, V9fsString *name)
2383 char *end;
2384 int err = 0;
2385 V9fsFidState *dirfidp = NULL;
2386 char *old_name, *new_name;
2388 if (newdirfid != -1) {
2389 dirfidp = get_fid(s, newdirfid);
2390 if (dirfidp == NULL) {
2391 err = -ENOENT;
2392 goto out_nofid;
2394 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2396 new_name = g_malloc0(dirfidp->path.size + name->size + 2);
2398 strcpy(new_name, dirfidp->path.data);
2399 strcat(new_name, "/");
2400 strcat(new_name + dirfidp->path.size, name->data);
2401 } else {
2402 old_name = fidp->path.data;
2403 end = strrchr(old_name, '/');
2404 if (end) {
2405 end++;
2406 } else {
2407 end = old_name;
2409 new_name = g_malloc0(end - old_name + name->size + 1);
2411 strncat(new_name, old_name, end - old_name);
2412 strncat(new_name + (end - old_name), name->data, name->size);
2415 v9fs_string_free(name);
2416 name->data = new_name;
2417 name->size = strlen(new_name);
2419 if (strcmp(new_name, fidp->path.data) != 0) {
2420 err = v9fs_co_rename(s, &fidp->path, name);
2421 if (err < 0) {
2422 goto out;
2424 V9fsFidState *tfidp;
2426 * Fixup fid's pointing to the old name to
2427 * start pointing to the new name
2429 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2430 if (fidp == tfidp) {
2432 * we replace name of this fid towards the end
2433 * so that our below strcmp will work
2435 continue;
2437 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2438 /* replace the name */
2439 v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
2442 v9fs_string_copy(&fidp->path, name);
2444 out:
2445 if (dirfidp) {
2446 put_fid(s, dirfidp);
2448 out_nofid:
2449 return err;
2452 static void v9fs_rename(void *opaque)
2454 int32_t fid;
2455 ssize_t err = 0;
2456 size_t offset = 7;
2457 V9fsString name;
2458 int32_t newdirfid;
2459 V9fsFidState *fidp;
2460 V9fsPDU *pdu = opaque;
2461 V9fsState *s = pdu->s;
2463 pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2465 fidp = get_fid(s, fid);
2466 if (fidp == NULL) {
2467 err = -ENOENT;
2468 goto out_nofid;
2470 BUG_ON(fidp->fid_type != P9_FID_NONE);
2472 err = v9fs_complete_rename(s, fidp, newdirfid, &name);
2473 if (!err) {
2474 err = offset;
2476 put_fid(s, fidp);
2477 out_nofid:
2478 complete_pdu(s, pdu, err);
2479 v9fs_string_free(&name);
2482 static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
2483 V9fsString *old_name, int32_t newdirfid,
2484 V9fsString *new_name)
2486 int err = 0;
2487 V9fsString old_full_name, new_full_name;
2488 V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2490 olddirfidp = get_fid(s, olddirfid);
2491 if (olddirfidp == NULL) {
2492 err = -ENOENT;
2493 goto out;
2495 v9fs_string_init(&old_full_name);
2496 v9fs_string_init(&new_full_name);
2498 v9fs_string_sprintf(&old_full_name, "%s/%s",
2499 olddirfidp->path.data, old_name->data);
2500 if (newdirfid != -1) {
2501 newdirfidp = get_fid(s, newdirfid);
2502 if (newdirfidp == NULL) {
2503 err = -ENOENT;
2504 goto out;
2506 v9fs_string_sprintf(&new_full_name, "%s/%s",
2507 newdirfidp->path.data, new_name->data);
2508 } else {
2509 v9fs_string_sprintf(&new_full_name, "%s/%s",
2510 olddirfidp->path.data, new_name->data);
2513 if (strcmp(old_full_name.data, new_full_name.data) != 0) {
2514 V9fsFidState *tfidp;
2515 err = v9fs_co_rename(s, &old_full_name, &new_full_name);
2516 if (err < 0) {
2517 goto out;
2520 * Fixup fid's pointing to the old name to
2521 * start pointing to the new name
2523 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2524 if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
2525 /* replace the name */
2526 v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
2530 out:
2531 if (olddirfidp) {
2532 put_fid(s, olddirfidp);
2534 if (newdirfidp) {
2535 put_fid(s, newdirfidp);
2537 v9fs_string_free(&old_full_name);
2538 v9fs_string_free(&new_full_name);
2539 return err;
2542 static void v9fs_renameat(void *opaque)
2544 ssize_t err = 0;
2545 size_t offset = 7;
2546 V9fsPDU *pdu = opaque;
2547 V9fsState *s = pdu->s;
2548 int32_t olddirfid, newdirfid;
2549 V9fsString old_name, new_name;
2551 pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2552 &old_name, &newdirfid, &new_name);
2554 err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
2555 if (!err) {
2556 err = offset;
2558 complete_pdu(s, pdu, err);
2559 v9fs_string_free(&old_name);
2560 v9fs_string_free(&new_name);
2563 static void v9fs_wstat(void *opaque)
2565 int32_t fid;
2566 int err = 0;
2567 int16_t unused;
2568 V9fsStat v9stat;
2569 size_t offset = 7;
2570 struct stat stbuf;
2571 V9fsFidState *fidp;
2572 V9fsPDU *pdu = opaque;
2573 V9fsState *s = pdu->s;
2575 pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2577 fidp = get_fid(s, fid);
2578 if (fidp == NULL) {
2579 err = -EINVAL;
2580 goto out_nofid;
2582 /* do we need to sync the file? */
2583 if (donttouch_stat(&v9stat)) {
2584 err = v9fs_co_fsync(s, fidp, 0);
2585 goto out;
2587 if (v9stat.mode != -1) {
2588 uint32_t v9_mode;
2589 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
2590 if (err < 0) {
2591 goto out;
2593 v9_mode = stat_to_v9mode(&stbuf);
2594 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2595 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2596 /* Attempting to change the type */
2597 err = -EIO;
2598 goto out;
2600 err = v9fs_co_chmod(s, &fidp->path,
2601 v9mode_to_mode(v9stat.mode,
2602 &v9stat.extension));
2603 if (err < 0) {
2604 goto out;
2607 if (v9stat.mtime != -1 || v9stat.atime != -1) {
2608 struct timespec times[2];
2609 if (v9stat.atime != -1) {
2610 times[0].tv_sec = v9stat.atime;
2611 times[0].tv_nsec = 0;
2612 } else {
2613 times[0].tv_nsec = UTIME_OMIT;
2615 if (v9stat.mtime != -1) {
2616 times[1].tv_sec = v9stat.mtime;
2617 times[1].tv_nsec = 0;
2618 } else {
2619 times[1].tv_nsec = UTIME_OMIT;
2621 err = v9fs_co_utimensat(s, &fidp->path, times);
2622 if (err < 0) {
2623 goto out;
2626 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2627 err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2628 if (err < 0) {
2629 goto out;
2632 if (v9stat.name.size != 0) {
2633 err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
2634 if (err < 0) {
2635 goto out;
2638 if (v9stat.length != -1) {
2639 err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
2640 if (err < 0) {
2641 goto out;
2644 err = offset;
2645 out:
2646 put_fid(s, fidp);
2647 out_nofid:
2648 v9fs_stat_free(&v9stat);
2649 complete_pdu(s, pdu, err);
2652 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2654 uint32_t f_type;
2655 uint32_t f_bsize;
2656 uint64_t f_blocks;
2657 uint64_t f_bfree;
2658 uint64_t f_bavail;
2659 uint64_t f_files;
2660 uint64_t f_ffree;
2661 uint64_t fsid_val;
2662 uint32_t f_namelen;
2663 size_t offset = 7;
2664 int32_t bsize_factor;
2667 * compute bsize factor based on host file system block size
2668 * and client msize
2670 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2671 if (!bsize_factor) {
2672 bsize_factor = 1;
2674 f_type = stbuf->f_type;
2675 f_bsize = stbuf->f_bsize;
2676 f_bsize *= bsize_factor;
2678 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2679 * adjust(divide) the number of blocks, free blocks and available
2680 * blocks by bsize factor
2682 f_blocks = stbuf->f_blocks/bsize_factor;
2683 f_bfree = stbuf->f_bfree/bsize_factor;
2684 f_bavail = stbuf->f_bavail/bsize_factor;
2685 f_files = stbuf->f_files;
2686 f_ffree = stbuf->f_ffree;
2687 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2688 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2689 f_namelen = stbuf->f_namelen;
2691 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2692 f_type, f_bsize, f_blocks, f_bfree,
2693 f_bavail, f_files, f_ffree,
2694 fsid_val, f_namelen);
2697 static void v9fs_statfs(void *opaque)
2699 int32_t fid;
2700 ssize_t retval = 0;
2701 size_t offset = 7;
2702 V9fsFidState *fidp;
2703 struct statfs stbuf;
2704 V9fsPDU *pdu = opaque;
2705 V9fsState *s = pdu->s;
2707 pdu_unmarshal(pdu, offset, "d", &fid);
2708 fidp = get_fid(s, fid);
2709 if (fidp == NULL) {
2710 retval = -ENOENT;
2711 goto out_nofid;
2713 retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2714 if (retval < 0) {
2715 goto out;
2717 retval = offset;
2718 retval += v9fs_fill_statfs(s, pdu, &stbuf);
2719 out:
2720 put_fid(s, fidp);
2721 out_nofid:
2722 complete_pdu(s, pdu, retval);
2723 return;
2726 static void v9fs_mknod(void *opaque)
2729 int mode;
2730 gid_t gid;
2731 int32_t fid;
2732 V9fsQID qid;
2733 int err = 0;
2734 int major, minor;
2735 size_t offset = 7;
2736 V9fsString name;
2737 struct stat stbuf;
2738 V9fsString fullname;
2739 V9fsFidState *fidp;
2740 V9fsPDU *pdu = opaque;
2741 V9fsState *s = pdu->s;
2743 v9fs_string_init(&fullname);
2744 pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2745 &major, &minor, &gid);
2747 fidp = get_fid(s, fid);
2748 if (fidp == NULL) {
2749 err = -ENOENT;
2750 goto out_nofid;
2752 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2753 err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
2754 makedev(major, minor), mode);
2755 if (err < 0) {
2756 goto out;
2758 err = v9fs_co_lstat(s, &fullname, &stbuf);
2759 if (err < 0) {
2760 goto out;
2762 stat_to_qid(&stbuf, &qid);
2763 err = offset;
2764 err += pdu_marshal(pdu, offset, "Q", &qid);
2765 out:
2766 put_fid(s, fidp);
2767 out_nofid:
2768 complete_pdu(s, pdu, err);
2769 v9fs_string_free(&fullname);
2770 v9fs_string_free(&name);
2774 * Implement posix byte range locking code
2775 * Server side handling of locking code is very simple, because 9p server in
2776 * QEMU can handle only one client. And most of the lock handling
2777 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2778 * do any thing in * qemu 9p server side lock code path.
2779 * So when a TLOCK request comes, always return success
2781 static void v9fs_lock(void *opaque)
2783 int8_t status;
2784 V9fsFlock *flock;
2785 size_t offset = 7;
2786 struct stat stbuf;
2787 V9fsFidState *fidp;
2788 int32_t fid, err = 0;
2789 V9fsPDU *pdu = opaque;
2790 V9fsState *s = pdu->s;
2792 flock = g_malloc(sizeof(*flock));
2793 pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
2794 &flock->flags, &flock->start, &flock->length,
2795 &flock->proc_id, &flock->client_id);
2796 status = P9_LOCK_ERROR;
2798 /* We support only block flag now (that too ignored currently) */
2799 if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
2800 err = -EINVAL;
2801 goto out_nofid;
2803 fidp = get_fid(s, fid);
2804 if (fidp == NULL) {
2805 err = -ENOENT;
2806 goto out_nofid;
2808 err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2809 if (err < 0) {
2810 goto out;
2812 status = P9_LOCK_SUCCESS;
2813 out:
2814 put_fid(s, fidp);
2815 out_nofid:
2816 err = offset;
2817 err += pdu_marshal(pdu, offset, "b", status);
2818 complete_pdu(s, pdu, err);
2819 v9fs_string_free(&flock->client_id);
2820 g_free(flock);
2824 * When a TGETLOCK request comes, always return success because all lock
2825 * handling is done by client's VFS layer.
2827 static void v9fs_getlock(void *opaque)
2829 size_t offset = 7;
2830 struct stat stbuf;
2831 V9fsFidState *fidp;
2832 V9fsGetlock *glock;
2833 int32_t fid, err = 0;
2834 V9fsPDU *pdu = opaque;
2835 V9fsState *s = pdu->s;
2837 glock = g_malloc(sizeof(*glock));
2838 pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
2839 &glock->start, &glock->length, &glock->proc_id,
2840 &glock->client_id);
2842 fidp = get_fid(s, fid);
2843 if (fidp == NULL) {
2844 err = -ENOENT;
2845 goto out_nofid;
2847 err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2848 if (err < 0) {
2849 goto out;
2851 glock->type = F_UNLCK;
2852 offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
2853 glock->start, glock->length, glock->proc_id,
2854 &glock->client_id);
2855 err = offset;
2856 out:
2857 put_fid(s, fidp);
2858 out_nofid:
2859 complete_pdu(s, pdu, err);
2860 v9fs_string_free(&glock->client_id);
2861 g_free(glock);
2864 static void v9fs_mkdir(void *opaque)
2866 V9fsPDU *pdu = opaque;
2867 size_t offset = 7;
2868 int32_t fid;
2869 struct stat stbuf;
2870 V9fsString name, fullname;
2871 V9fsQID qid;
2872 V9fsFidState *fidp;
2873 gid_t gid;
2874 int mode;
2875 int err = 0;
2877 v9fs_string_init(&fullname);
2878 pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2880 fidp = get_fid(pdu->s, fid);
2881 if (fidp == NULL) {
2882 err = -ENOENT;
2883 goto out_nofid;
2885 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2886 err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
2887 if (err < 0) {
2888 goto out;
2890 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2891 if (err < 0) {
2892 goto out;
2894 stat_to_qid(&stbuf, &qid);
2895 offset += pdu_marshal(pdu, offset, "Q", &qid);
2896 err = offset;
2897 out:
2898 put_fid(pdu->s, fidp);
2899 out_nofid:
2900 complete_pdu(pdu->s, pdu, err);
2901 v9fs_string_free(&fullname);
2902 v9fs_string_free(&name);
2905 static void v9fs_xattrwalk(void *opaque)
2907 int64_t size;
2908 V9fsString name;
2909 ssize_t err = 0;
2910 size_t offset = 7;
2911 int32_t fid, newfid;
2912 V9fsFidState *file_fidp;
2913 V9fsFidState *xattr_fidp = NULL;
2914 V9fsPDU *pdu = opaque;
2915 V9fsState *s = pdu->s;
2917 pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
2918 file_fidp = get_fid(s, fid);
2919 if (file_fidp == NULL) {
2920 err = -ENOENT;
2921 goto out_nofid;
2923 xattr_fidp = alloc_fid(s, newfid);
2924 if (xattr_fidp == NULL) {
2925 err = -EINVAL;
2926 goto out;
2928 v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
2929 if (name.data[0] == 0) {
2931 * listxattr request. Get the size first
2933 size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
2934 if (size < 0) {
2935 err = size;
2936 clunk_fid(s, xattr_fidp->fid);
2937 goto out;
2940 * Read the xattr value
2942 xattr_fidp->fs.xattr.len = size;
2943 xattr_fidp->fid_type = P9_FID_XATTR;
2944 xattr_fidp->fs.xattr.copied_len = -1;
2945 if (size) {
2946 xattr_fidp->fs.xattr.value = g_malloc(size);
2947 err = v9fs_co_llistxattr(s, &xattr_fidp->path,
2948 xattr_fidp->fs.xattr.value,
2949 xattr_fidp->fs.xattr.len);
2950 if (err < 0) {
2951 clunk_fid(s, xattr_fidp->fid);
2952 goto out;
2955 offset += pdu_marshal(pdu, offset, "q", size);
2956 err = offset;
2957 } else {
2959 * specific xattr fid. We check for xattr
2960 * presence also collect the xattr size
2962 size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2963 &name, NULL, 0);
2964 if (size < 0) {
2965 err = size;
2966 clunk_fid(s, xattr_fidp->fid);
2967 goto out;
2970 * Read the xattr value
2972 xattr_fidp->fs.xattr.len = size;
2973 xattr_fidp->fid_type = P9_FID_XATTR;
2974 xattr_fidp->fs.xattr.copied_len = -1;
2975 if (size) {
2976 xattr_fidp->fs.xattr.value = g_malloc(size);
2977 err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2978 &name, xattr_fidp->fs.xattr.value,
2979 xattr_fidp->fs.xattr.len);
2980 if (err < 0) {
2981 clunk_fid(s, xattr_fidp->fid);
2982 goto out;
2985 offset += pdu_marshal(pdu, offset, "q", size);
2986 err = offset;
2988 out:
2989 put_fid(s, file_fidp);
2990 if (xattr_fidp) {
2991 put_fid(s, xattr_fidp);
2993 out_nofid:
2994 complete_pdu(s, pdu, err);
2995 v9fs_string_free(&name);
2998 static void v9fs_xattrcreate(void *opaque)
3000 int flags;
3001 int32_t fid;
3002 int64_t size;
3003 ssize_t err = 0;
3004 V9fsString name;
3005 size_t offset = 7;
3006 V9fsFidState *file_fidp;
3007 V9fsFidState *xattr_fidp;
3008 V9fsPDU *pdu = opaque;
3009 V9fsState *s = pdu->s;
3011 pdu_unmarshal(pdu, offset, "dsqd",
3012 &fid, &name, &size, &flags);
3014 file_fidp = get_fid(s, fid);
3015 if (file_fidp == NULL) {
3016 err = -EINVAL;
3017 goto out_nofid;
3019 /* Make the file fid point to xattr */
3020 xattr_fidp = file_fidp;
3021 xattr_fidp->fid_type = P9_FID_XATTR;
3022 xattr_fidp->fs.xattr.copied_len = 0;
3023 xattr_fidp->fs.xattr.len = size;
3024 xattr_fidp->fs.xattr.flags = flags;
3025 v9fs_string_init(&xattr_fidp->fs.xattr.name);
3026 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3027 if (size) {
3028 xattr_fidp->fs.xattr.value = g_malloc(size);
3029 } else {
3030 xattr_fidp->fs.xattr.value = NULL;
3032 err = offset;
3033 put_fid(s, file_fidp);
3034 out_nofid:
3035 complete_pdu(s, pdu, err);
3036 v9fs_string_free(&name);
3039 static void v9fs_readlink(void *opaque)
3041 V9fsPDU *pdu = opaque;
3042 size_t offset = 7;
3043 V9fsString target;
3044 int32_t fid;
3045 int err = 0;
3046 V9fsFidState *fidp;
3048 pdu_unmarshal(pdu, offset, "d", &fid);
3049 fidp = get_fid(pdu->s, fid);
3050 if (fidp == NULL) {
3051 err = -ENOENT;
3052 goto out_nofid;
3055 v9fs_string_init(&target);
3056 err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
3057 if (err < 0) {
3058 goto out;
3060 offset += pdu_marshal(pdu, offset, "s", &target);
3061 err = offset;
3062 v9fs_string_free(&target);
3063 out:
3064 put_fid(pdu->s, fidp);
3065 out_nofid:
3066 complete_pdu(pdu->s, pdu, err);
3069 static CoroutineEntry *pdu_co_handlers[] = {
3070 [P9_TREADDIR] = v9fs_readdir,
3071 [P9_TSTATFS] = v9fs_statfs,
3072 [P9_TGETATTR] = v9fs_getattr,
3073 [P9_TSETATTR] = v9fs_setattr,
3074 [P9_TXATTRWALK] = v9fs_xattrwalk,
3075 [P9_TXATTRCREATE] = v9fs_xattrcreate,
3076 [P9_TMKNOD] = v9fs_mknod,
3077 [P9_TRENAME] = v9fs_rename,
3078 [P9_TLOCK] = v9fs_lock,
3079 [P9_TGETLOCK] = v9fs_getlock,
3080 [P9_TRENAMEAT] = v9fs_renameat,
3081 [P9_TREADLINK] = v9fs_readlink,
3082 [P9_TUNLINKAT] = v9fs_unlinkat,
3083 [P9_TMKDIR] = v9fs_mkdir,
3084 [P9_TVERSION] = v9fs_version,
3085 [P9_TLOPEN] = v9fs_open,
3086 [P9_TATTACH] = v9fs_attach,
3087 [P9_TSTAT] = v9fs_stat,
3088 [P9_TWALK] = v9fs_walk,
3089 [P9_TCLUNK] = v9fs_clunk,
3090 [P9_TFSYNC] = v9fs_fsync,
3091 [P9_TOPEN] = v9fs_open,
3092 [P9_TREAD] = v9fs_read,
3093 #if 0
3094 [P9_TAUTH] = v9fs_auth,
3095 #endif
3096 [P9_TFLUSH] = v9fs_flush,
3097 [P9_TLINK] = v9fs_link,
3098 [P9_TSYMLINK] = v9fs_symlink,
3099 [P9_TCREATE] = v9fs_create,
3100 [P9_TLCREATE] = v9fs_lcreate,
3101 [P9_TWRITE] = v9fs_write,
3102 [P9_TWSTAT] = v9fs_wstat,
3103 [P9_TREMOVE] = v9fs_remove,
3106 static void v9fs_op_not_supp(void *opaque)
3108 V9fsPDU *pdu = opaque;
3109 complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3112 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3114 Coroutine *co;
3115 CoroutineEntry *handler;
3117 if (debug_9p_pdu) {
3118 pprint_pdu(pdu);
3120 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3121 (pdu_co_handlers[pdu->id] == NULL)) {
3122 handler = v9fs_op_not_supp;
3123 } else {
3124 handler = pdu_co_handlers[pdu->id];
3126 co = qemu_coroutine_create(handler);
3127 qemu_coroutine_enter(co, pdu);
3130 void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3132 V9fsState *s = (V9fsState *)vdev;
3133 V9fsPDU *pdu;
3134 ssize_t len;
3136 while ((pdu = alloc_pdu(s)) &&
3137 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3138 uint8_t *ptr;
3139 pdu->s = s;
3140 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3141 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3143 ptr = pdu->elem.out_sg[0].iov_base;
3145 memcpy(&pdu->size, ptr, 4);
3146 pdu->id = ptr[4];
3147 memcpy(&pdu->tag, ptr + 5, 2);
3148 submit_pdu(s, pdu);
3150 free_pdu(s, pdu);
3153 void virtio_9p_set_fd_limit(void)
3155 struct rlimit rlim;
3156 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3157 fprintf(stderr, "Failed to get the resource limit\n");
3158 exit(1);
3160 open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3161 open_fd_rc = rlim.rlim_cur/2;