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