Print this page
5056 ZFS deadlock on db_mtx and dn_holds
Reviewed by: Will Andrews <willa@spectralogic.com>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dbuf.c
          +++ new/usr/src/uts/common/fs/zfs/dbuf.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24   24   * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  26   26   * Copyright (c) 2013, Joyent, Inc. All rights reserved.
       27 + * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  27   28   */
  28   29  
  29   30  #include <sys/zfs_context.h>
  30   31  #include <sys/dmu.h>
  31   32  #include <sys/dmu_send.h>
  32   33  #include <sys/dmu_impl.h>
  33   34  #include <sys/dbuf.h>
  34   35  #include <sys/dmu_objset.h>
  35   36  #include <sys/dsl_dataset.h>
  36   37  #include <sys/dsl_dir.h>
↓ open down ↓ 10 lines elided ↑ open up ↑
  47   48  /*
  48   49   * Number of times that zfs_free_range() took the slow path while doing
  49   50   * a zfs receive.  A nonzero value indicates a potential performance problem.
  50   51   */
  51   52  uint64_t zfs_free_range_recv_miss;
  52   53  
  53   54  static void dbuf_destroy(dmu_buf_impl_t *db);
  54   55  static boolean_t dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
  55   56  static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx);
  56   57  
       58 +#ifndef __lint
       59 +extern inline void dmu_buf_init_user(dmu_buf_user_t *dbu,
       60 +    dmu_buf_evict_func_t *evict_func, dmu_buf_t **clear_on_evict_dbufp);
       61 +#endif /* ! __lint */
       62 +
  57   63  /*
  58   64   * Global data structures and functions for the dbuf cache.
  59   65   */
  60   66  static kmem_cache_t *dbuf_cache;
       67 +static taskq_t *dbu_evict_taskq;
  61   68  
  62   69  /* ARGSUSED */
  63   70  static int
  64   71  dbuf_cons(void *vdb, void *unused, int kmflag)
  65   72  {
  66   73          dmu_buf_impl_t *db = vdb;
  67   74          bzero(db, sizeof (dmu_buf_impl_t));
  68   75  
  69   76          mutex_init(&db->db_mtx, NULL, MUTEX_DEFAULT, NULL);
  70   77          cv_init(&db->db_changed, NULL, CV_DEFAULT, NULL);
↓ open down ↓ 137 lines elided ↑ open up ↑
 208  215                  ASSERT(dbf != NULL);
 209  216          }
 210  217          *dbp = db->db_hash_next;
 211  218          db->db_hash_next = NULL;
 212  219          mutex_exit(DBUF_HASH_MUTEX(h, idx));
 213  220          atomic_dec_64(&dbuf_hash_count);
 214  221  }
 215  222  
 216  223  static arc_evict_func_t dbuf_do_evict;
 217  224  
      225 +typedef enum {
      226 +        DBVU_EVICTING,
      227 +        DBVU_NOT_EVICTING
      228 +} dbvu_verify_type_t;
      229 +
 218  230  static void
      231 +dbuf_verify_user(dmu_buf_impl_t *db, dbvu_verify_type_t verify_type)
      232 +{
      233 +#ifdef ZFS_DEBUG
      234 +        int64_t holds;
      235 +
      236 +        if (db->db_user == NULL)
      237 +                return;
      238 +
      239 +        /* Only data blocks support the attachment of user data. */
      240 +        ASSERT(db->db_level == 0);
      241 +
      242 +        /* Clients must resolve a dbuf before attaching user data. */
      243 +        ASSERT(db->db.db_data != NULL);
      244 +        ASSERT3U(db->db_state, ==, DB_CACHED);
      245 +
      246 +        holds = refcount_count(&db->db_holds);
      247 +        if (verify_type == DBVU_EVICTING) {
      248 +                /*
      249 +                 * Immediate eviction occurs when holds == dirtycnt.
      250 +                 * For normal eviction buffers, holds is zero on
      251 +                 * eviction, except when dbuf_fix_old_data() calls
      252 +                 * dbuf_clear_data().  However, the hold count can grow
      253 +                 * during eviction even though db_mtx is held (see
      254 +                 * dmu_bonus_hold() for an example), so we can only
      255 +                 * test the generic invariant that holds >= dirtycnt.
      256 +                 */
      257 +                ASSERT3U(holds, >=, db->db_dirtycnt);
      258 +        } else {
      259 +                if (db->db_immediate_evict == TRUE)
      260 +                        ASSERT3U(holds, >=, db->db_dirtycnt);
      261 +                else
      262 +                        ASSERT3U(holds, >, 0);
      263 +        }
      264 +#endif
      265 +}
      266 +
      267 +static void
 219  268  dbuf_evict_user(dmu_buf_impl_t *db)
 220  269  {
      270 +        dmu_buf_user_t *dbu = db->db_user;
      271 +
 221  272          ASSERT(MUTEX_HELD(&db->db_mtx));
 222  273  
 223      -        if (db->db_level != 0 || db->db_evict_func == NULL)
      274 +        if (dbu == NULL)
 224  275                  return;
 225  276  
 226      -        db->db_evict_func(&db->db, db->db_user_ptr);
 227      -        db->db_user_ptr = NULL;
 228      -        db->db_evict_func = NULL;
      277 +        dbuf_verify_user(db, DBVU_EVICTING);
      278 +        db->db_user = NULL;
      279 +
      280 +#ifdef ZFS_DEBUG
      281 +        if (dbu->dbu_clear_on_evict_dbufp != NULL)
      282 +                *dbu->dbu_clear_on_evict_dbufp = NULL;
      283 +#endif
      284 +
      285 +        /*
      286 +         * Invoke the callback from a taskq to avoid lock order reversals
      287 +         * and limit stack depth.
      288 +         */
      289 +        taskq_dispatch_ent(dbu_evict_taskq, dbu->dbu_evict_func, dbu, 0,
      290 +            &dbu->dbu_tqent);
 229  291  }
 230  292  
 231  293  boolean_t
 232  294  dbuf_is_metadata(dmu_buf_impl_t *db)
 233  295  {
 234  296          if (db->db_level > 0) {
 235  297                  return (B_TRUE);
 236  298          } else {
 237  299                  boolean_t is_metadata;
 238  300  
↓ open down ↓ 40 lines elided ↑ open up ↑
 279  341                  hsize >>= 1;
 280  342                  goto retry;
 281  343          }
 282  344  
 283  345          dbuf_cache = kmem_cache_create("dmu_buf_impl_t",
 284  346              sizeof (dmu_buf_impl_t),
 285  347              0, dbuf_cons, dbuf_dest, NULL, NULL, NULL, 0);
 286  348  
 287  349          for (i = 0; i < DBUF_MUTEXES; i++)
 288  350                  mutex_init(&h->hash_mutexes[i], NULL, MUTEX_DEFAULT, NULL);
      351 +
      352 +        /*
      353 +         * All entries are queued via taskq_dispatch_ent(), so min/maxalloc
      354 +         * configuration is not required.
      355 +         */
      356 +        dbu_evict_taskq = taskq_create("dbu_evict", 1, minclsyspri, 0, 0, 0);
 289  357  }
 290  358  
 291  359  void
 292  360  dbuf_fini(void)
 293  361  {
 294  362          dbuf_hash_table_t *h = &dbuf_hash_table;
 295  363          int i;
 296  364  
 297  365          for (i = 0; i < DBUF_MUTEXES; i++)
 298  366                  mutex_destroy(&h->hash_mutexes[i]);
 299  367          kmem_free(h->hash_table, (h->hash_table_mask + 1) * sizeof (void *));
 300  368          kmem_cache_destroy(dbuf_cache);
      369 +        taskq_destroy(dbu_evict_taskq);
 301  370  }
 302  371  
 303  372  /*
 304  373   * Other stuff.
 305  374   */
 306  375  
 307  376  #ifdef ZFS_DEBUG
 308  377  static void
 309  378  dbuf_verify(dmu_buf_impl_t *db)
 310  379  {
↓ open down ↓ 97 lines elided ↑ open up ↑
 408  477                          for (i = 0; i < db->db.db_size >> 3; i++) {
 409  478                                  ASSERT(buf[i] == 0);
 410  479                          }
 411  480                  }
 412  481          }
 413  482          DB_DNODE_EXIT(db);
 414  483  }
 415  484  #endif
 416  485  
 417  486  static void
      487 +dbuf_clear_data(dmu_buf_impl_t *db)
      488 +{
      489 +        ASSERT(MUTEX_HELD(&db->db_mtx));
      490 +        dbuf_evict_user(db);
      491 +        db->db_buf = NULL;
      492 +        db->db.db_data = NULL;
      493 +        if (db->db_state != DB_NOFILL)
      494 +                db->db_state = DB_UNCACHED;
      495 +}
      496 +
      497 +static void
 418  498  dbuf_set_data(dmu_buf_impl_t *db, arc_buf_t *buf)
 419  499  {
 420  500          ASSERT(MUTEX_HELD(&db->db_mtx));
      501 +        ASSERT(buf != NULL);
      502 +
 421  503          db->db_buf = buf;
 422      -        if (buf != NULL) {
 423      -                ASSERT(buf->b_data != NULL);
 424      -                db->db.db_data = buf->b_data;
 425      -                if (!arc_released(buf))
 426      -                        arc_set_callback(buf, dbuf_do_evict, db);
 427      -        } else {
 428      -                dbuf_evict_user(db);
 429      -                db->db.db_data = NULL;
 430      -                if (db->db_state != DB_NOFILL)
 431      -                        db->db_state = DB_UNCACHED;
 432      -        }
      504 +        ASSERT(buf->b_data != NULL);
      505 +        db->db.db_data = buf->b_data;
      506 +        if (!arc_released(buf))
      507 +                arc_set_callback(buf, dbuf_do_evict, db);
 433  508  }
 434  509  
 435  510  /*
 436  511   * Loan out an arc_buf for read.  Return the loaned arc_buf.
 437  512   */
 438  513  arc_buf_t *
 439  514  dbuf_loan_arcbuf(dmu_buf_impl_t *db)
 440  515  {
 441  516          arc_buf_t *abuf;
 442  517  
↓ open down ↓ 1 lines elided ↑ open up ↑
 444  519          if (arc_released(db->db_buf) || refcount_count(&db->db_holds) > 1) {
 445  520                  int blksz = db->db.db_size;
 446  521                  spa_t *spa = db->db_objset->os_spa;
 447  522  
 448  523                  mutex_exit(&db->db_mtx);
 449  524                  abuf = arc_loan_buf(spa, blksz);
 450  525                  bcopy(db->db.db_data, abuf->b_data, blksz);
 451  526          } else {
 452  527                  abuf = db->db_buf;
 453  528                  arc_loan_inuse_buf(abuf, db);
 454      -                dbuf_set_data(db, NULL);
      529 +                dbuf_clear_data(db);
 455  530                  mutex_exit(&db->db_mtx);
 456  531          }
 457  532          return (abuf);
 458  533  }
 459  534  
 460  535  uint64_t
 461  536  dbuf_whichblock(dnode_t *dn, uint64_t offset)
 462  537  {
 463  538          if (dn->dn_datablkshift) {
 464  539                  return (offset >> dn->dn_datablkshift);
↓ open down ↓ 215 lines elided ↑ open up ↑
 680  755                  cv_wait(&db->db_changed, &db->db_mtx);
 681  756          if (db->db_state == DB_UNCACHED) {
 682  757                  arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
 683  758                  spa_t *spa = db->db_objset->os_spa;
 684  759  
 685  760                  ASSERT(db->db_buf == NULL);
 686  761                  ASSERT(db->db.db_data == NULL);
 687  762                  dbuf_set_data(db, arc_buf_alloc(spa, db->db.db_size, db, type));
 688  763                  db->db_state = DB_FILL;
 689  764          } else if (db->db_state == DB_NOFILL) {
 690      -                dbuf_set_data(db, NULL);
      765 +                dbuf_clear_data(db);
 691  766          } else {
 692  767                  ASSERT3U(db->db_state, ==, DB_CACHED);
 693  768          }
 694  769          mutex_exit(&db->db_mtx);
 695  770  }
 696  771  
 697  772  /*
 698  773   * This is our just-in-time copy function.  It makes a copy of
 699  774   * buffers, that have been modified in a previous transaction
 700  775   * group, before we modify them in the current active group.
↓ open down ↓ 35 lines elided ↑ open up ↑
 736  811                  arc_space_consume(DN_MAX_BONUSLEN, ARC_SPACE_OTHER);
 737  812                  bcopy(db->db.db_data, dr->dt.dl.dr_data, DN_MAX_BONUSLEN);
 738  813          } else if (refcount_count(&db->db_holds) > db->db_dirtycnt) {
 739  814                  int size = db->db.db_size;
 740  815                  arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
 741  816                  spa_t *spa = db->db_objset->os_spa;
 742  817  
 743  818                  dr->dt.dl.dr_data = arc_buf_alloc(spa, size, db, type);
 744  819                  bcopy(db->db.db_data, dr->dt.dl.dr_data->b_data, size);
 745  820          } else {
 746      -                dbuf_set_data(db, NULL);
      821 +                dbuf_clear_data(db);
 747  822          }
 748  823  }
 749  824  
 750  825  void
 751  826  dbuf_unoverride(dbuf_dirty_record_t *dr)
 752  827  {
 753  828          dmu_buf_impl_t *db = dr->dr_dbuf;
 754  829          blkptr_t *bp = &dr->dt.dl.dr_overridden_by;
 755  830          uint64_t txg = dr->dr_txg;
 756  831  
↓ open down ↓ 30 lines elided ↑ open up ↑
 787  862   * data blocks in the free range, so that any future readers will find
 788  863   * empty blocks.
 789  864   *
 790  865   * This is a no-op if the dataset is in the middle of an incremental
 791  866   * receive; see comment below for details.
 792  867   */
 793  868  void
 794  869  dbuf_free_range(dnode_t *dn, uint64_t start_blkid, uint64_t end_blkid,
 795  870      dmu_tx_t *tx)
 796  871  {
 797      -        dmu_buf_impl_t *db, *db_next, db_search;
      872 +        dmu_buf_impl_t db_search;
      873 +        dmu_buf_impl_t *db, *db_next;
 798  874          uint64_t txg = tx->tx_txg;
 799  875          avl_index_t where;
 800  876  
 801  877          if (end_blkid > dn->dn_maxblkid && (end_blkid != DMU_SPILL_BLKID))
 802  878                  end_blkid = dn->dn_maxblkid;
 803  879          dprintf_dnode(dn, "start=%llu end=%llu\n", start_blkid, end_blkid);
 804  880  
 805  881          db_search.db_level = 0;
 806  882          db_search.db_blkid = start_blkid;
 807  883          db_search.db_state = DB_SEARCH;
↓ open down ↓ 555 lines elided ↑ open up ↑
1363 1439  
1364 1440          kmem_free(dr, sizeof (dbuf_dirty_record_t));
1365 1441  
1366 1442          ASSERT(db->db_dirtycnt > 0);
1367 1443          db->db_dirtycnt -= 1;
1368 1444  
1369 1445          if (refcount_remove(&db->db_holds, (void *)(uintptr_t)txg) == 0) {
1370 1446                  arc_buf_t *buf = db->db_buf;
1371 1447  
1372 1448                  ASSERT(db->db_state == DB_NOFILL || arc_released(buf));
1373      -                dbuf_set_data(db, NULL);
     1449 +                dbuf_clear_data(db);
1374 1450                  VERIFY(arc_buf_remove_ref(buf, db));
1375 1451                  dbuf_evict(db);
1376 1452                  return (B_TRUE);
1377 1453          }
1378 1454  
1379 1455          return (B_FALSE);
1380 1456  }
1381 1457  
1382 1458  void
1383 1459  dmu_buf_will_dirty(dmu_buf_t *db_fake, dmu_tx_t *tx)
↓ open down ↓ 319 lines elided ↑ open up ↑
1703 1779          db->db_objset = os;
1704 1780          db->db.db_object = dn->dn_object;
1705 1781          db->db_level = level;
1706 1782          db->db_blkid = blkid;
1707 1783          db->db_last_dirty = NULL;
1708 1784          db->db_dirtycnt = 0;
1709 1785          db->db_dnode_handle = dn->dn_handle;
1710 1786          db->db_parent = parent;
1711 1787          db->db_blkptr = blkptr;
1712 1788  
1713      -        db->db_user_ptr = NULL;
1714      -        db->db_evict_func = NULL;
     1789 +        db->db_user = NULL;
1715 1790          db->db_immediate_evict = 0;
1716 1791          db->db_freed_in_flight = 0;
1717 1792  
1718 1793          if (blkid == DMU_BONUS_BLKID) {
1719 1794                  ASSERT3P(parent, ==, dn->dn_dbuf);
1720 1795                  db->db.db_size = DN_MAX_BONUSLEN -
1721 1796                      (dn->dn_nblkptr-1) * sizeof (blkptr_t);
1722 1797                  ASSERT3U(db->db.db_size, >=, dn->dn_bonuslen);
1723 1798                  db->db.db_offset = DMU_BONUS_BLKID;
1724 1799                  db->db_state = DB_UNCACHED;
↓ open down ↓ 382 lines elided ↑ open up ↑
2107 2182                           * dbuf with any data allocated from the ARC.
2108 2183                           */
2109 2184                          ASSERT(db->db_state == DB_UNCACHED ||
2110 2185                              db->db_state == DB_NOFILL);
2111 2186                          dbuf_evict(db);
2112 2187                  } else if (arc_released(db->db_buf)) {
2113 2188                          arc_buf_t *buf = db->db_buf;
2114 2189                          /*
2115 2190                           * This dbuf has anonymous data associated with it.
2116 2191                           */
2117      -                        dbuf_set_data(db, NULL);
     2192 +                        dbuf_clear_data(db);
2118 2193                          VERIFY(arc_buf_remove_ref(buf, db));
2119 2194                          dbuf_evict(db);
2120 2195                  } else {
2121 2196                          VERIFY(!arc_buf_remove_ref(db->db_buf, db));
2122 2197  
2123 2198                          /*
2124 2199                           * A dbuf will be eligible for eviction if either the
2125 2200                           * 'primarycache' property is set or a duplicate
2126 2201                           * copy of this buffer is already cached in the arc.
2127 2202                           *
↓ open down ↓ 12 lines elided ↑ open up ↑
2140 2215                                      !BP_IS_HOLE(db->db_blkptr) &&
2141 2216                                      !BP_IS_EMBEDDED(db->db_blkptr)) {
2142 2217                                          spa_t *spa =
2143 2218                                              dmu_objset_spa(db->db_objset);
2144 2219                                          blkptr_t bp = *db->db_blkptr;
2145 2220                                          dbuf_clear(db);
2146 2221                                          arc_freed(spa, &bp);
2147 2222                                  } else {
2148 2223                                          dbuf_clear(db);
2149 2224                                  }
2150      -                        } else if (arc_buf_eviction_needed(db->db_buf)) {
     2225 +                        } else if (db->db_objset->os_evicting ||
     2226 +                            arc_buf_eviction_needed(db->db_buf)) {
2151 2227                                  dbuf_clear(db);
2152 2228                          } else {
2153 2229                                  mutex_exit(&db->db_mtx);
2154 2230                          }
2155 2231                  }
2156 2232          } else {
2157 2233                  mutex_exit(&db->db_mtx);
2158 2234          }
2159 2235  }
2160 2236  
2161 2237  #pragma weak dmu_buf_refcount = dbuf_refcount
2162 2238  uint64_t
2163 2239  dbuf_refcount(dmu_buf_impl_t *db)
2164 2240  {
2165 2241          return (refcount_count(&db->db_holds));
2166 2242  }
2167 2243  
2168 2244  void *
2169      -dmu_buf_set_user(dmu_buf_t *db_fake, void *user_ptr,
2170      -    dmu_buf_evict_func_t *evict_func)
     2245 +dmu_buf_replace_user(dmu_buf_t *db_fake, dmu_buf_user_t *old_user,
     2246 +    dmu_buf_user_t *new_user)
2171 2247  {
2172      -        return (dmu_buf_update_user(db_fake, NULL, user_ptr, evict_func));
     2248 +        dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
     2249 +
     2250 +        mutex_enter(&db->db_mtx);
     2251 +        dbuf_verify_user(db, DBVU_NOT_EVICTING);
     2252 +        if (db->db_user == old_user)
     2253 +                db->db_user = new_user;
     2254 +        else
     2255 +                old_user = db->db_user;
     2256 +        dbuf_verify_user(db, DBVU_NOT_EVICTING);
     2257 +        mutex_exit(&db->db_mtx);
     2258 +
     2259 +        return (old_user);
2173 2260  }
2174 2261  
2175 2262  void *
2176      -dmu_buf_set_user_ie(dmu_buf_t *db_fake, void *user_ptr,
2177      -    dmu_buf_evict_func_t *evict_func)
     2263 +dmu_buf_set_user(dmu_buf_t *db_fake, dmu_buf_user_t *user)
2178 2264  {
2179      -        dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
2180      -
2181      -        db->db_immediate_evict = TRUE;
2182      -        return (dmu_buf_update_user(db_fake, NULL, user_ptr, evict_func));
     2265 +        return (dmu_buf_replace_user(db_fake, NULL, user));
2183 2266  }
2184 2267  
2185 2268  void *
2186      -dmu_buf_update_user(dmu_buf_t *db_fake, void *old_user_ptr, void *user_ptr,
2187      -    dmu_buf_evict_func_t *evict_func)
     2269 +dmu_buf_set_user_ie(dmu_buf_t *db_fake, dmu_buf_user_t *user)
2188 2270  {
2189 2271          dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
2190      -        ASSERT(db->db_level == 0);
2191 2272  
2192      -        ASSERT((user_ptr == NULL) == (evict_func == NULL));
     2273 +        db->db_immediate_evict = TRUE;
     2274 +        return (dmu_buf_set_user(db_fake, user));
     2275 +}
2193 2276  
2194      -        mutex_enter(&db->db_mtx);
2195      -
2196      -        if (db->db_user_ptr == old_user_ptr) {
2197      -                db->db_user_ptr = user_ptr;
2198      -                db->db_evict_func = evict_func;
2199      -        } else {
2200      -                old_user_ptr = db->db_user_ptr;
2201      -        }
2202      -
2203      -        mutex_exit(&db->db_mtx);
2204      -        return (old_user_ptr);
     2277 +void *
     2278 +dmu_buf_remove_user(dmu_buf_t *db_fake, dmu_buf_user_t *user)
     2279 +{
     2280 +        return (dmu_buf_replace_user(db_fake, user, NULL));
2205 2281  }
2206 2282  
2207 2283  void *
2208 2284  dmu_buf_get_user(dmu_buf_t *db_fake)
2209 2285  {
2210 2286          dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
2211      -        ASSERT(!refcount_is_zero(&db->db_holds));
2212 2287  
2213      -        return (db->db_user_ptr);
     2288 +        dbuf_verify_user(db, DBVU_NOT_EVICTING);
     2289 +        return (db->db_user);
2214 2290  }
2215 2291  
     2292 +void
     2293 +dmu_buf_user_evict_wait()
     2294 +{
     2295 +        taskq_wait(dbu_evict_taskq);
     2296 +}
     2297 +
2216 2298  boolean_t
2217 2299  dmu_buf_freeable(dmu_buf_t *dbuf)
2218 2300  {
2219 2301          boolean_t res = B_FALSE;
2220 2302          dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbuf;
2221 2303  
2222 2304          if (db->db_blkptr)
2223 2305                  res = dsl_dataset_block_freeable(db->db_objset->os_dsl_dataset,
2224 2306                      db->db_blkptr, db->db_blkptr->blk_birth);
2225 2307  
↓ open down ↓ 608 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX