LCOV - code coverage report
Current view: top level - drivers - block-vindex.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 353 0.0 %
Date: 2025-04-18 11:59:49 Functions: 0 32 0.0 %
Branches: 0 227 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                 :            : #include <fcntl.h>
      37                 :            : #include <unistd.h>
      38                 :            : #include <stdlib.h>
      39                 :            : 
      40                 :            : #include "debug.h"
      41                 :            : #include "tapdisk.h"
      42                 :            : #include "tapdisk-utils.h"
      43                 :            : #include "tapdisk-driver.h"
      44                 :            : #include "tapdisk-server.h"
      45                 :            : #include "tapdisk-interface.h"
      46                 :            : 
      47                 :            : #include "libvhd.h"
      48                 :            : #include "libvhd-index.h"
      49                 :            : 
      50                 :            : #define DBG(_level, _f, _a...)       tlog_write(_level, _f, ##_a)
      51                 :            : #define ERR(_err, _f, _a...)         tlog_error(_err, _f, ##_a)
      52                 :            : #define WARN(_f, _a...)              tlog_write(TLOG_WARN, _f, ##_a)
      53                 :            : 
      54                 :            : #define VHD_INDEX_FILE_POOL_SIZE     12
      55                 :            : #define VHD_INDEX_CACHE_SIZE         4
      56                 :            : #define VHD_INDEX_REQUESTS           (TAPDISK_DATA_REQUESTS + VHD_INDEX_CACHE_SIZE)
      57                 :            : 
      58                 :            : #define VHD_INDEX_BLOCK_READ_PENDING 0x0001
      59                 :            : #define VHD_INDEX_BLOCK_VALID        0x0002
      60                 :            : 
      61                 :            : #define VHD_INDEX_BAT_CLEAR          0
      62                 :            : #define VHD_INDEX_BIT_CLEAR          1
      63                 :            : #define VHD_INDEX_BIT_SET            2
      64                 :            : #define VHD_INDEX_CACHE_MISS         3
      65                 :            : #define VHD_INDEX_META_READ_PENDING  4
      66                 :            : 
      67                 :            : typedef struct vhd_index             vhd_index_t;
      68                 :            : typedef struct vhd_index_block       vhd_index_block_t;
      69                 :            : typedef struct vhd_index_request     vhd_index_request_t;
      70                 :            : typedef struct vhd_index_file_ref    vhd_index_file_ref_t;
      71                 :            : 
      72                 :            : struct vhd_index_request {
      73                 :            :         off64_t                      off;
      74                 :            :         td_request_t                 treq;
      75                 :            :         vhd_index_t                 *index;
      76                 :            :         struct tiocb                 tiocb;
      77                 :            :         struct list_head             next;
      78                 :            :         vhd_index_file_ref_t        *file;
      79                 :            : };
      80                 :            : 
      81                 :            : struct vhd_index_block {
      82                 :            :         uint64_t                     blk;
      83                 :            :         uint32_t                     seqno;
      84                 :            :         td_flag_t                    state;
      85                 :            :         vhdi_block_t                 vhdi_block;
      86                 :            :         int                          table_size;
      87                 :            :         struct list_head             queue;
      88                 :            :         vhd_index_request_t          req;
      89                 :            : };
      90                 :            : 
      91                 :            : struct vhd_index_file_ref {
      92                 :            :         int                          fd;
      93                 :            :         vhdi_file_id_t               fid;
      94                 :            :         uint32_t                     seqno;
      95                 :            :         uint32_t                     refcnt;
      96                 :            : };
      97                 :            : 
      98                 :            : struct vhd_index {
      99                 :            :         char                        *name;
     100                 :            : 
     101                 :            :         vhdi_bat_t                   bat;
     102                 :            :         vhdi_context_t               vhdi;
     103                 :            :         vhdi_file_table_t            files;
     104                 :            : 
     105                 :            :         vhd_index_file_ref_t         fds[VHD_INDEX_FILE_POOL_SIZE];
     106                 :            : 
     107                 :            :         vhd_index_block_t           *cache[VHD_INDEX_CACHE_SIZE];
     108                 :            : 
     109                 :            :         int                          cache_free_cnt;
     110                 :            :         vhd_index_block_t           *cache_free_list[VHD_INDEX_CACHE_SIZE];
     111                 :            :         vhd_index_block_t            cache_list[VHD_INDEX_CACHE_SIZE];
     112                 :            : 
     113                 :            :         int                          requests_free_cnt;
     114                 :            :         vhd_index_request_t         *requests_free_list[VHD_INDEX_REQUESTS];
     115                 :            :         vhd_index_request_t          requests_list[VHD_INDEX_REQUESTS];
     116                 :            : 
     117                 :            :         td_driver_t                 *driver;
     118                 :            : };
     119                 :            : 
     120                 :            : static void vhd_index_complete_meta_read(void *, struct tiocb *, int);
     121                 :            : static void vhd_index_complete_data_read(void *, struct tiocb *, int);
     122                 :            : 
     123                 :            : #define vhd_index_block_for_each_request(_block, _req, _tmp)            \
     124                 :            :         list_for_each_entry_safe((_req), (_tmp), &(_block)->queue, next)
     125                 :            : 
     126                 :            : static inline void
     127                 :            : vhd_index_initialize_request(vhd_index_request_t *req)
     128                 :            : {
     129                 :            :         memset(req, 0, sizeof(vhd_index_request_t));
     130                 :          0 :         INIT_LIST_HEAD(&req->next);
     131                 :            : }
     132                 :            : 
     133                 :            : static inline void
     134                 :          0 : vhd_index_initialize_block(vhd_index_block_t *block)
     135                 :            : {
     136                 :          0 :         block->blk   = 0;
     137                 :          0 :         block->state = 0;
     138                 :          0 :         INIT_LIST_HEAD(&block->queue);
     139                 :          0 :         vhd_index_initialize_request(&block->req);
     140                 :          0 :         memset(block->vhdi_block.table, 0, block->table_size);
     141                 :          0 : }
     142                 :            : 
     143                 :            : static void
     144                 :          0 : vhd_index_init(vhd_index_t *index)
     145                 :            : {
     146                 :            :         int i;
     147                 :            : 
     148                 :            :         memset(index, 0, sizeof(vhd_index_t));
     149                 :            : 
     150                 :          0 :         index->cache_free_cnt = VHD_INDEX_CACHE_SIZE;
     151         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
     152                 :          0 :                 index->cache_free_list[i] = index->cache_list + i;
     153                 :          0 :                 vhd_index_initialize_block(index->cache_free_list[i]);
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         index->requests_free_cnt = VHD_INDEX_REQUESTS;
     157         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_REQUESTS; i++) {
     158                 :          0 :                 index->requests_free_list[i] = index->requests_list + i;
     159                 :          0 :                 vhd_index_initialize_request(index->requests_free_list[i]);
     160                 :            :         }
     161                 :            : 
     162         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
     163                 :          0 :                 index->fds[i].fd = -1;
     164                 :          0 : }
     165                 :            : 
     166                 :            : static int
     167                 :          0 : vhd_index_allocate_cache(vhd_index_t *index)
     168                 :            : {
     169                 :            :         void *buf;
     170                 :            :         int i, err;
     171                 :            :         size_t size;
     172                 :            : 
     173                 :          0 :         size = vhd_bytes_padded(index->vhdi.spb * sizeof(vhdi_entry_t));
     174                 :            : 
     175         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
     176                 :          0 :                 err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
     177         [ #  # ]:          0 :                 if (err)
     178                 :            :                         goto fail;
     179                 :            : 
     180                 :          0 :                 memset(buf, 0, size);
     181                 :          0 :                 index->cache_list[i].vhdi_block.table   = (vhdi_entry_t *)buf;
     182                 :          0 :                 index->cache_list[i].vhdi_block.entries = index->vhdi.spb;
     183                 :          0 :                 index->cache_list[i].table_size         = size;
     184                 :            :         }
     185                 :            : 
     186                 :          0 :         return 0;
     187                 :            : 
     188                 :            : fail:
     189         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
     190                 :          0 :                 free(index->cache_list[i].vhdi_block.table);
     191                 :          0 :                 index->cache_list[i].vhdi_block.table = NULL;
     192                 :            :         }
     193                 :            : 
     194                 :            :         return -ENOMEM;
     195                 :            : }
     196                 :            : 
     197                 :            : static void
     198                 :          0 : vhd_index_free(vhd_index_t *index)
     199                 :            : {
     200                 :            :         int i;
     201                 :            : 
     202         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++)
     203                 :          0 :                 free(index->cache_list[i].vhdi_block.table);
     204                 :            : 
     205         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
     206         [ #  # ]:          0 :                 if (index->fds[i].fd != -1)
     207                 :          0 :                         close(index->fds[i].fd);
     208                 :            : 
     209                 :          0 :         vhdi_file_table_free(&index->files);
     210                 :          0 :         free(index->bat.table);
     211                 :          0 :         free(index->name);
     212                 :          0 : }
     213                 :            : 
     214                 :            : static int
     215                 :          0 : vhd_index_load(vhd_index_t *index)
     216                 :            : {
     217                 :            :         int err;
     218                 :            : 
     219                 :          0 :         err = vhdi_bat_load(index->name, &index->bat);
     220         [ #  # ]:          0 :         if (err)
     221                 :            :                 return err;
     222                 :            : 
     223                 :          0 :         err = vhdi_open(&index->vhdi,
     224                 :          0 :                         index->bat.index_path,
     225                 :            :                         O_RDONLY | O_DIRECT | O_LARGEFILE);
     226         [ #  # ]:          0 :         if (err)
     227                 :            :                 goto fail;
     228                 :            : 
     229                 :          0 :         err = vhdi_file_table_load(index->bat.file_table_path, &index->files);
     230         [ #  # ]:          0 :         if (err) {
     231                 :          0 :                 vhdi_close(&index->vhdi);
     232                 :          0 :                 goto fail;
     233                 :            :         }
     234                 :            : 
     235                 :            :         return 0;
     236                 :            : 
     237                 :            : fail:
     238                 :          0 :         free(index->bat.table);
     239                 :          0 :         memset(&index->bat, 0, sizeof(vhdi_bat_t));
     240                 :          0 :         memset(&index->vhdi, 0, sizeof(vhdi_context_t));
     241                 :          0 :         memset(&index->files, 0, sizeof(vhdi_file_table_t));
     242                 :          0 :         return err;
     243                 :            : }
     244                 :            : 
     245                 :            : static int
     246                 :          0 : vhd_index_open(td_driver_t *driver, const char *name,
     247                 :            :                struct td_vbd_encryption *encryption, td_flag_t flags)
     248                 :            : {
     249                 :            :         int err;
     250                 :            :         vhd_index_t *index;
     251                 :            : 
     252                 :          0 :         index = (vhd_index_t *)driver->data;
     253                 :            : 
     254                 :          0 :         vhd_index_init(index);
     255                 :            : 
     256                 :          0 :         index->name = strdup(name);
     257         [ #  # ]:          0 :         if (!index->name)
     258                 :            :                 return -ENOMEM;
     259                 :            : 
     260                 :          0 :         err = vhd_index_load(index);
     261         [ #  # ]:          0 :         if (err) {
     262                 :          0 :                 free(index->name);
     263                 :          0 :                 return err;
     264                 :            :         }
     265                 :            : 
     266                 :          0 :         err = vhd_index_allocate_cache(index);
     267         [ #  # ]:          0 :         if (err) {
     268                 :          0 :                 vhd_index_free(index);
     269                 :          0 :                 return err;
     270                 :            :         }
     271                 :            : 
     272                 :          0 :         driver->info.size = index->bat.vhd_blocks * index->bat.vhd_block_size;
     273                 :          0 :         driver->info.sector_size = VHD_SECTOR_SIZE;
     274                 :          0 :         driver->info.info = 0;
     275                 :            : 
     276                 :          0 :         index->driver = driver;
     277                 :            : 
     278                 :            :         DPRINTF("opened vhd index %s\n", name);
     279                 :            : 
     280                 :          0 :         return 0;
     281                 :            : }
     282                 :            : 
     283                 :            : static int
     284                 :          0 : vhd_index_close(td_driver_t *driver)
     285                 :            : {
     286                 :            :         vhd_index_t *index;
     287                 :            : 
     288                 :          0 :         index = (vhd_index_t *)driver->data;
     289                 :          0 :         vhdi_close(&index->vhdi);
     290                 :            : 
     291                 :          0 :         DPRINTF("closed vhd index %s\n", index->name);
     292                 :            : 
     293                 :          0 :         vhd_index_free(index);
     294                 :            : 
     295                 :          0 :         return 0;
     296                 :            : }
     297                 :            : 
     298                 :            : static inline void
     299                 :          0 : vhd_index_touch_file_ref(vhd_index_t *index, vhd_index_file_ref_t *ref)
     300                 :            : {
     301                 :            :         int i;
     302                 :            : 
     303 [ #  # ][ #  # ]:          0 :         if (++ref->seqno == 0xFFFFFFFF)
     304 [ #  # ][ #  # ]:          0 :                 for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
     305                 :          0 :                         index->fds[i].seqno >>= 1;
     306                 :          0 : }
     307                 :            : 
     308                 :            : static inline void
     309                 :          0 : vhd_index_get_file_ref(vhd_index_file_ref_t *ref)
     310                 :            : {
     311                 :          0 :         ++ref->refcnt;
     312                 :          0 : }
     313                 :            : 
     314                 :            : static inline void
     315                 :          0 : vhd_index_put_file_ref(vhd_index_file_ref_t *ref)
     316                 :            : {
     317                 :          0 :         --ref->refcnt;
     318                 :          0 : }
     319                 :            : 
     320                 :            : static inline vhd_index_file_ref_t *
     321                 :            : vhd_index_find_lru_file_ref(vhd_index_t *index)
     322                 :            : {
     323                 :            :         int i;
     324                 :            :         uint32_t min;
     325                 :            :         vhd_index_file_ref_t *lru;
     326                 :            : 
     327                 :            :         lru = NULL;
     328                 :            :         min = (uint32_t)-1;
     329                 :            : 
     330         [ #  # ]:          0 :         for (i = 1; i < VHD_INDEX_FILE_POOL_SIZE; i++) {
     331         [ #  # ]:          0 :                 if (index->fds[i].refcnt)
     332                 :          0 :                         continue;
     333                 :            : 
     334 [ #  # ][ #  # ]:          0 :                 if (!lru || index->fds[i].seqno < min) {
     335                 :          0 :                         min = index->fds[i].seqno;
     336                 :          0 :                         lru = index->fds + i;
     337                 :            :                 }
     338                 :            :         }
     339                 :            : 
     340                 :            :         return lru;
     341                 :            : }
     342                 :            : 
     343                 :            : static inline int
     344                 :          0 : vhd_index_open_file(vhd_index_t *index,
     345                 :            :                     vhdi_file_id_t id, vhd_index_file_ref_t *ref)
     346                 :            : {
     347                 :            :         int i;
     348                 :            :         char *path;
     349                 :            : 
     350                 :          0 :         path = NULL;
     351                 :            : 
     352         [ #  # ]:          0 :         for (i = 0; i < index->files.entries; i++)
     353         [ #  # ]:          0 :                 if (index->files.table[i].file_id == id) {
     354                 :          0 :                         path = index->files.table[i].path;
     355                 :          0 :                         break;
     356                 :            :                 }
     357                 :            : 
     358         [ #  # ]:          0 :         if (!path)
     359                 :            :                 return -ENOENT;
     360                 :            : 
     361                 :          0 :         ref->fd = open(path, O_RDONLY | O_DIRECT | O_LARGEFILE);
     362         [ #  # ]:          0 :         if (ref->fd == -1)
     363                 :          0 :                 return -errno;
     364                 :            : 
     365                 :          0 :         ref->fid    = id;
     366                 :          0 :         ref->refcnt = 0;
     367                 :            : 
     368                 :          0 :         return 0;
     369                 :            : }
     370                 :            : 
     371                 :            : static int
     372                 :          0 : vhd_index_get_file(vhd_index_t *index,
     373                 :            :                    vhdi_file_id_t id, vhd_index_file_ref_t **ref)
     374                 :            : {
     375                 :            :         int i, err;
     376                 :            :         vhd_index_file_ref_t *lru;
     377                 :            : 
     378                 :          0 :         *ref = NULL;
     379                 :            : 
     380         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
     381         [ #  # ]:          0 :                 if (id == index->fds[i].fid) {
     382                 :          0 :                         *ref = index->fds + i;
     383                 :          0 :                         vhd_index_touch_file_ref(index, *ref);
     384                 :          0 :                         vhd_index_get_file_ref(*ref);
     385                 :          0 :                         return 0;
     386                 :            :                 }
     387                 :            : 
     388                 :          0 :         lru = vhd_index_find_lru_file_ref(index);
     389         [ #  # ]:          0 :         if (!lru)
     390                 :            :                 return -EBUSY;
     391                 :            : 
     392         [ #  # ]:          0 :         if (lru->fd != -1)
     393                 :          0 :                 close(lru->fd);
     394                 :            : 
     395                 :          0 :         err = vhd_index_open_file(index, id, lru);
     396         [ #  # ]:          0 :         if (err)
     397                 :            :                 goto fail;
     398                 :            : 
     399                 :          0 :         vhd_index_touch_file_ref(index, lru);
     400                 :          0 :         vhd_index_get_file_ref(lru);
     401                 :          0 :         *ref = lru;
     402                 :          0 :         return 0;
     403                 :            : 
     404                 :            : fail:
     405                 :          0 :         lru->fd     = -1;
     406                 :          0 :         lru->fid    = 0;
     407                 :          0 :         lru->refcnt = 0;
     408                 :          0 :         return err;
     409                 :            : }
     410                 :            : 
     411                 :            : static inline vhd_index_request_t *
     412                 :          0 : vhd_index_allocate_request(vhd_index_t *index)
     413                 :            : {
     414                 :            :         vhd_index_request_t *req;
     415                 :            : 
     416         [ #  # ]:          0 :         if (index->requests_free_cnt <= 0)
     417                 :            :                 return NULL;
     418                 :            : 
     419                 :          0 :         req = index->requests_free_list[--index->requests_free_cnt];
     420         [ #  # ]:          0 :         ASSERT(!req->index);
     421                 :            : 
     422                 :            :         return req;
     423                 :            : }
     424                 :            : 
     425                 :            : static inline void
     426                 :          0 : vhd_index_free_request(vhd_index_t *index, vhd_index_request_t *req)
     427                 :            : {
     428                 :          0 :         list_del(&req->next);
     429                 :            :         vhd_index_initialize_request(req);
     430                 :          0 :         index->requests_free_list[index->requests_free_cnt++] = req;
     431                 :          0 : }
     432                 :            : 
     433                 :            : static inline int
     434                 :            : vhd_index_block_valid(vhd_index_block_t *block)
     435                 :            : {
     436                 :          0 :         return (!td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING) &&
     437                 :            :                 td_flag_test(block->state, VHD_INDEX_BLOCK_VALID));
     438                 :            : }
     439                 :            : 
     440                 :            : static inline void
     441                 :          0 : vhd_index_touch_block(vhd_index_t *index, vhd_index_block_t *block)
     442                 :            : {
     443                 :            :         int i;
     444                 :            : 
     445 [ #  # ][ #  # ]:          0 :         if (++block->seqno == 0xFFFFFFFF)
     446 [ #  # ][ #  # ]:          0 :                 for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++)
     447                 :          0 :                         index->cache_list[i].seqno >>= 1;
     448                 :          0 : }
     449                 :            : 
     450                 :            : static inline vhd_index_block_t *
     451                 :          0 : vhd_index_get_lru_block(vhd_index_t *index)
     452                 :            : {
     453                 :            :         int i, idx;
     454                 :            :         uint32_t min;
     455                 :            :         vhd_index_block_t *block, *lru;
     456                 :            : 
     457                 :          0 :         lru = NULL;
     458                 :          0 :         min = (uint32_t)-1;
     459                 :          0 :         idx = 0;
     460                 :            : 
     461         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
     462                 :          0 :                 block = index->cache[i];
     463                 :            : 
     464         [ #  # ]:          0 :                 if (!block)
     465                 :          0 :                         continue;
     466                 :            : 
     467         [ #  # ]:          0 :                 if (td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING))
     468                 :          0 :                         continue;
     469                 :            : 
     470 [ #  # ][ #  # ]:          0 :                 if (!lru || block->seqno < min) {
     471                 :          0 :                         lru = block;
     472                 :          0 :                         min = block->seqno;
     473                 :          0 :                         idx = i;
     474                 :            :                 }
     475                 :            :         }
     476                 :            : 
     477         [ #  # ]:          0 :         if (lru)
     478                 :          0 :                 index->cache[idx] = NULL;
     479                 :            : 
     480                 :          0 :         return lru;
     481                 :            : }
     482                 :            : 
     483                 :            : static inline int
     484                 :          0 : vhd_index_allocate_block(vhd_index_t *index, vhd_index_block_t **block)
     485                 :            : {
     486                 :            :         vhd_index_block_t *b;
     487                 :            : 
     488                 :          0 :         *block = NULL;
     489                 :            : 
     490         [ #  # ]:          0 :         if (index->cache_free_cnt > 0)
     491                 :          0 :                 b = index->cache_free_list[--index->cache_free_cnt];
     492                 :            :         else {
     493                 :          0 :                 b = vhd_index_get_lru_block(index);
     494         [ #  # ]:          0 :                 if (!b)
     495                 :            :                         return -EBUSY;
     496                 :            :         }
     497                 :            : 
     498                 :          0 :         vhd_index_initialize_block(b);
     499                 :          0 :         vhd_index_touch_block(index, b);
     500                 :          0 :         *block = b;
     501                 :            : 
     502                 :          0 :         return 0;
     503                 :            : }
     504                 :            : 
     505                 :            : static int
     506                 :          0 : vhd_index_install_block(vhd_index_t *index,
     507                 :            :                         vhd_index_block_t **block, uint32_t blk)
     508                 :            : {
     509                 :            :         int i, err;
     510                 :            :         vhd_index_block_t *b;
     511                 :            : 
     512                 :          0 :         *block = NULL;
     513                 :            : 
     514                 :          0 :         err = vhd_index_allocate_block(index, &b);
     515         [ #  # ]:          0 :         if (err)
     516                 :          0 :                 return err;
     517                 :            : 
     518                 :          0 :         b->blk = blk;
     519                 :            : 
     520         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++)
     521         [ #  # ]:          0 :                 if (!index->cache[i]) {
     522                 :          0 :                         index->cache[i] = b;
     523                 :          0 :                         break;
     524                 :            :                 }
     525                 :            : 
     526         [ #  # ]:          0 :         ASSERT(i < VHD_INDEX_CACHE_SIZE);
     527                 :          0 :         *block = b;
     528                 :            : 
     529                 :          0 :         return 0;
     530                 :            : }
     531                 :            : 
     532                 :            : static inline vhd_index_block_t *
     533                 :            : vhd_index_get_block(vhd_index_t *index, uint32_t blk)
     534                 :            : {
     535                 :            :         int i;
     536                 :            :         vhd_index_block_t *block;
     537                 :            : 
     538 [ #  # ][ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     539                 :          0 :                 block = index->cache[i];
     540 [ #  # ][ #  # ]:          0 :                 if (!block)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     541                 :          0 :                         continue;
     542                 :            : 
     543 [ #  # ][ #  # ]:          0 :                 if (block->blk == blk)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     544                 :            :                         return block;
     545                 :            :         }
     546                 :            : 
     547                 :            :         return NULL;
     548                 :            : }
     549                 :            : 
     550                 :            : static int
     551                 :          0 : vhd_index_read_cache(vhd_index_t *index, uint64_t sector)
     552                 :            : {
     553                 :            :         uint32_t blk, sec;
     554                 :            :         vhd_index_block_t *block;
     555                 :            : 
     556                 :          0 :         blk = sector / index->vhdi.spb;
     557                 :            : 
     558         [ #  # ]:          0 :         if (blk >= index->bat.vhd_blocks)
     559                 :            :                 return -EINVAL;
     560                 :            : 
     561         [ #  # ]:          0 :         if (index->bat.table[blk] == DD_BLK_UNUSED)
     562                 :            :                 return VHD_INDEX_BAT_CLEAR;
     563                 :            : 
     564                 :          0 :         block = vhd_index_get_block(index, blk);
     565         [ #  # ]:          0 :         if (!block)
     566                 :            :                 return VHD_INDEX_CACHE_MISS;
     567                 :            : 
     568                 :          0 :         vhd_index_touch_block(index, block);
     569                 :            : 
     570         [ #  # ]:          0 :         if (td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING))
     571                 :            :                 return VHD_INDEX_META_READ_PENDING;
     572                 :            : 
     573                 :          0 :         sec = sector % index->vhdi.spb;
     574         [ #  # ]:          0 :         if (block->vhdi_block.table[sec].offset == DD_BLK_UNUSED)
     575                 :            :                 return VHD_INDEX_BIT_CLEAR;
     576                 :            : 
     577                 :          0 :         return VHD_INDEX_BIT_SET;
     578                 :            : }
     579                 :            : 
     580                 :            : static int
     581                 :          0 : vhd_index_read_cache_span(vhd_index_t *index,
     582                 :            :                           uint64_t sector, int secs, int value)
     583                 :            : {
     584                 :            :         int i;
     585                 :            :         uint32_t blk, sec;
     586                 :            :         vhd_index_block_t *block;
     587                 :            : 
     588                 :          0 :         blk = sector / index->vhdi.spb;
     589                 :          0 :         sec = sector % index->vhdi.spb;
     590                 :            : 
     591         [ #  # ]:          0 :         ASSERT(blk < index->bat.vhd_blocks);
     592                 :            : 
     593                 :          0 :         block = vhd_index_get_block(index, blk);
     594 [ #  # ][ #  # ]:          0 :         ASSERT(block && vhd_index_block_valid(block));
     595                 :            : 
     596 [ #  # ][ #  # ]:          0 :         for (i = 0; i < secs && i + sec < index->vhdi.spb; i++)
     597         [ #  # ]:          0 :                 if (value ^
     598                 :          0 :                     (block->vhdi_block.table[sec + i].offset != DD_BLK_UNUSED))
     599                 :            :                         break;
     600                 :            : 
     601                 :          0 :         return i;
     602                 :            : }
     603                 :            : 
     604                 :            : static int
     605                 :          0 : vhd_index_schedule_meta_read(vhd_index_t *index, uint32_t blk)
     606                 :            : {
     607                 :            :         int err;
     608                 :            :         off64_t offset;
     609                 :            :         vhd_index_block_t *block;
     610                 :            :         vhd_index_request_t *req;
     611                 :            : 
     612         [ #  # ]:          0 :         ASSERT(index->bat.table[blk] != DD_BLK_UNUSED);
     613                 :            : 
     614                 :          0 :         block = vhd_index_get_block(index, blk);
     615         [ #  # ]:          0 :         if (!block) {
     616                 :          0 :                 err = vhd_index_install_block(index, &block, blk);
     617         [ #  # ]:          0 :                 if (err)
     618                 :          0 :                         return err;
     619                 :            :         }
     620                 :            : 
     621                 :          0 :         offset         = vhd_sectors_to_bytes(index->bat.table[blk]);
     622                 :            : 
     623                 :          0 :         req            = &block->req;
     624                 :          0 :         req->index     = index;
     625                 :          0 :         req->treq.sec  = (td_sector_t)blk * index->vhdi.spb;
     626                 :          0 :         req->treq.secs = block->table_size >> VHD_SECTOR_SHIFT;
     627                 :            : 
     628                 :          0 :         td_prep_read(index->driver, &req->tiocb, index->vhdi.fd,
     629                 :          0 :                      (char *)block->vhdi_block.table, block->table_size,
     630                 :            :                      offset, vhd_index_complete_meta_read, req);
     631                 :          0 :         td_queue_tiocb(index->driver, &req->tiocb);
     632                 :            : 
     633                 :          0 :         td_flag_set(block->state, VHD_INDEX_BLOCK_READ_PENDING);
     634                 :            : 
     635                 :          0 :         return 0;
     636                 :            : }
     637                 :            : 
     638                 :            : static int
     639                 :          0 : vhd_index_schedule_data_read(vhd_index_t *index, td_request_t treq)
     640                 :            : {
     641                 :            :         int i, err;
     642                 :            :         size_t size;
     643                 :            :         off64_t offset;
     644                 :            :         uint32_t blk, sec;
     645                 :            :         vhd_index_block_t *block;
     646                 :            :         vhd_index_request_t *req;
     647                 :            :         vhd_index_file_ref_t *file;
     648                 :            : 
     649                 :          0 :         blk   = treq.sec / index->vhdi.spb;
     650                 :          0 :         sec   = treq.sec % index->vhdi.spb;
     651                 :          0 :         block = vhd_index_get_block(index, blk);
     652                 :            : 
     653 [ #  # ][ #  # ]:          0 :         ASSERT(block && vhd_index_block_valid(block));
     654         [ #  # ]:          0 :         for (i = 0; i < treq.secs; i++) {
     655         [ #  # ]:          0 :                 ASSERT(block->vhdi_block.table[sec + i].file_id != 0);
     656         [ #  # ]:          0 :                 ASSERT(block->vhdi_block.table[sec + i].offset != DD_BLK_UNUSED);
     657                 :            :         }
     658                 :            : 
     659                 :          0 :         req = vhd_index_allocate_request(index);
     660         [ #  # ]:          0 :         if (!req)
     661                 :          0 :                 return -EBUSY;
     662                 :            : 
     663                 :          0 :         err = vhd_index_get_file(index,
     664                 :          0 :                                  block->vhdi_block.table[sec].file_id, &file);
     665         [ #  # ]:          0 :         if (err) {
     666                 :          0 :                 vhd_index_free_request(index, req);
     667                 :          0 :                 return err;
     668                 :            :         }
     669                 :            : 
     670                 :          0 :         size       = vhd_sectors_to_bytes(treq.secs);
     671                 :          0 :         offset     = vhd_sectors_to_bytes(block->vhdi_block.table[sec].offset);
     672                 :            : 
     673                 :          0 :         req->file  = file;
     674                 :          0 :         req->treq  = treq;
     675                 :          0 :         req->index = index;
     676                 :          0 :         req->off   = offset;
     677                 :            : 
     678                 :          0 :         td_prep_read(index->driver, &req->tiocb, file->fd, treq.buf, size, offset,
     679                 :            :                      vhd_index_complete_data_read, req);
     680                 :          0 :         td_queue_tiocb(index->driver, &req->tiocb);
     681                 :            : 
     682                 :            :         return 0;
     683                 :            : }
     684                 :            : 
     685                 :            : static int
     686                 :          0 : vhd_index_queue_request(vhd_index_t *index, td_request_t treq)
     687                 :            : {
     688                 :            :         vhd_index_block_t *block;
     689                 :            :         vhd_index_request_t *req;
     690                 :            : 
     691                 :          0 :         req = vhd_index_allocate_request(index);
     692         [ #  # ]:          0 :         if (!req)
     693                 :            :                 return -EBUSY;
     694                 :            : 
     695                 :          0 :         req->treq = treq;
     696                 :            : 
     697                 :          0 :         block = vhd_index_get_block(index, treq.sec / index->vhdi.spb);
     698 [ #  # ][ #  # ]:          0 :         ASSERT(block && td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING));
     699                 :            : 
     700                 :          0 :         list_add_tail(&req->next, &block->queue);
     701                 :          0 :         return 0;
     702                 :            : }
     703                 :            : 
     704                 :            : static void
     705                 :          0 : vhd_index_queue_read(td_driver_t *driver, td_request_t treq)
     706                 :            : {
     707                 :            :         vhd_index_t *index;
     708                 :            : 
     709                 :          0 :         index = (vhd_index_t *)driver->data;
     710                 :            : 
     711         [ #  # ]:          0 :         while (treq.secs) {
     712                 :            :                 int err;
     713                 :            :                 td_request_t clone;
     714                 :            : 
     715                 :          0 :                 err   = 0;
     716                 :          0 :                 clone = treq;
     717                 :            : 
     718   [ #  #  #  #  :          0 :                 switch (vhd_index_read_cache(index, clone.sec)) {
                #  #  # ]
     719                 :            :                 case -EINVAL:
     720                 :            :                         err = -EINVAL;
     721                 :            :                         goto fail;
     722                 :            : 
     723                 :            :                 case VHD_INDEX_BAT_CLEAR:
     724                 :          0 :                         clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb));
     725                 :          0 :                         td_forward_request(clone);
     726                 :            :                         break;
     727                 :            : 
     728                 :            :                 case VHD_INDEX_BIT_CLEAR:
     729                 :          0 :                         clone.secs = vhd_index_read_cache_span(index, clone.sec, clone.secs, 0);
     730                 :          0 :                         td_forward_request(clone);
     731                 :            :                         break;
     732                 :            : 
     733                 :            :                 case VHD_INDEX_BIT_SET:
     734                 :          0 :                         clone.secs = vhd_index_read_cache_span(index, clone.sec, clone.secs, 1);
     735                 :          0 :                         err = vhd_index_schedule_data_read(index, clone);
     736         [ #  # ]:          0 :                         if (err)
     737                 :            :                                 goto fail;
     738                 :            :                         break;
     739                 :            : 
     740                 :            :                 case VHD_INDEX_CACHE_MISS:
     741                 :          0 :                         err = vhd_index_schedule_meta_read(index, clone.sec / index->vhdi.spb);
     742         [ #  # ]:          0 :                         if (err)
     743                 :            :                                 goto fail;
     744                 :            : 
     745                 :          0 :                         clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb));
     746                 :          0 :                         vhd_index_queue_request(index, clone);
     747                 :            :                         break;
     748                 :            : 
     749                 :            :                 case VHD_INDEX_META_READ_PENDING:
     750                 :          0 :                         clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb));
     751                 :          0 :                         err = vhd_index_queue_request(index, clone);
     752         [ #  # ]:          0 :                         if (err)
     753                 :            :                                 goto fail;
     754                 :            :                         break;
     755                 :            :                 }
     756                 :            : 
     757                 :          0 :                 treq.sec  += clone.secs;
     758                 :          0 :                 treq.secs -= clone.secs;
     759                 :          0 :                 treq.buf  += vhd_sectors_to_bytes(clone.secs);
     760                 :          0 :                 continue;
     761                 :            : 
     762                 :            :         fail:
     763                 :          0 :                 clone.secs = treq.secs;
     764                 :          0 :                 td_complete_request(clone, err);
     765                 :          0 :                 break;
     766                 :            :         }
     767                 :          0 : }
     768                 :            : 
     769                 :            : static void
     770                 :          0 : vhd_index_queue_write(td_driver_t *driver, td_request_t treq)
     771                 :            : {
     772                 :          0 :         td_complete_request(treq, -EPERM);
     773                 :          0 : }
     774                 :            : 
     775                 :            : static inline void
     776                 :          0 : vhd_index_signal_completion(vhd_index_t *index,
     777                 :            :                             vhd_index_request_t *req, int err)
     778                 :            : {
     779                 :          0 :         td_complete_request(req->treq, err);
     780                 :          0 :         vhd_index_put_file_ref(req->file);
     781                 :          0 :         vhd_index_free_request(index, req);
     782                 :          0 : }
     783                 :            : 
     784                 :            : static void
     785                 :          0 : vhd_index_complete_meta_read(void *arg, struct tiocb *tiocb, int err)
     786                 :            : {
     787                 :            :         int i;
     788                 :            :         uint32_t blk;
     789                 :            :         td_request_t treq;
     790                 :            :         vhd_index_t *index;
     791                 :            :         vhd_index_block_t *block;
     792                 :            :         vhd_index_request_t *req, *r, *tmp;
     793                 :            : 
     794                 :          0 :         req   = (vhd_index_request_t *)arg;
     795                 :          0 :         index = req->index;
     796                 :            : 
     797                 :          0 :         blk   = req->treq.sec / index->vhdi.spb;
     798                 :          0 :         block = vhd_index_get_block(index, blk);
     799 [ #  # ][ #  # ]:          0 :         ASSERT(block && td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING));
     800                 :          0 :         td_flag_clear(block->state, VHD_INDEX_BLOCK_READ_PENDING);
     801                 :            : 
     802         [ #  # ]:          0 :         if (err) {
     803                 :          0 :                 memset(block->vhdi_block.table, 0, block->table_size);
     804         [ #  # ]:          0 :                 vhd_index_block_for_each_request(block, r, tmp)
     805                 :          0 :                         vhd_index_signal_completion(index, r, err);
     806                 :          0 :                 return;
     807                 :            :         }
     808                 :            : 
     809         [ #  # ]:          0 :         for (i = 0; i < block->vhdi_block.entries; i++)
     810                 :          0 :                 vhdi_entry_in(block->vhdi_block.table + i);
     811                 :            : 
     812                 :          0 :         td_flag_set(block->state, VHD_INDEX_BLOCK_VALID);
     813                 :            : 
     814         [ #  # ]:          0 :         vhd_index_block_for_each_request(block, r, tmp) {
     815                 :          0 :                 treq = r->treq;
     816                 :          0 :                 vhd_index_free_request(index, r);
     817                 :          0 :                 vhd_index_queue_read(index->driver, treq);
     818                 :            :         }
     819                 :            : }
     820                 :            : 
     821                 :            : static void
     822                 :          0 : vhd_index_complete_data_read(void *arg, struct tiocb *tiocb, int err)
     823                 :            : {
     824                 :            :         vhd_index_t *index;
     825                 :            :         vhd_index_request_t *req;
     826                 :            : 
     827                 :          0 :         req   = (vhd_index_request_t *)arg;
     828                 :          0 :         index = req->index;
     829                 :            : 
     830                 :          0 :         vhd_index_signal_completion(index, req, err);
     831                 :          0 : }
     832                 :            : 
     833                 :            : static int
     834                 :          0 : vhd_index_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
     835                 :            : {
     836                 :          0 :         return -EINVAL;
     837                 :            : }
     838                 :            : 
     839                 :            : static int
     840                 :          0 : vhd_index_validate_parent(td_driver_t *driver,
     841                 :            :                           td_driver_t *parent, td_flag_t flags)
     842                 :            : {
     843                 :          0 :         return -EINVAL;
     844                 :            : }
     845                 :            : 
     846                 :            : static void
     847                 :          0 : vhd_index_debug(td_driver_t *driver)
     848                 :            : {
     849                 :            :         int i;
     850                 :            :         vhd_index_t *index;
     851                 :            : 
     852                 :          0 :         index = (vhd_index_t *)driver->data;
     853                 :            : 
     854                 :          0 :         WARN("VHD INDEX %s\n", index->name);
     855                 :          0 :         WARN("FILES:\n");
     856         [ #  # ]:          0 :         for (i = 0; i < index->files.entries; i++) {
     857                 :            :                 int j, fd, refcnt;
     858                 :            : 
     859                 :            :                 fd     = -1;
     860                 :            :                 refcnt = 0;
     861                 :            : 
     862         [ #  # ]:          0 :                 for (j = 0; j < VHD_INDEX_FILE_POOL_SIZE; j++)
     863         [ #  # ]:          0 :                         if (index->fds[j].fid == index->files.table[i].file_id) {
     864                 :          0 :                                 fd     = index->fds[j].fd;
     865                 :          0 :                                 refcnt = index->fds[j].refcnt;
     866                 :            :                         }
     867                 :            : 
     868                 :          0 :                 WARN("%s %u %d %d\n",
     869                 :            :                      index->files.table[i].path,
     870                 :            :                      index->files.table[i].file_id,
     871                 :            :                      fd, refcnt);
     872                 :            :         }
     873                 :            : 
     874                 :          0 :         WARN("REQUESTS:\n");
     875         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_REQUESTS; i++) {
     876                 :            :                 vhd_index_request_t *req;
     877                 :            : 
     878                 :          0 :                 req = index->requests_list + i;
     879                 :            : 
     880         [ #  # ]:          0 :                 if (!req->index)
     881                 :          0 :                         continue;
     882                 :            : 
     883                 :          0 :                 WARN("%d: buf: %p, sec: 0x%08"PRIx64", secs: 0x%04x, "
     884                 :            :                      "fid: %u, off: 0x%016"PRIx64"\n", i, req->treq.buf,
     885                 :            :                      req->treq.sec, req->treq.secs, req->file->fid, req->off);
     886                 :            :         }
     887                 :            : 
     888                 :          0 :         WARN("BLOCKS:\n");
     889         [ #  # ]:          0 :         for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
     890                 :            :                 int queued;
     891                 :            :                 vhd_index_block_t *block;
     892                 :            :                 vhd_index_request_t *req, *tmp;
     893                 :            : 
     894                 :          0 :                 queued = 0;
     895                 :          0 :                 block  = index->cache[i];
     896                 :            : 
     897         [ #  # ]:          0 :                 if (!block)
     898                 :          0 :                         continue;
     899                 :            : 
     900         [ #  # ]:          0 :                 vhd_index_block_for_each_request(block, req, tmp)
     901                 :          0 :                         ++queued;
     902                 :            : 
     903                 :          0 :                 WARN("%d: blk: 0x%08"PRIx64", state: 0x%08x, queued: %d\n",
     904                 :            :                      i, block->blk, block->state, queued);
     905                 :            :         }
     906                 :          0 : }
     907                 :            : 
     908                 :            : struct tap_disk tapdisk_vhd_index = {
     909                 :            :         .disk_type                = "tapdisk_vhd_index",
     910                 :            :         .flags                    = 0,
     911                 :            :         .private_data_size        = sizeof(vhd_index_t),
     912                 :            :         .td_open                  = vhd_index_open,
     913                 :            :         .td_close                 = vhd_index_close,
     914                 :            :         .td_queue_read            = vhd_index_queue_read,
     915                 :            :         .td_queue_write           = vhd_index_queue_write,
     916                 :            :         .td_get_parent_id         = vhd_index_get_parent_id,
     917                 :            :         .td_validate_parent       = vhd_index_validate_parent,
     918                 :            :         .td_debug                 = vhd_index_debug,
     919                 :            : };

Generated by: LCOV version 1.13