LCOV - code coverage report
Current view: top level - drivers - td-blkif.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 307 0.0 %
Date: 2025-01-09 17:56:42 Functions: 0 21 0.0 %
Branches: 0 364 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                 :            : #include <stdlib.h>
      32                 :            : #include <errno.h>
      33                 :            : #include <sys/mman.h>
      34                 :            : #include <unistd.h>
      35                 :            : #include <stdio.h>
      36                 :            : #include <libgen.h>
      37                 :            : #include <zlib.h>
      38                 :            : 
      39                 :            : #include "blktap-xenif.h"
      40                 :            : #include "debug.h"
      41                 :            : #include "blktap3.h"
      42                 :            : #include "tapdisk.h"
      43                 :            : #include "tapdisk-log.h"
      44                 :            : #include "util.h"
      45                 :            : #include "tapdisk-server.h"
      46                 :            : #include "tapdisk-metrics.h"
      47                 :            : #include "timeout-math.h"
      48                 :            : 
      49                 :            : #include "td-blkif.h"
      50                 :            : #include "td-ctx.h"
      51                 :            : #include "td-req.h"
      52                 :            : 
      53                 :            : struct td_xenblkif *
      54                 :          0 : tapdisk_xenblkif_find(const domid_t domid, const int devid)
      55                 :            : {
      56                 :          0 :     struct td_xenblkif *blkif = NULL;
      57                 :            :     struct td_xenio_ctx *ctx;
      58                 :            : 
      59         [ #  # ]:          0 :     tapdisk_xenio_for_each_ctx(ctx) {
      60 [ #  # ][ #  # ]:          0 :         tapdisk_xenio_ctx_find_blkif(ctx, blkif,
         [ #  # ][ #  # ]
                 [ #  # ]
      61                 :            :                                      blkif->domid == domid &&
      62                 :            :                                      blkif->devid == devid);
      63         [ #  # ]:          0 :         if (blkif)
      64                 :            :             return blkif;
      65                 :            :     }
      66                 :            : 
      67                 :            :     return NULL;
      68                 :            : }
      69                 :            : 
      70                 :            : 
      71                 :            : /**
      72                 :            :  * Returns 0 on success, -errno on failure.
      73                 :            :  */
      74                 :            : static int
      75                 :          0 : tapdisk_xenblkif_stats_destroy(struct td_xenblkif *blkif)
      76                 :            : {
      77                 :            :     int err;
      78                 :            : 
      79                 :          0 :     err = shm_destroy(&blkif->xenvbd_stats.io_ring);
      80         [ #  # ]:          0 :     if (unlikely(err))
      81                 :            :         goto out;
      82                 :          0 :     free(blkif->xenvbd_stats.io_ring.path);
      83                 :          0 :     blkif->xenvbd_stats.io_ring.path = NULL;
      84                 :            : 
      85                 :            :         /*
      86                 :            :          * blkif->stats.xenvbd was initialised to blkif->xenvbd_stats.stats.mem
      87                 :            :          * in tapdisk_xenblkif_stats_create(). That address will be unmapped
      88                 :            :          * by the call to shm_destroy(), and an error return does not mean it
      89                 :            :          * wasn't, so we must unconditionally NULL blkif->stats.xenvbd here.
      90                 :            :          */
      91                 :          0 :         blkif->stats.xenvbd = NULL;
      92                 :          0 :     err = shm_destroy(&blkif->xenvbd_stats.stats);
      93         [ #  # ]:          0 :     if (unlikely(err))
      94                 :            :         goto out;
      95                 :          0 :     free(blkif->xenvbd_stats.stats.path);
      96                 :          0 :     blkif->xenvbd_stats.stats.path = NULL;
      97                 :            : 
      98         [ #  # ]:          0 :     if (likely(blkif->xenvbd_stats.root)) {
      99                 :          0 :         err = rmdir(blkif->xenvbd_stats.root);
     100 [ #  # ][ #  # ]:          0 :         if (unlikely(err && errno != ENOENT)) {
     101                 :          0 :             err = errno;
     102                 :          0 :             EPRINTF("failed to remove %s: %s\n",
     103                 :            :                     blkif->xenvbd_stats.root, strerror(err));
     104                 :            :             goto out;
     105                 :            :         }
     106                 :          0 :         err = 0;
     107                 :            : 
     108                 :          0 :         free(blkif->xenvbd_stats.root);
     109                 :          0 :         blkif->xenvbd_stats.root = NULL;
     110                 :            :     }
     111                 :            : out:
     112                 :          0 :     return -err;
     113                 :            : }
     114                 :            : 
     115                 :            : 
     116                 :            : /*
     117                 :            :  * TODO provide ring stats in raw format (the same way I/O stats are provided).
     118                 :            :  * xen-ringwatch will have to be modified accordingly.
     119                 :            :  */
     120                 :            : static int
     121                 :          0 : tapdisk_xenblkif_stats_create(struct td_xenblkif *blkif)
     122                 :            : {
     123                 :          0 :     int err = 0, len;
     124                 :          0 :     char *_path = NULL;
     125                 :            : 
     126                 :          0 :     len = asprintf(&blkif->xenvbd_stats.root, "/dev/shm/vbd3-%d-%d",
     127                 :            :             blkif->domid, blkif->devid);
     128         [ #  # ]:          0 :     if (unlikely(len == -1)) {
     129                 :          0 :         err = errno;
     130                 :          0 :         blkif->xenvbd_stats.root = NULL;
     131                 :          0 :         goto out;
     132                 :            :     }
     133                 :            : 
     134                 :          0 :         err = mkdir(blkif->xenvbd_stats.root, S_IRUSR | S_IWUSR);
     135         [ #  # ]:          0 :         if (unlikely(err)) {
     136                 :          0 :         err = errno;
     137         [ #  # ]:          0 :         if (err != EEXIST) {
     138                 :          0 :             EPRINTF("failed to create %s: %s\n",
     139                 :            :                     blkif->xenvbd_stats.root, strerror(err));
     140                 :            :                 goto out;
     141                 :            :         }
     142                 :            :         err = 0;
     143                 :            :     }
     144                 :            : 
     145                 :          0 :     len = asprintf(&blkif->xenvbd_stats.io_ring.path, "%s/io_ring~",
     146                 :            :             blkif->xenvbd_stats.root);
     147         [ #  # ]:          0 :     if (unlikely(len == -1)) {
     148                 :          0 :         err = errno;
     149                 :          0 :         blkif->xenvbd_stats.io_ring.path = NULL;
     150                 :          0 :         goto out;
     151                 :            :     }
     152                 :          0 :     blkif->xenvbd_stats.io_ring.size = PAGE_SIZE;
     153                 :          0 :     err = shm_create(&blkif->xenvbd_stats.io_ring);
     154         [ #  # ]:          0 :     if (unlikely(err)) {
     155                 :          0 :         err = errno;
     156                 :          0 :         EPRINTF("failed to create shm ring stats file: %s\n", strerror(err));
     157                 :            :         goto out;
     158                 :            :    }
     159                 :            : 
     160                 :          0 :     err = asprintf(&blkif->xenvbd_stats.stats.path, "%s/statistics",
     161                 :            :             blkif->xenvbd_stats.root);
     162         [ #  # ]:          0 :     if (unlikely(err == -1)) {
     163                 :          0 :         err = errno;
     164                 :          0 :         blkif->xenvbd_stats.stats.path = NULL;
     165                 :          0 :         goto out;
     166                 :            :     }
     167                 :          0 :     blkif->xenvbd_stats.stats.size = PAGE_SIZE;
     168                 :          0 :     err = shm_create(&blkif->xenvbd_stats.stats);
     169         [ #  # ]:          0 :     if (unlikely(err))
     170                 :            :         goto out;
     171                 :            : 
     172                 :          0 :     blkif->xenvbd_stats.last = 0;
     173                 :            : 
     174                 :          0 :         blkif->stats.xenvbd = blkif->xenvbd_stats.stats.mem;
     175                 :            : 
     176         [ #  # ]:          0 :     if (tapdisk_server_mem_mode()) {
     177                 :          0 :         td_flag_set(blkif->stats.xenvbd->flags, BT3_LOW_MEMORY_MODE);
     178                 :          0 :         td_flag_set(blkif->vbd_stats.stats->flags, BT3_LOW_MEMORY_MODE);
     179                 :            :     }
     180                 :            : 
     181                 :          0 :     err = tapdisk_xenblkif_ring_stats_update(blkif);
     182         [ #  # ]:          0 :     if (unlikely(err)) {
     183                 :          0 :         EPRINTF("failed to generate shared I/O ring stats: %s\n",
     184                 :            :                 strerror(-err));
     185                 :            :         goto out;
     186                 :            :     }
     187                 :            : 
     188                 :          0 :     _path = strndup(blkif->xenvbd_stats.io_ring.path, len - 1);
     189         [ #  # ]:          0 :     if (unlikely(!_path)) {
     190                 :          0 :         err = errno;
     191                 :          0 :         goto out;
     192                 :            :     }
     193                 :            : 
     194                 :          0 :     err = rename(blkif->xenvbd_stats.io_ring.path, _path);
     195         [ #  # ]:          0 :     if (unlikely(err)) {
     196                 :          0 :         err = errno;
     197                 :          0 :         goto out;
     198                 :            :     }
     199                 :            : 
     200                 :          0 :     free(blkif->xenvbd_stats.io_ring.path);
     201                 :          0 :     blkif->xenvbd_stats.io_ring.path = _path;
     202                 :          0 :     _path = NULL;
     203                 :            : out:
     204                 :          0 :     free(_path);
     205         [ #  # ]:          0 :     if (err) {
     206                 :          0 :         int err2 = tapdisk_xenblkif_stats_destroy(blkif);
     207         [ #  # ]:          0 :         if (err2)
     208                 :          0 :             EPRINTF("failed to clean up failed stats file: "
     209                 :            :                     "%s (error ignored)\n", strerror(-err2));
     210                 :            :     }
     211                 :          0 :     return -err;
     212                 :            : }
     213                 :            : 
     214                 :            : 
     215                 :            : int
     216                 :          0 : tapdisk_xenblkif_destroy(struct td_xenblkif * blkif)
     217                 :            : {
     218                 :            :     int err;
     219                 :            : 
     220         [ #  # ]:          0 :     ASSERT(blkif);
     221                 :            : 
     222         [ #  # ]:          0 :     if (tapdisk_xenblkif_chkrng_event_id(blkif) >= 0) {
     223                 :          0 :         tapdisk_server_unregister_event(
     224                 :            :                                 tapdisk_xenblkif_chkrng_event_id(blkif));
     225                 :          0 :         blkif->chkrng_event = -1;
     226                 :            :     }
     227                 :            : 
     228         [ #  # ]:          0 :     if (tapdisk_xenblkif_stoppolling_event_id(blkif) >= 0) {
     229                 :          0 :         tapdisk_server_unregister_event(
     230                 :            :                                 tapdisk_xenblkif_stoppolling_event_id(blkif));
     231                 :          0 :         blkif->stoppolling_event = -1;
     232                 :            :     }
     233                 :            : 
     234                 :          0 :     tapdisk_xenblkif_reqs_free(blkif);
     235                 :            : 
     236         [ #  # ]:          0 :     if (blkif->ctx) {
     237         [ #  # ]:          0 :         if (blkif->port >= 0)
     238                 :          0 :             xenevtchn_unbind(blkif->ctx->xce_handle, blkif->port);
     239                 :            : 
     240         [ #  # ]:          0 :         if (blkif->rings.common.sring) {
     241                 :          0 :             err = xengnttab_unmap(blkif->ctx->xcg_handle,
     242                 :            :                                         blkif->rings.common.sring, blkif->ring_n_pages);
     243         [ #  # ]:          0 :                         if (unlikely(err)) {
     244                 :          0 :                                 err = errno;
     245                 :          0 :                                 EPRINTF("failed to unmap ring page %p (%d pages): %s "
     246                 :            :                                                 "(error ignored)\n",
     247                 :            :                                                 blkif->rings.common.sring, blkif->ring_n_pages,
     248                 :            :                                                 strerror(err));
     249                 :          0 :                                 err = 0;
     250                 :            :                         }
     251                 :            :                 }
     252                 :            : 
     253                 :          0 :                 list_del(&blkif->entry_ctx);
     254                 :          0 :         list_del(&blkif->entry);
     255                 :          0 :         tapdisk_xenio_ctx_put(blkif->ctx);
     256                 :            :     }
     257                 :          0 :     err = td_metrics_vbd_stop(&blkif->vbd_stats);
     258         [ #  # ]:          0 :     if (unlikely(err))
     259                 :          0 :         EPRINTF("failed to destroy blkfront stats file: %s\n", strerror(-err));
     260                 :            : 
     261                 :          0 :     err = tapdisk_xenblkif_stats_destroy(blkif);
     262         [ #  # ]:          0 :     if (unlikely(err)) {
     263                 :          0 :         EPRINTF("failed to clean up ring stats file: %s (error ignored)\n",
     264                 :            :                 strerror(-err));
     265                 :          0 :         err = 0;
     266                 :            :     }
     267                 :            : 
     268                 :          0 :     free(blkif);
     269                 :            : 
     270                 :          0 :     return err;
     271                 :            : }
     272                 :            : 
     273                 :            : 
     274                 :            : int
     275                 :          0 : tapdisk_xenblkif_reqs_pending(const struct td_xenblkif * const blkif)
     276                 :            : {
     277         [ #  # ]:          0 :         ASSERT(blkif);
     278                 :            : 
     279                 :          0 :         return blkif->ring_size - blkif->n_reqs_free;
     280                 :            : }
     281                 :            : 
     282                 :            : 
     283                 :            : int
     284                 :          0 : tapdisk_xenblkif_disconnect(const domid_t domid, const int devid)
     285                 :            : {
     286                 :            :     int err;
     287                 :            :     struct td_xenblkif *blkif;
     288                 :            : 
     289                 :          0 :     blkif = tapdisk_xenblkif_find(domid, devid);
     290         [ #  # ]:          0 :     if (!blkif)
     291                 :            :         return -ENODEV;
     292                 :            : 
     293         [ #  # ]:          0 :     if (tapdisk_xenblkif_reqs_pending(blkif)) {
     294                 :          0 :         RING_DEBUG(blkif, "disconnect from ring with %d pending requests\n",
     295                 :            :                 blkif->ring_size - blkif->n_reqs_free);
     296         [ #  # ]:          0 :                 if (td_flag_test(blkif->vbd->state, TD_VBD_PAUSED))
     297                 :          0 :                         RING_ERR(blkif, "disconnect from ring with %d pending requests "
     298                 :            :                     "and the VBD paused\n",
     299                 :            :                     blkif->ring_size - blkif->n_reqs_free);
     300                 :          0 :         list_move(&blkif->entry, &blkif->vbd->dead_rings);
     301                 :          0 :         blkif->dead = true;
     302 [ #  # ][ #  # ]:          0 :         if (blkif->ctx && blkif->port >= 0) {
     303                 :          0 :             xenevtchn_unbind(blkif->ctx->xce_handle, blkif->port);
     304                 :          0 :             blkif->port = -1;
     305                 :            :         }
     306                 :            : 
     307                 :          0 :         err = td_metrics_vbd_stop(&blkif->vbd_stats);
     308         [ #  # ]:          0 :         if (unlikely(err))
     309                 :          0 :             EPRINTF("failed to destroy blkfront stats file: %s\n", strerror(-err));
     310                 :            : 
     311                 :          0 :         err = tapdisk_xenblkif_stats_destroy(blkif);
     312         [ #  # ]:          0 :         if (unlikely(err))
     313                 :          0 :             EPRINTF("failed to clean up ring stats file: %s (error ignored)\n",
     314                 :            :                     strerror(-err));
     315                 :            : 
     316                 :            :         /*
     317                 :            :          * FIXME shall we unmap the ring or will that lead to some fatal error
     318                 :            :          * in tapdisk? IIUC if we don't unmap it we'll get errors during grant
     319                 :            :          * copy.
     320                 :            :          */
     321                 :            :         return 0;
     322                 :            :         } else
     323                 :          0 :         return tapdisk_xenblkif_destroy(blkif);
     324                 :            : }
     325                 :            : 
     326                 :            : 
     327                 :            : void
     328                 :          0 : tapdisk_xenblkif_sched_stoppolling(const struct td_xenblkif *blkif)
     329                 :            : {
     330                 :            :         int err;
     331                 :            : 
     332         [ #  # ]:          0 :         ASSERT(blkif);
     333                 :            : 
     334                 :          0 :         err = tapdisk_server_event_set_timeout(
     335                 :          0 :                 tapdisk_xenblkif_stoppolling_event_id(blkif), TV_USECS(blkif->poll_duration));
     336         [ #  # ]:          0 :         ASSERT(!err);
     337                 :          0 : }
     338                 :            : 
     339                 :            : void
     340                 :          0 : tapdisk_xenblkif_unsched_stoppolling(const struct td_xenblkif *blkif)
     341                 :            : {
     342                 :            :         int err;
     343                 :            : 
     344         [ #  # ]:          0 :         ASSERT(blkif);
     345                 :            : 
     346                 :          0 :         err = tapdisk_server_event_set_timeout(
     347                 :          0 :                 tapdisk_xenblkif_stoppolling_event_id(blkif), TV_INF);
     348         [ #  # ]:          0 :         ASSERT(!err);
     349                 :          0 : }
     350                 :            : 
     351                 :            : 
     352                 :            : void
     353                 :          0 : tapdisk_start_polling(struct td_xenblkif *blkif)
     354                 :            : {
     355         [ #  # ]:          0 :     ASSERT(blkif);
     356                 :            : 
     357                 :            :     /* Only enter polling if the CPU utilisation is not too high */
     358         [ #  # ]:          0 :     if (tapdisk_server_system_idle_cpu() > (float)blkif->poll_idle_threshold) {
     359                 :          0 :         blkif->in_polling = true;
     360                 :            : 
     361                 :            :         /* Start checking the ring immediately */
     362                 :          0 :         tapdisk_xenblkif_sched_chkrng(blkif);
     363                 :            : 
     364                 :            :         /* Schedule the future 'stop polling' event */
     365                 :          0 :         tapdisk_xenblkif_sched_stoppolling(blkif);
     366                 :            : 
     367                 :          0 :         tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 1);
     368                 :            :     }
     369                 :          0 : }
     370                 :            : 
     371                 :            : static inline void
     372                 :          0 : tapdisk_xenblkif_cb_stoppolling(event_id_t id __attribute__((unused)),
     373                 :            :         char mode __attribute__((unused)), void *private)
     374                 :            : {
     375                 :          0 :     struct td_xenblkif *blkif = private;
     376                 :            : 
     377         [ #  # ]:          0 :     ASSERT(blkif);
     378                 :            : 
     379                 :            :     /* Process the ring one final time, setting the event counter */
     380         [ #  # ]:          0 :     if (!tapdisk_xenio_ctx_process_ring(blkif, blkif->ctx, 1)) {
     381                 :            :         /* If there were no new requests this time, then stop polling */
     382                 :          0 :         blkif->in_polling = false;
     383                 :            : 
     384                 :            :         /* Stop obsessively checking the ring */
     385                 :          0 :         tapdisk_xenblkif_unsched_chkrng(blkif);
     386                 :            : 
     387                 :            :         /* Make the 'stop polling' event not fire again */
     388                 :          0 :         tapdisk_xenblkif_unsched_stoppolling(blkif);
     389                 :            : 
     390                 :          0 :         tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 0);
     391                 :            :     }
     392                 :          0 : }
     393                 :            : 
     394                 :            : void
     395                 :          0 : tapdisk_xenblkif_sched_chkrng(const struct td_xenblkif *blkif)
     396                 :            : {
     397                 :            :         int err;
     398                 :            : 
     399         [ #  # ]:          0 :         ASSERT(blkif);
     400                 :            : 
     401                 :          0 :         err = tapdisk_server_event_set_timeout(
     402                 :          0 :                         tapdisk_xenblkif_chkrng_event_id(blkif), TV_ZERO);
     403         [ #  # ]:          0 :         ASSERT(!err);
     404                 :          0 : }
     405                 :            : 
     406                 :            : void
     407                 :          0 : tapdisk_xenblkif_unsched_chkrng(const struct td_xenblkif *blkif)
     408                 :            : {
     409                 :            :         int err;
     410                 :            : 
     411         [ #  # ]:          0 :         ASSERT(blkif);
     412                 :            : 
     413                 :          0 :         err = tapdisk_server_event_set_timeout(
     414                 :          0 :                         tapdisk_xenblkif_chkrng_event_id(blkif), TV_INF);
     415         [ #  # ]:          0 :         ASSERT(!err);
     416                 :          0 : }
     417                 :            : 
     418                 :            : static inline void
     419                 :          0 : tapdisk_xenblkif_cb_chkrng(event_id_t id __attribute__((unused)),
     420                 :            :         char mode __attribute__((unused)), void *private)
     421                 :            : {
     422                 :          0 :     struct td_xenblkif *blkif = private;
     423                 :            : 
     424         [ #  # ]:          0 :     ASSERT(blkif);
     425                 :            : 
     426                 :            :     /*
     427                 :            :      * If we are polling, process the ring without setting the event counter.
     428                 :            :      * If we are not polling, unschedule this event, process the ring and set
     429                 :            :      * the event counter.
     430                 :            :      */
     431                 :            : 
     432         [ #  # ]:          0 :     if (!blkif->in_polling)
     433                 :          0 :         tapdisk_xenblkif_unsched_chkrng(blkif);
     434                 :            : 
     435                 :          0 :     tapdisk_xenio_ctx_process_ring(blkif, blkif->ctx, !blkif->in_polling);
     436                 :          0 : }
     437                 :            : 
     438                 :            : 
     439                 :            : int
     440                 :          0 : tapdisk_xenblkif_connect(domid_t domid, int devid, const grant_ref_t * grefs,
     441                 :            :         int order, evtchn_port_t port, int proto, int poll_duration,
     442                 :            :         int poll_idle_threshold, const char *pool, td_vbd_t * vbd)
     443                 :            : {
     444                 :          0 :     struct td_xenblkif *td_blkif = NULL; /* TODO rename to blkif */
     445                 :            :     struct td_xenio_ctx *td_ctx;
     446                 :            :     int err;
     447                 :            :     unsigned int i;
     448                 :            :     void *sring;
     449                 :            :     size_t sz;
     450                 :            : 
     451         [ #  # ]:          0 :     ASSERT(grefs);
     452         [ #  # ]:          0 :     ASSERT(vbd);
     453                 :            : 
     454                 :            :     /*
     455                 :            :      * Already connected?
     456                 :            :      */
     457         [ #  # ]:          0 :     if (tapdisk_xenblkif_find(domid, devid)) {
     458                 :            :         /* TODO log error */
     459                 :          0 :         return -EALREADY;
     460                 :            :     }
     461                 :            : 
     462                 :          0 :     err = tapdisk_xenio_ctx_get(pool, &td_ctx);
     463         [ #  # ]:          0 :     if (err) {
     464                 :            :         /* TODO log error */
     465                 :            :         goto fail;
     466                 :            :     }
     467                 :            : 
     468                 :          0 :     td_blkif = calloc(1, sizeof(*td_blkif));
     469         [ #  # ]:          0 :     if (!td_blkif) {
     470                 :            :         /* TODO log error */
     471                 :          0 :         err = -errno;
     472                 :          0 :         goto fail;
     473                 :            :     }
     474                 :            : 
     475                 :          0 :     td_blkif->domid = domid;
     476                 :          0 :     td_blkif->devid = devid;
     477                 :          0 :     td_blkif->vbd = vbd;
     478                 :          0 :     td_blkif->ctx = td_ctx;
     479                 :          0 :     td_blkif->proto = proto;
     480                 :          0 :     td_blkif->dead = false;
     481                 :          0 :         td_blkif->chkrng_event = -1;
     482                 :          0 :         td_blkif->stoppolling_event = -1;
     483                 :          0 :         td_blkif->in_polling = false;
     484                 :          0 :         td_blkif->poll_duration = poll_duration;
     485                 :          0 :         td_blkif->poll_idle_threshold = poll_idle_threshold;
     486                 :          0 :         td_blkif->barrier.msg = NULL;
     487                 :          0 :         td_blkif->barrier.io_done = false;
     488                 :          0 :         td_blkif->barrier.io_err = 0;
     489                 :            : 
     490                 :          0 :     td_blkif->xenvbd_stats.root = NULL;
     491                 :          0 :     shm_init(&td_blkif->xenvbd_stats.io_ring);
     492                 :          0 :     shm_init(&td_blkif->xenvbd_stats.stats);
     493                 :            : 
     494                 :          0 :     memset(&td_blkif->stats, 0, sizeof(td_blkif->stats));
     495                 :            : 
     496                 :          0 :     INIT_LIST_HEAD(&td_blkif->entry_ctx);
     497                 :          0 :     INIT_LIST_HEAD(&td_blkif->entry);
     498                 :            : 
     499                 :            :     /*
     500                 :            :      * Create the shared ring.
     501                 :            :      */
     502                 :          0 :     td_blkif->ring_n_pages = 1 << order;
     503         [ #  # ]:          0 :     if (td_blkif->ring_n_pages > ARRAY_SIZE(td_blkif->ring_ref)) {
     504                 :          0 :         RING_ERR(td_blkif, "too many pages (%u), max %zu\n",
     505                 :            :                 td_blkif->ring_n_pages, ARRAY_SIZE(td_blkif->ring_ref));
     506                 :            :         err = -EINVAL;
     507                 :            :         goto fail;
     508                 :            :     }
     509                 :            : 
     510                 :            :     /*
     511                 :            :      * TODO Why don't we just keep a copy of the array's address? There should
     512                 :            :      * be a reason for copying the addresses of the pages, figure out why.
     513                 :            :      * TODO Why do we even store it in the td_blkif in the first place?
     514                 :            :      */
     515         [ #  # ]:          0 :     for (i = 0; i < td_blkif->ring_n_pages; i++)
     516                 :          0 :         td_blkif->ring_ref[i] = grefs[i];
     517                 :            : 
     518                 :            :     /*
     519                 :            :      * Map the grant references that will be holding the request descriptors.
     520                 :            :      */
     521                 :          0 :     sring = xengnttab_map_domain_grant_refs(td_blkif->ctx->xcg_handle,
     522                 :          0 :             td_blkif->ring_n_pages, td_blkif->domid, td_blkif->ring_ref,
     523                 :            :             PROT_READ | PROT_WRITE);
     524         [ #  # ]:          0 :     if (!sring) {
     525                 :          0 :         err = -errno;
     526                 :          0 :         RING_ERR(td_blkif, "failed to map domain's grant references: %s\n",
     527                 :            :                 strerror(-err));
     528                 :            :         goto fail;
     529                 :            :     }
     530                 :            : 
     531                 :            :     /*
     532                 :            :      * Size of the ring, in bytes.
     533                 :            :      */
     534                 :          0 :     sz = (size_t)PAGE_SIZE << order;
     535                 :            : 
     536                 :            :     /*
     537                 :            :      * Initialize the mapped address into the shared ring.
     538                 :            :      *
     539                 :            :      * TODO Check for protocol support in the beginning of this function.
     540                 :            :      */
     541   [ #  #  #  # ]:          0 :     switch (td_blkif->proto) {
     542                 :            :         case BLKIF_PROTOCOL_NATIVE:
     543                 :            :             {
     544                 :          0 :                 blkif_sring_t *__sring = sring;
     545 [ #  # ][ #  # ]:          0 :                 BACK_RING_INIT(&td_blkif->rings.native, __sring, sz);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     546                 :          0 :                 break;
     547                 :            :             }
     548                 :            :         case BLKIF_PROTOCOL_X86_32:
     549                 :            :             {
     550                 :          0 :                 blkif_x86_32_sring_t *__sring = sring;
     551 [ #  # ][ #  # ]:          0 :                 BACK_RING_INIT(&td_blkif->rings.x86_32, __sring, sz);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     552                 :          0 :                 break;
     553                 :            :             }
     554                 :            :         case BLKIF_PROTOCOL_X86_64:
     555                 :            :             {
     556                 :          0 :                 blkif_x86_64_sring_t *__sring = sring;
     557 [ #  # ][ #  # ]:          0 :                 BACK_RING_INIT(&td_blkif->rings.x86_64, __sring, sz);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     558                 :          0 :                 break;
     559                 :            :             }
     560                 :            :         default:
     561                 :          0 :             RING_ERR(td_blkif, "unsupported protocol 0x%x\n", td_blkif->proto);
     562                 :            :             err = -EPROTONOSUPPORT;
     563                 :            :             goto fail;
     564                 :            :     }
     565                 :            : 
     566                 :            :     /*
     567                 :            :      * Bind to the remote port.
     568                 :            :      * TODO elaborate
     569                 :            :      */
     570                 :          0 :     td_blkif->port = xenevtchn_bind_interdomain(td_blkif->ctx->xce_handle,
     571                 :          0 :             td_blkif->domid, port);
     572         [ #  # ]:          0 :     if (td_blkif->port == -1) {
     573                 :          0 :         err = -errno;
     574                 :          0 :         RING_ERR(td_blkif, "failed to bind to event channel port %d: %s\n",
     575                 :            :                 port, strerror(-err));
     576                 :            :         goto fail;
     577                 :            :     }
     578                 :            : 
     579                 :          0 :     err = tapdisk_xenblkif_reqs_init(td_blkif);
     580         [ #  # ]:          0 :     if (err) {
     581                 :            :         /* TODO log error */
     582                 :            :         goto fail;
     583                 :            :     }
     584                 :            : 
     585                 :          0 :         td_blkif->chkrng_event = tapdisk_server_register_event(
     586                 :          0 :                         SCHEDULER_POLL_TIMEOUT, -1, TV_INF,
     587                 :            :                         tapdisk_xenblkif_cb_chkrng, td_blkif);
     588         [ #  # ]:          0 :         if (unlikely(td_blkif->chkrng_event < 0)) {
     589                 :          0 :                 err = td_blkif->chkrng_event;
     590                 :          0 :                 RING_ERR(td_blkif, "failed to register event: %s\n", strerror(-err));
     591                 :            :                 goto fail;
     592                 :            :         }
     593                 :            : 
     594                 :          0 :         err = td_metrics_vbd_start(td_blkif->domid, td_blkif->devid, &td_blkif->vbd_stats);
     595         [ #  # ]:          0 :         if (unlikely(err))
     596                 :            :                 goto fail;
     597                 :            : 
     598                 :          0 :         td_blkif->stoppolling_event = tapdisk_server_register_event(
     599                 :          0 :                         SCHEDULER_POLL_TIMEOUT, -1, TV_INF,
     600                 :            :                         tapdisk_xenblkif_cb_stoppolling, td_blkif);
     601         [ #  # ]:          0 :     if (unlikely(td_blkif->stoppolling_event < 0)) {
     602                 :          0 :         err = td_blkif->stoppolling_event;
     603                 :          0 :         RING_ERR(td_blkif, "failed to register event: %s\n", strerror(-err));
     604                 :            :         goto fail;
     605                 :            :     }
     606                 :            : 
     607                 :          0 :     err = tapdisk_xenblkif_stats_create(td_blkif);
     608         [ #  # ]:          0 :     if (unlikely(err))
     609                 :            :         goto fail;
     610                 :            : 
     611                 :          0 :     list_add_tail(&td_blkif->entry, &vbd->rings);
     612                 :          0 :         list_add_tail(&td_blkif->entry_ctx, &td_ctx->blkifs);
     613                 :            : 
     614                 :            :     DPRINTF("ring %p connected\n", td_blkif);
     615                 :            : 
     616                 :            :     return 0;
     617                 :            : 
     618                 :            : fail:
     619         [ #  # ]:          0 :     if (td_blkif) {
     620                 :          0 :         int err2 = tapdisk_xenblkif_destroy(td_blkif);
     621         [ #  # ]:          0 :         if (err2)
     622                 :          0 :             EPRINTF("failed to destroy the block interface: %s "
     623                 :            :                     "(error ignored)\n", strerror(-err2));
     624                 :            :     }
     625                 :            : 
     626                 :          0 :     return err;
     627                 :            : }
     628                 :            : 
     629                 :            : 
     630                 :            : event_id_t
     631                 :          0 : tapdisk_xenblkif_evtchn_event_id(const struct td_xenblkif *blkif)
     632                 :            : {
     633                 :          0 :         return blkif->ctx->ring_event;
     634                 :            : }
     635                 :            : 
     636                 :            : 
     637                 :            : event_id_t
     638                 :          0 : tapdisk_xenblkif_chkrng_event_id(const struct td_xenblkif *blkif)
     639                 :            : {
     640                 :          0 :         return blkif->chkrng_event;
     641                 :            : }
     642                 :            : 
     643                 :            : 
     644                 :            : event_id_t
     645                 :          0 : tapdisk_xenblkif_stoppolling_event_id(const struct td_xenblkif *blkif)
     646                 :            : {
     647                 :          0 :         return blkif->stoppolling_event;
     648                 :            : }
     649                 :            : 
     650                 :            : 
     651                 :            : int
     652                 :          0 : tapdisk_xenblkif_ring_stats_update(struct td_xenblkif *blkif)
     653                 :            : {
     654                 :            :     time_t t;
     655                 :          0 :     int err = 0, len;
     656                 :          0 :         struct blkif_common_back_ring *ring = NULL;
     657                 :          0 :         uLong *chksum = NULL;
     658                 :            : 
     659         [ #  # ]:          0 :     if (!blkif)
     660                 :            :         return 0;
     661                 :            : 
     662         [ #  # ]:          0 :     if (unlikely(blkif->dead))
     663                 :            :         return 0;
     664                 :            : 
     665                 :          0 :     ring = &blkif->rings.common;
     666         [ #  # ]:          0 :         if (!ring->sring)
     667                 :            :         return 0;
     668                 :            : 
     669         [ #  # ]:          0 :     ASSERT(blkif->xenvbd_stats.io_ring.mem);
     670                 :            : 
     671                 :            :     /*
     672                 :            :      * Update the ring stats once every five seconds.
     673                 :            :      */
     674                 :          0 :     t = time(NULL);
     675         [ #  # ]:          0 :         if (t - blkif->xenvbd_stats.last < 5)
     676                 :            :                 return 0;
     677                 :          0 :         blkif->xenvbd_stats.last = t;
     678                 :            : 
     679                 :          0 :     len = snprintf(blkif->xenvbd_stats.io_ring.mem + sizeof(*chksum),
     680                 :          0 :             blkif->xenvbd_stats.io_ring.size,
     681                 :            :             "nr_ents %u\n"
     682                 :            :             "req prod %u cons %d event %u\n"
     683                 :            :             "rsp prod %u pvt %d event %u\n",
     684                 :            :             ring->nr_ents,
     685                 :            :             ring->sring->req_prod, ring->req_cons, ring->sring->req_event,
     686                 :          0 :             ring->sring->rsp_prod, ring->rsp_prod_pvt, ring->sring->rsp_event);
     687         [ #  # ]:          0 :     if (unlikely(len < 0))
     688                 :          0 :         err = errno;
     689         [ #  # ]:          0 :     else if (unlikely(len + sizeof(uLong) >= blkif->xenvbd_stats.io_ring.size))
     690                 :            :         err = ENOBUFS;
     691                 :            :     else {
     692                 :          0 :         err = ftruncate(blkif->xenvbd_stats.io_ring.fd, len + sizeof(*chksum));
     693         [ #  # ]:          0 :         if (unlikely(err)) {
     694                 :          0 :             err = errno;
     695                 :          0 :             EPRINTF("failed to truncate %s to %lu: %s\n",
     696                 :            :                     blkif->xenvbd_stats.io_ring.path, len + sizeof(*chksum),
     697                 :            :                                         strerror(err));
     698                 :            :         }
     699                 :            :     }
     700                 :            : 
     701                 :          0 :         chksum = blkif->xenvbd_stats.io_ring.mem;
     702                 :          0 :         *chksum = crc32(0L, blkif->xenvbd_stats.io_ring.mem + sizeof(*chksum),
     703                 :            :                         len);
     704                 :            : 
     705                 :          0 :     return -err;
     706                 :            : }
     707                 :            : 
     708                 :            : 
     709                 :            : void
     710                 :          0 : tapdisk_xenblkif_suspend(struct td_xenblkif * const blkif)
     711                 :            : {
     712         [ #  # ]:          0 :         ASSERT(blkif);
     713                 :            : 
     714                 :          0 :         tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 1);
     715                 :          0 :         tapdisk_server_mask_event(tapdisk_xenblkif_chkrng_event_id(blkif), 1);
     716                 :          0 : }
     717                 :            : 
     718                 :            : 
     719                 :            : void
     720                 :          0 : tapdisk_xenblkif_resume(struct td_xenblkif * const blkif)
     721                 :            : {
     722         [ #  # ]:          0 :         ASSERT(blkif);
     723                 :            : 
     724                 :          0 :         tapdisk_server_mask_event(tapdisk_xenblkif_evtchn_event_id(blkif), 0);
     725                 :          0 :         tapdisk_server_mask_event(tapdisk_xenblkif_chkrng_event_id(blkif), 0);
     726                 :          0 : }
     727                 :            : 
     728                 :            : 
     729                 :            : bool
     730                 :          0 : tapdisk_xenblkif_barrier_should_complete(
     731                 :            :                 const struct td_xenblkif * const blkif)
     732                 :            : {
     733         [ #  # ]:          0 :         ASSERT(blkif);
     734                 :            : 
     735 [ #  # ][ #  # ]:          0 :         return blkif->barrier.msg && 1 == tapdisk_xenblkif_reqs_pending(blkif) &&
                 [ #  # ]
     736         [ #  # ]:          0 :                 (0 == blkif->barrier.msg->nr_segments || blkif->barrier.io_done);
     737                 :            : }

Generated by: LCOV version 1.13