1 /*
2 * Copyright (C) 2014 FUJITSU LIMITED
3 * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
15
16 #include "libxl_osdeps.h" /* must come before any other headers */
17
18 #include "libxl_internal.h"
19
20 /*----- setup() and teardown() -----*/
21
22 /* callbacks */
23
24 static void all_devices_setup_cb(libxl__egc *egc,
25 libxl__multidev *multidev,
26 int rc);
27 static void device_setup_iterate(libxl__egc *egc,
28 libxl__ao_device *aodev);
29 static void devices_teardown_cb(libxl__egc *egc,
30 libxl__multidev *multidev,
31 int rc);
32
33 /* checkpoint device setup and teardown */
34
checkpoint_device_init(libxl__egc * egc,libxl__checkpoint_devices_state * cds,libxl__device_kind kind,void * libxl_dev)35 static libxl__checkpoint_device* checkpoint_device_init(libxl__egc *egc,
36 libxl__checkpoint_devices_state *cds,
37 libxl__device_kind kind,
38 void *libxl_dev)
39 {
40 libxl__checkpoint_device *dev = NULL;
41
42 STATE_AO_GC(cds->ao);
43 GCNEW(dev);
44 dev->backend_dev = libxl_dev;
45 dev->kind = kind;
46 dev->cds = cds;
47
48 return dev;
49 }
50
51 static void checkpoint_devices_setup(libxl__egc *egc,
52 libxl__checkpoint_devices_state *cds);
53
libxl__checkpoint_devices_setup(libxl__egc * egc,libxl__checkpoint_devices_state * cds)54 void libxl__checkpoint_devices_setup(libxl__egc *egc,
55 libxl__checkpoint_devices_state *cds)
56 {
57 int i;
58
59 STATE_AO_GC(cds->ao);
60
61 cds->num_devices = 0;
62 cds->num_nics = 0;
63 cds->num_disks = 0;
64
65 if (cds->device_kind_flags & (1 << LIBXL__DEVICE_KIND_VIF))
66 cds->nics = libxl__device_list(gc, &libxl__nic_devtype, cds->domid,
67 &cds->num_nics);
68
69 if (cds->device_kind_flags & (1 << LIBXL__DEVICE_KIND_VBD))
70 cds->disks = libxl__device_list(gc, &libxl__disk_devtype, cds->domid,
71 &cds->num_disks);
72
73 if (cds->num_nics == 0 && cds->num_disks == 0)
74 goto out;
75
76 GCNEW_ARRAY(cds->devs, cds->num_nics + cds->num_disks);
77
78 for (i = 0; i < cds->num_nics; i++) {
79 cds->devs[cds->num_devices++] = checkpoint_device_init(egc, cds,
80 LIBXL__DEVICE_KIND_VIF,
81 &cds->nics[i]);
82 }
83
84 for (i = 0; i < cds->num_disks; i++) {
85 cds->devs[cds->num_devices++] = checkpoint_device_init(egc, cds,
86 LIBXL__DEVICE_KIND_VBD,
87 &cds->disks[i]);
88 }
89
90 checkpoint_devices_setup(egc, cds);
91
92 return;
93
94 out:
95 cds->callback(egc, cds, 0);
96 }
97
checkpoint_devices_setup(libxl__egc * egc,libxl__checkpoint_devices_state * cds)98 static void checkpoint_devices_setup(libxl__egc *egc,
99 libxl__checkpoint_devices_state *cds)
100 {
101 int i, rc;
102
103 STATE_AO_GC(cds->ao);
104
105 libxl__multidev_begin(ao, &cds->multidev);
106 cds->multidev.callback = all_devices_setup_cb;
107 for (i = 0; i < cds->num_devices; i++) {
108 libxl__checkpoint_device *dev = cds->devs[i];
109 dev->ops_index = -1;
110 libxl__multidev_prepare_with_aodev(&cds->multidev, &dev->aodev);
111
112 dev->aodev.rc = ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED;
113 dev->aodev.callback = device_setup_iterate;
114 device_setup_iterate(egc,&dev->aodev);
115 }
116
117 rc = 0;
118 libxl__multidev_prepared(egc, &cds->multidev, rc);
119 }
120
121
device_setup_iterate(libxl__egc * egc,libxl__ao_device * aodev)122 static void device_setup_iterate(libxl__egc *egc, libxl__ao_device *aodev)
123 {
124 libxl__checkpoint_device *dev = CONTAINER_OF(aodev, *dev, aodev);
125 EGC_GC;
126
127 if (aodev->rc != ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED &&
128 aodev->rc != ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
129 /* might be success or disaster */
130 goto out;
131
132 do {
133 dev->ops = dev->cds->ops[++dev->ops_index];
134 if (!dev->ops) {
135 libxl_device_nic * nic = NULL;
136 libxl_device_disk * disk = NULL;
137 uint32_t domid = INVALID_DOMID;
138 int devid;
139 if (dev->kind == LIBXL__DEVICE_KIND_VIF) {
140 nic = (libxl_device_nic *)dev->backend_dev;
141 domid = nic->backend_domid;
142 devid = nic->devid;
143 } else if (dev->kind == LIBXL__DEVICE_KIND_VBD) {
144 disk = (libxl_device_disk *)dev->backend_dev;
145 domid = disk->backend_domid;
146 devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL);
147 } else {
148 LOGD(ERROR, domid, "device kind not handled by checkpoint: %s",
149 libxl__device_kind_to_string(dev->kind));
150 aodev->rc = ERROR_FAIL;
151 goto out;
152 }
153 LOGD(ERROR, domid, "device not handled by checkpoint"
154 " (device=%s:%"PRId32"/%"PRId32")",
155 libxl__device_kind_to_string(dev->kind),
156 domid, devid);
157 aodev->rc = ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED;
158 goto out;
159 }
160 } while (dev->ops->kind != dev->kind);
161
162 /* found the next ops_index to try */
163 assert(dev->aodev.callback == device_setup_iterate);
164 dev->ops->setup(egc,dev);
165 return;
166
167 out:
168 libxl__multidev_one_callback(egc,aodev);
169 }
170
all_devices_setup_cb(libxl__egc * egc,libxl__multidev * multidev,int rc)171 static void all_devices_setup_cb(libxl__egc *egc,
172 libxl__multidev *multidev,
173 int rc)
174 {
175 STATE_AO_GC(multidev->ao);
176
177 /* Convenience aliases */
178 libxl__checkpoint_devices_state *const cds =
179 CONTAINER_OF(multidev, *cds, multidev);
180
181 cds->callback(egc, cds, rc);
182 }
183
libxl__checkpoint_devices_teardown(libxl__egc * egc,libxl__checkpoint_devices_state * cds)184 void libxl__checkpoint_devices_teardown(libxl__egc *egc,
185 libxl__checkpoint_devices_state *cds)
186 {
187 int i;
188 libxl__checkpoint_device *dev;
189
190 STATE_AO_GC(cds->ao);
191
192 libxl__multidev_begin(ao, &cds->multidev);
193 cds->multidev.callback = devices_teardown_cb;
194 for (i = 0; i < cds->num_devices; i++) {
195 dev = cds->devs[i];
196 if (!dev->ops || !dev->matched)
197 continue;
198
199 libxl__multidev_prepare_with_aodev(&cds->multidev, &dev->aodev);
200 dev->ops->teardown(egc,dev);
201 }
202
203 libxl__multidev_prepared(egc, &cds->multidev, 0);
204 }
205
devices_teardown_cb(libxl__egc * egc,libxl__multidev * multidev,int rc)206 static void devices_teardown_cb(libxl__egc *egc,
207 libxl__multidev *multidev,
208 int rc)
209 {
210 STATE_AO_GC(multidev->ao);
211
212 /* Convenience aliases */
213 libxl__checkpoint_devices_state *const cds =
214 CONTAINER_OF(multidev, *cds, multidev);
215
216 /* clean nic */
217 libxl__device_list_free(&libxl__nic_devtype, cds->nics, cds->num_nics);
218 cds->nics = NULL;
219 cds->num_nics = 0;
220
221 /* clean disk */
222 libxl__device_list_free(&libxl__disk_devtype, cds->disks, cds->num_disks);
223 cds->disks = NULL;
224 cds->num_disks = 0;
225
226 cds->callback(egc, cds, rc);
227 }
228
229 /*----- checkpointing APIs -----*/
230
231 /* callbacks */
232
233 static void devices_checkpoint_cb(libxl__egc *egc,
234 libxl__multidev *multidev,
235 int rc);
236
237 /* API implementations */
238
239 #define define_checkpoint_api(api) \
240 void libxl__checkpoint_devices_##api(libxl__egc *egc, \
241 libxl__checkpoint_devices_state *cds) \
242 { \
243 int i; \
244 libxl__checkpoint_device *dev; \
245 \
246 STATE_AO_GC(cds->ao); \
247 \
248 libxl__multidev_begin(ao, &cds->multidev); \
249 cds->multidev.callback = devices_checkpoint_cb; \
250 for (i = 0; i < cds->num_devices; i++) { \
251 dev = cds->devs[i]; \
252 if (!dev->matched || !dev->ops->api) \
253 continue; \
254 libxl__multidev_prepare_with_aodev(&cds->multidev, &dev->aodev);\
255 dev->ops->api(egc,dev); \
256 } \
257 \
258 libxl__multidev_prepared(egc, &cds->multidev, 0); \
259 }
260
261 define_checkpoint_api(postsuspend);
262
263 define_checkpoint_api(preresume);
264
265 define_checkpoint_api(commit);
266
devices_checkpoint_cb(libxl__egc * egc,libxl__multidev * multidev,int rc)267 static void devices_checkpoint_cb(libxl__egc *egc,
268 libxl__multidev *multidev,
269 int rc)
270 {
271 STATE_AO_GC(multidev->ao);
272
273 /* Convenience aliases */
274 libxl__checkpoint_devices_state *const cds =
275 CONTAINER_OF(multidev, *cds, multidev);
276
277 cds->callback(egc, cds, rc);
278 }
279