Print this page
    
10592 misc. metaslab and vdev related ZoL bug fixes
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed by: George Melikov <mail@gmelikov.ru>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: Pavel Zakharov <pavel.zakharov@delphix.com>
Reviewed by: Tony Hutter <hutter2@llnl.gov>
Reviewed by: Kody Kantor <kody.kantor@joyent.com>
Approved by: Dan McDonald <danmcd@joyent.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/zfs/vdev_indirect_mapping.c
          +++ new/usr/src/uts/common/fs/zfs/vdev_indirect_mapping.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * This file and its contents are supplied under the terms of the
   5    5   * Common Development and Distribution License ("CDDL"), version 1.0.
   6    6   * You may only use this file in accordance with the terms of version
   7    7   * 1.0 of the CDDL.
   8    8   *
   9    9   * A full copy of the text of the CDDL should have accompanied this
  10   10   * source.  A copy of the CDDL is also available via the Internet at
  11   11   * http://www.illumos.org/license/CDDL.
  12   12   *
  13   13   * CDDL HEADER END
  14   14   */
  15   15  
  16   16  /*
  17   17   * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
  18   18   */
  19   19  
  20   20  #include <sys/dmu_tx.h>
  21   21  #include <sys/dsl_pool.h>
  22   22  #include <sys/spa.h>
  23   23  #include <sys/vdev_impl.h>
  24   24  #include <sys/vdev_indirect_mapping.h>
  25   25  #include <sys/zfeature.h>
  26   26  #include <sys/dmu_objset.h>
  27   27  
  28   28  static boolean_t
  29   29  vdev_indirect_mapping_verify(vdev_indirect_mapping_t *vim)
  30   30  {
  31   31          ASSERT(vim != NULL);
  32   32  
  33   33          ASSERT(vim->vim_object != 0);
  34   34          ASSERT(vim->vim_objset != NULL);
  35   35          ASSERT(vim->vim_phys != NULL);
  36   36          ASSERT(vim->vim_dbuf != NULL);
  37   37  
  38   38          EQUIV(vim->vim_phys->vimp_num_entries > 0,
  39   39              vim->vim_entries != NULL);
  40   40          if (vim->vim_phys->vimp_num_entries > 0) {
  41   41                  vdev_indirect_mapping_entry_phys_t *last_entry =
  42   42                      &vim->vim_entries[vim->vim_phys->vimp_num_entries - 1];
  43   43                  uint64_t offset = DVA_MAPPING_GET_SRC_OFFSET(last_entry);
  44   44                  uint64_t size = DVA_GET_ASIZE(&last_entry->vimep_dst);
  45   45  
  46   46                  ASSERT3U(vim->vim_phys->vimp_max_offset, >=, offset + size);
  47   47          }
  48   48          if (vim->vim_havecounts) {
  49   49                  ASSERT(vim->vim_phys->vimp_counts_object != 0);
  50   50          }
  51   51  
  52   52          return (B_TRUE);
  53   53  }
  54   54  
  55   55  uint64_t
  56   56  vdev_indirect_mapping_num_entries(vdev_indirect_mapping_t *vim)
  57   57  {
  58   58          ASSERT(vdev_indirect_mapping_verify(vim));
  59   59  
  60   60          return (vim->vim_phys->vimp_num_entries);
  61   61  }
  62   62  
  63   63  uint64_t
  64   64  vdev_indirect_mapping_max_offset(vdev_indirect_mapping_t *vim)
  65   65  {
  66   66          ASSERT(vdev_indirect_mapping_verify(vim));
  67   67  
  68   68          return (vim->vim_phys->vimp_max_offset);
  69   69  }
  70   70  
  71   71  uint64_t
  72   72  vdev_indirect_mapping_object(vdev_indirect_mapping_t *vim)
  73   73  {
  74   74          ASSERT(vdev_indirect_mapping_verify(vim));
  75   75  
  76   76          return (vim->vim_object);
  77   77  }
  78   78  
  79   79  uint64_t
  80   80  vdev_indirect_mapping_bytes_mapped(vdev_indirect_mapping_t *vim)
  81   81  {
  82   82          ASSERT(vdev_indirect_mapping_verify(vim));
  83   83  
  84   84          return (vim->vim_phys->vimp_bytes_mapped);
  85   85  }
  86   86  
  87   87  /*
  88   88   * The length (in bytes) of the mapping object array in memory and
  89   89   * (logically) on disk.
  90   90   *
  91   91   * Note that unlike most of our accessor functions,
  92   92   * we don't assert that the struct is consistent; therefore it can be
  93   93   * called while there may be concurrent changes, if we don't care about
  94   94   * the value being immediately stale (e.g. from spa_removal_get_stats()).
  95   95   */
  96   96  uint64_t
  97   97  vdev_indirect_mapping_size(vdev_indirect_mapping_t *vim)
  98   98  {
  99   99          return (vim->vim_phys->vimp_num_entries * sizeof (*vim->vim_entries));
 100  100  }
 101  101  
 102  102  /*
 103  103   * Compare an offset with an indirect mapping entry; there are three
 104  104   * possible scenarios:
 105  105   *
 106  106   *     1. The offset is "less than" the mapping entry; meaning the
 107  107   *        offset is less than the source offset of the mapping entry. In
 108  108   *        this case, there is no overlap between the offset and the
 109  109   *        mapping entry and -1 will be returned.
 110  110   *
 111  111   *     2. The offset is "greater than" the mapping entry; meaning the
 112  112   *        offset is greater than the mapping entry's source offset plus
 113  113   *        the entry's size. In this case, there is no overlap between
 114  114   *        the offset and the mapping entry and 1 will be returned.
 115  115   *
 116  116   *        NOTE: If the offset is actually equal to the entry's offset
 117  117   *        plus size, this is considered to be "greater" than the entry,
 118  118   *        and this case applies (i.e. 1 will be returned). Thus, the
 119  119   *        entry's "range" can be considered to be inclusive at its
 120  120   *        start, but exclusive at its end: e.g. [src, src + size).
 121  121   *
 122  122   *     3. The last case to consider is if the offset actually falls
 123  123   *        within the mapping entry's range. If this is the case, the
 124  124   *        offset is considered to be "equal to" the mapping entry and
 125  125   *        0 will be returned.
 126  126   *
 127  127   *        NOTE: If the offset is equal to the entry's source offset,
 128  128   *        this case applies and 0 will be returned. If the offset is
 129  129   *        equal to the entry's source plus its size, this case does
 130  130   *        *not* apply (see "NOTE" above for scenario 2), and 1 will be
 131  131   *        returned.
 132  132   */
 133  133  static int
 134  134  dva_mapping_overlap_compare(const void *v_key, const void *v_array_elem)
 135  135  {
 136  136          const uint64_t *key = v_key;
 137  137          const vdev_indirect_mapping_entry_phys_t *array_elem =
 138  138              v_array_elem;
 139  139          uint64_t src_offset = DVA_MAPPING_GET_SRC_OFFSET(array_elem);
 140  140  
 141  141          if (*key < src_offset) {
 142  142                  return (-1);
 143  143          } else if (*key < src_offset + DVA_GET_ASIZE(&array_elem->vimep_dst)) {
 144  144                  return (0);
 145  145          } else {
 146  146                  return (1);
 147  147          }
 148  148  }
 149  149  
 150  150  /*
 151  151   * Returns the mapping entry for the given offset.
 152  152   *
 153  153   * It's possible that the given offset will not be in the mapping table
 154  154   * (i.e. no mapping entries contain this offset), in which case, the
 155  155   * return value value depends on the "next_if_missing" parameter.
 156  156   *
 157  157   * If the offset is not found in the table and "next_if_missing" is
 158  158   * B_FALSE, then NULL will always be returned. The behavior is intended
 159  159   * to allow consumers to get the entry corresponding to the offset
 160  160   * parameter, iff the offset overlaps with an entry in the table.
 161  161   *
 162  162   * If the offset is not found in the table and "next_if_missing" is
 163  163   * B_TRUE, then the entry nearest to the given offset will be returned,
 164  164   * such that the entry's source offset is greater than the offset
 165  165   * passed in (i.e. the "next" mapping entry in the table is returned, if
 166  166   * the offset is missing from the table). If there are no entries whose
 167  167   * source offset is greater than the passed in offset, NULL is returned.
 168  168   */
 169  169  static vdev_indirect_mapping_entry_phys_t *
 170  170  vdev_indirect_mapping_entry_for_offset_impl(vdev_indirect_mapping_t *vim,
 171  171      uint64_t offset, boolean_t next_if_missing)
 172  172  {
 173  173          ASSERT(vdev_indirect_mapping_verify(vim));
 174  174          ASSERT(vim->vim_phys->vimp_num_entries > 0);
 175  175  
 176  176          vdev_indirect_mapping_entry_phys_t *entry = NULL;
 177  177  
 178  178          uint64_t last = vim->vim_phys->vimp_num_entries - 1;
 179  179          uint64_t base = 0;
 180  180  
 181  181          /*
 182  182           * We don't define these inside of the while loop because we use
 183  183           * their value in the case that offset isn't in the mapping.
 184  184           */
 185  185          uint64_t mid;
 186  186          int result;
 187  187  
 188  188          while (last >= base) {
 189  189                  mid = base + ((last - base) >> 1);
 190  190  
 191  191                  result = dva_mapping_overlap_compare(&offset,
 192  192                      &vim->vim_entries[mid]);
 193  193  
 194  194                  if (result == 0) {
 195  195                          entry = &vim->vim_entries[mid];
 196  196                          break;
 197  197                  } else if (result < 0) {
 198  198                          last = mid - 1;
 199  199                  } else {
 200  200                          base = mid + 1;
 201  201                  }
 202  202          }
 203  203  
 204  204          if (entry == NULL && next_if_missing) {
 205  205                  ASSERT3U(base, ==, last + 1);
 206  206                  ASSERT(mid == base || mid == last);
 207  207                  ASSERT3S(result, !=, 0);
 208  208  
 209  209                  /*
 210  210                   * The offset we're looking for isn't actually contained
 211  211                   * in the mapping table, thus we need to return the
 212  212                   * closest mapping entry that is greater than the
 213  213                   * offset. We reuse the result of the last comparison,
 214  214                   * comparing the mapping entry at index "mid" and the
 215  215                   * offset. The offset is guaranteed to lie between
 216  216                   * indices one less than "mid", and one greater than
 217  217                   * "mid"; we just need to determine if offset is greater
 218  218                   * than, or less than the mapping entry contained at
 219  219                   * index "mid".
 220  220                   */
 221  221  
 222  222                  uint64_t index;
 223  223                  if (result < 0)
 224  224                          index = mid;
 225  225                  else
 226  226                          index = mid + 1;
 227  227  
 228  228                  ASSERT3U(index, <=, vim->vim_phys->vimp_num_entries);
 229  229  
 230  230                  if (index == vim->vim_phys->vimp_num_entries) {
 231  231                          /*
 232  232                           * If "index" is past the end of the entries
 233  233                           * array, then not only is the offset not in the
 234  234                           * mapping table, but it's actually greater than
 235  235                           * all entries in the table. In this case, we
 236  236                           * can't return a mapping entry greater than the
 237  237                           * offset (since none exist), so we return NULL.
 238  238                           */
 239  239  
 240  240                          ASSERT3S(dva_mapping_overlap_compare(&offset,
 241  241                              &vim->vim_entries[index - 1]), >, 0);
 242  242  
 243  243                          return (NULL);
 244  244                  } else {
 245  245                          /*
 246  246                           * Just to be safe, we verify the offset falls
 247  247                           * in between the mapping entries at index and
 248  248                           * one less than index. Since we know the offset
 249  249                           * doesn't overlap an entry, and we're supposed
 250  250                           * to return the entry just greater than the
 251  251                           * offset, both of the following tests must be
 252  252                           * true.
 253  253                           */
 254  254                          ASSERT3S(dva_mapping_overlap_compare(&offset,
 255  255                              &vim->vim_entries[index]), <, 0);
 256  256                          IMPLY(index >= 1, dva_mapping_overlap_compare(&offset,
 257  257                              &vim->vim_entries[index - 1]) > 0);
 258  258  
 259  259                          return (&vim->vim_entries[index]);
 260  260                  }
 261  261          } else {
 262  262                  return (entry);
 263  263          }
 264  264  }
 265  265  
 266  266  vdev_indirect_mapping_entry_phys_t *
 267  267  vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim,
 268  268      uint64_t offset)
 269  269  {
 270  270          return (vdev_indirect_mapping_entry_for_offset_impl(vim, offset,
 271  271              B_FALSE));
 272  272  }
 273  273  
 274  274  vdev_indirect_mapping_entry_phys_t *
 275  275  vdev_indirect_mapping_entry_for_offset_or_next(vdev_indirect_mapping_t *vim,
 276  276      uint64_t offset)
 277  277  {
 278  278          return (vdev_indirect_mapping_entry_for_offset_impl(vim, offset,
 279  279              B_TRUE));
 280  280  }
 281  281  
 282  282  void
 283  283  vdev_indirect_mapping_close(vdev_indirect_mapping_t *vim)
 284  284  {
 285  285          ASSERT(vdev_indirect_mapping_verify(vim));
 286  286  
 287  287          if (vim->vim_phys->vimp_num_entries > 0) {
 288  288                  uint64_t map_size = vdev_indirect_mapping_size(vim);
 289  289                  kmem_free(vim->vim_entries, map_size);
 290  290                  vim->vim_entries = NULL;
 291  291          }
 292  292  
 293  293          dmu_buf_rele(vim->vim_dbuf, vim);
 294  294  
 295  295          vim->vim_objset = NULL;
 296  296          vim->vim_object = 0;
 297  297          vim->vim_dbuf = NULL;
 298  298          vim->vim_phys = NULL;
 299  299  
 300  300          kmem_free(vim, sizeof (*vim));
 301  301  }
 302  302  
 303  303  uint64_t
 304  304  vdev_indirect_mapping_alloc(objset_t *os, dmu_tx_t *tx)
 305  305  {
 306  306          uint64_t object;
 307  307          ASSERT(dmu_tx_is_syncing(tx));
 308  308          uint64_t bonus_size = VDEV_INDIRECT_MAPPING_SIZE_V0;
 309  309  
 310  310          if (spa_feature_is_enabled(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
 311  311                  bonus_size = sizeof (vdev_indirect_mapping_phys_t);
 312  312          }
 313  313  
 314  314          object = dmu_object_alloc(os,
 315  315              DMU_OTN_UINT64_METADATA, SPA_OLD_MAXBLOCKSIZE,
 316  316              DMU_OTN_UINT64_METADATA, bonus_size,
 317  317              tx);
 318  318  
 319  319          if (spa_feature_is_enabled(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
 320  320                  dmu_buf_t *dbuf;
 321  321                  vdev_indirect_mapping_phys_t *vimp;
 322  322  
 323  323                  VERIFY0(dmu_bonus_hold(os, object, FTAG, &dbuf));
 324  324                  dmu_buf_will_dirty(dbuf, tx);
 325  325                  vimp = dbuf->db_data;
 326  326                  vimp->vimp_counts_object = dmu_object_alloc(os,
 327  327                      DMU_OTN_UINT32_METADATA, SPA_OLD_MAXBLOCKSIZE,
 328  328                      DMU_OT_NONE, 0, tx);
 329  329                  spa_feature_incr(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
 330  330                  dmu_buf_rele(dbuf, FTAG);
 331  331          }
 332  332  
 333  333          return (object);
 334  334  }
 335  335  
 336  336  
 337  337  vdev_indirect_mapping_t *
 338  338  vdev_indirect_mapping_open(objset_t *os, uint64_t mapping_object)
 339  339  {
 340  340          vdev_indirect_mapping_t *vim = kmem_zalloc(sizeof (*vim), KM_SLEEP);
 341  341          dmu_object_info_t doi;
 342  342          VERIFY0(dmu_object_info(os, mapping_object, &doi));
 343  343  
 344  344          vim->vim_objset = os;
 345  345          vim->vim_object = mapping_object;
 346  346  
 347  347          VERIFY0(dmu_bonus_hold(os, vim->vim_object, vim,
 348  348              &vim->vim_dbuf));
 349  349          vim->vim_phys = vim->vim_dbuf->db_data;
 350  350  
 351  351          vim->vim_havecounts =
 352  352              (doi.doi_bonus_size > VDEV_INDIRECT_MAPPING_SIZE_V0);
 353  353  
 354  354          if (vim->vim_phys->vimp_num_entries > 0) {
 355  355                  uint64_t map_size = vdev_indirect_mapping_size(vim);
 356  356                  vim->vim_entries = kmem_alloc(map_size, KM_SLEEP);
 357  357                  VERIFY0(dmu_read(os, vim->vim_object, 0, map_size,
 358  358                      vim->vim_entries, DMU_READ_PREFETCH));
 359  359          }
 360  360  
 361  361          ASSERT(vdev_indirect_mapping_verify(vim));
 362  362  
 363  363          return (vim);
 364  364  }
 365  365  
 366  366  void
 367  367  vdev_indirect_mapping_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
 368  368  {
 369  369          vdev_indirect_mapping_t *vim = vdev_indirect_mapping_open(os, object);
 370  370          if (vim->vim_havecounts) {
 371  371                  VERIFY0(dmu_object_free(os, vim->vim_phys->vimp_counts_object,
 372  372                      tx));
 373  373                  spa_feature_decr(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
 374  374          }
 375  375          vdev_indirect_mapping_close(vim);
 376  376  
 377  377          VERIFY0(dmu_object_free(os, object, tx));
 378  378  }
 379  379  
 380  380  /*
 381  381   * Append the list of vdev_indirect_mapping_entry_t's to the on-disk
 382  382   * mapping object.  Also remove the entries from the list and free them.
 383  383   * This also implicitly extends the max_offset of the mapping (to the end
 384  384   * of the last entry).
 385  385   */
 386  386  void
 387  387  vdev_indirect_mapping_add_entries(vdev_indirect_mapping_t *vim,
 388  388      list_t *list, dmu_tx_t *tx)
 389  389  {
 390  390          vdev_indirect_mapping_entry_phys_t *mapbuf;
 391  391          uint64_t old_size;
 392  392          uint32_t *countbuf = NULL;
 393  393          vdev_indirect_mapping_entry_phys_t *old_entries;
 394  394          uint64_t old_count;
 395  395          uint64_t entries_written = 0;
 396  396  
 397  397          ASSERT(vdev_indirect_mapping_verify(vim));
 398  398          ASSERT(dmu_tx_is_syncing(tx));
 399  399          ASSERT(dsl_pool_sync_context(dmu_tx_pool(tx)));
 400  400          ASSERT(!list_is_empty(list));
 401  401  
 402  402          old_size = vdev_indirect_mapping_size(vim);
 403  403          old_entries = vim->vim_entries;
 404  404          old_count = vim->vim_phys->vimp_num_entries;
 405  405  
 406  406          dmu_buf_will_dirty(vim->vim_dbuf, tx);
 407  407  
 408  408          mapbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
 409  409          if (vim->vim_havecounts) {
 410  410                  countbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
 411  411                  ASSERT(spa_feature_is_active(vim->vim_objset->os_spa,
 412  412                      SPA_FEATURE_OBSOLETE_COUNTS));
 413  413          }
 414  414          while (!list_is_empty(list)) {
 415  415                  uint64_t i;
 416  416                  /*
 417  417                   * Write entries from the list to the
 418  418                   * vdev_im_object in batches of size SPA_OLD_MAXBLOCKSIZE.
 419  419                   */
 420  420                  for (i = 0; i < SPA_OLD_MAXBLOCKSIZE / sizeof (*mapbuf); i++) {
 421  421                          vdev_indirect_mapping_entry_t *entry =
 422  422                              list_remove_head(list);
 423  423                          if (entry == NULL)
 424  424                                  break;
 425  425  
 426  426                          uint64_t size =
 427  427                              DVA_GET_ASIZE(&entry->vime_mapping.vimep_dst);
 428  428                          uint64_t src_offset =
 429  429                              DVA_MAPPING_GET_SRC_OFFSET(&entry->vime_mapping);
 430  430  
 431  431                          /*
 432  432                           * We shouldn't be adding an entry which is fully
 433  433                           * obsolete.
 434  434                           */
 435  435                          ASSERT3U(entry->vime_obsolete_count, <, size);
 436  436                          IMPLY(entry->vime_obsolete_count != 0,
 437  437                              vim->vim_havecounts);
 438  438  
 439  439                          mapbuf[i] = entry->vime_mapping;
 440  440                          if (vim->vim_havecounts)
 441  441                                  countbuf[i] = entry->vime_obsolete_count;
 442  442  
 443  443                          vim->vim_phys->vimp_bytes_mapped += size;
 444  444                          ASSERT3U(src_offset, >=,
 445  445                              vim->vim_phys->vimp_max_offset);
 446  446                          vim->vim_phys->vimp_max_offset = src_offset + size;
 447  447  
 448  448                          entries_written++;
 449  449  
 450  450                          kmem_free(entry, sizeof (*entry));
 451  451                  }
 452  452                  dmu_write(vim->vim_objset, vim->vim_object,
 453  453                      vim->vim_phys->vimp_num_entries * sizeof (*mapbuf),
 454  454                      i * sizeof (*mapbuf),
 455  455                      mapbuf, tx);
 456  456                  if (vim->vim_havecounts) {
 457  457                          dmu_write(vim->vim_objset,
 458  458                              vim->vim_phys->vimp_counts_object,
 459  459                              vim->vim_phys->vimp_num_entries *
 460  460                              sizeof (*countbuf),
 461  461                              i * sizeof (*countbuf), countbuf, tx);
 462  462                  }
 463  463                  vim->vim_phys->vimp_num_entries += i;
 464  464          }
 465  465          zio_buf_free(mapbuf, SPA_OLD_MAXBLOCKSIZE);
 466  466          if (vim->vim_havecounts)
 467  467                  zio_buf_free(countbuf, SPA_OLD_MAXBLOCKSIZE);
 468  468  
 469  469          /*
 470  470           * Update the entry array to reflect the new entries. First, copy
 471  471           * over any old entries then read back the new entries we just wrote.
 472  472           */
 473  473          uint64_t new_size = vdev_indirect_mapping_size(vim);
 474  474          ASSERT3U(new_size, >, old_size);
 475  475          ASSERT3U(new_size - old_size, ==,
 476  476              entries_written * sizeof (vdev_indirect_mapping_entry_phys_t));
 477  477          vim->vim_entries = kmem_alloc(new_size, KM_SLEEP);
 478  478          if (old_size > 0) {
 479  479                  bcopy(old_entries, vim->vim_entries, old_size);
 480  480                  kmem_free(old_entries, old_size);
 481  481          }
 482  482          VERIFY0(dmu_read(vim->vim_objset, vim->vim_object, old_size,
 483  483              new_size - old_size, &vim->vim_entries[old_count],
 484  484              DMU_READ_PREFETCH));
 485  485  
 486  486          zfs_dbgmsg("txg %llu: wrote %llu entries to "
 487  487              "indirect mapping obj %llu; max offset=0x%llx",
 488  488              (u_longlong_t)dmu_tx_get_txg(tx),
 489  489              (u_longlong_t)entries_written,
 490  490              (u_longlong_t)vim->vim_object,
 491  491              (u_longlong_t)vim->vim_phys->vimp_max_offset);
 492  492  }
 493  493  
 494  494  /*
 495  495   * Increment the relevant counts for the specified offset and length.
 496  496   * The counts array must be obtained from
 497  497   * vdev_indirect_mapping_load_obsolete_counts().
 498  498   */
 499  499  void
 500  500  vdev_indirect_mapping_increment_obsolete_count(vdev_indirect_mapping_t *vim,
 501  501      uint64_t offset, uint64_t length, uint32_t *counts)
 502  502  {
 503  503          vdev_indirect_mapping_entry_phys_t *mapping;
 504  504          uint64_t index;
 505  505  
 506  506          mapping = vdev_indirect_mapping_entry_for_offset(vim,  offset);
 507  507  
 508  508          ASSERT(length > 0);
 509  509          ASSERT3P(mapping, !=, NULL);
 510  510  
 511  511          index = mapping - vim->vim_entries;
 512  512  
 513  513          while (length > 0) {
 514  514                  ASSERT3U(index, <, vdev_indirect_mapping_num_entries(vim));
 515  515  
 516  516                  uint64_t size = DVA_GET_ASIZE(&mapping->vimep_dst);
 517  517                  uint64_t inner_offset = offset -
 518  518                      DVA_MAPPING_GET_SRC_OFFSET(mapping);
 519  519                  VERIFY3U(inner_offset, <, size);
 520  520                  uint64_t inner_size = MIN(length, size - inner_offset);
 521  521  
 522  522                  VERIFY3U(counts[index] + inner_size, <=, size);
 523  523                  counts[index] += inner_size;
 524  524  
 525  525                  offset += inner_size;
 526  526                  length -= inner_size;
 527  527                  mapping++;
 528  528                  index++;
 529  529          }
 530  530  }
 531  531  
 532  532  typedef struct load_obsolete_space_map_arg {
 533  533          vdev_indirect_mapping_t *losma_vim;
 534  534          uint32_t                *losma_counts;
 535  535  } load_obsolete_space_map_arg_t;
 536  536  
 537  537  static int
 538  538  load_obsolete_sm_callback(space_map_entry_t *sme, void *arg)
 539  539  {
 540  540          load_obsolete_space_map_arg_t *losma = arg;
 541  541          ASSERT3S(sme->sme_type, ==, SM_ALLOC);
 542  542  
 543  543          vdev_indirect_mapping_increment_obsolete_count(losma->losma_vim,
 544  544              sme->sme_offset, sme->sme_run, losma->losma_counts);
 545  545  
 546  546          return (0);
 547  547  }
 548  548  
 549  549  /*
  
    | 
      ↓ open down ↓ | 
    549 lines elided | 
    
      ↑ open up ↑ | 
  
 550  550   * Modify the counts (increment them) based on the spacemap.
 551  551   */
 552  552  void
 553  553  vdev_indirect_mapping_load_obsolete_spacemap(vdev_indirect_mapping_t *vim,
 554  554      uint32_t *counts, space_map_t *obsolete_space_sm)
 555  555  {
 556  556          load_obsolete_space_map_arg_t losma;
 557  557          losma.losma_counts = counts;
 558  558          losma.losma_vim = vim;
 559  559          VERIFY0(space_map_iterate(obsolete_space_sm,
      560 +            space_map_length(obsolete_space_sm),
 560  561              load_obsolete_sm_callback, &losma));
 561  562  }
 562  563  
 563  564  /*
 564  565   * Read the obsolete counts from disk, returning them in an array.
 565  566   */
 566  567  uint32_t *
 567  568  vdev_indirect_mapping_load_obsolete_counts(vdev_indirect_mapping_t *vim)
 568  569  {
 569  570          ASSERT(vdev_indirect_mapping_verify(vim));
 570  571  
 571  572          uint64_t counts_size =
 572  573              vim->vim_phys->vimp_num_entries * sizeof (uint32_t);
 573  574          uint32_t *counts = kmem_alloc(counts_size, KM_SLEEP);
 574  575          if (vim->vim_havecounts) {
 575  576                  VERIFY0(dmu_read(vim->vim_objset,
 576  577                      vim->vim_phys->vimp_counts_object,
 577  578                      0, counts_size,
 578  579                      counts, DMU_READ_PREFETCH));
 579  580          } else {
 580  581                  bzero(counts, counts_size);
 581  582          }
 582  583          return (counts);
 583  584  }
 584  585  
 585  586  extern void
 586  587  vdev_indirect_mapping_free_obsolete_counts(vdev_indirect_mapping_t *vim,
 587  588      uint32_t *counts)
 588  589  {
 589  590          ASSERT(vdev_indirect_mapping_verify(vim));
 590  591  
 591  592          kmem_free(counts, vim->vim_phys->vimp_num_entries * sizeof (uint32_t));
 592  593  }
  
    | 
      ↓ open down ↓ | 
    23 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX