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 <assert.h>
32 : : #include <errno.h>
33 : : #include <stdlib.h>
34 : : #include <unistd.h>
35 : : #include <sys/types.h>
36 : : #include <sys/stat.h>
37 : : #include <fcntl.h>
38 : : #include <alloca.h>
39 : :
40 : : #include "blktap-xenif.h"
41 : : #include "debug.h"
42 : : #include "tapdisk-server.h"
43 : : #include "td-ctx.h"
44 : : #include "tapdisk-log.h"
45 : : #include "timeout-math.h"
46 : :
47 : : #define ERROR(_f, _a...) tlog_syslog(TLOG_WARN, "td-ctx: " _f, ##_a)
48 : :
49 : : struct list_head _td_xenio_ctxs = LIST_HEAD_INIT(_td_xenio_ctxs);
50 : :
51 : : /**
52 : : * TODO releases a pool?
53 : : */
54 : : static void
55 : 0 : tapdisk_xenio_ctx_close(struct td_xenio_ctx * const ctx)
56 : : {
57 [ # # ]: 0 : if (!ctx)
58 : : return;
59 : :
60 [ # # ]: 0 : if (ctx->ring_event >= 0) {
61 : 0 : tapdisk_server_unregister_event(ctx->ring_event);
62 : 0 : ctx->ring_event = -1;
63 : : }
64 : :
65 [ # # ]: 0 : if (ctx->xce_handle) {
66 : 0 : xenevtchn_close(ctx->xce_handle);
67 : 0 : ctx->xce_handle = NULL;
68 : : }
69 : :
70 [ # # ]: 0 : if (ctx->xcg_handle) {
71 : 0 : xengnttab_close(ctx->xcg_handle);
72 : 0 : ctx->xcg_handle = NULL;
73 : : }
74 : :
75 [ # # ]: 0 : if (ctx->gntdev_fd != -1) {
76 : 0 : close(ctx->gntdev_fd);
77 : 0 : ctx->gntdev_fd = -1;
78 : : }
79 : :
80 : 0 : list_del(&ctx->entry);
81 : :
82 : 0 : free(ctx);
83 : : }
84 : :
85 : : /*
86 : : * XXX only called by tapdisk_xenio_ctx_ring_event
87 : : */
88 : : static inline struct td_xenblkif *
89 : 0 : xenio_pending_blkif(struct td_xenio_ctx * const ctx)
90 : : {
91 : 0 : xenevtchn_port_or_error_t port;
92 : 0 : struct td_xenblkif *blkif;
93 : 0 : int err;
94 : :
95 [ # # ]: 0 : ASSERT(ctx);
96 : :
97 : : /*
98 : : * Get the local port for which there is a pending event.
99 : : */
100 : 0 : port = xenevtchn_pending(ctx->xce_handle);
101 [ # # ]: 0 : if (port == -1) {
102 : : /* TODO log error */
103 : : return NULL;
104 : : }
105 : :
106 : : /*
107 : : * Find the block interface with that local port.
108 : : */
109 [ # # # # : 0 : tapdisk_xenio_ctx_find_blkif(ctx, blkif,
# # # # ]
110 : : blkif->port == port);
111 : 0 : if (blkif) {
112 : 0 : err = xenevtchn_unmask(ctx->xce_handle, port);
113 [ # # ]: 0 : if (err) {
114 : : /* TODO log error */
115 : : return NULL;
116 : : }
117 : : }
118 : : /*
119 : : * TODO Is it possible to have an pending event channel but no block
120 : : * interface associated with it?
121 : : */
122 : :
123 : : return blkif;
124 : : }
125 : :
126 : : #define blkif_get_req(dst, src) \
127 : : { \
128 : : int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; \
129 : : dst->operation = src->operation; \
130 : : dst->nr_segments = src->nr_segments; \
131 : : dst->handle = src->handle; \
132 : : dst->id = src->id; \
133 : : dst->sector_number = src->sector_number; \
134 : : xen_rmb(); \
135 : : if (n > dst->nr_segments) \
136 : : n = dst->nr_segments; \
137 : : for (i = 0; i < n; i++) \
138 : : dst->seg[i] = src->seg[i]; \
139 : : }
140 : :
141 : : /**
142 : : * Utility function that retrieves a request using @idx as the ring index,
143 : : * copying it to the @dst in a H/W independent way.
144 : : *
145 : : * @param blkif the block interface
146 : : * @param dst address that receives the request
147 : : * @param rc the index of the request in the ring
148 : : */
149 : : static inline void
150 : 0 : xenio_blkif_get_request(struct td_xenblkif * const blkif,
151 : : blkif_request_t *const dst, const RING_IDX idx)
152 : : {
153 : 0 : blkif_back_rings_t * rings;
154 : :
155 [ # # ]: 0 : ASSERT(blkif);
156 [ # # ]: 0 : ASSERT(dst);
157 : :
158 : 0 : rings = &blkif->rings;
159 : :
160 [ # # # # ]: 0 : switch (blkif->proto) {
161 : 0 : case BLKIF_PROTOCOL_NATIVE:
162 : : {
163 : 0 : blkif_request_t *src;
164 : 0 : src = RING_GET_REQUEST(&rings->native, idx);
165 : 0 : memcpy(dst, src, sizeof(blkif_request_t));
166 : 0 : break;
167 : : }
168 : :
169 : 0 : case BLKIF_PROTOCOL_X86_32:
170 : : {
171 : 0 : blkif_x86_32_request_t *src;
172 : 0 : src = RING_GET_REQUEST(&rings->x86_32, idx);
173 [ # # ]: 0 : blkif_get_req(dst, src);
174 : : break;
175 : : }
176 : :
177 : 0 : case BLKIF_PROTOCOL_X86_64:
178 : : {
179 : 0 : blkif_x86_64_request_t *src;
180 : 0 : src = RING_GET_REQUEST(&rings->x86_64, idx);
181 [ # # ]: 0 : blkif_get_req(dst, src);
182 : : break;
183 : : }
184 : :
185 : : default:
186 : : /*
187 : : * TODO log error
188 : : */
189 : 0 : ASSERT(0);
190 : : }
191 : 0 : }
192 : :
193 : : /**
194 : : * Retrieves at most @count request descriptors from the ring, up to the
195 : : * first barrier request, copying them to @reqs.
196 : : *
197 : : * @param blkif the block interface
198 : : * @param reqs array of pointers where each element points to sufficient memory
199 : : * space that receives each request descriptor
200 : : * @param count retrieve at most that many request descriptors
201 : : * @returns the number of retrieved request descriptors
202 : : *
203 : : * XXX only called by xenio_blkif_get_requests
204 : : */
205 : : static inline int
206 : 0 : __xenio_blkif_get_requests(struct td_xenblkif * const blkif,
207 : : blkif_request_t *reqs[], const unsigned int count)
208 : : {
209 : 0 : blkif_common_back_ring_t * ring;
210 : 0 : RING_IDX rp, rc;
211 : 0 : unsigned int n;
212 : 0 : bool barrier;
213 : :
214 [ # # ]: 0 : ASSERT(blkif);
215 [ # # ]: 0 : ASSERT(reqs);
216 : :
217 [ # # ]: 0 : if (!count)
218 : : return 0;
219 : :
220 : 0 : ring = &blkif->rings.common;
221 : :
222 : 0 : rp = ring->sring->req_prod;
223 : 0 : xen_rmb(); /* TODO why? */
224 : :
225 : 0 : for (rc = ring->req_cons, n = 0, barrier = false;
226 [ # # # # ]: 0 : rc != rp && n < count && !barrier;
227 : 0 : rc++, n++) {
228 : :
229 : 0 : blkif_request_t *dst = reqs[n];
230 : :
231 : 0 : xenio_blkif_get_request(blkif, dst, rc);
232 : :
233 [ # # ]: 0 : if (unlikely(dst->operation == BLKIF_OP_WRITE_BARRIER))
234 : 0 : barrier = true;
235 : : }
236 : :
237 : 0 : ring->req_cons = rc;
238 : :
239 : 0 : return n;
240 : : }
241 : :
242 : : /**
243 : : * Retrieves at most @count request descriptors.
244 : : *
245 : : * @param blkif the block interface
246 : : * @param reqs array of pointers where each pointer points to sufficient
247 : : * memory to hold a request descriptor
248 : : * @count maximum number of request descriptors to retrieve
249 : : * @param final re-enable notifications before it stops reading
250 : : * @returns the number of request descriptors retrieved
251 : : *
252 : : * TODO change name
253 : : */
254 : : static inline int
255 : 0 : xenio_blkif_get_requests(struct td_xenblkif * const blkif,
256 : : blkif_request_t *reqs[], const int count, const int final)
257 : : {
258 : 0 : blkif_common_back_ring_t * ring;
259 : 0 : int n = 0;
260 : 0 : int work = 0;
261 : :
262 [ # # ]: 0 : ASSERT(blkif);
263 [ # # ]: 0 : ASSERT(reqs);
264 : :
265 : : ring = &blkif->rings.common;
266 : :
267 : 0 : do {
268 [ # # ]: 0 : if (final)
269 [ # # ]: 0 : RING_FINAL_CHECK_FOR_REQUESTS(ring, work);
270 : : else
271 : 0 : work = RING_HAS_UNCONSUMED_REQUESTS(ring);
272 : :
273 [ # # ]: 0 : if (!work)
274 : : break;
275 : :
276 [ # # ]: 0 : if (n >= count)
277 : : break;
278 : :
279 : 0 : n += __xenio_blkif_get_requests(blkif, reqs + n, count - n);
280 : :
281 [ # # # # ]: 0 : if (unlikely(n && reqs[(n - 1)]->operation == BLKIF_OP_WRITE_BARRIER))
282 : : break;
283 : :
284 : : } while (1);
285 : :
286 : 0 : return n;
287 : : }
288 : :
289 : : int
290 : 0 : tapdisk_xenio_ctx_process_ring(struct td_xenblkif *blkif,
291 : : struct td_xenio_ctx *ctx, int final)
292 : : {
293 : 0 : int n_reqs;
294 : 0 : int start;
295 : 0 : blkif_request_t **reqs;
296 : 0 : int limit;
297 : :
298 : 0 : start = blkif->n_reqs_free;
299 : :
300 [ # # ]: 0 : if (unlikely(blkif->barrier.msg))
301 : : return 0;
302 : :
303 : : limit = blkif->n_reqs_free;
304 : :
305 : 0 : do {
306 : 0 : reqs = &blkif->reqs_free[blkif->ring_size - blkif->n_reqs_free];
307 : :
308 [ # # ]: 0 : ASSERT(reqs);
309 : :
310 : 0 : n_reqs = xenio_blkif_get_requests(blkif, reqs, limit, final);
311 [ # # ]: 0 : ASSERT(n_reqs >= 0);
312 [ # # ]: 0 : if (!n_reqs)
313 : : break;
314 : :
315 : 0 : blkif->n_reqs_free -= n_reqs;
316 [ # # ]: 0 : ASSERT(blkif->n_reqs_free <= blkif->ring_size);
317 : 0 : limit -= n_reqs;
318 : 0 : final = 1;
319 : :
320 [ # # ]: 0 : if (unlikely(reqs[(n_reqs - 1)]->operation ==
321 : : BLKIF_OP_WRITE_BARRIER)) {
322 [ # # ]: 0 : ASSERT(!blkif->barrier.msg);
323 : 0 : blkif->barrier.msg = reqs[(n_reqs - 1)];
324 : 0 : blkif->barrier.io_done = false;
325 : 0 : blkif->barrier.io_err = 0;
326 : 0 : break;
327 : : }
328 : :
329 : : } while (1);
330 : :
331 : 0 : n_reqs = start - blkif->n_reqs_free;
332 : :
333 [ # # ]: 0 : if (!n_reqs)
334 : : /*
335 : : * We got a notification but the ring is empty. This is because we had
336 : : * previously suspended the operation of the ring because of a
337 : : * VBD.pause but when we completed a request prior to the pause we
338 : : * checked the ring for new requests. If there were request in the ring
339 : : * at that time, we consumed them but we did not consume the
340 : : * notification. This notification is the one we should have consumed,
341 : : * and can be ignored.
342 : : */
343 : : return 0;
344 : :
345 [ # # ]: 0 : if (blkif->in_polling)
346 : : /* We found at least one request, so keep polling some more */
347 : 0 : tapdisk_xenblkif_sched_stoppolling(blkif);
348 [ # # ]: 0 : else if (blkif->poll_duration)
349 : : /* We weren't polling, but polling is enabled, so let's start now */
350 : 0 : tapdisk_start_polling(blkif);
351 : :
352 : 0 : blkif->stats.reqs.in += n_reqs;
353 : :
354 : 0 : reqs = alloca(sizeof(blkif_request_t*) * n_reqs);
355 : 0 : memcpy(reqs, &blkif->reqs_free[blkif->ring_size - start],
356 : : sizeof(blkif_request_t*) * n_reqs);
357 : :
358 : 0 : tapdisk_xenblkif_queue_requests(blkif, reqs, n_reqs);
359 : :
360 : 0 : return n_reqs;
361 : : }
362 : :
363 : : /**
364 : : * Callback executed when there is a request descriptor in the ring. Copies as
365 : : * many request descriptors as possible (limited by local buffer space) to the
366 : : * td_blkif's local request buffer and queues them to the tapdisk queue.
367 : : */
368 : : static inline void
369 : 0 : tapdisk_xenio_ctx_ring_event(event_id_t id __attribute__((unused)),
370 : : char mode __attribute__((unused)), void *private)
371 : : {
372 : 0 : struct td_xenio_ctx *ctx = private;
373 : 0 : struct td_xenblkif *blkif = NULL;
374 : :
375 [ # # ]: 0 : ASSERT(ctx);
376 : :
377 : 0 : blkif = xenio_pending_blkif(ctx);
378 [ # # ]: 0 : if (!blkif) {
379 : : /* TODO log error */
380 : : return;
381 : : }
382 : :
383 : 0 : blkif->stats.kicks.in++;
384 : :
385 : 0 : tapdisk_xenio_ctx_process_ring(blkif, ctx, 0);
386 : : }
387 : :
388 : : /* NB. may be NULL, but then the image must be bouncing I/O */
389 : : #define TD_XENBLKIF_DEFAULT_POOL "td-xenio-default"
390 : :
391 : : /**
392 : : * Opens a context on the specified pool.
393 : : *
394 : : * @param pool the pool, it can either be NULL or a non-zero length string
395 : : * @returns 0 in success, -errno on error
396 : : *
397 : : * TODO The pool is ignored, we always open the default pool.
398 : : */
399 : : static inline int
400 : 0 : tapdisk_xenio_ctx_open(const char *pool)
401 : : {
402 : 0 : struct td_xenio_ctx *ctx;
403 : 0 : int fd, err;
404 : :
405 : : /* zero-length pool names are not allowed */
406 [ # # # # ]: 0 : if (pool && !strlen(pool))
407 : 0 : return -EINVAL;
408 : :
409 : 0 : ctx = calloc(1, sizeof(*ctx));
410 [ # # ]: 0 : if (!ctx) {
411 : 0 : err = -errno;
412 : 0 : ERROR("cannot allocate memory");
413 : 0 : goto fail;
414 : : }
415 : :
416 : 0 : ctx->ring_event = -1; /* TODO is there a special value? */
417 : 0 : ctx->gntdev_fd = -1;
418 : 0 : ctx->pool = TD_XENBLKIF_DEFAULT_POOL;
419 : 0 : INIT_LIST_HEAD(&ctx->blkifs);
420 : 0 : list_add(&ctx->entry, &_td_xenio_ctxs);
421 : :
422 : 0 : ctx->gntdev_fd = open("/dev/xen/gntdev", O_NONBLOCK);
423 [ # # ]: 0 : if (ctx->gntdev_fd == -1) {
424 : 0 : err = -errno;
425 : 0 : ERROR("failed to open the grant device: %s\n", strerror(-err));
426 : 0 : goto fail;
427 : : }
428 : :
429 : 0 : ctx->xce_handle = xenevtchn_open(NULL, 0);
430 [ # # ]: 0 : if (!ctx->xce_handle) {
431 : 0 : err = -errno;
432 : 0 : ERROR("failed to open the event channel driver: %s\n",
433 : : strerror(-err));
434 : 0 : goto fail;
435 : : }
436 : :
437 : 0 : ctx->xcg_handle = xengnttab_open(NULL, 0);
438 [ # # ]: 0 : if (!ctx->xcg_handle) {
439 : 0 : err = -errno;
440 : 0 : ERROR("failed to open the grant table driver: %s\n",
441 : : strerror(-err));
442 : 0 : goto fail;
443 : : }
444 : :
445 : 0 : fd = xenevtchn_fd(ctx->xce_handle);
446 [ # # ]: 0 : if (fd < 0) {
447 : 0 : err = -errno;
448 : 0 : ERROR("failed to get the event channel file descriptor: %s\n",
449 : : strerror(-err));
450 : 0 : goto fail;
451 : : }
452 : :
453 : 0 : ctx->ring_event = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
454 : 0 : fd, TV_ZERO, tapdisk_xenio_ctx_ring_event, ctx);
455 [ # # ]: 0 : if (ctx->ring_event < 0) {
456 : 0 : err = ctx->ring_event;
457 : 0 : ERROR("failed to register event: %s\n", strerror(-err));
458 : 0 : goto fail;
459 : : }
460 : :
461 : : return 0;
462 : :
463 : 0 : fail:
464 : 0 : tapdisk_xenio_ctx_close(ctx);
465 : : return err;
466 : : }
467 : :
468 : :
469 : : /**
470 : : * Tells whether @ctx belongs to @pool.
471 : : *
472 : : * If no @pool is not specified and a default pool is set, @ctx is compared
473 : : * against the default pool. Note that NULL is valid pool name value.
474 : : */
475 : : static inline int
476 : 0 : __td_xenio_ctx_match(struct td_xenio_ctx * ctx, const char *pool)
477 : : {
478 [ # # ]: 0 : if (unlikely(!pool)) {
479 : 0 : assert(TD_XENBLKIF_DEFAULT_POOL);
480 : 0 : return !strcmp(ctx->pool, TD_XENBLKIF_DEFAULT_POOL);
481 : : }
482 : :
483 : 0 : return !strcmp(ctx->pool, pool);
484 : : }
485 : :
486 : : #define tapdisk_xenio_find_ctx(_ctx, _cond) \
487 : : do { \
488 : : int found = 0; \
489 : : tapdisk_xenio_for_each_ctx(_ctx) { \
490 : : if (_cond) { \
491 : : found = 1; \
492 : : break; \
493 : : } \
494 : : } \
495 : : if (!found) \
496 : : _ctx = NULL; \
497 : : } while (0)
498 : :
499 : : int
500 : 0 : tapdisk_xenio_ctx_get(const char *pool, struct td_xenio_ctx ** _ctx)
501 : : {
502 : 0 : struct td_xenio_ctx *ctx;
503 : 0 : int err = 0;
504 : :
505 : 0 : do {
506 [ # # # # : 0 : tapdisk_xenio_find_ctx(ctx, __td_xenio_ctx_match(ctx, pool));
# # ]
507 : 0 : if (ctx) {
508 : 0 : *_ctx = ctx;
509 : 0 : return 0;
510 : : }
511 : :
512 : 0 : err = tapdisk_xenio_ctx_open(pool);
513 [ # # ]: 0 : } while (!err);
514 : :
515 : : return err;
516 : : }
517 : :
518 : : void
519 : 0 : tapdisk_xenio_ctx_put(struct td_xenio_ctx * ctx)
520 : : {
521 [ # # ]: 0 : if (list_empty(&ctx->blkifs))
522 : 0 : tapdisk_xenio_ctx_close(ctx);
523 : 0 : }
|