LCOV - code coverage report
Current view: top level - drivers - block-llcache.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 169 0.0 %
Date: 2025-02-07 10:27:58 Functions: 0 19 0.0 %
Branches: 0 78 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 <errno.h>
      36                 :            : 
      37                 :            : #include "tapdisk.h"
      38                 :            : #include "tapdisk-vbd.h"
      39                 :            : #include "tapdisk-driver.h"
      40                 :            : #include "tapdisk-interface.h"
      41                 :            : #include "tapdisk-disktype.h"
      42                 :            : 
      43                 :            : #define DBG(_f, _a...)  tlog_syslog(TLOG_DBG, _f, ##_a)
      44                 :            : #define INFO(_f, _a...) tlog_syslog(TLOG_INFO, _f, ##_a)
      45                 :            : #define WARN(_f, _a...) tlog_syslog(TLOG_WARN, "WARNING: "_f "in %s:%d", \
      46                 :            :                                     ##_a, __func__, __LINE__)
      47                 :            : 
      48                 :            : #define BUG()           td_panic()
      49                 :            : #define BUG_ON(_cond)   if (unlikely(_cond)) { td_panic(); }
      50                 :            : #define WARN_ON(_p)     if (unlikely(_cond)) { WARN(_cond); }
      51                 :            : 
      52                 :          0 : int ll_write_error(int curr, int error)
      53                 :            : {
      54 [ #  # ][ #  # ]:          0 :         if (error && (!curr || curr == -ENOSPC))
      55                 :          0 :                 return error;
      56                 :            : 
      57                 :            :         return 0;
      58                 :            : }
      59                 :            : 
      60                 :          0 : void ll_log_switch(int type, int error,
      61                 :            :                    td_image_t *local, td_image_t *shared)
      62                 :            : {
      63                 :          0 :         WARN("WARNING: %s, on %s:%s. Switching to %s:%s.",
      64                 :            :              strerror(-error),
      65                 :            :              tapdisk_disk_types[local->type]->name, local->name,
      66                 :            :              tapdisk_disk_types[shared->type]->name, shared->name);
      67                 :          0 : }
      68                 :            : 
      69                 :            : /*
      70                 :            :  * LLP: Local leaf persistent cache
      71                 :            :  *      -- Persistent write caching in local storage.
      72                 :            :  *
      73                 :            :  *    VBD
      74                 :            :  *      \
      75                 :            :  *       +--r/w--> llp+vhd:/local/leaf
      76                 :            :  *        \
      77                 :            :  *         +--r/w--> vhd:/shared/leaf
      78                 :            :  *          \
      79                 :            :  *           +--r/o--> vhd:/shared/parent
      80                 :            :  *
      81                 :            :  * We drive two 'leaf' (r/w) images: One LOCAL (i.e. on local storage,
      82                 :            :  * unreliable and prone to out-of-space failures), and one SHARED
      83                 :            :  * (i.e. in shared storage with plenty of physical backing).
      84                 :            :  *
      85                 :            :  * All images are on a linear read chain: LOCAL inherits from SHARED,
      86                 :            :  * which inherits from a shared master image. This filter driver
      87                 :            :  * aggregates LOCAL. SHARED is our immediate parent, forced into R/W
      88                 :            :  * mode.
      89                 :            :  *
      90                 :            :  * Unless LOCAL failed, reads are issued to LOCAL, to save shared
      91                 :            :  * storage bandwidth. In case of failure, SHARED provides continued
      92                 :            :  * VDI consistency.
      93                 :            :  *
      94                 :            :  */
      95                 :            : enum {
      96                 :            :         LLP_MIRROR = 1,
      97                 :            :         /*
      98                 :            :          * LLP_MIRROR:
      99                 :            :          *
     100                 :            :          * Writes are mirrored to both LOCAL and SHARED. Reads are
     101                 :            :          * issued to LOCAL.
     102                 :            :          *
     103                 :            :          * Failure to write LOCAL are recoverable. The driver will
     104                 :            :          * transition to LLP_SHARED.
     105                 :            :          *
     106                 :            :          * Failure to write SHARED is irrecoverable, and signaled to
     107                 :            :          * the original issuer.
     108                 :            :          */
     109                 :            : 
     110                 :            :         LLP_SHARED = 2,
     111                 :            :         /*
     112                 :            :          * LLP_SHARED:
     113                 :            :          *
     114                 :            :          * Writes are issued to SHARED only. As are reads.
     115                 :            :          *
     116                 :            :          * Failure to write SHARED is irrecoverable.
     117                 :            :          */
     118                 :            : };
     119                 :            : 
     120                 :            : typedef struct llpcache                 td_llpcache_t;
     121                 :            : typedef struct llpcache_request         td_llpcache_req_t;
     122                 :            : #define TD_LLPCACHE_MAX_REQ             (MAX_REQUESTS*2)
     123                 :            : 
     124                 :            : struct llpcache_vreq {
     125                 :            :         enum { LOCAL = 0, SHARED = 1 }  target;
     126                 :            :         td_vbd_request_t                vreq;
     127                 :            : };
     128                 :            : 
     129                 :            : struct llpcache_request {
     130                 :            :         td_request_t            treq;
     131                 :            : 
     132                 :            :         struct td_iovec         iov;
     133                 :            :         int                     error;
     134                 :            : 
     135                 :            :         struct llpcache_vreq    lvr[2];
     136                 :            : 
     137                 :            :         unsigned int            pending;
     138                 :            :         int                     mode;
     139                 :            : };
     140                 :            : 
     141                 :            : struct llpcache {
     142                 :            :         td_image_t             *local;
     143                 :            :         int                     mode;
     144                 :            : 
     145                 :            :         td_llpcache_req_t       reqv[TD_LLPCACHE_MAX_REQ];
     146                 :            :         td_llpcache_req_t      *free[TD_LLPCACHE_MAX_REQ];
     147                 :            :         int                     n_free;
     148                 :            : };
     149                 :            : 
     150                 :            : static td_llpcache_req_t *
     151                 :            : llpcache_alloc_request(td_llpcache_t *s)
     152                 :            : {
     153                 :          0 :         td_llpcache_req_t *req = NULL;
     154                 :            : 
     155         [ #  # ]:          0 :         if (likely(s->n_free))
     156                 :          0 :                 req = s->free[--s->n_free];
     157                 :            : 
     158                 :            :         return req;
     159                 :            : }
     160                 :            : 
     161                 :            : static void
     162                 :            : llpcache_free_request(td_llpcache_t *s, td_llpcache_req_t *req)
     163                 :            : {
     164 [ #  # ][ #  # ]:          0 :         BUG_ON(s->n_free >= TD_LLPCACHE_MAX_REQ);
                 [ #  # ]
     165                 :          0 :         s->free[s->n_free++] = req;
     166                 :            : }
     167                 :            : 
     168                 :            : static void
     169                 :          0 : __llpcache_write_cb(td_vbd_request_t *vreq, int error,
     170                 :            :                    void *token, int final)
     171                 :            : {
     172                 :          0 :         td_llpcache_t *s = token;
     173                 :            :         struct llpcache_vreq *lvr;
     174                 :            :         td_llpcache_req_t *req;
     175                 :            :         int mask;
     176                 :            : 
     177                 :          0 :         lvr = container_of(vreq, struct llpcache_vreq, vreq);
     178                 :          0 :         req = container_of(lvr, td_llpcache_req_t, lvr[lvr->target]);
     179                 :            : 
     180                 :          0 :         mask = 1U << lvr->target;
     181         [ #  # ]:          0 :         BUG_ON(!(req->pending & mask))
     182                 :            : 
     183 [ #  # ][ #  # ]:          0 :         if (lvr->target == LOCAL && error == -ENOSPC) {
     184                 :          0 :                 td_image_t *shared =
     185                 :          0 :                         container_of(req->treq.image->next.next,
     186                 :            :                                     td_image_t, next);
     187                 :          0 :                 ll_log_switch(DISK_TYPE_LLPCACHE, error,
     188                 :            :                               s->local, shared);
     189                 :          0 :                 s->mode = LLP_SHARED;
     190                 :          0 :                 error = 0;
     191                 :            :         }
     192                 :            : 
     193                 :          0 :         req->pending &= ~mask;
     194                 :          0 :         req->error    = ll_write_error(req->error, error);
     195                 :            : 
     196         [ #  # ]:          0 :         if (!req->pending) {
     197                 :            :                 /* FIXME: Make sure this won't retry. */
     198                 :          0 :                 td_complete_request(req->treq, req->error);
     199                 :            :                 llpcache_free_request(s, req);
     200                 :            :         }
     201                 :          0 : }
     202                 :            : 
     203                 :            : /*
     204                 :            :  * NB. Write mirroring. Lacking per-image queues, it's still a
     205                 :            :  * hack. But shall do for now:
     206                 :            :  *
     207                 :            :  *   1. Store the treq, thereby blocking the original vreq.
     208                 :            :  *   2. Reissue, as two clone vreqs. One local, one shared.
     209                 :            :  *   3. Clones seen again then get forwarded.
     210                 :            :  *   4. Treq completes after both vreqs.
     211                 :            :  *
     212                 :            :  * We can recognize clones by matching the vreq->token field.
     213                 :            :  */
     214                 :            : 
     215                 :            : static int
     216                 :          0 : llpcache_requeue_treq(td_llpcache_t *s, td_llpcache_req_t *req, int target)
     217                 :            : {
     218                 :            :         struct llpcache_vreq *lvr;
     219                 :            :         td_vbd_request_t *vreq;
     220                 :            :         int err;
     221                 :            : 
     222                 :          0 :         lvr           = &req->lvr[target];
     223                 :          0 :         lvr->target   = target;
     224                 :            : 
     225                 :          0 :         vreq          = &lvr->vreq;
     226                 :          0 :         vreq->op      = TD_OP_WRITE;
     227                 :          0 :         vreq->sec     = req->treq.sec;
     228                 :          0 :         vreq->iov     = &req->iov;
     229                 :          0 :         vreq->iovcnt  = 1;
     230                 :          0 :         vreq->cb      = __llpcache_write_cb;
     231                 :          0 :         vreq->token   = s;
     232                 :            : 
     233                 :          0 :         err = tapdisk_vbd_queue_request(req->treq.vreq->vbd, vreq);
     234         [ #  # ]:          0 :         if (err)
     235                 :            :                 goto fail;
     236                 :            : 
     237                 :          0 :         req->pending |= 1UL << target;
     238                 :          0 :         return 0;
     239                 :            : 
     240                 :            : fail:
     241         [ #  # ]:          0 :         req->error   = req->error ? : err;
     242                 :          0 :         return err;
     243                 :            : }
     244                 :            : 
     245                 :            : static void
     246                 :          0 : llpcache_fork_write(td_llpcache_t *s, td_request_t treq)
     247                 :            : {
     248                 :            :         td_llpcache_req_t *req;
     249                 :            :         struct td_iovec *iov;
     250                 :            :         int err;
     251                 :            : 
     252                 :          0 :         req = llpcache_alloc_request(s);
     253         [ #  # ]:          0 :         if (!req) {
     254                 :          0 :                 td_complete_request(treq, -EBUSY);
     255                 :          0 :                 return;
     256                 :            :         }
     257                 :            : 
     258                 :            :         memset(req, 0, sizeof(td_llpcache_req_t));
     259                 :            : 
     260                 :          0 :         req->treq     = treq;
     261                 :            : 
     262                 :          0 :         iov           = &req->iov;
     263                 :          0 :         iov->base     = treq.buf;
     264                 :          0 :         iov->secs     = treq.secs;
     265                 :            : 
     266                 :          0 :         err = llpcache_requeue_treq(s, req, LOCAL);
     267         [ #  # ]:          0 :         if (err)
     268                 :            :                 goto fail;
     269                 :            : 
     270                 :          0 :         err = llpcache_requeue_treq(s, req, SHARED);
     271         [ #  # ]:          0 :         if (err)
     272                 :            :                 goto fail;
     273                 :            : 
     274                 :            :         return;
     275                 :            : 
     276                 :            : fail:
     277         [ #  # ]:          0 :         if (!req->pending) {
     278                 :          0 :                 td_complete_request(treq, req->error);
     279                 :            :                 llpcache_free_request(s, req);
     280                 :            :         }
     281                 :            : }
     282                 :            : 
     283                 :            : static void
     284                 :          0 : llpcache_forward_write(td_llpcache_t *s, td_request_t treq)
     285                 :            : {
     286                 :          0 :         const td_vbd_request_t *vreq = treq.vreq;
     287                 :            :         struct llpcache_vreq *lvr;
     288                 :            : 
     289                 :          0 :         lvr = container_of(vreq, struct llpcache_vreq, vreq);
     290                 :            : 
     291      [ #  #  # ]:          0 :         switch (lvr->target) {
     292                 :            :         case SHARED:
     293                 :          0 :                 td_forward_request(treq);
     294                 :          0 :                 break;
     295                 :            :         case LOCAL:
     296                 :          0 :                 td_queue_write(s->local, treq);
     297                 :          0 :                 break;
     298                 :            :         default:
     299                 :          0 :                 BUG();
     300                 :            :         }
     301                 :          0 : }
     302                 :            : 
     303                 :            : static void
     304                 :          0 : llpcache_queue_write(td_driver_t *driver, td_request_t treq)
     305                 :            : {
     306                 :          0 :         td_llpcache_t *s = driver->data;
     307                 :            : 
     308         [ #  # ]:          0 :         if (treq.vreq->token == s)
     309                 :          0 :                 llpcache_forward_write(s, treq);
     310                 :            :         else
     311                 :          0 :                 llpcache_fork_write(s, treq);
     312                 :          0 : }
     313                 :            : 
     314                 :            : static void
     315                 :          0 : llpcache_queue_read(td_driver_t *driver, td_request_t treq)
     316                 :            : {
     317                 :          0 :         td_llpcache_t *s = driver->data;
     318                 :            : 
     319      [ #  #  # ]:          0 :         switch (s->mode) {
     320                 :            :         case LLP_MIRROR:
     321                 :          0 :                 td_queue_read(s->local, treq);
     322                 :            :                 break;
     323                 :            :         case LLP_SHARED:
     324                 :          0 :                 td_forward_request(treq);
     325                 :            :         default:
     326                 :          0 :                 BUG();
     327                 :            :         }
     328                 :          0 : }
     329                 :            : 
     330                 :            : static int
     331                 :          0 : llpcache_close(td_driver_t *driver)
     332                 :            : {
     333                 :          0 :         td_llpcache_t *s = driver->data;
     334                 :            : 
     335 [ #  # ][ #  # ]:          0 :         if (s->local) {
     336                 :          0 :                 tapdisk_image_close(s->local);
     337                 :          0 :                 s->local = NULL;
     338                 :            :         }
     339                 :            : 
     340                 :          0 :         return 0;
     341                 :            : }
     342                 :            : 
     343                 :            : static int
     344                 :          0 : llpcache_open(td_driver_t *driver, const char *name,
     345                 :            :               struct td_vbd_encryption *encryption, td_flag_t flags)
     346                 :            : {
     347                 :          0 :         td_llpcache_t *s = driver->data;
     348                 :            :         int i, err;
     349                 :            : 
     350                 :          0 :         s->mode = LLP_MIRROR;
     351                 :            : 
     352         [ #  # ]:          0 :         for (i = 0; i < TD_LLPCACHE_MAX_REQ; i++)
     353                 :          0 :                 llpcache_free_request(s, &s->reqv[i]);
     354                 :            : 
     355                 :          0 :         err = tapdisk_image_open(DISK_TYPE_VHD, name, flags, encryption, &s->local);
     356         [ #  # ]:          0 :         if (err)
     357                 :            :                 goto fail;
     358                 :            : 
     359                 :          0 :         driver->info = s->local->driver->info;
     360                 :            : 
     361                 :          0 :         return 0;
     362                 :            : 
     363                 :            : fail:
     364                 :            :         llpcache_close(driver);
     365                 :          0 :         return err;
     366                 :            : }
     367                 :            : 
     368                 :            : static int
     369                 :          0 : llcache_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
     370                 :            : {
     371                 :          0 :         td_llpcache_t *s = driver->data;
     372                 :            :         int err;
     373                 :            : 
     374                 :          0 :         err = td_get_parent_id(s->local, id);
     375         [ #  # ]:          0 :         if (!err)
     376                 :          0 :                 id->flags &= ~TD_OPEN_RDONLY;
     377                 :            : 
     378                 :          0 :         return err;
     379                 :            : }
     380                 :            : 
     381                 :            : static int
     382                 :          0 : llcache_validate_parent(td_driver_t *driver,
     383                 :            :                         td_driver_t *pdriver, td_flag_t flags)
     384                 :            : {
     385                 :          0 :         return -ENOSYS;
     386                 :            : }
     387                 :            : 
     388                 :            : 
     389                 :            : struct tap_disk tapdisk_llpcache = {
     390                 :            :         .disk_type                  = "tapdisk_llpcache",
     391                 :            :         .flags                      = 0,
     392                 :            :         .private_data_size          = sizeof(td_llpcache_t),
     393                 :            :         .td_open                    = llpcache_open,
     394                 :            :         .td_close                   = llpcache_close,
     395                 :            :         .td_queue_read              = llpcache_queue_read,
     396                 :            :         .td_queue_write             = llpcache_queue_write,
     397                 :            :         .td_get_parent_id           = llcache_get_parent_id,
     398                 :            :         .td_validate_parent         = llcache_validate_parent,
     399                 :            : };
     400                 :            : 
     401                 :            : /*
     402                 :            :  * LLE: Local Leaf Ephemeral Cache
     403                 :            :  *      -- Non-persistent write caching in local storage.
     404                 :            :  *
     405                 :            :  *    VBD
     406                 :            :  *      \
     407                 :            :  *       +--r/w--> lle+vhd:/shared/leaf
     408                 :            :  *        \
     409                 :            :  *         +--r/w--> vhd:/local/leaf
     410                 :            :  *          \
     411                 :            :  *           +--r/o--> vhd:/shared/parent
     412                 :            :  *
     413                 :            :  * Note that LOCAL and SHARED chain order differs from LLP. Shared
     414                 :            :  * storage data masks local data.
     415                 :            :  *
     416                 :            :  * This means VDI state in shared storage state alone is
     417                 :            :  * inconsistent. Wherever local is unavailable, SHARED must be
     418                 :            :  * discarded too.
     419                 :            :  */
     420                 :            : enum {
     421                 :            :         LLE_LOCAL = 1,
     422                 :            :         /*
     423                 :            :          * LLE_LOCAL:
     424                 :            :          *
     425                 :            :          * Writes are forwarded to LOCAL only. As are reads. This
     426                 :            :          * reduces network overhead.
     427                 :            :          *
     428                 :            :          * Failure to write LOCAL is recoverable. The driver will
     429                 :            :          * transition to LLE_SHARED.
     430                 :            :          *
     431                 :            :          * Failure to write to shared are irrecoverable and signaled
     432                 :            :          * to the original issuer.
     433                 :            :          */
     434                 :            : 
     435                 :            :         LLE_SHARED = 2,
     436                 :            :         /*
     437                 :            :          * LLE_SHARED:
     438                 :            :          *
     439                 :            :          * Writes are issued to SHARED. As are reads.
     440                 :            :          *
     441                 :            :          * Failure to write to SHARED is irrecoverable.
     442                 :            :          */
     443                 :            : };
     444                 :            : 
     445                 :            : typedef struct llecache                 td_llecache_t;
     446                 :            : typedef struct llecache_request         td_llecache_req_t;
     447                 :            : #define TD_LLECACHE_MAX_REQ             (MAX_REQUESTS*2)
     448                 :            : 
     449                 :            : struct llecache_request {
     450                 :            :         td_llecache_t          *s;
     451                 :            :         td_request_t            treq;
     452                 :            :         int                     pending;
     453                 :            :         int                     error;
     454                 :            : };
     455                 :            : 
     456                 :            : struct llecache {
     457                 :            :         td_image_t             *shared;
     458                 :            :         int                     mode;
     459                 :            : 
     460                 :            :         td_llecache_req_t       reqv[TD_LLECACHE_MAX_REQ];
     461                 :            :         td_llecache_req_t      *free[TD_LLECACHE_MAX_REQ];
     462                 :            :         int                     n_free;
     463                 :            : };
     464                 :            : 
     465                 :            : static td_llecache_req_t *
     466                 :            : llecache_alloc_request(td_llecache_t *s)
     467                 :            : {
     468                 :          0 :         td_llecache_req_t *req = NULL;
     469                 :            : 
     470         [ #  # ]:          0 :         if (likely(s->n_free))
     471                 :          0 :                 req = s->free[--s->n_free];
     472                 :            : 
     473                 :            :         return req;
     474                 :            : }
     475                 :            : 
     476                 :            : static void
     477                 :            : llecache_free_request(td_llecache_t *s, td_llecache_req_t *req)
     478                 :            : {
     479 [ #  # ][ #  # ]:          0 :         BUG_ON(s->n_free >= TD_LLECACHE_MAX_REQ);
     480                 :          0 :         s->free[s->n_free++] = req;
     481                 :            : }
     482                 :            : 
     483                 :            : static int
     484                 :          0 : llecache_close(td_driver_t *driver)
     485                 :            : {
     486                 :          0 :         td_llecache_t *s = driver->data;
     487                 :            : 
     488 [ #  # ][ #  # ]:          0 :         if (s->shared) {
     489                 :          0 :                 tapdisk_image_close(s->shared);
     490                 :          0 :                 s->shared = NULL;
     491                 :            :         }
     492                 :            : 
     493                 :          0 :         return 0;
     494                 :            : }
     495                 :            : 
     496                 :            : static int
     497                 :          0 : llecache_open(td_driver_t *driver, const char *name,
     498                 :            :               struct td_vbd_encryption *encryption, td_flag_t flags)
     499                 :            : {
     500                 :          0 :         td_llecache_t *s = driver->data;
     501                 :            :         int i, err;
     502                 :            : 
     503                 :          0 :         s->mode = LLE_LOCAL;
     504                 :            : 
     505         [ #  # ]:          0 :         for (i = 0; i < TD_LLECACHE_MAX_REQ; i++)
     506                 :          0 :                 llecache_free_request(s, &s->reqv[i]);
     507                 :            : 
     508                 :          0 :         err = tapdisk_image_open(DISK_TYPE_VHD, name, flags, encryption, &s->shared);
     509         [ #  # ]:          0 :         if (err)
     510                 :            :                 goto fail;
     511                 :            : 
     512                 :          0 :         driver->info = s->shared->driver->info;
     513                 :            : 
     514                 :          0 :         return 0;
     515                 :            : 
     516                 :            : fail:
     517                 :            :         llecache_close(driver);
     518                 :          0 :         return err;
     519                 :            : }
     520                 :            : 
     521                 :            : static void
     522                 :          0 : __llecache_write_cb(td_request_t treq, int error)
     523                 :            : {
     524                 :          0 :         td_llecache_req_t *req = treq.cb_data;
     525                 :          0 :         td_llecache_t *s = req->s;
     526                 :            : 
     527         [ #  # ]:          0 :         BUG_ON(req->pending < treq.secs);
     528                 :            : 
     529                 :          0 :         req->pending -= treq.secs;
     530                 :          0 :         req->error    = ll_write_error(req->error, error);
     531                 :            : 
     532         [ #  # ]:          0 :         if (req->pending)
     533                 :          0 :                 return;
     534                 :            : 
     535         [ #  # ]:          0 :         if (req->error == -ENOSPC) {
     536                 :          0 :                 ll_log_switch(DISK_TYPE_LLECACHE, req->error,
     537                 :            :                               treq.image, s->shared);
     538                 :            : 
     539                 :          0 :                 s->mode = LLE_SHARED;
     540                 :          0 :                 td_queue_write(s->shared, req->treq);
     541                 :            : 
     542                 :            :         } else
     543                 :          0 :                 td_complete_request(req->treq, error);
     544                 :            : 
     545                 :            :         llecache_free_request(s, req);
     546                 :            : }
     547                 :            : 
     548                 :            : static void
     549                 :          0 : llecache_forward_write(td_llecache_t *s, td_request_t treq)
     550                 :            : {
     551                 :            :         td_llecache_req_t *req;
     552                 :            :         td_request_t clone;
     553                 :            : 
     554                 :          0 :         req = llecache_alloc_request(s);
     555         [ #  # ]:          0 :         if (!req) {
     556                 :          0 :                 td_complete_request(treq, -EBUSY);
     557                 :          0 :                 return;
     558                 :            :         }
     559                 :            : 
     560                 :            :         memset(req, 0, sizeof(td_llecache_req_t));
     561                 :            : 
     562                 :          0 :         req->treq       = treq;
     563                 :          0 :         req->pending    = treq.secs;
     564                 :          0 :         req->s          = s;
     565                 :            : 
     566                 :          0 :         clone           = treq;
     567                 :          0 :         clone.cb        = __llecache_write_cb;
     568                 :          0 :         clone.cb_data   = req;
     569                 :            : 
     570                 :          0 :         td_forward_request(clone);
     571                 :            : }
     572                 :            : 
     573                 :            : static void
     574                 :          0 : llecache_queue_write(td_driver_t *driver, td_request_t treq)
     575                 :            : {
     576                 :          0 :         td_llecache_t *s = driver->data;
     577                 :            : 
     578      [ #  #  # ]:          0 :         switch (s->mode) {
     579                 :            :         case LLE_LOCAL:
     580                 :          0 :                 llecache_forward_write(s, treq);
     581                 :          0 :                 break;
     582                 :            :         case LLE_SHARED:
     583                 :          0 :                 td_queue_write(s->shared, treq);
     584                 :          0 :                 break;
     585                 :            :         }
     586                 :          0 : }
     587                 :            : 
     588                 :            : static void
     589                 :          0 : llecache_queue_read(td_driver_t *driver, td_request_t treq)
     590                 :            : {
     591                 :          0 :         td_llecache_t *s = driver->data;
     592                 :            : 
     593      [ #  #  # ]:          0 :         switch (s->mode) {
     594                 :            :         case LLE_LOCAL:
     595                 :          0 :                 td_forward_request(treq);
     596                 :          0 :                 break;
     597                 :            :         case LLE_SHARED:
     598                 :          0 :                 td_queue_read(s->shared, treq);
     599                 :          0 :                 break;
     600                 :            :         default:
     601                 :          0 :                 BUG();
     602                 :            :         }
     603                 :          0 : }
     604                 :            : 
     605                 :            : struct tap_disk tapdisk_llecache = {
     606                 :            :         .disk_type                  = "tapdisk_llecache",
     607                 :            :         .flags                      = 0,
     608                 :            :         .private_data_size          = sizeof(td_llecache_t),
     609                 :            :         .td_open                    = llecache_open,
     610                 :            :         .td_close                   = llecache_close,
     611                 :            :         .td_queue_read              = llecache_queue_read,
     612                 :            :         .td_queue_write             = llecache_queue_write,
     613                 :            :         .td_get_parent_id           = llcache_get_parent_id,
     614                 :            :         .td_validate_parent         = llcache_validate_parent,
     615                 :            : };

Generated by: LCOV version 1.13