LCOV - code coverage report
Current view: top level - drivers - tapdisk-server.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 322 0.0 %
Date: 2024-06-19 15:27:45 Functions: 0 45 0.0 %
Branches: 0 146 0.0 %

           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                 :            : 

Generated by: LCOV version 1.13