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.
14 #include "hw/virtio.h"
16 #include "qemu_socket.h"
17 #include "hw/virtio-pci.h"
18 #include "virtio-9p.h"
19 #include "fsdev/qemu-fsdev.h"
20 #include "virtio-9p-xattr.h"
21 #include "virtio-9p-coth.h"
23 static uint32_t virtio_9p_get_features(VirtIODevice
*vdev
, uint32_t features
)
25 features
|= 1 << VIRTIO_9P_MOUNT_TAG
;
29 static V9fsState
*to_virtio_9p(VirtIODevice
*vdev
)
31 return (V9fsState
*)vdev
;
34 static void virtio_9p_get_config(VirtIODevice
*vdev
, uint8_t *config
)
37 struct virtio_9p_config
*cfg
;
38 V9fsState
*s
= to_virtio_9p(vdev
);
41 cfg
= g_malloc0(sizeof(struct virtio_9p_config
) + len
);
42 stw_raw(&cfg
->tag_len
, len
);
43 /* We don't copy the terminating null to config space */
44 memcpy(cfg
->tag
, s
->tag
, len
);
45 memcpy(config
, cfg
, s
->config_size
);
49 VirtIODevice
*virtio_9p_init(DeviceState
*dev
, V9fsConf
*conf
)
57 s
= (V9fsState
*)virtio_common_init("virtio-9p",
59 sizeof(struct virtio_9p_config
)+
62 /* initialize pdu allocator */
63 QLIST_INIT(&s
->free_list
);
64 QLIST_INIT(&s
->active_list
);
65 for (i
= 0; i
< (MAX_REQ
- 1); i
++) {
66 QLIST_INSERT_HEAD(&s
->free_list
, &s
->pdus
[i
], next
);
69 s
->vq
= virtio_add_queue(&s
->vdev
, MAX_REQ
, handle_9p_output
);
71 fse
= get_fsdev_fsentry(conf
->fsdev_id
);
74 /* We don't have a fsdev identified by fsdev_id */
75 fprintf(stderr
, "Virtio-9p device couldn't find fsdev with the "
76 "id = %s\n", conf
->fsdev_id
? conf
->fsdev_id
: "NULL");
81 /* we haven't specified a mount_tag */
82 fprintf(stderr
, "fsdev with id %s needs mount_tag arguments\n",
87 s
->ctx
.export_flags
= fse
->export_flags
;
89 s
->ctx
.fs_root
= g_strdup(fse
->path
);
91 s
->ctx
.fs_root
= NULL
;
93 s
->ctx
.exops
.get_st_gen
= NULL
;
95 if (fse
->export_flags
& V9FS_SM_PASSTHROUGH
) {
96 s
->ctx
.xops
= passthrough_xattr_ops
;
97 } else if (fse
->export_flags
& V9FS_SM_MAPPED
) {
98 s
->ctx
.xops
= mapped_xattr_ops
;
99 } else if (fse
->export_flags
& V9FS_SM_NONE
) {
100 s
->ctx
.xops
= none_xattr_ops
;
103 len
= strlen(conf
->tag
);
104 if (len
> MAX_TAG_LEN
- 1) {
105 fprintf(stderr
, "mount tag '%s' (%d bytes) is longer than "
106 "maximum (%d bytes)", conf
->tag
, len
, MAX_TAG_LEN
- 1);
110 s
->tag
= strdup(conf
->tag
);
114 s
->vdev
.get_features
= virtio_9p_get_features
;
115 s
->config_size
= sizeof(struct virtio_9p_config
) + len
;
116 s
->vdev
.get_config
= virtio_9p_get_config
;
118 qemu_co_rwlock_init(&s
->rename_lock
);
120 if (s
->ops
->init(&s
->ctx
) < 0) {
121 fprintf(stderr
, "Virtio-9p Failed to initialize fs-driver with id:%s"
122 " and export path:%s\n", conf
->fsdev_id
, s
->ctx
.fs_root
);
125 if (v9fs_init_worker_threads() < 0) {
126 fprintf(stderr
, "worker thread initialization failed\n");
131 * Check details of export path, We need to use fs driver
132 * call back to do that. Since we are in the init path, we don't
133 * use co-routines here.
135 v9fs_path_init(&path
);
136 if (s
->ops
->name_to_path(&s
->ctx
, NULL
, "/", &path
) < 0) {
138 "error in converting name to path %s", strerror(errno
));
141 if (s
->ops
->lstat(&s
->ctx
, &path
, &stat
)) {
142 fprintf(stderr
, "share path %s does not exist\n", fse
->path
);
144 } else if (!S_ISDIR(stat
.st_mode
)) {
145 fprintf(stderr
, "share path %s is not a directory\n", fse
->path
);
148 v9fs_path_free(&path
);
153 static int virtio_9p_init_pci(PCIDevice
*pci_dev
)
155 VirtIOPCIProxy
*proxy
= DO_UPCAST(VirtIOPCIProxy
, pci_dev
, pci_dev
);
158 vdev
= virtio_9p_init(&pci_dev
->qdev
, &proxy
->fsconf
);
159 vdev
->nvectors
= proxy
->nvectors
;
160 virtio_init_pci(proxy
, vdev
);
161 /* make the actual value visible */
162 proxy
->nvectors
= vdev
->nvectors
;
166 static Property virtio_9p_properties
[] = {
167 DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy
, flags
, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT
, true),
168 DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy
, nvectors
, 2),
169 DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy
, host_features
),
170 DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy
, fsconf
.tag
),
171 DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy
, fsconf
.fsdev_id
),
172 DEFINE_PROP_END_OF_LIST(),
175 static void virtio_9p_class_init(ObjectClass
*klass
, void *data
)
177 DeviceClass
*dc
= DEVICE_CLASS(klass
);
178 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
180 k
->init
= virtio_9p_init_pci
;
181 k
->vendor_id
= PCI_VENDOR_ID_REDHAT_QUMRANET
;
182 k
->device_id
= 0x1009;
183 k
->revision
= VIRTIO_PCI_ABI_VERSION
;
185 dc
->props
= virtio_9p_properties
;
186 dc
->reset
= virtio_pci_reset
;
189 static TypeInfo virtio_9p_info
= {
190 .name
= "virtio-9p-pci",
191 .parent
= TYPE_PCI_DEVICE
,
192 .instance_size
= sizeof(VirtIOPCIProxy
),
193 .class_init
= virtio_9p_class_init
,
196 static void virtio_9p_register_devices(void)
198 type_register_static(&virtio_9p_info
);
199 virtio_9p_set_fd_limit();
202 device_init(virtio_9p_register_devices
)