Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #include <stdlib.h>
32 : : #include <errno.h>
33 : : #include <sys/mman.h>
34 : : #include <unistd.h>
35 : : #include <stdio.h>
36 : : #include <libgen.h>
37 : : #include <zlib.h>
38 : :
39 : : #include "blktap-xenif.h"
40 : : #include "debug.h"
41 : : #include "blktap3.h"
42 : : #include "tapdisk.h"
43 : : #include "tapdisk-log.h"
44 : : #include "util.h"
45 : : #include "tapdisk-server.h"
46 : : #include "tapdisk-metrics.h"
47 : : #include "timeout-math.h"
48 : :
49 : : #include "td-blkif.h"
50 : : #include "td-ctx.h"
51 : : #include "td-req.h"
52 : :
53 : : struct td_xenblkif *
54 : 0 : tapdisk_xenblkif_find(const domid_t domid, const int devid)
55 : : {
56 : 0 : struct td_xenblkif *blkif = NULL;
57 : 0 : struct td_xenio_ctx *ctx;
58 : :
59 [ # # ]: 0 : tapdisk_xenio_for_each_ctx(ctx) {
60 [ # # # # : 0 : tapdisk_xenio_ctx_find_blkif(ctx, blkif,
# # # # #
# ]
61 : : blkif->domid == domid &&
62 : : blkif->devid == devid);
63 : : if (blkif)
64 : : return blkif;
65 : : }
66 : :
67 : : return NULL;
68 : : }
69 : :
70 : :
71 : : /**
72 : : * Returns 0 on success, -errno on failure.
73 : : */
74 : : static int
75 : 0 : tapdisk_xenblkif_stats_destroy(struct td_xenblkif *blkif)
76 : : {
77 : 0 : int err;
78 : :
79 : 0 : err = shm_destroy(&blkif->xenvbd_stats.io_ring);
80 [ # # ]: 0 : if (unlikely(err))
81 : 0 : goto out;
82 : 0 : free(blkif->xenvbd_stats.io_ring.path);
83 : 0 : blkif->xenvbd_stats.io_ring.path = NULL;
84 : :
85 : : /*
86 : : * blkif->stats.xenvbd was initialised to blkif->xenvbd_stats.stats.mem
87 : : * in tapdisk_xenblkif_stats_create(). That address will be unmapped
88 : : * by the call to shm_destroy(), and an error return does not mean it
89 : : * wasn't, so we must unconditionally NULL blkif->stats.xenvbd here.
90 : : */
91 : 0 : blkif->stats.xenvbd = NULL;
92 : 0 : err = shm_destroy(&blkif->xenvbd_stats.stats);
93 [ # # ]: 0 : if (unlikely(err))
94 : 0 : goto out;
95 : 0 : free(blkif->xenvbd_stats.stats.path);
96 : 0 : blkif->xenvbd_stats.stats.path = NULL;
97 : :
98 [ # # ]: 0 : if (likely(blkif->xenvbd_stats.root)) {
99 : 0 : err = rmdir(blkif->xenvbd_stats.root);
100 [ # # # # ]: 0 : if (unlikely(err && errno != ENOENT)) {
101 : 0 : err = errno;
102 : 0 : EPRINTF("failed to remove %s: %s\n",
103 : : blkif->xenvbd_stats.root, strerror(err));
104 : 0 : goto out;
105 : : }
106 : 0 : err = 0;
107 : :
108 : 0 : free(blkif->xenvbd_stats.root);
109 : 0 : blkif->xenvbd_stats.root = NULL;
110 : : }
111 : 0 : out:
112 : 0 : return -err;
113 : : }
114 : :
115 : :
116 : : /*
117 : : * TODO provide ring stats in raw format (the same way I/O stats are provided).
118 : : * xen-ringwatch will have to be modified accordingly.
119 : : */
120 : : static int
121 : 0 : tapdisk_xenblkif_stats_create(struct td_xenblkif *blkif)
122 : : {
123 : 0 : int err = 0, len;
124 : 0 : char *_path = NULL;
125 : :
126 : 0 : len = asprintf(&blkif->xenvbd_stats.root, "/dev/shm/vbd3-%d-%d",
127 : : blkif->domid, blkif->devid);
128 [ # # ]: 0 : if (unlikely(len == -1)) {
129 : 0 : err = errno;
130 : 0 : blkif->xenvbd_stats.root = NULL;
131 : 0 : goto out;
132 : : }
133 : :
134 : 0 : err = mkdir(blkif->xenvbd_stats.root, S_IRUSR | S_IWUSR);
135 [ # # ]: 0 : if (unlikely(err)) {
136 : 0 : err = errno;
137 [ # # ]: 0 : if (err != EEXIST) {
138 : 0 : EPRINTF("failed to create %s: %s\n",
139 : : blkif->xenvbd_stats.root, strerror(err));
140 : 0 : goto out;
141 : : }
142 : 0 : err = 0;
143 : : }
144 : :
145 : 0 : len = asprintf(&blkif->xenvbd_stats.io_ring.path, "%s/io_ring~",
146 : : blkif->xenvbd_stats.root);
147 [ # # ]: 0 : if (unlikely(len == -1)) {
148 : 0 : err = errno;
149 : 0 : blkif->xenvbd_stats.io_ring.path = NULL;
150 : 0 : goto out;
151 : : }
152 : 0 : blkif->xenvbd_stats.io_ring.size = PAGE_SIZE;
153 : 0 : err = shm_create(&blkif->xenvbd_stats.io_ring);
154 [ # # ]: 0 : if (unlikely(err)) {
155 : 0 : err = errno;
156 : 0 : EPRINTF("failed to create shm ring stats file: %s\n", strerror(err));
157 : 0 : goto out;
158 : : }
159 : :
160 : 0 : err = asprintf(&blkif->xenvbd_stats.stats.path, "%s/statistics",
161 : : blkif->xenvbd_stats.root);
162 [ # # ]: 0 : if (unlikely(err == -1)) {
163 : 0 : err = errno;
164 : 0 : blkif->xenvbd_stats.stats.path = NULL;
165 : 0 : goto out;
166 : : }
167 : 0 : blkif->xenvbd_stats.stats.size = PAGE_SIZE;
168 : 0 : err = shm_create(&blkif->xenvbd_stats.stats);
169 [ # # ]: 0 : if (unlikely(err))
170 : 0 : goto out;
171 : :
172 : 0 : blkif->xenvbd_stats.last = 0;
173 : :
174 : 0 : blkif->stats.xenvbd = blkif->xenvbd_stats.stats.mem;
175 : :
176 : 0 : err = tapdisk_xenblkif_ring_stats_update(blkif);
177 [ # # ]: 0 : if (unlikely(err)) {
178 : 0 : EPRINTF("failed to generate shared I/O ring stats: %s\n",
179 : : strerror(-err));
180 : 0 : goto out;
181 : : }
182 : :
183 : 0 : _path = strndup(blkif->xenvbd_stats.io_ring.path, len - 1);
184 [ # # ]: 0 : if (unlikely(!_path)) {
185 : 0 : err = errno;
186 : 0 : goto out;
187 : : }
188 : :
189 : 0 : err = rename(blkif->xenvbd_stats.io_ring.path, _path);
190 [ # # ]: 0 : if (unlikely(err)) {
191 : 0 : err = errno;
192 : 0 : goto out;
193 : : }
194 : :
195 : 0 : free(blkif->xenvbd_stats.io_ring.path);
196 : 0 : blkif->xenvbd_stats.io_ring.path = _path;
197 : 0 : _path = NULL;
198 : 0 : out:
199 : 0 : free(_path);
200 [ # # ]: 0 : if (err) {
201 : 0 : int err2 = tapdisk_xenblkif_stats_destroy(blkif);
202 [ # # ]: 0 : if (err2)
203 : 0 : EPRINTF("failed to clean up failed stats file: "
204 : : "%s (error ignored)\n", strerror(-err2));
205 : : }
206 : 0 : return -err;
207 : : }
208 : :
209 : :
210 : : int
211 : 0 : tapdisk_xenblkif_destroy(struct td_xenblkif * blkif)
212 : : {
213 : 0 : int err;
214 : :
215 [ # # ]: 0 : ASSERT(blkif);
216 : :
217 [ # # ]: 0 : if (tapdisk_xenblkif_chkrng_event_id(blkif) >= 0) {
218 : 0 : tapdisk_server_unregister_event(
219 : : tapdisk_xenblkif_chkrng_event_id(blkif));
220 : 0 : blkif->chkrng_event = -1;
221 : : }
222 : :
223 [ # # ]: 0 : if (tapdisk_xenblkif_stoppolling_event_id(blkif) >= 0) {
224 : 0 : tapdisk_server_unregister_event(
225 : : tapdisk_xenblkif_stoppolling_event_id(blkif));
226 : 0 : blkif->stoppolling_event = -1;
227 : : }
228 : :
229 : 0 : tapdisk_xenblkif_reqs_free(blkif);
230 : :
231 [ # # ]: 0 : if (blkif->ctx) {
232 [ # # ]: 0 : if (blkif->port >= 0)
233 : 0 : xenevtchn_unbind(blkif->ctx->xce_handle, blkif->port);
234 : :
235 [ # # ]: 0 : if (blkif->rings.common.sring) {
236 : 0 : err = xengnttab_unmap(blkif->ctx->xcg_handle,
237 : : blkif->rings.common.sring, blkif->ring_n_pages);
238 [ # # ]: 0 : if (unlikely(err)) {
239 : 0 : err = errno;
240 : 0 : EPRINTF("failed to unmap ring page %p (%d pages): %s "
241 : : "(error ignored)\n",
242 : : blkif->rings.common.sring, blkif->ring_n_pages,
243 : : strerror(err));
244 : 0 : err = 0;
245 : : }
246 : : }
247 : :
248 : 0 : list_del(&blkif->entry_ctx);
249 : 0 : list_del(&blkif->entry);
250 : 0 : tapdisk_xenio_ctx_put(blkif->ctx);
251 : : }
252 : 0 : err = td_metrics_vbd_stop(&blkif->vbd_stats);
253 [ # # ]: 0 : if (unlikely(err))
254 : 0 : EPRINTF("failed to destroy blkfront stats file: %s\n", strerror(-err));
255 : :
256 : 0 : err = tapdisk_xenblkif_stats_destroy(blkif);
257 [ # # ]: 0 : if (unlikely(err)) {
258 : 0 : EPRINTF("failed to clean up ring stats file: %s (error ignored)\n",
259 : : strerror(-err));
260 : 0 : err = 0;
261 : : }
262 : :
263 : 0 : free(blkif);
264 : :
265 : 0 : return err;
266 : : }
267 : :
268 : :
269 : : int
270 : 0 : tapdisk_xenblkif_reqs_pending(const struct td_xenblkif * const blkif)
271 : : {
272 [ # # ]: 0 : ASSERT(blkif);
273 : :
274 : 0 : return blkif->ring_size - blkif->n_reqs_free;
275 : : }
276 : :
277 : :
278 : : int
279 : 0 : tapdisk_xenblkif_disconnect(const domid_t domid, const int devid)
280 : : {
281 : 0 : int err;
282 : 0 : struct td_xenblkif *blkif;
283 : :
284 : 0 : blkif = tapdisk_xenblkif_find(domid, devid);
285 [ # # ]: 0 : if (!blkif)
286 : : return -ENODEV;
287 : :
288 [ # # ]: 0 : if (tapdisk_xenblkif_reqs_pending(blkif)) {
289 : 0 : RING_DEBUG(blkif, "disconnect from ring with %d pending requests\n",
290 : 0 : blkif->ring_size - blkif->n_reqs_free);
291 [ # # ]: 0 : if (td_flag_test(blkif->vbd->state, TD_VBD_PAUSED))
292 : 0 : RING_ERR(blkif, "disconnect from ring with %d pending requests "
293 : : "and the VBD paused\n",
294 : 0 : blkif->ring_size - blkif->n_reqs_free);
295 [ # # ]: 0 : list_move(&blkif->entry, &blkif->vbd->dead_rings);
296 : 0 : blkif->dead = true;
297 [ # # # # ]: 0 : if (blkif->ctx && blkif->port >= 0) {
298 : 0 : xenevtchn_unbind(blkif->ctx->xce_handle, blkif->port);
299 : 0 : blkif->port = -1;
300 : : }
301 : :
302 : 0 : err = td_metrics_vbd_stop(&blkif->vbd_stats);
303 [ # # ]: 0 : if (unlikely(err))
304 : 0 : EPRINTF("failed to destroy blkfront stats file: %s\n", strerror(-err));
305 : :
306 : 0 : err = tapdisk_xenblkif_stats_destroy(blkif);
307 [ # # ]: 0 : if (unlikely(err))
308 : 0 : EPRINTF("failed to clean up ring stats file: %s (error ignored)\n",
309 : : strerror(-err));
310 : :
311 : : /*
312 : : * FIXME shall we unmap the ring or will that lead to some fatal error
313 : : * in tapdisk? IIUC if we don't unmap it we'll get errors during grant
314 : : * copy.
315 : : */
316 : 0 : return 0;
317 : : } else
318 : 0 : return tapdisk_xenblkif_destroy(blkif);
319 : : }
320 : :
321 : :
322 : : void
323 : 0 : tapdisk_xenblkif_sched_stoppolling(const struct td_xenblkif *blkif)
324 : : {
325 : 0 : int err;
326 : :
327 [ # # ]: 0 : ASSERT(blkif);
328 : :
329 : 0 : err = tapdisk_server_event_set_timeout(
330 : 0 : tapdisk_xenblkif_stoppolling_event_id(blkif), TV_USECS(blkif->poll_duration));
331 [ # # ]: 0 : ASSERT(!err);
332 : 0 : }
333 : :
334 : : void
335 : 0 : tapdisk_xenblkif_unsched_stoppolling(const struct td_xenblkif *blkif)
336 : : {
337 : 0 : int err;
338 : :
339 [ # # ]: 0 : ASSERT(blkif);
340 : :
341 : 0 : err = tapdisk_server_event_set_timeout(
342 : 0 : tapdisk_xenblkif_stoppolling_event_id(blkif), TV_INF);
343 [ # # ]: 0 : ASSERT(!err);
344 : 0 : }
345 : :
346 : :
347 : : void
348 : 0 : tapdisk_start_polling(struct td_xenblkif *blkif)
349 : : {
350 [ # # ]: 0 : ASSERT(blkif);
351 : :
352 : : /* Only enter polling if the CPU utilisation is not too high */
353 [ # # ]: 0 : if (tapdisk_server_system_idle_cpu() > (float)blkif->poll_idle_threshold) {
354 : 0 : blkif->in_polling = true;
355 : :
356 : : /* Start checking the ring immediately */
357 : 0 : tapdisk_xenblkif_sched_chkrng(blkif);
358 : :
359 : : /* Schedule the future 'stop polling' event */
360 : 0 : tapdisk_xenblkif_sched_stoppolling(blkif);
361 : :
362 : 0 : tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 1);
363 : : }
364 : 0 : }
365 : :
366 : : static inline void
367 : 0 : tapdisk_xenblkif_cb_stoppolling(event_id_t id __attribute__((unused)),
368 : : char mode __attribute__((unused)), void *private)
369 : : {
370 : 0 : struct td_xenblkif *blkif = private;
371 : :
372 [ # # ]: 0 : ASSERT(blkif);
373 : :
374 : : /* Process the ring one final time, setting the event counter */
375 [ # # ]: 0 : if (!tapdisk_xenio_ctx_process_ring(blkif, blkif->ctx, 1)) {
376 : : /* If there were no new requests this time, then stop polling */
377 : 0 : blkif->in_polling = false;
378 : :
379 : : /* Stop obsessively checking the ring */
380 : 0 : tapdisk_xenblkif_unsched_chkrng(blkif);
381 : :
382 : : /* Make the 'stop polling' event not fire again */
383 : 0 : tapdisk_xenblkif_unsched_stoppolling(blkif);
384 : :
385 : 0 : tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 0);
386 : : }
387 : 0 : }
388 : :
389 : : void
390 : 0 : tapdisk_xenblkif_sched_chkrng(const struct td_xenblkif *blkif)
391 : : {
392 : 0 : int err;
393 : :
394 [ # # ]: 0 : ASSERT(blkif);
395 : :
396 : 0 : err = tapdisk_server_event_set_timeout(
397 : 0 : tapdisk_xenblkif_chkrng_event_id(blkif), TV_ZERO);
398 [ # # ]: 0 : ASSERT(!err);
399 : 0 : }
400 : :
401 : : void
402 : 0 : tapdisk_xenblkif_unsched_chkrng(const struct td_xenblkif *blkif)
403 : : {
404 : 0 : int err;
405 : :
406 [ # # ]: 0 : ASSERT(blkif);
407 : :
408 : 0 : err = tapdisk_server_event_set_timeout(
409 : 0 : tapdisk_xenblkif_chkrng_event_id(blkif), TV_INF);
410 [ # # ]: 0 : ASSERT(!err);
411 : 0 : }
412 : :
413 : : static inline void
414 : 0 : tapdisk_xenblkif_cb_chkrng(event_id_t id __attribute__((unused)),
415 : : char mode __attribute__((unused)), void *private)
416 : : {
417 : 0 : struct td_xenblkif *blkif = private;
418 : :
419 [ # # ]: 0 : ASSERT(blkif);
420 : :
421 : : /*
422 : : * If we are polling, process the ring without setting the event counter.
423 : : * If we are not polling, unschedule this event, process the ring and set
424 : : * the event counter.
425 : : */
426 : :
427 [ # # ]: 0 : if (!blkif->in_polling)
428 : 0 : tapdisk_xenblkif_unsched_chkrng(blkif);
429 : :
430 : 0 : tapdisk_xenio_ctx_process_ring(blkif, blkif->ctx, !blkif->in_polling);
431 : 0 : }
432 : :
433 : :
434 : : int
435 : 0 : tapdisk_xenblkif_connect(domid_t domid, int devid, const grant_ref_t * grefs,
436 : : int order, evtchn_port_t port, int proto, int poll_duration,
437 : : int poll_idle_threshold, const char *pool, td_vbd_t * vbd)
438 : : {
439 : 0 : struct td_xenblkif *td_blkif = NULL; /* TODO rename to blkif */
440 : 0 : struct td_xenio_ctx *td_ctx;
441 : 0 : int err;
442 : 0 : unsigned int i;
443 : 0 : void *sring;
444 : 0 : size_t sz;
445 : :
446 [ # # ]: 0 : ASSERT(grefs);
447 [ # # ]: 0 : ASSERT(vbd);
448 : :
449 : : /*
450 : : * Already connected?
451 : : */
452 [ # # ]: 0 : if (tapdisk_xenblkif_find(domid, devid)) {
453 : : /* TODO log error */
454 : 0 : return -EALREADY;
455 : : }
456 : :
457 : 0 : err = tapdisk_xenio_ctx_get(pool, &td_ctx);
458 [ # # ]: 0 : if (err) {
459 : : /* TODO log error */
460 : 0 : goto fail;
461 : : }
462 : :
463 : 0 : td_blkif = calloc(1, sizeof(*td_blkif));
464 [ # # ]: 0 : if (!td_blkif) {
465 : : /* TODO log error */
466 : 0 : err = -errno;
467 : 0 : goto fail;
468 : : }
469 : :
470 : 0 : td_blkif->domid = domid;
471 : 0 : td_blkif->devid = devid;
472 : 0 : td_blkif->vbd = vbd;
473 : 0 : td_blkif->ctx = td_ctx;
474 : 0 : td_blkif->proto = proto;
475 : 0 : td_blkif->dead = false;
476 : 0 : td_blkif->chkrng_event = -1;
477 : 0 : td_blkif->stoppolling_event = -1;
478 : 0 : td_blkif->in_polling = false;
479 : 0 : td_blkif->poll_duration = poll_duration;
480 : 0 : td_blkif->poll_idle_threshold = poll_idle_threshold;
481 : 0 : td_blkif->barrier.msg = NULL;
482 : 0 : td_blkif->barrier.io_done = false;
483 : 0 : td_blkif->barrier.io_err = 0;
484 : :
485 : 0 : td_blkif->xenvbd_stats.root = NULL;
486 : 0 : shm_init(&td_blkif->xenvbd_stats.io_ring);
487 : 0 : shm_init(&td_blkif->xenvbd_stats.stats);
488 : :
489 [ # # ]: 0 : memset(&td_blkif->stats, 0, sizeof(td_blkif->stats));
490 : :
491 [ # # ]: 0 : INIT_LIST_HEAD(&td_blkif->entry_ctx);
492 : 0 : INIT_LIST_HEAD(&td_blkif->entry);
493 : :
494 : : /*
495 : : * Create the shared ring.
496 : : */
497 : 0 : td_blkif->ring_n_pages = 1 << order;
498 [ # # ]: 0 : if (td_blkif->ring_n_pages > ARRAY_SIZE(td_blkif->ring_ref)) {
499 : 0 : RING_ERR(td_blkif, "too many pages (%u), max %zu\n",
500 : 0 : td_blkif->ring_n_pages, ARRAY_SIZE(td_blkif->ring_ref));
501 : 0 : err = -EINVAL;
502 : 0 : goto fail;
503 : : }
504 : :
505 : : /*
506 : : * TODO Why don't we just keep a copy of the array's address? There should
507 : : * be a reason for copying the addresses of the pages, figure out why.
508 : : * TODO Why do we even store it in the td_blkif in the first place?
509 : : */
510 [ # # ]: 0 : for (i = 0; i < td_blkif->ring_n_pages; i++)
511 : 0 : td_blkif->ring_ref[i] = grefs[i];
512 : :
513 : : /*
514 : : * Map the grant references that will be holding the request descriptors.
515 : : */
516 : 0 : sring = xengnttab_map_domain_grant_refs(td_blkif->ctx->xcg_handle,
517 : 0 : td_blkif->ring_n_pages, td_blkif->domid, td_blkif->ring_ref,
518 : : PROT_READ | PROT_WRITE);
519 [ # # ]: 0 : if (!sring) {
520 : 0 : err = -errno;
521 : 0 : RING_ERR(td_blkif, "failed to map domain's grant references: %s\n",
522 : 0 : strerror(-err));
523 : 0 : goto fail;
524 : : }
525 : :
526 : : /*
527 : : * Size of the ring, in bytes.
528 : : */
529 : 0 : sz = (size_t)PAGE_SIZE << order;
530 : :
531 : : /*
532 : : * Initialize the mapped address into the shared ring.
533 : : *
534 : : * TODO Check for protocol support in the beginning of this function.
535 : : */
536 [ # # # # ]: 0 : switch (td_blkif->proto) {
537 : 0 : case BLKIF_PROTOCOL_NATIVE:
538 : : {
539 : 0 : blkif_sring_t *__sring = sring;
540 [ # # # # : 0 : BACK_RING_INIT(&td_blkif->rings.native, __sring, sz);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
541 : 0 : break;
542 : : }
543 : 0 : case BLKIF_PROTOCOL_X86_32:
544 : : {
545 : 0 : blkif_x86_32_sring_t *__sring = sring;
546 [ # # # # : 0 : BACK_RING_INIT(&td_blkif->rings.x86_32, __sring, sz);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
547 : 0 : break;
548 : : }
549 : 0 : case BLKIF_PROTOCOL_X86_64:
550 : : {
551 : 0 : blkif_x86_64_sring_t *__sring = sring;
552 [ # # # # : 0 : BACK_RING_INIT(&td_blkif->rings.x86_64, __sring, sz);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
553 : 0 : break;
554 : : }
555 : 0 : default:
556 : 0 : RING_ERR(td_blkif, "unsupported protocol 0x%x\n", td_blkif->proto);
557 : 0 : err = -EPROTONOSUPPORT;
558 : 0 : goto fail;
559 : : }
560 : :
561 : : /*
562 : : * Bind to the remote port.
563 : : * TODO elaborate
564 : : */
565 : 0 : td_blkif->port = xenevtchn_bind_interdomain(td_blkif->ctx->xce_handle,
566 : 0 : td_blkif->domid, port);
567 [ # # ]: 0 : if (td_blkif->port == -1) {
568 : 0 : err = -errno;
569 : 0 : RING_ERR(td_blkif, "failed to bind to event channel port %d: %s\n",
570 : 0 : port, strerror(-err));
571 : 0 : goto fail;
572 : : }
573 : :
574 : 0 : err = tapdisk_xenblkif_reqs_init(td_blkif);
575 [ # # ]: 0 : if (err) {
576 : : /* TODO log error */
577 : 0 : goto fail;
578 : : }
579 : :
580 : 0 : td_blkif->chkrng_event = tapdisk_server_register_event(
581 : 0 : SCHEDULER_POLL_TIMEOUT, -1, TV_INF,
582 : : tapdisk_xenblkif_cb_chkrng, td_blkif);
583 [ # # ]: 0 : if (unlikely(td_blkif->chkrng_event < 0)) {
584 : 0 : err = td_blkif->chkrng_event;
585 : 0 : RING_ERR(td_blkif, "failed to register event: %s\n", strerror(-err));
586 : 0 : goto fail;
587 : : }
588 : :
589 : 0 : err = td_metrics_vbd_start(td_blkif->domid, td_blkif->devid, &td_blkif->vbd_stats);
590 [ # # ]: 0 : if (unlikely(err))
591 : 0 : goto fail;
592 : :
593 : 0 : td_blkif->stoppolling_event = tapdisk_server_register_event(
594 : 0 : SCHEDULER_POLL_TIMEOUT, -1, TV_INF,
595 : : tapdisk_xenblkif_cb_stoppolling, td_blkif);
596 [ # # ]: 0 : if (unlikely(td_blkif->stoppolling_event < 0)) {
597 : 0 : err = td_blkif->stoppolling_event;
598 : 0 : RING_ERR(td_blkif, "failed to register event: %s\n", strerror(-err));
599 : 0 : goto fail;
600 : : }
601 : :
602 : 0 : err = tapdisk_xenblkif_stats_create(td_blkif);
603 [ # # ]: 0 : if (unlikely(err))
604 : 0 : goto fail;
605 : :
606 : 0 : list_add_tail(&td_blkif->entry, &vbd->rings);
607 : 0 : list_add_tail(&td_blkif->entry_ctx, &td_ctx->blkifs);
608 : :
609 : 0 : DPRINTF("ring %p connected\n", td_blkif);
610 : :
611 : : return 0;
612 : :
613 : 0 : fail:
614 [ # # ]: 0 : if (td_blkif) {
615 : 0 : int err2 = tapdisk_xenblkif_destroy(td_blkif);
616 [ # # ]: 0 : if (err2)
617 : 0 : EPRINTF("failed to destroy the block interface: %s "
618 : : "(error ignored)\n", strerror(-err2));
619 : : }
620 : :
621 : : return err;
622 : : }
623 : :
624 : :
625 : : event_id_t
626 : 0 : tapdisk_xenblkif_evtchn_event_id(const struct td_xenblkif *blkif)
627 : : {
628 : 0 : return blkif->ctx->ring_event;
629 : : }
630 : :
631 : :
632 : : event_id_t
633 : 0 : tapdisk_xenblkif_chkrng_event_id(const struct td_xenblkif *blkif)
634 : : {
635 [ # # ]: 0 : return blkif->chkrng_event;
636 : : }
637 : :
638 : :
639 : : event_id_t
640 : 0 : tapdisk_xenblkif_stoppolling_event_id(const struct td_xenblkif *blkif)
641 : : {
642 [ # # ]: 0 : return blkif->stoppolling_event;
643 : : }
644 : :
645 : :
646 : : int
647 : 0 : tapdisk_xenblkif_ring_stats_update(struct td_xenblkif *blkif)
648 : : {
649 : 0 : time_t t;
650 : 0 : int err = 0, len;
651 : 0 : struct blkif_common_back_ring *ring = NULL;
652 : 0 : uLong *chksum = NULL;
653 : :
654 [ # # ]: 0 : if (!blkif)
655 : : return 0;
656 : :
657 [ # # ]: 0 : if (unlikely(blkif->dead))
658 : : return 0;
659 : :
660 : 0 : ring = &blkif->rings.common;
661 [ # # ]: 0 : if (!ring->sring)
662 : : return 0;
663 : :
664 [ # # ]: 0 : ASSERT(blkif->xenvbd_stats.io_ring.mem);
665 : :
666 : : /*
667 : : * Update the ring stats once every five seconds.
668 : : */
669 : 0 : t = time(NULL);
670 [ # # ]: 0 : if (t - blkif->xenvbd_stats.last < 5)
671 : : return 0;
672 : 0 : blkif->xenvbd_stats.last = t;
673 : :
674 : 0 : len = snprintf(blkif->xenvbd_stats.io_ring.mem + sizeof(*chksum),
675 : 0 : blkif->xenvbd_stats.io_ring.size,
676 : : "nr_ents %u\n"
677 : : "req prod %u cons %d event %u\n"
678 : : "rsp prod %u pvt %d event %u\n",
679 : : ring->nr_ents,
680 : : ring->sring->req_prod, ring->req_cons, ring->sring->req_event,
681 [ # # ]: 0 : ring->sring->rsp_prod, ring->rsp_prod_pvt, ring->sring->rsp_event);
682 [ # # ]: 0 : if (unlikely(len < 0))
683 : 0 : err = errno;
684 [ # # ]: 0 : else if (unlikely(len + sizeof(uLong) >= blkif->xenvbd_stats.io_ring.size))
685 : : err = ENOBUFS;
686 : : else {
687 : 0 : err = ftruncate(blkif->xenvbd_stats.io_ring.fd, len + sizeof(*chksum));
688 [ # # ]: 0 : if (unlikely(err)) {
689 : 0 : err = errno;
690 : 0 : EPRINTF("failed to truncate %s to %lu: %s\n",
691 : : blkif->xenvbd_stats.io_ring.path, len + sizeof(*chksum),
692 : : strerror(err));
693 : : }
694 : : }
695 : :
696 : 0 : chksum = blkif->xenvbd_stats.io_ring.mem;
697 : 0 : *chksum = crc32(0L, blkif->xenvbd_stats.io_ring.mem + sizeof(*chksum),
698 : : len);
699 : :
700 : 0 : return -err;
701 : : }
702 : :
703 : :
704 : : void
705 : 0 : tapdisk_xenblkif_suspend(struct td_xenblkif * const blkif)
706 : : {
707 [ # # ]: 0 : ASSERT(blkif);
708 : :
709 : 0 : tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 1);
710 : 0 : tapdisk_server_mask_event(tapdisk_xenblkif_chkrng_event_id(blkif), 1);
711 : 0 : }
712 : :
713 : :
714 : : void
715 : 0 : tapdisk_xenblkif_resume(struct td_xenblkif * const blkif)
716 : : {
717 [ # # ]: 0 : ASSERT(blkif);
718 : :
719 : 0 : tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 0);
720 : 0 : tapdisk_server_mask_event(tapdisk_xenblkif_chkrng_event_id(blkif), 0);
721 : 0 : }
722 : :
723 : :
724 : : bool
725 : 0 : tapdisk_xenblkif_barrier_should_complete(
726 : : const struct td_xenblkif * const blkif)
727 : : {
728 [ # # ]: 0 : ASSERT(blkif);
729 : :
730 [ # # # # ]: 0 : return blkif->barrier.msg && 1 == tapdisk_xenblkif_reqs_pending(blkif) &&
731 [ # # # # ]: 0 : (0 == blkif->barrier.msg->nr_segments || blkif->barrier.io_done);
732 : : }
|