hw/9pfs: use migration blockers to prevent live migration when virtfs export path...
[qemu.git] / hw / 9pfs / virtio-9p.c
blob32b98ddef223cc3ca60e88b407a6a9c1aff45c81
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 <glib.h>
15 #include <glib/gprintf.h>
17 #include "hw/virtio.h"
18 #include "hw/pc.h"
19 #include "qemu_socket.h"
20 #include "hw/virtio-pci.h"
21 #include "virtio-9p.h"
22 #include "fsdev/qemu-fsdev.h"
23 #include "virtio-9p-xattr.h"
24 #include "virtio-9p-coth.h"
25 #include "trace.h"
26 #include "migration.h"
28 int open_fd_hw;
29 int total_open_fd;
30 static int open_fd_rc;
32 enum {
33 Oread = 0x00,
34 Owrite = 0x01,
35 Ordwr = 0x02,
36 Oexec = 0x03,
37 Oexcl = 0x04,
38 Otrunc = 0x10,
39 Orexec = 0x20,
40 Orclose = 0x40,
41 Oappend = 0x80,
44 static int omode_to_uflags(int8_t mode)
46 int ret = 0;
48 switch (mode & 3) {
49 case Oread:
50 ret = O_RDONLY;
51 break;
52 case Ordwr:
53 ret = O_RDWR;
54 break;
55 case Owrite:
56 ret = O_WRONLY;
57 break;
58 case Oexec:
59 ret = O_RDONLY;
60 break;
63 if (mode & Otrunc) {
64 ret |= O_TRUNC;
67 if (mode & Oappend) {
68 ret |= O_APPEND;
71 if (mode & Oexcl) {
72 ret |= O_EXCL;
75 return ret;
78 struct dotl_openflag_map {
79 int dotl_flag;
80 int open_flag;
83 static int dotl_to_open_flags(int flags)
85 int i;
87 * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
88 * and P9_DOTL_NOACCESS
90 int oflags = flags & O_ACCMODE;
92 struct dotl_openflag_map dotl_oflag_map[] = {
93 { P9_DOTL_CREATE, O_CREAT },
94 { P9_DOTL_EXCL, O_EXCL },
95 { P9_DOTL_NOCTTY , O_NOCTTY },
96 { P9_DOTL_TRUNC, O_TRUNC },
97 { P9_DOTL_APPEND, O_APPEND },
98 { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
99 { P9_DOTL_DSYNC, O_DSYNC },
100 { P9_DOTL_FASYNC, FASYNC },
101 { P9_DOTL_DIRECT, O_DIRECT },
102 { P9_DOTL_LARGEFILE, O_LARGEFILE },
103 { P9_DOTL_DIRECTORY, O_DIRECTORY },
104 { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
105 { P9_DOTL_NOATIME, O_NOATIME },
106 { P9_DOTL_SYNC, O_SYNC },
109 for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
110 if (flags & dotl_oflag_map[i].dotl_flag) {
111 oflags |= dotl_oflag_map[i].open_flag;
115 return oflags;
118 void cred_init(FsCred *credp)
120 credp->fc_uid = -1;
121 credp->fc_gid = -1;
122 credp->fc_mode = -1;
123 credp->fc_rdev = -1;
126 static int get_dotl_openflags(V9fsState *s, int oflags)
128 int flags;
130 * Filter the client open flags
132 flags = dotl_to_open_flags(oflags);
133 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
135 * Ignore direct disk access hint until the server supports it.
137 flags &= ~O_DIRECT;
138 return flags;
141 void v9fs_string_init(V9fsString *str)
143 str->data = NULL;
144 str->size = 0;
147 void v9fs_string_free(V9fsString *str)
149 g_free(str->data);
150 str->data = NULL;
151 str->size = 0;
154 void v9fs_string_null(V9fsString *str)
156 v9fs_string_free(str);
159 void GCC_FMT_ATTR(2, 3)
160 v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
162 va_list ap;
164 v9fs_string_free(str);
166 va_start(ap, fmt);
167 str->size = g_vasprintf(&str->data, fmt, ap);
168 va_end(ap);
171 void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
173 v9fs_string_free(lhs);
174 v9fs_string_sprintf(lhs, "%s", rhs->data);
177 void v9fs_path_init(V9fsPath *path)
179 path->data = NULL;
180 path->size = 0;
183 void v9fs_path_free(V9fsPath *path)
185 g_free(path->data);
186 path->data = NULL;
187 path->size = 0;
190 void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
192 v9fs_path_free(lhs);
193 lhs->data = g_malloc(rhs->size);
194 memcpy(lhs->data, rhs->data, rhs->size);
195 lhs->size = rhs->size;
198 int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
199 const char *name, V9fsPath *path)
201 int err;
202 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
203 if (err < 0) {
204 err = -errno;
206 return err;
210 * Return TRUE if s1 is an ancestor of s2.
212 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
213 * As a special case, We treat s1 as ancestor of s2 if they are same!
215 static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
217 if (!strncmp(s1->data, s2->data, s1->size - 1)) {
218 if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
219 return 1;
222 return 0;
225 static size_t v9fs_string_size(V9fsString *str)
227 return str->size;
231 * returns 0 if fid got re-opened, 1 if not, < 0 on error */
232 static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
234 int err = 1;
235 if (f->fid_type == P9_FID_FILE) {
236 if (f->fs.fd == -1) {
237 do {
238 err = v9fs_co_open(pdu, f, f->open_flags);
239 } while (err == -EINTR && !pdu->cancelled);
241 } else if (f->fid_type == P9_FID_DIR) {
242 if (f->fs.dir == NULL) {
243 do {
244 err = v9fs_co_opendir(pdu, f);
245 } while (err == -EINTR && !pdu->cancelled);
248 return err;
251 static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
253 int err;
254 V9fsFidState *f;
255 V9fsState *s = pdu->s;
257 for (f = s->fid_list; f; f = f->next) {
258 BUG_ON(f->clunked);
259 if (f->fid == fid) {
261 * Update the fid ref upfront so that
262 * we don't get reclaimed when we yield
263 * in open later.
265 f->ref++;
267 * check whether we need to reopen the
268 * file. We might have closed the fd
269 * while trying to free up some file
270 * descriptors.
272 err = v9fs_reopen_fid(pdu, f);
273 if (err < 0) {
274 f->ref--;
275 return NULL;
278 * Mark the fid as referenced so that the LRU
279 * reclaim won't close the file descriptor
281 f->flags |= FID_REFERENCED;
282 return f;
285 return NULL;
288 static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
290 V9fsFidState *f;
292 for (f = s->fid_list; f; f = f->next) {
293 /* If fid is already there return NULL */
294 BUG_ON(f->clunked);
295 if (f->fid == fid) {
296 return NULL;
299 f = g_malloc0(sizeof(V9fsFidState));
300 f->fid = fid;
301 f->fid_type = P9_FID_NONE;
302 f->ref = 1;
304 * Mark the fid as referenced so that the LRU
305 * reclaim won't close the file descriptor
307 f->flags |= FID_REFERENCED;
308 f->next = s->fid_list;
309 s->fid_list = f;
311 return f;
314 static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
316 int retval = 0;
318 if (fidp->fs.xattr.copied_len == -1) {
319 /* getxattr/listxattr fid */
320 goto free_value;
323 * if this is fid for setxattr. clunk should
324 * result in setxattr localcall
326 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
327 /* clunk after partial write */
328 retval = -EINVAL;
329 goto free_out;
331 if (fidp->fs.xattr.len) {
332 retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
333 fidp->fs.xattr.value,
334 fidp->fs.xattr.len,
335 fidp->fs.xattr.flags);
336 } else {
337 retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
339 free_out:
340 v9fs_string_free(&fidp->fs.xattr.name);
341 free_value:
342 if (fidp->fs.xattr.value) {
343 g_free(fidp->fs.xattr.value);
345 return retval;
348 static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
350 int retval = 0;
352 if (fidp->fid_type == P9_FID_FILE) {
353 /* If we reclaimed the fd no need to close */
354 if (fidp->fs.fd != -1) {
355 retval = v9fs_co_close(pdu, &fidp->fs);
357 } else if (fidp->fid_type == P9_FID_DIR) {
358 if (fidp->fs.dir != NULL) {
359 retval = v9fs_co_closedir(pdu, &fidp->fs);
361 } else if (fidp->fid_type == P9_FID_XATTR) {
362 retval = v9fs_xattr_fid_clunk(pdu, fidp);
364 v9fs_path_free(&fidp->path);
365 g_free(fidp);
366 return retval;
369 static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
371 BUG_ON(!fidp->ref);
372 fidp->ref--;
374 * Don't free the fid if it is in reclaim list
376 if (!fidp->ref && fidp->clunked) {
377 if (fidp->fid == pdu->s->root_fid) {
379 * if the clunked fid is root fid then we
380 * have unmounted the fs on the client side.
381 * delete the migration blocker. Ideally, this
382 * should be hooked to transport close notification
384 if (pdu->s->migration_blocker) {
385 migrate_del_blocker(pdu->s->migration_blocker);
386 error_free(pdu->s->migration_blocker);
387 pdu->s->migration_blocker = NULL;
390 free_fid(pdu, fidp);
394 static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
396 V9fsFidState **fidpp, *fidp;
398 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
399 if ((*fidpp)->fid == fid) {
400 break;
403 if (*fidpp == NULL) {
404 return NULL;
406 fidp = *fidpp;
407 *fidpp = fidp->next;
408 fidp->clunked = 1;
409 return fidp;
412 void v9fs_reclaim_fd(V9fsPDU *pdu)
414 int reclaim_count = 0;
415 V9fsState *s = pdu->s;
416 V9fsFidState *f, *reclaim_list = NULL;
418 for (f = s->fid_list; f; f = f->next) {
420 * Unlink fids cannot be reclaimed. Check
421 * for them and skip them. Also skip fids
422 * currently being operated on.
424 if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
425 continue;
428 * if it is a recently referenced fid
429 * we leave the fid untouched and clear the
430 * reference bit. We come back to it later
431 * in the next iteration. (a simple LRU without
432 * moving list elements around)
434 if (f->flags & FID_REFERENCED) {
435 f->flags &= ~FID_REFERENCED;
436 continue;
439 * Add fids to reclaim list.
441 if (f->fid_type == P9_FID_FILE) {
442 if (f->fs.fd != -1) {
444 * Up the reference count so that
445 * a clunk request won't free this fid
447 f->ref++;
448 f->rclm_lst = reclaim_list;
449 reclaim_list = f;
450 f->fs_reclaim.fd = f->fs.fd;
451 f->fs.fd = -1;
452 reclaim_count++;
454 } else if (f->fid_type == P9_FID_DIR) {
455 if (f->fs.dir != NULL) {
457 * Up the reference count so that
458 * a clunk request won't free this fid
460 f->ref++;
461 f->rclm_lst = reclaim_list;
462 reclaim_list = f;
463 f->fs_reclaim.dir = f->fs.dir;
464 f->fs.dir = NULL;
465 reclaim_count++;
468 if (reclaim_count >= open_fd_rc) {
469 break;
473 * Now close the fid in reclaim list. Free them if they
474 * are already clunked.
476 while (reclaim_list) {
477 f = reclaim_list;
478 reclaim_list = f->rclm_lst;
479 if (f->fid_type == P9_FID_FILE) {
480 v9fs_co_close(pdu, &f->fs_reclaim);
481 } else if (f->fid_type == P9_FID_DIR) {
482 v9fs_co_closedir(pdu, &f->fs_reclaim);
484 f->rclm_lst = NULL;
486 * Now drop the fid reference, free it
487 * if clunked.
489 put_fid(pdu, f);
493 static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
495 int err;
496 V9fsState *s = pdu->s;
497 V9fsFidState *fidp, head_fid;
499 head_fid.next = s->fid_list;
500 for (fidp = s->fid_list; fidp; fidp = fidp->next) {
501 if (fidp->path.size != path->size) {
502 continue;
504 if (!memcmp(fidp->path.data, path->data, path->size)) {
505 /* Mark the fid non reclaimable. */
506 fidp->flags |= FID_NON_RECLAIMABLE;
508 /* reopen the file/dir if already closed */
509 err = v9fs_reopen_fid(pdu, fidp);
510 if (err < 0) {
511 return -1;
514 * Go back to head of fid list because
515 * the list could have got updated when
516 * switched to the worker thread
518 if (err == 0) {
519 fidp = &head_fid;
523 return 0;
526 #define P9_QID_TYPE_DIR 0x80
527 #define P9_QID_TYPE_SYMLINK 0x02
529 #define P9_STAT_MODE_DIR 0x80000000
530 #define P9_STAT_MODE_APPEND 0x40000000
531 #define P9_STAT_MODE_EXCL 0x20000000
532 #define P9_STAT_MODE_MOUNT 0x10000000
533 #define P9_STAT_MODE_AUTH 0x08000000
534 #define P9_STAT_MODE_TMP 0x04000000
535 #define P9_STAT_MODE_SYMLINK 0x02000000
536 #define P9_STAT_MODE_LINK 0x01000000
537 #define P9_STAT_MODE_DEVICE 0x00800000
538 #define P9_STAT_MODE_NAMED_PIPE 0x00200000
539 #define P9_STAT_MODE_SOCKET 0x00100000
540 #define P9_STAT_MODE_SETUID 0x00080000
541 #define P9_STAT_MODE_SETGID 0x00040000
542 #define P9_STAT_MODE_SETVTX 0x00010000
544 #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
545 P9_STAT_MODE_SYMLINK | \
546 P9_STAT_MODE_LINK | \
547 P9_STAT_MODE_DEVICE | \
548 P9_STAT_MODE_NAMED_PIPE | \
549 P9_STAT_MODE_SOCKET)
551 /* This is the algorithm from ufs in spfs */
552 static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
554 size_t size;
556 memset(&qidp->path, 0, sizeof(qidp->path));
557 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
558 memcpy(&qidp->path, &stbuf->st_ino, size);
559 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
560 qidp->type = 0;
561 if (S_ISDIR(stbuf->st_mode)) {
562 qidp->type |= P9_QID_TYPE_DIR;
564 if (S_ISLNK(stbuf->st_mode)) {
565 qidp->type |= P9_QID_TYPE_SYMLINK;
569 static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
571 struct stat stbuf;
572 int err;
574 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
575 if (err < 0) {
576 return err;
578 stat_to_qid(&stbuf, qidp);
579 return 0;
582 static V9fsPDU *alloc_pdu(V9fsState *s)
584 V9fsPDU *pdu = NULL;
586 if (!QLIST_EMPTY(&s->free_list)) {
587 pdu = QLIST_FIRST(&s->free_list);
588 QLIST_REMOVE(pdu, next);
589 QLIST_INSERT_HEAD(&s->active_list, pdu, next);
591 return pdu;
594 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
596 if (pdu) {
598 * Cancelled pdu are added back to the freelist
599 * by flush request .
601 if (!pdu->cancelled) {
602 QLIST_REMOVE(pdu, next);
603 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
608 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
609 size_t offset, size_t size, int pack)
611 int i = 0;
612 size_t copied = 0;
614 for (i = 0; size && i < sg_count; i++) {
615 size_t len;
616 if (offset >= sg[i].iov_len) {
617 /* skip this sg */
618 offset -= sg[i].iov_len;
619 continue;
620 } else {
621 len = MIN(sg[i].iov_len - offset, size);
622 if (pack) {
623 memcpy(sg[i].iov_base + offset, addr, len);
624 } else {
625 memcpy(addr, sg[i].iov_base + offset, len);
627 size -= len;
628 copied += len;
629 addr += len;
630 if (size) {
631 offset = 0;
632 continue;
637 return copied;
640 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
642 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
643 offset, size, 0);
646 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
647 size_t size)
649 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
650 offset, size, 1);
653 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
655 size_t pos = 0;
656 int i, j;
657 struct iovec *src_sg;
658 unsigned int num;
660 if (rx) {
661 src_sg = pdu->elem.in_sg;
662 num = pdu->elem.in_num;
663 } else {
664 src_sg = pdu->elem.out_sg;
665 num = pdu->elem.out_num;
668 j = 0;
669 for (i = 0; i < num; i++) {
670 if (offset <= pos) {
671 sg[j].iov_base = src_sg[i].iov_base;
672 sg[j].iov_len = src_sg[i].iov_len;
673 j++;
674 } else if (offset < (src_sg[i].iov_len + pos)) {
675 sg[j].iov_base = src_sg[i].iov_base;
676 sg[j].iov_len = src_sg[i].iov_len;
677 sg[j].iov_base += (offset - pos);
678 sg[j].iov_len -= (offset - pos);
679 j++;
681 pos += src_sg[i].iov_len;
684 return j;
687 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
689 size_t old_offset = offset;
690 va_list ap;
691 int i;
693 va_start(ap, fmt);
694 for (i = 0; fmt[i]; i++) {
695 switch (fmt[i]) {
696 case 'b': {
697 uint8_t *valp = va_arg(ap, uint8_t *);
698 offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
699 break;
701 case 'w': {
702 uint16_t val, *valp;
703 valp = va_arg(ap, uint16_t *);
704 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
705 *valp = le16_to_cpu(val);
706 break;
708 case 'd': {
709 uint32_t val, *valp;
710 valp = va_arg(ap, uint32_t *);
711 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
712 *valp = le32_to_cpu(val);
713 break;
715 case 'q': {
716 uint64_t val, *valp;
717 valp = va_arg(ap, uint64_t *);
718 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
719 *valp = le64_to_cpu(val);
720 break;
722 case 'v': {
723 struct iovec *iov = va_arg(ap, struct iovec *);
724 int *iovcnt = va_arg(ap, int *);
725 *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
726 break;
728 case 's': {
729 V9fsString *str = va_arg(ap, V9fsString *);
730 offset += pdu_unmarshal(pdu, offset, "w", &str->size);
731 /* FIXME: sanity check str->size */
732 str->data = g_malloc(str->size + 1);
733 offset += pdu_unpack(str->data, pdu, offset, str->size);
734 str->data[str->size] = 0;
735 break;
737 case 'Q': {
738 V9fsQID *qidp = va_arg(ap, V9fsQID *);
739 offset += pdu_unmarshal(pdu, offset, "bdq",
740 &qidp->type, &qidp->version, &qidp->path);
741 break;
743 case 'S': {
744 V9fsStat *statp = va_arg(ap, V9fsStat *);
745 offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
746 &statp->size, &statp->type, &statp->dev,
747 &statp->qid, &statp->mode, &statp->atime,
748 &statp->mtime, &statp->length,
749 &statp->name, &statp->uid, &statp->gid,
750 &statp->muid, &statp->extension,
751 &statp->n_uid, &statp->n_gid,
752 &statp->n_muid);
753 break;
755 case 'I': {
756 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
757 offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
758 &iattr->valid, &iattr->mode,
759 &iattr->uid, &iattr->gid, &iattr->size,
760 &iattr->atime_sec, &iattr->atime_nsec,
761 &iattr->mtime_sec, &iattr->mtime_nsec);
762 break;
764 default:
765 break;
769 va_end(ap);
771 return offset - old_offset;
774 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
776 size_t old_offset = offset;
777 va_list ap;
778 int i;
780 va_start(ap, fmt);
781 for (i = 0; fmt[i]; i++) {
782 switch (fmt[i]) {
783 case 'b': {
784 uint8_t val = va_arg(ap, int);
785 offset += pdu_pack(pdu, offset, &val, sizeof(val));
786 break;
788 case 'w': {
789 uint16_t val;
790 cpu_to_le16w(&val, va_arg(ap, int));
791 offset += pdu_pack(pdu, offset, &val, sizeof(val));
792 break;
794 case 'd': {
795 uint32_t val;
796 cpu_to_le32w(&val, va_arg(ap, uint32_t));
797 offset += pdu_pack(pdu, offset, &val, sizeof(val));
798 break;
800 case 'q': {
801 uint64_t val;
802 cpu_to_le64w(&val, va_arg(ap, uint64_t));
803 offset += pdu_pack(pdu, offset, &val, sizeof(val));
804 break;
806 case 'v': {
807 struct iovec *iov = va_arg(ap, struct iovec *);
808 int *iovcnt = va_arg(ap, int *);
809 *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
810 break;
812 case 's': {
813 V9fsString *str = va_arg(ap, V9fsString *);
814 offset += pdu_marshal(pdu, offset, "w", str->size);
815 offset += pdu_pack(pdu, offset, str->data, str->size);
816 break;
818 case 'Q': {
819 V9fsQID *qidp = va_arg(ap, V9fsQID *);
820 offset += pdu_marshal(pdu, offset, "bdq",
821 qidp->type, qidp->version, qidp->path);
822 break;
824 case 'S': {
825 V9fsStat *statp = va_arg(ap, V9fsStat *);
826 offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
827 statp->size, statp->type, statp->dev,
828 &statp->qid, statp->mode, statp->atime,
829 statp->mtime, statp->length, &statp->name,
830 &statp->uid, &statp->gid, &statp->muid,
831 &statp->extension, statp->n_uid,
832 statp->n_gid, statp->n_muid);
833 break;
835 case 'A': {
836 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
837 offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
838 statp->st_result_mask,
839 &statp->qid, statp->st_mode,
840 statp->st_uid, statp->st_gid,
841 statp->st_nlink, statp->st_rdev,
842 statp->st_size, statp->st_blksize, statp->st_blocks,
843 statp->st_atime_sec, statp->st_atime_nsec,
844 statp->st_mtime_sec, statp->st_mtime_nsec,
845 statp->st_ctime_sec, statp->st_ctime_nsec,
846 statp->st_btime_sec, statp->st_btime_nsec,
847 statp->st_gen, statp->st_data_version);
848 break;
850 default:
851 break;
854 va_end(ap);
856 return offset - old_offset;
859 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
861 int8_t id = pdu->id + 1; /* Response */
863 if (len < 0) {
864 int err = -len;
865 len = 7;
867 if (s->proto_version != V9FS_PROTO_2000L) {
868 V9fsString str;
870 str.data = strerror(err);
871 str.size = strlen(str.data);
873 len += pdu_marshal(pdu, len, "s", &str);
874 id = P9_RERROR;
877 len += pdu_marshal(pdu, len, "d", err);
879 if (s->proto_version == V9FS_PROTO_2000L) {
880 id = P9_RLERROR;
882 trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
885 /* fill out the header */
886 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
888 /* keep these in sync */
889 pdu->size = len;
890 pdu->id = id;
892 /* push onto queue and notify */
893 virtqueue_push(s->vq, &pdu->elem, len);
895 /* FIXME: we should batch these completions */
896 virtio_notify(&s->vdev, s->vq);
898 /* Now wakeup anybody waiting in flush for this request */
899 qemu_co_queue_next(&pdu->complete);
901 free_pdu(s, pdu);
904 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
906 mode_t ret;
908 ret = mode & 0777;
909 if (mode & P9_STAT_MODE_DIR) {
910 ret |= S_IFDIR;
913 if (mode & P9_STAT_MODE_SYMLINK) {
914 ret |= S_IFLNK;
916 if (mode & P9_STAT_MODE_SOCKET) {
917 ret |= S_IFSOCK;
919 if (mode & P9_STAT_MODE_NAMED_PIPE) {
920 ret |= S_IFIFO;
922 if (mode & P9_STAT_MODE_DEVICE) {
923 if (extension && extension->data[0] == 'c') {
924 ret |= S_IFCHR;
925 } else {
926 ret |= S_IFBLK;
930 if (!(ret&~0777)) {
931 ret |= S_IFREG;
934 if (mode & P9_STAT_MODE_SETUID) {
935 ret |= S_ISUID;
937 if (mode & P9_STAT_MODE_SETGID) {
938 ret |= S_ISGID;
940 if (mode & P9_STAT_MODE_SETVTX) {
941 ret |= S_ISVTX;
944 return ret;
947 static int donttouch_stat(V9fsStat *stat)
949 if (stat->type == -1 &&
950 stat->dev == -1 &&
951 stat->qid.type == -1 &&
952 stat->qid.version == -1 &&
953 stat->qid.path == -1 &&
954 stat->mode == -1 &&
955 stat->atime == -1 &&
956 stat->mtime == -1 &&
957 stat->length == -1 &&
958 !stat->name.size &&
959 !stat->uid.size &&
960 !stat->gid.size &&
961 !stat->muid.size &&
962 stat->n_uid == -1 &&
963 stat->n_gid == -1 &&
964 stat->n_muid == -1) {
965 return 1;
968 return 0;
971 static void v9fs_stat_free(V9fsStat *stat)
973 v9fs_string_free(&stat->name);
974 v9fs_string_free(&stat->uid);
975 v9fs_string_free(&stat->gid);
976 v9fs_string_free(&stat->muid);
977 v9fs_string_free(&stat->extension);
980 static uint32_t stat_to_v9mode(const struct stat *stbuf)
982 uint32_t mode;
984 mode = stbuf->st_mode & 0777;
985 if (S_ISDIR(stbuf->st_mode)) {
986 mode |= P9_STAT_MODE_DIR;
989 if (S_ISLNK(stbuf->st_mode)) {
990 mode |= P9_STAT_MODE_SYMLINK;
993 if (S_ISSOCK(stbuf->st_mode)) {
994 mode |= P9_STAT_MODE_SOCKET;
997 if (S_ISFIFO(stbuf->st_mode)) {
998 mode |= P9_STAT_MODE_NAMED_PIPE;
1001 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
1002 mode |= P9_STAT_MODE_DEVICE;
1005 if (stbuf->st_mode & S_ISUID) {
1006 mode |= P9_STAT_MODE_SETUID;
1009 if (stbuf->st_mode & S_ISGID) {
1010 mode |= P9_STAT_MODE_SETGID;
1013 if (stbuf->st_mode & S_ISVTX) {
1014 mode |= P9_STAT_MODE_SETVTX;
1017 return mode;
1020 static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
1021 const struct stat *stbuf,
1022 V9fsStat *v9stat)
1024 int err;
1025 const char *str;
1027 memset(v9stat, 0, sizeof(*v9stat));
1029 stat_to_qid(stbuf, &v9stat->qid);
1030 v9stat->mode = stat_to_v9mode(stbuf);
1031 v9stat->atime = stbuf->st_atime;
1032 v9stat->mtime = stbuf->st_mtime;
1033 v9stat->length = stbuf->st_size;
1035 v9fs_string_null(&v9stat->uid);
1036 v9fs_string_null(&v9stat->gid);
1037 v9fs_string_null(&v9stat->muid);
1039 v9stat->n_uid = stbuf->st_uid;
1040 v9stat->n_gid = stbuf->st_gid;
1041 v9stat->n_muid = 0;
1043 v9fs_string_null(&v9stat->extension);
1045 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1046 err = v9fs_co_readlink(pdu, name, &v9stat->extension);
1047 if (err < 0) {
1048 return err;
1050 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1051 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1052 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1053 major(stbuf->st_rdev), minor(stbuf->st_rdev));
1054 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1055 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1056 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1059 str = strrchr(name->data, '/');
1060 if (str) {
1061 str += 1;
1062 } else {
1063 str = name->data;
1066 v9fs_string_sprintf(&v9stat->name, "%s", str);
1068 v9stat->size = 61 +
1069 v9fs_string_size(&v9stat->name) +
1070 v9fs_string_size(&v9stat->uid) +
1071 v9fs_string_size(&v9stat->gid) +
1072 v9fs_string_size(&v9stat->muid) +
1073 v9fs_string_size(&v9stat->extension);
1074 return 0;
1077 #define P9_STATS_MODE 0x00000001ULL
1078 #define P9_STATS_NLINK 0x00000002ULL
1079 #define P9_STATS_UID 0x00000004ULL
1080 #define P9_STATS_GID 0x00000008ULL
1081 #define P9_STATS_RDEV 0x00000010ULL
1082 #define P9_STATS_ATIME 0x00000020ULL
1083 #define P9_STATS_MTIME 0x00000040ULL
1084 #define P9_STATS_CTIME 0x00000080ULL
1085 #define P9_STATS_INO 0x00000100ULL
1086 #define P9_STATS_SIZE 0x00000200ULL
1087 #define P9_STATS_BLOCKS 0x00000400ULL
1089 #define P9_STATS_BTIME 0x00000800ULL
1090 #define P9_STATS_GEN 0x00001000ULL
1091 #define P9_STATS_DATA_VERSION 0x00002000ULL
1093 #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
1094 #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
1097 static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1098 V9fsStatDotl *v9lstat)
1100 memset(v9lstat, 0, sizeof(*v9lstat));
1102 v9lstat->st_mode = stbuf->st_mode;
1103 v9lstat->st_nlink = stbuf->st_nlink;
1104 v9lstat->st_uid = stbuf->st_uid;
1105 v9lstat->st_gid = stbuf->st_gid;
1106 v9lstat->st_rdev = stbuf->st_rdev;
1107 v9lstat->st_size = stbuf->st_size;
1108 v9lstat->st_blksize = stbuf->st_blksize;
1109 v9lstat->st_blocks = stbuf->st_blocks;
1110 v9lstat->st_atime_sec = stbuf->st_atime;
1111 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1112 v9lstat->st_mtime_sec = stbuf->st_mtime;
1113 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1114 v9lstat->st_ctime_sec = stbuf->st_ctime;
1115 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1116 /* Currently we only support BASIC fields in stat */
1117 v9lstat->st_result_mask = P9_STATS_BASIC;
1119 stat_to_qid(stbuf, &v9lstat->qid);
1122 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1124 while (len && *iovcnt) {
1125 if (len < sg->iov_len) {
1126 sg->iov_len -= len;
1127 sg->iov_base += len;
1128 len = 0;
1129 } else {
1130 len -= sg->iov_len;
1131 sg++;
1132 *iovcnt -= 1;
1136 return sg;
1139 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1141 int i;
1142 int total = 0;
1144 for (i = 0; i < *cnt; i++) {
1145 if ((total + sg[i].iov_len) > cap) {
1146 sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1147 i++;
1148 break;
1150 total += sg[i].iov_len;
1153 *cnt = i;
1155 return sg;
1158 static void print_sg(struct iovec *sg, int cnt)
1160 int i;
1162 printf("sg[%d]: {", cnt);
1163 for (i = 0; i < cnt; i++) {
1164 if (i) {
1165 printf(", ");
1167 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1169 printf("}\n");
1172 /* Will call this only for path name based fid */
1173 static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
1175 V9fsPath str;
1176 v9fs_path_init(&str);
1177 v9fs_path_copy(&str, dst);
1178 v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
1179 v9fs_path_free(&str);
1180 /* +1 to include terminating NULL */
1181 dst->size++;
1184 static inline bool is_ro_export(FsContext *ctx)
1186 return ctx->export_flags & V9FS_RDONLY;
1189 static void v9fs_version(void *opaque)
1191 V9fsPDU *pdu = opaque;
1192 V9fsState *s = pdu->s;
1193 V9fsString version;
1194 size_t offset = 7;
1196 pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1197 trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
1199 if (!strcmp(version.data, "9P2000.u")) {
1200 s->proto_version = V9FS_PROTO_2000U;
1201 } else if (!strcmp(version.data, "9P2000.L")) {
1202 s->proto_version = V9FS_PROTO_2000L;
1203 } else {
1204 v9fs_string_sprintf(&version, "unknown");
1207 offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1208 trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
1210 complete_pdu(s, pdu, offset);
1212 v9fs_string_free(&version);
1213 return;
1216 static void v9fs_attach(void *opaque)
1218 V9fsPDU *pdu = opaque;
1219 V9fsState *s = pdu->s;
1220 int32_t fid, afid, n_uname;
1221 V9fsString uname, aname;
1222 V9fsFidState *fidp;
1223 size_t offset = 7;
1224 V9fsQID qid;
1225 ssize_t err;
1227 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1228 trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
1230 fidp = alloc_fid(s, fid);
1231 if (fidp == NULL) {
1232 err = -EINVAL;
1233 goto out_nofid;
1235 fidp->uid = n_uname;
1236 err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
1237 if (err < 0) {
1238 err = -EINVAL;
1239 clunk_fid(s, fid);
1240 goto out;
1242 err = fid_to_qid(pdu, fidp, &qid);
1243 if (err < 0) {
1244 err = -EINVAL;
1245 clunk_fid(s, fid);
1246 goto out;
1248 offset += pdu_marshal(pdu, offset, "Q", &qid);
1249 err = offset;
1250 trace_v9fs_attach_return(pdu->tag, pdu->id,
1251 qid.type, qid.version, qid.path);
1252 s->root_fid = fid;
1253 /* disable migration */
1254 error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
1255 s->ctx.fs_root, s->tag);
1256 migrate_add_blocker(s->migration_blocker);
1257 out:
1258 put_fid(pdu, fidp);
1259 out_nofid:
1260 complete_pdu(s, pdu, err);
1261 v9fs_string_free(&uname);
1262 v9fs_string_free(&aname);
1265 static void v9fs_stat(void *opaque)
1267 int32_t fid;
1268 V9fsStat v9stat;
1269 ssize_t err = 0;
1270 size_t offset = 7;
1271 struct stat stbuf;
1272 V9fsFidState *fidp;
1273 V9fsPDU *pdu = opaque;
1274 V9fsState *s = pdu->s;
1276 pdu_unmarshal(pdu, offset, "d", &fid);
1277 trace_v9fs_stat(pdu->tag, pdu->id, fid);
1279 fidp = get_fid(pdu, fid);
1280 if (fidp == NULL) {
1281 err = -ENOENT;
1282 goto out_nofid;
1284 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1285 if (err < 0) {
1286 goto out;
1288 err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
1289 if (err < 0) {
1290 goto out;
1292 offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1293 err = offset;
1294 trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
1295 v9stat.atime, v9stat.mtime, v9stat.length);
1296 v9fs_stat_free(&v9stat);
1297 out:
1298 put_fid(pdu, fidp);
1299 out_nofid:
1300 complete_pdu(s, pdu, err);
1303 static void v9fs_getattr(void *opaque)
1305 int32_t fid;
1306 size_t offset = 7;
1307 ssize_t retval = 0;
1308 struct stat stbuf;
1309 V9fsFidState *fidp;
1310 uint64_t request_mask;
1311 V9fsStatDotl v9stat_dotl;
1312 V9fsPDU *pdu = opaque;
1313 V9fsState *s = pdu->s;
1315 pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1316 trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
1318 fidp = get_fid(pdu, fid);
1319 if (fidp == NULL) {
1320 retval = -ENOENT;
1321 goto out_nofid;
1324 * Currently we only support BASIC fields in stat, so there is no
1325 * need to look at request_mask.
1327 retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1328 if (retval < 0) {
1329 goto out;
1331 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1333 /* fill st_gen if requested and supported by underlying fs */
1334 if (request_mask & P9_STATS_GEN) {
1335 retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
1336 if (retval < 0) {
1337 goto out;
1339 v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1341 retval = offset;
1342 retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1343 trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1344 v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1345 v9stat_dotl.st_gid);
1346 out:
1347 put_fid(pdu, fidp);
1348 out_nofid:
1349 complete_pdu(s, pdu, retval);
1352 /* From Linux kernel code */
1353 #define ATTR_MODE (1 << 0)
1354 #define ATTR_UID (1 << 1)
1355 #define ATTR_GID (1 << 2)
1356 #define ATTR_SIZE (1 << 3)
1357 #define ATTR_ATIME (1 << 4)
1358 #define ATTR_MTIME (1 << 5)
1359 #define ATTR_CTIME (1 << 6)
1360 #define ATTR_MASK 127
1361 #define ATTR_ATIME_SET (1 << 7)
1362 #define ATTR_MTIME_SET (1 << 8)
1364 static void v9fs_setattr(void *opaque)
1366 int err = 0;
1367 int32_t fid;
1368 V9fsFidState *fidp;
1369 size_t offset = 7;
1370 V9fsIattr v9iattr;
1371 V9fsPDU *pdu = opaque;
1372 V9fsState *s = pdu->s;
1374 pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1376 fidp = get_fid(pdu, fid);
1377 if (fidp == NULL) {
1378 err = -EINVAL;
1379 goto out_nofid;
1381 if (v9iattr.valid & ATTR_MODE) {
1382 err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
1383 if (err < 0) {
1384 goto out;
1387 if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1388 struct timespec times[2];
1389 if (v9iattr.valid & ATTR_ATIME) {
1390 if (v9iattr.valid & ATTR_ATIME_SET) {
1391 times[0].tv_sec = v9iattr.atime_sec;
1392 times[0].tv_nsec = v9iattr.atime_nsec;
1393 } else {
1394 times[0].tv_nsec = UTIME_NOW;
1396 } else {
1397 times[0].tv_nsec = UTIME_OMIT;
1399 if (v9iattr.valid & ATTR_MTIME) {
1400 if (v9iattr.valid & ATTR_MTIME_SET) {
1401 times[1].tv_sec = v9iattr.mtime_sec;
1402 times[1].tv_nsec = v9iattr.mtime_nsec;
1403 } else {
1404 times[1].tv_nsec = UTIME_NOW;
1406 } else {
1407 times[1].tv_nsec = UTIME_OMIT;
1409 err = v9fs_co_utimensat(pdu, &fidp->path, times);
1410 if (err < 0) {
1411 goto out;
1415 * If the only valid entry in iattr is ctime we can call
1416 * chown(-1,-1) to update the ctime of the file
1418 if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1419 ((v9iattr.valid & ATTR_CTIME)
1420 && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1421 if (!(v9iattr.valid & ATTR_UID)) {
1422 v9iattr.uid = -1;
1424 if (!(v9iattr.valid & ATTR_GID)) {
1425 v9iattr.gid = -1;
1427 err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
1428 v9iattr.gid);
1429 if (err < 0) {
1430 goto out;
1433 if (v9iattr.valid & (ATTR_SIZE)) {
1434 err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
1435 if (err < 0) {
1436 goto out;
1439 err = offset;
1440 out:
1441 put_fid(pdu, fidp);
1442 out_nofid:
1443 complete_pdu(s, pdu, err);
1446 static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1448 int i;
1449 size_t offset = 7;
1450 offset += pdu_marshal(pdu, offset, "w", nwnames);
1451 for (i = 0; i < nwnames; i++) {
1452 offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
1454 return offset;
1457 static void v9fs_walk(void *opaque)
1459 int name_idx;
1460 V9fsQID *qids = NULL;
1461 int i, err = 0;
1462 V9fsPath dpath, path;
1463 uint16_t nwnames;
1464 struct stat stbuf;
1465 size_t offset = 7;
1466 int32_t fid, newfid;
1467 V9fsString *wnames = NULL;
1468 V9fsFidState *fidp;
1469 V9fsFidState *newfidp = NULL;;
1470 V9fsPDU *pdu = opaque;
1471 V9fsState *s = pdu->s;
1473 offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
1474 &newfid, &nwnames);
1476 trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1478 if (nwnames && nwnames <= P9_MAXWELEM) {
1479 wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1480 qids = g_malloc0(sizeof(qids[0]) * nwnames);
1481 for (i = 0; i < nwnames; i++) {
1482 offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1484 } else if (nwnames > P9_MAXWELEM) {
1485 err = -EINVAL;
1486 goto out_nofid;
1488 fidp = get_fid(pdu, fid);
1489 if (fidp == NULL) {
1490 err = -ENOENT;
1491 goto out_nofid;
1493 v9fs_path_init(&dpath);
1494 v9fs_path_init(&path);
1496 * Both dpath and path initially poin to fidp.
1497 * Needed to handle request with nwnames == 0
1499 v9fs_path_copy(&dpath, &fidp->path);
1500 v9fs_path_copy(&path, &fidp->path);
1501 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1502 err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
1503 if (err < 0) {
1504 goto out;
1506 err = v9fs_co_lstat(pdu, &path, &stbuf);
1507 if (err < 0) {
1508 goto out;
1510 stat_to_qid(&stbuf, &qids[name_idx]);
1511 v9fs_path_copy(&dpath, &path);
1513 if (fid == newfid) {
1514 BUG_ON(fidp->fid_type != P9_FID_NONE);
1515 v9fs_path_copy(&fidp->path, &path);
1516 } else {
1517 newfidp = alloc_fid(s, newfid);
1518 if (newfidp == NULL) {
1519 err = -EINVAL;
1520 goto out;
1522 newfidp->uid = fidp->uid;
1523 v9fs_path_copy(&newfidp->path, &path);
1525 err = v9fs_walk_marshal(pdu, nwnames, qids);
1526 trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
1527 out:
1528 put_fid(pdu, fidp);
1529 if (newfidp) {
1530 put_fid(pdu, newfidp);
1532 v9fs_path_free(&dpath);
1533 v9fs_path_free(&path);
1534 out_nofid:
1535 complete_pdu(s, pdu, err);
1536 if (nwnames && nwnames <= P9_MAXWELEM) {
1537 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1538 v9fs_string_free(&wnames[name_idx]);
1540 g_free(wnames);
1541 g_free(qids);
1543 return;
1546 static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
1548 struct statfs stbuf;
1549 int32_t iounit = 0;
1550 V9fsState *s = pdu->s;
1553 * iounit should be multiples of f_bsize (host filesystem block size
1554 * and as well as less than (client msize - P9_IOHDRSZ))
1556 if (!v9fs_co_statfs(pdu, path, &stbuf)) {
1557 iounit = stbuf.f_bsize;
1558 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1560 if (!iounit) {
1561 iounit = s->msize - P9_IOHDRSZ;
1563 return iounit;
1566 static void v9fs_open(void *opaque)
1568 int flags;
1569 int32_t fid;
1570 int32_t mode;
1571 V9fsQID qid;
1572 int iounit = 0;
1573 ssize_t err = 0;
1574 size_t offset = 7;
1575 struct stat stbuf;
1576 V9fsFidState *fidp;
1577 V9fsPDU *pdu = opaque;
1578 V9fsState *s = pdu->s;
1580 if (s->proto_version == V9FS_PROTO_2000L) {
1581 pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1582 } else {
1583 pdu_unmarshal(pdu, offset, "db", &fid, &mode);
1585 trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1587 fidp = get_fid(pdu, fid);
1588 if (fidp == NULL) {
1589 err = -ENOENT;
1590 goto out_nofid;
1592 BUG_ON(fidp->fid_type != P9_FID_NONE);
1594 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1595 if (err < 0) {
1596 goto out;
1598 stat_to_qid(&stbuf, &qid);
1599 if (S_ISDIR(stbuf.st_mode)) {
1600 err = v9fs_co_opendir(pdu, fidp);
1601 if (err < 0) {
1602 goto out;
1604 fidp->fid_type = P9_FID_DIR;
1605 offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
1606 err = offset;
1607 } else {
1608 if (s->proto_version == V9FS_PROTO_2000L) {
1609 flags = get_dotl_openflags(s, mode);
1610 } else {
1611 flags = omode_to_uflags(mode);
1613 if (is_ro_export(&s->ctx)) {
1614 if (mode & O_WRONLY || mode & O_RDWR ||
1615 mode & O_APPEND || mode & O_TRUNC) {
1616 err = -EROFS;
1617 goto out;
1619 flags |= O_NOATIME;
1621 err = v9fs_co_open(pdu, fidp, flags);
1622 if (err < 0) {
1623 goto out;
1625 fidp->fid_type = P9_FID_FILE;
1626 fidp->open_flags = flags;
1627 if (flags & O_EXCL) {
1629 * We let the host file system do O_EXCL check
1630 * We should not reclaim such fd
1632 fidp->flags |= FID_NON_RECLAIMABLE;
1634 iounit = get_iounit(pdu, &fidp->path);
1635 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1636 err = offset;
1638 trace_v9fs_open_return(pdu->tag, pdu->id,
1639 qid.type, qid.version, qid.path, iounit);
1640 out:
1641 put_fid(pdu, fidp);
1642 out_nofid:
1643 complete_pdu(s, pdu, err);
1646 static void v9fs_lcreate(void *opaque)
1648 int32_t dfid, flags, mode;
1649 gid_t gid;
1650 ssize_t err = 0;
1651 ssize_t offset = 7;
1652 V9fsString name;
1653 V9fsFidState *fidp;
1654 struct stat stbuf;
1655 V9fsQID qid;
1656 int32_t iounit;
1657 V9fsPDU *pdu = opaque;
1659 pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
1660 &mode, &gid);
1661 trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
1663 fidp = get_fid(pdu, dfid);
1664 if (fidp == NULL) {
1665 err = -ENOENT;
1666 goto out_nofid;
1669 flags = get_dotl_openflags(pdu->s, flags);
1670 err = v9fs_co_open2(pdu, fidp, &name, gid,
1671 flags | O_CREAT, mode, &stbuf);
1672 if (err < 0) {
1673 goto out;
1675 fidp->fid_type = P9_FID_FILE;
1676 fidp->open_flags = flags;
1677 if (flags & O_EXCL) {
1679 * We let the host file system do O_EXCL check
1680 * We should not reclaim such fd
1682 fidp->flags |= FID_NON_RECLAIMABLE;
1684 iounit = get_iounit(pdu, &fidp->path);
1685 stat_to_qid(&stbuf, &qid);
1686 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1687 err = offset;
1688 trace_v9fs_lcreate_return(pdu->tag, pdu->id,
1689 qid.type, qid.version, qid.path, iounit);
1690 out:
1691 put_fid(pdu, fidp);
1692 out_nofid:
1693 complete_pdu(pdu->s, pdu, err);
1694 v9fs_string_free(&name);
1697 static void v9fs_fsync(void *opaque)
1699 int err;
1700 int32_t fid;
1701 int datasync;
1702 size_t offset = 7;
1703 V9fsFidState *fidp;
1704 V9fsPDU *pdu = opaque;
1705 V9fsState *s = pdu->s;
1707 pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1708 trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
1710 fidp = get_fid(pdu, fid);
1711 if (fidp == NULL) {
1712 err = -ENOENT;
1713 goto out_nofid;
1715 err = v9fs_co_fsync(pdu, fidp, datasync);
1716 if (!err) {
1717 err = offset;
1719 put_fid(pdu, fidp);
1720 out_nofid:
1721 complete_pdu(s, pdu, err);
1724 static void v9fs_clunk(void *opaque)
1726 int err;
1727 int32_t fid;
1728 size_t offset = 7;
1729 V9fsFidState *fidp;
1730 V9fsPDU *pdu = opaque;
1731 V9fsState *s = pdu->s;
1733 pdu_unmarshal(pdu, offset, "d", &fid);
1734 trace_v9fs_clunk(pdu->tag, pdu->id, fid);
1736 fidp = clunk_fid(s, fid);
1737 if (fidp == NULL) {
1738 err = -ENOENT;
1739 goto out_nofid;
1742 * Bump the ref so that put_fid will
1743 * free the fid.
1745 fidp->ref++;
1746 err = offset;
1748 put_fid(pdu, fidp);
1749 out_nofid:
1750 complete_pdu(s, pdu, err);
1753 static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
1754 V9fsFidState *fidp, int64_t off, int32_t max_count)
1756 size_t offset = 7;
1757 int read_count;
1758 int64_t xattr_len;
1760 xattr_len = fidp->fs.xattr.len;
1761 read_count = xattr_len - off;
1762 if (read_count > max_count) {
1763 read_count = max_count;
1764 } else if (read_count < 0) {
1766 * read beyond XATTR value
1768 read_count = 0;
1770 offset += pdu_marshal(pdu, offset, "d", read_count);
1771 offset += pdu_pack(pdu, offset,
1772 ((char *)fidp->fs.xattr.value) + off,
1773 read_count);
1774 return offset;
1777 static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
1778 V9fsFidState *fidp, int32_t max_count)
1780 V9fsPath path;
1781 V9fsStat v9stat;
1782 int len, err = 0;
1783 int32_t count = 0;
1784 struct stat stbuf;
1785 off_t saved_dir_pos;
1786 struct dirent *dent, *result;
1788 /* save the directory position */
1789 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1790 if (saved_dir_pos < 0) {
1791 return saved_dir_pos;
1794 dent = g_malloc(sizeof(struct dirent));
1796 while (1) {
1797 v9fs_path_init(&path);
1798 err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
1799 if (err || !result) {
1800 break;
1802 err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
1803 if (err < 0) {
1804 goto out;
1806 err = v9fs_co_lstat(pdu, &path, &stbuf);
1807 if (err < 0) {
1808 goto out;
1810 err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
1811 if (err < 0) {
1812 goto out;
1814 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1815 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1816 if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1817 /* Ran out of buffer. Set dir back to old position and return */
1818 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1819 v9fs_stat_free(&v9stat);
1820 v9fs_path_free(&path);
1821 g_free(dent);
1822 return count;
1824 count += len;
1825 v9fs_stat_free(&v9stat);
1826 v9fs_path_free(&path);
1827 saved_dir_pos = dent->d_off;
1829 out:
1830 g_free(dent);
1831 v9fs_path_free(&path);
1832 if (err < 0) {
1833 return err;
1835 return count;
1838 static void v9fs_read(void *opaque)
1840 int32_t fid;
1841 int64_t off;
1842 ssize_t err = 0;
1843 int32_t count = 0;
1844 size_t offset = 7;
1845 int32_t max_count;
1846 V9fsFidState *fidp;
1847 V9fsPDU *pdu = opaque;
1848 V9fsState *s = pdu->s;
1850 pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1851 trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
1853 fidp = get_fid(pdu, fid);
1854 if (fidp == NULL) {
1855 err = -EINVAL;
1856 goto out_nofid;
1858 if (fidp->fid_type == P9_FID_DIR) {
1860 if (off == 0) {
1861 v9fs_co_rewinddir(pdu, fidp);
1863 count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
1864 if (count < 0) {
1865 err = count;
1866 goto out;
1868 err = offset;
1869 err += pdu_marshal(pdu, offset, "d", count);
1870 err += count;
1871 } else if (fidp->fid_type == P9_FID_FILE) {
1872 int32_t cnt;
1873 int32_t len;
1874 struct iovec *sg;
1875 struct iovec iov[128]; /* FIXME: bad, bad, bad */
1877 sg = iov;
1878 pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
1879 sg = cap_sg(sg, max_count, &cnt);
1880 do {
1881 if (0) {
1882 print_sg(sg, cnt);
1884 /* Loop in case of EINTR */
1885 do {
1886 len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
1887 if (len >= 0) {
1888 off += len;
1889 count += len;
1891 } while (len == -EINTR && !pdu->cancelled);
1892 if (len < 0) {
1893 /* IO error return the error */
1894 err = len;
1895 goto out;
1897 sg = adjust_sg(sg, len, &cnt);
1898 } while (count < max_count && len > 0);
1899 err = offset;
1900 err += pdu_marshal(pdu, offset, "d", count);
1901 err += count;
1902 } else if (fidp->fid_type == P9_FID_XATTR) {
1903 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1904 } else {
1905 err = -EINVAL;
1907 trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
1908 out:
1909 put_fid(pdu, fidp);
1910 out_nofid:
1911 complete_pdu(s, pdu, err);
1914 static size_t v9fs_readdir_data_size(V9fsString *name)
1917 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1918 * size of type (1) + size of name.size (2) + strlen(name.data)
1920 return 24 + v9fs_string_size(name);
1923 static int v9fs_do_readdir(V9fsPDU *pdu,
1924 V9fsFidState *fidp, int32_t max_count)
1926 size_t size;
1927 V9fsQID qid;
1928 V9fsString name;
1929 int len, err = 0;
1930 int32_t count = 0;
1931 off_t saved_dir_pos;
1932 struct dirent *dent, *result;
1934 /* save the directory position */
1935 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1936 if (saved_dir_pos < 0) {
1937 return saved_dir_pos;
1940 dent = g_malloc(sizeof(struct dirent));
1942 while (1) {
1943 err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
1944 if (err || !result) {
1945 break;
1947 v9fs_string_init(&name);
1948 v9fs_string_sprintf(&name, "%s", dent->d_name);
1949 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1950 /* Ran out of buffer. Set dir back to old position and return */
1951 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1952 v9fs_string_free(&name);
1953 g_free(dent);
1954 return count;
1957 * Fill up just the path field of qid because the client uses
1958 * only that. To fill the entire qid structure we will have
1959 * to stat each dirent found, which is expensive
1961 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1962 memcpy(&qid.path, &dent->d_ino, size);
1963 /* Fill the other fields with dummy values */
1964 qid.type = 0;
1965 qid.version = 0;
1967 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1968 len = pdu_marshal(pdu, 11 + count, "Qqbs",
1969 &qid, dent->d_off,
1970 dent->d_type, &name);
1971 count += len;
1972 v9fs_string_free(&name);
1973 saved_dir_pos = dent->d_off;
1975 g_free(dent);
1976 if (err < 0) {
1977 return err;
1979 return count;
1982 static void v9fs_readdir(void *opaque)
1984 int32_t fid;
1985 V9fsFidState *fidp;
1986 ssize_t retval = 0;
1987 size_t offset = 7;
1988 int64_t initial_offset;
1989 int32_t count, max_count;
1990 V9fsPDU *pdu = opaque;
1991 V9fsState *s = pdu->s;
1993 pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
1995 trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
1997 fidp = get_fid(pdu, fid);
1998 if (fidp == NULL) {
1999 retval = -EINVAL;
2000 goto out_nofid;
2002 if (!fidp->fs.dir) {
2003 retval = -EINVAL;
2004 goto out;
2006 if (initial_offset == 0) {
2007 v9fs_co_rewinddir(pdu, fidp);
2008 } else {
2009 v9fs_co_seekdir(pdu, fidp, initial_offset);
2011 count = v9fs_do_readdir(pdu, fidp, max_count);
2012 if (count < 0) {
2013 retval = count;
2014 goto out;
2016 retval = offset;
2017 retval += pdu_marshal(pdu, offset, "d", count);
2018 retval += count;
2019 trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
2020 out:
2021 put_fid(pdu, fidp);
2022 out_nofid:
2023 complete_pdu(s, pdu, retval);
2026 static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
2027 int64_t off, int32_t count,
2028 struct iovec *sg, int cnt)
2030 int i, to_copy;
2031 ssize_t err = 0;
2032 int write_count;
2033 int64_t xattr_len;
2034 size_t offset = 7;
2037 xattr_len = fidp->fs.xattr.len;
2038 write_count = xattr_len - off;
2039 if (write_count > count) {
2040 write_count = count;
2041 } else if (write_count < 0) {
2043 * write beyond XATTR value len specified in
2044 * xattrcreate
2046 err = -ENOSPC;
2047 goto out;
2049 offset += pdu_marshal(pdu, offset, "d", write_count);
2050 err = offset;
2051 fidp->fs.xattr.copied_len += write_count;
2053 * Now copy the content from sg list
2055 for (i = 0; i < cnt; i++) {
2056 if (write_count > sg[i].iov_len) {
2057 to_copy = sg[i].iov_len;
2058 } else {
2059 to_copy = write_count;
2061 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
2062 /* updating vs->off since we are not using below */
2063 off += to_copy;
2064 write_count -= to_copy;
2066 out:
2067 return err;
2070 static void v9fs_write(void *opaque)
2072 int cnt;
2073 ssize_t err;
2074 int32_t fid;
2075 int64_t off;
2076 int32_t count;
2077 int32_t len = 0;
2078 int32_t total = 0;
2079 size_t offset = 7;
2080 V9fsFidState *fidp;
2081 struct iovec iov[128]; /* FIXME: bad, bad, bad */
2082 struct iovec *sg = iov;
2083 V9fsPDU *pdu = opaque;
2084 V9fsState *s = pdu->s;
2086 pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
2087 trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt);
2089 fidp = get_fid(pdu, fid);
2090 if (fidp == NULL) {
2091 err = -EINVAL;
2092 goto out_nofid;
2094 if (fidp->fid_type == P9_FID_FILE) {
2095 if (fidp->fs.fd == -1) {
2096 err = -EINVAL;
2097 goto out;
2099 } else if (fidp->fid_type == P9_FID_XATTR) {
2101 * setxattr operation
2103 err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
2104 goto out;
2105 } else {
2106 err = -EINVAL;
2107 goto out;
2109 sg = cap_sg(sg, count, &cnt);
2110 do {
2111 if (0) {
2112 print_sg(sg, cnt);
2114 /* Loop in case of EINTR */
2115 do {
2116 len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
2117 if (len >= 0) {
2118 off += len;
2119 total += len;
2121 } while (len == -EINTR && !pdu->cancelled);
2122 if (len < 0) {
2123 /* IO error return the error */
2124 err = len;
2125 goto out;
2127 sg = adjust_sg(sg, len, &cnt);
2128 } while (total < count && len > 0);
2129 offset += pdu_marshal(pdu, offset, "d", total);
2130 err = offset;
2131 trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
2132 out:
2133 put_fid(pdu, fidp);
2134 out_nofid:
2135 complete_pdu(s, pdu, err);
2138 static void v9fs_create(void *opaque)
2140 int32_t fid;
2141 int err = 0;
2142 size_t offset = 7;
2143 V9fsFidState *fidp;
2144 V9fsQID qid;
2145 int32_t perm;
2146 int8_t mode;
2147 V9fsPath path;
2148 struct stat stbuf;
2149 V9fsString name;
2150 V9fsString extension;
2151 int iounit;
2152 V9fsPDU *pdu = opaque;
2154 v9fs_path_init(&path);
2156 pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2157 &perm, &mode, &extension);
2159 trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2161 fidp = get_fid(pdu, fid);
2162 if (fidp == NULL) {
2163 err = -EINVAL;
2164 goto out_nofid;
2166 if (perm & P9_STAT_MODE_DIR) {
2167 err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
2168 fidp->uid, -1, &stbuf);
2169 if (err < 0) {
2170 goto out;
2172 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2173 if (err < 0) {
2174 goto out;
2176 v9fs_path_copy(&fidp->path, &path);
2177 err = v9fs_co_opendir(pdu, fidp);
2178 if (err < 0) {
2179 goto out;
2181 fidp->fid_type = P9_FID_DIR;
2182 } else if (perm & P9_STAT_MODE_SYMLINK) {
2183 err = v9fs_co_symlink(pdu, fidp, &name,
2184 extension.data, -1 , &stbuf);
2185 if (err < 0) {
2186 goto out;
2188 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2189 if (err < 0) {
2190 goto out;
2192 v9fs_path_copy(&fidp->path, &path);
2193 } else if (perm & P9_STAT_MODE_LINK) {
2194 int32_t ofid = atoi(extension.data);
2195 V9fsFidState *ofidp = get_fid(pdu, ofid);
2196 if (ofidp == NULL) {
2197 err = -EINVAL;
2198 goto out;
2200 err = v9fs_co_link(pdu, ofidp, fidp, &name);
2201 put_fid(pdu, ofidp);
2202 if (err < 0) {
2203 goto out;
2205 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2206 if (err < 0) {
2207 fidp->fid_type = P9_FID_NONE;
2208 goto out;
2210 v9fs_path_copy(&fidp->path, &path);
2211 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2212 if (err < 0) {
2213 fidp->fid_type = P9_FID_NONE;
2214 goto out;
2216 } else if (perm & P9_STAT_MODE_DEVICE) {
2217 char ctype;
2218 uint32_t major, minor;
2219 mode_t nmode = 0;
2221 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2222 err = -errno;
2223 goto out;
2226 switch (ctype) {
2227 case 'c':
2228 nmode = S_IFCHR;
2229 break;
2230 case 'b':
2231 nmode = S_IFBLK;
2232 break;
2233 default:
2234 err = -EIO;
2235 goto out;
2238 nmode |= perm & 0777;
2239 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2240 makedev(major, minor), nmode, &stbuf);
2241 if (err < 0) {
2242 goto out;
2244 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2245 if (err < 0) {
2246 goto out;
2248 v9fs_path_copy(&fidp->path, &path);
2249 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2250 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2251 0, S_IFIFO | (perm & 0777), &stbuf);
2252 if (err < 0) {
2253 goto out;
2255 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2256 if (err < 0) {
2257 goto out;
2259 v9fs_path_copy(&fidp->path, &path);
2260 } else if (perm & P9_STAT_MODE_SOCKET) {
2261 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2262 0, S_IFSOCK | (perm & 0777), &stbuf);
2263 if (err < 0) {
2264 goto out;
2266 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2267 if (err < 0) {
2268 goto out;
2270 v9fs_path_copy(&fidp->path, &path);
2271 } else {
2272 err = v9fs_co_open2(pdu, fidp, &name, -1,
2273 omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
2274 if (err < 0) {
2275 goto out;
2277 fidp->fid_type = P9_FID_FILE;
2278 fidp->open_flags = omode_to_uflags(mode);
2279 if (fidp->open_flags & O_EXCL) {
2281 * We let the host file system do O_EXCL check
2282 * We should not reclaim such fd
2284 fidp->flags |= FID_NON_RECLAIMABLE;
2287 iounit = get_iounit(pdu, &fidp->path);
2288 stat_to_qid(&stbuf, &qid);
2289 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2290 err = offset;
2291 trace_v9fs_create_return(pdu->tag, pdu->id,
2292 qid.type, qid.version, qid.path, iounit);
2293 out:
2294 put_fid(pdu, fidp);
2295 out_nofid:
2296 complete_pdu(pdu->s, pdu, err);
2297 v9fs_string_free(&name);
2298 v9fs_string_free(&extension);
2299 v9fs_path_free(&path);
2302 static void v9fs_symlink(void *opaque)
2304 V9fsPDU *pdu = opaque;
2305 V9fsString name;
2306 V9fsString symname;
2307 V9fsFidState *dfidp;
2308 V9fsQID qid;
2309 struct stat stbuf;
2310 int32_t dfid;
2311 int err = 0;
2312 gid_t gid;
2313 size_t offset = 7;
2315 pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2316 trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
2318 dfidp = get_fid(pdu, dfid);
2319 if (dfidp == NULL) {
2320 err = -EINVAL;
2321 goto out_nofid;
2323 err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
2324 if (err < 0) {
2325 goto out;
2327 stat_to_qid(&stbuf, &qid);
2328 offset += pdu_marshal(pdu, offset, "Q", &qid);
2329 err = offset;
2330 trace_v9fs_symlink_return(pdu->tag, pdu->id,
2331 qid.type, qid.version, qid.path);
2332 out:
2333 put_fid(pdu, dfidp);
2334 out_nofid:
2335 complete_pdu(pdu->s, pdu, err);
2336 v9fs_string_free(&name);
2337 v9fs_string_free(&symname);
2340 static void v9fs_flush(void *opaque)
2342 int16_t tag;
2343 size_t offset = 7;
2344 V9fsPDU *cancel_pdu;
2345 V9fsPDU *pdu = opaque;
2346 V9fsState *s = pdu->s;
2348 pdu_unmarshal(pdu, offset, "w", &tag);
2349 trace_v9fs_flush(pdu->tag, pdu->id, tag);
2351 QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2352 if (cancel_pdu->tag == tag) {
2353 break;
2356 if (cancel_pdu) {
2357 cancel_pdu->cancelled = 1;
2359 * Wait for pdu to complete.
2361 qemu_co_queue_wait(&cancel_pdu->complete);
2362 cancel_pdu->cancelled = 0;
2363 free_pdu(pdu->s, cancel_pdu);
2365 complete_pdu(s, pdu, 7);
2366 return;
2369 static void v9fs_link(void *opaque)
2371 V9fsPDU *pdu = opaque;
2372 V9fsState *s = pdu->s;
2373 int32_t dfid, oldfid;
2374 V9fsFidState *dfidp, *oldfidp;
2375 V9fsString name;;
2376 size_t offset = 7;
2377 int err = 0;
2379 pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2380 trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
2382 dfidp = get_fid(pdu, dfid);
2383 if (dfidp == NULL) {
2384 err = -ENOENT;
2385 goto out_nofid;
2388 oldfidp = get_fid(pdu, oldfid);
2389 if (oldfidp == NULL) {
2390 err = -ENOENT;
2391 goto out;
2393 err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
2394 if (!err) {
2395 err = offset;
2397 out:
2398 put_fid(pdu, dfidp);
2399 out_nofid:
2400 v9fs_string_free(&name);
2401 complete_pdu(s, pdu, err);
2404 /* Only works with path name based fid */
2405 static void v9fs_remove(void *opaque)
2407 int32_t fid;
2408 int err = 0;
2409 size_t offset = 7;
2410 V9fsFidState *fidp;
2411 V9fsPDU *pdu = opaque;
2413 pdu_unmarshal(pdu, offset, "d", &fid);
2414 trace_v9fs_remove(pdu->tag, pdu->id, fid);
2416 fidp = get_fid(pdu, fid);
2417 if (fidp == NULL) {
2418 err = -EINVAL;
2419 goto out_nofid;
2421 /* if fs driver is not path based, return EOPNOTSUPP */
2422 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2423 err = -EOPNOTSUPP;
2424 goto out_err;
2427 * IF the file is unlinked, we cannot reopen
2428 * the file later. So don't reclaim fd
2430 err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
2431 if (err < 0) {
2432 goto out_err;
2434 err = v9fs_co_remove(pdu, &fidp->path);
2435 if (!err) {
2436 err = offset;
2438 out_err:
2439 /* For TREMOVE we need to clunk the fid even on failed remove */
2440 clunk_fid(pdu->s, fidp->fid);
2441 put_fid(pdu, fidp);
2442 out_nofid:
2443 complete_pdu(pdu->s, pdu, err);
2446 static void v9fs_unlinkat(void *opaque)
2448 int err = 0;
2449 V9fsString name;
2450 int32_t dfid, flags;
2451 size_t offset = 7;
2452 V9fsPath path;
2453 V9fsFidState *dfidp;
2454 V9fsPDU *pdu = opaque;
2456 pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2458 dfidp = get_fid(pdu, dfid);
2459 if (dfidp == NULL) {
2460 err = -EINVAL;
2461 goto out_nofid;
2464 * IF the file is unlinked, we cannot reopen
2465 * the file later. So don't reclaim fd
2467 v9fs_path_init(&path);
2468 err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
2469 if (err < 0) {
2470 goto out_err;
2472 err = v9fs_mark_fids_unreclaim(pdu, &path);
2473 if (err < 0) {
2474 goto out_err;
2476 err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
2477 if (!err) {
2478 err = offset;
2480 out_err:
2481 put_fid(pdu, dfidp);
2482 v9fs_path_free(&path);
2483 out_nofid:
2484 complete_pdu(pdu->s, pdu, err);
2485 v9fs_string_free(&name);
2489 /* Only works with path name based fid */
2490 static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
2491 int32_t newdirfid, V9fsString *name)
2493 char *end;
2494 int err = 0;
2495 V9fsPath new_path;
2496 V9fsFidState *tfidp;
2497 V9fsState *s = pdu->s;
2498 V9fsFidState *dirfidp = NULL;
2499 char *old_name, *new_name;
2501 v9fs_path_init(&new_path);
2502 if (newdirfid != -1) {
2503 dirfidp = get_fid(pdu, newdirfid);
2504 if (dirfidp == NULL) {
2505 err = -ENOENT;
2506 goto out_nofid;
2508 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2509 v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
2510 } else {
2511 old_name = fidp->path.data;
2512 end = strrchr(old_name, '/');
2513 if (end) {
2514 end++;
2515 } else {
2516 end = old_name;
2518 new_name = g_malloc0(end - old_name + name->size + 1);
2519 strncat(new_name, old_name, end - old_name);
2520 strncat(new_name + (end - old_name), name->data, name->size);
2521 v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
2522 g_free(new_name);
2524 err = v9fs_co_rename(pdu, &fidp->path, &new_path);
2525 if (err < 0) {
2526 goto out;
2529 * Fixup fid's pointing to the old name to
2530 * start pointing to the new name
2532 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2533 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2534 /* replace the name */
2535 v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
2538 out:
2539 if (dirfidp) {
2540 put_fid(pdu, dirfidp);
2542 v9fs_path_free(&new_path);
2543 out_nofid:
2544 return err;
2547 /* Only works with path name based fid */
2548 static void v9fs_rename(void *opaque)
2550 int32_t fid;
2551 ssize_t err = 0;
2552 size_t offset = 7;
2553 V9fsString name;
2554 int32_t newdirfid;
2555 V9fsFidState *fidp;
2556 V9fsPDU *pdu = opaque;
2557 V9fsState *s = pdu->s;
2559 pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2561 fidp = get_fid(pdu, fid);
2562 if (fidp == NULL) {
2563 err = -ENOENT;
2564 goto out_nofid;
2566 BUG_ON(fidp->fid_type != P9_FID_NONE);
2567 /* if fs driver is not path based, return EOPNOTSUPP */
2568 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2569 err = -EOPNOTSUPP;
2570 goto out;
2572 v9fs_path_write_lock(s);
2573 err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
2574 v9fs_path_unlock(s);
2575 if (!err) {
2576 err = offset;
2578 out:
2579 put_fid(pdu, fidp);
2580 out_nofid:
2581 complete_pdu(s, pdu, err);
2582 v9fs_string_free(&name);
2585 static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
2586 V9fsString *old_name, V9fsPath *newdir,
2587 V9fsString *new_name)
2589 V9fsFidState *tfidp;
2590 V9fsPath oldpath, newpath;
2591 V9fsState *s = pdu->s;
2594 v9fs_path_init(&oldpath);
2595 v9fs_path_init(&newpath);
2596 v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
2597 v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
2600 * Fixup fid's pointing to the old name to
2601 * start pointing to the new name
2603 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2604 if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
2605 /* replace the name */
2606 v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
2609 v9fs_path_free(&oldpath);
2610 v9fs_path_free(&newpath);
2613 static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
2614 V9fsString *old_name, int32_t newdirfid,
2615 V9fsString *new_name)
2617 int err = 0;
2618 V9fsState *s = pdu->s;
2619 V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2621 olddirfidp = get_fid(pdu, olddirfid);
2622 if (olddirfidp == NULL) {
2623 err = -ENOENT;
2624 goto out;
2626 if (newdirfid != -1) {
2627 newdirfidp = get_fid(pdu, newdirfid);
2628 if (newdirfidp == NULL) {
2629 err = -ENOENT;
2630 goto out;
2632 } else {
2633 newdirfidp = get_fid(pdu, olddirfid);
2636 err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
2637 &newdirfidp->path, new_name);
2638 if (err < 0) {
2639 goto out;
2641 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
2642 /* Only for path based fid we need to do the below fixup */
2643 v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
2644 &newdirfidp->path, new_name);
2646 out:
2647 if (olddirfidp) {
2648 put_fid(pdu, olddirfidp);
2650 if (newdirfidp) {
2651 put_fid(pdu, newdirfidp);
2653 return err;
2656 static void v9fs_renameat(void *opaque)
2658 ssize_t err = 0;
2659 size_t offset = 7;
2660 V9fsPDU *pdu = opaque;
2661 V9fsState *s = pdu->s;
2662 int32_t olddirfid, newdirfid;
2663 V9fsString old_name, new_name;
2665 pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2666 &old_name, &newdirfid, &new_name);
2668 v9fs_path_write_lock(s);
2669 err = v9fs_complete_renameat(pdu, olddirfid,
2670 &old_name, newdirfid, &new_name);
2671 v9fs_path_unlock(s);
2672 if (!err) {
2673 err = offset;
2675 complete_pdu(s, pdu, err);
2676 v9fs_string_free(&old_name);
2677 v9fs_string_free(&new_name);
2680 static void v9fs_wstat(void *opaque)
2682 int32_t fid;
2683 int err = 0;
2684 int16_t unused;
2685 V9fsStat v9stat;
2686 size_t offset = 7;
2687 struct stat stbuf;
2688 V9fsFidState *fidp;
2689 V9fsPDU *pdu = opaque;
2690 V9fsState *s = pdu->s;
2692 pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2693 trace_v9fs_wstat(pdu->tag, pdu->id, fid,
2694 v9stat.mode, v9stat.atime, v9stat.mtime);
2696 fidp = get_fid(pdu, fid);
2697 if (fidp == NULL) {
2698 err = -EINVAL;
2699 goto out_nofid;
2701 /* do we need to sync the file? */
2702 if (donttouch_stat(&v9stat)) {
2703 err = v9fs_co_fsync(pdu, fidp, 0);
2704 goto out;
2706 if (v9stat.mode != -1) {
2707 uint32_t v9_mode;
2708 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2709 if (err < 0) {
2710 goto out;
2712 v9_mode = stat_to_v9mode(&stbuf);
2713 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2714 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2715 /* Attempting to change the type */
2716 err = -EIO;
2717 goto out;
2719 err = v9fs_co_chmod(pdu, &fidp->path,
2720 v9mode_to_mode(v9stat.mode,
2721 &v9stat.extension));
2722 if (err < 0) {
2723 goto out;
2726 if (v9stat.mtime != -1 || v9stat.atime != -1) {
2727 struct timespec times[2];
2728 if (v9stat.atime != -1) {
2729 times[0].tv_sec = v9stat.atime;
2730 times[0].tv_nsec = 0;
2731 } else {
2732 times[0].tv_nsec = UTIME_OMIT;
2734 if (v9stat.mtime != -1) {
2735 times[1].tv_sec = v9stat.mtime;
2736 times[1].tv_nsec = 0;
2737 } else {
2738 times[1].tv_nsec = UTIME_OMIT;
2740 err = v9fs_co_utimensat(pdu, &fidp->path, times);
2741 if (err < 0) {
2742 goto out;
2745 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2746 err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2747 if (err < 0) {
2748 goto out;
2751 if (v9stat.name.size != 0) {
2752 err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
2753 if (err < 0) {
2754 goto out;
2757 if (v9stat.length != -1) {
2758 err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
2759 if (err < 0) {
2760 goto out;
2763 err = offset;
2764 out:
2765 put_fid(pdu, fidp);
2766 out_nofid:
2767 v9fs_stat_free(&v9stat);
2768 complete_pdu(s, pdu, err);
2771 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2773 uint32_t f_type;
2774 uint32_t f_bsize;
2775 uint64_t f_blocks;
2776 uint64_t f_bfree;
2777 uint64_t f_bavail;
2778 uint64_t f_files;
2779 uint64_t f_ffree;
2780 uint64_t fsid_val;
2781 uint32_t f_namelen;
2782 size_t offset = 7;
2783 int32_t bsize_factor;
2786 * compute bsize factor based on host file system block size
2787 * and client msize
2789 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2790 if (!bsize_factor) {
2791 bsize_factor = 1;
2793 f_type = stbuf->f_type;
2794 f_bsize = stbuf->f_bsize;
2795 f_bsize *= bsize_factor;
2797 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2798 * adjust(divide) the number of blocks, free blocks and available
2799 * blocks by bsize factor
2801 f_blocks = stbuf->f_blocks/bsize_factor;
2802 f_bfree = stbuf->f_bfree/bsize_factor;
2803 f_bavail = stbuf->f_bavail/bsize_factor;
2804 f_files = stbuf->f_files;
2805 f_ffree = stbuf->f_ffree;
2806 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2807 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2808 f_namelen = stbuf->f_namelen;
2810 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2811 f_type, f_bsize, f_blocks, f_bfree,
2812 f_bavail, f_files, f_ffree,
2813 fsid_val, f_namelen);
2816 static void v9fs_statfs(void *opaque)
2818 int32_t fid;
2819 ssize_t retval = 0;
2820 size_t offset = 7;
2821 V9fsFidState *fidp;
2822 struct statfs stbuf;
2823 V9fsPDU *pdu = opaque;
2824 V9fsState *s = pdu->s;
2826 pdu_unmarshal(pdu, offset, "d", &fid);
2827 fidp = get_fid(pdu, fid);
2828 if (fidp == NULL) {
2829 retval = -ENOENT;
2830 goto out_nofid;
2832 retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
2833 if (retval < 0) {
2834 goto out;
2836 retval = offset;
2837 retval += v9fs_fill_statfs(s, pdu, &stbuf);
2838 out:
2839 put_fid(pdu, fidp);
2840 out_nofid:
2841 complete_pdu(s, pdu, retval);
2842 return;
2845 static void v9fs_mknod(void *opaque)
2848 int mode;
2849 gid_t gid;
2850 int32_t fid;
2851 V9fsQID qid;
2852 int err = 0;
2853 int major, minor;
2854 size_t offset = 7;
2855 V9fsString name;
2856 struct stat stbuf;
2857 V9fsFidState *fidp;
2858 V9fsPDU *pdu = opaque;
2859 V9fsState *s = pdu->s;
2861 pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2862 &major, &minor, &gid);
2863 trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
2865 fidp = get_fid(pdu, fid);
2866 if (fidp == NULL) {
2867 err = -ENOENT;
2868 goto out_nofid;
2870 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
2871 makedev(major, minor), mode, &stbuf);
2872 if (err < 0) {
2873 goto out;
2875 stat_to_qid(&stbuf, &qid);
2876 err = offset;
2877 err += pdu_marshal(pdu, offset, "Q", &qid);
2878 trace_v9fs_mknod_return(pdu->tag, pdu->id,
2879 qid.type, qid.version, qid.path);
2880 out:
2881 put_fid(pdu, fidp);
2882 out_nofid:
2883 complete_pdu(s, pdu, err);
2884 v9fs_string_free(&name);
2888 * Implement posix byte range locking code
2889 * Server side handling of locking code is very simple, because 9p server in
2890 * QEMU can handle only one client. And most of the lock handling
2891 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2892 * do any thing in * qemu 9p server side lock code path.
2893 * So when a TLOCK request comes, always return success
2895 static void v9fs_lock(void *opaque)
2897 int8_t status;
2898 V9fsFlock *flock;
2899 size_t offset = 7;
2900 struct stat stbuf;
2901 V9fsFidState *fidp;
2902 int32_t fid, err = 0;
2903 V9fsPDU *pdu = opaque;
2904 V9fsState *s = pdu->s;
2906 flock = g_malloc(sizeof(*flock));
2907 pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
2908 &flock->flags, &flock->start, &flock->length,
2909 &flock->proc_id, &flock->client_id);
2911 trace_v9fs_lock(pdu->tag, pdu->id, fid,
2912 flock->type, flock->start, flock->length);
2914 status = P9_LOCK_ERROR;
2916 /* We support only block flag now (that too ignored currently) */
2917 if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
2918 err = -EINVAL;
2919 goto out_nofid;
2921 fidp = get_fid(pdu, fid);
2922 if (fidp == NULL) {
2923 err = -ENOENT;
2924 goto out_nofid;
2926 err = v9fs_co_fstat(pdu, fidp, &stbuf);
2927 if (err < 0) {
2928 goto out;
2930 status = P9_LOCK_SUCCESS;
2931 out:
2932 put_fid(pdu, fidp);
2933 out_nofid:
2934 err = offset;
2935 err += pdu_marshal(pdu, offset, "b", status);
2936 trace_v9fs_lock_return(pdu->tag, pdu->id, status);
2937 complete_pdu(s, pdu, err);
2938 v9fs_string_free(&flock->client_id);
2939 g_free(flock);
2943 * When a TGETLOCK request comes, always return success because all lock
2944 * handling is done by client's VFS layer.
2946 static void v9fs_getlock(void *opaque)
2948 size_t offset = 7;
2949 struct stat stbuf;
2950 V9fsFidState *fidp;
2951 V9fsGetlock *glock;
2952 int32_t fid, err = 0;
2953 V9fsPDU *pdu = opaque;
2954 V9fsState *s = pdu->s;
2956 glock = g_malloc(sizeof(*glock));
2957 pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
2958 &glock->start, &glock->length, &glock->proc_id,
2959 &glock->client_id);
2961 trace_v9fs_getlock(pdu->tag, pdu->id, fid,
2962 glock->type, glock->start, glock->length);
2964 fidp = get_fid(pdu, fid);
2965 if (fidp == NULL) {
2966 err = -ENOENT;
2967 goto out_nofid;
2969 err = v9fs_co_fstat(pdu, fidp, &stbuf);
2970 if (err < 0) {
2971 goto out;
2973 glock->type = P9_LOCK_TYPE_UNLCK;
2974 offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
2975 glock->start, glock->length, glock->proc_id,
2976 &glock->client_id);
2977 err = offset;
2978 trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
2979 glock->length, glock->proc_id);
2980 out:
2981 put_fid(pdu, fidp);
2982 out_nofid:
2983 complete_pdu(s, pdu, err);
2984 v9fs_string_free(&glock->client_id);
2985 g_free(glock);
2988 static void v9fs_mkdir(void *opaque)
2990 V9fsPDU *pdu = opaque;
2991 size_t offset = 7;
2992 int32_t fid;
2993 struct stat stbuf;
2994 V9fsQID qid;
2995 V9fsString name;
2996 V9fsFidState *fidp;
2997 gid_t gid;
2998 int mode;
2999 int err = 0;
3001 pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3003 trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
3005 fidp = get_fid(pdu, fid);
3006 if (fidp == NULL) {
3007 err = -ENOENT;
3008 goto out_nofid;
3010 err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
3011 if (err < 0) {
3012 goto out;
3014 stat_to_qid(&stbuf, &qid);
3015 offset += pdu_marshal(pdu, offset, "Q", &qid);
3016 err = offset;
3017 trace_v9fs_mkdir_return(pdu->tag, pdu->id,
3018 qid.type, qid.version, qid.path, err);
3019 out:
3020 put_fid(pdu, fidp);
3021 out_nofid:
3022 complete_pdu(pdu->s, pdu, err);
3023 v9fs_string_free(&name);
3026 static void v9fs_xattrwalk(void *opaque)
3028 int64_t size;
3029 V9fsString name;
3030 ssize_t err = 0;
3031 size_t offset = 7;
3032 int32_t fid, newfid;
3033 V9fsFidState *file_fidp;
3034 V9fsFidState *xattr_fidp = NULL;
3035 V9fsPDU *pdu = opaque;
3036 V9fsState *s = pdu->s;
3038 pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3039 trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
3041 file_fidp = get_fid(pdu, fid);
3042 if (file_fidp == NULL) {
3043 err = -ENOENT;
3044 goto out_nofid;
3046 xattr_fidp = alloc_fid(s, newfid);
3047 if (xattr_fidp == NULL) {
3048 err = -EINVAL;
3049 goto out;
3051 v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
3052 if (name.data[0] == 0) {
3054 * listxattr request. Get the size first
3056 size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
3057 if (size < 0) {
3058 err = size;
3059 clunk_fid(s, xattr_fidp->fid);
3060 goto out;
3063 * Read the xattr value
3065 xattr_fidp->fs.xattr.len = size;
3066 xattr_fidp->fid_type = P9_FID_XATTR;
3067 xattr_fidp->fs.xattr.copied_len = -1;
3068 if (size) {
3069 xattr_fidp->fs.xattr.value = g_malloc(size);
3070 err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
3071 xattr_fidp->fs.xattr.value,
3072 xattr_fidp->fs.xattr.len);
3073 if (err < 0) {
3074 clunk_fid(s, xattr_fidp->fid);
3075 goto out;
3078 offset += pdu_marshal(pdu, offset, "q", size);
3079 err = offset;
3080 } else {
3082 * specific xattr fid. We check for xattr
3083 * presence also collect the xattr size
3085 size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3086 &name, NULL, 0);
3087 if (size < 0) {
3088 err = size;
3089 clunk_fid(s, xattr_fidp->fid);
3090 goto out;
3093 * Read the xattr value
3095 xattr_fidp->fs.xattr.len = size;
3096 xattr_fidp->fid_type = P9_FID_XATTR;
3097 xattr_fidp->fs.xattr.copied_len = -1;
3098 if (size) {
3099 xattr_fidp->fs.xattr.value = g_malloc(size);
3100 err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3101 &name, xattr_fidp->fs.xattr.value,
3102 xattr_fidp->fs.xattr.len);
3103 if (err < 0) {
3104 clunk_fid(s, xattr_fidp->fid);
3105 goto out;
3108 offset += pdu_marshal(pdu, offset, "q", size);
3109 err = offset;
3111 trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
3112 out:
3113 put_fid(pdu, file_fidp);
3114 if (xattr_fidp) {
3115 put_fid(pdu, xattr_fidp);
3117 out_nofid:
3118 complete_pdu(s, pdu, err);
3119 v9fs_string_free(&name);
3122 static void v9fs_xattrcreate(void *opaque)
3124 int flags;
3125 int32_t fid;
3126 int64_t size;
3127 ssize_t err = 0;
3128 V9fsString name;
3129 size_t offset = 7;
3130 V9fsFidState *file_fidp;
3131 V9fsFidState *xattr_fidp;
3132 V9fsPDU *pdu = opaque;
3133 V9fsState *s = pdu->s;
3135 pdu_unmarshal(pdu, offset, "dsqd",
3136 &fid, &name, &size, &flags);
3137 trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
3139 file_fidp = get_fid(pdu, fid);
3140 if (file_fidp == NULL) {
3141 err = -EINVAL;
3142 goto out_nofid;
3144 /* Make the file fid point to xattr */
3145 xattr_fidp = file_fidp;
3146 xattr_fidp->fid_type = P9_FID_XATTR;
3147 xattr_fidp->fs.xattr.copied_len = 0;
3148 xattr_fidp->fs.xattr.len = size;
3149 xattr_fidp->fs.xattr.flags = flags;
3150 v9fs_string_init(&xattr_fidp->fs.xattr.name);
3151 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3152 if (size) {
3153 xattr_fidp->fs.xattr.value = g_malloc(size);
3154 } else {
3155 xattr_fidp->fs.xattr.value = NULL;
3157 err = offset;
3158 put_fid(pdu, file_fidp);
3159 out_nofid:
3160 complete_pdu(s, pdu, err);
3161 v9fs_string_free(&name);
3164 static void v9fs_readlink(void *opaque)
3166 V9fsPDU *pdu = opaque;
3167 size_t offset = 7;
3168 V9fsString target;
3169 int32_t fid;
3170 int err = 0;
3171 V9fsFidState *fidp;
3173 pdu_unmarshal(pdu, offset, "d", &fid);
3174 trace_v9fs_readlink(pdu->tag, pdu->id, fid);
3175 fidp = get_fid(pdu, fid);
3176 if (fidp == NULL) {
3177 err = -ENOENT;
3178 goto out_nofid;
3181 v9fs_string_init(&target);
3182 err = v9fs_co_readlink(pdu, &fidp->path, &target);
3183 if (err < 0) {
3184 goto out;
3186 offset += pdu_marshal(pdu, offset, "s", &target);
3187 err = offset;
3188 trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
3189 v9fs_string_free(&target);
3190 out:
3191 put_fid(pdu, fidp);
3192 out_nofid:
3193 complete_pdu(pdu->s, pdu, err);
3196 static CoroutineEntry *pdu_co_handlers[] = {
3197 [P9_TREADDIR] = v9fs_readdir,
3198 [P9_TSTATFS] = v9fs_statfs,
3199 [P9_TGETATTR] = v9fs_getattr,
3200 [P9_TSETATTR] = v9fs_setattr,
3201 [P9_TXATTRWALK] = v9fs_xattrwalk,
3202 [P9_TXATTRCREATE] = v9fs_xattrcreate,
3203 [P9_TMKNOD] = v9fs_mknod,
3204 [P9_TRENAME] = v9fs_rename,
3205 [P9_TLOCK] = v9fs_lock,
3206 [P9_TGETLOCK] = v9fs_getlock,
3207 [P9_TRENAMEAT] = v9fs_renameat,
3208 [P9_TREADLINK] = v9fs_readlink,
3209 [P9_TUNLINKAT] = v9fs_unlinkat,
3210 [P9_TMKDIR] = v9fs_mkdir,
3211 [P9_TVERSION] = v9fs_version,
3212 [P9_TLOPEN] = v9fs_open,
3213 [P9_TATTACH] = v9fs_attach,
3214 [P9_TSTAT] = v9fs_stat,
3215 [P9_TWALK] = v9fs_walk,
3216 [P9_TCLUNK] = v9fs_clunk,
3217 [P9_TFSYNC] = v9fs_fsync,
3218 [P9_TOPEN] = v9fs_open,
3219 [P9_TREAD] = v9fs_read,
3220 #if 0
3221 [P9_TAUTH] = v9fs_auth,
3222 #endif
3223 [P9_TFLUSH] = v9fs_flush,
3224 [P9_TLINK] = v9fs_link,
3225 [P9_TSYMLINK] = v9fs_symlink,
3226 [P9_TCREATE] = v9fs_create,
3227 [P9_TLCREATE] = v9fs_lcreate,
3228 [P9_TWRITE] = v9fs_write,
3229 [P9_TWSTAT] = v9fs_wstat,
3230 [P9_TREMOVE] = v9fs_remove,
3233 static void v9fs_op_not_supp(void *opaque)
3235 V9fsPDU *pdu = opaque;
3236 complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3239 static void v9fs_fs_ro(void *opaque)
3241 V9fsPDU *pdu = opaque;
3242 complete_pdu(pdu->s, pdu, -EROFS);
3245 static inline bool is_read_only_op(V9fsPDU *pdu)
3247 switch (pdu->id) {
3248 case P9_TREADDIR:
3249 case P9_TSTATFS:
3250 case P9_TGETATTR:
3251 case P9_TXATTRWALK:
3252 case P9_TLOCK:
3253 case P9_TGETLOCK:
3254 case P9_TREADLINK:
3255 case P9_TVERSION:
3256 case P9_TLOPEN:
3257 case P9_TATTACH:
3258 case P9_TSTAT:
3259 case P9_TWALK:
3260 case P9_TCLUNK:
3261 case P9_TFSYNC:
3262 case P9_TOPEN:
3263 case P9_TREAD:
3264 case P9_TAUTH:
3265 case P9_TFLUSH:
3266 return 1;
3267 default:
3268 return 0;
3272 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3274 Coroutine *co;
3275 CoroutineEntry *handler;
3277 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3278 (pdu_co_handlers[pdu->id] == NULL)) {
3279 handler = v9fs_op_not_supp;
3280 } else {
3281 handler = pdu_co_handlers[pdu->id];
3284 if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
3285 handler = v9fs_fs_ro;
3287 co = qemu_coroutine_create(handler);
3288 qemu_coroutine_enter(co, pdu);
3291 void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3293 V9fsState *s = (V9fsState *)vdev;
3294 V9fsPDU *pdu;
3295 ssize_t len;
3297 while ((pdu = alloc_pdu(s)) &&
3298 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3299 uint8_t *ptr;
3300 pdu->s = s;
3301 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3302 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3304 ptr = pdu->elem.out_sg[0].iov_base;
3306 memcpy(&pdu->size, ptr, 4);
3307 pdu->id = ptr[4];
3308 memcpy(&pdu->tag, ptr + 5, 2);
3309 qemu_co_queue_init(&pdu->complete);
3310 submit_pdu(s, pdu);
3312 free_pdu(s, pdu);
3315 void virtio_9p_set_fd_limit(void)
3317 struct rlimit rlim;
3318 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3319 fprintf(stderr, "Failed to get the resource limit\n");
3320 exit(1);
3322 open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3323 open_fd_rc = rlim.rlim_cur/2;