configure: Avoid duplicate flags when calling compile_prog
[qemu.git] / hw / 9pfs / virtio-9p.c
blob94b7090e7d082e9452018ac894751f99963f86c1
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 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
547 memcpy(&qidp->path, &stbuf->st_ino, size);
548 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
549 qidp->type = 0;
550 if (S_ISDIR(stbuf->st_mode)) {
551 qidp->type |= P9_QID_TYPE_DIR;
553 if (S_ISLNK(stbuf->st_mode)) {
554 qidp->type |= P9_QID_TYPE_SYMLINK;
558 static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
560 struct stat stbuf;
561 int err;
563 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
564 if (err < 0) {
565 return err;
567 stat_to_qid(&stbuf, qidp);
568 return 0;
571 static V9fsPDU *alloc_pdu(V9fsState *s)
573 V9fsPDU *pdu = NULL;
575 if (!QLIST_EMPTY(&s->free_list)) {
576 pdu = QLIST_FIRST(&s->free_list);
577 QLIST_REMOVE(pdu, next);
579 return pdu;
582 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
584 if (pdu) {
585 if (debug_9p_pdu) {
586 pprint_pdu(pdu);
588 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
592 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
593 size_t offset, size_t size, int pack)
595 int i = 0;
596 size_t copied = 0;
598 for (i = 0; size && i < sg_count; i++) {
599 size_t len;
600 if (offset >= sg[i].iov_len) {
601 /* skip this sg */
602 offset -= sg[i].iov_len;
603 continue;
604 } else {
605 len = MIN(sg[i].iov_len - offset, size);
606 if (pack) {
607 memcpy(sg[i].iov_base + offset, addr, len);
608 } else {
609 memcpy(addr, sg[i].iov_base + offset, len);
611 size -= len;
612 copied += len;
613 addr += len;
614 if (size) {
615 offset = 0;
616 continue;
621 return copied;
624 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
626 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
627 offset, size, 0);
630 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
631 size_t size)
633 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
634 offset, size, 1);
637 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
639 size_t pos = 0;
640 int i, j;
641 struct iovec *src_sg;
642 unsigned int num;
644 if (rx) {
645 src_sg = pdu->elem.in_sg;
646 num = pdu->elem.in_num;
647 } else {
648 src_sg = pdu->elem.out_sg;
649 num = pdu->elem.out_num;
652 j = 0;
653 for (i = 0; i < num; i++) {
654 if (offset <= pos) {
655 sg[j].iov_base = src_sg[i].iov_base;
656 sg[j].iov_len = src_sg[i].iov_len;
657 j++;
658 } else if (offset < (src_sg[i].iov_len + pos)) {
659 sg[j].iov_base = src_sg[i].iov_base;
660 sg[j].iov_len = src_sg[i].iov_len;
661 sg[j].iov_base += (offset - pos);
662 sg[j].iov_len -= (offset - pos);
663 j++;
665 pos += src_sg[i].iov_len;
668 return j;
671 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
673 size_t old_offset = offset;
674 va_list ap;
675 int i;
677 va_start(ap, fmt);
678 for (i = 0; fmt[i]; i++) {
679 switch (fmt[i]) {
680 case 'b': {
681 uint8_t *valp = va_arg(ap, uint8_t *);
682 offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
683 break;
685 case 'w': {
686 uint16_t val, *valp;
687 valp = va_arg(ap, uint16_t *);
688 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
689 *valp = le16_to_cpu(val);
690 break;
692 case 'd': {
693 uint32_t val, *valp;
694 valp = va_arg(ap, uint32_t *);
695 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
696 *valp = le32_to_cpu(val);
697 break;
699 case 'q': {
700 uint64_t val, *valp;
701 valp = va_arg(ap, uint64_t *);
702 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
703 *valp = le64_to_cpu(val);
704 break;
706 case 'v': {
707 struct iovec *iov = va_arg(ap, struct iovec *);
708 int *iovcnt = va_arg(ap, int *);
709 *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
710 break;
712 case 's': {
713 V9fsString *str = va_arg(ap, V9fsString *);
714 offset += pdu_unmarshal(pdu, offset, "w", &str->size);
715 /* FIXME: sanity check str->size */
716 str->data = g_malloc(str->size + 1);
717 offset += pdu_unpack(str->data, pdu, offset, str->size);
718 str->data[str->size] = 0;
719 break;
721 case 'Q': {
722 V9fsQID *qidp = va_arg(ap, V9fsQID *);
723 offset += pdu_unmarshal(pdu, offset, "bdq",
724 &qidp->type, &qidp->version, &qidp->path);
725 break;
727 case 'S': {
728 V9fsStat *statp = va_arg(ap, V9fsStat *);
729 offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
730 &statp->size, &statp->type, &statp->dev,
731 &statp->qid, &statp->mode, &statp->atime,
732 &statp->mtime, &statp->length,
733 &statp->name, &statp->uid, &statp->gid,
734 &statp->muid, &statp->extension,
735 &statp->n_uid, &statp->n_gid,
736 &statp->n_muid);
737 break;
739 case 'I': {
740 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
741 offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
742 &iattr->valid, &iattr->mode,
743 &iattr->uid, &iattr->gid, &iattr->size,
744 &iattr->atime_sec, &iattr->atime_nsec,
745 &iattr->mtime_sec, &iattr->mtime_nsec);
746 break;
748 default:
749 break;
753 va_end(ap);
755 return offset - old_offset;
758 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
760 size_t old_offset = offset;
761 va_list ap;
762 int i;
764 va_start(ap, fmt);
765 for (i = 0; fmt[i]; i++) {
766 switch (fmt[i]) {
767 case 'b': {
768 uint8_t val = va_arg(ap, int);
769 offset += pdu_pack(pdu, offset, &val, sizeof(val));
770 break;
772 case 'w': {
773 uint16_t val;
774 cpu_to_le16w(&val, va_arg(ap, int));
775 offset += pdu_pack(pdu, offset, &val, sizeof(val));
776 break;
778 case 'd': {
779 uint32_t val;
780 cpu_to_le32w(&val, va_arg(ap, uint32_t));
781 offset += pdu_pack(pdu, offset, &val, sizeof(val));
782 break;
784 case 'q': {
785 uint64_t val;
786 cpu_to_le64w(&val, va_arg(ap, uint64_t));
787 offset += pdu_pack(pdu, offset, &val, sizeof(val));
788 break;
790 case 'v': {
791 struct iovec *iov = va_arg(ap, struct iovec *);
792 int *iovcnt = va_arg(ap, int *);
793 *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
794 break;
796 case 's': {
797 V9fsString *str = va_arg(ap, V9fsString *);
798 offset += pdu_marshal(pdu, offset, "w", str->size);
799 offset += pdu_pack(pdu, offset, str->data, str->size);
800 break;
802 case 'Q': {
803 V9fsQID *qidp = va_arg(ap, V9fsQID *);
804 offset += pdu_marshal(pdu, offset, "bdq",
805 qidp->type, qidp->version, qidp->path);
806 break;
808 case 'S': {
809 V9fsStat *statp = va_arg(ap, V9fsStat *);
810 offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
811 statp->size, statp->type, statp->dev,
812 &statp->qid, statp->mode, statp->atime,
813 statp->mtime, statp->length, &statp->name,
814 &statp->uid, &statp->gid, &statp->muid,
815 &statp->extension, statp->n_uid,
816 statp->n_gid, statp->n_muid);
817 break;
819 case 'A': {
820 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
821 offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
822 statp->st_result_mask,
823 &statp->qid, statp->st_mode,
824 statp->st_uid, statp->st_gid,
825 statp->st_nlink, statp->st_rdev,
826 statp->st_size, statp->st_blksize, statp->st_blocks,
827 statp->st_atime_sec, statp->st_atime_nsec,
828 statp->st_mtime_sec, statp->st_mtime_nsec,
829 statp->st_ctime_sec, statp->st_ctime_nsec,
830 statp->st_btime_sec, statp->st_btime_nsec,
831 statp->st_gen, statp->st_data_version);
832 break;
834 default:
835 break;
838 va_end(ap);
840 return offset - old_offset;
843 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
845 int8_t id = pdu->id + 1; /* Response */
847 if (len < 0) {
848 int err = -len;
849 len = 7;
851 if (s->proto_version != V9FS_PROTO_2000L) {
852 V9fsString str;
854 str.data = strerror(err);
855 str.size = strlen(str.data);
857 len += pdu_marshal(pdu, len, "s", &str);
858 id = P9_RERROR;
861 len += pdu_marshal(pdu, len, "d", err);
863 if (s->proto_version == V9FS_PROTO_2000L) {
864 id = P9_RLERROR;
868 /* fill out the header */
869 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
871 /* keep these in sync */
872 pdu->size = len;
873 pdu->id = id;
875 /* push onto queue and notify */
876 virtqueue_push(s->vq, &pdu->elem, len);
878 /* FIXME: we should batch these completions */
879 virtio_notify(&s->vdev, s->vq);
881 free_pdu(s, pdu);
884 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
886 mode_t ret;
888 ret = mode & 0777;
889 if (mode & P9_STAT_MODE_DIR) {
890 ret |= S_IFDIR;
893 if (mode & P9_STAT_MODE_SYMLINK) {
894 ret |= S_IFLNK;
896 if (mode & P9_STAT_MODE_SOCKET) {
897 ret |= S_IFSOCK;
899 if (mode & P9_STAT_MODE_NAMED_PIPE) {
900 ret |= S_IFIFO;
902 if (mode & P9_STAT_MODE_DEVICE) {
903 if (extension && extension->data[0] == 'c') {
904 ret |= S_IFCHR;
905 } else {
906 ret |= S_IFBLK;
910 if (!(ret&~0777)) {
911 ret |= S_IFREG;
914 if (mode & P9_STAT_MODE_SETUID) {
915 ret |= S_ISUID;
917 if (mode & P9_STAT_MODE_SETGID) {
918 ret |= S_ISGID;
920 if (mode & P9_STAT_MODE_SETVTX) {
921 ret |= S_ISVTX;
924 return ret;
927 static int donttouch_stat(V9fsStat *stat)
929 if (stat->type == -1 &&
930 stat->dev == -1 &&
931 stat->qid.type == -1 &&
932 stat->qid.version == -1 &&
933 stat->qid.path == -1 &&
934 stat->mode == -1 &&
935 stat->atime == -1 &&
936 stat->mtime == -1 &&
937 stat->length == -1 &&
938 !stat->name.size &&
939 !stat->uid.size &&
940 !stat->gid.size &&
941 !stat->muid.size &&
942 stat->n_uid == -1 &&
943 stat->n_gid == -1 &&
944 stat->n_muid == -1) {
945 return 1;
948 return 0;
951 static void v9fs_stat_free(V9fsStat *stat)
953 v9fs_string_free(&stat->name);
954 v9fs_string_free(&stat->uid);
955 v9fs_string_free(&stat->gid);
956 v9fs_string_free(&stat->muid);
957 v9fs_string_free(&stat->extension);
960 static uint32_t stat_to_v9mode(const struct stat *stbuf)
962 uint32_t mode;
964 mode = stbuf->st_mode & 0777;
965 if (S_ISDIR(stbuf->st_mode)) {
966 mode |= P9_STAT_MODE_DIR;
969 if (S_ISLNK(stbuf->st_mode)) {
970 mode |= P9_STAT_MODE_SYMLINK;
973 if (S_ISSOCK(stbuf->st_mode)) {
974 mode |= P9_STAT_MODE_SOCKET;
977 if (S_ISFIFO(stbuf->st_mode)) {
978 mode |= P9_STAT_MODE_NAMED_PIPE;
981 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
982 mode |= P9_STAT_MODE_DEVICE;
985 if (stbuf->st_mode & S_ISUID) {
986 mode |= P9_STAT_MODE_SETUID;
989 if (stbuf->st_mode & S_ISGID) {
990 mode |= P9_STAT_MODE_SETGID;
993 if (stbuf->st_mode & S_ISVTX) {
994 mode |= P9_STAT_MODE_SETVTX;
997 return mode;
1000 static int stat_to_v9stat(V9fsState *s, V9fsString *name,
1001 const struct stat *stbuf,
1002 V9fsStat *v9stat)
1004 int err;
1005 const char *str;
1007 memset(v9stat, 0, sizeof(*v9stat));
1009 stat_to_qid(stbuf, &v9stat->qid);
1010 v9stat->mode = stat_to_v9mode(stbuf);
1011 v9stat->atime = stbuf->st_atime;
1012 v9stat->mtime = stbuf->st_mtime;
1013 v9stat->length = stbuf->st_size;
1015 v9fs_string_null(&v9stat->uid);
1016 v9fs_string_null(&v9stat->gid);
1017 v9fs_string_null(&v9stat->muid);
1019 v9stat->n_uid = stbuf->st_uid;
1020 v9stat->n_gid = stbuf->st_gid;
1021 v9stat->n_muid = 0;
1023 v9fs_string_null(&v9stat->extension);
1025 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1026 err = v9fs_co_readlink(s, name, &v9stat->extension);
1027 if (err < 0) {
1028 return err;
1030 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1031 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1032 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1033 major(stbuf->st_rdev), minor(stbuf->st_rdev));
1034 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1035 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1036 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1039 str = strrchr(name->data, '/');
1040 if (str) {
1041 str += 1;
1042 } else {
1043 str = name->data;
1046 v9fs_string_sprintf(&v9stat->name, "%s", str);
1048 v9stat->size = 61 +
1049 v9fs_string_size(&v9stat->name) +
1050 v9fs_string_size(&v9stat->uid) +
1051 v9fs_string_size(&v9stat->gid) +
1052 v9fs_string_size(&v9stat->muid) +
1053 v9fs_string_size(&v9stat->extension);
1054 return 0;
1057 #define P9_STATS_MODE 0x00000001ULL
1058 #define P9_STATS_NLINK 0x00000002ULL
1059 #define P9_STATS_UID 0x00000004ULL
1060 #define P9_STATS_GID 0x00000008ULL
1061 #define P9_STATS_RDEV 0x00000010ULL
1062 #define P9_STATS_ATIME 0x00000020ULL
1063 #define P9_STATS_MTIME 0x00000040ULL
1064 #define P9_STATS_CTIME 0x00000080ULL
1065 #define P9_STATS_INO 0x00000100ULL
1066 #define P9_STATS_SIZE 0x00000200ULL
1067 #define P9_STATS_BLOCKS 0x00000400ULL
1069 #define P9_STATS_BTIME 0x00000800ULL
1070 #define P9_STATS_GEN 0x00001000ULL
1071 #define P9_STATS_DATA_VERSION 0x00002000ULL
1073 #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
1074 #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
1077 static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1078 V9fsStatDotl *v9lstat)
1080 memset(v9lstat, 0, sizeof(*v9lstat));
1082 v9lstat->st_mode = stbuf->st_mode;
1083 v9lstat->st_nlink = stbuf->st_nlink;
1084 v9lstat->st_uid = stbuf->st_uid;
1085 v9lstat->st_gid = stbuf->st_gid;
1086 v9lstat->st_rdev = stbuf->st_rdev;
1087 v9lstat->st_size = stbuf->st_size;
1088 v9lstat->st_blksize = stbuf->st_blksize;
1089 v9lstat->st_blocks = stbuf->st_blocks;
1090 v9lstat->st_atime_sec = stbuf->st_atime;
1091 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1092 v9lstat->st_mtime_sec = stbuf->st_mtime;
1093 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1094 v9lstat->st_ctime_sec = stbuf->st_ctime;
1095 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1096 /* Currently we only support BASIC fields in stat */
1097 v9lstat->st_result_mask = P9_STATS_BASIC;
1099 stat_to_qid(stbuf, &v9lstat->qid);
1102 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1104 while (len && *iovcnt) {
1105 if (len < sg->iov_len) {
1106 sg->iov_len -= len;
1107 sg->iov_base += len;
1108 len = 0;
1109 } else {
1110 len -= sg->iov_len;
1111 sg++;
1112 *iovcnt -= 1;
1116 return sg;
1119 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1121 int i;
1122 int total = 0;
1124 for (i = 0; i < *cnt; i++) {
1125 if ((total + sg[i].iov_len) > cap) {
1126 sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1127 i++;
1128 break;
1130 total += sg[i].iov_len;
1133 *cnt = i;
1135 return sg;
1138 static void print_sg(struct iovec *sg, int cnt)
1140 int i;
1142 printf("sg[%d]: {", cnt);
1143 for (i = 0; i < cnt; i++) {
1144 if (i) {
1145 printf(", ");
1147 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1149 printf("}\n");
1152 static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1154 V9fsString str;
1155 v9fs_string_init(&str);
1156 v9fs_string_copy(&str, dst);
1157 v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1158 v9fs_string_free(&str);
1161 static void v9fs_version(void *opaque)
1163 V9fsPDU *pdu = opaque;
1164 V9fsState *s = pdu->s;
1165 V9fsString version;
1166 size_t offset = 7;
1168 pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1170 if (!strcmp(version.data, "9P2000.u")) {
1171 s->proto_version = V9FS_PROTO_2000U;
1172 } else if (!strcmp(version.data, "9P2000.L")) {
1173 s->proto_version = V9FS_PROTO_2000L;
1174 } else {
1175 v9fs_string_sprintf(&version, "unknown");
1178 offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1179 complete_pdu(s, pdu, offset);
1181 v9fs_string_free(&version);
1182 return;
1185 static void v9fs_attach(void *opaque)
1187 V9fsPDU *pdu = opaque;
1188 V9fsState *s = pdu->s;
1189 int32_t fid, afid, n_uname;
1190 V9fsString uname, aname;
1191 V9fsFidState *fidp;
1192 size_t offset = 7;
1193 V9fsQID qid;
1194 ssize_t err;
1196 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1198 fidp = alloc_fid(s, fid);
1199 if (fidp == NULL) {
1200 err = -EINVAL;
1201 goto out_nofid;
1203 fidp->uid = n_uname;
1204 v9fs_string_sprintf(&fidp->path, "%s", "/");
1205 err = fid_to_qid(s, fidp, &qid);
1206 if (err < 0) {
1207 err = -EINVAL;
1208 clunk_fid(s, fid);
1209 goto out;
1211 offset += pdu_marshal(pdu, offset, "Q", &qid);
1212 err = offset;
1213 out:
1214 put_fid(s, fidp);
1215 out_nofid:
1216 complete_pdu(s, pdu, err);
1217 v9fs_string_free(&uname);
1218 v9fs_string_free(&aname);
1221 static void v9fs_stat(void *opaque)
1223 int32_t fid;
1224 V9fsStat v9stat;
1225 ssize_t err = 0;
1226 size_t offset = 7;
1227 struct stat stbuf;
1228 V9fsFidState *fidp;
1229 V9fsPDU *pdu = opaque;
1230 V9fsState *s = pdu->s;
1232 pdu_unmarshal(pdu, offset, "d", &fid);
1234 fidp = get_fid(s, fid);
1235 if (fidp == NULL) {
1236 err = -ENOENT;
1237 goto out_nofid;
1239 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1240 if (err < 0) {
1241 goto out;
1243 err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
1244 if (err < 0) {
1245 goto out;
1247 offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1248 err = offset;
1249 v9fs_stat_free(&v9stat);
1250 out:
1251 put_fid(s, fidp);
1252 out_nofid:
1253 complete_pdu(s, pdu, err);
1256 static void v9fs_getattr(void *opaque)
1258 int32_t fid;
1259 size_t offset = 7;
1260 ssize_t retval = 0;
1261 struct stat stbuf;
1262 V9fsFidState *fidp;
1263 uint64_t request_mask;
1264 V9fsStatDotl v9stat_dotl;
1265 V9fsPDU *pdu = opaque;
1266 V9fsState *s = pdu->s;
1268 pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1270 fidp = get_fid(s, fid);
1271 if (fidp == NULL) {
1272 retval = -ENOENT;
1273 goto out_nofid;
1276 * Currently we only support BASIC fields in stat, so there is no
1277 * need to look at request_mask.
1279 retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
1280 if (retval < 0) {
1281 goto out;
1283 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1284 retval = offset;
1285 retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1286 out:
1287 put_fid(s, fidp);
1288 out_nofid:
1289 complete_pdu(s, pdu, retval);
1292 /* From Linux kernel code */
1293 #define ATTR_MODE (1 << 0)
1294 #define ATTR_UID (1 << 1)
1295 #define ATTR_GID (1 << 2)
1296 #define ATTR_SIZE (1 << 3)
1297 #define ATTR_ATIME (1 << 4)
1298 #define ATTR_MTIME (1 << 5)
1299 #define ATTR_CTIME (1 << 6)
1300 #define ATTR_MASK 127
1301 #define ATTR_ATIME_SET (1 << 7)
1302 #define ATTR_MTIME_SET (1 << 8)
1304 static void v9fs_setattr(void *opaque)
1306 int err = 0;
1307 int32_t fid;
1308 V9fsFidState *fidp;
1309 size_t offset = 7;
1310 V9fsIattr v9iattr;
1311 V9fsPDU *pdu = opaque;
1312 V9fsState *s = pdu->s;
1314 pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1316 fidp = get_fid(s, fid);
1317 if (fidp == NULL) {
1318 err = -EINVAL;
1319 goto out_nofid;
1321 if (v9iattr.valid & ATTR_MODE) {
1322 err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
1323 if (err < 0) {
1324 goto out;
1327 if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1328 struct timespec times[2];
1329 if (v9iattr.valid & ATTR_ATIME) {
1330 if (v9iattr.valid & ATTR_ATIME_SET) {
1331 times[0].tv_sec = v9iattr.atime_sec;
1332 times[0].tv_nsec = v9iattr.atime_nsec;
1333 } else {
1334 times[0].tv_nsec = UTIME_NOW;
1336 } else {
1337 times[0].tv_nsec = UTIME_OMIT;
1339 if (v9iattr.valid & ATTR_MTIME) {
1340 if (v9iattr.valid & ATTR_MTIME_SET) {
1341 times[1].tv_sec = v9iattr.mtime_sec;
1342 times[1].tv_nsec = v9iattr.mtime_nsec;
1343 } else {
1344 times[1].tv_nsec = UTIME_NOW;
1346 } else {
1347 times[1].tv_nsec = UTIME_OMIT;
1349 err = v9fs_co_utimensat(s, &fidp->path, times);
1350 if (err < 0) {
1351 goto out;
1355 * If the only valid entry in iattr is ctime we can call
1356 * chown(-1,-1) to update the ctime of the file
1358 if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1359 ((v9iattr.valid & ATTR_CTIME)
1360 && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1361 if (!(v9iattr.valid & ATTR_UID)) {
1362 v9iattr.uid = -1;
1364 if (!(v9iattr.valid & ATTR_GID)) {
1365 v9iattr.gid = -1;
1367 err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
1368 v9iattr.gid);
1369 if (err < 0) {
1370 goto out;
1373 if (v9iattr.valid & (ATTR_SIZE)) {
1374 err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
1375 if (err < 0) {
1376 goto out;
1379 err = offset;
1380 out:
1381 put_fid(s, fidp);
1382 out_nofid:
1383 complete_pdu(s, pdu, err);
1386 static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1388 int i;
1389 size_t offset = 7;
1390 offset += pdu_marshal(pdu, offset, "w", nwnames);
1391 for (i = 0; i < nwnames; i++) {
1392 offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
1394 return offset;
1397 static void v9fs_walk(void *opaque)
1399 int name_idx;
1400 V9fsQID *qids = NULL;
1401 int i, err = 0;
1402 V9fsString path;
1403 uint16_t nwnames;
1404 struct stat stbuf;
1405 size_t offset = 7;
1406 int32_t fid, newfid;
1407 V9fsString *wnames = NULL;
1408 V9fsFidState *fidp;
1409 V9fsFidState *newfidp = NULL;;
1410 V9fsPDU *pdu = opaque;
1411 V9fsState *s = pdu->s;
1413 offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
1414 &newfid, &nwnames);
1416 if (nwnames && nwnames <= P9_MAXWELEM) {
1417 wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1418 qids = g_malloc0(sizeof(qids[0]) * nwnames);
1419 for (i = 0; i < nwnames; i++) {
1420 offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1423 } else if (nwnames > P9_MAXWELEM) {
1424 err = -EINVAL;
1425 goto out_nofid;
1427 fidp = get_fid(s, fid);
1428 if (fidp == NULL) {
1429 err = -ENOENT;
1430 goto out_nofid;
1432 if (fid == newfid) {
1433 BUG_ON(fidp->fid_type != P9_FID_NONE);
1434 v9fs_string_init(&path);
1435 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1436 v9fs_string_sprintf(&path, "%s/%s",
1437 fidp->path.data, wnames[name_idx].data);
1438 v9fs_string_copy(&fidp->path, &path);
1440 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1441 if (err < 0) {
1442 v9fs_string_free(&path);
1443 goto out;
1445 stat_to_qid(&stbuf, &qids[name_idx]);
1447 v9fs_string_free(&path);
1448 } else {
1449 newfidp = alloc_fid(s, newfid);
1450 if (newfidp == NULL) {
1451 err = -EINVAL;
1452 goto out;
1454 newfidp->uid = fidp->uid;
1455 v9fs_string_init(&path);
1456 v9fs_string_copy(&newfidp->path, &fidp->path);
1457 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1458 v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
1459 wnames[name_idx].data);
1460 v9fs_string_copy(&newfidp->path, &path);
1461 err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
1462 if (err < 0) {
1463 clunk_fid(s, newfidp->fid);
1464 v9fs_string_free(&path);
1465 goto out;
1467 stat_to_qid(&stbuf, &qids[name_idx]);
1469 v9fs_string_free(&path);
1471 err = v9fs_walk_marshal(pdu, nwnames, qids);
1472 out:
1473 put_fid(s, fidp);
1474 if (newfidp) {
1475 put_fid(s, newfidp);
1477 out_nofid:
1478 complete_pdu(s, pdu, err);
1479 if (nwnames && nwnames <= P9_MAXWELEM) {
1480 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1481 v9fs_string_free(&wnames[name_idx]);
1483 g_free(wnames);
1484 g_free(qids);
1488 static int32_t get_iounit(V9fsState *s, V9fsString *name)
1490 struct statfs stbuf;
1491 int32_t iounit = 0;
1494 * iounit should be multiples of f_bsize (host filesystem block size
1495 * and as well as less than (client msize - P9_IOHDRSZ))
1497 if (!v9fs_co_statfs(s, name, &stbuf)) {
1498 iounit = stbuf.f_bsize;
1499 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1501 if (!iounit) {
1502 iounit = s->msize - P9_IOHDRSZ;
1504 return iounit;
1507 static void v9fs_open(void *opaque)
1509 int flags;
1510 int iounit;
1511 int32_t fid;
1512 int32_t mode;
1513 V9fsQID qid;
1514 ssize_t err = 0;
1515 size_t offset = 7;
1516 struct stat stbuf;
1517 V9fsFidState *fidp;
1518 V9fsPDU *pdu = opaque;
1519 V9fsState *s = pdu->s;
1521 if (s->proto_version == V9FS_PROTO_2000L) {
1522 pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1523 } else {
1524 pdu_unmarshal(pdu, offset, "db", &fid, &mode);
1526 fidp = get_fid(s, fid);
1527 if (fidp == NULL) {
1528 err = -ENOENT;
1529 goto out_nofid;
1531 BUG_ON(fidp->fid_type != P9_FID_NONE);
1533 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1534 if (err < 0) {
1535 goto out;
1537 stat_to_qid(&stbuf, &qid);
1538 if (S_ISDIR(stbuf.st_mode)) {
1539 err = v9fs_co_opendir(s, fidp);
1540 if (err < 0) {
1541 goto out;
1543 fidp->fid_type = P9_FID_DIR;
1544 offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
1545 err = offset;
1546 } else {
1547 if (s->proto_version == V9FS_PROTO_2000L) {
1548 flags = mode;
1549 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1550 /* Ignore direct disk access hint until the server supports it. */
1551 flags &= ~O_DIRECT;
1552 } else {
1553 flags = omode_to_uflags(mode);
1555 err = v9fs_co_open(s, fidp, flags);
1556 if (err < 0) {
1557 goto out;
1559 fidp->fid_type = P9_FID_FILE;
1560 fidp->open_flags = flags;
1561 if (flags & O_EXCL) {
1563 * We let the host file system do O_EXCL check
1564 * We should not reclaim such fd
1566 fidp->flags |= FID_NON_RECLAIMABLE;
1568 iounit = get_iounit(s, &fidp->path);
1569 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1570 err = offset;
1572 out:
1573 put_fid(s, fidp);
1574 out_nofid:
1575 complete_pdu(s, pdu, err);
1578 static void v9fs_lcreate(void *opaque)
1580 int32_t dfid, flags, mode;
1581 gid_t gid;
1582 ssize_t err = 0;
1583 ssize_t offset = 7;
1584 V9fsString fullname;
1585 V9fsString name;
1586 V9fsFidState *fidp;
1587 struct stat stbuf;
1588 V9fsQID qid;
1589 int32_t iounit;
1590 V9fsPDU *pdu = opaque;
1592 v9fs_string_init(&fullname);
1593 pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
1594 &mode, &gid);
1596 fidp = get_fid(pdu->s, dfid);
1597 if (fidp == NULL) {
1598 err = -ENOENT;
1599 goto out_nofid;
1601 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
1603 /* Ignore direct disk access hint until the server supports it. */
1604 flags &= ~O_DIRECT;
1606 err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
1607 if (err < 0) {
1608 goto out;
1610 fidp->fid_type = P9_FID_FILE;
1611 fidp->open_flags = flags;
1612 if (flags & O_EXCL) {
1614 * We let the host file system do O_EXCL check
1615 * We should not reclaim such fd
1617 fidp->flags |= FID_NON_RECLAIMABLE;
1619 iounit = get_iounit(pdu->s, &fullname);
1621 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
1622 if (err < 0) {
1623 fidp->fid_type = P9_FID_NONE;
1624 if (fidp->fs.fd > 0) {
1625 v9fs_co_close(pdu->s, fidp->fs.fd);
1627 goto out;
1629 v9fs_string_copy(&fidp->path, &fullname);
1630 stat_to_qid(&stbuf, &qid);
1631 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1632 err = offset;
1633 out:
1634 put_fid(pdu->s, fidp);
1635 out_nofid:
1636 complete_pdu(pdu->s, pdu, err);
1637 v9fs_string_free(&name);
1638 v9fs_string_free(&fullname);
1641 static void v9fs_fsync(void *opaque)
1643 int err;
1644 int32_t fid;
1645 int datasync;
1646 size_t offset = 7;
1647 V9fsFidState *fidp;
1648 V9fsPDU *pdu = opaque;
1649 V9fsState *s = pdu->s;
1651 pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1652 fidp = get_fid(s, fid);
1653 if (fidp == NULL) {
1654 err = -ENOENT;
1655 goto out_nofid;
1657 err = v9fs_co_fsync(s, fidp, datasync);
1658 if (!err) {
1659 err = offset;
1661 put_fid(s, fidp);
1662 out_nofid:
1663 complete_pdu(s, pdu, err);
1666 static void v9fs_clunk(void *opaque)
1668 int err;
1669 int32_t fid;
1670 size_t offset = 7;
1671 V9fsFidState *fidp;
1672 V9fsPDU *pdu = opaque;
1673 V9fsState *s = pdu->s;
1675 pdu_unmarshal(pdu, offset, "d", &fid);
1677 fidp = get_fid(s, fid);
1678 if (fidp == NULL) {
1679 err = -ENOENT;
1680 goto out_nofid;
1682 err = clunk_fid(s, fidp->fid);
1683 if (err < 0) {
1684 goto out;
1686 err = offset;
1687 out:
1688 put_fid(s, fidp);
1689 out_nofid:
1690 complete_pdu(s, pdu, err);
1693 static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
1694 V9fsFidState *fidp, int64_t off, int32_t max_count)
1696 size_t offset = 7;
1697 int read_count;
1698 int64_t xattr_len;
1700 xattr_len = fidp->fs.xattr.len;
1701 read_count = xattr_len - off;
1702 if (read_count > max_count) {
1703 read_count = max_count;
1704 } else if (read_count < 0) {
1706 * read beyond XATTR value
1708 read_count = 0;
1710 offset += pdu_marshal(pdu, offset, "d", read_count);
1711 offset += pdu_pack(pdu, offset,
1712 ((char *)fidp->fs.xattr.value) + off,
1713 read_count);
1714 return offset;
1717 static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
1718 V9fsFidState *fidp, int32_t max_count)
1720 V9fsString name;
1721 V9fsStat v9stat;
1722 int len, err = 0;
1723 int32_t count = 0;
1724 struct stat stbuf;
1725 off_t saved_dir_pos;
1726 struct dirent *dent, *result;
1728 /* save the directory position */
1729 saved_dir_pos = v9fs_co_telldir(s, fidp);
1730 if (saved_dir_pos < 0) {
1731 return saved_dir_pos;
1734 dent = g_malloc(sizeof(struct dirent));
1736 while (1) {
1737 v9fs_string_init(&name);
1738 err = v9fs_co_readdir_r(s, fidp, dent, &result);
1739 if (err || !result) {
1740 break;
1742 v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
1743 err = v9fs_co_lstat(s, &name, &stbuf);
1744 if (err < 0) {
1745 goto out;
1747 err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
1748 if (err < 0) {
1749 goto out;
1751 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1752 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1753 if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1754 /* Ran out of buffer. Set dir back to old position and return */
1755 v9fs_co_seekdir(s, fidp, saved_dir_pos);
1756 v9fs_stat_free(&v9stat);
1757 v9fs_string_free(&name);
1758 g_free(dent);
1759 return count;
1761 count += len;
1762 v9fs_stat_free(&v9stat);
1763 v9fs_string_free(&name);
1764 saved_dir_pos = dent->d_off;
1766 out:
1767 g_free(dent);
1768 v9fs_string_free(&name);
1769 if (err < 0) {
1770 return err;
1772 return count;
1775 static void v9fs_read(void *opaque)
1777 int32_t fid;
1778 int64_t off;
1779 ssize_t err = 0;
1780 int32_t count = 0;
1781 size_t offset = 7;
1782 int32_t max_count;
1783 V9fsFidState *fidp;
1784 V9fsPDU *pdu = opaque;
1785 V9fsState *s = pdu->s;
1787 pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1789 fidp = get_fid(s, fid);
1790 if (fidp == NULL) {
1791 err = -EINVAL;
1792 goto out_nofid;
1794 if (fidp->fid_type == P9_FID_DIR) {
1796 if (off == 0) {
1797 v9fs_co_rewinddir(s, fidp);
1799 count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
1800 if (count < 0) {
1801 err = count;
1802 goto out;
1804 err = offset;
1805 err += pdu_marshal(pdu, offset, "d", count);
1806 err += count;
1807 } else if (fidp->fid_type == P9_FID_FILE) {
1808 int32_t cnt;
1809 int32_t len;
1810 struct iovec *sg;
1811 struct iovec iov[128]; /* FIXME: bad, bad, bad */
1813 sg = iov;
1814 pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
1815 sg = cap_sg(sg, max_count, &cnt);
1816 do {
1817 if (0) {
1818 print_sg(sg, cnt);
1820 /* Loop in case of EINTR */
1821 do {
1822 len = v9fs_co_preadv(s, fidp, sg, cnt, off);
1823 if (len >= 0) {
1824 off += len;
1825 count += len;
1827 } while (len == -EINTR);
1828 if (len < 0) {
1829 /* IO error return the error */
1830 err = len;
1831 goto out;
1833 sg = adjust_sg(sg, len, &cnt);
1834 } while (count < max_count && len > 0);
1835 err = offset;
1836 err += pdu_marshal(pdu, offset, "d", count);
1837 err += count;
1838 } else if (fidp->fid_type == P9_FID_XATTR) {
1839 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1840 } else {
1841 err = -EINVAL;
1843 out:
1844 put_fid(s, fidp);
1845 out_nofid:
1846 complete_pdu(s, pdu, err);
1849 static size_t v9fs_readdir_data_size(V9fsString *name)
1852 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1853 * size of type (1) + size of name.size (2) + strlen(name.data)
1855 return 24 + v9fs_string_size(name);
1858 static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
1859 V9fsFidState *fidp, int32_t max_count)
1861 size_t size;
1862 V9fsQID qid;
1863 V9fsString name;
1864 int len, err = 0;
1865 int32_t count = 0;
1866 off_t saved_dir_pos;
1867 struct dirent *dent, *result;
1869 /* save the directory position */
1870 saved_dir_pos = v9fs_co_telldir(s, fidp);
1871 if (saved_dir_pos < 0) {
1872 return saved_dir_pos;
1875 dent = g_malloc(sizeof(struct dirent));
1877 while (1) {
1878 err = v9fs_co_readdir_r(s, fidp, dent, &result);
1879 if (err || !result) {
1880 break;
1882 v9fs_string_init(&name);
1883 v9fs_string_sprintf(&name, "%s", dent->d_name);
1884 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1885 /* Ran out of buffer. Set dir back to old position and return */
1886 v9fs_co_seekdir(s, fidp, saved_dir_pos);
1887 v9fs_string_free(&name);
1888 g_free(dent);
1889 return count;
1892 * Fill up just the path field of qid because the client uses
1893 * only that. To fill the entire qid structure we will have
1894 * to stat each dirent found, which is expensive
1896 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1897 memcpy(&qid.path, &dent->d_ino, size);
1898 /* Fill the other fields with dummy values */
1899 qid.type = 0;
1900 qid.version = 0;
1902 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1903 len = pdu_marshal(pdu, 11 + count, "Qqbs",
1904 &qid, dent->d_off,
1905 dent->d_type, &name);
1906 count += len;
1907 v9fs_string_free(&name);
1908 saved_dir_pos = dent->d_off;
1910 g_free(dent);
1911 if (err < 0) {
1912 return err;
1914 return count;
1917 static void v9fs_readdir(void *opaque)
1919 int32_t fid;
1920 V9fsFidState *fidp;
1921 ssize_t retval = 0;
1922 size_t offset = 7;
1923 int64_t initial_offset;
1924 int32_t count, max_count;
1925 V9fsPDU *pdu = opaque;
1926 V9fsState *s = pdu->s;
1928 pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
1930 fidp = get_fid(s, fid);
1931 if (fidp == NULL) {
1932 retval = -EINVAL;
1933 goto out_nofid;
1935 if (!fidp->fs.dir) {
1936 retval = -EINVAL;
1937 goto out;
1939 if (initial_offset == 0) {
1940 v9fs_co_rewinddir(s, fidp);
1941 } else {
1942 v9fs_co_seekdir(s, fidp, initial_offset);
1944 count = v9fs_do_readdir(s, pdu, fidp, max_count);
1945 if (count < 0) {
1946 retval = count;
1947 goto out;
1949 retval = offset;
1950 retval += pdu_marshal(pdu, offset, "d", count);
1951 retval += count;
1952 out:
1953 put_fid(s, fidp);
1954 out_nofid:
1955 complete_pdu(s, pdu, retval);
1958 static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1959 int64_t off, int32_t count,
1960 struct iovec *sg, int cnt)
1962 int i, to_copy;
1963 ssize_t err = 0;
1964 int write_count;
1965 int64_t xattr_len;
1966 size_t offset = 7;
1969 xattr_len = fidp->fs.xattr.len;
1970 write_count = xattr_len - off;
1971 if (write_count > count) {
1972 write_count = count;
1973 } else if (write_count < 0) {
1975 * write beyond XATTR value len specified in
1976 * xattrcreate
1978 err = -ENOSPC;
1979 goto out;
1981 offset += pdu_marshal(pdu, offset, "d", write_count);
1982 err = offset;
1983 fidp->fs.xattr.copied_len += write_count;
1985 * Now copy the content from sg list
1987 for (i = 0; i < cnt; i++) {
1988 if (write_count > sg[i].iov_len) {
1989 to_copy = sg[i].iov_len;
1990 } else {
1991 to_copy = write_count;
1993 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
1994 /* updating vs->off since we are not using below */
1995 off += to_copy;
1996 write_count -= to_copy;
1998 out:
1999 return err;
2002 static void v9fs_write(void *opaque)
2004 int cnt;
2005 ssize_t err;
2006 int32_t fid;
2007 int64_t off;
2008 int32_t count;
2009 int32_t len = 0;
2010 int32_t total = 0;
2011 size_t offset = 7;
2012 V9fsFidState *fidp;
2013 struct iovec iov[128]; /* FIXME: bad, bad, bad */
2014 struct iovec *sg = iov;
2015 V9fsPDU *pdu = opaque;
2016 V9fsState *s = pdu->s;
2018 pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
2020 fidp = get_fid(s, fid);
2021 if (fidp == NULL) {
2022 err = -EINVAL;
2023 goto out_nofid;
2025 if (fidp->fid_type == P9_FID_FILE) {
2026 if (fidp->fs.fd == -1) {
2027 err = -EINVAL;
2028 goto out;
2030 } else if (fidp->fid_type == P9_FID_XATTR) {
2032 * setxattr operation
2034 err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
2035 goto out;
2036 } else {
2037 err = -EINVAL;
2038 goto out;
2040 sg = cap_sg(sg, count, &cnt);
2041 do {
2042 if (0) {
2043 print_sg(sg, cnt);
2045 /* Loop in case of EINTR */
2046 do {
2047 len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
2048 if (len >= 0) {
2049 off += len;
2050 total += len;
2052 } while (len == -EINTR);
2053 if (len < 0) {
2054 /* IO error return the error */
2055 err = len;
2056 goto out;
2058 sg = adjust_sg(sg, len, &cnt);
2059 } while (total < count && len > 0);
2060 offset += pdu_marshal(pdu, offset, "d", total);
2061 err = offset;
2062 out:
2063 put_fid(s, fidp);
2064 out_nofid:
2065 complete_pdu(s, pdu, err);
2068 static void v9fs_create(void *opaque)
2070 int32_t fid;
2071 int err = 0;
2072 size_t offset = 7;
2073 V9fsFidState *fidp;
2074 V9fsQID qid;
2075 int32_t perm;
2076 int8_t mode;
2077 struct stat stbuf;
2078 V9fsString name;
2079 V9fsString extension;
2080 V9fsString fullname;
2081 int iounit;
2082 V9fsPDU *pdu = opaque;
2084 v9fs_string_init(&fullname);
2086 pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2087 &perm, &mode, &extension);
2089 fidp = get_fid(pdu->s, fid);
2090 if (fidp == NULL) {
2091 err = -EINVAL;
2092 goto out_nofid;
2095 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2096 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2097 if (!err) {
2098 err = -EEXIST;
2099 goto out;
2100 } else if (err != -ENOENT) {
2101 goto out;
2103 if (perm & P9_STAT_MODE_DIR) {
2104 err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
2105 fidp->uid, -1);
2106 if (err < 0) {
2107 goto out;
2109 err = v9fs_co_opendir(pdu->s, fidp);
2110 if (err < 0) {
2111 goto out;
2113 fidp->fid_type = P9_FID_DIR;
2114 } else if (perm & P9_STAT_MODE_SYMLINK) {
2115 err = v9fs_co_symlink(pdu->s, fidp, extension.data,
2116 fullname.data, -1);
2117 if (err < 0) {
2118 goto out;
2120 } else if (perm & P9_STAT_MODE_LINK) {
2121 int32_t nfid = atoi(extension.data);
2122 V9fsFidState *nfidp = get_fid(pdu->s, nfid);
2123 if (nfidp == NULL) {
2124 err = -EINVAL;
2125 goto out;
2127 err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
2128 if (err < 0) {
2129 put_fid(pdu->s, nfidp);
2130 goto out;
2132 put_fid(pdu->s, nfidp);
2133 } else if (perm & P9_STAT_MODE_DEVICE) {
2134 char ctype;
2135 uint32_t major, minor;
2136 mode_t nmode = 0;
2138 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2139 err = -errno;
2140 goto out;
2143 switch (ctype) {
2144 case 'c':
2145 nmode = S_IFCHR;
2146 break;
2147 case 'b':
2148 nmode = S_IFBLK;
2149 break;
2150 default:
2151 err = -EIO;
2152 goto out;
2155 nmode |= perm & 0777;
2156 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2157 makedev(major, minor), nmode);
2158 if (err < 0) {
2159 goto out;
2161 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2162 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2163 0, S_IFIFO | (perm & 0777));
2164 if (err < 0) {
2165 goto out;
2167 } else if (perm & P9_STAT_MODE_SOCKET) {
2168 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2169 0, S_IFSOCK | (perm & 0777));
2170 if (err < 0) {
2171 goto out;
2173 } else {
2174 err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
2175 omode_to_uflags(mode)|O_CREAT, perm);
2176 if (err < 0) {
2177 goto out;
2179 fidp->fid_type = P9_FID_FILE;
2180 fidp->open_flags = omode_to_uflags(mode);
2181 if (fidp->open_flags & O_EXCL) {
2183 * We let the host file system do O_EXCL check
2184 * We should not reclaim such fd
2186 fidp->flags |= FID_NON_RECLAIMABLE;
2189 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2190 if (err < 0) {
2191 fidp->fid_type = P9_FID_NONE;
2192 if (fidp->fs.fd) {
2193 v9fs_co_close(pdu->s, fidp->fs.fd);
2195 goto out;
2197 iounit = get_iounit(pdu->s, &fidp->path);
2198 v9fs_string_copy(&fidp->path, &fullname);
2199 stat_to_qid(&stbuf, &qid);
2200 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2201 err = offset;
2202 out:
2203 put_fid(pdu->s, fidp);
2204 out_nofid:
2205 complete_pdu(pdu->s, pdu, err);
2206 v9fs_string_free(&name);
2207 v9fs_string_free(&extension);
2208 v9fs_string_free(&fullname);
2211 static void v9fs_symlink(void *opaque)
2213 V9fsPDU *pdu = opaque;
2214 V9fsString name;
2215 V9fsString symname;
2216 V9fsString fullname;
2217 V9fsFidState *dfidp;
2218 V9fsQID qid;
2219 struct stat stbuf;
2220 int32_t dfid;
2221 int err = 0;
2222 gid_t gid;
2223 size_t offset = 7;
2225 v9fs_string_init(&fullname);
2226 pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2228 dfidp = get_fid(pdu->s, dfid);
2229 if (dfidp == NULL) {
2230 err = -EINVAL;
2231 goto out_nofid;
2234 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2235 err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
2236 if (err < 0) {
2237 goto out;
2239 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2240 if (err < 0) {
2241 goto out;
2243 stat_to_qid(&stbuf, &qid);
2244 offset += pdu_marshal(pdu, offset, "Q", &qid);
2245 err = offset;
2246 out:
2247 put_fid(pdu->s, dfidp);
2248 out_nofid:
2249 complete_pdu(pdu->s, pdu, err);
2250 v9fs_string_free(&name);
2251 v9fs_string_free(&symname);
2252 v9fs_string_free(&fullname);
2255 static void v9fs_flush(void *opaque)
2257 V9fsPDU *pdu = opaque;
2258 V9fsState *s = pdu->s;
2259 /* A nop call with no return */
2260 complete_pdu(s, pdu, 7);
2261 return;
2264 static void v9fs_link(void *opaque)
2266 V9fsPDU *pdu = opaque;
2267 V9fsState *s = pdu->s;
2268 int32_t dfid, oldfid;
2269 V9fsFidState *dfidp, *oldfidp;
2270 V9fsString name, fullname;
2271 size_t offset = 7;
2272 int err = 0;
2274 v9fs_string_init(&fullname);
2276 pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2278 dfidp = get_fid(s, dfid);
2279 if (dfidp == NULL) {
2280 err = -ENOENT;
2281 goto out_nofid;
2284 oldfidp = get_fid(s, oldfid);
2285 if (oldfidp == NULL) {
2286 err = -ENOENT;
2287 goto out;
2290 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2291 err = v9fs_co_link(s, &oldfidp->path, &fullname);
2292 if (!err) {
2293 err = offset;
2295 v9fs_string_free(&fullname);
2297 out:
2298 put_fid(s, dfidp);
2299 out_nofid:
2300 v9fs_string_free(&name);
2301 complete_pdu(s, pdu, err);
2304 static void v9fs_remove(void *opaque)
2306 int32_t fid;
2307 int err = 0;
2308 size_t offset = 7;
2309 V9fsFidState *fidp;
2310 V9fsPDU *pdu = opaque;
2312 pdu_unmarshal(pdu, offset, "d", &fid);
2314 fidp = get_fid(pdu->s, fid);
2315 if (fidp == NULL) {
2316 err = -EINVAL;
2317 goto out_nofid;
2320 * IF the file is unlinked, we cannot reopen
2321 * the file later. So don't reclaim fd
2323 err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
2324 if (err < 0) {
2325 goto out_err;
2327 err = v9fs_co_remove(pdu->s, &fidp->path);
2328 if (!err) {
2329 err = offset;
2331 out_err:
2332 /* For TREMOVE we need to clunk the fid even on failed remove */
2333 clunk_fid(pdu->s, fidp->fid);
2334 put_fid(pdu->s, fidp);
2335 out_nofid:
2336 complete_pdu(pdu->s, pdu, err);
2339 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
2340 int32_t newdirfid, V9fsString *name)
2342 char *end;
2343 int err = 0;
2344 V9fsFidState *dirfidp = NULL;
2345 char *old_name, *new_name;
2347 if (newdirfid != -1) {
2348 dirfidp = get_fid(s, newdirfid);
2349 if (dirfidp == NULL) {
2350 err = -ENOENT;
2351 goto out_nofid;
2353 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2355 new_name = g_malloc0(dirfidp->path.size + name->size + 2);
2357 strcpy(new_name, dirfidp->path.data);
2358 strcat(new_name, "/");
2359 strcat(new_name + dirfidp->path.size, name->data);
2360 } else {
2361 old_name = fidp->path.data;
2362 end = strrchr(old_name, '/');
2363 if (end) {
2364 end++;
2365 } else {
2366 end = old_name;
2368 new_name = g_malloc0(end - old_name + name->size + 1);
2370 strncat(new_name, old_name, end - old_name);
2371 strncat(new_name + (end - old_name), name->data, name->size);
2374 v9fs_string_free(name);
2375 name->data = new_name;
2376 name->size = strlen(new_name);
2378 if (strcmp(new_name, fidp->path.data) != 0) {
2379 err = v9fs_co_rename(s, &fidp->path, name);
2380 if (err < 0) {
2381 goto out;
2383 V9fsFidState *tfidp;
2385 * Fixup fid's pointing to the old name to
2386 * start pointing to the new name
2388 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2389 if (fidp == tfidp) {
2391 * we replace name of this fid towards the end
2392 * so that our below strcmp will work
2394 continue;
2396 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2397 /* replace the name */
2398 v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
2401 v9fs_string_copy(&fidp->path, name);
2403 out:
2404 if (dirfidp) {
2405 put_fid(s, dirfidp);
2407 out_nofid:
2408 return err;
2411 static void v9fs_rename(void *opaque)
2413 int32_t fid;
2414 ssize_t err = 0;
2415 size_t offset = 7;
2416 V9fsString name;
2417 int32_t newdirfid;
2418 V9fsFidState *fidp;
2419 V9fsPDU *pdu = opaque;
2420 V9fsState *s = pdu->s;
2422 pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2424 fidp = get_fid(s, fid);
2425 if (fidp == NULL) {
2426 err = -ENOENT;
2427 goto out_nofid;
2429 BUG_ON(fidp->fid_type != P9_FID_NONE);
2431 err = v9fs_complete_rename(s, fidp, newdirfid, &name);
2432 if (!err) {
2433 err = offset;
2435 put_fid(s, fidp);
2436 out_nofid:
2437 complete_pdu(s, pdu, err);
2438 v9fs_string_free(&name);
2441 static void v9fs_wstat(void *opaque)
2443 int32_t fid;
2444 int err = 0;
2445 int16_t unused;
2446 V9fsStat v9stat;
2447 size_t offset = 7;
2448 struct stat stbuf;
2449 V9fsFidState *fidp;
2450 V9fsPDU *pdu = opaque;
2451 V9fsState *s = pdu->s;
2453 pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2455 fidp = get_fid(s, fid);
2456 if (fidp == NULL) {
2457 err = -EINVAL;
2458 goto out_nofid;
2460 /* do we need to sync the file? */
2461 if (donttouch_stat(&v9stat)) {
2462 err = v9fs_co_fsync(s, fidp, 0);
2463 goto out;
2465 if (v9stat.mode != -1) {
2466 uint32_t v9_mode;
2467 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
2468 if (err < 0) {
2469 goto out;
2471 v9_mode = stat_to_v9mode(&stbuf);
2472 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2473 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2474 /* Attempting to change the type */
2475 err = -EIO;
2476 goto out;
2478 err = v9fs_co_chmod(s, &fidp->path,
2479 v9mode_to_mode(v9stat.mode,
2480 &v9stat.extension));
2481 if (err < 0) {
2482 goto out;
2485 if (v9stat.mtime != -1 || v9stat.atime != -1) {
2486 struct timespec times[2];
2487 if (v9stat.atime != -1) {
2488 times[0].tv_sec = v9stat.atime;
2489 times[0].tv_nsec = 0;
2490 } else {
2491 times[0].tv_nsec = UTIME_OMIT;
2493 if (v9stat.mtime != -1) {
2494 times[1].tv_sec = v9stat.mtime;
2495 times[1].tv_nsec = 0;
2496 } else {
2497 times[1].tv_nsec = UTIME_OMIT;
2499 err = v9fs_co_utimensat(s, &fidp->path, times);
2500 if (err < 0) {
2501 goto out;
2504 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2505 err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2506 if (err < 0) {
2507 goto out;
2510 if (v9stat.name.size != 0) {
2511 err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
2512 if (err < 0) {
2513 goto out;
2516 if (v9stat.length != -1) {
2517 err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
2518 if (err < 0) {
2519 goto out;
2522 err = offset;
2523 out:
2524 put_fid(s, fidp);
2525 out_nofid:
2526 v9fs_stat_free(&v9stat);
2527 complete_pdu(s, pdu, err);
2530 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2532 uint32_t f_type;
2533 uint32_t f_bsize;
2534 uint64_t f_blocks;
2535 uint64_t f_bfree;
2536 uint64_t f_bavail;
2537 uint64_t f_files;
2538 uint64_t f_ffree;
2539 uint64_t fsid_val;
2540 uint32_t f_namelen;
2541 size_t offset = 7;
2542 int32_t bsize_factor;
2545 * compute bsize factor based on host file system block size
2546 * and client msize
2548 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2549 if (!bsize_factor) {
2550 bsize_factor = 1;
2552 f_type = stbuf->f_type;
2553 f_bsize = stbuf->f_bsize;
2554 f_bsize *= bsize_factor;
2556 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2557 * adjust(divide) the number of blocks, free blocks and available
2558 * blocks by bsize factor
2560 f_blocks = stbuf->f_blocks/bsize_factor;
2561 f_bfree = stbuf->f_bfree/bsize_factor;
2562 f_bavail = stbuf->f_bavail/bsize_factor;
2563 f_files = stbuf->f_files;
2564 f_ffree = stbuf->f_ffree;
2565 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2566 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2567 f_namelen = stbuf->f_namelen;
2569 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2570 f_type, f_bsize, f_blocks, f_bfree,
2571 f_bavail, f_files, f_ffree,
2572 fsid_val, f_namelen);
2575 static void v9fs_statfs(void *opaque)
2577 int32_t fid;
2578 ssize_t retval = 0;
2579 size_t offset = 7;
2580 V9fsFidState *fidp;
2581 struct statfs stbuf;
2582 V9fsPDU *pdu = opaque;
2583 V9fsState *s = pdu->s;
2585 pdu_unmarshal(pdu, offset, "d", &fid);
2586 fidp = get_fid(s, fid);
2587 if (fidp == NULL) {
2588 retval = -ENOENT;
2589 goto out_nofid;
2591 retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2592 if (retval < 0) {
2593 goto out;
2595 retval = offset;
2596 retval += v9fs_fill_statfs(s, pdu, &stbuf);
2597 out:
2598 put_fid(s, fidp);
2599 out_nofid:
2600 complete_pdu(s, pdu, retval);
2601 return;
2604 static void v9fs_mknod(void *opaque)
2607 int mode;
2608 gid_t gid;
2609 int32_t fid;
2610 V9fsQID qid;
2611 int err = 0;
2612 int major, minor;
2613 size_t offset = 7;
2614 V9fsString name;
2615 struct stat stbuf;
2616 V9fsString fullname;
2617 V9fsFidState *fidp;
2618 V9fsPDU *pdu = opaque;
2619 V9fsState *s = pdu->s;
2621 v9fs_string_init(&fullname);
2622 pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2623 &major, &minor, &gid);
2625 fidp = get_fid(s, fid);
2626 if (fidp == NULL) {
2627 err = -ENOENT;
2628 goto out_nofid;
2630 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2631 err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
2632 makedev(major, minor), mode);
2633 if (err < 0) {
2634 goto out;
2636 err = v9fs_co_lstat(s, &fullname, &stbuf);
2637 if (err < 0) {
2638 goto out;
2640 stat_to_qid(&stbuf, &qid);
2641 err = offset;
2642 err += pdu_marshal(pdu, offset, "Q", &qid);
2643 out:
2644 put_fid(s, fidp);
2645 out_nofid:
2646 complete_pdu(s, pdu, err);
2647 v9fs_string_free(&fullname);
2648 v9fs_string_free(&name);
2652 * Implement posix byte range locking code
2653 * Server side handling of locking code is very simple, because 9p server in
2654 * QEMU can handle only one client. And most of the lock handling
2655 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2656 * do any thing in * qemu 9p server side lock code path.
2657 * So when a TLOCK request comes, always return success
2659 static void v9fs_lock(void *opaque)
2661 int8_t status;
2662 V9fsFlock *flock;
2663 size_t offset = 7;
2664 struct stat stbuf;
2665 V9fsFidState *fidp;
2666 int32_t fid, err = 0;
2667 V9fsPDU *pdu = opaque;
2668 V9fsState *s = pdu->s;
2670 flock = g_malloc(sizeof(*flock));
2671 pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
2672 &flock->flags, &flock->start, &flock->length,
2673 &flock->proc_id, &flock->client_id);
2674 status = P9_LOCK_ERROR;
2676 /* We support only block flag now (that too ignored currently) */
2677 if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
2678 err = -EINVAL;
2679 goto out_nofid;
2681 fidp = get_fid(s, fid);
2682 if (fidp == NULL) {
2683 err = -ENOENT;
2684 goto out_nofid;
2686 err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2687 if (err < 0) {
2688 goto out;
2690 status = P9_LOCK_SUCCESS;
2691 out:
2692 put_fid(s, fidp);
2693 out_nofid:
2694 err = offset;
2695 err += pdu_marshal(pdu, offset, "b", status);
2696 complete_pdu(s, pdu, err);
2697 g_free(flock);
2701 * When a TGETLOCK request comes, always return success because all lock
2702 * handling is done by client's VFS layer.
2704 static void v9fs_getlock(void *opaque)
2706 size_t offset = 7;
2707 struct stat stbuf;
2708 V9fsFidState *fidp;
2709 V9fsGetlock *glock;
2710 int32_t fid, err = 0;
2711 V9fsPDU *pdu = opaque;
2712 V9fsState *s = pdu->s;
2714 glock = g_malloc(sizeof(*glock));
2715 pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
2716 &glock->start, &glock->length, &glock->proc_id,
2717 &glock->client_id);
2719 fidp = get_fid(s, fid);
2720 if (fidp == NULL) {
2721 err = -ENOENT;
2722 goto out_nofid;
2724 err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2725 if (err < 0) {
2726 goto out;
2728 glock->type = F_UNLCK;
2729 offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
2730 glock->start, glock->length, glock->proc_id,
2731 &glock->client_id);
2732 err = offset;
2733 out:
2734 put_fid(s, fidp);
2735 out_nofid:
2736 complete_pdu(s, pdu, err);
2737 g_free(glock);
2740 static void v9fs_mkdir(void *opaque)
2742 V9fsPDU *pdu = opaque;
2743 size_t offset = 7;
2744 int32_t fid;
2745 struct stat stbuf;
2746 V9fsString name, fullname;
2747 V9fsQID qid;
2748 V9fsFidState *fidp;
2749 gid_t gid;
2750 int mode;
2751 int err = 0;
2753 v9fs_string_init(&fullname);
2754 pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2756 fidp = get_fid(pdu->s, fid);
2757 if (fidp == NULL) {
2758 err = -ENOENT;
2759 goto out_nofid;
2761 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2762 err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
2763 if (err < 0) {
2764 goto out;
2766 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2767 if (err < 0) {
2768 goto out;
2770 stat_to_qid(&stbuf, &qid);
2771 offset += pdu_marshal(pdu, offset, "Q", &qid);
2772 err = offset;
2773 out:
2774 put_fid(pdu->s, fidp);
2775 out_nofid:
2776 complete_pdu(pdu->s, pdu, err);
2777 v9fs_string_free(&fullname);
2778 v9fs_string_free(&name);
2781 static void v9fs_xattrwalk(void *opaque)
2783 int64_t size;
2784 V9fsString name;
2785 ssize_t err = 0;
2786 size_t offset = 7;
2787 int32_t fid, newfid;
2788 V9fsFidState *file_fidp;
2789 V9fsFidState *xattr_fidp = NULL;
2790 V9fsPDU *pdu = opaque;
2791 V9fsState *s = pdu->s;
2793 pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
2794 file_fidp = get_fid(s, fid);
2795 if (file_fidp == NULL) {
2796 err = -ENOENT;
2797 goto out_nofid;
2799 xattr_fidp = alloc_fid(s, newfid);
2800 if (xattr_fidp == NULL) {
2801 err = -EINVAL;
2802 goto out;
2804 v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
2805 if (name.data[0] == 0) {
2807 * listxattr request. Get the size first
2809 size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
2810 if (size < 0) {
2811 err = size;
2812 clunk_fid(s, xattr_fidp->fid);
2813 goto out;
2816 * Read the xattr value
2818 xattr_fidp->fs.xattr.len = size;
2819 xattr_fidp->fid_type = P9_FID_XATTR;
2820 xattr_fidp->fs.xattr.copied_len = -1;
2821 if (size) {
2822 xattr_fidp->fs.xattr.value = g_malloc(size);
2823 err = v9fs_co_llistxattr(s, &xattr_fidp->path,
2824 xattr_fidp->fs.xattr.value,
2825 xattr_fidp->fs.xattr.len);
2826 if (err < 0) {
2827 clunk_fid(s, xattr_fidp->fid);
2828 goto out;
2831 offset += pdu_marshal(pdu, offset, "q", size);
2832 err = offset;
2833 } else {
2835 * specific xattr fid. We check for xattr
2836 * presence also collect the xattr size
2838 size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2839 &name, NULL, 0);
2840 if (size < 0) {
2841 err = size;
2842 clunk_fid(s, xattr_fidp->fid);
2843 goto out;
2846 * Read the xattr value
2848 xattr_fidp->fs.xattr.len = size;
2849 xattr_fidp->fid_type = P9_FID_XATTR;
2850 xattr_fidp->fs.xattr.copied_len = -1;
2851 if (size) {
2852 xattr_fidp->fs.xattr.value = g_malloc(size);
2853 err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2854 &name, xattr_fidp->fs.xattr.value,
2855 xattr_fidp->fs.xattr.len);
2856 if (err < 0) {
2857 clunk_fid(s, xattr_fidp->fid);
2858 goto out;
2861 offset += pdu_marshal(pdu, offset, "q", size);
2862 err = offset;
2864 out:
2865 put_fid(s, file_fidp);
2866 if (xattr_fidp) {
2867 put_fid(s, xattr_fidp);
2869 out_nofid:
2870 complete_pdu(s, pdu, err);
2871 v9fs_string_free(&name);
2874 static void v9fs_xattrcreate(void *opaque)
2876 int flags;
2877 int32_t fid;
2878 int64_t size;
2879 ssize_t err = 0;
2880 V9fsString name;
2881 size_t offset = 7;
2882 V9fsFidState *file_fidp;
2883 V9fsFidState *xattr_fidp;
2884 V9fsPDU *pdu = opaque;
2885 V9fsState *s = pdu->s;
2887 pdu_unmarshal(pdu, offset, "dsqd",
2888 &fid, &name, &size, &flags);
2890 file_fidp = get_fid(s, fid);
2891 if (file_fidp == NULL) {
2892 err = -EINVAL;
2893 goto out_nofid;
2895 /* Make the file fid point to xattr */
2896 xattr_fidp = file_fidp;
2897 xattr_fidp->fid_type = P9_FID_XATTR;
2898 xattr_fidp->fs.xattr.copied_len = 0;
2899 xattr_fidp->fs.xattr.len = size;
2900 xattr_fidp->fs.xattr.flags = flags;
2901 v9fs_string_init(&xattr_fidp->fs.xattr.name);
2902 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
2903 if (size) {
2904 xattr_fidp->fs.xattr.value = g_malloc(size);
2905 } else {
2906 xattr_fidp->fs.xattr.value = NULL;
2908 err = offset;
2909 put_fid(s, file_fidp);
2910 out_nofid:
2911 complete_pdu(s, pdu, err);
2912 v9fs_string_free(&name);
2915 static void v9fs_readlink(void *opaque)
2917 V9fsPDU *pdu = opaque;
2918 size_t offset = 7;
2919 V9fsString target;
2920 int32_t fid;
2921 int err = 0;
2922 V9fsFidState *fidp;
2924 pdu_unmarshal(pdu, offset, "d", &fid);
2925 fidp = get_fid(pdu->s, fid);
2926 if (fidp == NULL) {
2927 err = -ENOENT;
2928 goto out_nofid;
2931 v9fs_string_init(&target);
2932 err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
2933 if (err < 0) {
2934 goto out;
2936 offset += pdu_marshal(pdu, offset, "s", &target);
2937 err = offset;
2938 v9fs_string_free(&target);
2939 out:
2940 put_fid(pdu->s, fidp);
2941 out_nofid:
2942 complete_pdu(pdu->s, pdu, err);
2945 static CoroutineEntry *pdu_co_handlers[] = {
2946 [P9_TREADDIR] = v9fs_readdir,
2947 [P9_TSTATFS] = v9fs_statfs,
2948 [P9_TGETATTR] = v9fs_getattr,
2949 [P9_TSETATTR] = v9fs_setattr,
2950 [P9_TXATTRWALK] = v9fs_xattrwalk,
2951 [P9_TXATTRCREATE] = v9fs_xattrcreate,
2952 [P9_TMKNOD] = v9fs_mknod,
2953 [P9_TRENAME] = v9fs_rename,
2954 [P9_TLOCK] = v9fs_lock,
2955 [P9_TGETLOCK] = v9fs_getlock,
2956 [P9_TREADLINK] = v9fs_readlink,
2957 [P9_TMKDIR] = v9fs_mkdir,
2958 [P9_TVERSION] = v9fs_version,
2959 [P9_TLOPEN] = v9fs_open,
2960 [P9_TATTACH] = v9fs_attach,
2961 [P9_TSTAT] = v9fs_stat,
2962 [P9_TWALK] = v9fs_walk,
2963 [P9_TCLUNK] = v9fs_clunk,
2964 [P9_TFSYNC] = v9fs_fsync,
2965 [P9_TOPEN] = v9fs_open,
2966 [P9_TREAD] = v9fs_read,
2967 #if 0
2968 [P9_TAUTH] = v9fs_auth,
2969 #endif
2970 [P9_TFLUSH] = v9fs_flush,
2971 [P9_TLINK] = v9fs_link,
2972 [P9_TSYMLINK] = v9fs_symlink,
2973 [P9_TCREATE] = v9fs_create,
2974 [P9_TLCREATE] = v9fs_lcreate,
2975 [P9_TWRITE] = v9fs_write,
2976 [P9_TWSTAT] = v9fs_wstat,
2977 [P9_TREMOVE] = v9fs_remove,
2980 static void v9fs_op_not_supp(void *opaque)
2982 V9fsPDU *pdu = opaque;
2983 complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
2986 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
2988 Coroutine *co;
2989 CoroutineEntry *handler;
2991 if (debug_9p_pdu) {
2992 pprint_pdu(pdu);
2994 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
2995 (pdu_co_handlers[pdu->id] == NULL)) {
2996 handler = v9fs_op_not_supp;
2997 } else {
2998 handler = pdu_co_handlers[pdu->id];
3000 co = qemu_coroutine_create(handler);
3001 qemu_coroutine_enter(co, pdu);
3004 void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3006 V9fsState *s = (V9fsState *)vdev;
3007 V9fsPDU *pdu;
3008 ssize_t len;
3010 while ((pdu = alloc_pdu(s)) &&
3011 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3012 uint8_t *ptr;
3013 pdu->s = s;
3014 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3015 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3017 ptr = pdu->elem.out_sg[0].iov_base;
3019 memcpy(&pdu->size, ptr, 4);
3020 pdu->id = ptr[4];
3021 memcpy(&pdu->tag, ptr + 5, 2);
3022 submit_pdu(s, pdu);
3024 free_pdu(s, pdu);
3027 void virtio_9p_set_fd_limit(void)
3029 struct rlimit rlim;
3030 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3031 fprintf(stderr, "Failed to get the resource limit\n");
3032 exit(1);
3034 open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3035 open_fd_rc = rlim.rlim_cur/2;