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 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <stdlib.h>
36 : : #include <stdio.h>
37 : : #include <unistd.h>
38 : : #include <errno.h>
39 : : #include <fcntl.h>
40 : : #include <limits.h>
41 : : #include <sys/mman.h>
42 : : #include <sys/ioctl.h>
43 : : #include <sys/sysmacros.h>
44 : : #include <sys/types.h>
45 : : #include <sys/stat.h>
46 : :
47 : : #include "blktap.h"
48 : : #include "tapdisk-vbd.h"
49 : : #include "tapdisk-blktap.h"
50 : : #include "tapdisk-metrics.h"
51 : : #include "tapdisk-server.h"
52 : : #include "timeout-math.h"
53 : : #include "linux-blktap.h"
54 : :
55 : : #define BUG(_cond) td_panic()
56 : : #define BUG_ON(_cond) if (unlikely(_cond)) { td_panic(); }
57 : :
58 : : #define DBG(_f, _a...) tlog_syslog(TLOG_DBG, _f, ##_a)
59 : : #define INFO(_f, _a...) tlog_syslog(TLOG_INFO, _f, ##_a)
60 : : #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
61 : : #define WARN(_f, _a...) tlog_syslog(TLOG_WARN, "WARNING: "_f "in %s:%d", \
62 : : ##_a, __func__, __LINE__)
63 : :
64 : : #define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1))
65 : : #define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x))
66 : : #define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x))
67 : : #define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x))
68 : : #define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
69 : :
70 : : #define BLKTAP_RD32(_n) __RD32(_n)
71 : : #define BLKTAP_RING_SIZE __BLKTAP_RING_SIZE(PAGE_SIZE)
72 : :
73 : : #define BLKTAP_GET_RESPONSE(_tap, _idx) \
74 : : (&(_tap)->sring->entry[(_idx) % BLKTAP_RING_SIZE].rsp)
75 : : #define BLKTAP_GET_REQUEST(_tap, _idx) \
76 : : (&(_tap)->sring->entry[(_idx) % BLKTAP_RING_SIZE].req)
77 : :
78 : : static void __tapdisk_blktap_close(td_blktap_t *);
79 : :
80 : : struct td_blktap_req {
81 : : td_vbd_request_t vreq;
82 : : unsigned int id;
83 : : char name[27];
84 : : struct td_iovec iov[BLKTAP_SEGMENT_MAX];
85 : : struct timeval ts;
86 : : };
87 : :
88 : : td_blktap_req_t *
89 : 0 : tapdisk_blktap_alloc_request(td_blktap_t *tap)
90 : : {
91 : 0 : td_blktap_req_t *req = NULL;
92 : :
93 [ # # ]: 0 : if (likely(tap->n_reqs_free))
94 : 0 : req = tap->reqs_free[--tap->n_reqs_free];
95 : :
96 : 0 : return req;
97 : : }
98 : :
99 : : void
100 : 0 : tapdisk_blktap_free_request(td_blktap_t *tap, td_blktap_req_t *req)
101 : : {
102 [ # # ]: 0 : BUG_ON(tap->n_reqs_free >= tap->n_reqs);
103 : 0 : tap->reqs_free[tap->n_reqs_free++] = req;
104 : 0 : }
105 : :
106 : : static void
107 : 0 : tapdisk_blktap_reqs_free(td_blktap_t *tap)
108 : : {
109 [ # # ]: 0 : if (tap->reqs) {
110 : 0 : free(tap->reqs);
111 : 0 : tap->reqs = NULL;
112 : : }
113 : :
114 [ # # ]: 0 : if (tap->reqs_free) {
115 : 0 : free(tap->reqs_free);
116 : 0 : tap->reqs_free = NULL;
117 : : }
118 : 0 : }
119 : :
120 : : static int
121 : 0 : tapdisk_blktap_reqs_init(td_blktap_t *tap, int n_reqs)
122 : : {
123 : : int i, err;
124 : :
125 : 0 : tap->reqs = malloc(n_reqs * sizeof(td_blktap_req_t));
126 [ # # ]: 0 : if (!tap->reqs) {
127 : 0 : err = -errno;
128 : 0 : goto fail;
129 : : }
130 : :
131 : 0 : tap->reqs_free = malloc(n_reqs * sizeof(td_blktap_req_t*));
132 [ # # ]: 0 : if (!tap->reqs_free) {
133 : 0 : err = -errno;
134 : 0 : goto fail;
135 : : }
136 : :
137 : 0 : tap->n_reqs = n_reqs;
138 : 0 : tap->n_reqs_free = 0;
139 : :
140 [ # # ]: 0 : for (i = 0; i < n_reqs; i++)
141 : 0 : tapdisk_blktap_free_request(tap, &tap->reqs[i]);
142 : :
143 : : return 0;
144 : :
145 : : fail:
146 : 0 : tapdisk_blktap_reqs_free(tap);
147 : 0 : return err;
148 : : }
149 : :
150 : : static void
151 : 0 : tapdisk_blktap_kick(td_blktap_t *tap)
152 : : {
153 [ # # ]: 0 : if (likely(tap->fd >= 0)) {
154 : 0 : ioctl(tap->fd, BLKTAP_IOCTL_RESPOND, 0);
155 : 0 : tap->stats.kicks.out++;
156 : : }
157 : 0 : }
158 : :
159 : : static int
160 : 0 : tapdisk_blktap_error_status(td_blktap_t *tap, int error)
161 : : {
162 : : int status;
163 : :
164 [ # # # ]: 0 : switch (error) {
[ # # # ]
165 : : case 0:
166 : : status = BLKTAP_RSP_OKAY;
167 : : break;
168 : : case -EOPNOTSUPP:
169 : : case EOPNOTSUPP:
170 : 0 : status = BLKTAP_RSP_EOPNOTSUPP;
171 : 0 : break;
172 : : default:
173 : 0 : status = BLKTAP_RSP_ERROR;
174 : 0 : break;
175 : : }
176 : :
177 : 0 : return status;
178 : : }
179 : :
180 : : static void
181 : 0 : __tapdisk_blktap_push_response(td_blktap_t *tap, int final)
182 : : {
183 : 0 : tap->rsp_prod_pvt++;
184 : :
185 [ # # ]: 0 : if (final) {
186 : 0 : tap->sring->rsp_prod = tap->rsp_prod_pvt;
187 : 0 : tapdisk_blktap_kick(tap);
188 : : }
189 : :
190 : 0 : tap->stats.reqs.out++;
191 : 0 : }
192 : :
193 : : static void
194 : 0 : tapdisk_blktap_fail_request(td_blktap_t *tap,
195 : : blktap_ring_req_t *msg, int error)
196 : : {
197 : : blktap_ring_rsp_t *rsp;
198 : :
199 [ # # ]: 0 : BUG_ON(!tap->vma);
200 : :
201 [ # # ][ # # ]: 0 : rsp = BLKTAP_GET_RESPONSE(tap, tap->rsp_prod_pvt);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
202 : :
203 : 0 : rsp->id = msg->id;
204 : 0 : rsp->operation = msg->operation;
205 : 0 : rsp->status = tapdisk_blktap_error_status(tap, error);
206 : :
207 : 0 : __tapdisk_blktap_push_response(tap, 1);
208 : 0 : }
209 : :
210 : : static void
211 : 0 : tapdisk_blktap_put_response(td_blktap_t *tap,
212 : : td_blktap_req_t *req, int error, int final)
213 : : {
214 : : blktap_ring_rsp_t *rsp;
215 : 0 : int op = 0;
216 : : unsigned long long interval;
217 : : struct timeval now;
218 : :
219 [ # # ]: 0 : BUG_ON(!tap->vma);
220 : :
221 [ # # ][ # # ]: 0 : rsp = BLKTAP_GET_RESPONSE(tap, tap->rsp_prod_pvt);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
222 : :
223 : 0 : gettimeofday(&now, NULL);
224 : 0 : interval = timeval_to_us(&now) - timeval_to_us(&req->ts);
225 [ # # # ]: 0 : switch (req->vreq.op) {
226 : : case TD_OP_READ:
227 : 0 : op = BLKTAP_OP_READ;
228 : 0 : tap->blktap_stats.stats->read_reqs_completed++;
229 : 0 : tap->blktap_stats.stats->read_total_ticks += interval;
230 : 0 : break;
231 : : case TD_OP_WRITE:
232 : 0 : op = BLKTAP_OP_WRITE;
233 : 0 : tap->blktap_stats.stats->write_reqs_completed++;
234 : 0 : tap->blktap_stats.stats->write_total_ticks += interval;
235 : 0 : break;
236 : : default:
237 : 0 : BUG();
238 : : }
239 : :
240 [ # # ]: 0 : if (error)
241 : 0 : tap->blktap_stats.stats->io_errors++;
242 : :
243 : 0 : rsp->id = req->id;
244 : 0 : rsp->operation = op;
245 : 0 : rsp->status = tapdisk_blktap_error_status(tap, error);
246 : :
247 : 0 : __tapdisk_blktap_push_response(tap, final);
248 : 0 : }
249 : :
250 : : static void
251 : 0 : tapdisk_blktap_complete_request(td_blktap_t *tap,
252 : : td_blktap_req_t *req, int error,
253 : : int final)
254 : : {
255 [ # # ]: 0 : if (likely(tap->vma))
256 : 0 : tapdisk_blktap_put_response(tap, req, error, final);
257 : :
258 : 0 : tapdisk_blktap_free_request(tap, req);
259 : 0 : }
260 : :
261 : : static void
262 : 0 : __tapdisk_blktap_request_cb(td_vbd_request_t *vreq, int error,
263 : : void *token, int final)
264 : : {
265 : 0 : td_blktap_req_t *req = container_of(vreq, td_blktap_req_t, vreq);
266 : 0 : td_blktap_t *tap = token;
267 : :
268 : 0 : tapdisk_blktap_complete_request(tap, req, error, final);
269 : 0 : }
270 : :
271 : : static void
272 : 0 : tapdisk_blktap_vector_request(td_blktap_t *tap,
273 : : const blktap_ring_req_t *msg,
274 : : td_blktap_req_t *req)
275 : : {
276 : 0 : td_vbd_request_t *vreq = &req->vreq;
277 : : const struct blktap_segment *seg;
278 : : struct td_iovec *iov;
279 : : void *page, *next, *last;
280 : : size_t size;
281 : : int i;
282 : 0 : unsigned nr_sect = 0;
283 : :
284 : 0 : iov = req->iov - 1;
285 : 0 : last = NULL;
286 : :
287 : 0 : page = tap->vstart;
288 : 0 : page += msg->id * BLKTAP_SEGMENT_MAX * PAGE_SIZE;
289 : :
290 [ # # ]: 0 : for (i = 0; i < msg->nr_segments; i++) {
291 : 0 : seg = &msg->seg[i];
292 : :
293 : 0 : next = page + (seg->first_sect << SECTOR_SHIFT);
294 : 0 : size = seg->last_sect - seg->first_sect + 1;
295 : :
296 [ # # ]: 0 : if (next != last) {
297 : 0 : iov++;
298 : 0 : iov->base = next;
299 : 0 : iov->secs = size;
300 : : } else
301 : 0 : iov->secs += size;
302 : :
303 : 0 : last = iov->base + (iov->secs << SECTOR_SHIFT);
304 : 0 : page += PAGE_SIZE;
305 : 0 : nr_sect += size;
306 : : }
307 : :
308 [ # # # ]: 0 : switch(msg->operation){
309 : : case BLKTAP_OP_READ:
310 : 0 : tap->blktap_stats.stats->read_sectors += nr_sect;
311 : 0 : break;
312 : : case BLKTAP_OP_WRITE:
313 : 0 : tap->blktap_stats.stats->write_sectors += nr_sect;
314 : 0 : break;
315 : : }
316 : 0 : vreq->iov = req->iov;
317 : 0 : vreq->iovcnt = iov - req->iov + 1;
318 : 0 : vreq->sec = msg->sector_number;
319 : 0 : }
320 : :
321 : : static int
322 : 0 : tapdisk_blktap_parse_request(td_blktap_t *tap,
323 : : const blktap_ring_req_t *msg, td_blktap_req_t *req)
324 : : {
325 : 0 : td_vbd_request_t *vreq = &req->vreq;
326 : 0 : int op, err = -EINVAL;
327 : :
328 : : memset(req, 0, sizeof(*req));
329 : :
330 : 0 : gettimeofday(&req->ts, NULL);
331 : :
332 [ # # # ]: 0 : switch (msg->operation) {
333 : : case BLKTAP_OP_READ:
334 : 0 : tap->blktap_stats.stats->read_reqs_submitted++;
335 : 0 : op = TD_OP_READ;
336 : 0 : break;
337 : : case BLKTAP_OP_WRITE:
338 : 0 : tap->blktap_stats.stats->write_reqs_submitted++;
339 : 0 : op = TD_OP_WRITE;
340 : 0 : break;
341 : : default:
342 : : goto fail;
343 : : }
344 : :
345 [ # # ][ # # ]: 0 : if (msg->id > BLKTAP_RING_SIZE)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
346 : : goto fail;
347 : :
348 [ # # ]: 0 : if (msg->nr_segments < 1 ||
349 : : msg->nr_segments > BLKTAP_SEGMENT_MAX)
350 : : goto fail;
351 : :
352 : 0 : req->id = msg->id;
353 : 0 : snprintf(req->name, sizeof(req->name),
354 : : "tap-%d.%d", tap->minor, req->id);
355 : :
356 : 0 : vreq->op = op;
357 : 0 : vreq->name = req->name;
358 : 0 : vreq->token = tap;
359 : 0 : vreq->cb = __tapdisk_blktap_request_cb;
360 : :
361 : 0 : tapdisk_blktap_vector_request(tap, msg, req);
362 : :
363 : 0 : err = 0;
364 : : fail:
365 : 0 : return err;
366 : : }
367 : :
368 : : static void
369 : 0 : tapdisk_blktap_get_requests(td_blktap_t *tap)
370 : : {
371 : : unsigned int rp, rc;
372 : : int err;
373 : :
374 : 0 : rp = tap->sring->req_prod;
375 : :
376 [ # # ]: 0 : for (rc = tap->req_cons; rc != rp; rc++) {
377 [ # # ][ # # ]: 0 : blktap_ring_req_t *msg = BLKTAP_GET_REQUEST(tap, rc);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
378 : : td_blktap_req_t *req;
379 : :
380 : 0 : tap->stats.reqs.in++;
381 : :
382 : 0 : req = tapdisk_blktap_alloc_request(tap);
383 [ # # ]: 0 : if (!req) {
384 : : err = -EFAULT;
385 : : goto fail_ring;
386 : : }
387 : :
388 : 0 : err = tapdisk_blktap_parse_request(tap, msg, req);
389 [ # # ]: 0 : if (err) {
390 : 0 : tapdisk_blktap_fail_request(tap, msg, err);
391 : 0 : tapdisk_blktap_free_request(tap, req);
392 : 0 : goto fail_ring;
393 : : }
394 : :
395 : 0 : err = tapdisk_vbd_queue_request(tap->vbd, &req->vreq);
396 [ # # ]: 0 : if (err)
397 : 0 : tapdisk_blktap_complete_request(tap, req, err, 1);
398 : : }
399 : :
400 : 0 : tap->req_cons = rc;
401 : :
402 : 0 : return;
403 : :
404 : : fail_ring:
405 : 0 : ERR(err, "ring error, disconnecting.");
406 : 0 : __tapdisk_blktap_close(tap);
407 : : }
408 : :
409 : : static void
410 : 0 : tapdisk_blktap_fd_event(event_id_t id, char mode, void *data)
411 : : {
412 : 0 : td_blktap_t *tap = data;
413 : :
414 : 0 : tap->stats.kicks.in++;
415 : 0 : tapdisk_blktap_get_requests(tap);
416 : 0 : }
417 : :
418 : : int
419 : 0 : tapdisk_blktap_remove_device(td_blktap_t *tap)
420 : : {
421 : 0 : int err = 0;
422 : :
423 [ # # ]: 0 : if (likely(tap->fd >= 0)) {
424 : 0 : err = ioctl(tap->fd, BLKTAP_IOCTL_REMOVE_DEVICE);
425 [ # # ]: 0 : if (err)
426 : 0 : err = -errno;
427 : : }
428 : :
429 : 0 : return err;
430 : : }
431 : :
432 : : int
433 : 0 : tapdisk_blktap_compat_create_device(td_blktap_t *tap,
434 : : const struct blktap_device_info *bdi)
435 : : {
436 : : struct blktap2_params params;
437 : : int err;
438 : :
439 : : memset(¶ms, 0, sizeof(params));
440 : 0 : params.capacity = bdi->capacity;
441 : 0 : params.sector_size = bdi->sector_size;
442 : :
443 : 0 : err = ioctl(tap->fd, BLKTAP_IOCTL_CREATE_DEVICE_COMPAT, ¶ms);
444 [ # # ]: 0 : if (err) {
445 : 0 : err = -errno;
446 : 0 : return err;
447 : : }
448 : :
449 [ # # ][ # # ]: 0 : if (bdi->flags || bdi->physical_sector_size != bdi->sector_size)
450 : 0 : WARN("fell back to compat ioctl(%d)",
451 : : BLKTAP_IOCTL_CREATE_DEVICE_COMPAT);
452 : :
453 : : return 0;
454 : : }
455 : :
456 : : #ifndef ENOIOCTLCMD
457 : : #define ENOIOCTLCMD 515
458 : : #endif
459 : :
460 : : int
461 : 0 : tapdisk_blktap_create_device(td_blktap_t *tap,
462 : : const td_disk_info_t *info, int rdonly)
463 : : {
464 : : struct blktap_device_info bdi;
465 : : unsigned long flags;
466 : : int err;
467 : :
468 : : memset(&bdi, 0, sizeof(bdi));
469 : :
470 : 0 : flags = 0;
471 [ # # ]: 0 : flags |= rdonly ? BLKTAP_DEVICE_RO : 0;
472 : :
473 : 0 : bdi.capacity = info->size;
474 : 0 : bdi.sector_size = info->sector_size;
475 : 0 : bdi.physical_sector_size = info->sector_size;
476 : 0 : bdi.flags = flags;
477 : :
478 : 0 : INFO("bdev: capacity=%llu sector_size=%u/%u flags=%#lx",
479 : : bdi.capacity, bdi.sector_size, bdi.physical_sector_size,
480 : : bdi.flags);
481 : :
482 : 0 : err = ioctl(tap->fd, BLKTAP_IOCTL_CREATE_DEVICE, &bdi);
483 [ # # ]: 0 : if (!err)
484 : 0 : return 0;
485 : :
486 : 0 : err = -errno;
487 [ # # ]: 0 : if (err == -ENOTTY || err == -ENOIOCTLCMD)
488 : 0 : err = tapdisk_blktap_compat_create_device(tap, &bdi);
489 : :
490 : 0 : return err;
491 : : }
492 : :
493 : : static void
494 : 0 : tapdisk_blktap_unmap(td_blktap_t *tap)
495 : : {
496 [ # # # # ]: 0 : if (tap->vma) {
497 : 0 : munmap(tap->vma, tap->vma_size);
498 : 0 : tap->vma = NULL;
499 : : }
500 : 0 : }
501 : :
502 : : static int
503 : 0 : tapdisk_blktap_map(td_blktap_t *tap)
504 : : {
505 : : int prot, flags, err;
506 : : void *vma;
507 : :
508 : 0 : tap->vma_size =
509 [ # # ][ # # ]: 0 : 1 + ((size_t)BLKTAP_RING_SIZE *
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
510 : 0 : BLKTAP_SEGMENT_MAX * PAGE_SIZE);
511 : :
512 : 0 : prot = PROT_READ | PROT_WRITE;
513 : 0 : flags = MAP_SHARED;
514 : :
515 : 0 : vma = mmap(NULL, tap->vma_size, prot, flags, tap->fd, 0);
516 [ # # ]: 0 : if (vma == MAP_FAILED) {
517 : 0 : err = -errno;
518 : : goto fail;
519 : : }
520 : :
521 : 0 : tap->vma = vma;
522 : 0 : tap->vstart = vma + PAGE_SIZE;
523 : :
524 : 0 : tap->req_cons = 0;
525 : 0 : tap->rsp_prod_pvt = 0;
526 : 0 : tap->sring = vma;
527 : :
528 : 0 : return 0;
529 : :
530 : : fail:
531 : 0 : tapdisk_blktap_unmap(tap);
532 : 0 : return err;
533 : : }
534 : :
535 : : static void
536 : 0 : __tapdisk_blktap_close(td_blktap_t *tap)
537 : : {
538 : : /*
539 : : * NB. this can bail out at runtime. after munmap, blktap
540 : : * already failed all pending block reqs. AIO on buffers will
541 : : * -EFAULT. vreq completion just backs off once fd/vma are
542 : : * gone, so we'll drain, then idle until close().
543 : : */
544 : : int err;
545 [ # # ]: 0 : if (tap->event_id >= 0) {
546 : 0 : tapdisk_server_unregister_event(tap->event_id);
547 : 0 : tap->event_id = -1;
548 : : }
549 : :
550 : 0 : tapdisk_blktap_unmap(tap);
551 : :
552 [ # # ]: 0 : if (tap->fd >= 0) {
553 : 0 : close(tap->fd);
554 : 0 : tap->fd = -1;
555 : : }
556 : 0 : err = td_metrics_blktap_stop(&tap->blktap_stats);
557 [ # # ]: 0 : if (err) {
558 : 0 : EPRINTF("failed to destroy blktap stats file: %s\n", strerror(-err));
559 : : }
560 : 0 : }
561 : :
562 : : void
563 : 0 : tapdisk_blktap_close(td_blktap_t *tap)
564 : : {
565 : 0 : __tapdisk_blktap_close(tap);
566 : 0 : tapdisk_blktap_reqs_free(tap);
567 : 0 : free(tap);
568 : 0 : }
569 : :
570 : : int
571 : 0 : tapdisk_blktap_open(const char *devname, td_vbd_t *vbd, td_blktap_t **_tap)
572 : : {
573 : : td_blktap_t *tap;
574 : : struct stat st;
575 : : int err;
576 : :
577 : 0 : tap = malloc(sizeof(*tap));
578 [ # # ]: 0 : if (!tap) {
579 : 0 : err = -errno;
580 : 0 : goto fail;
581 : : }
582 : :
583 : : memset(tap, 0, sizeof(*tap));
584 : 0 : tap->fd = -1;
585 : 0 : tap->event_id = -1;
586 : :
587 : 0 : tap->fd = open(devname, O_RDWR);
588 [ # # ]: 0 : if (tap->fd < 0) {
589 : 0 : err = -errno;
590 : 0 : goto fail;
591 : : }
592 : :
593 : 0 : err = fstat(tap->fd, &st);
594 [ # # ]: 0 : if (err) {
595 : 0 : err = -errno;
596 : 0 : goto fail;
597 : : }
598 : :
599 : 0 : tap->vbd = vbd;
600 : 0 : tap->minor = minor(st.st_rdev);
601 : :
602 : 0 : err = tapdisk_blktap_map(tap);
603 [ # # ]: 0 : if (err)
604 : : goto fail;
605 : :
606 : 0 : err = td_metrics_blktap_start(tap->minor, &tap->blktap_stats);
607 [ # # ]: 0 : if (err)
608 : : goto fail;
609 : :
610 : 0 : tap->event_id =
611 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
612 : 0 : tap->fd, TV_ZERO,
613 : : tapdisk_blktap_fd_event,
614 : : tap);
615 [ # # ]: 0 : if (tap->event_id < 0) {
616 : : err = tap->event_id;
617 : : goto fail;
618 : : }
619 : :
620 [ # # ][ # # ]: 0 : err = tapdisk_blktap_reqs_init(tap, BLKTAP_RING_SIZE);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
621 [ # # ]: 0 : if (err)
622 : : goto fail;
623 : :
624 [ # # ]: 0 : if (_tap)
625 : 0 : *_tap = tap;
626 : :
627 : 0 : return 0;
628 : :
629 : : fail:
630 [ # # ]: 0 : if (tap)
631 : 0 : tapdisk_blktap_close(tap);
632 : :
633 : 0 : return err;
634 : : }
635 : :
636 : : void
637 : 0 : tapdisk_blktap_stats(td_blktap_t *tap, td_stats_t *st)
638 : : {
639 : 0 : tapdisk_stats_field(st, "minor", "d", tap->minor);
640 : :
641 : 0 : tapdisk_stats_field(st, "reqs", "[");
642 : 0 : tapdisk_stats_val(st, "llu", tap->stats.reqs.in);
643 : 0 : tapdisk_stats_val(st, "llu", tap->stats.reqs.out);
644 : 0 : tapdisk_stats_leave(st, ']');
645 : :
646 : 0 : tapdisk_stats_field(st, "kicks", "[");
647 : 0 : tapdisk_stats_val(st, "llu", tap->stats.kicks.in);
648 : 0 : tapdisk_stats_val(st, "llu", tap->stats.kicks.out);
649 : 0 : tapdisk_stats_leave(st, ']');
650 : 0 : }
|