LCOV - code coverage report
Current view: top level - drivers - td-req.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 366 0.0 %
Date: 2025-02-07 10:09:38 Functions: 0 21 0.0 %
Branches: 0 269 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 <stdio.h>
      33                 :            : #include <errno.h>
      34                 :            : #include <syslog.h>
      35                 :            : #include <inttypes.h>
      36                 :            : #include <sys/mman.h>
      37                 :            : #include <unistd.h>
      38                 :            : #include <sys/ioctl.h>
      39                 :            : 
      40                 :            : #ifdef __linux__
      41                 :            : #include <linux/version.h>
      42                 :            : #endif
      43                 :            : 
      44                 :            : #include "blktap-xenif.h"
      45                 :            : #include "debug.h"
      46                 :            : #include "td-req.h"
      47                 :            : #include "td-blkif.h"
      48                 :            : #include "td-ctx.h"
      49                 :            : #include "tapdisk-server.h"
      50                 :            : #include "tapdisk-metrics.h"
      51                 :            : #include "tapdisk-vbd.h"
      52                 :            : #include "tapdisk-log.h"
      53                 :            : #include "tapdisk.h"
      54                 :            : #include "timeout-math.h"
      55                 :            : #include "util.h"
      56                 :            : 
      57                 :            : #ifdef DEBUG
      58                 :            : #define BLKIF_MSG_POISON 0xdeadbeef
      59                 :            : #endif
      60                 :            : 
      61                 :            : #define ERR(blkif, fmt, args...) \
      62                 :            :     EPRINTF("%d/%d: "fmt, (blkif)->domid, (blkif)->devid, ##args);
      63                 :            : 
      64                 :            : #define TD_REQS_BUFCACHE_EXPIRE 3 // time in seconds
      65                 :            : #define TD_REQS_BUFCACHE_MIN    1 // buffers to always keep in the cache
      66                 :            : 
      67                 :            : static void
      68                 :            : td_xenblkif_bufcache_free(struct td_xenblkif * const blkif);
      69                 :            : static inline void
      70                 :            : td_xenblkif_bufcache_evt_unreg(struct td_xenblkif * const blkif);
      71                 :            : 
      72                 :            : static void
      73                 :          0 : td_xenblkif_bufcache_event(event_id_t id, char mode, void *private)
      74                 :            : {
      75                 :          0 :     struct td_xenblkif *blkif = private;
      76                 :            : 
      77                 :          0 :     td_xenblkif_bufcache_free(blkif);
      78                 :            : 
      79                 :          0 :     td_xenblkif_bufcache_evt_unreg(blkif);
      80                 :          0 : }
      81                 :            : 
      82                 :            : /**
      83                 :            :  * Unregister the event to expire the request buffer cache.
      84                 :            :  *
      85                 :            :  * @param blkif the block interface
      86                 :            :  */
      87                 :            : static inline void
      88                 :          0 : td_xenblkif_bufcache_evt_unreg(struct td_xenblkif * const blkif)
      89                 :            : {
      90   [ #  #  #  # ]:          0 :     if (blkif->reqs_bufcache_evtid > 0){
           [ #  #  #  # ]
      91                 :          0 :         tapdisk_server_unregister_event(blkif->reqs_bufcache_evtid);
      92                 :            :     }
      93                 :          0 :     blkif->reqs_bufcache_evtid = 0;
      94                 :          0 : }
      95                 :            : 
      96                 :            : /**
      97                 :            :  * Register the event to expire the request buffer cache.
      98                 :            :  *
      99                 :            :  * @param blkif the block interface
     100                 :            :  */
     101                 :            : static inline void
     102                 :          0 : td_xenblkif_bufcache_evt_reg(struct td_xenblkif * const blkif)
     103                 :            : {
     104                 :          0 :     blkif->reqs_bufcache_evtid =
     105                 :          0 :         tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT,
     106                 :            :                                       -1, /* dummy fd */
     107                 :          0 :                                       TV_SECS(TD_REQS_BUFCACHE_EXPIRE),
     108                 :            :                                       td_xenblkif_bufcache_event,
     109                 :            :                                       blkif);
     110                 :          0 : }
     111                 :            : 
     112                 :            : /**
     113                 :            :  * Free request buffer cache.
     114                 :            :  *
     115                 :            :  * @param blkif the block interface
     116                 :            :  */
     117                 :            : static void
     118                 :          0 : td_xenblkif_bufcache_free(struct td_xenblkif * const blkif)
     119                 :            : {
     120         [ #  # ]:          0 :     ASSERT(blkif);
     121                 :            : 
     122         [ #  # ]:          0 :     while (blkif->n_reqs_bufcache_free > TD_REQS_BUFCACHE_MIN){
     123                 :          0 :         munmap(blkif->reqs_bufcache[--blkif->n_reqs_bufcache_free],
     124                 :            :                (size_t)BLKIF_MAX_BUFFER_SEGMENTS_PER_REQUEST << PAGE_SHIFT);
     125                 :            :     }
     126                 :          0 : }
     127                 :            : 
     128                 :            : /**
     129                 :            :  * Get buffer for a request. From cache if available or newly allocated.
     130                 :            :  *
     131                 :            :  * @param blkif the block interface
     132                 :            :  */
     133                 :            : static void *
     134                 :          0 : td_xenblkif_bufcache_get(struct td_xenblkif * const blkif)
     135                 :            : {
     136                 :            :     void *buf;
     137                 :            : 
     138         [ #  # ]:          0 :     ASSERT(blkif);
     139                 :            : 
     140         [ #  # ]:          0 :     if (!blkif->n_reqs_bufcache_free) {
     141                 :          0 :             buf = mmap(NULL, (size_t)TD_REQ_BUFFER_SIZE,
     142                 :            :                    PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
     143         [ #  # ]:          0 :         if (unlikely(buf == MAP_FAILED))
     144                 :          0 :             buf = NULL;
     145                 :            :     } else
     146                 :          0 :         buf = blkif->reqs_bufcache[--blkif->n_reqs_bufcache_free];
     147                 :            : 
     148                 :            :     // If we just got a request, we cancel the cache expire timer
     149                 :          0 :     td_xenblkif_bufcache_evt_unreg(blkif);
     150                 :            : 
     151                 :          0 :     return buf;
     152                 :            : }
     153                 :            : 
     154                 :            : static void
     155                 :          0 : td_xenblkif_bufcache_put(struct td_xenblkif * const blkif, void *buf)
     156                 :            : {
     157         [ #  # ]:          0 :     ASSERT(blkif);
     158                 :            : 
     159         [ #  # ]:          0 :     if (unlikely(!buf))
     160                 :          0 :         return;
     161                 :            : 
     162                 :            : #ifdef DEBUG
     163                 :            :         {
     164                 :            :                 int i;
     165                 :            : 
     166                 :            :                 for (i = 0; i < blkif->n_reqs_bufcache_free; i++)
     167                 :            :                         ASSERT(blkif->reqs_bufcache[i] != buf);
     168                 :            :         }
     169                 :            : #endif
     170                 :            : 
     171                 :          0 :     blkif->reqs_bufcache[blkif->n_reqs_bufcache_free++] = buf;
     172                 :            : 
     173                 :            :     /* If we're in low memory mode, prune the bufcache immediately. */
     174         [ #  # ]:          0 :     if (tapdisk_server_mem_mode() == LOW_MEMORY_MODE) {
     175                 :          0 :         td_xenblkif_bufcache_free(blkif);
     176                 :            :     } else {
     177                 :            :         // We only set the expire event when no requests are inflight
     178         [ #  # ]:          0 :         if (blkif->n_reqs_free == blkif->ring_size)
     179                 :          0 :             td_xenblkif_bufcache_evt_reg(blkif);
     180                 :            :     }
     181                 :            : }
     182                 :            : 
     183                 :            : /**
     184                 :            :  * Puts the request back to the free list of this block interface.
     185                 :            :  *
     186                 :            :  * @param blkif the block interface
     187                 :            :  * @param tapreq the request to give back
     188                 :            :  */
     189                 :            : static void
     190                 :          0 : tapdisk_xenblkif_free_request(struct td_xenblkif * const blkif,
     191                 :            :         struct td_xenblkif_req * const tapreq)
     192                 :            : {
     193         [ #  # ]:          0 :     ASSERT(blkif);
     194         [ #  # ]:          0 :     ASSERT(tapreq);
     195         [ #  # ]:          0 :     ASSERT(blkif->n_reqs_free < blkif->ring_size);
     196                 :            : 
     197                 :            : #ifdef DEBUG
     198                 :            :         memset(&tapreq->msg, BLKIF_MSG_POISON, sizeof(tapreq->msg));
     199                 :            : #endif
     200                 :            : 
     201                 :          0 :     blkif->reqs_free[blkif->ring_size - (++blkif->n_reqs_free)] = &tapreq->msg;
     202                 :            : 
     203         [ #  # ]:          0 :         if (likely(tapreq->msg.nr_segments))
     204                 :          0 :             td_xenblkif_bufcache_put(blkif, tapreq->vma);
     205                 :          0 : }
     206                 :            : 
     207                 :            : /**
     208                 :            :  * Returns the size, in request descriptors, of the shared ring
     209                 :            :  *
     210                 :            :  * @param blkif the block interface
     211                 :            :  * @returns the size, in request descriptors, of the shared ring
     212                 :            :  */
     213                 :            : static int
     214                 :          0 : td_blkif_ring_size(const struct td_xenblkif * const blkif)
     215                 :            : {
     216         [ #  # ]:          0 :     ASSERT(blkif);
     217                 :            : 
     218   [ #  #  #  # ]:          0 :     switch (blkif->proto) {
     219                 :            :         case BLKIF_PROTOCOL_NATIVE:
     220                 :          0 :             return RING_SIZE(&blkif->rings.native);
     221                 :            : 
     222                 :            :         case BLKIF_PROTOCOL_X86_32:
     223                 :          0 :             return RING_SIZE(&blkif->rings.x86_32);
     224                 :            : 
     225                 :            :         case BLKIF_PROTOCOL_X86_64:
     226                 :          0 :             return RING_SIZE(&blkif->rings.x86_64);
     227                 :            : 
     228                 :            :         default:
     229                 :            :             return -EPROTONOSUPPORT;
     230                 :            :     }
     231                 :            : }
     232                 :            : 
     233                 :            : /**
     234                 :            :  * Get the response that corresponds to the specified ring index in a H/W
     235                 :            :  * independent way.
     236                 :            :  *
     237                 :            :  * @returns a pointer to the response, NULL on error, sets errno
     238                 :            :  *
     239                 :            :  * TODO use function pointers instead of switch
     240                 :            :  * XXX only called by xenio_blkif_put_response
     241                 :            :  */
     242                 :            : static inline blkif_response_t *
     243                 :          0 : xenio_blkif_get_response(struct td_xenblkif* const blkif, const RING_IDX rp)
     244                 :            : {
     245                 :          0 :     blkif_back_rings_t * const rings = &blkif->rings;
     246                 :          0 :     blkif_response_t * p = NULL;
     247                 :            : 
     248   [ #  #  #  # ]:          0 :     switch (blkif->proto) {
     249                 :            :         case BLKIF_PROTOCOL_NATIVE:
     250                 :          0 :             p = (blkif_response_t *) RING_GET_RESPONSE(&rings->native, rp);
     251                 :          0 :             break;
     252                 :            :         case BLKIF_PROTOCOL_X86_32:
     253                 :          0 :             p = (blkif_response_t *) RING_GET_RESPONSE(&rings->x86_32, rp);
     254                 :          0 :             break;
     255                 :            :         case BLKIF_PROTOCOL_X86_64:
     256                 :          0 :             p = (blkif_response_t *) RING_GET_RESPONSE(&rings->x86_64, rp);
     257                 :          0 :             break;
     258                 :            :         default:
     259                 :          0 :             errno = EPROTONOSUPPORT;
     260                 :          0 :                         return NULL;
     261                 :            :     }
     262                 :            : 
     263                 :          0 :     return p;
     264                 :            : }
     265                 :            : 
     266                 :            : /**
     267                 :            :  * Puts a response in the ring.
     268                 :            :  *
     269                 :            :  * @param blkif the VBD
     270                 :            :  * @param req the request for which the response should be put
     271                 :            :  * @param status the status of the response (success or an error code)
     272                 :            :  * @param final controls whether the front-end will be notified, if necessary
     273                 :            :  *
     274                 :            :  * TODO @req can be NULL so the function will only notify the other end. This
     275                 :            :  * is used in the error path of tapdisk_xenblkif_queue_requests. The point is
     276                 :            :  * that the other will just be notified, does this make sense?
     277                 :            :  */
     278                 :            : static int
     279                 :          0 : xenio_blkif_put_response(struct td_xenblkif * const blkif,
     280                 :            :         struct td_xenblkif_req *req, int const status, int const final)
     281                 :            : {
     282                 :          0 :     blkif_common_back_ring_t * const ring = &blkif->rings.common;
     283                 :            : 
     284         [ #  # ]:          0 :     if (req) {
     285                 :          0 :         blkif_response_t * msg = xenio_blkif_get_response(blkif,
     286                 :            :                 ring->rsp_prod_pvt);
     287         [ #  # ]:          0 :                 if (!msg)
     288                 :          0 :                         return -errno;
     289                 :            : 
     290 [ #  # ][ #  # ]:          0 :         ASSERT(status == BLKIF_RSP_EOPNOTSUPP || status == BLKIF_RSP_ERROR
     291                 :            :                 || status == BLKIF_RSP_OKAY);
     292                 :            : 
     293                 :          0 :         msg->id = req->msg.id;
     294                 :            : 
     295                 :          0 :         msg->operation = req->msg.operation;
     296                 :            : 
     297                 :          0 :         msg->status = status;
     298                 :            : 
     299                 :          0 :         ring->rsp_prod_pvt++;
     300                 :            :     }
     301                 :            : 
     302         [ #  # ]:          0 :     if (final) {
     303                 :            :         int notify;
     304                 :          0 :         RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
     305         [ #  # ]:          0 :         if (notify) {
     306                 :          0 :             int err = xenevtchn_notify(blkif->ctx->xce_handle, blkif->port);
     307         [ #  # ]:          0 :             if (err < 0) {
     308                 :          0 :                 err = -errno;
     309         [ #  # ]:          0 :                 if (req) {
     310                 :          0 :                     RING_ERR(blkif, "req %lu: failed to notify event channel: "
     311                 :            :                             "%s\n", req->msg.id, strerror(-err));
     312                 :            :                 } else {
     313                 :          0 :                     RING_ERR(blkif, "failed to notify event channel: %s\n",
     314                 :            :                             strerror(-err));
     315                 :            :                 }
     316                 :          0 :                 return err;
     317                 :            :             }
     318                 :            :         }
     319                 :            :     }
     320                 :            : 
     321                 :            :     return 0;
     322                 :            : }
     323                 :            : 
     324                 :            : 
     325                 :            : /**
     326                 :            :  * Tells whether the request requires data to be read.
     327                 :            :  */
     328                 :            : static inline bool
     329                 :          0 : blkif_rq_rd(blkif_request_t const * const msg)
     330                 :            : {
     331                 :          0 :         return BLKIF_OP_READ == msg->operation;
     332                 :            : }
     333                 :            : 
     334                 :            : 
     335                 :            : /**
     336                 :            :  * Tells whether the request requires data to be written.
     337                 :            :  */
     338                 :            : static inline bool
     339                 :          0 : blkif_rq_wr(blkif_request_t const * const msg)
     340                 :            : {
     341 [ #  # ][ #  # ]:          0 :         return BLKIF_OP_WRITE == msg->operation ||
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     342 [ #  # ][ #  # ]:          0 :                 (BLKIF_OP_WRITE_BARRIER == msg->operation && msg->nr_segments);
         [ #  # ][ #  # ]
     343                 :            : }
     344                 :            : 
     345                 :            : 
     346                 :            : /**
     347                 :            :  * Tells whether the request requires data to transferred.
     348                 :            :  */
     349                 :            : static inline bool
     350                 :          0 : blkif_rq_data(blkif_request_t const * const msg)
     351                 :            : {
     352 [ #  # ][ #  # ]:          0 :         return blkif_rq_rd(msg) || blkif_rq_wr(msg);
     353                 :            : }
     354                 :            : 
     355                 :            : 
     356                 :            : static int
     357                 :          0 : guest_copy2(struct td_xenblkif * const blkif,
     358                 :            :         struct td_xenblkif_req * const tapreq /* TODO rename to req */) {
     359                 :            : 
     360                 :          0 :     int i = 0;
     361                 :          0 :     long err = 0;
     362                 :            :     struct ioctl_gntdev_grant_copy gcopy;
     363                 :            : 
     364         [ #  # ]:          0 :     ASSERT(blkif);
     365         [ #  # ]:          0 :     ASSERT(blkif->ctx);
     366         [ #  # ]:          0 :     ASSERT(tapreq);
     367         [ #  # ]:          0 :     ASSERT(blkif_rq_data(&tapreq->msg));
     368         [ #  # ]:          0 :         ASSERT(tapreq->msg.nr_segments > 0);
     369         [ #  # ]:          0 :         ASSERT(tapreq->msg.nr_segments <= ARRAY_SIZE(tapreq->gcopy_segs));
     370                 :            : 
     371         [ #  # ]:          0 :     for (i = 0; i < tapreq->msg.nr_segments; i++) {
     372                 :          0 :         struct blkif_request_segment *blkif_seg = &tapreq->msg.seg[i];
     373                 :          0 :         struct gntdev_grant_copy_segment *gcopy_seg = &tapreq->gcopy_segs[i];
     374                 :            : #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
     375         [ #  # ]:          0 :         if (blkif_rq_wr(&tapreq->msg)) {
     376                 :            :             /* copy from guest */
     377                 :          0 :             gcopy_seg->dest.virt = tapreq->vma + (i << PAGE_SHIFT)
     378                 :          0 :                 + (blkif_seg->first_sect << SECTOR_SHIFT);
     379                 :          0 :             gcopy_seg->source.foreign.ref = blkif_seg->gref;
     380                 :          0 :             gcopy_seg->source.foreign.offset = blkif_seg->first_sect << SECTOR_SHIFT;
     381                 :          0 :             gcopy_seg->source.foreign.domid = blkif->domid;
     382                 :          0 :             gcopy_seg->flags = GNTCOPY_source_gref;
     383                 :            :         } else {
     384                 :            :             /* copy to guest */
     385                 :          0 :             gcopy_seg->source.virt = tapreq->vma + (i << PAGE_SHIFT)
     386                 :          0 :                 + (blkif_seg->first_sect << SECTOR_SHIFT);
     387                 :          0 :             gcopy_seg->dest.foreign.ref = blkif_seg->gref;
     388                 :          0 :             gcopy_seg->dest.foreign.offset = blkif_seg->first_sect << SECTOR_SHIFT;
     389                 :          0 :             gcopy_seg->dest.foreign.domid = blkif->domid;
     390                 :          0 :             gcopy_seg->flags = GNTCOPY_dest_gref;
     391                 :            :         }
     392                 :            : 
     393                 :          0 :         gcopy_seg->len = (blkif_seg->last_sect
     394                 :          0 :                 - blkif_seg->first_sect
     395                 :            :                 + 1)
     396                 :            :             << SECTOR_SHIFT;
     397                 :            :     }
     398                 :            : #else
     399                 :            :         gcopy_seg->iov.iov_base = tapreq->vma + (i << PAGE_SHIFT)
     400                 :            :             + (blkif_seg->first_sect << SECTOR_SHIFT);
     401                 :            :         gcopy_seg->iov.iov_len = (blkif_seg->last_sect
     402                 :            :                 - blkif_seg->first_sect
     403                 :            :                 + 1)
     404                 :            :             << SECTOR_SHIFT;
     405                 :            :         gcopy_seg->ref = blkif_seg->gref;
     406                 :            :         gcopy_seg->offset = blkif_seg->first_sect << SECTOR_SHIFT;
     407                 :            :     }
     408                 :            : 
     409                 :            :     gcopy.dir = blkif_rq_wr(&tapreq->msg);
     410                 :            :     gcopy.domid = blkif->domid;
     411                 :            : #endif
     412                 :          0 :     gcopy.count = tapreq->msg.nr_segments;
     413                 :          0 :         gcopy.segments = tapreq->gcopy_segs;
     414                 :            : 
     415                 :          0 :     err = -ioctl(blkif->ctx->gntdev_fd, IOCTL_GNTDEV_GRANT_COPY, &gcopy);
     416         [ #  # ]:          0 :     if (err) {
     417                 :          0 :         err = -errno;
     418                 :          0 :         RING_ERR(blkif, "failed to grant-copy request %"PRIu64" "
     419                 :            :                 "(%d segments): %s\n", tapreq->msg.id,
     420                 :            :                 tapreq->msg.nr_segments, strerror(-err));
     421                 :            :         goto out;
     422                 :            :     }
     423                 :            : 
     424         [ #  # ]:          0 :         for (i = 0; i < tapreq->msg.nr_segments; i++) {
     425                 :          0 :                 struct gntdev_grant_copy_segment *gcopy_seg = &tapreq->gcopy_segs[i];
     426         [ #  # ]:          0 :                 if (gcopy_seg->status != GNTST_okay) {
     427                 :            :                         /*
     428                 :            :                          * TODO use gnttabop_error for reporting errors, defined in
     429                 :            :                          * xen/extras/mini-os/include/gnttab.h (header not available to
     430                 :            :                          * user space)
     431                 :            :                          */
     432                 :          0 :                         RING_ERR(blkif, "req %lu: failed to grant-copy segment %d: %d\n",
     433                 :            :                     tapreq->msg.id, i, gcopy_seg->status);
     434                 :            :                         err = -EIO;
     435                 :            :                         goto out;
     436                 :            :                 }
     437                 :            :         }
     438                 :            : 
     439                 :            : out:
     440                 :          0 :     return err;
     441                 :            : }
     442                 :            : 
     443                 :            : 
     444                 :            : /**
     445                 :            :  * Completes a request. If this is the last pending request of a dead block
     446                 :            :  * interface, the block interface is destroyed, the caller must not access it
     447                 :            :  * any more.
     448                 :            :  *
     449                 :            :  * @blkif the VBD the request belongs belongs to
     450                 :            :  * @tapreq the request to complete TODO rename to req
     451                 :            :  * @error completion status of the request
     452                 :            :  * @final controls whether the other end should be notified
     453                 :            :  */
     454                 :            : void
     455                 :          0 : tapdisk_xenblkif_complete_request(struct td_xenblkif * const blkif,
     456                 :            :                 struct td_xenblkif_req* tapreq, int err, const int final)
     457                 :            : {
     458                 :            :         int _err;
     459                 :          0 :         long long *max = NULL, *sum = NULL, *cnt = NULL;
     460                 :            :         static int depth = 0;
     461                 :            :         bool processing_barrier_message;
     462                 :          0 :         uint64_t *ticks = NULL;
     463                 :            : 
     464         [ #  # ]:          0 :         ASSERT(blkif);
     465         [ #  # ]:          0 :         ASSERT(tapreq);
     466         [ #  # ]:          0 :         ASSERT(depth >= 0);
     467                 :            : 
     468                 :          0 :         depth++;
     469                 :            : 
     470                 :          0 :         processing_barrier_message =
     471                 :          0 :                 tapreq->msg.operation == BLKIF_OP_WRITE_BARRIER;
     472                 :            : 
     473                 :            :         /*
     474                 :            :          * If a barrier request completes, check whether it's an I/O completion
     475                 :            :          * (the barrier carries write I/O data), or a completion because the last
     476                 :            :          * pending non-barrier request completed. If the former case is true, we
     477                 :            :          * need to check again whether the latter is true and proceed with the
     478                 :            :          * completion, otherwise simply note the fact that I/O is done and when
     479                 :            :          * the last pending non-barrier requests completes, this function will be
     480                 :            :          * called again passing the barrier request.
     481                 :            :          */
     482         [ #  # ]:          0 :         if (unlikely(processing_barrier_message)) {
     483         [ #  # ]:          0 :                 ASSERT(blkif->barrier.msg == &tapreq->msg);
     484 [ #  # ][ #  # ]:          0 :                 if (tapreq->msg.nr_segments && !blkif->barrier.io_done) {
     485                 :          0 :                         blkif->barrier.io_err = err;
     486                 :          0 :                         blkif->barrier.io_done = true;
     487                 :            :                 }
     488         [ #  # ]:          0 :                 if (!tapdisk_xenblkif_barrier_should_complete(blkif))
     489                 :            :                         goto out;
     490                 :            :         }
     491                 :            : 
     492         [ #  # ]:          0 :         if (likely(!blkif->dead)) {
     493         [ #  # ]:          0 :                 if (blkif_rq_rd(&tapreq->msg)) {
     494                 :            :                         /*
     495                 :            :                          * TODO stats should be collected after grant-copy for better
     496                 :            :                          * accuracy
     497                 :            :                          */
     498         [ #  # ]:          0 :                         if (likely(blkif->stats.xenvbd)) {
     499                 :          0 :                                 cnt = &blkif->stats.xenvbd->st_rd_cnt;
     500                 :          0 :                                 sum = &blkif->stats.xenvbd->st_rd_sum_usecs;
     501                 :          0 :                                 max = &blkif->stats.xenvbd->st_rd_max_usecs;
     502                 :            :                         }
     503                 :          0 :                         blkif->vbd_stats.stats->read_reqs_completed++;
     504                 :          0 :                         ticks = &blkif->vbd_stats.stats->read_total_ticks;
     505         [ #  # ]:          0 :                         if (likely(!err)) {
     506                 :          0 :                                 _err = guest_copy2(blkif, tapreq);
     507         [ #  # ]:          0 :                                 if (unlikely(_err)) {
     508                 :          0 :                                         err = _err;
     509                 :          0 :                                         RING_ERR(blkif, "req %lu: failed to copy from/to guest: "
     510                 :            :                                                         "%s\n", tapreq->msg.id, strerror(-err));
     511                 :            :                                 }
     512                 :            :                         }
     513         [ #  # ]:          0 :                 } else if (blkif_rq_wr(&tapreq->msg)) {
     514         [ #  # ]:          0 :                         if (likely(blkif->stats.xenvbd)) {
     515                 :          0 :                                 cnt = &blkif->stats.xenvbd->st_wr_cnt;
     516                 :          0 :                                 sum = &blkif->stats.xenvbd->st_wr_sum_usecs;
     517                 :          0 :                                 max = &blkif->stats.xenvbd->st_wr_max_usecs;
     518                 :            :                         }
     519                 :          0 :                         blkif->vbd_stats.stats->write_reqs_completed++;
     520                 :          0 :                         ticks = &blkif->vbd_stats.stats->write_total_ticks;
     521                 :            :                 }
     522                 :            : 
     523         [ #  # ]:          0 :                 if (likely(cnt)) {
     524                 :            :                         struct timeval now;
     525                 :            :                         long long interval;
     526                 :          0 :                         gettimeofday(&now, NULL);
     527                 :          0 :                         interval = timeval_to_us(&now) - timeval_to_us(&tapreq->ts);
     528                 :          0 :                         *ticks += interval;
     529         [ #  # ]:          0 :                         if (interval > *max)
     530                 :          0 :                                 *max = interval;
     531                 :            : 
     532                 :          0 :                         *sum += interval;
     533                 :          0 :                         *cnt += 1;
     534                 :            :                 }
     535                 :            : 
     536         [ #  # ]:          0 :                 if (likely(err == 0))
     537                 :            :                         _err = BLKIF_RSP_OKAY;
     538                 :            :                 else
     539                 :          0 :                         _err = BLKIF_RSP_ERROR;
     540                 :            : 
     541                 :          0 :                 xenio_blkif_put_response(blkif, tapreq, _err, final);
     542                 :            :         }
     543                 :            : 
     544                 :          0 :         tapdisk_xenblkif_free_request(blkif, tapreq);
     545                 :            : 
     546                 :          0 :         blkif->stats.reqs.out++;
     547         [ #  # ]:          0 :         if (final)
     548                 :          0 :                 blkif->stats.kicks.out++;
     549                 :            : 
     550         [ #  # ]:          0 :         if (unlikely(processing_barrier_message))
     551                 :          0 :                 blkif->barrier.msg = NULL;
     552                 :            : 
     553                 :            :         /*
     554                 :            :          * Schedule a ring check in case we left requests in it due to lack of
     555                 :            :          * memory or in case we stopped processing it because of a barrier.
     556                 :            :          *
     557                 :            :          * FIXME we should decide whether a ring check is necessary more
     558                 :            :          * intelligently.
     559                 :            :         */
     560         [ #  # ]:          0 :         if (!blkif->barrier.msg) {
     561         [ #  # ]:          0 :                 if (likely(!blkif->dead))
     562                 :          0 :                         tapdisk_xenblkif_sched_chkrng(blkif);
     563                 :            :         } else {
     564                 :            :                 /*
     565                 :            :                  * If this is the last request, complete the barrier request.
     566                 :            :                  */
     567         [ #  # ]:          0 :                 if (tapdisk_xenblkif_barrier_should_complete(blkif))
     568                 :          0 :                         tapdisk_xenblkif_complete_request(blkif,
     569                 :          0 :                                         msg_to_tapreq(blkif->barrier.msg), 0, 1);
     570                 :            :         }
     571                 :            : 
     572                 :            :         /*
     573                 :            :          * Last request of a dead ring completes, destroy the ring.
     574                 :            :          */
     575 [ #  # ][ #  # ]:          0 :         if (unlikely(1 == depth
         [ #  # ][ #  # ]
     576                 :            :                                 && blkif->dead
     577                 :            :                                 && !tapdisk_xenblkif_reqs_pending(blkif))) {
     578                 :            : 
     579                 :          0 :                 RING_DEBUG(blkif, "destroying dead ring\n");
     580                 :          0 :                 tapdisk_xenblkif_destroy(blkif);
     581                 :            :         }
     582                 :            : 
     583                 :            : out:
     584                 :          0 :         depth--;
     585                 :          0 : }
     586                 :            : 
     587                 :            : /**
     588                 :            :  * Request completion callback, executed when the tapdisk has finished
     589                 :            :  * processing the request.
     590                 :            :  *
     591                 :            :  * @param vreq the completed request
     592                 :            :  * @param error status of the request
     593                 :            :  * @param token token previously associated with this request
     594                 :            :  * @param final TODO ?
     595                 :            :  */
     596                 :            : static inline void
     597                 :          0 : __tapdisk_xenblkif_request_cb(struct td_vbd_request * const vreq,
     598                 :            :         const int error, void * const token, const int final)
     599                 :            : {
     600                 :            :     struct td_xenblkif_req *tapreq;
     601                 :          0 :     struct td_xenblkif * const blkif = token;
     602                 :            : 
     603         [ #  # ]:          0 :     ASSERT(vreq);
     604         [ #  # ]:          0 :     ASSERT(blkif);
     605                 :            : 
     606                 :          0 :     tapreq = container_of(vreq, struct td_xenblkif_req, vreq);
     607                 :            : 
     608         [ #  # ]:          0 :     if (error) {
     609         [ #  # ]:          0 :         if (likely(!blkif->dead)) {
     610                 :          0 :             blkif->stats.errors.img++;
     611                 :          0 :             blkif->vbd_stats.stats->io_errors++;
     612                 :            :         }
     613                 :            :     }
     614                 :            : 
     615                 :          0 :     tapdisk_xenblkif_complete_request(blkif, tapreq, error, final);
     616                 :          0 : }
     617                 :            : 
     618                 :            : 
     619                 :            : static inline int
     620                 :          0 : tapdisk_xenblkif_parse_request(struct td_xenblkif * const blkif,
     621                 :            :         struct td_xenblkif_req * const req)
     622                 :            : {
     623                 :            :     td_vbd_request_t *vreq;
     624                 :            :     int i;
     625                 :            :     struct td_iovec *iov;
     626                 :            :     void *page, *next, *last;
     627                 :          0 :     int err = 0;
     628                 :          0 :     unsigned nr_sect = 0;
     629                 :            : 
     630         [ #  # ]:          0 :     ASSERT(blkif);
     631         [ #  # ]:          0 :     ASSERT(req);
     632                 :            : 
     633                 :          0 :     vreq = &req->vreq;
     634         [ #  # ]:          0 :     ASSERT(vreq);
     635                 :            : 
     636                 :          0 :     req->vma = td_xenblkif_bufcache_get(blkif);
     637         [ #  # ]:          0 :     if (unlikely(!req->vma)) {
     638                 :          0 :         err = errno;
     639                 :          0 :         goto out;
     640                 :            :     }
     641                 :            : 
     642         [ #  # ]:          0 :     for (i = 0; i < req->msg.nr_segments; i++) {
     643                 :          0 :         struct blkif_request_segment *seg = &req->msg.seg[i];
     644                 :          0 :         req->gref[i] = seg->gref;
     645                 :            : 
     646                 :            :         /*
     647                 :            :          * Note that first and last may be equal, which means only one sector
     648                 :            :          * must be transferred.
     649                 :            :          */
     650         [ #  # ]:          0 :         if (seg->last_sect < seg->first_sect) {
     651                 :          0 :             RING_ERR(blkif, "req %lu: invalid sectors %d-%d\n",
     652                 :            :                     req->msg.id, seg->first_sect, seg->last_sect);
     653                 :          0 :             err = EINVAL;
     654                 :          0 :             goto out;
     655                 :            :         }
     656                 :            :     }
     657                 :            : 
     658                 :            :     /*
     659                 :            :      * Vectorises the request: creates the struct iovec (in tapreq->iov) that
     660                 :            :      * describes each segment to be transferred. Also, merges consecutive
     661                 :            :      * segments.
     662                 :            :      *
     663                 :            :      * In each loop, iov points to the previous scatter/gather element in
     664                 :            :      * order to reuse it if the current and previous segments are
     665                 :            :      * consecutive.
     666                 :            :      */
     667                 :          0 :     iov = req->iov - 1;
     668                 :          0 :     last = NULL;
     669                 :          0 :     page = req->vma;
     670                 :            : 
     671         [ #  # ]:          0 :     for (i = 0; i < req->msg.nr_segments; i++) { /* for each segment */
     672                 :          0 :         struct blkif_request_segment *seg = &req->msg.seg[i];
     673                 :            :         size_t size;
     674                 :            : 
     675                 :            :         /* TODO check that first_sect/last_sect are within page */
     676                 :            : 
     677                 :          0 :         next = page + (seg->first_sect << SECTOR_SHIFT);
     678                 :          0 :         size = seg->last_sect - seg->first_sect + 1;
     679                 :            : 
     680         [ #  # ]:          0 :         if (next != last) {
     681                 :          0 :             iov++;
     682                 :          0 :             iov->base = next;
     683                 :          0 :             iov->secs = size;
     684                 :            :         } else /* The "else" is true if fist_sect is 0. */
     685                 :          0 :             iov->secs += size;
     686                 :            : 
     687                 :          0 :         last = iov->base + (iov->secs << SECTOR_SHIFT);
     688                 :          0 :         page += PAGE_SIZE;
     689                 :          0 :         nr_sect += size;
     690                 :            :     }
     691                 :            : 
     692                 :          0 :     vreq->iov = req->iov;
     693                 :          0 :     vreq->iovcnt = iov - req->iov + 1;
     694                 :          0 :     vreq->sec = req->msg.sector_number;
     695                 :            : 
     696         [ #  # ]:          0 :     if (blkif_rq_wr(&req->msg)) {
     697                 :          0 :         err = guest_copy2(blkif, req);
     698         [ #  # ]:          0 :         if (err) {
     699                 :          0 :             RING_ERR(blkif, "req %lu: failed to copy from guest: %s\n",
     700                 :            :                     req->msg.id, strerror(-err));
     701                 :            :             goto out;
     702                 :            :         }
     703         [ #  # ]:          0 :                 if (likely(blkif->stats.xenvbd))
     704                 :          0 :                         blkif->stats.xenvbd->st_wr_sect += nr_sect;
     705         [ #  # ]:          0 :                 if (likely(blkif->vbd_stats.stats))
     706                 :          0 :                         blkif->vbd_stats.stats->write_sectors += nr_sect;
     707                 :            :     } else {
     708         [ #  # ]:          0 :                 if (likely(blkif->stats.xenvbd))
     709                 :          0 :                         blkif->stats.xenvbd->st_rd_sect += nr_sect;
     710         [ #  # ]:          0 :                 if (likely(blkif->vbd_stats.stats))
     711                 :          0 :                         blkif->vbd_stats.stats->read_sectors += nr_sect;
     712                 :            :     } 
     713                 :            : 
     714                 :            :     /*
     715                 :            :      * TODO Isn't this kind of expensive to do for each requests? Why does
     716                 :            :      * the tapdisk need this in the first place?
     717                 :            :      */
     718                 :          0 :     snprintf(req->name, sizeof(req->name), "xenvbd-%d-%d.%"SCNx64"",
     719                 :            :              blkif->domid, blkif->devid, req->msg.id);
     720                 :            : 
     721                 :          0 :     vreq->name = req->name;
     722                 :          0 :     vreq->token = blkif;
     723                 :          0 :     vreq->cb = __tapdisk_xenblkif_request_cb;
     724                 :            : 
     725                 :            : out:
     726                 :          0 :     return err;
     727                 :            : }
     728                 :            : 
     729                 :            : 
     730                 :            : /**
     731                 :            :  * Initialises the standard tapdisk request (td_vbd_request_t) from the
     732                 :            :  * intermediate ring request (td_xenblkif_req) in order to prepare it
     733                 :            :  * processing.
     734                 :            :  *
     735                 :            :  * @param blkif the block interface
     736                 :            :  * @param tapreq the request to prepare TODO rename to req
     737                 :            :  * @returns 0 on success
     738                 :            :  *
     739                 :            :  * XXX only called by tapdisk_xenblkif_queue_request
     740                 :            :  */
     741                 :            : static inline int
     742                 :          0 : tapdisk_xenblkif_make_vbd_request(struct td_xenblkif * const blkif,
     743                 :            :         struct td_xenblkif_req * const tapreq)
     744                 :            : {
     745                 :          0 :     int err = 0;
     746                 :            :     td_vbd_request_t *vreq;
     747                 :            : 
     748         [ #  # ]:          0 :     ASSERT(tapreq);
     749                 :            : 
     750                 :          0 :     vreq = &tapreq->vreq;
     751         [ #  # ]:          0 :     ASSERT(vreq);
     752                 :            :     memset(vreq, 0, sizeof(*vreq));
     753                 :            : 
     754                 :          0 :         tapreq->vma = NULL;
     755      [ #  #  # ]:          0 :     switch (tapreq->msg.operation) {
     756                 :            :     case BLKIF_OP_READ:
     757         [ #  # ]:          0 :         if (likely(blkif->stats.xenvbd))
     758                 :          0 :                         blkif->stats.xenvbd->st_rd_req++;
     759         [ #  # ]:          0 :         if (likely(blkif->vbd_stats.stats))
     760                 :          0 :                 blkif->vbd_stats.stats->read_reqs_submitted++;
     761                 :          0 :         tapreq->prot = PROT_WRITE;
     762                 :          0 :         vreq->op = TD_OP_READ;
     763                 :          0 :         break;
     764                 :            :     case BLKIF_OP_WRITE:
     765                 :            :     case BLKIF_OP_WRITE_BARRIER:
     766         [ #  # ]:          0 :         if (likely(blkif->stats.xenvbd))
     767                 :          0 :                         blkif->stats.xenvbd->st_wr_req++;
     768         [ #  # ]:          0 :         if (likely(blkif->vbd_stats.stats))
     769                 :          0 :                 blkif->vbd_stats.stats->write_reqs_submitted++;
     770                 :          0 :         tapreq->prot = PROT_READ;
     771                 :          0 :         vreq->op = TD_OP_WRITE;
     772                 :          0 :         break;
     773                 :            :     default:
     774                 :          0 :         RING_ERR(blkif, "req %lu: invalid request type %d\n",
     775                 :            :                 tapreq->msg.id, tapreq->msg.operation);
     776                 :          0 :         err = EOPNOTSUPP;
     777                 :          0 :         goto out;
     778                 :            :     }
     779                 :            :     /* Timestamp before the requests leave the blkif layer */
     780                 :          0 :     gettimeofday(&tapreq->ts, NULL);
     781                 :            : 
     782                 :            :     /*
     783                 :            :      * Check that the number of segments is sane.
     784                 :            :      */
     785 [ #  # ][ #  # ]:          0 :     if (unlikely((tapreq->msg.nr_segments == 0 &&
         [ #  # ][ #  # ]
     786                 :            :                 tapreq->msg.operation != BLKIF_OP_WRITE_BARRIER) ||
     787                 :            :             tapreq->msg.nr_segments > BLKIF_MAX_BUFFER_SEGMENTS_PER_REQUEST)) {
     788                 :          0 :         RING_ERR(blkif, "req %lu: bad number of segments in request (%d)\n",
     789                 :            :                 tapreq->msg.id, tapreq->msg.nr_segments);
     790                 :          0 :         err = EINVAL;
     791                 :          0 :         goto out;
     792                 :            :     }
     793                 :            : 
     794         [ #  # ]:          0 :     if (likely(tapreq->msg.nr_segments))
     795                 :          0 :         err = tapdisk_xenblkif_parse_request(blkif, tapreq);
     796                 :            :     /*
     797                 :            :      * If we only got one request from the ring and that was a barrier one,
     798                 :            :      * check whether the barrier requests completion conditions are satisfied
     799                 :            :          * and if they are, complete the barrier request.
     800                 :            :      *
     801                 :            :      * It could be that there are more requests in the ring after the barrier
     802                 :            :      * request, tapdisk_xenblkif_complete_request() will schedule a ring check.
     803                 :            :      */
     804         [ #  # ]:          0 :     else if (tapdisk_xenblkif_barrier_should_complete(blkif)) {
     805                 :          0 :         tapdisk_xenblkif_complete_request(blkif,
     806                 :          0 :                 msg_to_tapreq(blkif->barrier.msg), 0, 1);
     807                 :          0 :         err = 0;
     808                 :            :     }
     809                 :            : out:
     810                 :          0 :     return err;
     811                 :            : }
     812                 :            : 
     813                 :            : 
     814                 :            : /**
     815                 :            :  * Queues a ring request, after it prepares it, to the standard taodisk queue
     816                 :            :  * for processing.
     817                 :            :  *
     818                 :            :  * @param blkif the block interface
     819                 :            :  * @param msg the ring request
     820                 :            :  * @param tapreq the intermediate request TODO rename to req
     821                 :            :  *
     822                 :            :  * TODO don't really need to supply the ring request since it's either way
     823                 :            :  * contained in the tapreq
     824                 :            :  *
     825                 :            :  * XXX only called by tapdisk_xenblkif_queue_requests
     826                 :            :  */
     827                 :            : static inline int
     828                 :          0 : tapdisk_xenblkif_queue_request(struct td_xenblkif * const blkif,
     829                 :            :         blkif_request_t *msg, struct td_xenblkif_req *tapreq)
     830                 :            : {
     831                 :            :     int err;
     832                 :            : 
     833         [ #  # ]:          0 :     ASSERT(blkif);
     834         [ #  # ]:          0 :     ASSERT(msg);
     835         [ #  # ]:          0 :     ASSERT(tapreq);
     836                 :            : 
     837                 :          0 :     err = tapdisk_xenblkif_make_vbd_request(blkif, tapreq);
     838         [ #  # ]:          0 :     if (unlikely(err)) {
     839                 :            :         /* TODO log error */
     840                 :          0 :         blkif->stats.errors.map++;
     841                 :          0 :         return err;
     842                 :            :     }
     843                 :            : 
     844         [ #  # ]:          0 :         if (likely(tapreq->msg.nr_segments)) {
     845                 :          0 :                 err = tapdisk_vbd_queue_request(blkif->vbd, &tapreq->vreq);
     846         [ #  # ]:          0 :                 if (unlikely(err)) {
     847                 :            :                         /* TODO log error */
     848                 :          0 :                         blkif->stats.errors.vbd++;
     849                 :          0 :                         return err;
     850                 :            :                 }
     851                 :            :         }
     852                 :            : 
     853                 :            :     return 0;
     854                 :            : }
     855                 :            : 
     856                 :            : 
     857                 :            : void
     858                 :          0 : tapdisk_xenblkif_queue_requests(struct td_xenblkif * const blkif,
     859                 :            :         blkif_request_t *reqs[], const int nr_reqs)
     860                 :            : {
     861                 :            :     int i;
     862                 :            :     int err;
     863                 :          0 :     int nr_errors = 0;
     864                 :            : 
     865         [ #  # ]:          0 :     ASSERT(blkif);
     866         [ #  # ]:          0 :     ASSERT(reqs);
     867         [ #  # ]:          0 :     ASSERT(nr_reqs >= 0);
     868                 :            : 
     869         [ #  # ]:          0 :     for (i = 0; i < nr_reqs; i++) { /* for each request in the ring... */
     870                 :          0 :         blkif_request_t *msg = reqs[i];
     871                 :            :         struct td_xenblkif_req *tapreq;
     872                 :            : 
     873         [ #  # ]:          0 :         ASSERT(msg);
     874                 :            : 
     875                 :          0 :         tapreq = msg_to_tapreq(msg);
     876                 :            : 
     877         [ #  # ]:          0 :         ASSERT(tapreq);
     878                 :            : 
     879                 :          0 :         err = tapdisk_xenblkif_queue_request(blkif, msg, tapreq);
     880         [ #  # ]:          0 :         if (err) {
     881                 :            :             /* TODO log error */
     882                 :          0 :             nr_errors++;
     883                 :          0 :             tapdisk_xenblkif_complete_request(blkif, tapreq, err, 1);
     884                 :            :         }
     885                 :            :     }
     886                 :            : 
     887                 :            :     /* there is a possibility of blkif getting freed if ring is 
     888                 :            :        dead and current request is the last one, hence adding 
     889                 :            :        this check to avoid seg fault */
     890                 :            : 
     891         [ #  # ]:          0 :     if (nr_errors && blkif)
     892                 :          0 :         xenio_blkif_put_response(blkif, NULL, 0, 1);
     893                 :          0 : }
     894                 :            : 
     895                 :            : void
     896                 :          0 : tapdisk_xenblkif_reqs_free(struct td_xenblkif * const blkif)
     897                 :            : {
     898         [ #  # ]:          0 :     ASSERT(blkif);
     899                 :            : 
     900                 :          0 :     td_xenblkif_bufcache_free(blkif);
     901                 :          0 :     td_xenblkif_bufcache_evt_unreg(blkif);
     902                 :            : 
     903                 :          0 :     free(blkif->reqs_bufcache);
     904                 :          0 :     blkif->reqs_bufcache = NULL;
     905                 :            : 
     906                 :          0 :     free(blkif->reqs);
     907                 :          0 :     blkif->reqs = NULL;
     908                 :            : 
     909                 :          0 :     free(blkif->reqs_free);
     910                 :          0 :     blkif->reqs_free = NULL;
     911                 :            : 
     912                 :          0 : }
     913                 :            : 
     914                 :            : int
     915                 :          0 : tapdisk_xenblkif_reqs_init(struct td_xenblkif *td_blkif)
     916                 :            : {
     917                 :            :     void *buf;
     918                 :          0 :     int i = 0;
     919                 :          0 :     int err = 0;
     920                 :            : 
     921         [ #  # ]:          0 :     ASSERT(td_blkif);
     922                 :            : 
     923                 :          0 :     td_blkif->ring_size = td_blkif_ring_size(td_blkif);
     924         [ #  # ]:          0 :     ASSERT(td_blkif->ring_size > 0);
     925                 :            : 
     926                 :          0 :     td_blkif->reqs =
     927                 :          0 :         calloc(td_blkif->ring_size, sizeof(struct td_xenblkif_req));
     928         [ #  # ]:          0 :     if (!td_blkif->reqs) {
     929                 :          0 :         err = -errno;
     930                 :          0 :         goto fail;
     931                 :            :     }
     932                 :            : 
     933                 :          0 :     td_blkif->reqs_free =
     934                 :          0 :         malloc(td_blkif->ring_size * sizeof(struct xenio_blkif_req *));
     935         [ #  # ]:          0 :     if (!td_blkif->reqs_free) {
     936                 :          0 :         err = -errno;
     937                 :          0 :         goto fail;
     938                 :            :     }
     939                 :            : 
     940                 :          0 :     td_blkif->n_reqs_free = 0;
     941         [ #  # ]:          0 :     for (i = 0; i < td_blkif->ring_size; i++)
     942                 :          0 :         tapdisk_xenblkif_free_request(td_blkif, &td_blkif->reqs[i]);
     943                 :            : 
     944                 :            :     // Allocate the buffer cache
     945                 :          0 :     td_blkif->reqs_bufcache = malloc(sizeof(void*) * td_blkif->ring_size);
     946         [ #  # ]:          0 :     if (!td_blkif->reqs_bufcache) {
     947                 :          0 :         err = -errno;
     948                 :          0 :         goto fail;
     949                 :            :     }
     950                 :          0 :     td_blkif->n_reqs_bufcache_free = 0;
     951                 :          0 :     td_blkif->reqs_bufcache_evtid = 0;
     952                 :            : 
     953                 :            :     // Populate cache with one buffer
     954                 :          0 :     buf = td_xenblkif_bufcache_get(td_blkif);
     955                 :          0 :     td_xenblkif_bufcache_put(td_blkif, buf);
     956                 :          0 :     td_xenblkif_bufcache_evt_unreg(td_blkif);
     957                 :            : 
     958                 :          0 :     return 0;
     959                 :            : 
     960                 :            : fail:
     961                 :          0 :     tapdisk_xenblkif_reqs_free(td_blkif);
     962                 :          0 :     return err;
     963                 :            : }

Generated by: LCOV version 1.13