1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "qemu/osdep.h"
15#include <glib/gprintf.h>
16#include "hw/virtio/virtio.h"
17#include "qapi/error.h"
18#include "qemu/error-report.h"
19#include "qemu/iov.h"
20#include "qemu/sockets.h"
21#include "virtio-9p.h"
22#include "fsdev/qemu-fsdev.h"
23#include "9p-xattr.h"
24#include "coth.h"
25#include "trace.h"
26#include "migration/blocker.h"
27
28int open_fd_hw;
29int total_open_fd;
30static int open_fd_rc;
31
32enum {
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,
42};
43
44ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
45{
46 ssize_t ret;
47 va_list ap;
48
49 va_start(ap, fmt);
50 ret = pdu->s->transport->pdu_vmarshal(pdu, offset, fmt, ap);
51 va_end(ap);
52
53 return ret;
54}
55
56ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
57{
58 ssize_t ret;
59 va_list ap;
60
61 va_start(ap, fmt);
62 ret = pdu->s->transport->pdu_vunmarshal(pdu, offset, fmt, ap);
63 va_end(ap);
64
65 return ret;
66}
67
68static int omode_to_uflags(int8_t mode)
69{
70 int ret = 0;
71
72 switch (mode & 3) {
73 case Oread:
74 ret = O_RDONLY;
75 break;
76 case Ordwr:
77 ret = O_RDWR;
78 break;
79 case Owrite:
80 ret = O_WRONLY;
81 break;
82 case Oexec:
83 ret = O_RDONLY;
84 break;
85 }
86
87 if (mode & Otrunc) {
88 ret |= O_TRUNC;
89 }
90
91 if (mode & Oappend) {
92 ret |= O_APPEND;
93 }
94
95 if (mode & Oexcl) {
96 ret |= O_EXCL;
97 }
98
99 return ret;
100}
101
102struct dotl_openflag_map {
103 int dotl_flag;
104 int open_flag;
105};
106
107static int dotl_to_open_flags(int flags)
108{
109 int i;
110
111
112
113
114 int oflags = flags & O_ACCMODE;
115
116 struct dotl_openflag_map dotl_oflag_map[] = {
117 { P9_DOTL_CREATE, O_CREAT },
118 { P9_DOTL_EXCL, O_EXCL },
119 { P9_DOTL_NOCTTY , O_NOCTTY },
120 { P9_DOTL_TRUNC, O_TRUNC },
121 { P9_DOTL_APPEND, O_APPEND },
122 { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
123 { P9_DOTL_DSYNC, O_DSYNC },
124 { P9_DOTL_FASYNC, FASYNC },
125 { P9_DOTL_DIRECT, O_DIRECT },
126 { P9_DOTL_LARGEFILE, O_LARGEFILE },
127 { P9_DOTL_DIRECTORY, O_DIRECTORY },
128 { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
129 { P9_DOTL_NOATIME, O_NOATIME },
130 { P9_DOTL_SYNC, O_SYNC },
131 };
132
133 for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
134 if (flags & dotl_oflag_map[i].dotl_flag) {
135 oflags |= dotl_oflag_map[i].open_flag;
136 }
137 }
138
139 return oflags;
140}
141
142void cred_init(FsCred *credp)
143{
144 credp->fc_uid = -1;
145 credp->fc_gid = -1;
146 credp->fc_mode = -1;
147 credp->fc_rdev = -1;
148}
149
150static int get_dotl_openflags(V9fsState *s, int oflags)
151{
152 int flags;
153
154
155
156 flags = dotl_to_open_flags(oflags);
157 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
158
159
160
161 flags &= ~O_DIRECT;
162 return flags;
163}
164
165void v9fs_path_init(V9fsPath *path)
166{
167 path->data = NULL;
168 path->size = 0;
169}
170
171void v9fs_path_free(V9fsPath *path)
172{
173 g_free(path->data);
174 path->data = NULL;
175 path->size = 0;
176}
177
178
179void GCC_FMT_ATTR(2, 3)
180v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...)
181{
182 va_list ap;
183
184 v9fs_path_free(path);
185
186 va_start(ap, fmt);
187
188 path->size = g_vasprintf(&path->data, fmt, ap) + 1;
189 va_end(ap);
190}
191
192void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
193{
194 v9fs_path_free(lhs);
195 lhs->data = g_malloc(rhs->size);
196 memcpy(lhs->data, rhs->data, rhs->size);
197 lhs->size = rhs->size;
198}
199
200int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
201 const char *name, V9fsPath *path)
202{
203 int err;
204 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
205 if (err < 0) {
206 err = -errno;
207 }
208 return err;
209}
210
211
212
213
214
215
216
217static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
218{
219 if (!strncmp(s1->data, s2->data, s1->size - 1)) {
220 if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
221 return 1;
222 }
223 }
224 return 0;
225}
226
227static size_t v9fs_string_size(V9fsString *str)
228{
229 return str->size;
230}
231
232
233
234static int coroutine_fn v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
235{
236 int err = 1;
237 if (f->fid_type == P9_FID_FILE) {
238 if (f->fs.fd == -1) {
239 do {
240 err = v9fs_co_open(pdu, f, f->open_flags);
241 } while (err == -EINTR && !pdu->cancelled);
242 }
243 } else if (f->fid_type == P9_FID_DIR) {
244 if (f->fs.dir.stream == NULL) {
245 do {
246 err = v9fs_co_opendir(pdu, f);
247 } while (err == -EINTR && !pdu->cancelled);
248 }
249 }
250 return err;
251}
252
253static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid)
254{
255 int err;
256 V9fsFidState *f;
257 V9fsState *s = pdu->s;
258
259 for (f = s->fid_list; f; f = f->next) {
260 BUG_ON(f->clunked);
261 if (f->fid == fid) {
262
263
264
265
266
267 f->ref++;
268
269
270
271
272
273
274 err = v9fs_reopen_fid(pdu, f);
275 if (err < 0) {
276 f->ref--;
277 return NULL;
278 }
279
280
281
282
283 f->flags |= FID_REFERENCED;
284 return f;
285 }
286 }
287 return NULL;
288}
289
290static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
291{
292 V9fsFidState *f;
293
294 for (f = s->fid_list; f; f = f->next) {
295
296 BUG_ON(f->clunked);
297 if (f->fid == fid) {
298 return NULL;
299 }
300 }
301 f = g_malloc0(sizeof(V9fsFidState));
302 f->fid = fid;
303 f->fid_type = P9_FID_NONE;
304 f->ref = 1;
305
306
307
308
309 f->flags |= FID_REFERENCED;
310 f->next = s->fid_list;
311 s->fid_list = f;
312
313 v9fs_readdir_init(&f->fs.dir);
314 v9fs_readdir_init(&f->fs_reclaim.dir);
315
316 return f;
317}
318
319static int coroutine_fn v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
320{
321 int retval = 0;
322
323 if (fidp->fs.xattr.xattrwalk_fid) {
324
325 goto free_value;
326 }
327
328
329
330
331 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
332
333 retval = -EINVAL;
334 goto free_out;
335 }
336 if (fidp->fs.xattr.len) {
337 retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
338 fidp->fs.xattr.value,
339 fidp->fs.xattr.len,
340 fidp->fs.xattr.flags);
341 } else {
342 retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
343 }
344free_out:
345 v9fs_string_free(&fidp->fs.xattr.name);
346free_value:
347 g_free(fidp->fs.xattr.value);
348 return retval;
349}
350
351static int coroutine_fn free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
352{
353 int retval = 0;
354
355 if (fidp->fid_type == P9_FID_FILE) {
356
357 if (fidp->fs.fd != -1) {
358 retval = v9fs_co_close(pdu, &fidp->fs);
359 }
360 } else if (fidp->fid_type == P9_FID_DIR) {
361 if (fidp->fs.dir.stream != NULL) {
362 retval = v9fs_co_closedir(pdu, &fidp->fs);
363 }
364 } else if (fidp->fid_type == P9_FID_XATTR) {
365 retval = v9fs_xattr_fid_clunk(pdu, fidp);
366 }
367 v9fs_path_free(&fidp->path);
368 g_free(fidp);
369 return retval;
370}
371
372static int coroutine_fn put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
373{
374 BUG_ON(!fidp->ref);
375 fidp->ref--;
376
377
378
379 if (!fidp->ref && fidp->clunked) {
380 if (fidp->fid == pdu->s->root_fid) {
381
382
383
384
385
386
387 if (pdu->s->migration_blocker) {
388 migrate_del_blocker(pdu->s->migration_blocker);
389 error_free(pdu->s->migration_blocker);
390 pdu->s->migration_blocker = NULL;
391 }
392 }
393 return free_fid(pdu, fidp);
394 }
395 return 0;
396}
397
398static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
399{
400 V9fsFidState **fidpp, *fidp;
401
402 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
403 if ((*fidpp)->fid == fid) {
404 break;
405 }
406 }
407 if (*fidpp == NULL) {
408 return NULL;
409 }
410 fidp = *fidpp;
411 *fidpp = fidp->next;
412 fidp->clunked = 1;
413 return fidp;
414}
415
416void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
417{
418 int reclaim_count = 0;
419 V9fsState *s = pdu->s;
420 V9fsFidState *f, *reclaim_list = NULL;
421
422 for (f = s->fid_list; f; f = f->next) {
423
424
425
426
427
428 if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
429 continue;
430 }
431
432
433
434
435
436
437
438 if (f->flags & FID_REFERENCED) {
439 f->flags &= ~FID_REFERENCED;
440 continue;
441 }
442
443
444
445 if (f->fid_type == P9_FID_FILE) {
446 if (f->fs.fd != -1) {
447
448
449
450
451 f->ref++;
452 f->rclm_lst = reclaim_list;
453 reclaim_list = f;
454 f->fs_reclaim.fd = f->fs.fd;
455 f->fs.fd = -1;
456 reclaim_count++;
457 }
458 } else if (f->fid_type == P9_FID_DIR) {
459 if (f->fs.dir.stream != NULL) {
460
461
462
463
464 f->ref++;
465 f->rclm_lst = reclaim_list;
466 reclaim_list = f;
467 f->fs_reclaim.dir.stream = f->fs.dir.stream;
468 f->fs.dir.stream = NULL;
469 reclaim_count++;
470 }
471 }
472 if (reclaim_count >= open_fd_rc) {
473 break;
474 }
475 }
476
477
478
479
480 while (reclaim_list) {
481 f = reclaim_list;
482 reclaim_list = f->rclm_lst;
483 if (f->fid_type == P9_FID_FILE) {
484 v9fs_co_close(pdu, &f->fs_reclaim);
485 } else if (f->fid_type == P9_FID_DIR) {
486 v9fs_co_closedir(pdu, &f->fs_reclaim);
487 }
488 f->rclm_lst = NULL;
489
490
491
492
493 put_fid(pdu, f);
494 }
495}
496
497static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
498{
499 int err;
500 V9fsState *s = pdu->s;
501 V9fsFidState *fidp, head_fid;
502
503 head_fid.next = s->fid_list;
504 for (fidp = s->fid_list; fidp; fidp = fidp->next) {
505 if (fidp->path.size != path->size) {
506 continue;
507 }
508 if (!memcmp(fidp->path.data, path->data, path->size)) {
509
510 fidp->flags |= FID_NON_RECLAIMABLE;
511
512
513 err = v9fs_reopen_fid(pdu, fidp);
514 if (err < 0) {
515 return -1;
516 }
517
518
519
520
521
522 if (err == 0) {
523 fidp = &head_fid;
524 }
525 }
526 }
527 return 0;
528}
529
530static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
531{
532 V9fsState *s = pdu->s;
533 V9fsFidState *fidp;
534
535
536 while (s->fid_list) {
537
538 fidp = s->fid_list;
539 fidp->ref++;
540
541
542 s->fid_list = fidp->next;
543 fidp->clunked = 1;
544
545 put_fid(pdu, fidp);
546 }
547}
548
549#define P9_QID_TYPE_DIR 0x80
550#define P9_QID_TYPE_SYMLINK 0x02
551
552#define P9_STAT_MODE_DIR 0x80000000
553#define P9_STAT_MODE_APPEND 0x40000000
554#define P9_STAT_MODE_EXCL 0x20000000
555#define P9_STAT_MODE_MOUNT 0x10000000
556#define P9_STAT_MODE_AUTH 0x08000000
557#define P9_STAT_MODE_TMP 0x04000000
558#define P9_STAT_MODE_SYMLINK 0x02000000
559#define P9_STAT_MODE_LINK 0x01000000
560#define P9_STAT_MODE_DEVICE 0x00800000
561#define P9_STAT_MODE_NAMED_PIPE 0x00200000
562#define P9_STAT_MODE_SOCKET 0x00100000
563#define P9_STAT_MODE_SETUID 0x00080000
564#define P9_STAT_MODE_SETGID 0x00040000
565#define P9_STAT_MODE_SETVTX 0x00010000
566
567#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
568 P9_STAT_MODE_SYMLINK | \
569 P9_STAT_MODE_LINK | \
570 P9_STAT_MODE_DEVICE | \
571 P9_STAT_MODE_NAMED_PIPE | \
572 P9_STAT_MODE_SOCKET)
573
574
575static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
576{
577 size_t size;
578
579 memset(&qidp->path, 0, sizeof(qidp->path));
580 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
581 memcpy(&qidp->path, &stbuf->st_ino, size);
582 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
583 qidp->type = 0;
584 if (S_ISDIR(stbuf->st_mode)) {
585 qidp->type |= P9_QID_TYPE_DIR;
586 }
587 if (S_ISLNK(stbuf->st_mode)) {
588 qidp->type |= P9_QID_TYPE_SYMLINK;
589 }
590}
591
592static int coroutine_fn fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp,
593 V9fsQID *qidp)
594{
595 struct stat stbuf;
596 int err;
597
598 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
599 if (err < 0) {
600 return err;
601 }
602 stat_to_qid(&stbuf, qidp);
603 return 0;
604}
605
606V9fsPDU *pdu_alloc(V9fsState *s)
607{
608 V9fsPDU *pdu = NULL;
609
610 if (!QLIST_EMPTY(&s->free_list)) {
611 pdu = QLIST_FIRST(&s->free_list);
612 QLIST_REMOVE(pdu, next);
613 QLIST_INSERT_HEAD(&s->active_list, pdu, next);
614 }
615 return pdu;
616}
617
618void pdu_free(V9fsPDU *pdu)
619{
620 V9fsState *s = pdu->s;
621
622 g_assert(!pdu->cancelled);
623 QLIST_REMOVE(pdu, next);
624 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
625}
626
627static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
628{
629 int8_t id = pdu->id + 1;
630 V9fsState *s = pdu->s;
631 int ret;
632
633 if (len < 0) {
634 int err = -len;
635 len = 7;
636
637 if (s->proto_version != V9FS_PROTO_2000L) {
638 V9fsString str;
639
640 str.data = strerror(err);
641 str.size = strlen(str.data);
642
643 ret = pdu_marshal(pdu, len, "s", &str);
644 if (ret < 0) {
645 goto out_notify;
646 }
647 len += ret;
648 id = P9_RERROR;
649 }
650
651 ret = pdu_marshal(pdu, len, "d", err);
652 if (ret < 0) {
653 goto out_notify;
654 }
655 len += ret;
656
657 if (s->proto_version == V9FS_PROTO_2000L) {
658 id = P9_RLERROR;
659 }
660 trace_v9fs_rerror(pdu->tag, pdu->id, err);
661 }
662
663
664 if (pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag) < 0) {
665 goto out_notify;
666 }
667
668
669 pdu->size = len;
670 pdu->id = id;
671
672out_notify:
673 pdu->s->transport->push_and_notify(pdu);
674
675
676 if (!qemu_co_queue_next(&pdu->complete)) {
677 pdu_free(pdu);
678 }
679}
680
681static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
682{
683 mode_t ret;
684
685 ret = mode & 0777;
686 if (mode & P9_STAT_MODE_DIR) {
687 ret |= S_IFDIR;
688 }
689
690 if (mode & P9_STAT_MODE_SYMLINK) {
691 ret |= S_IFLNK;
692 }
693 if (mode & P9_STAT_MODE_SOCKET) {
694 ret |= S_IFSOCK;
695 }
696 if (mode & P9_STAT_MODE_NAMED_PIPE) {
697 ret |= S_IFIFO;
698 }
699 if (mode & P9_STAT_MODE_DEVICE) {
700 if (extension->size && extension->data[0] == 'c') {
701 ret |= S_IFCHR;
702 } else {
703 ret |= S_IFBLK;
704 }
705 }
706
707 if (!(ret&~0777)) {
708 ret |= S_IFREG;
709 }
710
711 if (mode & P9_STAT_MODE_SETUID) {
712 ret |= S_ISUID;
713 }
714 if (mode & P9_STAT_MODE_SETGID) {
715 ret |= S_ISGID;
716 }
717 if (mode & P9_STAT_MODE_SETVTX) {
718 ret |= S_ISVTX;
719 }
720
721 return ret;
722}
723
724static int donttouch_stat(V9fsStat *stat)
725{
726 if (stat->type == -1 &&
727 stat->dev == -1 &&
728 stat->qid.type == -1 &&
729 stat->qid.version == -1 &&
730 stat->qid.path == -1 &&
731 stat->mode == -1 &&
732 stat->atime == -1 &&
733 stat->mtime == -1 &&
734 stat->length == -1 &&
735 !stat->name.size &&
736 !stat->uid.size &&
737 !stat->gid.size &&
738 !stat->muid.size &&
739 stat->n_uid == -1 &&
740 stat->n_gid == -1 &&
741 stat->n_muid == -1) {
742 return 1;
743 }
744
745 return 0;
746}
747
748static void v9fs_stat_init(V9fsStat *stat)
749{
750 v9fs_string_init(&stat->name);
751 v9fs_string_init(&stat->uid);
752 v9fs_string_init(&stat->gid);
753 v9fs_string_init(&stat->muid);
754 v9fs_string_init(&stat->extension);
755}
756
757static void v9fs_stat_free(V9fsStat *stat)
758{
759 v9fs_string_free(&stat->name);
760 v9fs_string_free(&stat->uid);
761 v9fs_string_free(&stat->gid);
762 v9fs_string_free(&stat->muid);
763 v9fs_string_free(&stat->extension);
764}
765
766static uint32_t stat_to_v9mode(const struct stat *stbuf)
767{
768 uint32_t mode;
769
770 mode = stbuf->st_mode & 0777;
771 if (S_ISDIR(stbuf->st_mode)) {
772 mode |= P9_STAT_MODE_DIR;
773 }
774
775 if (S_ISLNK(stbuf->st_mode)) {
776 mode |= P9_STAT_MODE_SYMLINK;
777 }
778
779 if (S_ISSOCK(stbuf->st_mode)) {
780 mode |= P9_STAT_MODE_SOCKET;
781 }
782
783 if (S_ISFIFO(stbuf->st_mode)) {
784 mode |= P9_STAT_MODE_NAMED_PIPE;
785 }
786
787 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
788 mode |= P9_STAT_MODE_DEVICE;
789 }
790
791 if (stbuf->st_mode & S_ISUID) {
792 mode |= P9_STAT_MODE_SETUID;
793 }
794
795 if (stbuf->st_mode & S_ISGID) {
796 mode |= P9_STAT_MODE_SETGID;
797 }
798
799 if (stbuf->st_mode & S_ISVTX) {
800 mode |= P9_STAT_MODE_SETVTX;
801 }
802
803 return mode;
804}
805
806static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
807 const char *basename,
808 const struct stat *stbuf,
809 V9fsStat *v9stat)
810{
811 int err;
812
813 memset(v9stat, 0, sizeof(*v9stat));
814
815 stat_to_qid(stbuf, &v9stat->qid);
816 v9stat->mode = stat_to_v9mode(stbuf);
817 v9stat->atime = stbuf->st_atime;
818 v9stat->mtime = stbuf->st_mtime;
819 v9stat->length = stbuf->st_size;
820
821 v9fs_string_free(&v9stat->uid);
822 v9fs_string_free(&v9stat->gid);
823 v9fs_string_free(&v9stat->muid);
824
825 v9stat->n_uid = stbuf->st_uid;
826 v9stat->n_gid = stbuf->st_gid;
827 v9stat->n_muid = 0;
828
829 v9fs_string_free(&v9stat->extension);
830
831 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
832 err = v9fs_co_readlink(pdu, path, &v9stat->extension);
833 if (err < 0) {
834 return err;
835 }
836 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
837 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
838 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
839 major(stbuf->st_rdev), minor(stbuf->st_rdev));
840 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
841 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
842 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
843 }
844
845 v9fs_string_sprintf(&v9stat->name, "%s", basename);
846
847 v9stat->size = 61 +
848 v9fs_string_size(&v9stat->name) +
849 v9fs_string_size(&v9stat->uid) +
850 v9fs_string_size(&v9stat->gid) +
851 v9fs_string_size(&v9stat->muid) +
852 v9fs_string_size(&v9stat->extension);
853 return 0;
854}
855
856#define P9_STATS_MODE 0x00000001ULL
857#define P9_STATS_NLINK 0x00000002ULL
858#define P9_STATS_UID 0x00000004ULL
859#define P9_STATS_GID 0x00000008ULL
860#define P9_STATS_RDEV 0x00000010ULL
861#define P9_STATS_ATIME 0x00000020ULL
862#define P9_STATS_MTIME 0x00000040ULL
863#define P9_STATS_CTIME 0x00000080ULL
864#define P9_STATS_INO 0x00000100ULL
865#define P9_STATS_SIZE 0x00000200ULL
866#define P9_STATS_BLOCKS 0x00000400ULL
867
868#define P9_STATS_BTIME 0x00000800ULL
869#define P9_STATS_GEN 0x00001000ULL
870#define P9_STATS_DATA_VERSION 0x00002000ULL
871
872#define P9_STATS_BASIC 0x000007ffULL
873#define P9_STATS_ALL 0x00003fffULL
874
875
876static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
877 V9fsStatDotl *v9lstat)
878{
879 memset(v9lstat, 0, sizeof(*v9lstat));
880
881 v9lstat->st_mode = stbuf->st_mode;
882 v9lstat->st_nlink = stbuf->st_nlink;
883 v9lstat->st_uid = stbuf->st_uid;
884 v9lstat->st_gid = stbuf->st_gid;
885 v9lstat->st_rdev = stbuf->st_rdev;
886 v9lstat->st_size = stbuf->st_size;
887 v9lstat->st_blksize = stbuf->st_blksize;
888 v9lstat->st_blocks = stbuf->st_blocks;
889 v9lstat->st_atime_sec = stbuf->st_atime;
890 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
891 v9lstat->st_mtime_sec = stbuf->st_mtime;
892 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
893 v9lstat->st_ctime_sec = stbuf->st_ctime;
894 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
895
896 v9lstat->st_result_mask = P9_STATS_BASIC;
897
898 stat_to_qid(stbuf, &v9lstat->qid);
899}
900
901static void print_sg(struct iovec *sg, int cnt)
902{
903 int i;
904
905 printf("sg[%d]: {", cnt);
906 for (i = 0; i < cnt; i++) {
907 if (i) {
908 printf(", ");
909 }
910 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
911 }
912 printf("}\n");
913}
914
915
916static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
917{
918 V9fsPath str;
919 v9fs_path_init(&str);
920 v9fs_path_copy(&str, dst);
921 v9fs_path_sprintf(dst, "%s%s", src->data, str.data + len);
922 v9fs_path_free(&str);
923}
924
925static inline bool is_ro_export(FsContext *ctx)
926{
927 return ctx->export_flags & V9FS_RDONLY;
928}
929
930static void coroutine_fn v9fs_version(void *opaque)
931{
932 ssize_t err;
933 V9fsPDU *pdu = opaque;
934 V9fsState *s = pdu->s;
935 V9fsString version;
936 size_t offset = 7;
937
938 v9fs_string_init(&version);
939 err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
940 if (err < 0) {
941 offset = err;
942 goto out;
943 }
944 trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
945
946 virtfs_reset(pdu);
947
948 if (!strcmp(version.data, "9P2000.u")) {
949 s->proto_version = V9FS_PROTO_2000U;
950 } else if (!strcmp(version.data, "9P2000.L")) {
951 s->proto_version = V9FS_PROTO_2000L;
952 } else {
953 v9fs_string_sprintf(&version, "unknown");
954 }
955
956 err = pdu_marshal(pdu, offset, "ds", s->msize, &version);
957 if (err < 0) {
958 offset = err;
959 goto out;
960 }
961 offset += err;
962 trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
963out:
964 pdu_complete(pdu, offset);
965 v9fs_string_free(&version);
966}
967
968static void coroutine_fn v9fs_attach(void *opaque)
969{
970 V9fsPDU *pdu = opaque;
971 V9fsState *s = pdu->s;
972 int32_t fid, afid, n_uname;
973 V9fsString uname, aname;
974 V9fsFidState *fidp;
975 size_t offset = 7;
976 V9fsQID qid;
977 ssize_t err;
978 Error *local_err = NULL;
979
980 v9fs_string_init(&uname);
981 v9fs_string_init(&aname);
982 err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
983 &afid, &uname, &aname, &n_uname);
984 if (err < 0) {
985 goto out_nofid;
986 }
987 trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
988
989 fidp = alloc_fid(s, fid);
990 if (fidp == NULL) {
991 err = -EINVAL;
992 goto out_nofid;
993 }
994 fidp->uid = n_uname;
995 err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
996 if (err < 0) {
997 err = -EINVAL;
998 clunk_fid(s, fid);
999 goto out;
1000 }
1001 err = fid_to_qid(pdu, fidp, &qid);
1002 if (err < 0) {
1003 err = -EINVAL;
1004 clunk_fid(s, fid);
1005 goto out;
1006 }
1007
1008
1009
1010
1011
1012 if (!s->migration_blocker) {
1013 error_setg(&s->migration_blocker,
1014 "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
1015 s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
1016 err = migrate_add_blocker(s->migration_blocker, &local_err);
1017 if (local_err) {
1018 error_free(local_err);
1019 error_free(s->migration_blocker);
1020 s->migration_blocker = NULL;
1021 clunk_fid(s, fid);
1022 goto out;
1023 }
1024 s->root_fid = fid;
1025 }
1026
1027 err = pdu_marshal(pdu, offset, "Q", &qid);
1028 if (err < 0) {
1029 clunk_fid(s, fid);
1030 goto out;
1031 }
1032 err += offset;
1033
1034 memcpy(&s->root_qid, &qid, sizeof(qid));
1035 trace_v9fs_attach_return(pdu->tag, pdu->id,
1036 qid.type, qid.version, qid.path);
1037out:
1038 put_fid(pdu, fidp);
1039out_nofid:
1040 pdu_complete(pdu, err);
1041 v9fs_string_free(&uname);
1042 v9fs_string_free(&aname);
1043}
1044
1045static void coroutine_fn v9fs_stat(void *opaque)
1046{
1047 int32_t fid;
1048 V9fsStat v9stat;
1049 ssize_t err = 0;
1050 size_t offset = 7;
1051 struct stat stbuf;
1052 V9fsFidState *fidp;
1053 V9fsPDU *pdu = opaque;
1054 char *basename;
1055
1056 err = pdu_unmarshal(pdu, offset, "d", &fid);
1057 if (err < 0) {
1058 goto out_nofid;
1059 }
1060 trace_v9fs_stat(pdu->tag, pdu->id, fid);
1061
1062 fidp = get_fid(pdu, fid);
1063 if (fidp == NULL) {
1064 err = -ENOENT;
1065 goto out_nofid;
1066 }
1067 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1068 if (err < 0) {
1069 goto out;
1070 }
1071 basename = g_path_get_basename(fidp->path.data);
1072 err = stat_to_v9stat(pdu, &fidp->path, basename, &stbuf, &v9stat);
1073 g_free(basename);
1074 if (err < 0) {
1075 goto out;
1076 }
1077 err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1078 if (err < 0) {
1079 v9fs_stat_free(&v9stat);
1080 goto out;
1081 }
1082 trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
1083 v9stat.atime, v9stat.mtime, v9stat.length);
1084 err += offset;
1085 v9fs_stat_free(&v9stat);
1086out:
1087 put_fid(pdu, fidp);
1088out_nofid:
1089 pdu_complete(pdu, err);
1090}
1091
1092static void coroutine_fn v9fs_getattr(void *opaque)
1093{
1094 int32_t fid;
1095 size_t offset = 7;
1096 ssize_t retval = 0;
1097 struct stat stbuf;
1098 V9fsFidState *fidp;
1099 uint64_t request_mask;
1100 V9fsStatDotl v9stat_dotl;
1101 V9fsPDU *pdu = opaque;
1102 V9fsState *s = pdu->s;
1103
1104 retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1105 if (retval < 0) {
1106 goto out_nofid;
1107 }
1108 trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
1109
1110 fidp = get_fid(pdu, fid);
1111 if (fidp == NULL) {
1112 retval = -ENOENT;
1113 goto out_nofid;
1114 }
1115
1116
1117
1118
1119 retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1120 if (retval < 0) {
1121 goto out;
1122 }
1123 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1124
1125
1126 if (request_mask & P9_STATS_GEN) {
1127 retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
1128 switch (retval) {
1129 case 0:
1130
1131 v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1132 break;
1133 case -EINTR:
1134
1135 goto out;
1136 default:
1137
1138 break;
1139 }
1140 }
1141 retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1142 if (retval < 0) {
1143 goto out;
1144 }
1145 retval += offset;
1146 trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1147 v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1148 v9stat_dotl.st_gid);
1149out:
1150 put_fid(pdu, fidp);
1151out_nofid:
1152 pdu_complete(pdu, retval);
1153}
1154
1155
1156#define P9_ATTR_MODE (1 << 0)
1157#define P9_ATTR_UID (1 << 1)
1158#define P9_ATTR_GID (1 << 2)
1159#define P9_ATTR_SIZE (1 << 3)
1160#define P9_ATTR_ATIME (1 << 4)
1161#define P9_ATTR_MTIME (1 << 5)
1162#define P9_ATTR_CTIME (1 << 6)
1163#define P9_ATTR_ATIME_SET (1 << 7)
1164#define P9_ATTR_MTIME_SET (1 << 8)
1165
1166#define P9_ATTR_MASK 127
1167
1168static void coroutine_fn v9fs_setattr(void *opaque)
1169{
1170 int err = 0;
1171 int32_t fid;
1172 V9fsFidState *fidp;
1173 size_t offset = 7;
1174 V9fsIattr v9iattr;
1175 V9fsPDU *pdu = opaque;
1176
1177 err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1178 if (err < 0) {
1179 goto out_nofid;
1180 }
1181
1182 fidp = get_fid(pdu, fid);
1183 if (fidp == NULL) {
1184 err = -EINVAL;
1185 goto out_nofid;
1186 }
1187 if (v9iattr.valid & P9_ATTR_MODE) {
1188 err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
1189 if (err < 0) {
1190 goto out;
1191 }
1192 }
1193 if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) {
1194 struct timespec times[2];
1195 if (v9iattr.valid & P9_ATTR_ATIME) {
1196 if (v9iattr.valid & P9_ATTR_ATIME_SET) {
1197 times[0].tv_sec = v9iattr.atime_sec;
1198 times[0].tv_nsec = v9iattr.atime_nsec;
1199 } else {
1200 times[0].tv_nsec = UTIME_NOW;
1201 }
1202 } else {
1203 times[0].tv_nsec = UTIME_OMIT;
1204 }
1205 if (v9iattr.valid & P9_ATTR_MTIME) {
1206 if (v9iattr.valid & P9_ATTR_MTIME_SET) {
1207 times[1].tv_sec = v9iattr.mtime_sec;
1208 times[1].tv_nsec = v9iattr.mtime_nsec;
1209 } else {
1210 times[1].tv_nsec = UTIME_NOW;
1211 }
1212 } else {
1213 times[1].tv_nsec = UTIME_OMIT;
1214 }
1215 err = v9fs_co_utimensat(pdu, &fidp->path, times);
1216 if (err < 0) {
1217 goto out;
1218 }
1219 }
1220
1221
1222
1223
1224 if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) ||
1225 ((v9iattr.valid & P9_ATTR_CTIME)
1226 && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) {
1227 if (!(v9iattr.valid & P9_ATTR_UID)) {
1228 v9iattr.uid = -1;
1229 }
1230 if (!(v9iattr.valid & P9_ATTR_GID)) {
1231 v9iattr.gid = -1;
1232 }
1233 err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
1234 v9iattr.gid);
1235 if (err < 0) {
1236 goto out;
1237 }
1238 }
1239 if (v9iattr.valid & (P9_ATTR_SIZE)) {
1240 err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
1241 if (err < 0) {
1242 goto out;
1243 }
1244 }
1245 err = offset;
1246out:
1247 put_fid(pdu, fidp);
1248out_nofid:
1249 pdu_complete(pdu, err);
1250}
1251
1252static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1253{
1254 int i;
1255 ssize_t err;
1256 size_t offset = 7;
1257
1258 err = pdu_marshal(pdu, offset, "w", nwnames);
1259 if (err < 0) {
1260 return err;
1261 }
1262 offset += err;
1263 for (i = 0; i < nwnames; i++) {
1264 err = pdu_marshal(pdu, offset, "Q", &qids[i]);
1265 if (err < 0) {
1266 return err;
1267 }
1268 offset += err;
1269 }
1270 return offset;
1271}
1272
1273static bool name_is_illegal(const char *name)
1274{
1275 return !*name || strchr(name, '/') != NULL;
1276}
1277
1278static bool not_same_qid(const V9fsQID *qid1, const V9fsQID *qid2)
1279{
1280 return
1281 qid1->type != qid2->type ||
1282 qid1->version != qid2->version ||
1283 qid1->path != qid2->path;
1284}
1285
1286static void coroutine_fn v9fs_walk(void *opaque)
1287{
1288 int name_idx;
1289 V9fsQID *qids = NULL;
1290 int i, err = 0;
1291 V9fsPath dpath, path;
1292 uint16_t nwnames;
1293 struct stat stbuf;
1294 size_t offset = 7;
1295 int32_t fid, newfid;
1296 V9fsString *wnames = NULL;
1297 V9fsFidState *fidp;
1298 V9fsFidState *newfidp = NULL;
1299 V9fsPDU *pdu = opaque;
1300 V9fsState *s = pdu->s;
1301 V9fsQID qid;
1302
1303 err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
1304 if (err < 0) {
1305 pdu_complete(pdu, err);
1306 return ;
1307 }
1308 offset += err;
1309
1310 trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1311
1312 if (nwnames && nwnames <= P9_MAXWELEM) {
1313 wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1314 qids = g_malloc0(sizeof(qids[0]) * nwnames);
1315 for (i = 0; i < nwnames; i++) {
1316 err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1317 if (err < 0) {
1318 goto out_nofid;
1319 }
1320 if (name_is_illegal(wnames[i].data)) {
1321 err = -ENOENT;
1322 goto out_nofid;
1323 }
1324 offset += err;
1325 }
1326 } else if (nwnames > P9_MAXWELEM) {
1327 err = -EINVAL;
1328 goto out_nofid;
1329 }
1330 fidp = get_fid(pdu, fid);
1331 if (fidp == NULL) {
1332 err = -ENOENT;
1333 goto out_nofid;
1334 }
1335
1336 v9fs_path_init(&dpath);
1337 v9fs_path_init(&path);
1338
1339 err = fid_to_qid(pdu, fidp, &qid);
1340 if (err < 0) {
1341 goto out;
1342 }
1343
1344
1345
1346
1347
1348 v9fs_path_copy(&dpath, &fidp->path);
1349 v9fs_path_copy(&path, &fidp->path);
1350 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1351 if (not_same_qid(&pdu->s->root_qid, &qid) ||
1352 strcmp("..", wnames[name_idx].data)) {
1353 err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data,
1354 &path);
1355 if (err < 0) {
1356 goto out;
1357 }
1358
1359 err = v9fs_co_lstat(pdu, &path, &stbuf);
1360 if (err < 0) {
1361 goto out;
1362 }
1363 stat_to_qid(&stbuf, &qid);
1364 v9fs_path_copy(&dpath, &path);
1365 }
1366 memcpy(&qids[name_idx], &qid, sizeof(qid));
1367 }
1368 if (fid == newfid) {
1369 if (fidp->fid_type != P9_FID_NONE) {
1370 err = -EINVAL;
1371 goto out;
1372 }
1373 v9fs_path_copy(&fidp->path, &path);
1374 } else {
1375 newfidp = alloc_fid(s, newfid);
1376 if (newfidp == NULL) {
1377 err = -EINVAL;
1378 goto out;
1379 }
1380 newfidp->uid = fidp->uid;
1381 v9fs_path_copy(&newfidp->path, &path);
1382 }
1383 err = v9fs_walk_marshal(pdu, nwnames, qids);
1384 trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
1385out:
1386 put_fid(pdu, fidp);
1387 if (newfidp) {
1388 put_fid(pdu, newfidp);
1389 }
1390 v9fs_path_free(&dpath);
1391 v9fs_path_free(&path);
1392out_nofid:
1393 pdu_complete(pdu, err);
1394 if (nwnames && nwnames <= P9_MAXWELEM) {
1395 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1396 v9fs_string_free(&wnames[name_idx]);
1397 }
1398 g_free(wnames);
1399 g_free(qids);
1400 }
1401}
1402
1403static int32_t coroutine_fn get_iounit(V9fsPDU *pdu, V9fsPath *path)
1404{
1405 struct statfs stbuf;
1406 int32_t iounit = 0;
1407 V9fsState *s = pdu->s;
1408
1409
1410
1411
1412
1413 if (!v9fs_co_statfs(pdu, path, &stbuf)) {
1414 iounit = stbuf.f_bsize;
1415 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1416 }
1417 if (!iounit) {
1418 iounit = s->msize - P9_IOHDRSZ;
1419 }
1420 return iounit;
1421}
1422
1423static void coroutine_fn v9fs_open(void *opaque)
1424{
1425 int flags;
1426 int32_t fid;
1427 int32_t mode;
1428 V9fsQID qid;
1429 int iounit = 0;
1430 ssize_t err = 0;
1431 size_t offset = 7;
1432 struct stat stbuf;
1433 V9fsFidState *fidp;
1434 V9fsPDU *pdu = opaque;
1435 V9fsState *s = pdu->s;
1436
1437 if (s->proto_version == V9FS_PROTO_2000L) {
1438 err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1439 } else {
1440 uint8_t modebyte;
1441 err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
1442 mode = modebyte;
1443 }
1444 if (err < 0) {
1445 goto out_nofid;
1446 }
1447 trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1448
1449 fidp = get_fid(pdu, fid);
1450 if (fidp == NULL) {
1451 err = -ENOENT;
1452 goto out_nofid;
1453 }
1454 if (fidp->fid_type != P9_FID_NONE) {
1455 err = -EINVAL;
1456 goto out;
1457 }
1458
1459 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1460 if (err < 0) {
1461 goto out;
1462 }
1463 stat_to_qid(&stbuf, &qid);
1464 if (S_ISDIR(stbuf.st_mode)) {
1465 err = v9fs_co_opendir(pdu, fidp);
1466 if (err < 0) {
1467 goto out;
1468 }
1469 fidp->fid_type = P9_FID_DIR;
1470 err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
1471 if (err < 0) {
1472 goto out;
1473 }
1474 err += offset;
1475 } else {
1476 if (s->proto_version == V9FS_PROTO_2000L) {
1477 flags = get_dotl_openflags(s, mode);
1478 } else {
1479 flags = omode_to_uflags(mode);
1480 }
1481 if (is_ro_export(&s->ctx)) {
1482 if (mode & O_WRONLY || mode & O_RDWR ||
1483 mode & O_APPEND || mode & O_TRUNC) {
1484 err = -EROFS;
1485 goto out;
1486 }
1487 }
1488 err = v9fs_co_open(pdu, fidp, flags);
1489 if (err < 0) {
1490 goto out;
1491 }
1492 fidp->fid_type = P9_FID_FILE;
1493 fidp->open_flags = flags;
1494 if (flags & O_EXCL) {
1495
1496
1497
1498
1499 fidp->flags |= FID_NON_RECLAIMABLE;
1500 }
1501 iounit = get_iounit(pdu, &fidp->path);
1502 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1503 if (err < 0) {
1504 goto out;
1505 }
1506 err += offset;
1507 }
1508 trace_v9fs_open_return(pdu->tag, pdu->id,
1509 qid.type, qid.version, qid.path, iounit);
1510out:
1511 put_fid(pdu, fidp);
1512out_nofid:
1513 pdu_complete(pdu, err);
1514}
1515
1516static void coroutine_fn v9fs_lcreate(void *opaque)
1517{
1518 int32_t dfid, flags, mode;
1519 gid_t gid;
1520 ssize_t err = 0;
1521 ssize_t offset = 7;
1522 V9fsString name;
1523 V9fsFidState *fidp;
1524 struct stat stbuf;
1525 V9fsQID qid;
1526 int32_t iounit;
1527 V9fsPDU *pdu = opaque;
1528
1529 v9fs_string_init(&name);
1530 err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
1531 &name, &flags, &mode, &gid);
1532 if (err < 0) {
1533 goto out_nofid;
1534 }
1535 trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
1536
1537 if (name_is_illegal(name.data)) {
1538 err = -ENOENT;
1539 goto out_nofid;
1540 }
1541
1542 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
1543 err = -EEXIST;
1544 goto out_nofid;
1545 }
1546
1547 fidp = get_fid(pdu, dfid);
1548 if (fidp == NULL) {
1549 err = -ENOENT;
1550 goto out_nofid;
1551 }
1552 if (fidp->fid_type != P9_FID_NONE) {
1553 err = -EINVAL;
1554 goto out;
1555 }
1556
1557 flags = get_dotl_openflags(pdu->s, flags);
1558 err = v9fs_co_open2(pdu, fidp, &name, gid,
1559 flags | O_CREAT, mode, &stbuf);
1560 if (err < 0) {
1561 goto out;
1562 }
1563 fidp->fid_type = P9_FID_FILE;
1564 fidp->open_flags = flags;
1565 if (flags & O_EXCL) {
1566
1567
1568
1569
1570 fidp->flags |= FID_NON_RECLAIMABLE;
1571 }
1572 iounit = get_iounit(pdu, &fidp->path);
1573 stat_to_qid(&stbuf, &qid);
1574 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1575 if (err < 0) {
1576 goto out;
1577 }
1578 err += offset;
1579 trace_v9fs_lcreate_return(pdu->tag, pdu->id,
1580 qid.type, qid.version, qid.path, iounit);
1581out:
1582 put_fid(pdu, fidp);
1583out_nofid:
1584 pdu_complete(pdu, err);
1585 v9fs_string_free(&name);
1586}
1587
1588static void coroutine_fn v9fs_fsync(void *opaque)
1589{
1590 int err;
1591 int32_t fid;
1592 int datasync;
1593 size_t offset = 7;
1594 V9fsFidState *fidp;
1595 V9fsPDU *pdu = opaque;
1596
1597 err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1598 if (err < 0) {
1599 goto out_nofid;
1600 }
1601 trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
1602
1603 fidp = get_fid(pdu, fid);
1604 if (fidp == NULL) {
1605 err = -ENOENT;
1606 goto out_nofid;
1607 }
1608 err = v9fs_co_fsync(pdu, fidp, datasync);
1609 if (!err) {
1610 err = offset;
1611 }
1612 put_fid(pdu, fidp);
1613out_nofid:
1614 pdu_complete(pdu, err);
1615}
1616
1617static void coroutine_fn v9fs_clunk(void *opaque)
1618{
1619 int err;
1620 int32_t fid;
1621 size_t offset = 7;
1622 V9fsFidState *fidp;
1623 V9fsPDU *pdu = opaque;
1624 V9fsState *s = pdu->s;
1625
1626 err = pdu_unmarshal(pdu, offset, "d", &fid);
1627 if (err < 0) {
1628 goto out_nofid;
1629 }
1630 trace_v9fs_clunk(pdu->tag, pdu->id, fid);
1631
1632 fidp = clunk_fid(s, fid);
1633 if (fidp == NULL) {
1634 err = -ENOENT;
1635 goto out_nofid;
1636 }
1637
1638
1639
1640
1641 fidp->ref++;
1642 err = put_fid(pdu, fidp);
1643 if (!err) {
1644 err = offset;
1645 }
1646out_nofid:
1647 pdu_complete(pdu, err);
1648}
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
1662 size_t skip, size_t size,
1663 bool is_write)
1664{
1665 QEMUIOVector elem;
1666 struct iovec *iov;
1667 unsigned int niov;
1668
1669 if (is_write) {
1670 pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip);
1671 } else {
1672 pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
1673 }
1674
1675 qemu_iovec_init_external(&elem, iov, niov);
1676 qemu_iovec_init(qiov, niov);
1677 qemu_iovec_concat(qiov, &elem, skip, size);
1678}
1679
1680static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1681 uint64_t off, uint32_t max_count)
1682{
1683 ssize_t err;
1684 size_t offset = 7;
1685 uint64_t read_count;
1686 QEMUIOVector qiov_full;
1687
1688 if (fidp->fs.xattr.len < off) {
1689 read_count = 0;
1690 } else {
1691 read_count = fidp->fs.xattr.len - off;
1692 }
1693 if (read_count > max_count) {
1694 read_count = max_count;
1695 }
1696 err = pdu_marshal(pdu, offset, "d", read_count);
1697 if (err < 0) {
1698 return err;
1699 }
1700 offset += err;
1701
1702 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, read_count, false);
1703 err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0,
1704 ((char *)fidp->fs.xattr.value) + off,
1705 read_count);
1706 qemu_iovec_destroy(&qiov_full);
1707 if (err < 0) {
1708 return err;
1709 }
1710 offset += err;
1711 return offset;
1712}
1713
1714static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu,
1715 V9fsFidState *fidp,
1716 uint32_t max_count)
1717{
1718 V9fsPath path;
1719 V9fsStat v9stat;
1720 int len, err = 0;
1721 int32_t count = 0;
1722 struct stat stbuf;
1723 off_t saved_dir_pos;
1724 struct dirent *dent;
1725
1726
1727 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1728 if (saved_dir_pos < 0) {
1729 return saved_dir_pos;
1730 }
1731
1732 while (1) {
1733 v9fs_path_init(&path);
1734
1735 v9fs_readdir_lock(&fidp->fs.dir);
1736
1737 err = v9fs_co_readdir(pdu, fidp, &dent);
1738 if (err || !dent) {
1739 break;
1740 }
1741 err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
1742 if (err < 0) {
1743 break;
1744 }
1745 err = v9fs_co_lstat(pdu, &path, &stbuf);
1746 if (err < 0) {
1747 break;
1748 }
1749 err = stat_to_v9stat(pdu, &path, dent->d_name, &stbuf, &v9stat);
1750 if (err < 0) {
1751 break;
1752 }
1753 if ((count + v9stat.size + 2) > max_count) {
1754 v9fs_readdir_unlock(&fidp->fs.dir);
1755
1756
1757 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1758 v9fs_stat_free(&v9stat);
1759 v9fs_path_free(&path);
1760 return count;
1761 }
1762
1763
1764 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1765
1766 v9fs_readdir_unlock(&fidp->fs.dir);
1767
1768 if (len < 0) {
1769 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1770 v9fs_stat_free(&v9stat);
1771 v9fs_path_free(&path);
1772 return len;
1773 }
1774 count += len;
1775 v9fs_stat_free(&v9stat);
1776 v9fs_path_free(&path);
1777 saved_dir_pos = dent->d_off;
1778 }
1779
1780 v9fs_readdir_unlock(&fidp->fs.dir);
1781
1782 v9fs_path_free(&path);
1783 if (err < 0) {
1784 return err;
1785 }
1786 return count;
1787}
1788
1789static void coroutine_fn v9fs_read(void *opaque)
1790{
1791 int32_t fid;
1792 uint64_t off;
1793 ssize_t err = 0;
1794 int32_t count = 0;
1795 size_t offset = 7;
1796 uint32_t max_count;
1797 V9fsFidState *fidp;
1798 V9fsPDU *pdu = opaque;
1799 V9fsState *s = pdu->s;
1800
1801 err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1802 if (err < 0) {
1803 goto out_nofid;
1804 }
1805 trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
1806
1807 fidp = get_fid(pdu, fid);
1808 if (fidp == NULL) {
1809 err = -EINVAL;
1810 goto out_nofid;
1811 }
1812 if (fidp->fid_type == P9_FID_DIR) {
1813
1814 if (off == 0) {
1815 v9fs_co_rewinddir(pdu, fidp);
1816 }
1817 count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
1818 if (count < 0) {
1819 err = count;
1820 goto out;
1821 }
1822 err = pdu_marshal(pdu, offset, "d", count);
1823 if (err < 0) {
1824 goto out;
1825 }
1826 err += offset + count;
1827 } else if (fidp->fid_type == P9_FID_FILE) {
1828 QEMUIOVector qiov_full;
1829 QEMUIOVector qiov;
1830 int32_t len;
1831
1832 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
1833 qemu_iovec_init(&qiov, qiov_full.niov);
1834 do {
1835 qemu_iovec_reset(&qiov);
1836 qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
1837 if (0) {
1838 print_sg(qiov.iov, qiov.niov);
1839 }
1840
1841 do {
1842 len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
1843 if (len >= 0) {
1844 off += len;
1845 count += len;
1846 }
1847 } while (len == -EINTR && !pdu->cancelled);
1848 if (len < 0) {
1849
1850 err = len;
1851 goto out_free_iovec;
1852 }
1853 } while (count < max_count && len > 0);
1854 err = pdu_marshal(pdu, offset, "d", count);
1855 if (err < 0) {
1856 goto out_free_iovec;
1857 }
1858 err += offset + count;
1859out_free_iovec:
1860 qemu_iovec_destroy(&qiov);
1861 qemu_iovec_destroy(&qiov_full);
1862 } else if (fidp->fid_type == P9_FID_XATTR) {
1863 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1864 } else {
1865 err = -EINVAL;
1866 }
1867 trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
1868out:
1869 put_fid(pdu, fidp);
1870out_nofid:
1871 pdu_complete(pdu, err);
1872}
1873
1874static size_t v9fs_readdir_data_size(V9fsString *name)
1875{
1876
1877
1878
1879
1880 return 24 + v9fs_string_size(name);
1881}
1882
1883static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
1884 int32_t max_count)
1885{
1886 size_t size;
1887 V9fsQID qid;
1888 V9fsString name;
1889 int len, err = 0;
1890 int32_t count = 0;
1891 off_t saved_dir_pos;
1892 struct dirent *dent;
1893
1894
1895 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1896 if (saved_dir_pos < 0) {
1897 return saved_dir_pos;
1898 }
1899
1900 while (1) {
1901 v9fs_readdir_lock(&fidp->fs.dir);
1902
1903 err = v9fs_co_readdir(pdu, fidp, &dent);
1904 if (err || !dent) {
1905 break;
1906 }
1907 v9fs_string_init(&name);
1908 v9fs_string_sprintf(&name, "%s", dent->d_name);
1909 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1910 v9fs_readdir_unlock(&fidp->fs.dir);
1911
1912
1913 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1914 v9fs_string_free(&name);
1915 return count;
1916 }
1917
1918
1919
1920
1921
1922 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1923 memcpy(&qid.path, &dent->d_ino, size);
1924
1925 qid.type = 0;
1926 qid.version = 0;
1927
1928
1929 len = pdu_marshal(pdu, 11 + count, "Qqbs",
1930 &qid, dent->d_off,
1931 dent->d_type, &name);
1932
1933 v9fs_readdir_unlock(&fidp->fs.dir);
1934
1935 if (len < 0) {
1936 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1937 v9fs_string_free(&name);
1938 return len;
1939 }
1940 count += len;
1941 v9fs_string_free(&name);
1942 saved_dir_pos = dent->d_off;
1943 }
1944
1945 v9fs_readdir_unlock(&fidp->fs.dir);
1946
1947 if (err < 0) {
1948 return err;
1949 }
1950 return count;
1951}
1952
1953static void coroutine_fn v9fs_readdir(void *opaque)
1954{
1955 int32_t fid;
1956 V9fsFidState *fidp;
1957 ssize_t retval = 0;
1958 size_t offset = 7;
1959 uint64_t initial_offset;
1960 int32_t count;
1961 uint32_t max_count;
1962 V9fsPDU *pdu = opaque;
1963
1964 retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
1965 &initial_offset, &max_count);
1966 if (retval < 0) {
1967 goto out_nofid;
1968 }
1969 trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
1970
1971 fidp = get_fid(pdu, fid);
1972 if (fidp == NULL) {
1973 retval = -EINVAL;
1974 goto out_nofid;
1975 }
1976 if (!fidp->fs.dir.stream) {
1977 retval = -EINVAL;
1978 goto out;
1979 }
1980 if (initial_offset == 0) {
1981 v9fs_co_rewinddir(pdu, fidp);
1982 } else {
1983 v9fs_co_seekdir(pdu, fidp, initial_offset);
1984 }
1985 count = v9fs_do_readdir(pdu, fidp, max_count);
1986 if (count < 0) {
1987 retval = count;
1988 goto out;
1989 }
1990 retval = pdu_marshal(pdu, offset, "d", count);
1991 if (retval < 0) {
1992 goto out;
1993 }
1994 retval += count + offset;
1995 trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
1996out:
1997 put_fid(pdu, fidp);
1998out_nofid:
1999 pdu_complete(pdu, retval);
2000}
2001
2002static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
2003 uint64_t off, uint32_t count,
2004 struct iovec *sg, int cnt)
2005{
2006 int i, to_copy;
2007 ssize_t err = 0;
2008 uint64_t write_count;
2009 size_t offset = 7;
2010
2011
2012 if (fidp->fs.xattr.len < off) {
2013 err = -ENOSPC;
2014 goto out;
2015 }
2016 write_count = fidp->fs.xattr.len - off;
2017 if (write_count > count) {
2018 write_count = count;
2019 }
2020 err = pdu_marshal(pdu, offset, "d", write_count);
2021 if (err < 0) {
2022 return err;
2023 }
2024 err += offset;
2025 fidp->fs.xattr.copied_len += write_count;
2026
2027
2028
2029 for (i = 0; i < cnt; i++) {
2030 if (write_count > sg[i].iov_len) {
2031 to_copy = sg[i].iov_len;
2032 } else {
2033 to_copy = write_count;
2034 }
2035 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
2036
2037 off += to_copy;
2038 write_count -= to_copy;
2039 }
2040out:
2041 return err;
2042}
2043
2044static void coroutine_fn v9fs_write(void *opaque)
2045{
2046 ssize_t err;
2047 int32_t fid;
2048 uint64_t off;
2049 uint32_t count;
2050 int32_t len = 0;
2051 int32_t total = 0;
2052 size_t offset = 7;
2053 V9fsFidState *fidp;
2054 V9fsPDU *pdu = opaque;
2055 V9fsState *s = pdu->s;
2056 QEMUIOVector qiov_full;
2057 QEMUIOVector qiov;
2058
2059 err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
2060 if (err < 0) {
2061 pdu_complete(pdu, err);
2062 return;
2063 }
2064 offset += err;
2065 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
2066 trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
2067
2068 fidp = get_fid(pdu, fid);
2069 if (fidp == NULL) {
2070 err = -EINVAL;
2071 goto out_nofid;
2072 }
2073 if (fidp->fid_type == P9_FID_FILE) {
2074 if (fidp->fs.fd == -1) {
2075 err = -EINVAL;
2076 goto out;
2077 }
2078 } else if (fidp->fid_type == P9_FID_XATTR) {
2079
2080
2081
2082 err = v9fs_xattr_write(s, pdu, fidp, off, count,
2083 qiov_full.iov, qiov_full.niov);
2084 goto out;
2085 } else {
2086 err = -EINVAL;
2087 goto out;
2088 }
2089 qemu_iovec_init(&qiov, qiov_full.niov);
2090 do {
2091 qemu_iovec_reset(&qiov);
2092 qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total);
2093 if (0) {
2094 print_sg(qiov.iov, qiov.niov);
2095 }
2096
2097 do {
2098 len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
2099 if (len >= 0) {
2100 off += len;
2101 total += len;
2102 }
2103 } while (len == -EINTR && !pdu->cancelled);
2104 if (len < 0) {
2105
2106 err = len;
2107 goto out_qiov;
2108 }
2109 } while (total < count && len > 0);
2110
2111 offset = 7;
2112 err = pdu_marshal(pdu, offset, "d", total);
2113 if (err < 0) {
2114 goto out_qiov;
2115 }
2116 err += offset;
2117 trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
2118out_qiov:
2119 qemu_iovec_destroy(&qiov);
2120out:
2121 put_fid(pdu, fidp);
2122out_nofid:
2123 qemu_iovec_destroy(&qiov_full);
2124 pdu_complete(pdu, err);
2125}
2126
2127static void coroutine_fn v9fs_create(void *opaque)
2128{
2129 int32_t fid;
2130 int err = 0;
2131 size_t offset = 7;
2132 V9fsFidState *fidp;
2133 V9fsQID qid;
2134 int32_t perm;
2135 int8_t mode;
2136 V9fsPath path;
2137 struct stat stbuf;
2138 V9fsString name;
2139 V9fsString extension;
2140 int iounit;
2141 V9fsPDU *pdu = opaque;
2142
2143 v9fs_path_init(&path);
2144 v9fs_string_init(&name);
2145 v9fs_string_init(&extension);
2146 err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2147 &perm, &mode, &extension);
2148 if (err < 0) {
2149 goto out_nofid;
2150 }
2151 trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2152
2153 if (name_is_illegal(name.data)) {
2154 err = -ENOENT;
2155 goto out_nofid;
2156 }
2157
2158 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2159 err = -EEXIST;
2160 goto out_nofid;
2161 }
2162
2163 fidp = get_fid(pdu, fid);
2164 if (fidp == NULL) {
2165 err = -EINVAL;
2166 goto out_nofid;
2167 }
2168 if (fidp->fid_type != P9_FID_NONE) {
2169 err = -EINVAL;
2170 goto out;
2171 }
2172 if (perm & P9_STAT_MODE_DIR) {
2173 err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
2174 fidp->uid, -1, &stbuf);
2175 if (err < 0) {
2176 goto out;
2177 }
2178 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2179 if (err < 0) {
2180 goto out;
2181 }
2182 v9fs_path_copy(&fidp->path, &path);
2183 err = v9fs_co_opendir(pdu, fidp);
2184 if (err < 0) {
2185 goto out;
2186 }
2187 fidp->fid_type = P9_FID_DIR;
2188 } else if (perm & P9_STAT_MODE_SYMLINK) {
2189 err = v9fs_co_symlink(pdu, fidp, &name,
2190 extension.data, -1 , &stbuf);
2191 if (err < 0) {
2192 goto out;
2193 }
2194 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2195 if (err < 0) {
2196 goto out;
2197 }
2198 v9fs_path_copy(&fidp->path, &path);
2199 } else if (perm & P9_STAT_MODE_LINK) {
2200 int32_t ofid = atoi(extension.data);
2201 V9fsFidState *ofidp = get_fid(pdu, ofid);
2202 if (ofidp == NULL) {
2203 err = -EINVAL;
2204 goto out;
2205 }
2206 err = v9fs_co_link(pdu, ofidp, fidp, &name);
2207 put_fid(pdu, ofidp);
2208 if (err < 0) {
2209 goto out;
2210 }
2211 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2212 if (err < 0) {
2213 fidp->fid_type = P9_FID_NONE;
2214 goto out;
2215 }
2216 v9fs_path_copy(&fidp->path, &path);
2217 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2218 if (err < 0) {
2219 fidp->fid_type = P9_FID_NONE;
2220 goto out;
2221 }
2222 } else if (perm & P9_STAT_MODE_DEVICE) {
2223 char ctype;
2224 uint32_t major, minor;
2225 mode_t nmode = 0;
2226
2227 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2228 err = -errno;
2229 goto out;
2230 }
2231
2232 switch (ctype) {
2233 case 'c':
2234 nmode = S_IFCHR;
2235 break;
2236 case 'b':
2237 nmode = S_IFBLK;
2238 break;
2239 default:
2240 err = -EIO;
2241 goto out;
2242 }
2243
2244 nmode |= perm & 0777;
2245 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2246 makedev(major, minor), nmode, &stbuf);
2247 if (err < 0) {
2248 goto out;
2249 }
2250 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2251 if (err < 0) {
2252 goto out;
2253 }
2254 v9fs_path_copy(&fidp->path, &path);
2255 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2256 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2257 0, S_IFIFO | (perm & 0777), &stbuf);
2258 if (err < 0) {
2259 goto out;
2260 }
2261 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2262 if (err < 0) {
2263 goto out;
2264 }
2265 v9fs_path_copy(&fidp->path, &path);
2266 } else if (perm & P9_STAT_MODE_SOCKET) {
2267 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2268 0, S_IFSOCK | (perm & 0777), &stbuf);
2269 if (err < 0) {
2270 goto out;
2271 }
2272 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2273 if (err < 0) {
2274 goto out;
2275 }
2276 v9fs_path_copy(&fidp->path, &path);
2277 } else {
2278 err = v9fs_co_open2(pdu, fidp, &name, -1,
2279 omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
2280 if (err < 0) {
2281 goto out;
2282 }
2283 fidp->fid_type = P9_FID_FILE;
2284 fidp->open_flags = omode_to_uflags(mode);
2285 if (fidp->open_flags & O_EXCL) {
2286
2287
2288
2289
2290 fidp->flags |= FID_NON_RECLAIMABLE;
2291 }
2292 }
2293 iounit = get_iounit(pdu, &fidp->path);
2294 stat_to_qid(&stbuf, &qid);
2295 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2296 if (err < 0) {
2297 goto out;
2298 }
2299 err += offset;
2300 trace_v9fs_create_return(pdu->tag, pdu->id,
2301 qid.type, qid.version, qid.path, iounit);
2302out:
2303 put_fid(pdu, fidp);
2304out_nofid:
2305 pdu_complete(pdu, err);
2306 v9fs_string_free(&name);
2307 v9fs_string_free(&extension);
2308 v9fs_path_free(&path);
2309}
2310
2311static void coroutine_fn v9fs_symlink(void *opaque)
2312{
2313 V9fsPDU *pdu = opaque;
2314 V9fsString name;
2315 V9fsString symname;
2316 V9fsFidState *dfidp;
2317 V9fsQID qid;
2318 struct stat stbuf;
2319 int32_t dfid;
2320 int err = 0;
2321 gid_t gid;
2322 size_t offset = 7;
2323
2324 v9fs_string_init(&name);
2325 v9fs_string_init(&symname);
2326 err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2327 if (err < 0) {
2328 goto out_nofid;
2329 }
2330 trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
2331
2332 if (name_is_illegal(name.data)) {
2333 err = -ENOENT;
2334 goto out_nofid;
2335 }
2336
2337 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2338 err = -EEXIST;
2339 goto out_nofid;
2340 }
2341
2342 dfidp = get_fid(pdu, dfid);
2343 if (dfidp == NULL) {
2344 err = -EINVAL;
2345 goto out_nofid;
2346 }
2347 err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
2348 if (err < 0) {
2349 goto out;
2350 }
2351 stat_to_qid(&stbuf, &qid);
2352 err = pdu_marshal(pdu, offset, "Q", &qid);
2353 if (err < 0) {
2354 goto out;
2355 }
2356 err += offset;
2357 trace_v9fs_symlink_return(pdu->tag, pdu->id,
2358 qid.type, qid.version, qid.path);
2359out:
2360 put_fid(pdu, dfidp);
2361out_nofid:
2362 pdu_complete(pdu, err);
2363 v9fs_string_free(&name);
2364 v9fs_string_free(&symname);
2365}
2366
2367static void coroutine_fn v9fs_flush(void *opaque)
2368{
2369 ssize_t err;
2370 int16_t tag;
2371 size_t offset = 7;
2372 V9fsPDU *cancel_pdu = NULL;
2373 V9fsPDU *pdu = opaque;
2374 V9fsState *s = pdu->s;
2375
2376 err = pdu_unmarshal(pdu, offset, "w", &tag);
2377 if (err < 0) {
2378 pdu_complete(pdu, err);
2379 return;
2380 }
2381 trace_v9fs_flush(pdu->tag, pdu->id, tag);
2382
2383 if (pdu->tag == tag) {
2384 warn_report("the guest sent a self-referencing 9P flush request");
2385 } else {
2386 QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2387 if (cancel_pdu->tag == tag) {
2388 break;
2389 }
2390 }
2391 }
2392 if (cancel_pdu) {
2393 cancel_pdu->cancelled = 1;
2394
2395
2396
2397 qemu_co_queue_wait(&cancel_pdu->complete, NULL);
2398 if (!qemu_co_queue_next(&cancel_pdu->complete)) {
2399 cancel_pdu->cancelled = 0;
2400 pdu_free(cancel_pdu);
2401 }
2402 }
2403 pdu_complete(pdu, 7);
2404}
2405
2406static void coroutine_fn v9fs_link(void *opaque)
2407{
2408 V9fsPDU *pdu = opaque;
2409 int32_t dfid, oldfid;
2410 V9fsFidState *dfidp, *oldfidp;
2411 V9fsString name;
2412 size_t offset = 7;
2413 int err = 0;
2414
2415 v9fs_string_init(&name);
2416 err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2417 if (err < 0) {
2418 goto out_nofid;
2419 }
2420 trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
2421
2422 if (name_is_illegal(name.data)) {
2423 err = -ENOENT;
2424 goto out_nofid;
2425 }
2426
2427 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2428 err = -EEXIST;
2429 goto out_nofid;
2430 }
2431
2432 dfidp = get_fid(pdu, dfid);
2433 if (dfidp == NULL) {
2434 err = -ENOENT;
2435 goto out_nofid;
2436 }
2437
2438 oldfidp = get_fid(pdu, oldfid);
2439 if (oldfidp == NULL) {
2440 err = -ENOENT;
2441 goto out;
2442 }
2443 err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
2444 if (!err) {
2445 err = offset;
2446 }
2447 put_fid(pdu, oldfidp);
2448out:
2449 put_fid(pdu, dfidp);
2450out_nofid:
2451 v9fs_string_free(&name);
2452 pdu_complete(pdu, err);
2453}
2454
2455
2456static void coroutine_fn v9fs_remove(void *opaque)
2457{
2458 int32_t fid;
2459 int err = 0;
2460 size_t offset = 7;
2461 V9fsFidState *fidp;
2462 V9fsPDU *pdu = opaque;
2463
2464 err = pdu_unmarshal(pdu, offset, "d", &fid);
2465 if (err < 0) {
2466 goto out_nofid;
2467 }
2468 trace_v9fs_remove(pdu->tag, pdu->id, fid);
2469
2470 fidp = get_fid(pdu, fid);
2471 if (fidp == NULL) {
2472 err = -EINVAL;
2473 goto out_nofid;
2474 }
2475
2476 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2477 err = -EOPNOTSUPP;
2478 goto out_err;
2479 }
2480
2481
2482
2483
2484 err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
2485 if (err < 0) {
2486 goto out_err;
2487 }
2488 err = v9fs_co_remove(pdu, &fidp->path);
2489 if (!err) {
2490 err = offset;
2491 }
2492out_err:
2493
2494 clunk_fid(pdu->s, fidp->fid);
2495 put_fid(pdu, fidp);
2496out_nofid:
2497 pdu_complete(pdu, err);
2498}
2499
2500static void coroutine_fn v9fs_unlinkat(void *opaque)
2501{
2502 int err = 0;
2503 V9fsString name;
2504 int32_t dfid, flags;
2505 size_t offset = 7;
2506 V9fsPath path;
2507 V9fsFidState *dfidp;
2508 V9fsPDU *pdu = opaque;
2509
2510 v9fs_string_init(&name);
2511 err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2512 if (err < 0) {
2513 goto out_nofid;
2514 }
2515
2516 if (name_is_illegal(name.data)) {
2517 err = -ENOENT;
2518 goto out_nofid;
2519 }
2520
2521 if (!strcmp(".", name.data)) {
2522 err = -EINVAL;
2523 goto out_nofid;
2524 }
2525
2526 if (!strcmp("..", name.data)) {
2527 err = -ENOTEMPTY;
2528 goto out_nofid;
2529 }
2530
2531 dfidp = get_fid(pdu, dfid);
2532 if (dfidp == NULL) {
2533 err = -EINVAL;
2534 goto out_nofid;
2535 }
2536
2537
2538
2539
2540 v9fs_path_init(&path);
2541 err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
2542 if (err < 0) {
2543 goto out_err;
2544 }
2545 err = v9fs_mark_fids_unreclaim(pdu, &path);
2546 if (err < 0) {
2547 goto out_err;
2548 }
2549 err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
2550 if (!err) {
2551 err = offset;
2552 }
2553out_err:
2554 put_fid(pdu, dfidp);
2555 v9fs_path_free(&path);
2556out_nofid:
2557 pdu_complete(pdu, err);
2558 v9fs_string_free(&name);
2559}
2560
2561
2562
2563static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
2564 int32_t newdirfid,
2565 V9fsString *name)
2566{
2567 int err = 0;
2568 V9fsPath new_path;
2569 V9fsFidState *tfidp;
2570 V9fsState *s = pdu->s;
2571 V9fsFidState *dirfidp = NULL;
2572
2573 v9fs_path_init(&new_path);
2574 if (newdirfid != -1) {
2575 dirfidp = get_fid(pdu, newdirfid);
2576 if (dirfidp == NULL) {
2577 err = -ENOENT;
2578 goto out_nofid;
2579 }
2580 if (fidp->fid_type != P9_FID_NONE) {
2581 err = -EINVAL;
2582 goto out;
2583 }
2584 err = v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
2585 if (err < 0) {
2586 goto out;
2587 }
2588 } else {
2589 char *dir_name = g_path_get_dirname(fidp->path.data);
2590 V9fsPath dir_path;
2591
2592 v9fs_path_init(&dir_path);
2593 v9fs_path_sprintf(&dir_path, "%s", dir_name);
2594 g_free(dir_name);
2595
2596 err = v9fs_co_name_to_path(pdu, &dir_path, name->data, &new_path);
2597 v9fs_path_free(&dir_path);
2598 if (err < 0) {
2599 goto out;
2600 }
2601 }
2602 err = v9fs_co_rename(pdu, &fidp->path, &new_path);
2603 if (err < 0) {
2604 goto out;
2605 }
2606
2607
2608
2609
2610 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2611 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2612
2613 v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
2614 }
2615 }
2616out:
2617 if (dirfidp) {
2618 put_fid(pdu, dirfidp);
2619 }
2620 v9fs_path_free(&new_path);
2621out_nofid:
2622 return err;
2623}
2624
2625
2626static void coroutine_fn v9fs_rename(void *opaque)
2627{
2628 int32_t fid;
2629 ssize_t err = 0;
2630 size_t offset = 7;
2631 V9fsString name;
2632 int32_t newdirfid;
2633 V9fsFidState *fidp;
2634 V9fsPDU *pdu = opaque;
2635 V9fsState *s = pdu->s;
2636
2637 v9fs_string_init(&name);
2638 err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2639 if (err < 0) {
2640 goto out_nofid;
2641 }
2642
2643 if (name_is_illegal(name.data)) {
2644 err = -ENOENT;
2645 goto out_nofid;
2646 }
2647
2648 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2649 err = -EISDIR;
2650 goto out_nofid;
2651 }
2652
2653 fidp = get_fid(pdu, fid);
2654 if (fidp == NULL) {
2655 err = -ENOENT;
2656 goto out_nofid;
2657 }
2658 if (fidp->fid_type != P9_FID_NONE) {
2659 err = -EINVAL;
2660 goto out;
2661 }
2662
2663 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2664 err = -EOPNOTSUPP;
2665 goto out;
2666 }
2667 v9fs_path_write_lock(s);
2668 err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
2669 v9fs_path_unlock(s);
2670 if (!err) {
2671 err = offset;
2672 }
2673out:
2674 put_fid(pdu, fidp);
2675out_nofid:
2676 pdu_complete(pdu, err);
2677 v9fs_string_free(&name);
2678}
2679
2680static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
2681 V9fsString *old_name,
2682 V9fsPath *newdir,
2683 V9fsString *new_name)
2684{
2685 V9fsFidState *tfidp;
2686 V9fsPath oldpath, newpath;
2687 V9fsState *s = pdu->s;
2688 int err;
2689
2690 v9fs_path_init(&oldpath);
2691 v9fs_path_init(&newpath);
2692 err = v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
2693 if (err < 0) {
2694 goto out;
2695 }
2696 err = v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
2697 if (err < 0) {
2698 goto out;
2699 }
2700
2701
2702
2703
2704
2705 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2706 if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
2707
2708 v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
2709 }
2710 }
2711out:
2712 v9fs_path_free(&oldpath);
2713 v9fs_path_free(&newpath);
2714 return err;
2715}
2716
2717static int coroutine_fn v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
2718 V9fsString *old_name,
2719 int32_t newdirfid,
2720 V9fsString *new_name)
2721{
2722 int err = 0;
2723 V9fsState *s = pdu->s;
2724 V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2725
2726 olddirfidp = get_fid(pdu, olddirfid);
2727 if (olddirfidp == NULL) {
2728 err = -ENOENT;
2729 goto out;
2730 }
2731 if (newdirfid != -1) {
2732 newdirfidp = get_fid(pdu, newdirfid);
2733 if (newdirfidp == NULL) {
2734 err = -ENOENT;
2735 goto out;
2736 }
2737 } else {
2738 newdirfidp = get_fid(pdu, olddirfid);
2739 }
2740
2741 err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
2742 &newdirfidp->path, new_name);
2743 if (err < 0) {
2744 goto out;
2745 }
2746 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
2747
2748 err = v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
2749 &newdirfidp->path, new_name);
2750 }
2751out:
2752 if (olddirfidp) {
2753 put_fid(pdu, olddirfidp);
2754 }
2755 if (newdirfidp) {
2756 put_fid(pdu, newdirfidp);
2757 }
2758 return err;
2759}
2760
2761static void coroutine_fn v9fs_renameat(void *opaque)
2762{
2763 ssize_t err = 0;
2764 size_t offset = 7;
2765 V9fsPDU *pdu = opaque;
2766 V9fsState *s = pdu->s;
2767 int32_t olddirfid, newdirfid;
2768 V9fsString old_name, new_name;
2769
2770 v9fs_string_init(&old_name);
2771 v9fs_string_init(&new_name);
2772 err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2773 &old_name, &newdirfid, &new_name);
2774 if (err < 0) {
2775 goto out_err;
2776 }
2777
2778 if (name_is_illegal(old_name.data) || name_is_illegal(new_name.data)) {
2779 err = -ENOENT;
2780 goto out_err;
2781 }
2782
2783 if (!strcmp(".", old_name.data) || !strcmp("..", old_name.data) ||
2784 !strcmp(".", new_name.data) || !strcmp("..", new_name.data)) {
2785 err = -EISDIR;
2786 goto out_err;
2787 }
2788
2789 v9fs_path_write_lock(s);
2790 err = v9fs_complete_renameat(pdu, olddirfid,
2791 &old_name, newdirfid, &new_name);
2792 v9fs_path_unlock(s);
2793 if (!err) {
2794 err = offset;
2795 }
2796
2797out_err:
2798 pdu_complete(pdu, err);
2799 v9fs_string_free(&old_name);
2800 v9fs_string_free(&new_name);
2801}
2802
2803static void coroutine_fn v9fs_wstat(void *opaque)
2804{
2805 int32_t fid;
2806 int err = 0;
2807 int16_t unused;
2808 V9fsStat v9stat;
2809 size_t offset = 7;
2810 struct stat stbuf;
2811 V9fsFidState *fidp;
2812 V9fsPDU *pdu = opaque;
2813
2814 v9fs_stat_init(&v9stat);
2815 err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2816 if (err < 0) {
2817 goto out_nofid;
2818 }
2819 trace_v9fs_wstat(pdu->tag, pdu->id, fid,
2820 v9stat.mode, v9stat.atime, v9stat.mtime);
2821
2822 fidp = get_fid(pdu, fid);
2823 if (fidp == NULL) {
2824 err = -EINVAL;
2825 goto out_nofid;
2826 }
2827
2828 if (donttouch_stat(&v9stat)) {
2829 err = v9fs_co_fsync(pdu, fidp, 0);
2830 goto out;
2831 }
2832 if (v9stat.mode != -1) {
2833 uint32_t v9_mode;
2834 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2835 if (err < 0) {
2836 goto out;
2837 }
2838 v9_mode = stat_to_v9mode(&stbuf);
2839 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2840 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2841
2842 err = -EIO;
2843 goto out;
2844 }
2845 err = v9fs_co_chmod(pdu, &fidp->path,
2846 v9mode_to_mode(v9stat.mode,
2847 &v9stat.extension));
2848 if (err < 0) {
2849 goto out;
2850 }
2851 }
2852 if (v9stat.mtime != -1 || v9stat.atime != -1) {
2853 struct timespec times[2];
2854 if (v9stat.atime != -1) {
2855 times[0].tv_sec = v9stat.atime;
2856 times[0].tv_nsec = 0;
2857 } else {
2858 times[0].tv_nsec = UTIME_OMIT;
2859 }
2860 if (v9stat.mtime != -1) {
2861 times[1].tv_sec = v9stat.mtime;
2862 times[1].tv_nsec = 0;
2863 } else {
2864 times[1].tv_nsec = UTIME_OMIT;
2865 }
2866 err = v9fs_co_utimensat(pdu, &fidp->path, times);
2867 if (err < 0) {
2868 goto out;
2869 }
2870 }
2871 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2872 err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2873 if (err < 0) {
2874 goto out;
2875 }
2876 }
2877 if (v9stat.name.size != 0) {
2878 err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
2879 if (err < 0) {
2880 goto out;
2881 }
2882 }
2883 if (v9stat.length != -1) {
2884 err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
2885 if (err < 0) {
2886 goto out;
2887 }
2888 }
2889 err = offset;
2890out:
2891 put_fid(pdu, fidp);
2892out_nofid:
2893 v9fs_stat_free(&v9stat);
2894 pdu_complete(pdu, err);
2895}
2896
2897static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2898{
2899 uint32_t f_type;
2900 uint32_t f_bsize;
2901 uint64_t f_blocks;
2902 uint64_t f_bfree;
2903 uint64_t f_bavail;
2904 uint64_t f_files;
2905 uint64_t f_ffree;
2906 uint64_t fsid_val;
2907 uint32_t f_namelen;
2908 size_t offset = 7;
2909 int32_t bsize_factor;
2910
2911
2912
2913
2914
2915 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2916 if (!bsize_factor) {
2917 bsize_factor = 1;
2918 }
2919 f_type = stbuf->f_type;
2920 f_bsize = stbuf->f_bsize;
2921 f_bsize *= bsize_factor;
2922
2923
2924
2925
2926
2927 f_blocks = stbuf->f_blocks/bsize_factor;
2928 f_bfree = stbuf->f_bfree/bsize_factor;
2929 f_bavail = stbuf->f_bavail/bsize_factor;
2930 f_files = stbuf->f_files;
2931 f_ffree = stbuf->f_ffree;
2932 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2933 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2934 f_namelen = stbuf->f_namelen;
2935
2936 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2937 f_type, f_bsize, f_blocks, f_bfree,
2938 f_bavail, f_files, f_ffree,
2939 fsid_val, f_namelen);
2940}
2941
2942static void coroutine_fn v9fs_statfs(void *opaque)
2943{
2944 int32_t fid;
2945 ssize_t retval = 0;
2946 size_t offset = 7;
2947 V9fsFidState *fidp;
2948 struct statfs stbuf;
2949 V9fsPDU *pdu = opaque;
2950 V9fsState *s = pdu->s;
2951
2952 retval = pdu_unmarshal(pdu, offset, "d", &fid);
2953 if (retval < 0) {
2954 goto out_nofid;
2955 }
2956 fidp = get_fid(pdu, fid);
2957 if (fidp == NULL) {
2958 retval = -ENOENT;
2959 goto out_nofid;
2960 }
2961 retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
2962 if (retval < 0) {
2963 goto out;
2964 }
2965 retval = v9fs_fill_statfs(s, pdu, &stbuf);
2966 if (retval < 0) {
2967 goto out;
2968 }
2969 retval += offset;
2970out:
2971 put_fid(pdu, fidp);
2972out_nofid:
2973 pdu_complete(pdu, retval);
2974}
2975
2976static void coroutine_fn v9fs_mknod(void *opaque)
2977{
2978
2979 int mode;
2980 gid_t gid;
2981 int32_t fid;
2982 V9fsQID qid;
2983 int err = 0;
2984 int major, minor;
2985 size_t offset = 7;
2986 V9fsString name;
2987 struct stat stbuf;
2988 V9fsFidState *fidp;
2989 V9fsPDU *pdu = opaque;
2990
2991 v9fs_string_init(&name);
2992 err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2993 &major, &minor, &gid);
2994 if (err < 0) {
2995 goto out_nofid;
2996 }
2997 trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
2998
2999 if (name_is_illegal(name.data)) {
3000 err = -ENOENT;
3001 goto out_nofid;
3002 }
3003
3004 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
3005 err = -EEXIST;
3006 goto out_nofid;
3007 }
3008
3009 fidp = get_fid(pdu, fid);
3010 if (fidp == NULL) {
3011 err = -ENOENT;
3012 goto out_nofid;
3013 }
3014 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
3015 makedev(major, minor), mode, &stbuf);
3016 if (err < 0) {
3017 goto out;
3018 }
3019 stat_to_qid(&stbuf, &qid);
3020 err = pdu_marshal(pdu, offset, "Q", &qid);
3021 if (err < 0) {
3022 goto out;
3023 }
3024 err += offset;
3025 trace_v9fs_mknod_return(pdu->tag, pdu->id,
3026 qid.type, qid.version, qid.path);
3027out:
3028 put_fid(pdu, fidp);
3029out_nofid:
3030 pdu_complete(pdu, err);
3031 v9fs_string_free(&name);
3032}
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042static void coroutine_fn v9fs_lock(void *opaque)
3043{
3044 V9fsFlock flock;
3045 size_t offset = 7;
3046 struct stat stbuf;
3047 V9fsFidState *fidp;
3048 int32_t fid, err = 0;
3049 V9fsPDU *pdu = opaque;
3050
3051 v9fs_string_init(&flock.client_id);
3052 err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
3053 &flock.flags, &flock.start, &flock.length,
3054 &flock.proc_id, &flock.client_id);
3055 if (err < 0) {
3056 goto out_nofid;
3057 }
3058 trace_v9fs_lock(pdu->tag, pdu->id, fid,
3059 flock.type, flock.start, flock.length);
3060
3061
3062
3063 if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) {
3064 err = -EINVAL;
3065 goto out_nofid;
3066 }
3067 fidp = get_fid(pdu, fid);
3068 if (fidp == NULL) {
3069 err = -ENOENT;
3070 goto out_nofid;
3071 }
3072 err = v9fs_co_fstat(pdu, fidp, &stbuf);
3073 if (err < 0) {
3074 goto out;
3075 }
3076 err = pdu_marshal(pdu, offset, "b", P9_LOCK_SUCCESS);
3077 if (err < 0) {
3078 goto out;
3079 }
3080 err += offset;
3081 trace_v9fs_lock_return(pdu->tag, pdu->id, P9_LOCK_SUCCESS);
3082out:
3083 put_fid(pdu, fidp);
3084out_nofid:
3085 pdu_complete(pdu, err);
3086 v9fs_string_free(&flock.client_id);
3087}
3088
3089
3090
3091
3092
3093static void coroutine_fn v9fs_getlock(void *opaque)
3094{
3095 size_t offset = 7;
3096 struct stat stbuf;
3097 V9fsFidState *fidp;
3098 V9fsGetlock glock;
3099 int32_t fid, err = 0;
3100 V9fsPDU *pdu = opaque;
3101
3102 v9fs_string_init(&glock.client_id);
3103 err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
3104 &glock.start, &glock.length, &glock.proc_id,
3105 &glock.client_id);
3106 if (err < 0) {
3107 goto out_nofid;
3108 }
3109 trace_v9fs_getlock(pdu->tag, pdu->id, fid,
3110 glock.type, glock.start, glock.length);
3111
3112 fidp = get_fid(pdu, fid);
3113 if (fidp == NULL) {
3114 err = -ENOENT;
3115 goto out_nofid;
3116 }
3117 err = v9fs_co_fstat(pdu, fidp, &stbuf);
3118 if (err < 0) {
3119 goto out;
3120 }
3121 glock.type = P9_LOCK_TYPE_UNLCK;
3122 err = pdu_marshal(pdu, offset, "bqqds", glock.type,
3123 glock.start, glock.length, glock.proc_id,
3124 &glock.client_id);
3125 if (err < 0) {
3126 goto out;
3127 }
3128 err += offset;
3129 trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
3130 glock.length, glock.proc_id);
3131out:
3132 put_fid(pdu, fidp);
3133out_nofid:
3134 pdu_complete(pdu, err);
3135 v9fs_string_free(&glock.client_id);
3136}
3137
3138static void coroutine_fn v9fs_mkdir(void *opaque)
3139{
3140 V9fsPDU *pdu = opaque;
3141 size_t offset = 7;
3142 int32_t fid;
3143 struct stat stbuf;
3144 V9fsQID qid;
3145 V9fsString name;
3146 V9fsFidState *fidp;
3147 gid_t gid;
3148 int mode;
3149 int err = 0;
3150
3151 v9fs_string_init(&name);
3152 err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3153 if (err < 0) {
3154 goto out_nofid;
3155 }
3156 trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
3157
3158 if (name_is_illegal(name.data)) {
3159 err = -ENOENT;
3160 goto out_nofid;
3161 }
3162
3163 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
3164 err = -EEXIST;
3165 goto out_nofid;
3166 }
3167
3168 fidp = get_fid(pdu, fid);
3169 if (fidp == NULL) {
3170 err = -ENOENT;
3171 goto out_nofid;
3172 }
3173 err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
3174 if (err < 0) {
3175 goto out;
3176 }
3177 stat_to_qid(&stbuf, &qid);
3178 err = pdu_marshal(pdu, offset, "Q", &qid);
3179 if (err < 0) {
3180 goto out;
3181 }
3182 err += offset;
3183 trace_v9fs_mkdir_return(pdu->tag, pdu->id,
3184 qid.type, qid.version, qid.path, err);
3185out:
3186 put_fid(pdu, fidp);
3187out_nofid:
3188 pdu_complete(pdu, err);
3189 v9fs_string_free(&name);
3190}
3191
3192static void coroutine_fn v9fs_xattrwalk(void *opaque)
3193{
3194 int64_t size;
3195 V9fsString name;
3196 ssize_t err = 0;
3197 size_t offset = 7;
3198 int32_t fid, newfid;
3199 V9fsFidState *file_fidp;
3200 V9fsFidState *xattr_fidp = NULL;
3201 V9fsPDU *pdu = opaque;
3202 V9fsState *s = pdu->s;
3203
3204 v9fs_string_init(&name);
3205 err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3206 if (err < 0) {
3207 goto out_nofid;
3208 }
3209 trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
3210
3211 file_fidp = get_fid(pdu, fid);
3212 if (file_fidp == NULL) {
3213 err = -ENOENT;
3214 goto out_nofid;
3215 }
3216 xattr_fidp = alloc_fid(s, newfid);
3217 if (xattr_fidp == NULL) {
3218 err = -EINVAL;
3219 goto out;
3220 }
3221 v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
3222 if (!v9fs_string_size(&name)) {
3223
3224
3225
3226 size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
3227 if (size < 0) {
3228 err = size;
3229 clunk_fid(s, xattr_fidp->fid);
3230 goto out;
3231 }
3232
3233
3234
3235 xattr_fidp->fs.xattr.len = size;
3236 xattr_fidp->fid_type = P9_FID_XATTR;
3237 xattr_fidp->fs.xattr.xattrwalk_fid = true;
3238 if (size) {
3239 xattr_fidp->fs.xattr.value = g_malloc(size);
3240 err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
3241 xattr_fidp->fs.xattr.value,
3242 xattr_fidp->fs.xattr.len);
3243 if (err < 0) {
3244 clunk_fid(s, xattr_fidp->fid);
3245 goto out;
3246 }
3247 }
3248 err = pdu_marshal(pdu, offset, "q", size);
3249 if (err < 0) {
3250 goto out;
3251 }
3252 err += offset;
3253 } else {
3254
3255
3256
3257
3258 size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3259 &name, NULL, 0);
3260 if (size < 0) {
3261 err = size;
3262 clunk_fid(s, xattr_fidp->fid);
3263 goto out;
3264 }
3265
3266
3267
3268 xattr_fidp->fs.xattr.len = size;
3269 xattr_fidp->fid_type = P9_FID_XATTR;
3270 xattr_fidp->fs.xattr.xattrwalk_fid = true;
3271 if (size) {
3272 xattr_fidp->fs.xattr.value = g_malloc(size);
3273 err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3274 &name, xattr_fidp->fs.xattr.value,
3275 xattr_fidp->fs.xattr.len);
3276 if (err < 0) {
3277 clunk_fid(s, xattr_fidp->fid);
3278 goto out;
3279 }
3280 }
3281 err = pdu_marshal(pdu, offset, "q", size);
3282 if (err < 0) {
3283 goto out;
3284 }
3285 err += offset;
3286 }
3287 trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
3288out:
3289 put_fid(pdu, file_fidp);
3290 if (xattr_fidp) {
3291 put_fid(pdu, xattr_fidp);
3292 }
3293out_nofid:
3294 pdu_complete(pdu, err);
3295 v9fs_string_free(&name);
3296}
3297
3298static void coroutine_fn v9fs_xattrcreate(void *opaque)
3299{
3300 int flags;
3301 int32_t fid;
3302 uint64_t size;
3303 ssize_t err = 0;
3304 V9fsString name;
3305 size_t offset = 7;
3306 V9fsFidState *file_fidp;
3307 V9fsFidState *xattr_fidp;
3308 V9fsPDU *pdu = opaque;
3309
3310 v9fs_string_init(&name);
3311 err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
3312 if (err < 0) {
3313 goto out_nofid;
3314 }
3315 trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
3316
3317 if (size > XATTR_SIZE_MAX) {
3318 err = -E2BIG;
3319 goto out_nofid;
3320 }
3321
3322 file_fidp = get_fid(pdu, fid);
3323 if (file_fidp == NULL) {
3324 err = -EINVAL;
3325 goto out_nofid;
3326 }
3327 if (file_fidp->fid_type != P9_FID_NONE) {
3328 err = -EINVAL;
3329 goto out_put_fid;
3330 }
3331
3332
3333 xattr_fidp = file_fidp;
3334 xattr_fidp->fid_type = P9_FID_XATTR;
3335 xattr_fidp->fs.xattr.copied_len = 0;
3336 xattr_fidp->fs.xattr.xattrwalk_fid = false;
3337 xattr_fidp->fs.xattr.len = size;
3338 xattr_fidp->fs.xattr.flags = flags;
3339 v9fs_string_init(&xattr_fidp->fs.xattr.name);
3340 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3341 xattr_fidp->fs.xattr.value = g_malloc0(size);
3342 err = offset;
3343out_put_fid:
3344 put_fid(pdu, file_fidp);
3345out_nofid:
3346 pdu_complete(pdu, err);
3347 v9fs_string_free(&name);
3348}
3349
3350static void coroutine_fn v9fs_readlink(void *opaque)
3351{
3352 V9fsPDU *pdu = opaque;
3353 size_t offset = 7;
3354 V9fsString target;
3355 int32_t fid;
3356 int err = 0;
3357 V9fsFidState *fidp;
3358
3359 err = pdu_unmarshal(pdu, offset, "d", &fid);
3360 if (err < 0) {
3361 goto out_nofid;
3362 }
3363 trace_v9fs_readlink(pdu->tag, pdu->id, fid);
3364 fidp = get_fid(pdu, fid);
3365 if (fidp == NULL) {
3366 err = -ENOENT;
3367 goto out_nofid;
3368 }
3369
3370 v9fs_string_init(&target);
3371 err = v9fs_co_readlink(pdu, &fidp->path, &target);
3372 if (err < 0) {
3373 goto out;
3374 }
3375 err = pdu_marshal(pdu, offset, "s", &target);
3376 if (err < 0) {
3377 v9fs_string_free(&target);
3378 goto out;
3379 }
3380 err += offset;
3381 trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
3382 v9fs_string_free(&target);
3383out:
3384 put_fid(pdu, fidp);
3385out_nofid:
3386 pdu_complete(pdu, err);
3387}
3388
3389static CoroutineEntry *pdu_co_handlers[] = {
3390 [P9_TREADDIR] = v9fs_readdir,
3391 [P9_TSTATFS] = v9fs_statfs,
3392 [P9_TGETATTR] = v9fs_getattr,
3393 [P9_TSETATTR] = v9fs_setattr,
3394 [P9_TXATTRWALK] = v9fs_xattrwalk,
3395 [P9_TXATTRCREATE] = v9fs_xattrcreate,
3396 [P9_TMKNOD] = v9fs_mknod,
3397 [P9_TRENAME] = v9fs_rename,
3398 [P9_TLOCK] = v9fs_lock,
3399 [P9_TGETLOCK] = v9fs_getlock,
3400 [P9_TRENAMEAT] = v9fs_renameat,
3401 [P9_TREADLINK] = v9fs_readlink,
3402 [P9_TUNLINKAT] = v9fs_unlinkat,
3403 [P9_TMKDIR] = v9fs_mkdir,
3404 [P9_TVERSION] = v9fs_version,
3405 [P9_TLOPEN] = v9fs_open,
3406 [P9_TATTACH] = v9fs_attach,
3407 [P9_TSTAT] = v9fs_stat,
3408 [P9_TWALK] = v9fs_walk,
3409 [P9_TCLUNK] = v9fs_clunk,
3410 [P9_TFSYNC] = v9fs_fsync,
3411 [P9_TOPEN] = v9fs_open,
3412 [P9_TREAD] = v9fs_read,
3413#if 0
3414 [P9_TAUTH] = v9fs_auth,
3415#endif
3416 [P9_TFLUSH] = v9fs_flush,
3417 [P9_TLINK] = v9fs_link,
3418 [P9_TSYMLINK] = v9fs_symlink,
3419 [P9_TCREATE] = v9fs_create,
3420 [P9_TLCREATE] = v9fs_lcreate,
3421 [P9_TWRITE] = v9fs_write,
3422 [P9_TWSTAT] = v9fs_wstat,
3423 [P9_TREMOVE] = v9fs_remove,
3424};
3425
3426static void coroutine_fn v9fs_op_not_supp(void *opaque)
3427{
3428 V9fsPDU *pdu = opaque;
3429 pdu_complete(pdu, -EOPNOTSUPP);
3430}
3431
3432static void coroutine_fn v9fs_fs_ro(void *opaque)
3433{
3434 V9fsPDU *pdu = opaque;
3435 pdu_complete(pdu, -EROFS);
3436}
3437
3438static inline bool is_read_only_op(V9fsPDU *pdu)
3439{
3440 switch (pdu->id) {
3441 case P9_TREADDIR:
3442 case P9_TSTATFS:
3443 case P9_TGETATTR:
3444 case P9_TXATTRWALK:
3445 case P9_TLOCK:
3446 case P9_TGETLOCK:
3447 case P9_TREADLINK:
3448 case P9_TVERSION:
3449 case P9_TLOPEN:
3450 case P9_TATTACH:
3451 case P9_TSTAT:
3452 case P9_TWALK:
3453 case P9_TCLUNK:
3454 case P9_TFSYNC:
3455 case P9_TOPEN:
3456 case P9_TREAD:
3457 case P9_TAUTH:
3458 case P9_TFLUSH:
3459 return 1;
3460 default:
3461 return 0;
3462 }
3463}
3464
3465void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr)
3466{
3467 Coroutine *co;
3468 CoroutineEntry *handler;
3469 V9fsState *s = pdu->s;
3470
3471 pdu->size = le32_to_cpu(hdr->size_le);
3472 pdu->id = hdr->id;
3473 pdu->tag = le16_to_cpu(hdr->tag_le);
3474
3475 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3476 (pdu_co_handlers[pdu->id] == NULL)) {
3477 handler = v9fs_op_not_supp;
3478 } else {
3479 handler = pdu_co_handlers[pdu->id];
3480 }
3481
3482 if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
3483 handler = v9fs_fs_ro;
3484 }
3485
3486 qemu_co_queue_init(&pdu->complete);
3487 co = qemu_coroutine_create(handler, pdu);
3488 qemu_coroutine_enter(co);
3489}
3490
3491
3492int v9fs_device_realize_common(V9fsState *s, Error **errp)
3493{
3494 int i, len;
3495 struct stat stat;
3496 FsDriverEntry *fse;
3497 V9fsPath path;
3498 int rc = 1;
3499
3500
3501 QLIST_INIT(&s->free_list);
3502 QLIST_INIT(&s->active_list);
3503 for (i = 0; i < MAX_REQ; i++) {
3504 QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
3505 s->pdus[i].s = s;
3506 s->pdus[i].idx = i;
3507 }
3508
3509 v9fs_path_init(&path);
3510
3511 fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
3512
3513 if (!fse) {
3514
3515 error_setg(errp, "9pfs device couldn't find fsdev with the "
3516 "id = %s",
3517 s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
3518 goto out;
3519 }
3520
3521 if (!s->fsconf.tag) {
3522
3523 error_setg(errp, "fsdev with id %s needs mount_tag arguments",
3524 s->fsconf.fsdev_id);
3525 goto out;
3526 }
3527
3528 s->ctx.export_flags = fse->export_flags;
3529 s->ctx.fs_root = g_strdup(fse->path);
3530 s->ctx.exops.get_st_gen = NULL;
3531 len = strlen(s->fsconf.tag);
3532 if (len > MAX_TAG_LEN - 1) {
3533 error_setg(errp, "mount tag '%s' (%d bytes) is longer than "
3534 "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
3535 goto out;
3536 }
3537
3538 s->tag = g_strdup(s->fsconf.tag);
3539 s->ctx.uid = -1;
3540
3541 s->ops = fse->ops;
3542
3543 s->ctx.fmode = fse->fmode;
3544 s->ctx.dmode = fse->dmode;
3545
3546 s->fid_list = NULL;
3547 qemu_co_rwlock_init(&s->rename_lock);
3548
3549 if (s->ops->init(&s->ctx) < 0) {
3550 error_setg(errp, "9pfs Failed to initialize fs-driver with id:%s"
3551 " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root);
3552 goto out;
3553 }
3554
3555
3556
3557
3558
3559
3560 if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
3561 error_setg(errp,
3562 "error in converting name to path %s", strerror(errno));
3563 goto out;
3564 }
3565 if (s->ops->lstat(&s->ctx, &path, &stat)) {
3566 error_setg(errp, "share path %s does not exist", fse->path);
3567 goto out;
3568 } else if (!S_ISDIR(stat.st_mode)) {
3569 error_setg(errp, "share path %s is not a directory", fse->path);
3570 goto out;
3571 }
3572
3573 s->ctx.fst = &fse->fst;
3574 fsdev_throttle_init(s->ctx.fst);
3575
3576 v9fs_path_free(&path);
3577
3578 rc = 0;
3579out:
3580 if (rc) {
3581 if (s->ops && s->ops->cleanup && s->ctx.private) {
3582 s->ops->cleanup(&s->ctx);
3583 }
3584 g_free(s->tag);
3585 g_free(s->ctx.fs_root);
3586 v9fs_path_free(&path);
3587 }
3588 return rc;
3589}
3590
3591void v9fs_device_unrealize_common(V9fsState *s, Error **errp)
3592{
3593 if (s->ops->cleanup) {
3594 s->ops->cleanup(&s->ctx);
3595 }
3596 fsdev_throttle_cleanup(s->ctx.fst);
3597 g_free(s->tag);
3598 g_free(s->ctx.fs_root);
3599}
3600
3601typedef struct VirtfsCoResetData {
3602 V9fsPDU pdu;
3603 bool done;
3604} VirtfsCoResetData;
3605
3606static void coroutine_fn virtfs_co_reset(void *opaque)
3607{
3608 VirtfsCoResetData *data = opaque;
3609
3610 virtfs_reset(&data->pdu);
3611 data->done = true;
3612}
3613
3614void v9fs_reset(V9fsState *s)
3615{
3616 VirtfsCoResetData data = { .pdu = { .s = s }, .done = false };
3617 Coroutine *co;
3618
3619 while (!QLIST_EMPTY(&s->active_list)) {
3620 aio_poll(qemu_get_aio_context(), true);
3621 }
3622
3623 co = qemu_coroutine_create(virtfs_co_reset, &data);
3624 qemu_coroutine_enter(co);
3625
3626 while (!data.done) {
3627 aio_poll(qemu_get_aio_context(), true);
3628 }
3629}
3630
3631static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
3632{
3633 struct rlimit rlim;
3634 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3635 error_report("Failed to get the resource limit");
3636 exit(1);
3637 }
3638 open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3639 open_fd_rc = rlim.rlim_cur/2;
3640}
3641