LCOV - code coverage report
Current view: top level - drivers - tapdisk-blktap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 280 0.0 %
Date: 2025-03-10 18:15:27 Functions: 0 28 0.0 %
Branches: 0 475 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016, Citrix Systems, Inc.
       3                 :            :  *
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions are met:
       8                 :            :  * 
       9                 :            :  *  1. Redistributions of source code must retain the above copyright
      10                 :            :  *     notice, this list of conditions and the following disclaimer.
      11                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *     notice, this list of conditions and the following disclaimer in the
      13                 :            :  *     documentation and/or other materials provided with the distribution.
      14                 :            :  *  3. Neither the name of the copyright holder nor the names of its 
      15                 :            :  *     contributors may be used to endorse or promote products derived from 
      16                 :            :  *     this software without specific prior written permission.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21                 :            :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
      22                 :            :  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      23                 :            :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      24                 :            :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      25                 :            :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      26                 :            :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      27                 :            :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28                 :            :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #ifdef HAVE_CONFIG_H
      32                 :            : #include "config.h"
      33                 :            : #endif
      34                 :            : 
      35                 :            : #include <stdlib.h>
      36                 :            : #include <stdio.h>
      37                 :            : #include <unistd.h>
      38                 :            : #include <errno.h>
      39                 :            : #include <fcntl.h>
      40                 :            : #include <limits.h>
      41                 :            : #include <sys/mman.h>
      42                 :            : #include <sys/ioctl.h>
      43                 :            : #include <sys/sysmacros.h>
      44                 :            : #include <sys/types.h>
      45                 :            : #include <sys/stat.h>
      46                 :            : 
      47                 :            : #include "blktap.h"
      48                 :            : #include "tapdisk-vbd.h"
      49                 :            : #include "tapdisk-blktap.h"
      50                 :            : #include "tapdisk-metrics.h"
      51                 :            : #include "tapdisk-server.h"
      52                 :            : #include "timeout-math.h"
      53                 :            : #include "linux-blktap.h"
      54                 :            : 
      55                 :            : #define BUG(_cond)       td_panic()
      56                 :            : #define BUG_ON(_cond)    if (unlikely(_cond)) { td_panic(); }
      57                 :            : 
      58                 :            : #define DBG(_f, _a...)       tlog_syslog(TLOG_DBG, _f, ##_a)
      59                 :            : #define INFO(_f, _a...)      tlog_syslog(TLOG_INFO, _f, ##_a)
      60                 :            : #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
      61                 :            : #define WARN(_f, _a...)      tlog_syslog(TLOG_WARN, "WARNING: "_f "in %s:%d", \
      62                 :            :                                          ##_a, __func__, __LINE__)
      63                 :            : 
      64                 :            : #define __RD2(_x)  (((_x) & 0x00000002) ? 0x2                  : ((_x) & 0x1))
      65                 :            : #define __RD4(_x)  (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2    : __RD2(_x))
      66                 :            : #define __RD8(_x)  (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4    : __RD4(_x))
      67                 :            : #define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8    : __RD8(_x))
      68                 :            : #define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
      69                 :            : 
      70                 :            : #define BLKTAP_RD32(_n)      __RD32(_n)
      71                 :            : #define BLKTAP_RING_SIZE     __BLKTAP_RING_SIZE(PAGE_SIZE)
      72                 :            : 
      73                 :            : #define BLKTAP_GET_RESPONSE(_tap, _idx) \
      74                 :            :         (&(_tap)->sring->entry[(_idx) % BLKTAP_RING_SIZE].rsp)
      75                 :            : #define BLKTAP_GET_REQUEST(_tap, _idx) \
      76                 :            :         (&(_tap)->sring->entry[(_idx) % BLKTAP_RING_SIZE].req)
      77                 :            : 
      78                 :            : static void __tapdisk_blktap_close(td_blktap_t *);
      79                 :            : 
      80                 :            : struct td_blktap_req {
      81                 :            :         td_vbd_request_t        vreq;
      82                 :            :         unsigned int            id;
      83                 :            :         char                    name[27];
      84                 :            :         struct td_iovec         iov[BLKTAP_SEGMENT_MAX];
      85                 :            :         struct timeval          ts;
      86                 :            : };
      87                 :            : 
      88                 :            : td_blktap_req_t *
      89                 :          0 : tapdisk_blktap_alloc_request(td_blktap_t *tap)
      90                 :            : {
      91                 :          0 :         td_blktap_req_t *req = NULL;
      92                 :            : 
      93         [ #  # ]:          0 :         if (likely(tap->n_reqs_free))
      94                 :          0 :                 req = tap->reqs_free[--tap->n_reqs_free];
      95                 :            : 
      96                 :          0 :         return req;
      97                 :            : }
      98                 :            : 
      99                 :            : void
     100                 :          0 : tapdisk_blktap_free_request(td_blktap_t *tap, td_blktap_req_t *req)
     101                 :            : {
     102         [ #  # ]:          0 :         BUG_ON(tap->n_reqs_free >= tap->n_reqs);
     103                 :          0 :         tap->reqs_free[tap->n_reqs_free++] = req;
     104                 :          0 : }
     105                 :            : 
     106                 :            : static void
     107                 :          0 : tapdisk_blktap_reqs_free(td_blktap_t *tap)
     108                 :            : {
     109         [ #  # ]:          0 :         if (tap->reqs) {
     110                 :          0 :                 free(tap->reqs);
     111                 :          0 :                 tap->reqs = NULL;
     112                 :            :         }
     113                 :            : 
     114         [ #  # ]:          0 :         if (tap->reqs_free) {
     115                 :          0 :                 free(tap->reqs_free);
     116                 :          0 :                 tap->reqs_free = NULL;
     117                 :            :         }
     118                 :          0 : }
     119                 :            : 
     120                 :            : static int
     121                 :          0 : tapdisk_blktap_reqs_init(td_blktap_t *tap, int n_reqs)
     122                 :            : {
     123                 :            :         int i, err;
     124                 :            : 
     125                 :          0 :         tap->reqs = malloc(n_reqs * sizeof(td_blktap_req_t));
     126         [ #  # ]:          0 :         if (!tap->reqs) {
     127                 :          0 :                 err = -errno;
     128                 :          0 :                 goto fail;
     129                 :            :         }
     130                 :            : 
     131                 :          0 :         tap->reqs_free = malloc(n_reqs * sizeof(td_blktap_req_t*));
     132         [ #  # ]:          0 :         if (!tap->reqs_free) {
     133                 :          0 :                 err = -errno;
     134                 :          0 :                 goto fail;
     135                 :            :         }
     136                 :            : 
     137                 :          0 :         tap->n_reqs      = n_reqs;
     138                 :          0 :         tap->n_reqs_free = 0;
     139                 :            : 
     140         [ #  # ]:          0 :         for (i = 0; i < n_reqs; i++)
     141                 :          0 :                 tapdisk_blktap_free_request(tap, &tap->reqs[i]);
     142                 :            : 
     143                 :            :         return 0;
     144                 :            : 
     145                 :            : fail:
     146                 :          0 :         tapdisk_blktap_reqs_free(tap);
     147                 :          0 :         return err;
     148                 :            : }
     149                 :            : 
     150                 :            : static void
     151                 :          0 : tapdisk_blktap_kick(td_blktap_t *tap)
     152                 :            : {
     153         [ #  # ]:          0 :         if (likely(tap->fd >= 0)) {
     154                 :          0 :                 ioctl(tap->fd, BLKTAP_IOCTL_RESPOND, 0);
     155                 :          0 :                 tap->stats.kicks.out++;
     156                 :            :         }
     157                 :          0 : }
     158                 :            : 
     159                 :            : static int
     160                 :          0 : tapdisk_blktap_error_status(td_blktap_t *tap, int error)
     161                 :            : {
     162                 :            :         int status;
     163                 :            : 
     164      [ #  #  # ]:          0 :         switch (error) {
              [ #  #  # ]
     165                 :            :         case 0:
     166                 :            :                 status = BLKTAP_RSP_OKAY;
     167                 :            :                 break;
     168                 :            :         case -EOPNOTSUPP:
     169                 :            :         case EOPNOTSUPP:
     170                 :          0 :                 status = BLKTAP_RSP_EOPNOTSUPP;
     171                 :          0 :                 break;
     172                 :            :         default:
     173                 :          0 :                 status = BLKTAP_RSP_ERROR;
     174                 :          0 :                 break;
     175                 :            :         }
     176                 :            : 
     177                 :          0 :         return status;
     178                 :            : }
     179                 :            : 
     180                 :            : static void
     181                 :          0 : __tapdisk_blktap_push_response(td_blktap_t *tap, int final)
     182                 :            : {
     183                 :          0 :         tap->rsp_prod_pvt++;
     184                 :            : 
     185         [ #  # ]:          0 :         if (final) {
     186                 :          0 :                 tap->sring->rsp_prod = tap->rsp_prod_pvt;
     187                 :          0 :                 tapdisk_blktap_kick(tap);
     188                 :            :         }
     189                 :            : 
     190                 :          0 :         tap->stats.reqs.out++;
     191                 :          0 : }
     192                 :            : 
     193                 :            : static void
     194                 :          0 : tapdisk_blktap_fail_request(td_blktap_t *tap,
     195                 :            :                             blktap_ring_req_t *msg, int error)
     196                 :            : {
     197                 :            :         blktap_ring_rsp_t *rsp;
     198                 :            : 
     199         [ #  # ]:          0 :         BUG_ON(!tap->vma);
     200                 :            : 
     201 [ #  # ][ #  # ]:          0 :         rsp = BLKTAP_GET_RESPONSE(tap, tap->rsp_prod_pvt);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     202                 :            : 
     203                 :          0 :         rsp->id        = msg->id;
     204                 :          0 :         rsp->operation = msg->operation;
     205                 :          0 :         rsp->status    = tapdisk_blktap_error_status(tap, error);
     206                 :            : 
     207                 :          0 :         __tapdisk_blktap_push_response(tap, 1);
     208                 :          0 : }
     209                 :            : 
     210                 :            : static void
     211                 :          0 : tapdisk_blktap_put_response(td_blktap_t *tap,
     212                 :            :                             td_blktap_req_t *req, int error, int final)
     213                 :            : {
     214                 :            :         blktap_ring_rsp_t *rsp;
     215                 :          0 :         int op = 0;
     216                 :            :         unsigned long long interval;
     217                 :            :         struct timeval now;
     218                 :            : 
     219         [ #  # ]:          0 :         BUG_ON(!tap->vma);
     220                 :            : 
     221 [ #  # ][ #  # ]:          0 :         rsp = BLKTAP_GET_RESPONSE(tap, tap->rsp_prod_pvt);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     222                 :            : 
     223                 :          0 :         gettimeofday(&now, NULL);
     224                 :          0 :         interval = timeval_to_us(&now) - timeval_to_us(&req->ts);
     225      [ #  #  # ]:          0 :         switch (req->vreq.op) {
     226                 :            :         case TD_OP_READ:
     227                 :          0 :                 op = BLKTAP_OP_READ;
     228                 :          0 :                 tap->blktap_stats.stats->read_reqs_completed++;
     229                 :          0 :                 tap->blktap_stats.stats->read_total_ticks += interval;
     230                 :          0 :                 break;
     231                 :            :         case TD_OP_WRITE:
     232                 :          0 :                 op = BLKTAP_OP_WRITE;
     233                 :          0 :                 tap->blktap_stats.stats->write_reqs_completed++;
     234                 :          0 :                 tap->blktap_stats.stats->write_total_ticks += interval;
     235                 :          0 :                 break;
     236                 :            :         default:
     237                 :          0 :                 BUG();
     238                 :            :         }
     239                 :            : 
     240         [ #  # ]:          0 :         if (error)
     241                 :          0 :                 tap->blktap_stats.stats->io_errors++;
     242                 :            : 
     243                 :          0 :         rsp->id        = req->id;
     244                 :          0 :         rsp->operation = op;
     245                 :          0 :         rsp->status    = tapdisk_blktap_error_status(tap, error);
     246                 :            : 
     247                 :          0 :         __tapdisk_blktap_push_response(tap, final);
     248                 :          0 : }
     249                 :            : 
     250                 :            : static void
     251                 :          0 : tapdisk_blktap_complete_request(td_blktap_t *tap,
     252                 :            :                                 td_blktap_req_t *req, int error,
     253                 :            :                                 int final)
     254                 :            : {
     255         [ #  # ]:          0 :         if (likely(tap->vma))
     256                 :          0 :                 tapdisk_blktap_put_response(tap, req, error, final);
     257                 :            : 
     258                 :          0 :         tapdisk_blktap_free_request(tap, req);
     259                 :          0 : }
     260                 :            : 
     261                 :            : static void
     262                 :          0 : __tapdisk_blktap_request_cb(td_vbd_request_t *vreq, int error,
     263                 :            :                             void *token, int final)
     264                 :            : {
     265                 :          0 :         td_blktap_req_t *req = container_of(vreq, td_blktap_req_t, vreq);
     266                 :          0 :         td_blktap_t *tap = token;
     267                 :            : 
     268                 :          0 :         tapdisk_blktap_complete_request(tap, req, error, final);
     269                 :          0 : }
     270                 :            : 
     271                 :            : static void
     272                 :          0 : tapdisk_blktap_vector_request(td_blktap_t *tap,
     273                 :            :                               const blktap_ring_req_t *msg,
     274                 :            :                               td_blktap_req_t *req)
     275                 :            : {
     276                 :          0 :         td_vbd_request_t *vreq = &req->vreq;
     277                 :            :         const struct blktap_segment *seg;
     278                 :            :         struct td_iovec *iov;
     279                 :            :         void *page, *next, *last;
     280                 :            :         size_t size;
     281                 :            :         int i;
     282                 :          0 :         unsigned nr_sect = 0;
     283                 :            : 
     284                 :          0 :         iov   = req->iov - 1;
     285                 :          0 :         last  = NULL;
     286                 :            : 
     287                 :          0 :         page  = tap->vstart;
     288                 :          0 :         page += msg->id * BLKTAP_SEGMENT_MAX * PAGE_SIZE;
     289                 :            : 
     290         [ #  # ]:          0 :         for (i = 0; i < msg->nr_segments; i++) {
     291                 :          0 :                 seg  = &msg->seg[i];
     292                 :            : 
     293                 :          0 :                 next = page + (seg->first_sect << SECTOR_SHIFT);
     294                 :          0 :                 size = seg->last_sect - seg->first_sect + 1;
     295                 :            : 
     296         [ #  # ]:          0 :                 if (next != last) {
     297                 :          0 :                         iov++;
     298                 :          0 :                         iov->base = next;
     299                 :          0 :                         iov->secs = size;
     300                 :            :                 } else
     301                 :          0 :                         iov->secs += size;
     302                 :            : 
     303                 :          0 :                 last  = iov->base + (iov->secs << SECTOR_SHIFT);
     304                 :          0 :                 page += PAGE_SIZE;
     305                 :          0 :                 nr_sect += size;
     306                 :            :         }
     307                 :            : 
     308      [ #  #  # ]:          0 :         switch(msg->operation){
     309                 :            :         case BLKTAP_OP_READ:
     310                 :          0 :             tap->blktap_stats.stats->read_sectors += nr_sect;
     311                 :          0 :             break;
     312                 :            :         case BLKTAP_OP_WRITE:
     313                 :          0 :             tap->blktap_stats.stats->write_sectors += nr_sect;
     314                 :          0 :             break;
     315                 :            :         }
     316                 :          0 :         vreq->iov    = req->iov;
     317                 :          0 :         vreq->iovcnt = iov - req->iov + 1;
     318                 :          0 :         vreq->sec    = msg->sector_number;
     319                 :          0 : }
     320                 :            : 
     321                 :            : static int
     322                 :          0 : tapdisk_blktap_parse_request(td_blktap_t *tap,
     323                 :            :                              const blktap_ring_req_t *msg, td_blktap_req_t *req)
     324                 :            : {
     325                 :          0 :         td_vbd_request_t *vreq = &req->vreq;
     326                 :          0 :         int op, err = -EINVAL;
     327                 :            : 
     328                 :            :         memset(req, 0, sizeof(*req));
     329                 :            : 
     330                 :          0 :         gettimeofday(&req->ts, NULL);
     331                 :            : 
     332      [ #  #  # ]:          0 :         switch (msg->operation) {
     333                 :            :         case BLKTAP_OP_READ:
     334                 :          0 :                 tap->blktap_stats.stats->read_reqs_submitted++;
     335                 :          0 :                 op = TD_OP_READ;
     336                 :          0 :                 break;
     337                 :            :         case BLKTAP_OP_WRITE:
     338                 :          0 :                 tap->blktap_stats.stats->write_reqs_submitted++;
     339                 :          0 :                 op = TD_OP_WRITE;
     340                 :          0 :                 break;
     341                 :            :         default:
     342                 :            :                 goto fail;
     343                 :            :         }
     344                 :            : 
     345 [ #  # ][ #  # ]:          0 :         if (msg->id > BLKTAP_RING_SIZE)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     346                 :            :                 goto fail;
     347                 :            : 
     348         [ #  # ]:          0 :         if (msg->nr_segments < 1 ||
     349                 :            :             msg->nr_segments > BLKTAP_SEGMENT_MAX)
     350                 :            :                 goto fail;
     351                 :            : 
     352                 :          0 :         req->id = msg->id;
     353                 :          0 :         snprintf(req->name, sizeof(req->name),
     354                 :            :                  "tap-%d.%d", tap->minor, req->id);
     355                 :            : 
     356                 :          0 :         vreq->op    = op;
     357                 :          0 :         vreq->name  = req->name;
     358                 :          0 :         vreq->token = tap;
     359                 :          0 :         vreq->cb    = __tapdisk_blktap_request_cb;
     360                 :            : 
     361                 :          0 :         tapdisk_blktap_vector_request(tap, msg, req);
     362                 :            : 
     363                 :          0 :         err = 0;
     364                 :            : fail:
     365                 :          0 :         return err;
     366                 :            : }
     367                 :            : 
     368                 :            : static void
     369                 :          0 : tapdisk_blktap_get_requests(td_blktap_t *tap)
     370                 :            : {
     371                 :            :         unsigned int rp, rc;
     372                 :            :         int err;
     373                 :            : 
     374                 :          0 :         rp = tap->sring->req_prod;
     375                 :            : 
     376         [ #  # ]:          0 :         for (rc = tap->req_cons; rc != rp; rc++) {
     377 [ #  # ][ #  # ]:          0 :                 blktap_ring_req_t *msg = BLKTAP_GET_REQUEST(tap, rc);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     378                 :            :                 td_blktap_req_t *req;
     379                 :            : 
     380                 :          0 :                 tap->stats.reqs.in++;
     381                 :            : 
     382                 :          0 :                 req = tapdisk_blktap_alloc_request(tap);
     383         [ #  # ]:          0 :                 if (!req) {
     384                 :            :                         err = -EFAULT;
     385                 :            :                         goto fail_ring;
     386                 :            :                 }
     387                 :            : 
     388                 :          0 :                 err = tapdisk_blktap_parse_request(tap, msg, req);
     389         [ #  # ]:          0 :                 if (err) {
     390                 :          0 :                         tapdisk_blktap_fail_request(tap, msg, err);
     391                 :          0 :                         tapdisk_blktap_free_request(tap, req);
     392                 :          0 :                         goto fail_ring;
     393                 :            :                 }
     394                 :            : 
     395                 :          0 :                 err = tapdisk_vbd_queue_request(tap->vbd, &req->vreq);
     396         [ #  # ]:          0 :                 if (err)
     397                 :          0 :                         tapdisk_blktap_complete_request(tap, req, err, 1);
     398                 :            :         }
     399                 :            : 
     400                 :          0 :         tap->req_cons = rc;
     401                 :            : 
     402                 :          0 :         return;
     403                 :            : 
     404                 :            : fail_ring:
     405                 :          0 :         ERR(err, "ring error, disconnecting.");
     406                 :          0 :         __tapdisk_blktap_close(tap);
     407                 :            : }
     408                 :            : 
     409                 :            : static void
     410                 :          0 : tapdisk_blktap_fd_event(event_id_t id, char mode, void *data)
     411                 :            : {
     412                 :          0 :         td_blktap_t *tap = data;
     413                 :            : 
     414                 :          0 :         tap->stats.kicks.in++;
     415                 :          0 :         tapdisk_blktap_get_requests(tap);
     416                 :          0 : }
     417                 :            : 
     418                 :            : int
     419                 :          0 : tapdisk_blktap_remove_device(td_blktap_t *tap)
     420                 :            : {
     421                 :          0 :         int err = 0;
     422                 :            : 
     423         [ #  # ]:          0 :         if (likely(tap->fd >= 0)) {
     424                 :          0 :                 err = ioctl(tap->fd, BLKTAP_IOCTL_REMOVE_DEVICE);
     425         [ #  # ]:          0 :                 if (err)
     426                 :          0 :                         err = -errno;
     427                 :            :         }
     428                 :            : 
     429                 :          0 :         return err;
     430                 :            : }
     431                 :            : 
     432                 :            : int
     433                 :          0 : tapdisk_blktap_compat_create_device(td_blktap_t *tap,
     434                 :            :                                     const struct blktap_device_info *bdi)
     435                 :            : {
     436                 :            :         struct blktap2_params params;
     437                 :            :         int err;
     438                 :            : 
     439                 :            :         memset(&params, 0, sizeof(params));
     440                 :          0 :         params.capacity    = bdi->capacity;
     441                 :          0 :         params.sector_size = bdi->sector_size;
     442                 :            : 
     443                 :          0 :         err = ioctl(tap->fd, BLKTAP_IOCTL_CREATE_DEVICE_COMPAT, &params);
     444         [ #  # ]:          0 :         if (err) {
     445                 :          0 :                 err = -errno;
     446                 :          0 :                 return err;
     447                 :            :         }
     448                 :            : 
     449 [ #  # ][ #  # ]:          0 :         if (bdi->flags || bdi->physical_sector_size != bdi->sector_size)
     450                 :          0 :                 WARN("fell back to compat ioctl(%d)",
     451                 :            :                      BLKTAP_IOCTL_CREATE_DEVICE_COMPAT);
     452                 :            : 
     453                 :            :         return 0;
     454                 :            : }
     455                 :            : 
     456                 :            : #ifndef ENOIOCTLCMD
     457                 :            : #define ENOIOCTLCMD 515
     458                 :            : #endif
     459                 :            : 
     460                 :            : int
     461                 :          0 : tapdisk_blktap_create_device(td_blktap_t *tap,
     462                 :            :                              const td_disk_info_t *info, int rdonly)
     463                 :            : {
     464                 :            :         struct blktap_device_info bdi;
     465                 :            :         unsigned long flags;
     466                 :            :         int err;
     467                 :            : 
     468                 :            :         memset(&bdi, 0, sizeof(bdi));
     469                 :            : 
     470                 :          0 :         flags  = 0;
     471         [ #  # ]:          0 :         flags |= rdonly ? BLKTAP_DEVICE_RO : 0;
     472                 :            : 
     473                 :          0 :         bdi.capacity             = info->size;
     474                 :          0 :         bdi.sector_size          = info->sector_size;
     475                 :          0 :         bdi.physical_sector_size = info->sector_size;
     476                 :          0 :         bdi.flags                = flags;
     477                 :            : 
     478                 :          0 :         INFO("bdev: capacity=%llu sector_size=%u/%u flags=%#lx",
     479                 :            :              bdi.capacity, bdi.sector_size, bdi.physical_sector_size,
     480                 :            :              bdi.flags);
     481                 :            : 
     482                 :          0 :         err = ioctl(tap->fd, BLKTAP_IOCTL_CREATE_DEVICE, &bdi);
     483         [ #  # ]:          0 :         if (!err)
     484                 :          0 :                 return 0;
     485                 :            : 
     486                 :          0 :         err = -errno;
     487         [ #  # ]:          0 :         if (err == -ENOTTY || err == -ENOIOCTLCMD)
     488                 :          0 :                 err = tapdisk_blktap_compat_create_device(tap, &bdi);
     489                 :            : 
     490                 :          0 :         return err;
     491                 :            : }
     492                 :            : 
     493                 :            : static void
     494                 :          0 : tapdisk_blktap_unmap(td_blktap_t *tap)
     495                 :            : {
     496   [ #  #  #  # ]:          0 :         if (tap->vma) {
     497                 :          0 :                 munmap(tap->vma, tap->vma_size);
     498                 :          0 :                 tap->vma = NULL;
     499                 :            :         }
     500                 :          0 : }
     501                 :            : 
     502                 :            : static int
     503                 :          0 : tapdisk_blktap_map(td_blktap_t *tap)
     504                 :            : {
     505                 :            :         int prot, flags, err;
     506                 :            :         void *vma;
     507                 :            : 
     508                 :          0 :         tap->vma_size =
     509 [ #  # ][ #  # ]:          0 :                 1 + ((size_t)BLKTAP_RING_SIZE *
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     510                 :          0 :                      BLKTAP_SEGMENT_MAX * PAGE_SIZE);
     511                 :            : 
     512                 :          0 :         prot  = PROT_READ | PROT_WRITE;
     513                 :          0 :         flags = MAP_SHARED;
     514                 :            : 
     515                 :          0 :         vma = mmap(NULL, tap->vma_size, prot, flags, tap->fd, 0);
     516         [ #  # ]:          0 :         if (vma == MAP_FAILED) {
     517                 :          0 :                 err = -errno;
     518                 :            :                 goto fail;
     519                 :            :         }
     520                 :            : 
     521                 :          0 :         tap->vma    = vma;
     522                 :          0 :         tap->vstart = vma + PAGE_SIZE;
     523                 :            : 
     524                 :          0 :         tap->req_cons     = 0;
     525                 :          0 :         tap->rsp_prod_pvt = 0;
     526                 :          0 :         tap->sring        = vma;
     527                 :            : 
     528                 :          0 :         return 0;
     529                 :            : 
     530                 :            : fail:
     531                 :          0 :         tapdisk_blktap_unmap(tap);
     532                 :          0 :         return err;
     533                 :            : }
     534                 :            : 
     535                 :            : static void
     536                 :          0 : __tapdisk_blktap_close(td_blktap_t *tap)
     537                 :            : {
     538                 :            :         /*
     539                 :            :          * NB. this can bail out at runtime. after munmap, blktap
     540                 :            :          * already failed all pending block reqs. AIO on buffers will
     541                 :            :          * -EFAULT. vreq completion just backs off once fd/vma are
     542                 :            :          * gone, so we'll drain, then idle until close().
     543                 :            :          */
     544                 :            :         int err;
     545         [ #  # ]:          0 :         if (tap->event_id >= 0) {
     546                 :          0 :                 tapdisk_server_unregister_event(tap->event_id);
     547                 :          0 :                 tap->event_id = -1;
     548                 :            :         }
     549                 :            : 
     550                 :          0 :         tapdisk_blktap_unmap(tap);
     551                 :            : 
     552         [ #  # ]:          0 :         if (tap->fd >= 0) {
     553                 :          0 :                 close(tap->fd);
     554                 :          0 :                 tap->fd = -1;
     555                 :            :         }
     556                 :          0 :         err = td_metrics_blktap_stop(&tap->blktap_stats);
     557         [ #  # ]:          0 :         if (err) {
     558                 :          0 :             EPRINTF("failed to destroy blktap stats file: %s\n", strerror(-err));
     559                 :            :         }
     560                 :          0 : }
     561                 :            : 
     562                 :            : void
     563                 :          0 : tapdisk_blktap_close(td_blktap_t *tap)
     564                 :            : {
     565                 :          0 :         __tapdisk_blktap_close(tap);
     566                 :          0 :         tapdisk_blktap_reqs_free(tap);
     567                 :          0 :         free(tap);
     568                 :          0 : }
     569                 :            : 
     570                 :            : int
     571                 :          0 : tapdisk_blktap_open(const char *devname, td_vbd_t *vbd, td_blktap_t **_tap)
     572                 :            : {
     573                 :            :         td_blktap_t *tap;
     574                 :            :         struct stat st;
     575                 :            :         int err;
     576                 :            : 
     577                 :          0 :         tap = malloc(sizeof(*tap));
     578         [ #  # ]:          0 :         if (!tap) {
     579                 :          0 :                 err = -errno;
     580                 :          0 :                 goto fail;
     581                 :            :         }
     582                 :            : 
     583                 :            :         memset(tap, 0, sizeof(*tap));
     584                 :          0 :         tap->fd = -1;
     585                 :          0 :         tap->event_id = -1;
     586                 :            : 
     587                 :          0 :         tap->fd = open(devname, O_RDWR);
     588         [ #  # ]:          0 :         if (tap->fd < 0) {
     589                 :          0 :                 err = -errno;
     590                 :          0 :                 goto fail;
     591                 :            :         }
     592                 :            : 
     593                 :          0 :         err = fstat(tap->fd, &st);
     594         [ #  # ]:          0 :         if (err) {
     595                 :          0 :                 err = -errno;
     596                 :          0 :                 goto fail;
     597                 :            :         }
     598                 :            : 
     599                 :          0 :         tap->vbd   = vbd;
     600                 :          0 :         tap->minor = minor(st.st_rdev);
     601                 :            : 
     602                 :          0 :         err = tapdisk_blktap_map(tap);
     603         [ #  # ]:          0 :         if (err)
     604                 :            :                 goto fail;
     605                 :            : 
     606                 :          0 :         err = td_metrics_blktap_start(tap->minor, &tap->blktap_stats);
     607         [ #  # ]:          0 :         if (err)
     608                 :            :             goto fail;
     609                 :            : 
     610                 :          0 :         tap->event_id =
     611                 :          0 :                 tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
     612                 :          0 :                                               tap->fd, TV_ZERO,
     613                 :            :                                               tapdisk_blktap_fd_event,
     614                 :            :                                               tap);
     615         [ #  # ]:          0 :         if (tap->event_id < 0) {
     616                 :            :                 err = tap->event_id;
     617                 :            :                 goto fail;
     618                 :            :         }
     619                 :            : 
     620 [ #  # ][ #  # ]:          0 :         err = tapdisk_blktap_reqs_init(tap, BLKTAP_RING_SIZE);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     621         [ #  # ]:          0 :         if (err)
     622                 :            :                 goto fail;
     623                 :            : 
     624         [ #  # ]:          0 :         if (_tap)
     625                 :          0 :                 *_tap = tap;
     626                 :            : 
     627                 :          0 :         return 0;
     628                 :            : 
     629                 :            : fail:
     630         [ #  # ]:          0 :         if (tap)
     631                 :          0 :                 tapdisk_blktap_close(tap);
     632                 :            : 
     633                 :          0 :         return err;
     634                 :            : }
     635                 :            : 
     636                 :            : void
     637                 :          0 : tapdisk_blktap_stats(td_blktap_t *tap, td_stats_t *st)
     638                 :            : {
     639                 :          0 :         tapdisk_stats_field(st, "minor", "d", tap->minor);
     640                 :            : 
     641                 :          0 :         tapdisk_stats_field(st, "reqs", "[");
     642                 :          0 :         tapdisk_stats_val(st, "llu", tap->stats.reqs.in);
     643                 :          0 :         tapdisk_stats_val(st, "llu", tap->stats.reqs.out);
     644                 :          0 :         tapdisk_stats_leave(st, ']');
     645                 :            : 
     646                 :          0 :         tapdisk_stats_field(st, "kicks", "[");
     647                 :          0 :         tapdisk_stats_val(st, "llu", tap->stats.kicks.in);
     648                 :          0 :         tapdisk_stats_val(st, "llu", tap->stats.kicks.out);
     649                 :          0 :         tapdisk_stats_leave(st, ']');
     650                 :          0 : }

Generated by: LCOV version 1.13