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