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 <string.h>
38 : : #include <unistd.h>
39 : : #include <errno.h>
40 : : #include <sys/socket.h>
41 : : #include <sys/un.h>
42 : :
43 : : #include "tapdisk.h"
44 : : #include "tapdisk-driver.h"
45 : : #include "tapdisk-server.h"
46 : : #include "tapdisk-interface.h"
47 : : #include "timeout-math.h"
48 : : #include "util.h"
49 : :
50 : : #include "block-valve.h"
51 : :
52 : : typedef struct td_valve td_valve_t;
53 : : typedef struct td_valve_request td_valve_request_t;
54 : :
55 : : struct td_valve_request {
56 : : td_request_t treq;
57 : : int secs;
58 : :
59 : : struct list_head entry;
60 : : td_valve_t *valve;
61 : : };
62 : :
63 : : struct td_valve_stats {
64 : : unsigned long long stor;
65 : : unsigned long long forw;
66 : : };
67 : :
68 : : struct td_valve {
69 : : char *brname;
70 : : unsigned long flags;
71 : :
72 : : int sock;
73 : : event_id_t sock_id;
74 : :
75 : : event_id_t sched_id;
76 : : event_id_t retry_id;
77 : :
78 : : unsigned int cred;
79 : : unsigned int need;
80 : : unsigned int done;
81 : :
82 : : struct list_head stor;
83 : : struct list_head forw;
84 : :
85 : : td_valve_request_t reqv[MAX_REQUESTS];
86 : : td_valve_request_t *free[MAX_REQUESTS];
87 : : int n_free;
88 : :
89 : : struct td_valve_stats stats;
90 : : };
91 : :
92 : : #define td_valve_for_each_stored_request(_req, _next, _valve) \
93 : : list_for_each_entry_safe(_req, _next, &(_valve)->stor, entry)
94 : :
95 : : #define td_valve_for_each_forwarded_request(_req, _next, _valve) \
96 : : list_for_each_entry_safe(_req, _next, &(_valve)->forw, entry)
97 : :
98 : : #define TD_VALVE_CONNECT_INTERVAL 2 /* s */
99 : :
100 : : #define TD_VALVE_RDLIMIT (1<<0)
101 : : #define TD_VALVE_WRLIMIT (1<<1)
102 : : #define TD_VALVE_KILLED (1<<31)
103 : :
104 : : static void valve_schedule_retry(td_valve_t *);
105 : : static void valve_conn_receive(td_valve_t *);
106 : : static void valve_conn_request(td_valve_t *, unsigned long);
107 : : static void valve_forward_stored_requests(td_valve_t *);
108 : : static void valve_kill(td_valve_t *);
109 : :
110 : : #define DBG(_f, _a...) if (1) { tlog_syslog(TLOG_DBG, _f, ##_a); }
111 : : #define INFO(_f, _a...) tlog_syslog(TLOG_INFO, "valve: " _f, ##_a)
112 : : #define WARN(_f, _a...) tlog_syslog(TLOG_WARN, "WARNING: "_f " in %s:%d", \
113 : : ##_a, __func__, __LINE__)
114 : : #define ERR(_f, _a...) tlog_syslog(TLOG_WARN, "ERROR: " _f " in %s:%d", \
115 : : ##_a, __func__, __LINE__)
116 : : #define VERR(_err, _f, _a...) tlog_syslog(TLOG_WARN, \
117 : : "ERROR: err=%d (%s), " _f ".", \
118 : : _err, strerror(-(_err)), ##_a)
119 : : #undef PERROR
120 : : #define PERROR(_f, _a...) VERR(-errno, _f, ##_a)
121 : :
122 : : #define BUG() do { \
123 : : ERR("Aborting"); \
124 : : td_panic(); \
125 : : } while (0)
126 : :
127 : : #define BUG_ON(_cond) \
128 : : if (unlikely(_cond)) { \
129 : : ERR("(%s) = %ld", #_cond, (long)(_cond)); \
130 : : BUG(); \
131 : : }
132 : :
133 : : #define WARN_ON(_cond) ({ \
134 : : int __cond = _cond; \
135 : : if (unlikely(__cond)) \
136 : : WARN("(%s) = %ld", #_cond, (long)(_cond)); \
137 : : __cond; \
138 : : })
139 : :
140 : : #define TREQ_SIZE(_treq) ((unsigned long)(_treq.secs) << 9)
141 : :
142 : : static td_valve_request_t *
143 : : valve_alloc_request(td_valve_t *valve)
144 : : {
145 : 0 : td_valve_request_t *req = NULL;
146 : :
147 [ # # ]: 0 : if (valve->n_free)
148 : 0 : req = valve->free[--valve->n_free];
149 : :
150 : : return req;
151 : : }
152 : :
153 : : static void
154 : 0 : valve_free_request(td_valve_t *valve, td_valve_request_t *req)
155 : : {
156 [ # # ]: 0 : BUG_ON(valve->n_free >= ARRAY_SIZE(valve->free));
157 : 0 : list_del_init(&req->entry);
158 : 0 : valve->free[valve->n_free++] = req;
159 : 0 : }
160 : :
161 : : static void
162 : 0 : __valve_sock_event(event_id_t id, char mode, void *private)
163 : : {
164 : 0 : td_valve_t *valve = private;
165 : :
166 : 0 : valve_conn_receive(valve);
167 : :
168 : 0 : valve_forward_stored_requests(valve);
169 : 0 : }
170 : :
171 : : static void
172 : 0 : valve_set_done_pending(td_valve_t *valve)
173 : : {
174 [ # # ]: 0 : WARN_ON(valve->done == 0);
175 : 0 : tapdisk_server_mask_event(valve->sched_id, 0);
176 : 0 : }
177 : :
178 : : static void
179 : 0 : valve_clear_done_pending(td_valve_t *valve)
180 : : {
181 [ # # ]: 0 : WARN_ON(valve->done != 0);
182 : 0 : tapdisk_server_mask_event(valve->sched_id, 1);
183 : 0 : }
184 : :
185 : : static void
186 : 0 : __valve_sched_event(event_id_t id, char mode, void *private)
187 : : {
188 : 0 : td_valve_t *valve = private;
189 : :
190 [ # # ]: 0 : if (likely(valve->done > 0))
191 : : /* flush valve->done */
192 : 0 : valve_conn_request(valve, 0);
193 : 0 : }
194 : :
195 : : static void
196 : 0 : valve_sock_close(td_valve_t *valve)
197 : : {
198 [ # # ]: 0 : if (valve->sock >= 0) {
199 : 0 : close(valve->sock);
200 : 0 : valve->sock = -1;
201 : : }
202 : :
203 [ # # ]: 0 : if (valve->sock_id >= 0) {
204 : 0 : tapdisk_server_unregister_event(valve->sock_id);
205 : 0 : valve->sock_id = -1;
206 : : }
207 : :
208 [ # # ]: 0 : if (valve->sched_id >= 0) {
209 : 0 : tapdisk_server_unregister_event(valve->sched_id);
210 : 0 : valve->sched_id = -1;
211 : : }
212 : 0 : }
213 : :
214 : : static int
215 : 0 : valve_sock_open(td_valve_t *valve)
216 : : {
217 : 0 : struct sockaddr_un addr = { .sun_family = AF_UNIX };
218 : : int s, id, err;
219 : :
220 : 0 : s = socket(AF_UNIX, SOCK_STREAM, 0);
221 [ # # ]: 0 : if (s < 0) {
222 : 0 : PERROR("socket");
223 : 0 : err = -errno;
224 : 0 : goto fail;
225 : : }
226 : :
227 : 0 : valve->sock = s;
228 : :
229 [ # # ]: 0 : if (valve->brname[0] == '/') {
230 [ # # ]: 0 : if (unlikely(strlen(valve->brname) >= sizeof(addr.sun_path))) {
231 : 0 : ERR("socket name too long: %s\n", valve->brname);
232 : : err = -ENAMETOOLONG;
233 : : goto fail;
234 : : }
235 : 0 : safe_strncpy(addr.sun_path, valve->brname, sizeof(addr.sun_path));
236 : : } else
237 : 0 : snprintf(addr.sun_path, sizeof(addr.sun_path),
238 : : "%s/%s", TD_VALVE_SOCKDIR, valve->brname);
239 : :
240 : 0 : err = connect(valve->sock, &addr, sizeof(addr));
241 [ # # ]: 0 : if (err) {
242 : 0 : err = -errno;
243 : 0 : goto fail;
244 : : }
245 : :
246 : 0 : id = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
247 : 0 : valve->sock, TV_ZERO,
248 : : __valve_sock_event,
249 : : valve);
250 [ # # ]: 0 : if (id < 0) {
251 : : err = id;
252 : : goto fail;
253 : : }
254 : :
255 : 0 : valve->sock_id = id;
256 : :
257 : 0 : id = tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT,
258 : 0 : -1, TV_ZERO,
259 : : __valve_sched_event,
260 : : valve);
261 [ # # ]: 0 : if (id < 0) {
262 : : err = id;
263 : : goto fail;
264 : : }
265 : :
266 : 0 : valve->sched_id = id;
267 : :
268 : 0 : INFO("Connected to %s", addr.sun_path);
269 : :
270 : 0 : valve->cred = 0;
271 : 0 : valve->need = 0;
272 : 0 : valve->done = 0;
273 : :
274 : 0 : valve_clear_done_pending(valve);
275 : :
276 : 0 : return 0;
277 : :
278 : : fail:
279 : 0 : valve_sock_close(valve);
280 : : return err;
281 : : }
282 : :
283 : : static int
284 : 0 : valve_sock_send(td_valve_t *valve, const void *msg, size_t size)
285 : : {
286 : : ssize_t n;
287 : :
288 : 0 : n = send(valve->sock, msg, size, MSG_DONTWAIT);
289 [ # # ]: 0 : if (n < 0)
290 : 0 : return -errno;
291 [ # # ]: 0 : if (n != size)
292 : : return -EPROTO;
293 : :
294 : 0 : return 0;
295 : : }
296 : :
297 : : static int
298 : 0 : valve_sock_recv(td_valve_t *valve, void *msg, size_t size)
299 : : {
300 : : ssize_t n;
301 : :
302 : 0 : n = recv(valve->sock, msg, size, MSG_DONTWAIT);
303 [ # # ]: 0 : if (n < 0)
304 : 0 : return -errno;
305 : :
306 : 0 : return n;
307 : : }
308 : :
309 : : static void
310 : 0 : __valve_retry_timeout(event_id_t id, char mode, void *private)
311 : : {
312 : 0 : td_valve_t *valve = private;
313 : : int err;
314 : :
315 : 0 : err = valve_sock_open(valve);
316 [ # # ]: 0 : if (!err)
317 : 0 : tapdisk_server_unregister_event(valve->retry_id);
318 : 0 : }
319 : :
320 : : static void
321 : 0 : valve_schedule_retry(td_valve_t *valve)
322 : : {
323 : : int id;
324 : :
325 [ # # ]: 0 : BUG_ON(valve->sock_id >= 0);
326 : :
327 : 0 : id = tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT,
328 : 0 : -1, TV_SECS(TD_VALVE_CONNECT_INTERVAL),
329 : : __valve_retry_timeout,
330 : : valve);
331 [ # # ]: 0 : BUG_ON(id < 0);
332 : :
333 : 0 : valve->retry_id = id;
334 : 0 : }
335 : :
336 : : static void
337 : 0 : valve_conn_open(td_valve_t *valve)
338 : : {
339 : : int err;
340 : :
341 [ # # ]: 0 : BUG_ON(valve->flags & TD_VALVE_KILLED);
342 : :
343 : 0 : err = valve_sock_open(valve);
344 [ # # ]: 0 : if (err) {
345 : 0 : WARN("%s: %s", valve->brname, strerror(-err));
346 : 0 : valve_schedule_retry(valve);
347 : : }
348 : 0 : }
349 : :
350 : : static void
351 : 0 : valve_conn_close(td_valve_t *valve, int reset)
352 : : {
353 : : td_valve_request_t *req, *next;
354 : :
355 : 0 : valve_sock_close(valve);
356 : :
357 [ # # ]: 0 : if (reset)
358 [ # # ]: 0 : td_valve_for_each_stored_request(req, next, valve) {
359 : 0 : td_forward_request(req->treq);
360 : 0 : valve->stats.forw++;
361 : 0 : valve_free_request(valve, req);
362 : : }
363 : :
364 [ # # ]: 0 : WARN_ON(!list_empty(&valve->stor));
365 : 0 : }
366 : :
367 : : static void
368 : : valve_conn_reset(td_valve_t *valve)
369 : : {
370 : 0 : valve_conn_close(valve, 1);
371 : 0 : valve_conn_open(valve);
372 : : }
373 : :
374 : : void
375 : 0 : valve_conn_receive(td_valve_t *valve)
376 : : {
377 : 0 : unsigned long buf[32], cred = 0;
378 : : ssize_t n;
379 : : int i, err;
380 : :
381 : 0 : n = valve_sock_recv(valve, buf, sizeof(buf));
382 [ # # ]: 0 : if (!n) {
383 : : err = -ECONNRESET;
384 : : goto reset;
385 : : }
386 : :
387 [ # # ]: 0 : if (n < 0) {
388 : 0 : err = n;
389 [ # # ]: 0 : if (err != -EAGAIN)
390 : : goto reset;
391 : : }
392 : :
393 [ # # ]: 0 : for (i = 0; i < n / sizeof(buf[0]); i++) {
394 [ # # ]: 0 : err = WARN_ON(buf[i] >= TD_RLB_REQUEST_MAX);
395 [ # # ]: 0 : if (err)
396 : : goto kill;
397 : :
398 : 0 : cred += buf[i];
399 : : }
400 : :
401 [ # # ]: 0 : if (cred > valve->need) {
402 : : err = -EINVAL;
403 : : goto reset;
404 : : }
405 : :
406 : 0 : valve->cred += cred;
407 : 0 : valve->need -= cred;
408 : :
409 : 0 : return;
410 : :
411 : : reset:
412 : 0 : VERR(err, "resetting connection");
413 : : valve_conn_reset(valve);
414 : : return;
415 : :
416 : : kill:
417 : 0 : ERR("Killing valve.");
418 : : valve_kill(valve);
419 : : }
420 : :
421 : : static void
422 : 0 : valve_conn_request(td_valve_t *valve, unsigned long size)
423 : : {
424 : : struct td_valve_req _req;
425 : : int err;
426 : :
427 : 0 : _req.need = size;
428 : 0 : _req.done = valve->done;
429 : :
430 : 0 : valve->need += size;
431 : 0 : valve->done = 0;
432 : :
433 : 0 : valve_clear_done_pending(valve);
434 : :
435 : 0 : err = valve_sock_send(valve, &_req, sizeof(_req));
436 [ # # ]: 0 : if (!err)
437 : 0 : return;
438 : :
439 : 0 : VERR(err, "resetting connection");
440 : : valve_conn_reset(valve);
441 : : }
442 : :
443 : : static int
444 : 0 : valve_expend_request(td_valve_t *valve, const td_request_t treq)
445 : : {
446 [ # # ][ # # ]: 0 : if (valve->flags & TD_VALVE_KILLED)
447 : : return 0;
448 : :
449 [ # # ][ # # ]: 0 : if (valve->sock < 0)
450 : : return 0;
451 : :
452 [ # # ][ # # ]: 0 : if (valve->cred < TREQ_SIZE(treq))
453 : : return -EAGAIN;
454 : :
455 : 0 : valve->cred -= TREQ_SIZE(treq);
456 : :
457 : 0 : return 0;
458 : : }
459 : :
460 : : static void
461 : 0 : __valve_complete_treq(td_request_t treq, int error)
462 : : {
463 : 0 : td_valve_request_t *req = treq.cb_data;
464 : 0 : td_valve_t *valve = req->valve;
465 : :
466 [ # # ]: 0 : BUG_ON(req->secs < treq.secs);
467 : 0 : req->secs -= treq.secs;
468 : :
469 : 0 : valve->done += TREQ_SIZE(treq);
470 : 0 : valve_set_done_pending(valve);
471 : :
472 : : /* Respond to original callback */
473 : 0 : treq.cb = req->treq.cb;
474 : 0 : treq.cb_data = req->treq.cb_data;
475 : 0 : td_complete_request(treq, error);
476 : :
477 [ # # ]: 0 : if (!req->secs) {
478 : 0 : valve_free_request(valve, req);
479 : : }
480 : 0 : }
481 : :
482 : : static void
483 : 0 : valve_forward_stored_requests(td_valve_t *valve)
484 : : {
485 : : td_valve_request_t *req, *next;
486 : : td_request_t clone;
487 : : int err;
488 : :
489 [ # # ]: 0 : td_valve_for_each_stored_request(req, next, valve) {
490 : :
491 : 0 : err = valve_expend_request(valve, req->treq);
492 [ # # ]: 0 : if (err)
493 : : break;
494 : :
495 : 0 : clone = req->treq;
496 : 0 : clone.cb = __valve_complete_treq;
497 : 0 : clone.cb_data = req;
498 : :
499 : 0 : list_move(&req->entry, &valve->forw);
500 : : /* 'list_move' must be run before td_forward_request.
501 : : * 'req' may already be freed when td_forward_request returned.
502 : : */
503 : 0 : td_forward_request(clone);
504 : 0 : valve->stats.forw++;
505 : : }
506 : 0 : }
507 : :
508 : : static int
509 : 0 : valve_store_request(td_valve_t *valve, td_request_t treq)
510 : : {
511 : : td_valve_request_t *req;
512 : :
513 : 0 : req = valve_alloc_request(valve);
514 [ # # ]: 0 : if (!req)
515 : : return -EBUSY;
516 : :
517 : 0 : valve_conn_request(valve, TREQ_SIZE(treq));
518 : :
519 : 0 : req->treq = treq;
520 : 0 : req->secs = treq.secs;
521 : :
522 : 0 : list_add_tail(&req->entry, &valve->stor);
523 : 0 : valve->stats.stor++;
524 : :
525 : 0 : return 0;
526 : : }
527 : :
528 : : static void
529 : : valve_kill(td_valve_t *valve)
530 : : {
531 : 0 : valve->flags |= TD_VALVE_KILLED;
532 : 0 : valve_conn_close(valve, 1);
533 : : }
534 : :
535 : : static void
536 : 0 : valve_init(td_valve_t *valve, unsigned long flags)
537 : : {
538 : : int i;
539 : :
540 : : memset(valve, 0, sizeof(*valve));
541 : :
542 : 0 : INIT_LIST_HEAD(&valve->stor);
543 : 0 : INIT_LIST_HEAD(&valve->forw);
544 : :
545 : 0 : valve->sock = -1;
546 : 0 : valve->sock_id = -1;
547 : :
548 : 0 : valve->retry_id = -1;
549 : 0 : valve->sched_id = -1;
550 : :
551 : 0 : valve->flags = flags;
552 : :
553 [ # # ]: 0 : for (i = ARRAY_SIZE(valve->reqv) - 1; i >= 0; i--) {
554 : 0 : td_valve_request_t *req = &valve->reqv[i];
555 : :
556 : 0 : req->valve = valve;
557 : 0 : INIT_LIST_HEAD(&req->entry);
558 : :
559 : 0 : valve_free_request(valve, req);
560 : : }
561 : 0 : }
562 : :
563 : : static int
564 : 0 : td_valve_close(td_driver_t *driver)
565 : : {
566 : 0 : td_valve_t *valve = driver->data;
567 : :
568 [ # # ]: 0 : WARN_ON(!list_empty(&valve->stor));
569 [ # # ]: 0 : WARN_ON(!list_empty(&valve->forw));
570 : :
571 : 0 : valve_conn_close(valve, 0);
572 : :
573 [ # # ]: 0 : if (valve->brname) {
574 : 0 : free(valve->brname);
575 : 0 : valve->brname = NULL;
576 : : }
577 : :
578 : 0 : return 0;
579 : : }
580 : :
581 : : static int
582 : 0 : td_valve_open(td_driver_t *driver, const char *name,
583 : : struct td_vbd_encryption *encryption, td_flag_t flags)
584 : : {
585 : 0 : td_valve_t *valve = driver->data;
586 : : int err;
587 : :
588 : 0 : valve_init(valve, TD_VALVE_WRLIMIT);
589 : :
590 : 0 : valve->brname = strdup(name);
591 [ # # ]: 0 : if (!valve->brname) {
592 : 0 : err = -errno;
593 : : goto fail;
594 : : }
595 : :
596 : 0 : valve_conn_open(valve);
597 : :
598 : 0 : return 0;
599 : :
600 : : fail:
601 : 0 : td_valve_close(driver);
602 : 0 : return err;
603 : : }
604 : :
605 : : static void
606 : 0 : td_valve_queue_request(td_driver_t *driver, td_request_t treq)
607 : : {
608 : 0 : td_valve_t *valve = driver->data;
609 : : int err;
610 : :
611 [ # # # ]: 0 : switch (treq.op) {
612 : :
613 : : case TD_OP_READ:
614 [ # # ]: 0 : if (valve->flags & TD_VALVE_RDLIMIT)
615 : : break;
616 : :
617 : : goto forward;
618 : :
619 : : case TD_OP_WRITE:
620 [ # # ]: 0 : if (valve->flags & TD_VALVE_WRLIMIT)
621 : : break;
622 : :
623 : : goto forward;
624 : :
625 : : default:
626 : 0 : BUG();
627 : : }
628 : :
629 : 0 : err = valve_expend_request(valve, treq);
630 [ # # ]: 0 : if (!err)
631 : : goto forward;
632 : :
633 : 0 : err = valve_store_request(valve, treq);
634 [ # # ]: 0 : if (err)
635 : 0 : td_complete_request(treq, -EBUSY);
636 : :
637 : 0 : return;
638 : :
639 : : forward:
640 : 0 : td_forward_request(treq);
641 : 0 : valve->stats.forw++;
642 : : }
643 : :
644 : : static int
645 : 0 : td_valve_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
646 : : {
647 : 0 : return -EINVAL;
648 : : }
649 : :
650 : : static int
651 : 0 : td_valve_validate_parent(td_driver_t *driver,
652 : : td_driver_t *parent_driver, td_flag_t flags)
653 : : {
654 : 0 : return -EINVAL;
655 : : }
656 : :
657 : : static void
658 : 0 : td_valve_stats(td_driver_t *driver, td_stats_t *st)
659 : : {
660 : 0 : td_valve_t *valve = driver->data;
661 : : td_valve_request_t *req, *next;
662 : : int n_reqs;
663 : :
664 : 0 : tapdisk_stats_field(st, "bridge", "d", valve->brname);
665 : 0 : tapdisk_stats_field(st, "flags", "lu", valve->flags);
666 : :
667 : 0 : tapdisk_stats_field(st, "cred", "d", valve->cred);
668 : 0 : tapdisk_stats_field(st, "need", "d", valve->need);
669 : 0 : tapdisk_stats_field(st, "done", "d", valve->done);
670 : :
671 : : /*
672 : : * stored is [ waiting, total-waits ]
673 : : */
674 : :
675 : 0 : n_reqs = 0;
676 [ # # ]: 0 : td_valve_for_each_stored_request(req, next, valve)
677 : 0 : n_reqs++;
678 : :
679 : 0 : tapdisk_stats_field(st, "stor", "[");
680 : 0 : tapdisk_stats_val(st, "d", n_reqs);
681 : 0 : tapdisk_stats_val(st, "llu", valve->stats.stor);
682 : 0 : tapdisk_stats_leave(st, ']');
683 : :
684 : : /*
685 : : * forwarded is [ in-flight, total-requests ]
686 : : */
687 : :
688 : 0 : n_reqs = 0;
689 [ # # ]: 0 : td_valve_for_each_forwarded_request(req, next, valve)
690 : 0 : n_reqs++;
691 : :
692 : 0 : tapdisk_stats_field(st, "forw", "[");
693 : 0 : tapdisk_stats_val(st, "d", n_reqs);
694 : 0 : tapdisk_stats_val(st, "llu", valve->stats.forw);
695 : 0 : tapdisk_stats_leave(st, ']');
696 : 0 : }
697 : :
698 : : struct tap_disk tapdisk_valve = {
699 : : .disk_type = "tapdisk_valve",
700 : : .flags = 0,
701 : : .private_data_size = sizeof(td_valve_t),
702 : : .td_open = td_valve_open,
703 : : .td_close = td_valve_close,
704 : : .td_queue_read = td_valve_queue_request,
705 : : .td_queue_write = td_valve_queue_request,
706 : : .td_get_parent_id = td_valve_get_parent_id,
707 : : .td_validate_parent = td_valve_validate_parent,
708 : : .td_stats = td_valve_stats,
709 : : };
|