4 * Copyright IBM, Corp. 2010
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
16 #include "qemu_socket.h"
17 #include "virtio-9p.h"
18 #include "fsdev/qemu-fsdev.h"
19 #include "virtio-9p-debug.h"
24 static int v9fs_do_lstat(V9fsState
*s
, V9fsString
*path
, struct stat
*stbuf
)
26 return s
->ops
->lstat(&s
->ctx
, path
->data
, stbuf
);
29 static int v9fs_do_setuid(V9fsState
*s
, uid_t uid
)
31 return s
->ops
->setuid(&s
->ctx
, uid
);
34 static ssize_t
v9fs_do_readlink(V9fsState
*s
, V9fsString
*path
, V9fsString
*buf
)
38 buf
->data
= qemu_malloc(1024);
40 len
= s
->ops
->readlink(&s
->ctx
, path
->data
, buf
->data
, 1024 - 1);
49 static int v9fs_do_close(V9fsState
*s
, int fd
)
51 return s
->ops
->close(&s
->ctx
, fd
);
54 static int v9fs_do_closedir(V9fsState
*s
, DIR *dir
)
56 return s
->ops
->closedir(&s
->ctx
, dir
);
59 static int v9fs_do_open(V9fsState
*s
, V9fsString
*path
, int flags
)
61 return s
->ops
->open(&s
->ctx
, path
->data
, flags
);
64 static DIR *v9fs_do_opendir(V9fsState
*s
, V9fsString
*path
)
66 return s
->ops
->opendir(&s
->ctx
, path
->data
);
69 static void v9fs_do_rewinddir(V9fsState
*s
, DIR *dir
)
71 return s
->ops
->rewinddir(&s
->ctx
, dir
);
74 static off_t
v9fs_do_telldir(V9fsState
*s
, DIR *dir
)
76 return s
->ops
->telldir(&s
->ctx
, dir
);
79 static struct dirent
*v9fs_do_readdir(V9fsState
*s
, DIR *dir
)
81 return s
->ops
->readdir(&s
->ctx
, dir
);
84 static void v9fs_do_seekdir(V9fsState
*s
, DIR *dir
, off_t off
)
86 return s
->ops
->seekdir(&s
->ctx
, dir
, off
);
89 static int v9fs_do_readv(V9fsState
*s
, int fd
, const struct iovec
*iov
,
92 return s
->ops
->readv(&s
->ctx
, fd
, iov
, iovcnt
);
95 static off_t
v9fs_do_lseek(V9fsState
*s
, int fd
, off_t offset
, int whence
)
97 return s
->ops
->lseek(&s
->ctx
, fd
, offset
, whence
);
100 static void v9fs_string_init(V9fsString
*str
)
106 static void v9fs_string_free(V9fsString
*str
)
108 qemu_free(str
->data
);
113 static void v9fs_string_null(V9fsString
*str
)
115 v9fs_string_free(str
);
118 static int number_to_string(void *arg
, char type
)
120 unsigned int ret
= 0;
124 unsigned int num
= *(unsigned int *)arg
;
133 printf("Number_to_string: Unknown number format\n");
140 static int v9fs_string_alloc_printf(char **strp
, const char *fmt
, va_list ap
)
143 char *iter
= (char *)fmt
;
147 unsigned int arg_uint
;
149 /* Find the number of %'s that denotes an argument */
150 for (iter
= strstr(iter
, "%"); iter
; iter
= strstr(iter
, "%")) {
155 len
= strlen(fmt
) - 2*nr_args
;
165 /* Now parse the format string */
166 for (iter
= strstr(iter
, "%"); iter
; iter
= strstr(iter
, "%")) {
170 arg_uint
= va_arg(ap2
, unsigned int);
171 len
+= number_to_string((void *)&arg_uint
, 'u');
174 arg_char_ptr
= va_arg(ap2
, char *);
175 len
+= strlen(arg_char_ptr
);
182 "v9fs_string_alloc_printf:Incorrect format %c", *iter
);
189 *strp
= qemu_malloc((len
+ 1) * sizeof(**strp
));
191 return vsprintf(*strp
, fmt
, ap
);
194 static void v9fs_string_sprintf(V9fsString
*str
, const char *fmt
, ...)
199 v9fs_string_free(str
);
202 err
= v9fs_string_alloc_printf(&str
->data
, fmt
, ap
);
209 static void v9fs_string_copy(V9fsString
*lhs
, V9fsString
*rhs
)
211 v9fs_string_free(lhs
);
212 v9fs_string_sprintf(lhs
, "%s", rhs
->data
);
215 static size_t v9fs_string_size(V9fsString
*str
)
220 static V9fsFidState
*lookup_fid(V9fsState
*s
, int32_t fid
)
224 for (f
= s
->fid_list
; f
; f
= f
->next
) {
226 v9fs_do_setuid(s
, f
->uid
);
234 static V9fsFidState
*alloc_fid(V9fsState
*s
, int32_t fid
)
238 f
= lookup_fid(s
, fid
);
243 f
= qemu_mallocz(sizeof(V9fsFidState
));
249 f
->next
= s
->fid_list
;
255 static int free_fid(V9fsState
*s
, int32_t fid
)
257 V9fsFidState
**fidpp
, *fidp
;
259 for (fidpp
= &s
->fid_list
; *fidpp
; fidpp
= &(*fidpp
)->next
) {
260 if ((*fidpp
)->fid
== fid
) {
265 if (*fidpp
== NULL
) {
272 if (fidp
->fd
!= -1) {
273 v9fs_do_close(s
, fidp
->fd
);
276 v9fs_do_closedir(s
, fidp
->dir
);
278 v9fs_string_free(&fidp
->path
);
284 #define P9_QID_TYPE_DIR 0x80
285 #define P9_QID_TYPE_SYMLINK 0x02
287 #define P9_STAT_MODE_DIR 0x80000000
288 #define P9_STAT_MODE_APPEND 0x40000000
289 #define P9_STAT_MODE_EXCL 0x20000000
290 #define P9_STAT_MODE_MOUNT 0x10000000
291 #define P9_STAT_MODE_AUTH 0x08000000
292 #define P9_STAT_MODE_TMP 0x04000000
293 #define P9_STAT_MODE_SYMLINK 0x02000000
294 #define P9_STAT_MODE_LINK 0x01000000
295 #define P9_STAT_MODE_DEVICE 0x00800000
296 #define P9_STAT_MODE_NAMED_PIPE 0x00200000
297 #define P9_STAT_MODE_SOCKET 0x00100000
298 #define P9_STAT_MODE_SETUID 0x00080000
299 #define P9_STAT_MODE_SETGID 0x00040000
300 #define P9_STAT_MODE_SETVTX 0x00010000
302 #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
303 P9_STAT_MODE_SYMLINK | \
304 P9_STAT_MODE_LINK | \
305 P9_STAT_MODE_DEVICE | \
306 P9_STAT_MODE_NAMED_PIPE | \
309 /* This is the algorithm from ufs in spfs */
310 static void stat_to_qid(const struct stat
*stbuf
, V9fsQID
*qidp
)
314 size
= MIN(sizeof(stbuf
->st_ino
), sizeof(qidp
->path
));
315 memcpy(&qidp
->path
, &stbuf
->st_ino
, size
);
316 qidp
->version
= stbuf
->st_mtime
^ (stbuf
->st_size
<< 8);
318 if (S_ISDIR(stbuf
->st_mode
)) {
319 qidp
->type
|= P9_QID_TYPE_DIR
;
321 if (S_ISLNK(stbuf
->st_mode
)) {
322 qidp
->type
|= P9_QID_TYPE_SYMLINK
;
326 static int fid_to_qid(V9fsState
*s
, V9fsFidState
*fidp
, V9fsQID
*qidp
)
331 err
= v9fs_do_lstat(s
, &fidp
->path
, &stbuf
);
336 stat_to_qid(&stbuf
, qidp
);
340 static V9fsPDU
*alloc_pdu(V9fsState
*s
)
344 if (!QLIST_EMPTY(&s
->free_list
)) {
345 pdu
= QLIST_FIRST(&s
->free_list
);
346 QLIST_REMOVE(pdu
, next
);
351 static void free_pdu(V9fsState
*s
, V9fsPDU
*pdu
)
354 QLIST_INSERT_HEAD(&s
->free_list
, pdu
, next
);
358 size_t pdu_packunpack(void *addr
, struct iovec
*sg
, int sg_count
,
359 size_t offset
, size_t size
, int pack
)
364 for (i
= 0; size
&& i
< sg_count
; i
++) {
366 if (offset
>= sg
[i
].iov_len
) {
368 offset
-= sg
[i
].iov_len
;
371 len
= MIN(sg
[i
].iov_len
- offset
, size
);
373 memcpy(sg
[i
].iov_base
+ offset
, addr
, len
);
375 memcpy(addr
, sg
[i
].iov_base
+ offset
, len
);
390 static size_t pdu_unpack(void *dst
, V9fsPDU
*pdu
, size_t offset
, size_t size
)
392 return pdu_packunpack(dst
, pdu
->elem
.out_sg
, pdu
->elem
.out_num
,
396 static size_t pdu_pack(V9fsPDU
*pdu
, size_t offset
, const void *src
,
399 return pdu_packunpack((void *)src
, pdu
->elem
.in_sg
, pdu
->elem
.in_num
,
403 static int pdu_copy_sg(V9fsPDU
*pdu
, size_t offset
, int rx
, struct iovec
*sg
)
407 struct iovec
*src_sg
;
411 src_sg
= pdu
->elem
.in_sg
;
412 num
= pdu
->elem
.in_num
;
414 src_sg
= pdu
->elem
.out_sg
;
415 num
= pdu
->elem
.out_num
;
419 for (i
= 0; i
< num
; i
++) {
421 sg
[j
].iov_base
= src_sg
[i
].iov_base
;
422 sg
[j
].iov_len
= src_sg
[i
].iov_len
;
424 } else if (offset
< (src_sg
[i
].iov_len
+ pos
)) {
425 sg
[j
].iov_base
= src_sg
[i
].iov_base
;
426 sg
[j
].iov_len
= src_sg
[i
].iov_len
;
427 sg
[j
].iov_base
+= (offset
- pos
);
428 sg
[j
].iov_len
-= (offset
- pos
);
431 pos
+= src_sg
[i
].iov_len
;
437 static size_t pdu_unmarshal(V9fsPDU
*pdu
, size_t offset
, const char *fmt
, ...)
439 size_t old_offset
= offset
;
444 for (i
= 0; fmt
[i
]; i
++) {
447 uint8_t *valp
= va_arg(ap
, uint8_t *);
448 offset
+= pdu_unpack(valp
, pdu
, offset
, sizeof(*valp
));
453 valp
= va_arg(ap
, uint16_t *);
454 val
= le16_to_cpupu(valp
);
455 offset
+= pdu_unpack(&val
, pdu
, offset
, sizeof(val
));
461 valp
= va_arg(ap
, uint32_t *);
462 val
= le32_to_cpupu(valp
);
463 offset
+= pdu_unpack(&val
, pdu
, offset
, sizeof(val
));
469 valp
= va_arg(ap
, uint64_t *);
470 val
= le64_to_cpup(valp
);
471 offset
+= pdu_unpack(&val
, pdu
, offset
, sizeof(val
));
476 struct iovec
*iov
= va_arg(ap
, struct iovec
*);
477 int *iovcnt
= va_arg(ap
, int *);
478 *iovcnt
= pdu_copy_sg(pdu
, offset
, 0, iov
);
482 V9fsString
*str
= va_arg(ap
, V9fsString
*);
483 offset
+= pdu_unmarshal(pdu
, offset
, "w", &str
->size
);
484 /* FIXME: sanity check str->size */
485 str
->data
= qemu_malloc(str
->size
+ 1);
486 offset
+= pdu_unpack(str
->data
, pdu
, offset
, str
->size
);
487 str
->data
[str
->size
] = 0;
491 V9fsQID
*qidp
= va_arg(ap
, V9fsQID
*);
492 offset
+= pdu_unmarshal(pdu
, offset
, "bdq",
493 &qidp
->type
, &qidp
->version
, &qidp
->path
);
497 V9fsStat
*statp
= va_arg(ap
, V9fsStat
*);
498 offset
+= pdu_unmarshal(pdu
, offset
, "wwdQdddqsssssddd",
499 &statp
->size
, &statp
->type
, &statp
->dev
,
500 &statp
->qid
, &statp
->mode
, &statp
->atime
,
501 &statp
->mtime
, &statp
->length
,
502 &statp
->name
, &statp
->uid
, &statp
->gid
,
503 &statp
->muid
, &statp
->extension
,
504 &statp
->n_uid
, &statp
->n_gid
,
515 return offset
- old_offset
;
518 static size_t pdu_marshal(V9fsPDU
*pdu
, size_t offset
, const char *fmt
, ...)
520 size_t old_offset
= offset
;
525 for (i
= 0; fmt
[i
]; i
++) {
528 uint8_t val
= va_arg(ap
, int);
529 offset
+= pdu_pack(pdu
, offset
, &val
, sizeof(val
));
534 cpu_to_le16w(&val
, va_arg(ap
, int));
535 offset
+= pdu_pack(pdu
, offset
, &val
, sizeof(val
));
540 cpu_to_le32w(&val
, va_arg(ap
, uint32_t));
541 offset
+= pdu_pack(pdu
, offset
, &val
, sizeof(val
));
546 cpu_to_le64w(&val
, va_arg(ap
, uint64_t));
547 offset
+= pdu_pack(pdu
, offset
, &val
, sizeof(val
));
551 struct iovec
*iov
= va_arg(ap
, struct iovec
*);
552 int *iovcnt
= va_arg(ap
, int *);
553 *iovcnt
= pdu_copy_sg(pdu
, offset
, 1, iov
);
557 V9fsString
*str
= va_arg(ap
, V9fsString
*);
558 offset
+= pdu_marshal(pdu
, offset
, "w", str
->size
);
559 offset
+= pdu_pack(pdu
, offset
, str
->data
, str
->size
);
563 V9fsQID
*qidp
= va_arg(ap
, V9fsQID
*);
564 offset
+= pdu_marshal(pdu
, offset
, "bdq",
565 qidp
->type
, qidp
->version
, qidp
->path
);
569 V9fsStat
*statp
= va_arg(ap
, V9fsStat
*);
570 offset
+= pdu_marshal(pdu
, offset
, "wwdQdddqsssssddd",
571 statp
->size
, statp
->type
, statp
->dev
,
572 &statp
->qid
, statp
->mode
, statp
->atime
,
573 statp
->mtime
, statp
->length
, &statp
->name
,
574 &statp
->uid
, &statp
->gid
, &statp
->muid
,
575 &statp
->extension
, statp
->n_uid
,
576 statp
->n_gid
, statp
->n_muid
);
585 return offset
- old_offset
;
588 static void complete_pdu(V9fsState
*s
, V9fsPDU
*pdu
, ssize_t len
)
590 int8_t id
= pdu
->id
+ 1; /* Response */
596 str
.data
= strerror(err
);
597 str
.size
= strlen(str
.data
);
600 len
+= pdu_marshal(pdu
, len
, "s", &str
);
602 len
+= pdu_marshal(pdu
, len
, "d", err
);
608 /* fill out the header */
609 pdu_marshal(pdu
, 0, "dbw", (int32_t)len
, id
, pdu
->tag
);
611 /* keep these in sync */
615 /* push onto queue and notify */
616 virtqueue_push(s
->vq
, &pdu
->elem
, len
);
618 /* FIXME: we should batch these completions */
619 virtio_notify(&s
->vdev
, s
->vq
);
624 static mode_t
v9mode_to_mode(uint32_t mode
, V9fsString
*extension
)
629 if (mode
& P9_STAT_MODE_DIR
) {
634 if (mode
& P9_STAT_MODE_SYMLINK
) {
637 if (mode
& P9_STAT_MODE_SOCKET
) {
640 if (mode
& P9_STAT_MODE_NAMED_PIPE
) {
643 if (mode
& P9_STAT_MODE_DEVICE
) {
644 if (extension
&& extension
->data
[0] == 'c') {
656 if (mode
& P9_STAT_MODE_SETUID
) {
659 if (mode
& P9_STAT_MODE_SETGID
) {
662 if (mode
& P9_STAT_MODE_SETVTX
) {
669 static int donttouch_stat(V9fsStat
*stat
)
671 if (stat
->type
== -1 &&
673 stat
->qid
.type
== -1 &&
674 stat
->qid
.version
== -1 &&
675 stat
->qid
.path
== -1 &&
679 stat
->length
== -1 &&
686 stat
->n_muid
== -1) {
693 static void v9fs_stat_free(V9fsStat
*stat
)
695 v9fs_string_free(&stat
->name
);
696 v9fs_string_free(&stat
->uid
);
697 v9fs_string_free(&stat
->gid
);
698 v9fs_string_free(&stat
->muid
);
699 v9fs_string_free(&stat
->extension
);
702 static uint32_t stat_to_v9mode(const struct stat
*stbuf
)
706 mode
= stbuf
->st_mode
& 0777;
707 if (S_ISDIR(stbuf
->st_mode
)) {
708 mode
|= P9_STAT_MODE_DIR
;
712 if (S_ISLNK(stbuf
->st_mode
)) {
713 mode
|= P9_STAT_MODE_SYMLINK
;
716 if (S_ISSOCK(stbuf
->st_mode
)) {
717 mode
|= P9_STAT_MODE_SOCKET
;
720 if (S_ISFIFO(stbuf
->st_mode
)) {
721 mode
|= P9_STAT_MODE_NAMED_PIPE
;
724 if (S_ISBLK(stbuf
->st_mode
) || S_ISCHR(stbuf
->st_mode
)) {
725 mode
|= P9_STAT_MODE_DEVICE
;
728 if (stbuf
->st_mode
& S_ISUID
) {
729 mode
|= P9_STAT_MODE_SETUID
;
732 if (stbuf
->st_mode
& S_ISGID
) {
733 mode
|= P9_STAT_MODE_SETGID
;
736 if (stbuf
->st_mode
& S_ISVTX
) {
737 mode
|= P9_STAT_MODE_SETVTX
;
744 static int stat_to_v9stat(V9fsState
*s
, V9fsString
*name
,
745 const struct stat
*stbuf
,
751 memset(v9stat
, 0, sizeof(*v9stat
));
753 stat_to_qid(stbuf
, &v9stat
->qid
);
754 v9stat
->mode
= stat_to_v9mode(stbuf
);
755 v9stat
->atime
= stbuf
->st_atime
;
756 v9stat
->mtime
= stbuf
->st_mtime
;
757 v9stat
->length
= stbuf
->st_size
;
759 v9fs_string_null(&v9stat
->uid
);
760 v9fs_string_null(&v9stat
->gid
);
761 v9fs_string_null(&v9stat
->muid
);
764 v9stat
->n_uid
= stbuf
->st_uid
;
765 v9stat
->n_gid
= stbuf
->st_gid
;
768 v9fs_string_null(&v9stat
->extension
);
770 if (v9stat
->mode
& P9_STAT_MODE_SYMLINK
) {
771 err
= v9fs_do_readlink(s
, name
, &v9stat
->extension
);
776 v9stat
->extension
.data
[err
] = 0;
777 v9stat
->extension
.size
= err
;
778 } else if (v9stat
->mode
& P9_STAT_MODE_DEVICE
) {
779 v9fs_string_sprintf(&v9stat
->extension
, "%c %u %u",
780 S_ISCHR(stbuf
->st_mode
) ? 'c' : 'b',
781 major(stbuf
->st_rdev
), minor(stbuf
->st_rdev
));
782 } else if (S_ISDIR(stbuf
->st_mode
) || S_ISREG(stbuf
->st_mode
)) {
783 v9fs_string_sprintf(&v9stat
->extension
, "%s %u",
784 "HARDLINKCOUNT", stbuf
->st_nlink
);
788 str
= strrchr(name
->data
, '/');
795 v9fs_string_sprintf(&v9stat
->name
, "%s", str
);
798 v9fs_string_size(&v9stat
->name
) +
799 v9fs_string_size(&v9stat
->uid
) +
800 v9fs_string_size(&v9stat
->gid
) +
801 v9fs_string_size(&v9stat
->muid
) +
802 v9fs_string_size(&v9stat
->extension
);
806 static struct iovec
*adjust_sg(struct iovec
*sg
, int len
, int *iovcnt
)
808 while (len
&& *iovcnt
) {
809 if (len
< sg
->iov_len
) {
823 static struct iovec
*cap_sg(struct iovec
*sg
, int cap
, int *cnt
)
828 for (i
= 0; i
< *cnt
; i
++) {
829 if ((total
+ sg
[i
].iov_len
) > cap
) {
830 sg
[i
].iov_len
-= ((total
+ sg
[i
].iov_len
) - cap
);
834 total
+= sg
[i
].iov_len
;
842 static void print_sg(struct iovec
*sg
, int cnt
)
846 printf("sg[%d]: {", cnt
);
847 for (i
= 0; i
< cnt
; i
++) {
851 printf("(%p, %zd)", sg
[i
].iov_base
, sg
[i
].iov_len
);
856 static void v9fs_dummy(V9fsState
*s
, V9fsPDU
*pdu
)
858 /* Note: The following have been added to prevent GCC from complaining
859 * They will be removed in the subsequent patches */
862 (void) v9fs_string_init
;
863 (void) v9fs_string_free
;
864 (void) v9fs_string_null
;
865 (void) v9fs_string_sprintf
;
866 (void) v9fs_string_copy
;
867 (void) v9fs_string_size
;
868 (void) v9fs_do_lstat
;
869 (void) v9fs_do_setuid
;
870 (void) v9fs_do_readlink
;
871 (void) v9fs_do_close
;
872 (void) v9fs_do_closedir
;
876 (void) v9mode_to_mode
;
877 (void) donttouch_stat
;
878 (void) v9fs_stat_free
;
879 (void) stat_to_v9stat
;
885 static void v9fs_version(V9fsState
*s
, V9fsPDU
*pdu
)
891 pdu_unmarshal(pdu
, offset
, "ds", &msize
, &version
);
893 if (strcmp(version
.data
, "9P2000.u")) {
894 v9fs_string_sprintf(&version
, "unknown");
897 offset
+= pdu_marshal(pdu
, offset
, "ds", msize
, &version
);
898 complete_pdu(s
, pdu
, offset
);
900 v9fs_string_free(&version
);
903 static void v9fs_attach(V9fsState
*s
, V9fsPDU
*pdu
)
905 int32_t fid
, afid
, n_uname
;
906 V9fsString uname
, aname
;
912 pdu_unmarshal(pdu
, offset
, "ddssd", &fid
, &afid
, &uname
, &aname
, &n_uname
);
914 fidp
= alloc_fid(s
, fid
);
922 v9fs_string_sprintf(&fidp
->path
, "%s", "/");
923 err
= fid_to_qid(s
, fidp
, &qid
);
930 offset
+= pdu_marshal(pdu
, offset
, "Q", &qid
);
934 complete_pdu(s
, pdu
, err
);
935 v9fs_string_free(&uname
);
936 v9fs_string_free(&aname
);
939 typedef struct V9fsStatState
{
947 static void v9fs_stat_post_lstat(V9fsState
*s
, V9fsStatState
*vs
, int err
)
954 err
= stat_to_v9stat(s
, &vs
->fidp
->path
, &vs
->stbuf
, &vs
->v9stat
);
958 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "wS", 0, &vs
->v9stat
);
962 complete_pdu(s
, vs
->pdu
, err
);
963 v9fs_stat_free(&vs
->v9stat
);
967 static void v9fs_stat(V9fsState
*s
, V9fsPDU
*pdu
)
973 vs
= qemu_malloc(sizeof(*vs
));
977 memset(&vs
->v9stat
, 0, sizeof(vs
->v9stat
));
979 pdu_unmarshal(vs
->pdu
, vs
->offset
, "d", &fid
);
981 vs
->fidp
= lookup_fid(s
, fid
);
982 if (vs
->fidp
== NULL
) {
987 err
= v9fs_do_lstat(s
, &vs
->fidp
->path
, &vs
->stbuf
);
988 v9fs_stat_post_lstat(s
, vs
, err
);
992 complete_pdu(s
, vs
->pdu
, err
);
993 v9fs_stat_free(&vs
->v9stat
);
997 typedef struct V9fsWalkState
{
1004 V9fsFidState
*newfidp
;
1010 static void v9fs_walk_complete(V9fsState
*s
, V9fsWalkState
*vs
, int err
)
1012 complete_pdu(s
, vs
->pdu
, err
);
1015 for (vs
->name_idx
= 0; vs
->name_idx
< vs
->nwnames
; vs
->name_idx
++) {
1016 v9fs_string_free(&vs
->wnames
[vs
->name_idx
]);
1019 qemu_free(vs
->wnames
);
1020 qemu_free(vs
->qids
);
1024 static void v9fs_walk_marshal(V9fsWalkState
*vs
)
1028 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "w", vs
->nwnames
);
1030 for (i
= 0; i
< vs
->nwnames
; i
++) {
1031 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "Q", &vs
->qids
[i
]);
1035 static void v9fs_walk_post_newfid_lstat(V9fsState
*s
, V9fsWalkState
*vs
,
1039 free_fid(s
, vs
->newfidp
->fid
);
1040 v9fs_string_free(&vs
->path
);
1045 stat_to_qid(&vs
->stbuf
, &vs
->qids
[vs
->name_idx
]);
1048 if (vs
->name_idx
< vs
->nwnames
) {
1049 v9fs_string_sprintf(&vs
->path
, "%s/%s", vs
->newfidp
->path
.data
,
1050 vs
->wnames
[vs
->name_idx
].data
);
1051 v9fs_string_copy(&vs
->newfidp
->path
, &vs
->path
);
1053 err
= v9fs_do_lstat(s
, &vs
->newfidp
->path
, &vs
->stbuf
);
1054 v9fs_walk_post_newfid_lstat(s
, vs
, err
);
1058 v9fs_string_free(&vs
->path
);
1059 v9fs_walk_marshal(vs
);
1062 v9fs_walk_complete(s
, vs
, err
);
1065 static void v9fs_walk_post_oldfid_lstat(V9fsState
*s
, V9fsWalkState
*vs
,
1069 v9fs_string_free(&vs
->path
);
1074 stat_to_qid(&vs
->stbuf
, &vs
->qids
[vs
->name_idx
]);
1076 if (vs
->name_idx
< vs
->nwnames
) {
1078 v9fs_string_sprintf(&vs
->path
, "%s/%s",
1079 vs
->fidp
->path
.data
, vs
->wnames
[vs
->name_idx
].data
);
1080 v9fs_string_copy(&vs
->fidp
->path
, &vs
->path
);
1082 err
= v9fs_do_lstat(s
, &vs
->fidp
->path
, &vs
->stbuf
);
1083 v9fs_walk_post_oldfid_lstat(s
, vs
, err
);
1087 v9fs_string_free(&vs
->path
);
1088 v9fs_walk_marshal(vs
);
1091 v9fs_walk_complete(s
, vs
, err
);
1094 static void v9fs_walk(V9fsState
*s
, V9fsPDU
*pdu
)
1096 int32_t fid
, newfid
;
1101 vs
= qemu_malloc(sizeof(*vs
));
1107 vs
->offset
+= pdu_unmarshal(vs
->pdu
, vs
->offset
, "ddw", &fid
,
1108 &newfid
, &vs
->nwnames
);
1111 vs
->wnames
= qemu_mallocz(sizeof(vs
->wnames
[0]) * vs
->nwnames
);
1113 vs
->qids
= qemu_mallocz(sizeof(vs
->qids
[0]) * vs
->nwnames
);
1115 for (i
= 0; i
< vs
->nwnames
; i
++) {
1116 vs
->offset
+= pdu_unmarshal(vs
->pdu
, vs
->offset
, "s",
1121 vs
->fidp
= lookup_fid(s
, fid
);
1122 if (vs
->fidp
== NULL
) {
1127 /* FIXME: is this really valid? */
1128 if (fid
== newfid
) {
1130 BUG_ON(vs
->fidp
->fd
!= -1);
1131 BUG_ON(vs
->fidp
->dir
);
1132 v9fs_string_init(&vs
->path
);
1135 if (vs
->name_idx
< vs
->nwnames
) {
1136 v9fs_string_sprintf(&vs
->path
, "%s/%s",
1137 vs
->fidp
->path
.data
, vs
->wnames
[vs
->name_idx
].data
);
1138 v9fs_string_copy(&vs
->fidp
->path
, &vs
->path
);
1140 err
= v9fs_do_lstat(s
, &vs
->fidp
->path
, &vs
->stbuf
);
1141 v9fs_walk_post_oldfid_lstat(s
, vs
, err
);
1145 vs
->newfidp
= alloc_fid(s
, newfid
);
1146 if (vs
->newfidp
== NULL
) {
1151 vs
->newfidp
->uid
= vs
->fidp
->uid
;
1152 v9fs_string_init(&vs
->path
);
1154 v9fs_string_copy(&vs
->newfidp
->path
, &vs
->fidp
->path
);
1156 if (vs
->name_idx
< vs
->nwnames
) {
1157 v9fs_string_sprintf(&vs
->path
, "%s/%s", vs
->newfidp
->path
.data
,
1158 vs
->wnames
[vs
->name_idx
].data
);
1159 v9fs_string_copy(&vs
->newfidp
->path
, &vs
->path
);
1161 err
= v9fs_do_lstat(s
, &vs
->newfidp
->path
, &vs
->stbuf
);
1162 v9fs_walk_post_newfid_lstat(s
, vs
, err
);
1167 v9fs_walk_marshal(vs
);
1170 v9fs_walk_complete(s
, vs
, err
);
1173 typedef struct V9fsOpenState
{
1195 static int omode_to_uflags(int8_t mode
)
1214 if (mode
& Otrunc
) {
1218 if (mode
& Oappend
) {
1229 static void v9fs_open_post_opendir(V9fsState
*s
, V9fsOpenState
*vs
, int err
)
1231 if (vs
->fidp
->dir
== NULL
) {
1236 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "Qd", &vs
->qid
, 0);
1239 complete_pdu(s
, vs
->pdu
, err
);
1244 static void v9fs_open_post_open(V9fsState
*s
, V9fsOpenState
*vs
, int err
)
1246 if (vs
->fidp
->fd
== -1) {
1251 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "Qd", &vs
->qid
, 0);
1254 complete_pdu(s
, vs
->pdu
, err
);
1258 static void v9fs_open_post_lstat(V9fsState
*s
, V9fsOpenState
*vs
, int err
)
1265 stat_to_qid(&vs
->stbuf
, &vs
->qid
);
1267 if (S_ISDIR(vs
->stbuf
.st_mode
)) {
1268 vs
->fidp
->dir
= v9fs_do_opendir(s
, &vs
->fidp
->path
);
1269 v9fs_open_post_opendir(s
, vs
, err
);
1271 vs
->fidp
->fd
= v9fs_do_open(s
, &vs
->fidp
->path
,
1272 omode_to_uflags(vs
->mode
));
1273 v9fs_open_post_open(s
, vs
, err
);
1277 complete_pdu(s
, vs
->pdu
, err
);
1281 static void v9fs_open(V9fsState
*s
, V9fsPDU
*pdu
)
1288 vs
= qemu_malloc(sizeof(*vs
));
1292 pdu_unmarshal(vs
->pdu
, vs
->offset
, "db", &fid
, &vs
->mode
);
1294 vs
->fidp
= lookup_fid(s
, fid
);
1295 if (vs
->fidp
== NULL
) {
1300 BUG_ON(vs
->fidp
->fd
!= -1);
1301 BUG_ON(vs
->fidp
->dir
);
1303 err
= v9fs_do_lstat(s
, &vs
->fidp
->path
, &vs
->stbuf
);
1305 v9fs_open_post_lstat(s
, vs
, err
);
1308 complete_pdu(s
, pdu
, err
);
1312 static void v9fs_clunk(V9fsState
*s
, V9fsPDU
*pdu
)
1318 pdu_unmarshal(pdu
, offset
, "d", &fid
);
1320 err
= free_fid(s
, fid
);
1328 complete_pdu(s
, pdu
, err
);
1331 typedef struct V9fsReadState
{
1338 struct iovec iov
[128]; /* FIXME: bad, bad, bad */
1341 struct dirent
*dent
;
1350 static void v9fs_read_post_readdir(V9fsState
*, V9fsReadState
*, ssize_t
);
1352 static void v9fs_read_post_seekdir(V9fsState
*s
, V9fsReadState
*vs
, ssize_t err
)
1357 v9fs_stat_free(&vs
->v9stat
);
1358 v9fs_string_free(&vs
->name
);
1359 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "d", vs
->count
);
1360 vs
->offset
+= vs
->count
;
1363 complete_pdu(s
, vs
->pdu
, err
);
1368 static void v9fs_read_post_dir_lstat(V9fsState
*s
, V9fsReadState
*vs
,
1375 err
= stat_to_v9stat(s
, &vs
->name
, &vs
->stbuf
, &vs
->v9stat
);
1380 vs
->len
= pdu_marshal(vs
->pdu
, vs
->offset
+ 4 + vs
->count
, "S",
1382 if ((vs
->len
!= (vs
->v9stat
.size
+ 2)) ||
1383 ((vs
->count
+ vs
->len
) > vs
->max_count
)) {
1384 v9fs_do_seekdir(s
, vs
->fidp
->dir
, vs
->dir_pos
);
1385 v9fs_read_post_seekdir(s
, vs
, err
);
1388 vs
->count
+= vs
->len
;
1389 v9fs_stat_free(&vs
->v9stat
);
1390 v9fs_string_free(&vs
->name
);
1391 vs
->dir_pos
= vs
->dent
->d_off
;
1392 vs
->dent
= v9fs_do_readdir(s
, vs
->fidp
->dir
);
1393 v9fs_read_post_readdir(s
, vs
, err
);
1396 v9fs_do_seekdir(s
, vs
->fidp
->dir
, vs
->dir_pos
);
1397 v9fs_read_post_seekdir(s
, vs
, err
);
1402 static void v9fs_read_post_readdir(V9fsState
*s
, V9fsReadState
*vs
, ssize_t err
)
1405 memset(&vs
->v9stat
, 0, sizeof(vs
->v9stat
));
1406 v9fs_string_init(&vs
->name
);
1407 v9fs_string_sprintf(&vs
->name
, "%s/%s", vs
->fidp
->path
.data
,
1409 err
= v9fs_do_lstat(s
, &vs
->name
, &vs
->stbuf
);
1410 v9fs_read_post_dir_lstat(s
, vs
, err
);
1414 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "d", vs
->count
);
1415 vs
->offset
+= vs
->count
;
1417 complete_pdu(s
, vs
->pdu
, err
);
1422 static void v9fs_read_post_telldir(V9fsState
*s
, V9fsReadState
*vs
, ssize_t err
)
1424 vs
->dent
= v9fs_do_readdir(s
, vs
->fidp
->dir
);
1425 v9fs_read_post_readdir(s
, vs
, err
);
1429 static void v9fs_read_post_rewinddir(V9fsState
*s
, V9fsReadState
*vs
,
1432 vs
->dir_pos
= v9fs_do_telldir(s
, vs
->fidp
->dir
);
1433 v9fs_read_post_telldir(s
, vs
, err
);
1437 static void v9fs_read_post_readv(V9fsState
*s
, V9fsReadState
*vs
, ssize_t err
)
1440 /* IO error return the error */
1444 vs
->total
+= vs
->len
;
1445 vs
->sg
= adjust_sg(vs
->sg
, vs
->len
, &vs
->cnt
);
1446 if (vs
->total
< vs
->count
&& vs
->len
> 0) {
1449 print_sg(vs
->sg
, vs
->cnt
);
1451 vs
->len
= v9fs_do_readv(s
, vs
->fidp
->fd
, vs
->sg
, vs
->cnt
);
1452 } while (vs
->len
== -1 && errno
== EINTR
);
1453 if (vs
->len
== -1) {
1456 v9fs_read_post_readv(s
, vs
, err
);
1459 vs
->offset
+= pdu_marshal(vs
->pdu
, vs
->offset
, "d", vs
->total
);
1460 vs
->offset
+= vs
->count
;
1464 complete_pdu(s
, vs
->pdu
, err
);
1468 static void v9fs_read_post_lseek(V9fsState
*s
, V9fsReadState
*vs
, ssize_t err
)
1474 vs
->sg
= cap_sg(vs
->sg
, vs
->count
, &vs
->cnt
);
1476 if (vs
->total
< vs
->count
) {
1479 print_sg(vs
->sg
, vs
->cnt
);
1481 vs
->len
= v9fs_do_readv(s
, vs
->fidp
->fd
, vs
->sg
, vs
->cnt
);
1482 } while (vs
->len
== -1 && errno
== EINTR
);
1483 if (vs
->len
== -1) {
1486 v9fs_read_post_readv(s
, vs
, err
);
1490 complete_pdu(s
, vs
->pdu
, err
);
1494 static void v9fs_read(V9fsState
*s
, V9fsPDU
*pdu
)
1500 vs
= qemu_malloc(sizeof(*vs
));
1507 pdu_unmarshal(vs
->pdu
, vs
->offset
, "dqd", &fid
, &vs
->off
, &vs
->count
);
1509 vs
->fidp
= lookup_fid(s
, fid
);
1510 if (vs
->fidp
== NULL
) {
1515 if (vs
->fidp
->dir
) {
1516 vs
->max_count
= vs
->count
;
1519 v9fs_do_rewinddir(s
, vs
->fidp
->dir
);
1521 v9fs_read_post_rewinddir(s
, vs
, err
);
1523 } else if (vs
->fidp
->fd
!= -1) {
1525 pdu_marshal(vs
->pdu
, vs
->offset
+ 4, "v", vs
->sg
, &vs
->cnt
);
1526 err
= v9fs_do_lseek(s
, vs
->fidp
->fd
, vs
->off
, SEEK_SET
);
1527 v9fs_read_post_lseek(s
, vs
, err
);
1533 complete_pdu(s
, pdu
, err
);
1537 static void v9fs_write(V9fsState
*s
, V9fsPDU
*pdu
)
1544 static void v9fs_create(V9fsState
*s
, V9fsPDU
*pdu
)
1551 static void v9fs_flush(V9fsState
*s
, V9fsPDU
*pdu
)
1559 static void v9fs_remove(V9fsState
*s
, V9fsPDU
*pdu
)
1566 static void v9fs_wstat(V9fsState
*s
, V9fsPDU
*pdu
)
1573 typedef void (pdu_handler_t
)(V9fsState
*s
, V9fsPDU
*pdu
);
1575 static pdu_handler_t
*pdu_handlers
[] = {
1576 [P9_TVERSION
] = v9fs_version
,
1577 [P9_TATTACH
] = v9fs_attach
,
1578 [P9_TSTAT
] = v9fs_stat
,
1579 [P9_TWALK
] = v9fs_walk
,
1580 [P9_TCLUNK
] = v9fs_clunk
,
1581 [P9_TOPEN
] = v9fs_open
,
1582 [P9_TREAD
] = v9fs_read
,
1584 [P9_TAUTH
] = v9fs_auth
,
1586 [P9_TFLUSH
] = v9fs_flush
,
1587 [P9_TCREATE
] = v9fs_create
,
1588 [P9_TWRITE
] = v9fs_write
,
1589 [P9_TWSTAT
] = v9fs_wstat
,
1590 [P9_TREMOVE
] = v9fs_remove
,
1593 static void submit_pdu(V9fsState
*s
, V9fsPDU
*pdu
)
1595 pdu_handler_t
*handler
;
1601 BUG_ON(pdu
->id
>= ARRAY_SIZE(pdu_handlers
));
1603 handler
= pdu_handlers
[pdu
->id
];
1604 BUG_ON(handler
== NULL
);
1609 static void handle_9p_output(VirtIODevice
*vdev
, VirtQueue
*vq
)
1611 V9fsState
*s
= (V9fsState
*)vdev
;
1615 while ((pdu
= alloc_pdu(s
)) &&
1616 (len
= virtqueue_pop(vq
, &pdu
->elem
)) != 0) {
1619 BUG_ON(pdu
->elem
.out_num
== 0 || pdu
->elem
.in_num
== 0);
1620 BUG_ON(pdu
->elem
.out_sg
[0].iov_len
< 7);
1622 ptr
= pdu
->elem
.out_sg
[0].iov_base
;
1624 memcpy(&pdu
->size
, ptr
, 4);
1626 memcpy(&pdu
->tag
, ptr
+ 5, 2);
1634 static uint32_t virtio_9p_get_features(VirtIODevice
*vdev
, uint32_t features
)
1636 features
|= 1 << VIRTIO_9P_MOUNT_TAG
;
1640 static V9fsState
*to_virtio_9p(VirtIODevice
*vdev
)
1642 return (V9fsState
*)vdev
;
1645 static void virtio_9p_get_config(VirtIODevice
*vdev
, uint8_t *config
)
1647 struct virtio_9p_config
*cfg
;
1648 V9fsState
*s
= to_virtio_9p(vdev
);
1650 cfg
= qemu_mallocz(sizeof(struct virtio_9p_config
) +
1652 stw_raw(&cfg
->tag_len
, s
->tag_len
);
1653 memcpy(cfg
->tag
, s
->tag
, s
->tag_len
);
1654 memcpy(config
, cfg
, s
->config_size
);
1658 VirtIODevice
*virtio_9p_init(DeviceState
*dev
, V9fsConf
*conf
)
1666 s
= (V9fsState
*)virtio_common_init("virtio-9p",
1668 sizeof(struct virtio_9p_config
)+
1672 /* initialize pdu allocator */
1673 QLIST_INIT(&s
->free_list
);
1674 for (i
= 0; i
< (MAX_REQ
- 1); i
++) {
1675 QLIST_INSERT_HEAD(&s
->free_list
, &s
->pdus
[i
], next
);
1678 s
->vq
= virtio_add_queue(&s
->vdev
, MAX_REQ
, handle_9p_output
);
1680 fse
= get_fsdev_fsentry(conf
->fsdev_id
);
1683 /* We don't have a fsdev identified by fsdev_id */
1684 fprintf(stderr
, "Virtio-9p device couldn't find fsdev "
1685 "with the id %s\n", conf
->fsdev_id
);
1689 if (!fse
->path
|| !conf
->tag
) {
1690 /* we haven't specified a mount_tag or the path */
1691 fprintf(stderr
, "fsdev with id %s needs path "
1692 "and Virtio-9p device needs mount_tag arguments\n",
1697 if (lstat(fse
->path
, &stat
)) {
1698 fprintf(stderr
, "share path %s does not exist\n", fse
->path
);
1700 } else if (!S_ISDIR(stat
.st_mode
)) {
1701 fprintf(stderr
, "share path %s is not a directory \n", fse
->path
);
1705 s
->ctx
.fs_root
= qemu_strdup(fse
->path
);
1706 len
= strlen(conf
->tag
);
1707 if (len
> MAX_TAG_LEN
) {
1710 /* s->tag is non-NULL terminated string */
1711 s
->tag
= qemu_malloc(len
);
1712 memcpy(s
->tag
, conf
->tag
, len
);
1717 s
->vdev
.get_features
= virtio_9p_get_features
;
1718 s
->config_size
= sizeof(struct virtio_9p_config
) +
1720 s
->vdev
.get_config
= virtio_9p_get_config
;