]>
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 | ||
0d09e41a | 14 | #include "hw/virtio/virtio.h" |
93b48c20 | 15 | #include "hw/virtio/virtio-9p.h" |
0d09e41a | 16 | #include "hw/i386/pc.h" |
1de7afc9 | 17 | #include "qemu/sockets.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" |
d64ccb91 | 22 | #include "hw/virtio/virtio-access.h" |
f4f61d27 | 23 | |
9d5b731d JW |
24 | static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features, |
25 | Error **errp) | |
f4f61d27 | 26 | { |
0cd09c3a | 27 | virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG); |
f4f61d27 AK |
28 | return features; |
29 | } | |
30 | ||
f4f61d27 AK |
31 | static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) |
32 | { | |
e9a0152b | 33 | int len; |
f4f61d27 | 34 | struct virtio_9p_config *cfg; |
13daf6ca | 35 | V9fsState *s = VIRTIO_9P(vdev); |
f4f61d27 | 36 | |
e9a0152b AK |
37 | len = strlen(s->tag); |
38 | cfg = g_malloc0(sizeof(struct virtio_9p_config) + len); | |
d64ccb91 | 39 | virtio_stw_p(vdev, &cfg->tag_len, len); |
e9a0152b AK |
40 | /* We don't copy the terminating null to config space */ |
41 | memcpy(cfg->tag, s->tag, len); | |
f4f61d27 | 42 | memcpy(config, cfg, s->config_size); |
7267c094 | 43 | g_free(cfg); |
f4f61d27 AK |
44 | } |
45 | ||
4652f164 GK |
46 | static void virtio_9p_save(QEMUFile *f, void *opaque) |
47 | { | |
48 | virtio_save(VIRTIO_DEVICE(opaque), f); | |
49 | } | |
50 | ||
51 | static int virtio_9p_load(QEMUFile *f, void *opaque, int version_id) | |
52 | { | |
53 | return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); | |
54 | } | |
55 | ||
59be7522 | 56 | static void virtio_9p_device_realize(DeviceState *dev, Error **errp) |
0174fe73 | 57 | { |
59be7522 AF |
58 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); |
59 | V9fsState *s = VIRTIO_9P(dev); | |
f4f61d27 AK |
60 | int i, len; |
61 | struct stat stat; | |
fbcbf101 | 62 | FsDriverEntry *fse; |
7cca27df | 63 | V9fsPath path; |
f4f61d27 | 64 | |
0f3657ec | 65 | virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, |
e8111e50 | 66 | sizeof(struct virtio_9p_config) + MAX_TAG_LEN); |
e7303c43 | 67 | |
f4f61d27 AK |
68 | /* initialize pdu allocator */ |
69 | QLIST_INIT(&s->free_list); | |
bccacf6c | 70 | QLIST_INIT(&s->active_list); |
f4f61d27 AK |
71 | for (i = 0; i < (MAX_REQ - 1); i++) { |
72 | QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next); | |
73 | } | |
74 | ||
e8111e50 | 75 | s->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); |
f4f61d27 | 76 | |
27915efb AF |
77 | v9fs_path_init(&path); |
78 | ||
e8111e50 | 79 | fse = get_fsdev_fsentry(s->fsconf.fsdev_id); |
f4f61d27 AK |
80 | |
81 | if (!fse) { | |
82 | /* We don't have a fsdev identified by fsdev_id */ | |
59be7522 AF |
83 | error_setg(errp, "Virtio-9p device couldn't find fsdev with the " |
84 | "id = %s", | |
85 | s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL"); | |
92304bf3 | 86 | goto out; |
f4f61d27 AK |
87 | } |
88 | ||
e8111e50 | 89 | if (!s->fsconf.tag) { |
99519f0a | 90 | /* we haven't specified a mount_tag */ |
59be7522 AF |
91 | error_setg(errp, "fsdev with id %s needs mount_tag arguments", |
92 | s->fsconf.fsdev_id); | |
92304bf3 | 93 | goto out; |
f4f61d27 AK |
94 | } |
95 | ||
b97400ca | 96 | s->ctx.export_flags = fse->export_flags; |
c64f50d1 | 97 | s->ctx.fs_root = g_strdup(fse->path); |
b97400ca | 98 | s->ctx.exops.get_st_gen = NULL; |
e8111e50 | 99 | len = strlen(s->fsconf.tag); |
e9a0152b | 100 | if (len > MAX_TAG_LEN - 1) { |
59be7522 AF |
101 | error_setg(errp, "mount tag '%s' (%d bytes) is longer than " |
102 | "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1); | |
92304bf3 | 103 | goto out; |
f4f61d27 | 104 | } |
e9a0152b | 105 | |
92304bf3 | 106 | s->tag = g_strdup(s->fsconf.tag); |
f4f61d27 AK |
107 | s->ctx.uid = -1; |
108 | ||
109 | s->ops = fse->ops; | |
e9a0152b | 110 | s->config_size = sizeof(struct virtio_9p_config) + len; |
9e5b2247 | 111 | s->fid_list = NULL; |
02cb7f3a | 112 | qemu_co_rwlock_init(&s->rename_lock); |
f4f61d27 | 113 | |
0174fe73 | 114 | if (s->ops->init(&s->ctx) < 0) { |
59be7522 AF |
115 | error_setg(errp, "Virtio-9p Failed to initialize fs-driver with id:%s" |
116 | " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root); | |
92304bf3 | 117 | goto out; |
0174fe73 | 118 | } |
7cca27df MK |
119 | |
120 | /* | |
121 | * Check details of export path, We need to use fs driver | |
122 | * call back to do that. Since we are in the init path, we don't | |
123 | * use co-routines here. | |
124 | */ | |
7cca27df | 125 | if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { |
59be7522 AF |
126 | error_setg(errp, |
127 | "error in converting name to path %s", strerror(errno)); | |
92304bf3 | 128 | goto out; |
7cca27df MK |
129 | } |
130 | if (s->ops->lstat(&s->ctx, &path, &stat)) { | |
59be7522 | 131 | error_setg(errp, "share path %s does not exist", fse->path); |
92304bf3 | 132 | goto out; |
7cca27df | 133 | } else if (!S_ISDIR(stat.st_mode)) { |
59be7522 | 134 | error_setg(errp, "share path %s is not a directory", fse->path); |
92304bf3 | 135 | goto out; |
7cca27df MK |
136 | } |
137 | v9fs_path_free(&path); | |
138 | ||
4652f164 | 139 | register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, s); |
59be7522 | 140 | return; |
92304bf3 MK |
141 | out: |
142 | g_free(s->ctx.fs_root); | |
143 | g_free(s->tag); | |
144 | virtio_cleanup(vdev); | |
145 | v9fs_path_free(&path); | |
e7303c43 FK |
146 | } |
147 | ||
6cecf093 GK |
148 | static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) |
149 | { | |
150 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
151 | V9fsState *s = VIRTIO_9P(dev); | |
152 | ||
153 | virtio_cleanup(vdev); | |
154 | unregister_savevm(dev, "virtio-9p", s); | |
155 | g_free(s->ctx.fs_root); | |
156 | g_free(s->tag); | |
157 | } | |
158 | ||
e7303c43 FK |
159 | /* virtio-9p device */ |
160 | ||
e7303c43 | 161 | static Property virtio_9p_properties[] = { |
83a84878 SZ |
162 | DEFINE_PROP_STRING("mount_tag", V9fsState, fsconf.tag), |
163 | DEFINE_PROP_STRING("fsdev", V9fsState, fsconf.fsdev_id), | |
e7303c43 FK |
164 | DEFINE_PROP_END_OF_LIST(), |
165 | }; | |
166 | ||
167 | static void virtio_9p_class_init(ObjectClass *klass, void *data) | |
168 | { | |
169 | DeviceClass *dc = DEVICE_CLASS(klass); | |
170 | VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); | |
59be7522 | 171 | |
e7303c43 | 172 | dc->props = virtio_9p_properties; |
125ee0ed | 173 | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); |
59be7522 | 174 | vdc->realize = virtio_9p_device_realize; |
6cecf093 | 175 | vdc->unrealize = virtio_9p_device_unrealize; |
e7303c43 FK |
176 | vdc->get_features = virtio_9p_get_features; |
177 | vdc->get_config = virtio_9p_get_config; | |
178 | } | |
179 | ||
180 | static const TypeInfo virtio_device_info = { | |
181 | .name = TYPE_VIRTIO_9P, | |
182 | .parent = TYPE_VIRTIO_DEVICE, | |
183 | .instance_size = sizeof(V9fsState), | |
184 | .class_init = virtio_9p_class_init, | |
185 | }; | |
186 | ||
187 | static void virtio_9p_register_types(void) | |
188 | { | |
189 | type_register_static(&virtio_device_info); | |
190 | } | |
191 | ||
192 | type_init(virtio_9p_register_types) |