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