]>
Commit | Line | Data |
---|---|---|
f4f61d27 AK |
1 | /* |
2 | * Virtio 9p backend | |
3 | * | |
4 | * Copyright IBM, Corp. 2010 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <[email protected]> | |
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" | |
f4f61d27 | 16 | #include "qemu_socket.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; |
99519f0a AK |
88 | if (fse->path) { |
89 | s->ctx.fs_root = g_strdup(fse->path); | |
90 | } else { | |
91 | s->ctx.fs_root = NULL; | |
92 | } | |
b97400ca | 93 | s->ctx.exops.get_st_gen = NULL; |
f4f61d27 | 94 | len = strlen(conf->tag); |
e9a0152b | 95 | if (len > MAX_TAG_LEN - 1) { |
a2f507d9 | 96 | fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " |
e9a0152b | 97 | "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN - 1); |
a2f507d9 | 98 | exit(1); |
f4f61d27 | 99 | } |
e9a0152b AK |
100 | |
101 | s->tag = strdup(conf->tag); | |
f4f61d27 AK |
102 | s->ctx.uid = -1; |
103 | ||
104 | s->ops = fse->ops; | |
105 | s->vdev.get_features = virtio_9p_get_features; | |
e9a0152b | 106 | s->config_size = sizeof(struct virtio_9p_config) + len; |
f4f61d27 | 107 | s->vdev.get_config = virtio_9p_get_config; |
9e5b2247 | 108 | s->fid_list = NULL; |
02cb7f3a | 109 | qemu_co_rwlock_init(&s->rename_lock); |
f4f61d27 | 110 | |
0174fe73 AK |
111 | if (s->ops->init(&s->ctx) < 0) { |
112 | fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s" | |
113 | " and export path:%s\n", conf->fsdev_id, s->ctx.fs_root); | |
114 | exit(1); | |
115 | } | |
39c0564e VJ |
116 | if (v9fs_init_worker_threads() < 0) { |
117 | fprintf(stderr, "worker thread initialization failed\n"); | |
118 | exit(1); | |
119 | } | |
7cca27df MK |
120 | |
121 | /* | |
122 | * Check details of export path, We need to use fs driver | |
123 | * call back to do that. Since we are in the init path, we don't | |
124 | * use co-routines here. | |
125 | */ | |
126 | v9fs_path_init(&path); | |
127 | if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { | |
128 | fprintf(stderr, | |
129 | "error in converting name to path %s", strerror(errno)); | |
130 | exit(1); | |
131 | } | |
132 | if (s->ops->lstat(&s->ctx, &path, &stat)) { | |
133 | fprintf(stderr, "share path %s does not exist\n", fse->path); | |
134 | exit(1); | |
135 | } else if (!S_ISDIR(stat.st_mode)) { | |
136 | fprintf(stderr, "share path %s is not a directory\n", fse->path); | |
137 | exit(1); | |
138 | } | |
139 | v9fs_path_free(&path); | |
140 | ||
f4f61d27 AK |
141 | return &s->vdev; |
142 | } | |
143 | ||
144 | static int virtio_9p_init_pci(PCIDevice *pci_dev) | |
145 | { | |
146 | VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | |
147 | VirtIODevice *vdev; | |
148 | ||
149 | vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); | |
150 | vdev->nvectors = proxy->nvectors; | |
befeac45 | 151 | virtio_init_pci(proxy, vdev); |
f4f61d27 AK |
152 | /* make the actual value visible */ |
153 | proxy->nvectors = vdev->nvectors; | |
154 | return 0; | |
155 | } | |
156 | ||
40021f08 AL |
157 | static Property virtio_9p_properties[] = { |
158 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | |
159 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), | |
160 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
161 | DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), | |
162 | DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), | |
163 | DEFINE_PROP_END_OF_LIST(), | |
164 | }; | |
165 | ||
166 | static void virtio_9p_class_init(ObjectClass *klass, void *data) | |
167 | { | |
39bffca2 | 168 | DeviceClass *dc = DEVICE_CLASS(klass); |
40021f08 AL |
169 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
170 | ||
171 | k->init = virtio_9p_init_pci; | |
172 | k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
173 | k->device_id = 0x1009; | |
174 | k->revision = VIRTIO_PCI_ABI_VERSION; | |
175 | k->class_id = 0x2; | |
39bffca2 AL |
176 | dc->props = virtio_9p_properties; |
177 | dc->reset = virtio_pci_reset; | |
40021f08 AL |
178 | } |
179 | ||
39bffca2 AL |
180 | static TypeInfo virtio_9p_info = { |
181 | .name = "virtio-9p-pci", | |
182 | .parent = TYPE_PCI_DEVICE, | |
183 | .instance_size = sizeof(VirtIOPCIProxy), | |
184 | .class_init = virtio_9p_class_init, | |
f4f61d27 AK |
185 | }; |
186 | ||
83f7d43a | 187 | static void virtio_9p_register_types(void) |
f4f61d27 | 188 | { |
39bffca2 | 189 | type_register_static(&virtio_9p_info); |
7a462745 | 190 | virtio_9p_set_fd_limit(); |
f4f61d27 AK |
191 | } |
192 | ||
83f7d43a | 193 | type_init(virtio_9p_register_types) |