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