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 */
|