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 <stdio.h>
36 : : #include <errno.h>
37 : : #include <unistd.h>
38 : : #include <stdlib.h>
39 : : #include <limits.h>
40 : : #include <time.h>
41 : : #include <sys/ioctl.h>
42 : : #include <sys/signal.h>
43 : : #ifdef HAVE_EVENTFD
44 : : #include <sys/eventfd.h>
45 : : #else
46 : : #include <sys/syscall.h>
47 : : #endif
48 : :
49 : : #include "tapdisk-syslog.h"
50 : : #include "tapdisk-server.h"
51 : : #include "tapdisk-driver.h"
52 : : #include "posixaio-backend.h"
53 : : #include "libaio-backend.h"
54 : : #include "tapdisk-interface.h"
55 : : #include "tapdisk-log.h"
56 : : #include "td-blkif.h"
57 : : #include "timeout-math.h"
58 : :
59 : : #include <sys/mman.h>
60 : : #include <sys/stat.h>
61 : : #include "../cpumond/cpumond.h"
62 : :
63 : : #define DBG(_level, _f, _a...) tlog_write(_level, _f, ##_a)
64 : : #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
65 : :
66 : : #define TAPDISK_TIOCBS (TAPDISK_DATA_REQUESTS + 50)
67 : :
68 : : typedef struct tapdisk_server {
69 : : int run;
70 : : struct list_head vbds;
71 : : scheduler_t scheduler;
72 : : tqueue rw_queue;
73 : : tqueue ro_queue;
74 : : struct backend *ro_backend;
75 : : struct backend *rw_backend;
76 : : char *name;
77 : : char *ident;
78 : : int facility;
79 : :
80 : : /* Memory mode state */
81 : : struct {
82 : : int wfd; /* event to watch for */
83 : : int efd; /* event fd */
84 : : int event_control; /* control fd */
85 : : event_id_t mem_evid; /* scheduler handle for
86 : : low mem and backoff
87 : : events */
88 : : event_id_t reset_evid; /* scheduler handle
89 : : for backoff reset
90 : : event */
91 : : enum memory_mode_t mode; /* memory mode */
92 : : int backoff; /* exponential backoff
93 : : factor */
94 : : } mem_state;
95 : :
96 : : /* CPU Utilisation Monitor client state */
97 : : struct {
98 : : int fd; /* shm fd */
99 : : cpumond_t *cpumon; /* mmap pointer */
100 : : } cpumond_state;
101 : :
102 : : event_id_t tlog_reopen_evid;
103 : : } tapdisk_server_t;
104 : :
105 : : static tapdisk_server_t server;
106 : :
107 : : unsigned int PAGE_SIZE;
108 : : unsigned int PAGE_MASK;
109 : : unsigned int PAGE_SHIFT;
110 : :
111 : : #define tapdisk_server_for_each_vbd(vbd, tmp) \
112 : : list_for_each_entry_safe(vbd, tmp, &server.vbds, next)
113 : :
114 : : td_image_t *
115 : 0 : tapdisk_server_get_shared_image(td_image_t *image)
116 : : {
117 : : td_vbd_t *vbd, *tmpv;
118 : : td_image_t *img, *tmpi;
119 : :
120 [ # # ]: 0 : if (!td_flag_test(image->flags, TD_OPEN_SHAREABLE))
121 : : return NULL;
122 : :
123 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmpv)
124 [ # # ]: 0 : tapdisk_vbd_for_each_image(vbd, img, tmpi)
125 [ # # ][ # # ]: 0 : if (img->type == image->type &&
126 : 0 : !strcmp(img->name, image->name))
127 : : return img;
128 : :
129 : : return NULL;
130 : : }
131 : :
132 : : struct list_head *
133 : 0 : tapdisk_server_get_all_vbds(void)
134 : : {
135 : 0 : return &server.vbds;
136 : : }
137 : :
138 : : td_vbd_t *
139 : 0 : tapdisk_server_get_vbd(uint16_t uuid)
140 : : {
141 : : td_vbd_t *vbd, *tmp;
142 : :
143 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
144 [ # # ]: 0 : if (vbd->uuid == uuid)
145 : : return vbd;
146 : :
147 : : return NULL;
148 : : }
149 : :
150 : : void
151 : 0 : tapdisk_server_add_vbd(td_vbd_t *vbd)
152 : : {
153 : 0 : list_add_tail(&vbd->next, &server.vbds);
154 : 0 : }
155 : :
156 : : void
157 : 0 : tapdisk_server_remove_vbd(td_vbd_t *vbd)
158 : : {
159 : 0 : list_del(&vbd->next);
160 : 0 : INIT_LIST_HEAD(&vbd->next);
161 : 0 : tapdisk_server_check_state();
162 : 0 : }
163 : :
164 : : void
165 : 0 : tapdisk_server_prep_tiocb(struct tiocb *tiocb, int fd, int rw, char *buf, size_t size,
166 : : long long offset, td_queue_callback_t cb, void *arg)
167 : : {
168 : 0 : server.rw_backend->prep(tiocb, fd, rw, buf, size, offset, cb, arg);
169 : 0 : }
170 : :
171 : : void
172 : 0 : tapdisk_server_queue_tiocb(struct tiocb *tiocb)
173 : : {
174 : 0 : server.rw_backend->queue(server.rw_queue, tiocb);
175 : 0 : }
176 : :
177 : : void
178 : 0 : tapdisk_server_prep_tiocb_ro(struct tiocb *tiocb, int fd, int rw, char *buf, size_t size,
179 : : long long offset, td_queue_callback_t cb, void *arg)
180 : : {
181 : 0 : server.ro_backend->prep(tiocb, fd, rw, buf, size, offset, cb, arg);
182 : 0 : }
183 : :
184 : : void
185 : 0 : tapdisk_server_queue_tiocb_ro(struct tiocb *tiocb)
186 : : {
187 : 0 : server.ro_backend->queue(server.ro_queue, tiocb);
188 : 0 : }
189 : :
190 : : void
191 : 0 : tapdisk_server_debug(void)
192 : : {
193 : : td_vbd_t *vbd, *tmp;
194 : :
195 [ # # ]: 0 : if (likely(server.rw_queue))
196 : 0 : server.rw_backend->debug(server.rw_queue);
197 [ # # ]: 0 : if (likely(server.ro_queue))
198 : 0 : server.ro_backend->debug(server.ro_queue);
199 : :
200 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
201 : 0 : tapdisk_vbd_debug(vbd);
202 : :
203 : 0 : DBG(TLOG_INFO, "debug log completed\n");
204 : 0 : tlog_precious(1);
205 : 0 : }
206 : :
207 : : void
208 : 0 : tapdisk_server_check_state(void)
209 : : {
210 [ # # ]: 0 : if (list_empty(&server.vbds))
211 : 0 : server.run = 0;
212 : 0 : }
213 : :
214 : : event_id_t
215 : 0 : tapdisk_server_register_event(char mode, int fd,
216 : : struct timeval timeout, event_cb_t cb, void *data)
217 : : {
218 : 0 : return scheduler_register_event(&server.scheduler,
219 : : mode, fd, timeout, cb, data);
220 : : }
221 : :
222 : : void
223 : 0 : tapdisk_server_unregister_event(event_id_t event)
224 : : {
225 : 0 : return scheduler_unregister_event(&server.scheduler, event);
226 : : }
227 : :
228 : : void
229 : 0 : tapdisk_server_mask_event(event_id_t event, int masked)
230 : : {
231 : 0 : return scheduler_mask_event(&server.scheduler, event, masked);
232 : : }
233 : :
234 : : void
235 : 0 : tapdisk_server_set_max_timeout(int seconds)
236 : : {
237 : 0 : scheduler_set_max_timeout(&server.scheduler, TV_SECS(seconds));
238 : 0 : }
239 : :
240 : : static void
241 : : tapdisk_server_assert_locks(void)
242 : : {
243 : :
244 : : }
245 : :
246 : : static void
247 : 0 : tapdisk_server_set_retry_timeout(void)
248 : : {
249 : : td_vbd_t *vbd, *tmp;
250 : :
251 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
252 [ # # ]: 0 : if (tapdisk_vbd_retry_needed(vbd)) {
253 : 0 : tapdisk_server_set_max_timeout(TD_VBD_RETRY_INTERVAL);
254 : 0 : return;
255 : : }
256 : : }
257 : :
258 : : static void
259 : 0 : tapdisk_server_check_progress(void)
260 : : {
261 : : struct timeval now;
262 : : td_vbd_t *vbd, *tmp;
263 : :
264 : 0 : gettimeofday(&now, NULL);
265 : :
266 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
267 : 0 : tapdisk_vbd_check_progress(vbd);
268 : 0 : }
269 : :
270 : : static void
271 : 0 : tapdisk_server_submit_tiocbs(void)
272 : : {
273 : 0 : server.rw_backend->submit_all(server.rw_queue);
274 : 0 : server.ro_backend->submit_all(server.ro_queue);
275 : 0 : }
276 : :
277 : : static void
278 : 0 : tapdisk_server_kick_responses(void)
279 : : {
280 : : td_vbd_t *vbd, *tmp;
281 : :
282 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
283 : 0 : tapdisk_vbd_kick(vbd);
284 : 0 : }
285 : :
286 : : static void
287 : 0 : tapdisk_server_check_vbds(void)
288 : : {
289 : : td_vbd_t *vbd, *tmp;
290 : :
291 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
292 : 0 : tapdisk_vbd_check_state(vbd);
293 : 0 : }
294 : :
295 : : /**
296 : : * Issues new requests. Returns the number of VBDs that contained new requests
297 : : * which have been issued.
298 : : */
299 : : static int
300 : 0 : tapdisk_server_recheck_vbds(void)
301 : : {
302 : : td_vbd_t *vbd, *tmp;
303 : 0 : int rv = 0;
304 : :
305 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
306 : 0 : rv += tapdisk_vbd_recheck_state(vbd);
307 : :
308 : 0 : return rv;
309 : : }
310 : :
311 : : static void
312 : 0 : tapdisk_server_stop_vbds(void)
313 : : {
314 : : td_vbd_t *vbd, *tmp;
315 : :
316 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
317 : 0 : tapdisk_vbd_kill_queue(vbd);
318 : 0 : }
319 : :
320 : : static int
321 : 0 : tapdisk_server_init_aio(void)
322 : : {
323 : : int err;
324 : 0 : err = server.ro_backend->init(&server.ro_queue, TAPDISK_TIOCBS,
325 : : TIO_DRV_LIO, NULL);
326 [ # # ]: 0 : if(err)
327 : : return err;
328 : :
329 : 0 : return server.rw_backend->init(&server.rw_queue, TAPDISK_TIOCBS,
330 : : TIO_DRV_LIO, NULL);
331 : : }
332 : :
333 : : static void
334 : : tapdisk_server_close_aio(void)
335 : : {
336 : 0 : server.rw_backend->free_queue(&server.rw_queue);
337 : 0 : server.ro_backend->free_queue(&server.ro_queue);
338 : : }
339 : :
340 : : int
341 : 0 : tapdisk_server_openlog(const char *name, int options, int facility)
342 : : {
343 : 0 : server.facility = facility;
344 : 0 : server.name = strdup(name);
345 : 0 : server.ident = tapdisk_syslog_ident(name);
346 : :
347 [ # # ][ # # ]: 0 : if (!server.name || !server.ident)
348 : 0 : return -errno;
349 : :
350 : 0 : openlog(server.ident, options, facility);
351 : :
352 : 0 : return 0;
353 : : }
354 : :
355 : : void
356 : 0 : tapdisk_server_closelog(void)
357 : : {
358 : 0 : closelog();
359 : :
360 : 0 : free(server.name);
361 : 0 : server.name = NULL;
362 : :
363 : 0 : free(server.ident);
364 : 0 : server.ident = NULL;
365 : 0 : }
366 : :
367 : : static int
368 : 0 : tapdisk_server_open_tlog(void)
369 : : {
370 : 0 : int err = 0;
371 : :
372 [ # # ]: 0 : if (server.name)
373 : 0 : err = tlog_open(server.name, server.facility, TLOG_WARN);
374 : :
375 : 0 : return err;
376 : : }
377 : :
378 : : static void
379 : : tapdisk_server_close_tlog(void)
380 : : {
381 : 0 : tlog_close();
382 : : }
383 : :
384 : : static void
385 : 0 : tapdisk_server_close(void)
386 : : {
387 [ # # ]: 0 : if (likely(server.tlog_reopen_evid >= 0))
388 : 0 : tapdisk_server_unregister_event(server.tlog_reopen_evid);
389 : :
390 : : tapdisk_server_close_tlog();
391 : : tapdisk_server_close_aio();
392 : 0 : }
393 : :
394 : : void
395 : 0 : tapdisk_server_iterate(void)
396 : : {
397 : : int ret;
398 : :
399 : : tapdisk_server_assert_locks();
400 : 0 : tapdisk_server_set_retry_timeout();
401 : 0 : tapdisk_server_check_progress();
402 : :
403 : 0 : ret = scheduler_wait_for_events(&server.scheduler);
404 [ # # ]: 0 : if (ret < 0)
405 : 0 : DBG(TLOG_WARN, "server wait returned %s\n", strerror(-ret));
406 : :
407 : 0 : tapdisk_server_check_vbds();
408 : : do {
409 : 0 : tapdisk_server_submit_tiocbs();
410 : 0 : tapdisk_server_kick_responses();
411 : :
412 : 0 : ret = tapdisk_server_recheck_vbds();
413 [ # # ]: 0 : } while (ret); /* repeat until there are no new requests to issue */
414 : 0 : }
415 : :
416 : : static void
417 : : __tapdisk_server_run(void)
418 : : {
419 [ # # ]: 0 : while (server.run)
420 : 0 : tapdisk_server_iterate();
421 : : }
422 : :
423 : : static void
424 : 0 : tapdisk_server_signal_handler(int signal)
425 : : {
426 : : td_vbd_t *vbd, *tmp;
427 : : struct td_xenblkif *blkif;
428 : : static int xfsz_error_sent = 0;
429 : :
430 [ # # # # : 0 : switch (signal) {
# # ]
431 : : case SIGBUS:
432 : : case SIGINT:
433 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
434 : 0 : tapdisk_vbd_close(vbd);
435 : : break;
436 : :
437 : : case SIGXFSZ:
438 : 0 : ERR(EFBIG, "received SIGXFSZ");
439 : 0 : tapdisk_server_stop_vbds();
440 [ # # ]: 0 : if (xfsz_error_sent)
441 : : break;
442 : :
443 : 0 : xfsz_error_sent = 1;
444 : 0 : break;
445 : :
446 : : case SIGUSR1:
447 : 0 : DBG(TLOG_INFO, "debugging on signal %d\n", signal);
448 : 0 : tapdisk_server_debug();
449 : 0 : break;
450 : :
451 : : case SIGUSR2:
452 : 0 : DBG(TLOG_INFO, "triggering polling on signal %d\n", signal);
453 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmp)
454 [ # # ]: 0 : list_for_each_entry(blkif, &vbd->rings, entry)
455 : 0 : tapdisk_start_polling(blkif);
456 : : break;
457 : :
458 : : case SIGHUP:
459 : 0 : tapdisk_server_event_set_timeout(server.tlog_reopen_evid, TV_ZERO);
460 : 0 : break;
461 : : }
462 : 0 : }
463 : :
464 : :
465 : : static void
466 : 0 : tlog_reopen_cb(event_id_t id, char mode __attribute__((unused)), void *private)
467 : : {
468 : 0 : tlog_reopen();
469 : 0 : tapdisk_server_event_set_timeout(id, TV_INF);
470 : 0 : }
471 : :
472 : :
473 : : /* Low memory algorithm:
474 : : * Register for low memory notifications from the kernel.
475 : : * If a low memory notification is received, deregister for the notification
476 : : * and go into low memory mode for an exponential backoff amount of time. When
477 : : * this time period has finished, return to normal memory mode and reregister
478 : : * for the low memory notification. Also set a timer to reset the backoff
479 : : * value after a certain amount of time in normal mode. If a low memory
480 : : * notification is received while the reset timer is running, cancel the reset
481 : : * timer.
482 : : *
483 : : * While perhaps a better alternative would be to remain subscribed to the
484 : : * notifications while in low memory mode and have an exponential backoff based
485 : : * on the notifications, these notifications can be frequent and bursty which
486 : : * is bad if there are a couple of thousand instances of tapdisk running.
487 : : */
488 : :
489 : : #ifndef HAVE_EVENTFD
490 : : int eventfd(unsigned int initval, int flags)
491 : : {
492 : : return syscall(SYS_eventfd2, initval, flags);
493 : : }
494 : : #endif
495 : :
496 : : #define MIN_BACKOFF 8
497 : : #define MAX_BACKOFF 512
498 : : #define RESET_BACKOFF 512
499 : :
500 : : #define MEMORY_PRESSURE_LEVEL "critical"
501 : : #define MEMORY_PRESSURE_PATH "/sys/fs/cgroup/memory/memory.pressure_level"
502 : : #define EVENT_CONTROL_PATH "/sys/fs/cgroup/memory/cgroup.event_control"
503 : :
504 : : static int tapdisk_server_reset_lowmem_mode(void);
505 : :
506 : : enum memory_mode_t
507 : 0 : tapdisk_server_mem_mode(void)
508 : : {
509 : 0 : return server.mem_state.mode;
510 : : }
511 : :
512 : : static void lowmem_state_init(void)
513 : : {
514 : 0 : server.mem_state.wfd = -1;
515 : 0 : server.mem_state.efd = -1;
516 : 0 : server.mem_state.event_control = -1;
517 : 0 : server.mem_state.mem_evid = -1;
518 : 0 : server.mem_state.reset_evid = -1;
519 : 0 : server.mem_state.backoff = MIN_BACKOFF;
520 : 0 : server.mem_state.mode = NORMAL_MEMORY_MODE;
521 : : }
522 : :
523 : 0 : static void lowmem_cleanup(void)
524 : : {
525 [ # # ]: 0 : if (server.mem_state.wfd >= 0)
526 : 0 : close(server.mem_state.wfd);
527 [ # # ]: 0 : if (server.mem_state.efd >= 0)
528 : 0 : close(server.mem_state.efd);
529 [ # # ]: 0 : if (server.mem_state.event_control >= 0)
530 : 0 : close(server.mem_state.event_control);
531 [ # # ]: 0 : if (server.mem_state.mem_evid >= 0)
532 : 0 : tapdisk_server_unregister_event(server.mem_state.mem_evid);
533 [ # # ]: 0 : if (server.mem_state.reset_evid >= 0)
534 : 0 : tapdisk_server_unregister_event(server.mem_state.reset_evid);
535 : :
536 : : lowmem_state_init();
537 : 0 : }
538 : :
539 : : /* Called when backoff period finishes */
540 : 0 : static void lowmem_timeout(event_id_t id, char mode, void *data)
541 : : {
542 : : int ret;
543 : : td_vbd_t *vbd, *tmpv;
544 : : struct td_xenblkif *blkif, *tmpb;
545 : :
546 : 0 : server.mem_state.mode = NORMAL_MEMORY_MODE;
547 : 0 : tapdisk_server_unregister_event(server.mem_state.mem_evid);
548 : 0 : server.mem_state.mem_evid = -1;
549 : :
550 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmpv)
551 [ # # ]: 0 : tapdisk_vbd_for_each_blkif(vbd, blkif, tmpb) {
552 [ # # ]: 0 : if (likely(blkif->stats.xenvbd))
553 : 0 : td_flag_clear(blkif->stats.xenvbd->flags, BT3_LOW_MEMORY_MODE);
554 [ # # ]: 0 : if (likely(blkif->vbd_stats.stats))
555 : 0 : td_flag_clear(blkif->vbd_stats.stats->flags, BT3_LOW_MEMORY_MODE);
556 : : }
557 : :
558 [ # # ]: 0 : if ((ret = tapdisk_server_reset_lowmem_mode()) < 0) {
559 : 0 : ERR(-ret, "Failed to re-init low memory handler: %s\n",
560 : : strerror(-ret));
561 : 0 : lowmem_cleanup();
562 : 0 : return;
563 : : }
564 : : }
565 : :
566 : : /* We received a low memory event. Switch into low memory mode. */
567 : 0 : static void lowmem_event(event_id_t id, char mode, void *data)
568 : : {
569 : : uint64_t result;
570 : : ssize_t n;
571 : : int backoff;
572 : :
573 : : td_vbd_t *vbd, *tmpv;
574 : : struct td_xenblkif *blkif, *tmpb;
575 : :
576 : 0 : n = read(server.mem_state.efd, &result, sizeof(result));
577 [ # # ]: 0 : if (n < 0) {
578 : 0 : ERR(-errno, "Failed to read from eventfd: %s\n",
579 : : strerror(-errno));
580 : 0 : lowmem_cleanup();
581 : 0 : return;
582 : : }
583 [ # # ]: 0 : if (n != sizeof(result)) {
584 : 0 : ERR(n,
585 : : "Failed to read from eventfd: short read\n");
586 : 0 : lowmem_cleanup();
587 : : return;
588 : : }
589 : :
590 : 0 : close(server.mem_state.efd);
591 : 0 : server.mem_state.efd = -1;
592 : 0 : tapdisk_server_unregister_event(server.mem_state.mem_evid);
593 : 0 : server.mem_state.mem_evid = -1;
594 : :
595 [ # # ]: 0 : if (server.mem_state.reset_evid != -1) {
596 : 0 : tapdisk_server_unregister_event(server.mem_state.reset_evid);
597 : 0 : server.mem_state.reset_evid = -1;
598 : : }
599 : :
600 : : /* Back off for a duration in the range n..(2n-1) */
601 : 0 : backoff = rand() % server.mem_state.backoff + server.mem_state.backoff;
602 : :
603 : 0 : server.mem_state.mem_evid =
604 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT,
605 : : -1,
606 : 0 : TV_SECS(backoff),
607 : : lowmem_timeout,
608 : : NULL);
609 [ # # ]: 0 : if (server.mem_state.mem_evid < 0) {
610 : 0 : ERR(-server.mem_state.mem_evid,
611 : : "Failed to initialize backoff: %s\n",
612 : : strerror(-server.mem_state.mem_evid));
613 : 0 : lowmem_cleanup();
614 : : return;
615 : : }
616 : 0 : server.mem_state.mode = LOW_MEMORY_MODE;
617 : :
618 [ # # ]: 0 : tapdisk_server_for_each_vbd(vbd, tmpv)
619 [ # # ]: 0 : tapdisk_vbd_for_each_blkif(vbd, blkif, tmpb) {
620 [ # # ]: 0 : if (likely(blkif->stats.xenvbd))
621 : 0 : td_flag_set(blkif->stats.xenvbd->flags, BT3_LOW_MEMORY_MODE);
622 [ # # ]: 0 : if (likely(blkif->vbd_stats.stats))
623 : 0 : td_flag_set(blkif->vbd_stats.stats->flags, BT3_LOW_MEMORY_MODE);
624 : : }
625 : :
626 : : /* Increment backoff up to a limit */
627 [ # # ]: 0 : if (server.mem_state.backoff < MAX_BACKOFF)
628 : 0 : server.mem_state.backoff *= 2;
629 : : }
630 : :
631 : : /* If a low memory event isn't received for RESET_BACKOFF seconds, reset the
632 : : * backoff
633 : : */
634 : 0 : static void reset_timeout(event_id_t id, char mode, void *data)
635 : : {
636 : 0 : server.mem_state.backoff = MIN_BACKOFF;
637 : 0 : tapdisk_server_unregister_event(server.mem_state.reset_evid);
638 : 0 : server.mem_state.reset_evid = -1;
639 : 0 : }
640 : :
641 : : /* Register for low memory notifications. Register a timer to reset the
642 : : * exponential backoff if necessary.
643 : : */
644 : : static int
645 : 0 : tapdisk_server_reset_lowmem_mode(void)
646 : : {
647 : : int ret;
648 : : char line[LINE_MAX];
649 : :
650 : 0 : server.mem_state.efd = eventfd(0, 0);
651 [ # # ]: 0 : if (server.mem_state.efd == -1)
652 : 0 : return -errno;
653 : :
654 : 0 : ret = snprintf(line, LINE_MAX, "%d %d " MEMORY_PRESSURE_LEVEL,
655 : : server.mem_state.efd, server.mem_state.wfd);
656 [ # # ]: 0 : if (ret >= LINE_MAX || ret < 0)
657 : : return -EINVAL;
658 : :
659 [ # # ]: 0 : if (write(server.mem_state.event_control, line, ret) == -1)
660 : 0 : return -errno;
661 : :
662 : 0 : server.mem_state.mem_evid =
663 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
664 : : server.mem_state.efd,
665 : 0 : TV_ZERO,
666 : : lowmem_event,
667 : : NULL);
668 [ # # ]: 0 : if (server.mem_state.mem_evid < 0)
669 : : return server.mem_state.mem_evid;
670 : :
671 [ # # ]: 0 : if (server.mem_state.backoff != MIN_BACKOFF) {
672 : : /* Start a timeout to reset the exponential backoff */
673 : 0 : server.mem_state.reset_evid =
674 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT,
675 : : -1,
676 : 0 : TV_SECS(RESET_BACKOFF),
677 : : reset_timeout,
678 : : NULL);
679 [ # # ]: 0 : if (server.mem_state.reset_evid < 0)
680 : 0 : return server.mem_state.reset_evid;
681 : : }
682 : :
683 : : return 0;
684 : : }
685 : :
686 : : /* Once-off initialization */
687 : : static int
688 : 0 : tapdisk_server_initialize_lowmem_mode(void)
689 : : {
690 : : lowmem_state_init();
691 : :
692 : 0 : srand(time(NULL));
693 : :
694 : 0 : server.mem_state.wfd =
695 : : open(MEMORY_PRESSURE_PATH, O_RDONLY);
696 [ # # ]: 0 : if (server.mem_state.wfd == -1)
697 : 0 : return -errno;
698 : :
699 : 0 : server.mem_state.event_control = open(EVENT_CONTROL_PATH, O_WRONLY);
700 [ # # ]: 0 : if (server.mem_state.event_control == -1)
701 : 0 : return -errno;
702 : :
703 : 0 : return tapdisk_server_reset_lowmem_mode();
704 : : }
705 : :
706 : : static void cpumond_state_init(void)
707 : : {
708 : 0 : server.cpumond_state.fd = -1;
709 : 0 : server.cpumond_state.cpumon = (cpumond_t *) 0;
710 : : }
711 : :
712 : 0 : static void cpumond_cleanup(void)
713 : : {
714 [ # # ]: 0 : if (server.cpumond_state.cpumon)
715 : 0 : munmap(server.cpumond_state.cpumon, sizeof(cpumond_t));
716 [ # # ]: 0 : if (server.cpumond_state.fd >= 0)
717 : 0 : close(server.cpumond_state.fd);
718 : :
719 : : cpumond_state_init();
720 : 0 : }
721 : :
722 : : float
723 : 0 : tapdisk_server_system_idle_cpu(void)
724 : : {
725 [ # # ]: 0 : if (server.cpumond_state.cpumon > 0)
726 : 0 : return server.cpumond_state.cpumon->idle;
727 : : else
728 : : return 0.0;
729 : : }
730 : :
731 : : /* Create the CPU Utilisation Monitor client. */
732 : : static int
733 : 0 : tapdisk_server_initialize_cpumond_client(void)
734 : : {
735 : 0 : server.cpumond_state.fd = shm_open(CPUMOND_PATH, O_RDONLY, 0);
736 [ # # ]: 0 : if (server.cpumond_state.fd == -1)
737 : 0 : return -errno;
738 : :
739 : 0 : server.cpumond_state.cpumon = mmap(NULL, sizeof(cpumond_t), PROT_READ, MAP_PRIVATE, server.cpumond_state.fd, 0);
740 [ # # ]: 0 : if (server.cpumond_state.cpumon == (cpumond_t *) -1) {
741 : 0 : server.cpumond_state.cpumon = 0;
742 : 0 : return -errno;
743 : : }
744 : :
745 : : return 0;
746 : : }
747 : :
748 : : int
749 : 0 : tapdisk_server_init(void)
750 : : {
751 : : int ret;
752 : 0 : unsigned int i = 0;
753 : :
754 : 0 : PAGE_SIZE = sysconf(_SC_PAGESIZE);
755 : 0 : PAGE_MASK = ~(PAGE_SIZE - 1);
756 : :
757 [ # # ]: 0 : for (i = PAGE_SIZE, PAGE_SHIFT = 0; i > 1; i >>= 1, PAGE_SHIFT++);
758 : :
759 : : memset(&server, 0, sizeof(server));
760 : : INIT_LIST_HEAD(&server.vbds);
761 : :
762 : 0 : scheduler_initialize(&server.scheduler);
763 : :
764 [ # # ]: 0 : if ((ret = tapdisk_server_initialize_lowmem_mode()) < 0) {
765 : 0 : EPRINTF("Failed to initialize low memory handler: %s\n",
766 : : strerror(-ret));
767 : 0 : lowmem_cleanup();
768 : 0 : goto out;
769 : : }
770 : :
771 [ # # ]: 0 : if ((ret = tapdisk_server_initialize_cpumond_client()) < 0) {
772 : 0 : EPRINTF("Failed to connect to cpumond: %s\n",
773 : : strerror(-ret));
774 : 0 : cpumond_cleanup();
775 : 0 : goto out;
776 : : }
777 : :
778 : : out:
779 : 0 : server.tlog_reopen_evid = -1;
780 : :
781 : 0 : return 0;
782 : : }
783 : :
784 : : int
785 : 0 : tapdisk_server_complete(void)
786 : : {
787 : : int err;
788 : 0 : server.rw_backend = get_libaio_backend();
789 : 0 : server.ro_backend = get_libaio_backend();
790 : :
791 : 0 : server.rw_backend = get_libaio_backend();
792 : 0 : err = tapdisk_server_init_aio();
793 [ # # ]: 0 : if (err)
794 : : goto fail;
795 : :
796 : 0 : err = tapdisk_server_open_tlog();
797 [ # # ]: 0 : if (err)
798 : : goto fail;
799 : :
800 : 0 : server.run = 1;
801 : :
802 : 0 : return 0;
803 : :
804 : : fail:
805 : : tapdisk_server_close_tlog();
806 : : tapdisk_server_close_aio();
807 : 0 : return err;
808 : : }
809 : :
810 : : int
811 : 0 : tapdisk_server_initialize(const char *read, const char *write)
812 : : {
813 : : int err;
814 : :
815 : 0 : tapdisk_server_init();
816 : :
817 : 0 : err = tapdisk_server_complete();
818 [ # # ]: 0 : if (err)
819 : : goto fail;
820 : :
821 : : return 0;
822 : :
823 : : fail:
824 : 0 : tapdisk_server_close();
825 : 0 : return err;
826 : : }
827 : :
828 : : int
829 : 0 : tapdisk_server_run()
830 : : {
831 : : int err;
832 : :
833 : 0 : err = tapdisk_set_resource_limits();
834 [ # # ]: 0 : if (err)
835 : : return err;
836 : :
837 : 0 : signal(SIGBUS, tapdisk_server_signal_handler);
838 : 0 : signal(SIGINT, tapdisk_server_signal_handler);
839 : 0 : signal(SIGUSR1, tapdisk_server_signal_handler);
840 : 0 : signal(SIGUSR2, tapdisk_server_signal_handler);
841 : 0 : signal(SIGHUP, tapdisk_server_signal_handler);
842 : 0 : signal(SIGXFSZ, tapdisk_server_signal_handler);
843 : :
844 : 0 : err = tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT, -1, TV_INF,
845 : : tlog_reopen_cb, NULL);
846 [ # # ]: 0 : if (unlikely(err < 0)) {
847 : 0 : EPRINTF("failed to register reopen log event: %s\n", strerror(-err));
848 : : goto out;
849 : : }
850 : :
851 : 0 : server.tlog_reopen_evid = err;
852 : :
853 : 0 : err = 0;
854 : :
855 : : __tapdisk_server_run();
856 : :
857 : : out:
858 : 0 : tapdisk_server_close();
859 : :
860 : 0 : return err;
861 : : }
862 : :
863 : : int
864 : 0 : tapdisk_server_event_set_timeout(event_id_t event_id, struct timeval timeo) {
865 : 0 : return scheduler_event_set_timeout(&server.scheduler, event_id, timeo);
866 : : }
867 : :
|