4 * Copyright IBM, Corp. 2010
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"
36 static int omode_to_uflags(int8_t mode)
70 void cred_init(FsCred *credp)
78 static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
80 return s->ops->lstat(&s->ctx, path->data, stbuf);
83 static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
87 buf->data = qemu_malloc(1024);
89 len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
98 static int v9fs_do_close(V9fsState *s, int fd)
100 return s->ops->close(&s->ctx, fd);
103 static int v9fs_do_closedir(V9fsState *s, DIR *dir)
105 return s->ops->closedir(&s->ctx, dir);
108 static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
110 return s->ops->open(&s->ctx, path->data, flags);
113 static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
115 return s->ops->opendir(&s->ctx, path->data);
118 static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
120 return s->ops->rewinddir(&s->ctx, dir);
123 static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
125 return s->ops->telldir(&s->ctx, dir);
128 static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
130 return s->ops->readdir(&s->ctx, dir);
133 static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
135 return s->ops->seekdir(&s->ctx, dir, off);
138 static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
141 return s->ops->readv(&s->ctx, fd, iov, iovcnt);
144 static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
146 return s->ops->lseek(&s->ctx, fd, offset, whence);
149 static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
152 return s->ops->writev(&s->ctx, fd, iov, iovcnt);
155 static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
160 return s->ops->chmod(&s->ctx, path->data, &cred);
163 static int v9fs_do_mknod(V9fsState *s, char *name,
164 mode_t mode, dev_t dev, uid_t uid, gid_t gid)
172 return s->ops->mknod(&s->ctx, name, &cred);
175 static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
176 uid_t uid, gid_t gid)
185 return s->ops->mkdir(&s->ctx, name, &cred);
188 static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
190 return s->ops->fstat(&s->ctx, fd, stbuf);
193 static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
201 cred.fc_mode = mode & 07777;
204 return s->ops->open2(&s->ctx, fullname, flags, &cred);
207 static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
208 const char *oldpath, const char *newpath, gid_t gid)
212 cred.fc_uid = fidp->uid;
216 return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
219 static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
221 return s->ops->link(&s->ctx, oldpath->data, newpath->data);
224 static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
226 return s->ops->truncate(&s->ctx, path->data, size);
229 static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
232 return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
235 static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
242 return s->ops->chown(&s->ctx, path->data, &cred);
245 static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
246 const struct timespec times[2])
248 return s->ops->utimensat(&s->ctx, path->data, times);
251 static int v9fs_do_remove(V9fsState *s, V9fsString *path)
253 return s->ops->remove(&s->ctx, path->data);
256 static int v9fs_do_fsync(V9fsState *s, int fd)
258 return s->ops->fsync(&s->ctx, fd);
261 static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
263 return s->ops->statfs(&s->ctx, path->data, stbuf);
266 static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
267 V9fsString *xattr_name,
268 void *value, size_t size)
270 return s->ops->lgetxattr(&s->ctx, path->data,
271 xattr_name->data, value, size);
274 static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
275 void *value, size_t size)
277 return s->ops->llistxattr(&s->ctx, path->data,
281 static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
282 V9fsString *xattr_name,
283 void *value, size_t size, int flags)
285 return s->ops->lsetxattr(&s->ctx, path->data,
286 xattr_name->data, value, size, flags);
289 static void v9fs_string_init(V9fsString *str)
295 static void v9fs_string_free(V9fsString *str)
297 qemu_free(str->data);
302 static void v9fs_string_null(V9fsString *str)
304 v9fs_string_free(str);
307 static int number_to_string(void *arg, char type)
309 unsigned int ret = 0;
313 unsigned int num = *(unsigned int *)arg;
322 printf("Number_to_string: Unknown number format\n");
329 static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
332 char *iter = (char *)fmt;
336 unsigned int arg_uint;
338 /* Find the number of %'s that denotes an argument */
339 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
344 len = strlen(fmt) - 2*nr_args;
354 /* Now parse the format string */
355 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
359 arg_uint = va_arg(ap2, unsigned int);
360 len += number_to_string((void *)&arg_uint, 'u');
363 arg_char_ptr = va_arg(ap2, char *);
364 len += strlen(arg_char_ptr);
371 "v9fs_string_alloc_printf:Incorrect format %c", *iter);
378 *strp = qemu_malloc((len + 1) * sizeof(**strp));
380 return vsprintf(*strp, fmt, ap);
383 static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
388 v9fs_string_free(str);
391 err = v9fs_string_alloc_printf(&str->data, fmt, ap);
398 static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
400 v9fs_string_free(lhs);
401 v9fs_string_sprintf(lhs, "%s", rhs->data);
404 static size_t v9fs_string_size(V9fsString *str)
409 static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
413 for (f = s->fid_list; f; f = f->next) {
422 static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
426 f = lookup_fid(s, fid);
431 f = qemu_mallocz(sizeof(V9fsFidState));
434 f->fid_type = P9_FID_NONE;
436 f->next = s->fid_list;
442 static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
446 if (fidp->fs.xattr.copied_len == -1) {
447 /* getxattr/listxattr fid */
451 * if this is fid for setxattr. clunk should
452 * result in setxattr localcall
454 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
455 /* clunk after partial write */
459 retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
460 fidp->fs.xattr.value,
462 fidp->fs.xattr.flags);
464 v9fs_string_free(&fidp->fs.xattr.name);
466 if (fidp->fs.xattr.value) {
467 qemu_free(fidp->fs.xattr.value);
472 static int free_fid(V9fsState *s, int32_t fid)
475 V9fsFidState **fidpp, *fidp;
477 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
478 if ((*fidpp)->fid == fid) {
483 if (*fidpp == NULL) {
490 if (fidp->fid_type == P9_FID_FILE) {
491 v9fs_do_close(s, fidp->fs.fd);
492 } else if (fidp->fid_type == P9_FID_DIR) {
493 v9fs_do_closedir(s, fidp->fs.dir);
494 } else if (fidp->fid_type == P9_FID_XATTR) {
495 retval = v9fs_xattr_fid_clunk(s, fidp);
497 v9fs_string_free(&fidp->path);
503 #define P9_QID_TYPE_DIR 0x80
504 #define P9_QID_TYPE_SYMLINK 0x02
506 #define P9_STAT_MODE_DIR 0x80000000
507 #define P9_STAT_MODE_APPEND 0x40000000
508 #define P9_STAT_MODE_EXCL 0x20000000
509 #define P9_STAT_MODE_MOUNT 0x10000000
510 #define P9_STAT_MODE_AUTH 0x08000000
511 #define P9_STAT_MODE_TMP 0x04000000
512 #define P9_STAT_MODE_SYMLINK 0x02000000
513 #define P9_STAT_MODE_LINK 0x01000000
514 #define P9_STAT_MODE_DEVICE 0x00800000
515 #define P9_STAT_MODE_NAMED_PIPE 0x00200000
516 #define P9_STAT_MODE_SOCKET 0x00100000
517 #define P9_STAT_MODE_SETUID 0x00080000
518 #define P9_STAT_MODE_SETGID 0x00040000
519 #define P9_STAT_MODE_SETVTX 0x00010000
521 #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
522 P9_STAT_MODE_SYMLINK | \
523 P9_STAT_MODE_LINK | \
524 P9_STAT_MODE_DEVICE | \
525 P9_STAT_MODE_NAMED_PIPE | \
528 /* This is the algorithm from ufs in spfs */
529 static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
533 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
534 memcpy(&qidp->path, &stbuf->st_ino, size);
535 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
537 if (S_ISDIR(stbuf->st_mode)) {
538 qidp->type |= P9_QID_TYPE_DIR;
540 if (S_ISLNK(stbuf->st_mode)) {
541 qidp->type |= P9_QID_TYPE_SYMLINK;
545 static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
550 err = v9fs_do_lstat(s, &fidp->path, &stbuf);
555 stat_to_qid(&stbuf, qidp);
559 static V9fsPDU *alloc_pdu(V9fsState *s)
563 if (!QLIST_EMPTY(&s->free_list)) {
564 pdu = QLIST_FIRST(&s->free_list);
565 QLIST_REMOVE(pdu, next);
570 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
573 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
577 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
578 size_t offset, size_t size, int pack)
583 for (i = 0; size && i < sg_count; i++) {
585 if (offset >= sg[i].iov_len) {
587 offset -= sg[i].iov_len;
590 len = MIN(sg[i].iov_len - offset, size);
592 memcpy(sg[i].iov_base + offset, addr, len);
594 memcpy(addr, sg[i].iov_base + offset, len);
609 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
611 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
615 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
618 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
622 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
626 struct iovec *src_sg;
630 src_sg = pdu->elem.in_sg;
631 num = pdu->elem.in_num;
633 src_sg = pdu->elem.out_sg;
634 num = pdu->elem.out_num;
638 for (i = 0; i < num; i++) {
640 sg[j].iov_base = src_sg[i].iov_base;
641 sg[j].iov_len = src_sg[i].iov_len;
643 } else if (offset < (src_sg[i].iov_len + pos)) {
644 sg[j].iov_base = src_sg[i].iov_base;
645 sg[j].iov_len = src_sg[i].iov_len;
646 sg[j].iov_base += (offset - pos);
647 sg[j].iov_len -= (offset - pos);
650 pos += src_sg[i].iov_len;
656 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
658 size_t old_offset = offset;
663 for (i = 0; fmt[i]; i++) {
666 uint8_t *valp = va_arg(ap, uint8_t *);
667 offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
672 valp = va_arg(ap, uint16_t *);
673 val = le16_to_cpupu(valp);
674 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
680 valp = va_arg(ap, uint32_t *);
681 val = le32_to_cpupu(valp);
682 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
688 valp = va_arg(ap, uint64_t *);
689 val = le64_to_cpup(valp);
690 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
695 struct iovec *iov = va_arg(ap, struct iovec *);
696 int *iovcnt = va_arg(ap, int *);
697 *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
701 V9fsString *str = va_arg(ap, V9fsString *);
702 offset += pdu_unmarshal(pdu, offset, "w", &str->size);
703 /* FIXME: sanity check str->size */
704 str->data = qemu_malloc(str->size + 1);
705 offset += pdu_unpack(str->data, pdu, offset, str->size);
706 str->data[str->size] = 0;
710 V9fsQID *qidp = va_arg(ap, V9fsQID *);
711 offset += pdu_unmarshal(pdu, offset, "bdq",
712 &qidp->type, &qidp->version, &qidp->path);
716 V9fsStat *statp = va_arg(ap, V9fsStat *);
717 offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
718 &statp->size, &statp->type, &statp->dev,
719 &statp->qid, &statp->mode, &statp->atime,
720 &statp->mtime, &statp->length,
721 &statp->name, &statp->uid, &statp->gid,
722 &statp->muid, &statp->extension,
723 &statp->n_uid, &statp->n_gid,
728 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
729 offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
730 &iattr->valid, &iattr->mode,
731 &iattr->uid, &iattr->gid, &iattr->size,
732 &iattr->atime_sec, &iattr->atime_nsec,
733 &iattr->mtime_sec, &iattr->mtime_nsec);
743 return offset - old_offset;
746 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
748 size_t old_offset = offset;
753 for (i = 0; fmt[i]; i++) {
756 uint8_t val = va_arg(ap, int);
757 offset += pdu_pack(pdu, offset, &val, sizeof(val));
762 cpu_to_le16w(&val, va_arg(ap, int));
763 offset += pdu_pack(pdu, offset, &val, sizeof(val));
768 cpu_to_le32w(&val, va_arg(ap, uint32_t));
769 offset += pdu_pack(pdu, offset, &val, sizeof(val));
774 cpu_to_le64w(&val, va_arg(ap, uint64_t));
775 offset += pdu_pack(pdu, offset, &val, sizeof(val));
779 struct iovec *iov = va_arg(ap, struct iovec *);
780 int *iovcnt = va_arg(ap, int *);
781 *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
785 V9fsString *str = va_arg(ap, V9fsString *);
786 offset += pdu_marshal(pdu, offset, "w", str->size);
787 offset += pdu_pack(pdu, offset, str->data, str->size);
791 V9fsQID *qidp = va_arg(ap, V9fsQID *);
792 offset += pdu_marshal(pdu, offset, "bdq",
793 qidp->type, qidp->version, qidp->path);
797 V9fsStat *statp = va_arg(ap, V9fsStat *);
798 offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
799 statp->size, statp->type, statp->dev,
800 &statp->qid, statp->mode, statp->atime,
801 statp->mtime, statp->length, &statp->name,
802 &statp->uid, &statp->gid, &statp->muid,
803 &statp->extension, statp->n_uid,
804 statp->n_gid, statp->n_muid);
808 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
809 offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
810 statp->st_result_mask,
811 &statp->qid, statp->st_mode,
812 statp->st_uid, statp->st_gid,
813 statp->st_nlink, statp->st_rdev,
814 statp->st_size, statp->st_blksize, statp->st_blocks,
815 statp->st_atime_sec, statp->st_atime_nsec,
816 statp->st_mtime_sec, statp->st_mtime_nsec,
817 statp->st_ctime_sec, statp->st_ctime_nsec,
818 statp->st_btime_sec, statp->st_btime_nsec,
819 statp->st_gen, statp->st_data_version);
828 return offset - old_offset;
831 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
833 int8_t id = pdu->id + 1; /* Response */
839 str.data = strerror(err);
840 str.size = strlen(str.data);
843 len += pdu_marshal(pdu, len, "s", &str);
845 len += pdu_marshal(pdu, len, "d", err);
851 /* fill out the header */
852 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
854 /* keep these in sync */
858 /* push onto queue and notify */
859 virtqueue_push(s->vq, &pdu->elem, len);
861 /* FIXME: we should batch these completions */
862 virtio_notify(&s->vdev, s->vq);
867 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
872 if (mode & P9_STAT_MODE_DIR) {
877 if (mode & P9_STAT_MODE_SYMLINK) {
880 if (mode & P9_STAT_MODE_SOCKET) {
883 if (mode & P9_STAT_MODE_NAMED_PIPE) {
886 if (mode & P9_STAT_MODE_DEVICE) {
887 if (extension && extension->data[0] == 'c') {
899 if (mode & P9_STAT_MODE_SETUID) {
902 if (mode & P9_STAT_MODE_SETGID) {
905 if (mode & P9_STAT_MODE_SETVTX) {
912 static int donttouch_stat(V9fsStat *stat)
914 if (stat->type == -1 &&
916 stat->qid.type == -1 &&
917 stat->qid.version == -1 &&
918 stat->qid.path == -1 &&
922 stat->length == -1 &&
929 stat->n_muid == -1) {
936 static void v9fs_stat_free(V9fsStat *stat)
938 v9fs_string_free(&stat->name);
939 v9fs_string_free(&stat->uid);
940 v9fs_string_free(&stat->gid);
941 v9fs_string_free(&stat->muid);
942 v9fs_string_free(&stat->extension);
945 static uint32_t stat_to_v9mode(const struct stat *stbuf)
949 mode = stbuf->st_mode & 0777;
950 if (S_ISDIR(stbuf->st_mode)) {
951 mode |= P9_STAT_MODE_DIR;
955 if (S_ISLNK(stbuf->st_mode)) {
956 mode |= P9_STAT_MODE_SYMLINK;
959 if (S_ISSOCK(stbuf->st_mode)) {
960 mode |= P9_STAT_MODE_SOCKET;
963 if (S_ISFIFO(stbuf->st_mode)) {
964 mode |= P9_STAT_MODE_NAMED_PIPE;
967 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
968 mode |= P9_STAT_MODE_DEVICE;
971 if (stbuf->st_mode & S_ISUID) {
972 mode |= P9_STAT_MODE_SETUID;
975 if (stbuf->st_mode & S_ISGID) {
976 mode |= P9_STAT_MODE_SETGID;
979 if (stbuf->st_mode & S_ISVTX) {
980 mode |= P9_STAT_MODE_SETVTX;
987 static int stat_to_v9stat(V9fsState *s, V9fsString *name,
988 const struct stat *stbuf,
994 memset(v9stat, 0, sizeof(*v9stat));
996 stat_to_qid(stbuf, &v9stat->qid);
997 v9stat->mode = stat_to_v9mode(stbuf);
998 v9stat->atime = stbuf->st_atime;
999 v9stat->mtime = stbuf->st_mtime;
1000 v9stat->length = stbuf->st_size;
1002 v9fs_string_null(&v9stat->uid);
1003 v9fs_string_null(&v9stat->gid);
1004 v9fs_string_null(&v9stat->muid);
1007 v9stat->n_uid = stbuf->st_uid;
1008 v9stat->n_gid = stbuf->st_gid;
1011 v9fs_string_null(&v9stat->extension);
1013 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1014 err = v9fs_do_readlink(s, name, &v9stat->extension);
1019 v9stat->extension.data[err] = 0;
1020 v9stat->extension.size = err;
1021 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1022 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1023 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1024 major(stbuf->st_rdev), minor(stbuf->st_rdev));
1025 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1026 v9fs_string_sprintf(&v9stat->extension, "%s %u",
1027 "HARDLINKCOUNT", stbuf->st_nlink);
1031 str = strrchr(name->data, '/');
1038 v9fs_string_sprintf(&v9stat->name, "%s", str);
1041 v9fs_string_size(&v9stat->name) +
1042 v9fs_string_size(&v9stat->uid) +
1043 v9fs_string_size(&v9stat->gid) +
1044 v9fs_string_size(&v9stat->muid) +
1045 v9fs_string_size(&v9stat->extension);
1049 #define P9_STATS_MODE 0x00000001ULL
1050 #define P9_STATS_NLINK 0x00000002ULL
1051 #define P9_STATS_UID 0x00000004ULL
1052 #define P9_STATS_GID 0x00000008ULL
1053 #define P9_STATS_RDEV 0x00000010ULL
1054 #define P9_STATS_ATIME 0x00000020ULL
1055 #define P9_STATS_MTIME 0x00000040ULL
1056 #define P9_STATS_CTIME 0x00000080ULL
1057 #define P9_STATS_INO 0x00000100ULL
1058 #define P9_STATS_SIZE 0x00000200ULL
1059 #define P9_STATS_BLOCKS 0x00000400ULL
1061 #define P9_STATS_BTIME 0x00000800ULL
1062 #define P9_STATS_GEN 0x00001000ULL
1063 #define P9_STATS_DATA_VERSION 0x00002000ULL
1065 #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
1066 #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
1069 static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1070 V9fsStatDotl *v9lstat)
1072 memset(v9lstat, 0, sizeof(*v9lstat));
1074 v9lstat->st_mode = stbuf->st_mode;
1075 v9lstat->st_nlink = stbuf->st_nlink;
1076 v9lstat->st_uid = stbuf->st_uid;
1077 v9lstat->st_gid = stbuf->st_gid;
1078 v9lstat->st_rdev = stbuf->st_rdev;
1079 v9lstat->st_size = stbuf->st_size;
1080 v9lstat->st_blksize = stbuf->st_blksize;
1081 v9lstat->st_blocks = stbuf->st_blocks;
1082 v9lstat->st_atime_sec = stbuf->st_atime;
1083 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1084 v9lstat->st_mtime_sec = stbuf->st_mtime;
1085 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1086 v9lstat->st_ctime_sec = stbuf->st_ctime;
1087 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1088 /* Currently we only support BASIC fields in stat */
1089 v9lstat->st_result_mask = P9_STATS_BASIC;
1091 stat_to_qid(stbuf, &v9lstat->qid);
1094 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1096 while (len && *iovcnt) {
1097 if (len < sg->iov_len) {
1099 sg->iov_base += len;
1111 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1116 for (i = 0; i < *cnt; i++) {
1117 if ((total + sg[i].iov_len) > cap) {
1118 sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1122 total += sg[i].iov_len;
1130 static void print_sg(struct iovec *sg, int cnt)
1134 printf("sg[%d]: {", cnt);
1135 for (i = 0; i < cnt; i++) {
1139 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1144 static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1147 v9fs_string_init(&str);
1148 v9fs_string_copy(&str, dst);
1149 v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1150 v9fs_string_free(&str);
1153 static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
1158 pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1160 if (!strcmp(version.data, "9P2000.u")) {
1161 s->proto_version = V9FS_PROTO_2000U;
1162 } else if (!strcmp(version.data, "9P2000.L")) {
1163 s->proto_version = V9FS_PROTO_2000L;
1165 v9fs_string_sprintf(&version, "unknown");
1168 offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1169 complete_pdu(s, pdu, offset);
1171 v9fs_string_free(&version);
1174 static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
1176 int32_t fid, afid, n_uname;
1177 V9fsString uname, aname;
1183 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1185 fidp = alloc_fid(s, fid);
1191 fidp->uid = n_uname;
1193 v9fs_string_sprintf(&fidp->path, "%s", "/");
1194 err = fid_to_qid(s, fidp, &qid);
1201 offset += pdu_marshal(pdu, offset, "Q", &qid);
1205 complete_pdu(s, pdu, err);
1206 v9fs_string_free(&uname);
1207 v9fs_string_free(&aname);
1210 static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1217 err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1221 vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1225 complete_pdu(s, vs->pdu, err);
1226 v9fs_stat_free(&vs->v9stat);
1230 static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
1236 vs = qemu_malloc(sizeof(*vs));
1240 memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1242 pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1244 vs->fidp = lookup_fid(s, fid);
1245 if (vs->fidp == NULL) {
1250 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1251 v9fs_stat_post_lstat(s, vs, err);
1255 complete_pdu(s, vs->pdu, err);
1256 v9fs_stat_free(&vs->v9stat);
1260 static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
1268 stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
1269 vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
1273 complete_pdu(s, vs->pdu, err);
1277 static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
1280 V9fsStatStateDotl *vs;
1283 uint64_t request_mask;
1285 vs = qemu_malloc(sizeof(*vs));
1289 memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
1291 pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
1293 fidp = lookup_fid(s, fid);
1299 /* Currently we only support BASIC fields in stat, so there is no
1300 * need to look at request_mask.
1302 err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
1303 v9fs_getattr_post_lstat(s, vs, err);
1307 complete_pdu(s, vs->pdu, err);
1311 /* From Linux kernel code */
1312 #define ATTR_MODE (1 << 0)
1313 #define ATTR_UID (1 << 1)
1314 #define ATTR_GID (1 << 2)
1315 #define ATTR_SIZE (1 << 3)
1316 #define ATTR_ATIME (1 << 4)
1317 #define ATTR_MTIME (1 << 5)
1318 #define ATTR_CTIME (1 << 6)
1319 #define ATTR_MASK 127
1320 #define ATTR_ATIME_SET (1 << 7)
1321 #define ATTR_MTIME_SET (1 << 8)
1323 static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
1333 complete_pdu(s, vs->pdu, err);
1337 static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
1344 if (vs->v9iattr.valid & (ATTR_SIZE)) {
1345 err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
1347 v9fs_setattr_post_truncate(s, vs, err);
1351 complete_pdu(s, vs->pdu, err);
1355 static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
1363 /* If the only valid entry in iattr is ctime we can call
1364 * chown(-1,-1) to update the ctime of the file
1366 if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1367 ((vs->v9iattr.valid & ATTR_CTIME)
1368 && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1369 if (!(vs->v9iattr.valid & ATTR_UID)) {
1370 vs->v9iattr.uid = -1;
1372 if (!(vs->v9iattr.valid & ATTR_GID)) {
1373 vs->v9iattr.gid = -1;
1375 err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
1378 v9fs_setattr_post_chown(s, vs, err);
1382 complete_pdu(s, vs->pdu, err);
1386 static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
1393 if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1394 struct timespec times[2];
1395 if (vs->v9iattr.valid & ATTR_ATIME) {
1396 if (vs->v9iattr.valid & ATTR_ATIME_SET) {
1397 times[0].tv_sec = vs->v9iattr.atime_sec;
1398 times[0].tv_nsec = vs->v9iattr.atime_nsec;
1400 times[0].tv_nsec = UTIME_NOW;
1403 times[0].tv_nsec = UTIME_OMIT;
1406 if (vs->v9iattr.valid & ATTR_MTIME) {
1407 if (vs->v9iattr.valid & ATTR_MTIME_SET) {
1408 times[1].tv_sec = vs->v9iattr.mtime_sec;
1409 times[1].tv_nsec = vs->v9iattr.mtime_nsec;
1411 times[1].tv_nsec = UTIME_NOW;
1414 times[1].tv_nsec = UTIME_OMIT;
1416 err = v9fs_do_utimensat(s, &vs->fidp->path, times);
1418 v9fs_setattr_post_utimensat(s, vs, err);
1422 complete_pdu(s, vs->pdu, err);
1426 static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
1429 V9fsSetattrState *vs;
1432 vs = qemu_malloc(sizeof(*vs));
1436 pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
1438 vs->fidp = lookup_fid(s, fid);
1439 if (vs->fidp == NULL) {
1444 if (vs->v9iattr.valid & ATTR_MODE) {
1445 err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
1448 v9fs_setattr_post_chmod(s, vs, err);
1452 complete_pdu(s, vs->pdu, err);
1456 static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1458 complete_pdu(s, vs->pdu, err);
1461 for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1462 v9fs_string_free(&vs->wnames[vs->name_idx]);
1465 qemu_free(vs->wnames);
1466 qemu_free(vs->qids);
1470 static void v9fs_walk_marshal(V9fsWalkState *vs)
1474 vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1476 for (i = 0; i < vs->nwnames; i++) {
1477 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1481 static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1485 free_fid(s, vs->newfidp->fid);
1486 v9fs_string_free(&vs->path);
1491 stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1494 if (vs->name_idx < vs->nwnames) {
1495 v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1496 vs->wnames[vs->name_idx].data);
1497 v9fs_string_copy(&vs->newfidp->path, &vs->path);
1499 err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1500 v9fs_walk_post_newfid_lstat(s, vs, err);
1504 v9fs_string_free(&vs->path);
1505 v9fs_walk_marshal(vs);
1508 v9fs_walk_complete(s, vs, err);
1511 static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1515 v9fs_string_free(&vs->path);
1520 stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1522 if (vs->name_idx < vs->nwnames) {
1524 v9fs_string_sprintf(&vs->path, "%s/%s",
1525 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1526 v9fs_string_copy(&vs->fidp->path, &vs->path);
1528 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1529 v9fs_walk_post_oldfid_lstat(s, vs, err);
1533 v9fs_string_free(&vs->path);
1534 v9fs_walk_marshal(vs);
1537 v9fs_walk_complete(s, vs, err);
1540 static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
1542 int32_t fid, newfid;
1547 vs = qemu_malloc(sizeof(*vs));
1553 vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1554 &newfid, &vs->nwnames);
1557 vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1559 vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1561 for (i = 0; i < vs->nwnames; i++) {
1562 vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1567 vs->fidp = lookup_fid(s, fid);
1568 if (vs->fidp == NULL) {
1573 /* FIXME: is this really valid? */
1574 if (fid == newfid) {
1576 BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1577 v9fs_string_init(&vs->path);
1580 if (vs->name_idx < vs->nwnames) {
1581 v9fs_string_sprintf(&vs->path, "%s/%s",
1582 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1583 v9fs_string_copy(&vs->fidp->path, &vs->path);
1585 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1586 v9fs_walk_post_oldfid_lstat(s, vs, err);
1590 vs->newfidp = alloc_fid(s, newfid);
1591 if (vs->newfidp == NULL) {
1596 vs->newfidp->uid = vs->fidp->uid;
1597 v9fs_string_init(&vs->path);
1599 v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1601 if (vs->name_idx < vs->nwnames) {
1602 v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1603 vs->wnames[vs->name_idx].data);
1604 v9fs_string_copy(&vs->newfidp->path, &vs->path);
1606 err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1607 v9fs_walk_post_newfid_lstat(s, vs, err);
1612 v9fs_walk_marshal(vs);
1615 v9fs_walk_complete(s, vs, err);
1618 static int32_t get_iounit(V9fsState *s, V9fsString *name)
1620 struct statfs stbuf;
1624 * iounit should be multiples of f_bsize (host filesystem block size
1625 * and as well as less than (client msize - P9_IOHDRSZ))
1627 if (!v9fs_do_statfs(s, name, &stbuf)) {
1628 iounit = stbuf.f_bsize;
1629 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1633 iounit = s->msize - P9_IOHDRSZ;
1638 static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1640 if (vs->fidp->fs.dir == NULL) {
1644 vs->fidp->fid_type = P9_FID_DIR;
1645 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1648 complete_pdu(s, vs->pdu, err);
1653 static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
1656 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
1658 complete_pdu(s, vs->pdu, err);
1662 static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1664 if (vs->fidp->fs.fd == -1) {
1668 vs->fidp->fid_type = P9_FID_FILE;
1669 vs->iounit = get_iounit(s, &vs->fidp->path);
1670 v9fs_open_post_getiounit(s, vs);
1673 complete_pdu(s, vs->pdu, err);
1677 static inline int valid_flags(int flag)
1679 if (flag & O_NOCTTY || flag & O_NONBLOCK || flag & O_ASYNC ||
1686 static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1695 stat_to_qid(&vs->stbuf, &vs->qid);
1697 if (S_ISDIR(vs->stbuf.st_mode)) {
1698 vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
1699 v9fs_open_post_opendir(s, vs, err);
1701 if (s->proto_version == V9FS_PROTO_2000L) {
1702 if (!valid_flags(vs->mode)) {
1708 flags = omode_to_uflags(vs->mode);
1710 vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
1711 v9fs_open_post_open(s, vs, err);
1715 complete_pdu(s, vs->pdu, err);
1719 static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
1725 vs = qemu_malloc(sizeof(*vs));
1730 if (s->proto_version == V9FS_PROTO_2000L) {
1731 pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
1733 pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1736 vs->fidp = lookup_fid(s, fid);
1737 if (vs->fidp == NULL) {
1742 BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1744 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1746 v9fs_open_post_lstat(s, vs, err);
1749 complete_pdu(s, pdu, err);
1753 static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
1756 v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1757 stat_to_qid(&vs->stbuf, &vs->qid);
1758 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
1762 vs->fidp->fid_type = P9_FID_NONE;
1763 close(vs->fidp->fs.fd);
1767 complete_pdu(s, vs->pdu, err);
1768 v9fs_string_free(&vs->name);
1769 v9fs_string_free(&vs->fullname);
1773 static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
1780 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1783 v9fs_post_lcreate(s, vs, err);
1786 static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
1789 if (vs->fidp->fs.fd == -1) {
1793 vs->fidp->fid_type = P9_FID_FILE;
1794 vs->iounit = get_iounit(s, &vs->fullname);
1795 v9fs_lcreate_post_get_iounit(s, vs, err);
1799 v9fs_post_lcreate(s, vs, err);
1802 static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
1804 int32_t dfid, flags, mode;
1806 V9fsLcreateState *vs;
1809 vs = qemu_malloc(sizeof(*vs));
1813 v9fs_string_init(&vs->fullname);
1815 pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
1818 vs->fidp = lookup_fid(s, dfid);
1819 if (vs->fidp == NULL) {
1824 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1827 vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
1829 v9fs_lcreate_post_do_open2(s, vs, err);
1833 complete_pdu(s, vs->pdu, err);
1834 v9fs_string_free(&vs->name);
1838 static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
1844 pdu_unmarshal(pdu, offset, "d", &fid);
1846 err = free_fid(s, fid);
1854 complete_pdu(s, pdu, err);
1857 static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1859 static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1864 v9fs_stat_free(&vs->v9stat);
1865 v9fs_string_free(&vs->name);
1866 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1867 vs->offset += vs->count;
1870 complete_pdu(s, vs->pdu, err);
1875 static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1882 err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1887 vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1889 if ((vs->len != (vs->v9stat.size + 2)) ||
1890 ((vs->count + vs->len) > vs->max_count)) {
1891 v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1892 v9fs_read_post_seekdir(s, vs, err);
1895 vs->count += vs->len;
1896 v9fs_stat_free(&vs->v9stat);
1897 v9fs_string_free(&vs->name);
1898 vs->dir_pos = vs->dent->d_off;
1899 vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
1900 v9fs_read_post_readdir(s, vs, err);
1903 v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1904 v9fs_read_post_seekdir(s, vs, err);
1909 static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1912 memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1913 v9fs_string_init(&vs->name);
1914 v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1916 err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1917 v9fs_read_post_dir_lstat(s, vs, err);
1921 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1922 vs->offset += vs->count;
1924 complete_pdu(s, vs->pdu, err);
1929 static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1931 vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
1932 v9fs_read_post_readdir(s, vs, err);
1936 static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1939 vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
1940 v9fs_read_post_telldir(s, vs, err);
1944 static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1947 /* IO error return the error */
1951 vs->total += vs->len;
1952 vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1953 if (vs->total < vs->count && vs->len > 0) {
1956 print_sg(vs->sg, vs->cnt);
1958 vs->len = v9fs_do_readv(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
1959 } while (vs->len == -1 && errno == EINTR);
1960 if (vs->len == -1) {
1963 v9fs_read_post_readv(s, vs, err);
1966 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1967 vs->offset += vs->count;
1971 complete_pdu(s, vs->pdu, err);
1975 static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
1981 vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1983 if (vs->total < vs->count) {
1986 print_sg(vs->sg, vs->cnt);
1988 vs->len = v9fs_do_readv(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
1989 } while (vs->len == -1 && errno == EINTR);
1990 if (vs->len == -1) {
1993 v9fs_read_post_readv(s, vs, err);
1997 complete_pdu(s, vs->pdu, err);
2001 static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
2007 xattr_len = vs->fidp->fs.xattr.len;
2008 read_count = xattr_len - vs->off;
2009 if (read_count > vs->count) {
2010 read_count = vs->count;
2011 } else if (read_count < 0) {
2013 * read beyond XATTR value
2017 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
2018 vs->offset += pdu_pack(vs->pdu, vs->offset,
2019 ((char *)vs->fidp->fs.xattr.value) + vs->off,
2022 complete_pdu(s, vs->pdu, err);
2026 static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
2032 vs = qemu_malloc(sizeof(*vs));
2039 pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
2041 vs->fidp = lookup_fid(s, fid);
2042 if (vs->fidp == NULL) {
2047 if (vs->fidp->fid_type == P9_FID_DIR) {
2048 vs->max_count = vs->count;
2051 v9fs_do_rewinddir(s, vs->fidp->fs.dir);
2053 v9fs_read_post_rewinddir(s, vs, err);
2055 } else if (vs->fidp->fid_type == P9_FID_FILE) {
2057 pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
2058 err = v9fs_do_lseek(s, vs->fidp->fs.fd, vs->off, SEEK_SET);
2059 v9fs_read_post_lseek(s, vs, err);
2061 } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2062 v9fs_xattr_read(s, vs);
2068 complete_pdu(s, pdu, err);
2072 typedef struct V9fsReadDirState {
2076 off_t saved_dir_pos;
2077 struct dirent *dent;
2081 int64_t initial_offset;
2085 static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
2087 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
2088 vs->offset += vs->count;
2089 complete_pdu(s, vs->pdu, vs->offset);
2094 /* Size of each dirent on the wire: size of qid (13) + size of offset (8)
2095 * size of type (1) + size of name.size (2) + strlen(name.data)
2097 #define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
2099 static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
2105 v9fs_string_init(&vs->name);
2106 v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
2108 if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
2109 /* Ran out of buffer. Set dir back to old position and return */
2110 v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
2111 v9fs_readdir_post_seekdir(s, vs);
2115 /* Fill up just the path field of qid because the client uses
2116 * only that. To fill the entire qid structure we will have
2117 * to stat each dirent found, which is expensive
2119 size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
2120 memcpy(&vs->qid.path, &vs->dent->d_ino, size);
2121 /* Fill the other fields with dummy values */
2123 vs->qid.version = 0;
2125 len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
2126 &vs->qid, vs->dent->d_off,
2127 vs->dent->d_type, &vs->name);
2129 v9fs_string_free(&vs->name);
2130 vs->saved_dir_pos = vs->dent->d_off;
2131 vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
2132 v9fs_readdir_post_readdir(s, vs);
2136 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
2137 vs->offset += vs->count;
2138 complete_pdu(s, vs->pdu, vs->offset);
2143 static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
2145 vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
2146 v9fs_readdir_post_readdir(s, vs);
2150 static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
2152 vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
2153 v9fs_readdir_post_telldir(s, vs);
2157 static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
2160 V9fsReadDirState *vs;
2164 vs = qemu_malloc(sizeof(*vs));
2169 pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
2172 vs->fidp = lookup_fid(s, fid);
2173 if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
2178 if (vs->initial_offset == 0) {
2179 v9fs_do_rewinddir(s, vs->fidp->fs.dir);
2181 v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
2184 v9fs_readdir_post_setdir(s, vs);
2188 complete_pdu(s, pdu, err);
2193 static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
2197 /* IO error return the error */
2201 vs->total += vs->len;
2202 vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2203 if (vs->total < vs->count && vs->len > 0) {
2206 print_sg(vs->sg, vs->cnt);
2208 vs->len = v9fs_do_writev(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
2209 } while (vs->len == -1 && errno == EINTR);
2210 if (vs->len == -1) {
2213 v9fs_write_post_writev(s, vs, err);
2216 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2220 complete_pdu(s, vs->pdu, err);
2224 static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
2230 vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2232 if (vs->total < vs->count) {
2235 print_sg(vs->sg, vs->cnt);
2237 vs->len = v9fs_do_writev(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
2238 } while (vs->len == -1 && errno == EINTR);
2239 if (vs->len == -1) {
2242 v9fs_write_post_writev(s, vs, err);
2247 complete_pdu(s, vs->pdu, err);
2251 static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
2258 xattr_len = vs->fidp->fs.xattr.len;
2259 write_count = xattr_len - vs->off;
2260 if (write_count > vs->count) {
2261 write_count = vs->count;
2262 } else if (write_count < 0) {
2264 * write beyond XATTR value len specified in
2270 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
2272 vs->fidp->fs.xattr.copied_len += write_count;
2274 * Now copy the content from sg list
2276 for (i = 0; i < vs->cnt; i++) {
2277 if (write_count > vs->sg[i].iov_len) {
2278 to_copy = vs->sg[i].iov_len;
2280 to_copy = write_count;
2282 memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
2283 vs->sg[i].iov_base, to_copy);
2284 /* updating vs->off since we are not using below */
2286 write_count -= to_copy;
2289 complete_pdu(s, vs->pdu, err);
2293 static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
2299 vs = qemu_malloc(sizeof(*vs));
2307 pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
2310 vs->fidp = lookup_fid(s, fid);
2311 if (vs->fidp == NULL) {
2316 if (vs->fidp->fid_type == P9_FID_FILE) {
2317 if (vs->fidp->fs.fd == -1) {
2321 } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2323 * setxattr operation
2325 v9fs_xattr_write(s, vs);
2331 err = v9fs_do_lseek(s, vs->fidp->fs.fd, vs->off, SEEK_SET);
2333 v9fs_write_post_lseek(s, vs, err);
2337 complete_pdu(s, vs->pdu, err);
2341 static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
2344 v9fs_string_copy(&vs->fidp->path, &vs->fullname);
2345 stat_to_qid(&vs->stbuf, &vs->qid);
2347 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
2350 complete_pdu(s, vs->pdu, err);
2351 v9fs_string_free(&vs->name);
2352 v9fs_string_free(&vs->extension);
2353 v9fs_string_free(&vs->fullname);
2357 static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
2360 vs->iounit = get_iounit(s, &vs->fidp->path);
2361 v9fs_create_post_getiounit(s, vs);
2365 complete_pdu(s, vs->pdu, err);
2366 v9fs_string_free(&vs->name);
2367 v9fs_string_free(&vs->extension);
2368 v9fs_string_free(&vs->fullname);
2372 static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
2377 v9fs_post_create(s, vs, err);
2380 static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
2383 if (!vs->fidp->fs.dir) {
2386 vs->fidp->fid_type = P9_FID_DIR;
2387 v9fs_post_create(s, vs, err);
2390 static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
2398 vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
2399 v9fs_create_post_opendir(s, vs, err);
2403 v9fs_post_create(s, vs, err);
2406 static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
2413 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2414 v9fs_create_post_dir_lstat(s, vs, err);
2418 v9fs_post_create(s, vs, err);
2421 static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
2424 vs->fidp->fid_type = P9_FID_NONE;
2425 close(vs->fidp->fs.fd);
2428 v9fs_post_create(s, vs, err);
2432 static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
2434 if (vs->fidp->fs.fd == -1) {
2438 vs->fidp->fid_type = P9_FID_FILE;
2439 err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
2440 v9fs_create_post_fstat(s, vs, err);
2445 v9fs_post_create(s, vs, err);
2449 static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
2452 if (err == 0 || errno != ENOENT) {
2457 if (vs->perm & P9_STAT_MODE_DIR) {
2458 err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
2460 v9fs_create_post_mkdir(s, vs, err);
2461 } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
2462 err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
2463 vs->fullname.data, -1);
2464 v9fs_create_post_perms(s, vs, err);
2465 } else if (vs->perm & P9_STAT_MODE_LINK) {
2466 int32_t nfid = atoi(vs->extension.data);
2467 V9fsFidState *nfidp = lookup_fid(s, nfid);
2468 if (nfidp == NULL) {
2470 v9fs_post_create(s, vs, err);
2472 err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
2473 v9fs_create_post_perms(s, vs, err);
2474 } else if (vs->perm & P9_STAT_MODE_DEVICE) {
2476 uint32_t major, minor;
2479 if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
2482 v9fs_post_create(s, vs, err);
2494 v9fs_post_create(s, vs, err);
2497 nmode |= vs->perm & 0777;
2498 err = v9fs_do_mknod(s, vs->fullname.data, nmode,
2499 makedev(major, minor), vs->fidp->uid, -1);
2500 v9fs_create_post_perms(s, vs, err);
2501 } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
2502 err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
2503 0, vs->fidp->uid, -1);
2504 v9fs_post_create(s, vs, err);
2505 } else if (vs->perm & P9_STAT_MODE_SOCKET) {
2506 err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
2507 0, vs->fidp->uid, -1);
2508 v9fs_post_create(s, vs, err);
2510 vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
2511 -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
2513 v9fs_create_post_open2(s, vs, err);
2519 v9fs_post_create(s, vs, err);
2522 static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
2525 V9fsCreateState *vs;
2528 vs = qemu_malloc(sizeof(*vs));
2532 v9fs_string_init(&vs->fullname);
2534 pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
2535 &vs->perm, &vs->mode, &vs->extension);
2537 vs->fidp = lookup_fid(s, fid);
2538 if (vs->fidp == NULL) {
2543 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
2546 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2547 v9fs_create_post_lstat(s, vs, err);
2551 complete_pdu(s, vs->pdu, err);
2552 v9fs_string_free(&vs->name);
2553 v9fs_string_free(&vs->extension);
2557 static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
2560 stat_to_qid(&vs->stbuf, &vs->qid);
2561 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
2566 complete_pdu(s, vs->pdu, err);
2567 v9fs_string_free(&vs->name);
2568 v9fs_string_free(&vs->symname);
2569 v9fs_string_free(&vs->fullname);
2573 static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
2579 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2581 v9fs_post_symlink(s, vs, err);
2584 static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
2587 V9fsSymlinkState *vs;
2591 vs = qemu_malloc(sizeof(*vs));
2595 v9fs_string_init(&vs->fullname);
2597 pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
2598 &vs->symname, &gid);
2600 vs->dfidp = lookup_fid(s, dfid);
2601 if (vs->dfidp == NULL) {
2606 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
2608 err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
2609 vs->fullname.data, gid);
2610 v9fs_symlink_post_do_symlink(s, vs, err);
2614 complete_pdu(s, vs->pdu, err);
2615 v9fs_string_free(&vs->name);
2616 v9fs_string_free(&vs->symname);
2620 static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
2622 /* A nop call with no return */
2623 complete_pdu(s, pdu, 7);
2626 static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
2628 int32_t dfid, oldfid;
2629 V9fsFidState *dfidp, *oldfidp;
2630 V9fsString name, fullname;
2634 v9fs_string_init(&fullname);
2636 pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2638 dfidp = lookup_fid(s, dfid);
2639 if (dfidp == NULL) {
2644 oldfidp = lookup_fid(s, oldfid);
2645 if (oldfidp == NULL) {
2650 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2652 err = v9fs_do_link(s, &oldfidp->path, &fullname);
2656 v9fs_string_free(&fullname);
2659 v9fs_string_free(&name);
2660 complete_pdu(s, pdu, err);
2663 static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
2672 /* For TREMOVE we need to clunk the fid even on failed remove */
2673 free_fid(s, vs->fidp->fid);
2675 complete_pdu(s, vs->pdu, err);
2679 static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
2682 V9fsRemoveState *vs;
2685 vs = qemu_malloc(sizeof(*vs));
2689 pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
2691 vs->fidp = lookup_fid(s, fid);
2692 if (vs->fidp == NULL) {
2697 err = v9fs_do_remove(s, &vs->fidp->path);
2698 v9fs_remove_post_remove(s, vs, err);
2702 complete_pdu(s, pdu, err);
2706 static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
2715 v9fs_stat_free(&vs->v9stat);
2716 complete_pdu(s, vs->pdu, err);
2720 static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
2725 if (vs->v9stat.length != -1) {
2726 if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
2730 v9fs_wstat_post_truncate(s, vs, err);
2734 v9fs_stat_free(&vs->v9stat);
2735 complete_pdu(s, vs->pdu, err);
2739 static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
2742 char *old_name, *new_name;
2745 if (vs->newdirfid != -1) {
2746 V9fsFidState *dirfidp;
2747 dirfidp = lookup_fid(s, vs->newdirfid);
2749 if (dirfidp == NULL) {
2754 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2756 new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
2758 strcpy(new_name, dirfidp->path.data);
2759 strcat(new_name, "/");
2760 strcat(new_name + dirfidp->path.size, vs->name.data);
2762 old_name = vs->fidp->path.data;
2763 end = strrchr(old_name, '/');
2769 new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
2771 strncat(new_name, old_name, end - old_name);
2772 strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
2775 v9fs_string_free(&vs->name);
2776 vs->name.data = qemu_strdup(new_name);
2777 vs->name.size = strlen(new_name);
2779 if (strcmp(new_name, vs->fidp->path.data) != 0) {
2780 if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
2785 * Fixup fid's pointing to the old name to
2786 * start pointing to the new name
2788 for (fidp = s->fid_list; fidp; fidp = fidp->next) {
2789 if (vs->fidp == fidp) {
2791 * we replace name of this fid towards the end
2792 * so that our below strcmp will work
2796 if (!strncmp(vs->fidp->path.data, fidp->path.data,
2797 strlen(vs->fidp->path.data))) {
2798 /* replace the name */
2799 v9fs_fix_path(&fidp->path, &vs->name,
2800 strlen(vs->fidp->path.data));
2803 v9fs_string_copy(&vs->fidp->path, &vs->name);
2807 v9fs_string_free(&vs->name);
2811 static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
2813 complete_pdu(s, vs->pdu, err);
2817 static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
2823 if (vs->v9stat.name.size != 0) {
2824 V9fsRenameState *vr;
2826 vr = qemu_malloc(sizeof(V9fsRenameState));
2827 memset(vr, sizeof(*vr), 0);
2830 vr->fidp = vs->fidp;
2831 vr->offset = vs->offset;
2832 vr->name.size = vs->v9stat.name.size;
2833 vr->name.data = qemu_strdup(vs->v9stat.name.data);
2835 err = v9fs_complete_rename(s, vr);
2838 v9fs_wstat_post_rename(s, vs, err);
2842 v9fs_stat_free(&vs->v9stat);
2843 complete_pdu(s, vs->pdu, err);
2847 static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
2850 V9fsRenameState *vs;
2853 vs = qemu_malloc(sizeof(*vs));
2857 pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
2859 vs->fidp = lookup_fid(s, fid);
2860 if (vs->fidp == NULL) {
2865 BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
2867 err = v9fs_complete_rename(s, vs);
2868 v9fs_rename_post_rename(s, vs, err);
2871 complete_pdu(s, vs->pdu, err);
2875 static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2881 if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
2882 if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2883 vs->v9stat.n_gid)) {
2887 v9fs_wstat_post_chown(s, vs, err);
2891 v9fs_stat_free(&vs->v9stat);
2892 complete_pdu(s, vs->pdu, err);
2896 static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2902 if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
2903 struct timespec times[2];
2904 if (vs->v9stat.atime != -1) {
2905 times[0].tv_sec = vs->v9stat.atime;
2906 times[0].tv_nsec = 0;
2908 times[0].tv_nsec = UTIME_OMIT;
2910 if (vs->v9stat.mtime != -1) {
2911 times[1].tv_sec = vs->v9stat.mtime;
2912 times[1].tv_nsec = 0;
2914 times[1].tv_nsec = UTIME_OMIT;
2917 if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
2922 v9fs_wstat_post_utime(s, vs, err);
2926 v9fs_stat_free(&vs->v9stat);
2927 complete_pdu(s, vs->pdu, err);
2931 static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2936 v9fs_stat_free(&vs->v9stat);
2937 complete_pdu(s, vs->pdu, err);
2941 static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2950 v9_mode = stat_to_v9mode(&vs->stbuf);
2952 if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2953 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2954 /* Attempting to change the type */
2959 if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2960 &vs->v9stat.extension))) {
2963 v9fs_wstat_post_chmod(s, vs, err);
2967 v9fs_stat_free(&vs->v9stat);
2968 complete_pdu(s, vs->pdu, err);
2972 static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
2978 vs = qemu_malloc(sizeof(*vs));
2982 pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
2984 vs->fidp = lookup_fid(s, fid);
2985 if (vs->fidp == NULL) {
2990 /* do we need to sync the file? */
2991 if (donttouch_stat(&vs->v9stat)) {
2992 err = v9fs_do_fsync(s, vs->fidp->fs.fd);
2993 v9fs_wstat_post_fsync(s, vs, err);
2997 if (vs->v9stat.mode != -1) {
2998 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2999 v9fs_wstat_post_lstat(s, vs, err);
3003 v9fs_wstat_post_chmod(s, vs, err);
3007 v9fs_stat_free(&vs->v9stat);
3008 complete_pdu(s, vs->pdu, err);
3012 static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
3014 int32_t bsize_factor;
3022 * compute bsize factor based on host file system block size
3025 bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
3026 if (!bsize_factor) {
3029 vs->v9statfs.f_type = vs->stbuf.f_type;
3030 vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
3031 vs->v9statfs.f_bsize *= bsize_factor;
3033 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
3034 * adjust(divide) the number of blocks, free blocks and available
3035 * blocks by bsize factor
3037 vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
3038 vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
3039 vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
3040 vs->v9statfs.f_files = vs->stbuf.f_files;
3041 vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
3042 vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
3043 (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
3044 vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
3046 vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
3047 vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
3048 vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
3049 vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
3050 vs->v9statfs.f_namelen);
3053 complete_pdu(s, vs->pdu, vs->offset);
3057 static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
3059 V9fsStatfsState *vs;
3062 vs = qemu_malloc(sizeof(*vs));
3066 memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
3068 pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
3070 vs->fidp = lookup_fid(s, vs->fid);
3071 if (vs->fidp == NULL) {
3076 err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
3077 v9fs_statfs_post_statfs(s, vs, err);
3081 complete_pdu(s, vs->pdu, err);
3085 static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
3092 stat_to_qid(&vs->stbuf, &vs->qid);
3093 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
3096 complete_pdu(s, vs->pdu, err);
3097 v9fs_string_free(&vs->fullname);
3098 v9fs_string_free(&vs->name);
3102 static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
3109 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
3110 v9fs_mknod_post_lstat(s, vs, err);
3113 complete_pdu(s, vs->pdu, err);
3114 v9fs_string_free(&vs->fullname);
3115 v9fs_string_free(&vs->name);
3119 static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
3129 vs = qemu_malloc(sizeof(*vs));
3133 v9fs_string_init(&vs->fullname);
3134 pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
3135 &major, &minor, &gid);
3137 fidp = lookup_fid(s, fid);
3143 v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
3144 err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
3146 v9fs_mknod_post_mknod(s, vs, err);
3150 complete_pdu(s, vs->pdu, err);
3151 v9fs_string_free(&vs->fullname);
3152 v9fs_string_free(&vs->name);
3156 static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
3163 stat_to_qid(&vs->stbuf, &vs->qid);
3164 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
3167 complete_pdu(s, vs->pdu, err);
3168 v9fs_string_free(&vs->fullname);
3169 v9fs_string_free(&vs->name);
3173 static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
3180 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
3181 v9fs_mkdir_post_lstat(s, vs, err);
3184 complete_pdu(s, vs->pdu, err);
3185 v9fs_string_free(&vs->fullname);
3186 v9fs_string_free(&vs->name);
3190 static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
3199 vs = qemu_malloc(sizeof(*vs));
3203 v9fs_string_init(&vs->fullname);
3204 pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
3207 fidp = lookup_fid(s, fid);
3213 v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
3214 err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
3215 v9fs_mkdir_post_mkdir(s, vs, err);
3219 complete_pdu(s, vs->pdu, err);
3220 v9fs_string_free(&vs->fullname);
3221 v9fs_string_free(&vs->name);
3225 static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
3230 free_fid(s, vs->xattr_fidp->fid);
3233 vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
3236 complete_pdu(s, vs->pdu, err);
3237 v9fs_string_free(&vs->name);
3242 static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
3246 free_fid(s, vs->xattr_fidp->fid);
3250 * Read the xattr value
3252 vs->xattr_fidp->fs.xattr.len = vs->size;
3253 vs->xattr_fidp->fid_type = P9_FID_XATTR;
3254 vs->xattr_fidp->fs.xattr.copied_len = -1;
3256 vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
3257 err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
3258 &vs->name, vs->xattr_fidp->fs.xattr.value,
3259 vs->xattr_fidp->fs.xattr.len);
3261 v9fs_post_xattr_getvalue(s, vs, err);
3264 complete_pdu(s, vs->pdu, err);
3265 v9fs_string_free(&vs->name);
3269 static void v9fs_post_lxattr_getvalue(V9fsState *s,
3270 V9fsXattrState *vs, int err)
3274 free_fid(s, vs->xattr_fidp->fid);
3277 vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
3280 complete_pdu(s, vs->pdu, err);
3281 v9fs_string_free(&vs->name);
3286 static void v9fs_post_lxattr_check(V9fsState *s,
3287 V9fsXattrState *vs, ssize_t err)
3291 free_fid(s, vs->xattr_fidp->fid);
3295 * Read the xattr value
3297 vs->xattr_fidp->fs.xattr.len = vs->size;
3298 vs->xattr_fidp->fid_type = P9_FID_XATTR;
3299 vs->xattr_fidp->fs.xattr.copied_len = -1;
3301 vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
3302 err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
3303 vs->xattr_fidp->fs.xattr.value,
3304 vs->xattr_fidp->fs.xattr.len);
3306 v9fs_post_lxattr_getvalue(s, vs, err);
3309 complete_pdu(s, vs->pdu, err);
3310 v9fs_string_free(&vs->name);
3314 static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
3318 int32_t fid, newfid;
3320 vs = qemu_malloc(sizeof(*vs));
3324 pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
3325 vs->file_fidp = lookup_fid(s, fid);
3326 if (vs->file_fidp == NULL) {
3331 vs->xattr_fidp = alloc_fid(s, newfid);
3332 if (vs->xattr_fidp == NULL) {
3337 v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
3338 if (vs->name.data[0] == 0) {
3340 * listxattr request. Get the size first
3342 vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
3347 v9fs_post_lxattr_check(s, vs, err);
3351 * specific xattr fid. We check for xattr
3352 * presence also collect the xattr size
3354 vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
3355 &vs->name, NULL, 0);
3359 v9fs_post_xattr_check(s, vs, err);
3363 complete_pdu(s, vs->pdu, err);
3364 v9fs_string_free(&vs->name);
3368 static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
3375 vs = qemu_malloc(sizeof(*vs));
3379 pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
3380 &fid, &vs->name, &vs->size, &flags);
3382 vs->file_fidp = lookup_fid(s, fid);
3383 if (vs->file_fidp == NULL) {
3388 /* Make the file fid point to xattr */
3389 vs->xattr_fidp = vs->file_fidp;
3390 vs->xattr_fidp->fid_type = P9_FID_XATTR;
3391 vs->xattr_fidp->fs.xattr.copied_len = 0;
3392 vs->xattr_fidp->fs.xattr.len = vs->size;
3393 vs->xattr_fidp->fs.xattr.flags = flags;
3394 v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
3395 v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
3396 vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
3399 complete_pdu(s, vs->pdu, err);
3400 v9fs_string_free(&vs->name);
3404 typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
3406 static pdu_handler_t *pdu_handlers[] = {
3407 [P9_TREADDIR] = v9fs_readdir,
3408 [P9_TSTATFS] = v9fs_statfs,
3409 [P9_TGETATTR] = v9fs_getattr,
3410 [P9_TSETATTR] = v9fs_setattr,
3411 [P9_TXATTRWALK] = v9fs_xattrwalk,
3412 [P9_TXATTRCREATE] = v9fs_xattrcreate,
3413 [P9_TMKNOD] = v9fs_mknod,
3414 [P9_TRENAME] = v9fs_rename,
3415 [P9_TMKDIR] = v9fs_mkdir,
3416 [P9_TVERSION] = v9fs_version,
3417 [P9_TLOPEN] = v9fs_open,
3418 [P9_TATTACH] = v9fs_attach,
3419 [P9_TSTAT] = v9fs_stat,
3420 [P9_TWALK] = v9fs_walk,
3421 [P9_TCLUNK] = v9fs_clunk,
3422 [P9_TOPEN] = v9fs_open,
3423 [P9_TREAD] = v9fs_read,
3425 [P9_TAUTH] = v9fs_auth,
3427 [P9_TFLUSH] = v9fs_flush,
3428 [P9_TLINK] = v9fs_link,
3429 [P9_TSYMLINK] = v9fs_symlink,
3430 [P9_TCREATE] = v9fs_create,
3431 [P9_TLCREATE] = v9fs_lcreate,
3432 [P9_TWRITE] = v9fs_write,
3433 [P9_TWSTAT] = v9fs_wstat,
3434 [P9_TREMOVE] = v9fs_remove,
3437 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3439 pdu_handler_t *handler;
3445 BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
3447 handler = pdu_handlers[pdu->id];
3448 BUG_ON(handler == NULL);
3453 static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3455 V9fsState *s = (V9fsState *)vdev;
3459 while ((pdu = alloc_pdu(s)) &&
3460 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3463 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3464 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3466 ptr = pdu->elem.out_sg[0].iov_base;
3468 memcpy(&pdu->size, ptr, 4);
3470 memcpy(&pdu->tag, ptr + 5, 2);
3478 static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
3480 features |= 1 << VIRTIO_9P_MOUNT_TAG;
3484 static V9fsState *to_virtio_9p(VirtIODevice *vdev)
3486 return (V9fsState *)vdev;
3489 static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
3491 struct virtio_9p_config *cfg;
3492 V9fsState *s = to_virtio_9p(vdev);
3494 cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
3496 stw_raw(&cfg->tag_len, s->tag_len);
3497 memcpy(cfg->tag, s->tag, s->tag_len);
3498 memcpy(config, cfg, s->config_size);
3502 VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
3510 s = (V9fsState *)virtio_common_init("virtio-9p",
3512 sizeof(struct virtio_9p_config)+
3516 /* initialize pdu allocator */
3517 QLIST_INIT(&s->free_list);
3518 for (i = 0; i < (MAX_REQ - 1); i++) {
3519 QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
3522 s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
3524 fse = get_fsdev_fsentry(conf->fsdev_id);
3527 /* We don't have a fsdev identified by fsdev_id */
3528 fprintf(stderr, "Virtio-9p device couldn't find fsdev "
3529 "with the id %s\n", conf->fsdev_id);
3533 if (!fse->path || !conf->tag) {
3534 /* we haven't specified a mount_tag or the path */
3535 fprintf(stderr, "fsdev with id %s needs path "
3536 "and Virtio-9p device needs mount_tag arguments\n",
3541 if (!strcmp(fse->security_model, "passthrough")) {
3542 /* Files on the Fileserver set to client user credentials */
3543 s->ctx.fs_sm = SM_PASSTHROUGH;
3544 } else if (!strcmp(fse->security_model, "mapped")) {
3545 /* Files on the fileserver are set to QEMU credentials.
3546 * Client user credentials are saved in extended attributes.
3548 s->ctx.fs_sm = SM_MAPPED;
3550 /* user haven't specified a correct security option */
3551 fprintf(stderr, "one of the following must be specified as the"
3552 "security option:\n\t security_model=passthrough \n\t "
3553 "security_model=mapped\n");
3557 if (lstat(fse->path, &stat)) {
3558 fprintf(stderr, "share path %s does not exist\n", fse->path);
3560 } else if (!S_ISDIR(stat.st_mode)) {
3561 fprintf(stderr, "share path %s is not a directory \n", fse->path);
3565 s->ctx.fs_root = qemu_strdup(fse->path);
3566 len = strlen(conf->tag);
3567 if (len > MAX_TAG_LEN) {
3570 /* s->tag is non-NULL terminated string */
3571 s->tag = qemu_malloc(len);
3572 memcpy(s->tag, conf->tag, len);
3577 s->vdev.get_features = virtio_9p_get_features;
3578 s->config_size = sizeof(struct virtio_9p_config) +
3580 s->vdev.get_config = virtio_9p_get_config;