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


  26 #include <sys/dmu.h>
  27 #include <sys/dmu_objset.h>
  28 #include <sys/dmu_tx.h>
  29 #include <sys/dsl_dataset.h>
  30 #include <sys/dsl_dir.h>
  31 #include <sys/dsl_prop.h>
  32 #include <sys/dsl_synctask.h>
  33 #include <sys/dsl_deleg.h>
  34 #include <sys/spa.h>
  35 #include <sys/metaslab.h>
  36 #include <sys/zap.h>
  37 #include <sys/zio.h>
  38 #include <sys/arc.h>
  39 #include <sys/sunddi.h>
  40 #include "zfs_namecheck.h"
  41 
  42 static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
  43 
  44 /* ARGSUSED */
  45 static void
  46 dsl_dir_evict(dmu_buf_t *db, void *arg)
  47 {
  48         dsl_dir_t *dd = arg;
  49         dsl_pool_t *dp = dd->dd_pool;
  50         int t;
  51 


  52         for (t = 0; t < TXG_SIZE; t++) {
  53                 ASSERT(!txg_list_member(&dp->dp_dirty_dirs, dd, t));
  54                 ASSERT(dd->dd_tempreserved[t] == 0);
  55                 ASSERT(dd->dd_space_towrite[t] == 0);
  56         }
  57 
  58         if (dd->dd_parent)
  59                 dsl_dir_rele(dd->dd_parent, dd);
  60 
  61         spa_close(dd->dd_pool->dp_spa, dd);
  62 
  63         /*
  64          * The props callback list should have been cleaned up by
  65          * objset_evict().
  66          */
  67         list_destroy(&dd->dd_prop_cbs);
  68         mutex_destroy(&dd->dd_lock);
  69         kmem_free(dd, sizeof (dsl_dir_t));
  70 }
  71 
  72 int
  73 dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
  74     const char *tail, void *tag, dsl_dir_t **ddp)
  75 {
  76         dmu_buf_t *dbuf;
  77         dsl_dir_t *dd;
  78         int err;
  79 
  80         ASSERT(dsl_pool_config_held(dp));
  81 
  82         err = dmu_bonus_hold(dp->dp_meta_objset, ddobj, tag, &dbuf);
  83         if (err != 0)
  84                 return (err);
  85         dd = dmu_buf_get_user(dbuf);
  86 #ifdef ZFS_DEBUG
  87         {
  88                 dmu_object_info_t doi;
  89                 dmu_object_info_from_db(dbuf, &doi);
  90                 ASSERT3U(doi.doi_type, ==, DMU_OT_DSL_DIR);
  91                 ASSERT3U(doi.doi_bonus_size, >=, sizeof (dsl_dir_phys_t));
  92         }
  93 #endif
  94         if (dd == NULL) {
  95                 dsl_dir_t *winner;
  96 
  97                 dd = kmem_zalloc(sizeof (dsl_dir_t), KM_SLEEP);
  98                 dd->dd_object = ddobj;
  99                 dd->dd_dbuf = dbuf;
 100                 dd->dd_pool = dp;
 101                 dd->dd_phys = dbuf->db_data;
 102                 mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL);
 103 
 104                 list_create(&dd->dd_prop_cbs, sizeof (dsl_prop_cb_record_t),
 105                     offsetof(dsl_prop_cb_record_t, cbr_node));
 106 
 107                 dsl_dir_snap_cmtime_update(dd);
 108 
 109                 if (dd->dd_phys->dd_parent_obj) {
 110                         err = dsl_dir_hold_obj(dp, dd->dd_phys->dd_parent_obj,
 111                             NULL, dd, &dd->dd_parent);
 112                         if (err != 0)
 113                                 goto errout;
 114                         if (tail) {
 115 #ifdef ZFS_DEBUG
 116                                 uint64_t foundobj;
 117 
 118                                 err = zap_lookup(dp->dp_meta_objset,
 119                                     dd->dd_parent->dd_phys->dd_child_dir_zapobj,
 120                                     tail, sizeof (foundobj), 1, &foundobj);
 121                                 ASSERT(err || foundobj == ddobj);


 134 
 135                 if (dsl_dir_is_clone(dd)) {
 136                         dmu_buf_t *origin_bonus;
 137                         dsl_dataset_phys_t *origin_phys;
 138 
 139                         /*
 140                          * We can't open the origin dataset, because
 141                          * that would require opening this dsl_dir.
 142                          * Just look at its phys directly instead.
 143                          */
 144                         err = dmu_bonus_hold(dp->dp_meta_objset,
 145                             dd->dd_phys->dd_origin_obj, FTAG, &origin_bonus);
 146                         if (err != 0)
 147                                 goto errout;
 148                         origin_phys = origin_bonus->db_data;
 149                         dd->dd_origin_txg =
 150                             origin_phys->ds_creation_txg;
 151                         dmu_buf_rele(origin_bonus, FTAG);
 152                 }
 153 
 154                 winner = dmu_buf_set_user_ie(dbuf, dd, &dd->dd_phys,
 155                     dsl_dir_evict);
 156                 if (winner) {
 157                         if (dd->dd_parent)
 158                                 dsl_dir_rele(dd->dd_parent, dd);
 159                         mutex_destroy(&dd->dd_lock);
 160                         kmem_free(dd, sizeof (dsl_dir_t));
 161                         dd = winner;
 162                 } else {
 163                         spa_open_ref(dp->dp_spa, dd);
 164                 }
 165         }
 166 
 167         /*
 168          * The dsl_dir_t has both open-to-close and instantiate-to-evict
 169          * holds on the spa.  We need the open-to-close holds because
 170          * otherwise the spa_refcnt wouldn't change when we open a
 171          * dir which the spa also has open, so we could incorrectly
 172          * think it was OK to unload/export/destroy the pool.  We need
 173          * the instantiate-to-evict hold because the dsl_dir_t has a
 174          * pointer to the dd_pool, which has a pointer to the spa_t.
 175          */




  26 #include <sys/dmu.h>
  27 #include <sys/dmu_objset.h>
  28 #include <sys/dmu_tx.h>
  29 #include <sys/dsl_dataset.h>
  30 #include <sys/dsl_dir.h>
  31 #include <sys/dsl_prop.h>
  32 #include <sys/dsl_synctask.h>
  33 #include <sys/dsl_deleg.h>
  34 #include <sys/spa.h>
  35 #include <sys/metaslab.h>
  36 #include <sys/zap.h>
  37 #include <sys/zio.h>
  38 #include <sys/arc.h>
  39 #include <sys/sunddi.h>
  40 #include "zfs_namecheck.h"
  41 
  42 static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
  43 
  44 /* ARGSUSED */
  45 static void
  46 dsl_dir_evict(dmu_buf_user_t *dbu)
  47 {
  48         dsl_dir_t *dd = (dsl_dir_t *)dbu;
  49         dsl_pool_t *dp = dd->dd_pool;
  50         int t;
  51 
  52         dd->dd_dbuf = NULL;
  53 
  54         for (t = 0; t < TXG_SIZE; t++) {
  55                 ASSERT(!txg_list_member(&dp->dp_dirty_dirs, dd, t));
  56                 ASSERT(dd->dd_tempreserved[t] == 0);
  57                 ASSERT(dd->dd_space_towrite[t] == 0);
  58         }
  59 
  60         if (dd->dd_parent)
  61                 dsl_dir_rele(dd->dd_parent, dd);
  62 
  63         spa_close(dd->dd_pool->dp_spa, dd);
  64 
  65         /*
  66          * The props callback list should have been cleaned up by
  67          * objset_evict().
  68          */
  69         list_destroy(&dd->dd_prop_cbs);
  70         mutex_destroy(&dd->dd_lock);
  71         kmem_free(dd, sizeof (dsl_dir_t));
  72 }
  73 
  74 int
  75 dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
  76     const char *tail, void *tag, dsl_dir_t **ddp)
  77 {
  78         dmu_buf_t *dbuf;
  79         dsl_dir_t *dd;
  80         int err;
  81 
  82         ASSERT(dsl_pool_config_held(dp));
  83 
  84         err = dmu_bonus_hold(dp->dp_meta_objset, ddobj, tag, &dbuf);
  85         if (err != 0)
  86                 return (err);
  87         dd = (dsl_dir_t *)dmu_buf_get_user(dbuf);
  88 #ifdef ZFS_DEBUG
  89         {
  90                 dmu_object_info_t doi;
  91                 dmu_object_info_from_db(dbuf, &doi);
  92                 ASSERT3U(doi.doi_type, ==, DMU_OT_DSL_DIR);
  93                 ASSERT3U(doi.doi_bonus_size, >=, sizeof (dsl_dir_phys_t));
  94         }
  95 #endif
  96         if (dd == NULL) {
  97                 dsl_dir_t *winner;
  98 
  99                 dd = kmem_zalloc(sizeof (dsl_dir_t), KM_SLEEP);
 100                 dd->dd_object = ddobj;
 101                 dd->dd_dbuf = dbuf;
 102                 dd->dd_pool = dp;

 103                 mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL);
 104 
 105                 list_create(&dd->dd_prop_cbs, sizeof (dsl_prop_cb_record_t),
 106                     offsetof(dsl_prop_cb_record_t, cbr_node));
 107 
 108                 dsl_dir_snap_cmtime_update(dd);
 109 
 110                 if (dd->dd_phys->dd_parent_obj) {
 111                         err = dsl_dir_hold_obj(dp, dd->dd_phys->dd_parent_obj,
 112                             NULL, dd, &dd->dd_parent);
 113                         if (err != 0)
 114                                 goto errout;
 115                         if (tail) {
 116 #ifdef ZFS_DEBUG
 117                                 uint64_t foundobj;
 118 
 119                                 err = zap_lookup(dp->dp_meta_objset,
 120                                     dd->dd_parent->dd_phys->dd_child_dir_zapobj,
 121                                     tail, sizeof (foundobj), 1, &foundobj);
 122                                 ASSERT(err || foundobj == ddobj);


 135 
 136                 if (dsl_dir_is_clone(dd)) {
 137                         dmu_buf_t *origin_bonus;
 138                         dsl_dataset_phys_t *origin_phys;
 139 
 140                         /*
 141                          * We can't open the origin dataset, because
 142                          * that would require opening this dsl_dir.
 143                          * Just look at its phys directly instead.
 144                          */
 145                         err = dmu_bonus_hold(dp->dp_meta_objset,
 146                             dd->dd_phys->dd_origin_obj, FTAG, &origin_bonus);
 147                         if (err != 0)
 148                                 goto errout;
 149                         origin_phys = origin_bonus->db_data;
 150                         dd->dd_origin_txg =
 151                             origin_phys->ds_creation_txg;
 152                         dmu_buf_rele(origin_bonus, FTAG);
 153                 }
 154 
 155                 dmu_buf_init_user(&dd->db_evict, dsl_dir_evict);
 156                 winner = (dsl_dir_t *)dmu_buf_set_user_ie(dbuf, &dd->db_evict);
 157                 if (winner) {
 158                         if (dd->dd_parent)
 159                                 dsl_dir_rele(dd->dd_parent, dd);
 160                         mutex_destroy(&dd->dd_lock);
 161                         kmem_free(dd, sizeof (dsl_dir_t));
 162                         dd = winner;
 163                 } else {
 164                         spa_open_ref(dp->dp_spa, dd);
 165                 }
 166         }
 167 
 168         /*
 169          * The dsl_dir_t has both open-to-close and instantiate-to-evict
 170          * holds on the spa.  We need the open-to-close holds because
 171          * otherwise the spa_refcnt wouldn't change when we open a
 172          * dir which the spa also has open, so we could incorrectly
 173          * think it was OK to unload/export/destroy the pool.  We need
 174          * the instantiate-to-evict hold because the dsl_dir_t has a
 175          * pointer to the dd_pool, which has a pointer to the spa_t.
 176          */