Print this page
3752 want more verifiable dbuf user eviction
Submitted by:   Justin Gibbs <justing@spectralogic.com>
Submitted by:   Will Andrews <willa@spectralogic.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dnode_sync.c
          +++ new/usr/src/uts/common/fs/zfs/dnode_sync.c
↓ open down ↓ 369 lines elided ↑ open up ↑
 370  370  }
 371  371  
 372  372  /*
 373  373   * Try to kick all the dnodes dbufs out of the cache...
 374  374   */
 375  375  void
 376  376  dnode_evict_dbufs(dnode_t *dn)
 377  377  {
 378  378          int progress;
 379  379          int pass = 0;
      380 +        list_t evict_list;
      381 +
      382 +        dmu_buf_create_user_evict_list(&evict_list);
 380  383  
 381  384          do {
 382  385                  dmu_buf_impl_t *db, marker;
 383  386                  int evicting = FALSE;
 384  387  
 385  388                  progress = FALSE;
 386  389                  mutex_enter(&dn->dn_dbufs_mtx);
 387  390                  list_insert_tail(&dn->dn_dbufs, &marker);
 388  391                  db = list_head(&dn->dn_dbufs);
 389  392                  for (; db != &marker; db = list_head(&dn->dn_dbufs)) {
↓ open down ↓ 5 lines elided ↑ open up ↑
 395  398                          DB_DNODE_EXIT(db);
 396  399  #endif  /* DEBUG */
 397  400  
 398  401                          mutex_enter(&db->db_mtx);
 399  402                          if (db->db_state == DB_EVICTING) {
 400  403                                  progress = TRUE;
 401  404                                  evicting = TRUE;
 402  405                                  mutex_exit(&db->db_mtx);
 403  406                          } else if (refcount_is_zero(&db->db_holds)) {
 404  407                                  progress = TRUE;
 405      -                                dbuf_clear(db); /* exits db_mtx for us */
      408 +                                dbuf_clear(db, &evict_list); /* exits db_mtx */
 406  409                          } else {
 407  410                                  mutex_exit(&db->db_mtx);
 408  411                          }
 409      -
      412 +                        ASSERT(MUTEX_NOT_HELD(&db->db_mtx));
      413 +                        dmu_buf_process_user_evicts(&evict_list);
 410  414                  }
 411  415                  list_remove(&dn->dn_dbufs, &marker);
 412  416                  /*
 413  417                   * NB: we need to drop dn_dbufs_mtx between passes so
 414  418                   * that any DB_EVICTING dbufs can make progress.
 415  419                   * Ideally, we would have some cv we could wait on, but
 416  420                   * since we don't, just wait a bit to give the other
 417  421                   * thread a chance to run.
 418  422                   */
 419  423                  mutex_exit(&dn->dn_dbufs_mtx);
 420  424                  if (evicting)
 421  425                          delay(1);
 422  426                  pass++;
 423  427                  ASSERT(pass < 100); /* sanity check */
 424  428          } while (progress);
 425  429  
 426  430          rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
 427  431          if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) {
 428  432                  mutex_enter(&dn->dn_bonus->db_mtx);
 429      -                dbuf_evict(dn->dn_bonus);
      433 +                dbuf_evict(dn->dn_bonus, &evict_list);
 430  434                  dn->dn_bonus = NULL;
 431  435          }
 432  436          rw_exit(&dn->dn_struct_rwlock);
      437 +        dmu_buf_destroy_user_evict_list(&evict_list);
 433  438  }
 434  439  
 435  440  static void
 436  441  dnode_undirty_dbufs(list_t *list)
 437  442  {
 438  443          dbuf_dirty_record_t *dr;
 439  444  
 440  445          while (dr = list_head(list)) {
 441  446                  dmu_buf_impl_t *db = dr->dr_dbuf;
 442  447                  uint64_t txg = dr->dr_txg;
↓ open down ↓ 254 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX