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

Generated by: LCOV version 2.0-1