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 : 0 : 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 : : xenevtchn_port_or_error_t port;
92 : : struct td_xenblkif *blkif;
93 : : 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 : 0 : 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 : : 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 : : case BLKIF_PROTOCOL_NATIVE:
162 : : {
163 : : blkif_request_t *src;
164 : 0 : src = RING_GET_REQUEST(&rings->native, idx);
165 : : memcpy(dst, src, sizeof(blkif_request_t));
166 : : break;
167 : : }
168 : :
169 : : case BLKIF_PROTOCOL_X86_32:
170 : : {
171 : : 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 : : case BLKIF_PROTOCOL_X86_64:
178 : : {
179 : : 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 : : blkif_common_back_ring_t * ring;
210 : : RING_IDX rp, rc;
211 : : unsigned int n;
212 : : 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 : : 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 : : 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 : : int n_reqs;
294 : : int start;
295 : : blkif_request_t **reqs;
296 : : int limit;
297 : :
298 : 0 : start = blkif->n_reqs_free;
299 : :
300 [ # # ]: 0 : if (unlikely(blkif->barrier.msg))
301 : : return 0;
302 : :
303 : : /*
304 : : * In each iteration, copy as many request descriptors from the shared ring
305 : : * that can fit within the constraints.
306 : : * If there's memory available, use as many requests as available.
307 : : * If in low memory mode, don't copy any if there's some in flight.
308 : : * Otherwise, only copy one.
309 : : */
310 [ # # ]: 0 : if (tapdisk_server_mem_mode() == LOW_MEMORY_MODE)
311 : 0 : limit = blkif->ring_size != blkif->n_reqs_free ? 0 : 1;
312 : : else
313 : 0 : limit = blkif->n_reqs_free;
314 : :
315 : : do {
316 : 0 : reqs = &blkif->reqs_free[blkif->ring_size - blkif->n_reqs_free];
317 : :
318 [ # # ]: 0 : ASSERT(reqs);
319 : :
320 : 0 : n_reqs = xenio_blkif_get_requests(blkif, reqs, limit, final);
321 [ # # ]: 0 : ASSERT(n_reqs >= 0);
322 [ # # ]: 0 : if (!n_reqs)
323 : : break;
324 : :
325 : 0 : blkif->n_reqs_free -= n_reqs;
326 [ # # ]: 0 : ASSERT(blkif->n_reqs_free <= blkif->ring_size);
327 : 0 : limit -= n_reqs;
328 : 0 : final = 1;
329 : :
330 [ # # ]: 0 : if (unlikely(reqs[(n_reqs - 1)]->operation ==
331 : : BLKIF_OP_WRITE_BARRIER)) {
332 [ # # ]: 0 : ASSERT(!blkif->barrier.msg);
333 : 0 : blkif->barrier.msg = reqs[(n_reqs - 1)];
334 : 0 : blkif->barrier.io_done = false;
335 : 0 : blkif->barrier.io_err = 0;
336 : 0 : break;
337 : : }
338 : :
339 : : } while (1);
340 : :
341 : 0 : n_reqs = start - blkif->n_reqs_free;
342 : :
343 [ # # ]: 0 : if (!n_reqs)
344 : : /*
345 : : * We got a notification but the ring is empty. This is because we had
346 : : * previously suspended the operation of the ring because of a
347 : : * VBD.pause but when we completed a request prior to the pause we
348 : : * checked the ring for new requests. If there were request in the ring
349 : : * at that time, we consumed them but we did not consume the
350 : : * notification. This notification is the one we should have consumed,
351 : : * and can be ignored.
352 : : */
353 : : return 0;
354 : :
355 [ # # ]: 0 : if (blkif->in_polling)
356 : : /* We found at least one request, so keep polling some more */
357 : 0 : tapdisk_xenblkif_sched_stoppolling(blkif);
358 [ # # ]: 0 : else if (blkif->poll_duration)
359 : : /* We weren't polling, but polling is enabled, so let's start now */
360 : 0 : tapdisk_start_polling(blkif);
361 : :
362 : 0 : blkif->stats.reqs.in += n_reqs;
363 : :
364 : 0 : reqs = alloca(sizeof(blkif_request_t*) * n_reqs);
365 : 0 : memcpy(reqs, &blkif->reqs_free[blkif->ring_size - start],
366 : : sizeof(blkif_request_t*) * n_reqs);
367 : :
368 : 0 : tapdisk_xenblkif_queue_requests(blkif, reqs, n_reqs);
369 : :
370 : 0 : return n_reqs;
371 : : }
372 : :
373 : : /**
374 : : * Callback executed when there is a request descriptor in the ring. Copies as
375 : : * many request descriptors as possible (limited by local buffer space) to the
376 : : * td_blkif's local request buffer and queues them to the tapdisk queue.
377 : : */
378 : : static inline void
379 : 0 : tapdisk_xenio_ctx_ring_event(event_id_t id __attribute__((unused)),
380 : : char mode __attribute__((unused)), void *private)
381 : : {
382 : 0 : struct td_xenio_ctx *ctx = private;
383 : 0 : struct td_xenblkif *blkif = NULL;
384 : :
385 [ # # ]: 0 : ASSERT(ctx);
386 : :
387 : 0 : blkif = xenio_pending_blkif(ctx);
388 [ # # ]: 0 : if (!blkif) {
389 : : /* TODO log error */
390 : 0 : return;
391 : : }
392 : :
393 : 0 : blkif->stats.kicks.in++;
394 : :
395 : 0 : tapdisk_xenio_ctx_process_ring(blkif, ctx, 0);
396 : : }
397 : :
398 : : /* NB. may be NULL, but then the image must be bouncing I/O */
399 : : #define TD_XENBLKIF_DEFAULT_POOL "td-xenio-default"
400 : :
401 : : /**
402 : : * Opens a context on the specified pool.
403 : : *
404 : : * @param pool the pool, it can either be NULL or a non-zero length string
405 : : * @returns 0 in success, -errno on error
406 : : *
407 : : * TODO The pool is ignored, we always open the default pool.
408 : : */
409 : : static inline int
410 : 0 : tapdisk_xenio_ctx_open(const char *pool)
411 : : {
412 : : struct td_xenio_ctx *ctx;
413 : : int fd, err;
414 : :
415 : : /* zero-length pool names are not allowed */
416 [ # # ][ # # ]: 0 : if (pool && !strlen(pool))
417 : : return -EINVAL;
418 : :
419 : 0 : ctx = calloc(1, sizeof(*ctx));
420 [ # # ]: 0 : if (!ctx) {
421 : 0 : err = -errno;
422 : 0 : ERROR("cannot allocate memory");
423 : 0 : goto fail;
424 : : }
425 : :
426 : 0 : ctx->ring_event = -1; /* TODO is there a special value? */
427 : 0 : ctx->gntdev_fd = -1;
428 : 0 : ctx->pool = TD_XENBLKIF_DEFAULT_POOL;
429 : 0 : INIT_LIST_HEAD(&ctx->blkifs);
430 : 0 : list_add(&ctx->entry, &_td_xenio_ctxs);
431 : :
432 : 0 : ctx->gntdev_fd = open("/dev/xen/gntdev", O_NONBLOCK);
433 [ # # ]: 0 : if (ctx->gntdev_fd == -1) {
434 : 0 : err = -errno;
435 : 0 : ERROR("failed to open the grant device: %s\n", strerror(-err));
436 : 0 : goto fail;
437 : : }
438 : :
439 : 0 : ctx->xce_handle = xenevtchn_open(NULL, 0);
440 [ # # ]: 0 : if (!ctx->xce_handle) {
441 : 0 : err = -errno;
442 : 0 : ERROR("failed to open the event channel driver: %s\n",
443 : : strerror(-err));
444 : 0 : goto fail;
445 : : }
446 : :
447 : 0 : ctx->xcg_handle = xengnttab_open(NULL, 0);
448 [ # # ]: 0 : if (!ctx->xcg_handle) {
449 : 0 : err = -errno;
450 : 0 : ERROR("failed to open the grant table driver: %s\n",
451 : : strerror(-err));
452 : 0 : goto fail;
453 : : }
454 : :
455 : 0 : fd = xenevtchn_fd(ctx->xce_handle);
456 [ # # ]: 0 : if (fd < 0) {
457 : 0 : err = -errno;
458 : 0 : ERROR("failed to get the event channel file descriptor: %s\n",
459 : : strerror(-err));
460 : 0 : goto fail;
461 : : }
462 : :
463 : 0 : ctx->ring_event = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
464 : 0 : fd, TV_ZERO, tapdisk_xenio_ctx_ring_event, ctx);
465 [ # # ]: 0 : if (ctx->ring_event < 0) {
466 : 0 : err = ctx->ring_event;
467 : 0 : ERROR("failed to register event: %s\n", strerror(-err));
468 : 0 : goto fail;
469 : : }
470 : :
471 : : return 0;
472 : :
473 : : fail:
474 : 0 : tapdisk_xenio_ctx_close(ctx);
475 : 0 : return err;
476 : : }
477 : :
478 : :
479 : : /**
480 : : * Tells whether @ctx belongs to @pool.
481 : : *
482 : : * If no @pool is not specified and a default pool is set, @ctx is compared
483 : : * against the default pool. Note that NULL is valid pool name value.
484 : : */
485 : : static inline int
486 : 0 : __td_xenio_ctx_match(struct td_xenio_ctx * ctx, const char *pool)
487 : : {
488 [ # # ]: 0 : if (unlikely(!pool)) {
489 : : assert(TD_XENBLKIF_DEFAULT_POOL);
490 : 0 : return !strcmp(ctx->pool, TD_XENBLKIF_DEFAULT_POOL);
491 : : }
492 : :
493 : 0 : return !strcmp(ctx->pool, pool);
494 : : }
495 : :
496 : : #define tapdisk_xenio_find_ctx(_ctx, _cond) \
497 : : do { \
498 : : int found = 0; \
499 : : tapdisk_xenio_for_each_ctx(_ctx) { \
500 : : if (_cond) { \
501 : : found = 1; \
502 : : break; \
503 : : } \
504 : : } \
505 : : if (!found) \
506 : : _ctx = NULL; \
507 : : } while (0)
508 : :
509 : : int
510 : 0 : tapdisk_xenio_ctx_get(const char *pool, struct td_xenio_ctx ** _ctx)
511 : : {
512 : 0 : struct td_xenio_ctx *ctx;
513 : 0 : int err = 0;
514 : :
515 : : do {
516 [ # # ][ # # ]: 0 : tapdisk_xenio_find_ctx(ctx, __td_xenio_ctx_match(ctx, pool));
[ # # ]
517 [ # # ]: 0 : if (ctx) {
518 : 0 : *_ctx = ctx;
519 : 0 : return 0;
520 : : }
521 : :
522 : 0 : err = tapdisk_xenio_ctx_open(pool);
523 [ # # ]: 0 : } while (!err);
524 : :
525 : : return err;
526 : : }
527 : :
528 : : void
529 : 0 : tapdisk_xenio_ctx_put(struct td_xenio_ctx * ctx)
530 : : {
531 [ # # ]: 0 : if (list_empty(&ctx->blkifs))
532 : 0 : tapdisk_xenio_ctx_close(ctx);
533 : 0 : }
|