]>
Commit | Line | Data |
---|---|---|
f4f61d27 AK |
1 | /* |
2 | * Virtio 9p backend | |
3 | * | |
4 | * Copyright IBM, Corp. 2010 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <aliguori@us.ibm.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
11 | * | |
12 | */ | |
13 | ||
873c3213 SW |
14 | #include "hw/virtio.h" |
15 | #include "hw/pc.h" | |
1de7afc9 | 16 | #include "qemu/sockets.h" |
873c3213 | 17 | #include "hw/virtio-pci.h" |
f4f61d27 AK |
18 | #include "virtio-9p.h" |
19 | #include "fsdev/qemu-fsdev.h" | |
20 | #include "virtio-9p-xattr.h" | |
39c0564e | 21 | #include "virtio-9p-coth.h" |
f4f61d27 AK |
22 | |
23 | static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features) | |
24 | { | |
25 | features |= 1 << VIRTIO_9P_MOUNT_TAG; | |
26 | return features; | |
27 | } | |
28 | ||
29 | static V9fsState *to_virtio_9p(VirtIODevice *vdev) | |
30 | { | |
31 | return (V9fsState *)vdev; | |
32 | } | |
33 | ||
34 | static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) | |
35 | { | |
e9a0152b | 36 | int len; |
f4f61d27 AK |
37 | struct virtio_9p_config *cfg; |
38 | V9fsState *s = to_virtio_9p(vdev); | |
39 | ||
e9a0152b AK |
40 | len = strlen(s->tag); |
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); | |
f4f61d27 | 45 | memcpy(config, cfg, s->config_size); |
7267c094 | 46 | g_free(cfg); |
f4f61d27 AK |
47 | } |
48 | ||
49 | VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) | |
0174fe73 | 50 | { |
f4f61d27 AK |
51 | V9fsState *s; |
52 | int i, len; | |
53 | struct stat stat; | |
fbcbf101 | 54 | FsDriverEntry *fse; |
7cca27df | 55 | V9fsPath path; |
f4f61d27 | 56 | |
f4f61d27 AK |
57 | s = (V9fsState *)virtio_common_init("virtio-9p", |
58 | VIRTIO_ID_9P, | |
59 | sizeof(struct virtio_9p_config)+ | |
60 | MAX_TAG_LEN, | |
61 | sizeof(V9fsState)); | |
f4f61d27 AK |
62 | /* initialize pdu allocator */ |
63 | QLIST_INIT(&s->free_list); | |
bccacf6c | 64 | QLIST_INIT(&s->active_list); |
f4f61d27 AK |
65 | for (i = 0; i < (MAX_REQ - 1); i++) { |
66 | QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next); | |
67 | } | |
68 | ||
69 | s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output); | |
70 | ||
71 | fse = get_fsdev_fsentry(conf->fsdev_id); | |
72 | ||
73 | if (!fse) { | |
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"); | |
77 | exit(1); | |
78 | } | |
79 | ||
99519f0a AK |
80 | if (!conf->tag) { |
81 | /* we haven't specified a mount_tag */ | |
82 | fprintf(stderr, "fsdev with id %s needs mount_tag arguments\n", | |
f4f61d27 AK |
83 | conf->fsdev_id); |
84 | exit(1); | |
85 | } | |
86 | ||
b97400ca | 87 | s->ctx.export_flags = fse->export_flags; |
c64f50d1 | 88 | s->ctx.fs_root = g_strdup(fse->path); |
b97400ca | 89 | s->ctx.exops.get_st_gen = NULL; |
f4f61d27 | 90 | len = strlen(conf->tag); |
e9a0152b | 91 | if (len > MAX_TAG_LEN - 1) { |
a2f507d9 | 92 | fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " |
e9a0152b | 93 | "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN - 1); |
a2f507d9 | 94 | exit(1); |
f4f61d27 | 95 | } |
e9a0152b | 96 | |
d3f8e138 | 97 | s->tag = g_strdup(conf->tag); |
f4f61d27 AK |
98 | s->ctx.uid = -1; |
99 | ||
100 | s->ops = fse->ops; | |
101 | s->vdev.get_features = virtio_9p_get_features; | |
e9a0152b | 102 | s->config_size = sizeof(struct virtio_9p_config) + len; |
f4f61d27 | 103 | s->vdev.get_config = virtio_9p_get_config; |
9e5b2247 | 104 | s->fid_list = NULL; |
02cb7f3a | 105 | qemu_co_rwlock_init(&s->rename_lock); |
f4f61d27 | 106 | |
0174fe73 AK |
107 | if (s->ops->init(&s->ctx) < 0) { |
108 | fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s" | |
109 | " and export path:%s\n", conf->fsdev_id, s->ctx.fs_root); | |
110 | exit(1); | |
111 | } | |
39c0564e VJ |
112 | if (v9fs_init_worker_threads() < 0) { |
113 | fprintf(stderr, "worker thread initialization failed\n"); | |
114 | exit(1); | |
115 | } | |
7cca27df MK |
116 | |
117 | /* | |
118 | * Check details of export path, We need to use fs driver | |
119 | * call back to do that. Since we are in the init path, we don't | |
120 | * use co-routines here. | |
121 | */ | |
122 | v9fs_path_init(&path); | |
123 | if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { | |
124 | fprintf(stderr, | |
125 | "error in converting name to path %s", strerror(errno)); | |
126 | exit(1); | |
127 | } | |
128 | if (s->ops->lstat(&s->ctx, &path, &stat)) { | |
129 | fprintf(stderr, "share path %s does not exist\n", fse->path); | |
130 | exit(1); | |
131 | } else if (!S_ISDIR(stat.st_mode)) { | |
132 | fprintf(stderr, "share path %s is not a directory\n", fse->path); | |
133 | exit(1); | |
134 | } | |
135 | v9fs_path_free(&path); | |
136 | ||
f4f61d27 AK |
137 | return &s->vdev; |
138 | } | |
139 | ||
140 | static int virtio_9p_init_pci(PCIDevice *pci_dev) | |
141 | { | |
142 | VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | |
143 | VirtIODevice *vdev; | |
144 | ||
145 | vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); | |
146 | vdev->nvectors = proxy->nvectors; | |
befeac45 | 147 | virtio_init_pci(proxy, vdev); |
f4f61d27 AK |
148 | /* make the actual value visible */ |
149 | proxy->nvectors = vdev->nvectors; | |
150 | return 0; | |
151 | } | |
152 | ||
40021f08 AL |
153 | static Property virtio_9p_properties[] = { |
154 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | |
155 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), | |
156 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
157 | DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), | |
158 | DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), | |
159 | DEFINE_PROP_END_OF_LIST(), | |
160 | }; | |
161 | ||
162 | static void virtio_9p_class_init(ObjectClass *klass, void *data) | |
163 | { | |
39bffca2 | 164 | DeviceClass *dc = DEVICE_CLASS(klass); |
40021f08 AL |
165 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
166 | ||
167 | k->init = virtio_9p_init_pci; | |
168 | k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
13744bd0 | 169 | k->device_id = PCI_DEVICE_ID_VIRTIO_9P; |
40021f08 AL |
170 | k->revision = VIRTIO_PCI_ABI_VERSION; |
171 | k->class_id = 0x2; | |
39bffca2 AL |
172 | dc->props = virtio_9p_properties; |
173 | dc->reset = virtio_pci_reset; | |
40021f08 AL |
174 | } |
175 | ||
8c43a6f0 | 176 | static const TypeInfo virtio_9p_info = { |
39bffca2 AL |
177 | .name = "virtio-9p-pci", |
178 | .parent = TYPE_PCI_DEVICE, | |
179 | .instance_size = sizeof(VirtIOPCIProxy), | |
180 | .class_init = virtio_9p_class_init, | |
f4f61d27 AK |
181 | }; |
182 | ||
83f7d43a | 183 | static void virtio_9p_register_types(void) |
f4f61d27 | 184 | { |
39bffca2 | 185 | type_register_static(&virtio_9p_info); |
7a462745 | 186 | virtio_9p_set_fd_limit(); |
f4f61d27 AK |
187 | } |
188 | ||
83f7d43a | 189 | type_init(virtio_9p_register_types) |