789
|
1 |
/*
|
|
2 |
* CDDL HEADER START
|
|
3 |
*
|
|
4 |
* The contents of this file are subject to the terms of the
|
1544
|
5 |
* Common Development and Distribution License (the "License").
|
|
6 |
* You may not use this file except in compliance with the License.
|
789
|
7 |
*
|
|
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
9 |
* or http://www.opensolaris.org/os/licensing.
|
|
10 |
* See the License for the specific language governing permissions
|
|
11 |
* and limitations under the License.
|
|
12 |
*
|
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each
|
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
15 |
* If applicable, add the following below this CDDL HEADER, with the
|
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
18 |
*
|
|
19 |
* CDDL HEADER END
|
|
20 |
*/
|
|
21 |
/*
|
1544
|
22 |
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
789
|
23 |
* Use is subject to license terms.
|
|
24 |
*/
|
|
25 |
|
|
26 |
#pragma ident "%Z%%M% %I% %E% SMI"
|
|
27 |
|
|
28 |
#include <sys/dsl_pool.h>
|
|
29 |
#include <sys/dsl_dataset.h>
|
|
30 |
#include <sys/dsl_dir.h>
|
|
31 |
#include <sys/dmu_tx.h>
|
|
32 |
#include <sys/dmu_objset.h>
|
|
33 |
#include <sys/arc.h>
|
|
34 |
#include <sys/zap.h>
|
|
35 |
#include <sys/zfs_context.h>
|
|
36 |
#include <sys/fs/zfs.h>
|
|
37 |
|
|
38 |
/* internal reserved dir name */
|
|
39 |
#define MOS_DIR_NAME "$MOS"
|
|
40 |
|
1544
|
41 |
static int
|
|
42 |
dsl_pool_open_mos_dir(dsl_pool_t *dp, dsl_dir_t **ddp)
|
789
|
43 |
{
|
|
44 |
uint64_t obj;
|
|
45 |
int err;
|
|
46 |
|
|
47 |
err = zap_lookup(dp->dp_meta_objset,
|
|
48 |
dp->dp_root_dir->dd_phys->dd_child_dir_zapobj,
|
|
49 |
MOS_DIR_NAME, sizeof (obj), 1, &obj);
|
1544
|
50 |
if (err)
|
|
51 |
return (err);
|
789
|
52 |
|
1544
|
53 |
return (dsl_dir_open_obj(dp, obj, MOS_DIR_NAME, dp, ddp));
|
789
|
54 |
}
|
|
55 |
|
|
56 |
static dsl_pool_t *
|
|
57 |
dsl_pool_open_impl(spa_t *spa, uint64_t txg)
|
|
58 |
{
|
|
59 |
dsl_pool_t *dp;
|
|
60 |
blkptr_t *bp = spa_get_rootblkptr(spa);
|
|
61 |
|
|
62 |
dp = kmem_zalloc(sizeof (dsl_pool_t), KM_SLEEP);
|
|
63 |
dp->dp_spa = spa;
|
|
64 |
dp->dp_meta_rootbp = *bp;
|
|
65 |
txg_init(dp, txg);
|
|
66 |
|
|
67 |
txg_list_create(&dp->dp_dirty_datasets,
|
|
68 |
offsetof(dsl_dataset_t, ds_dirty_link));
|
|
69 |
txg_list_create(&dp->dp_dirty_dirs,
|
|
70 |
offsetof(dsl_dir_t, dd_dirty_link));
|
|
71 |
list_create(&dp->dp_synced_objsets, sizeof (dsl_dataset_t),
|
|
72 |
offsetof(dsl_dataset_t, ds_synced_link));
|
|
73 |
|
|
74 |
return (dp);
|
|
75 |
}
|
|
76 |
|
1544
|
77 |
int
|
|
78 |
dsl_pool_open(spa_t *spa, uint64_t txg, dsl_pool_t **dpp)
|
789
|
79 |
{
|
|
80 |
int err;
|
|
81 |
dsl_pool_t *dp = dsl_pool_open_impl(spa, txg);
|
1544
|
82 |
objset_impl_t *osi;
|
789
|
83 |
|
|
84 |
rw_enter(&dp->dp_config_rwlock, RW_READER);
|
1544
|
85 |
err = dmu_objset_open_impl(spa, NULL, &dp->dp_meta_rootbp, &osi);
|
|
86 |
if (err)
|
|
87 |
goto out;
|
|
88 |
dp->dp_meta_objset = &osi->os;
|
|
89 |
|
789
|
90 |
err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
|
|
91 |
DMU_POOL_ROOT_DATASET, sizeof (uint64_t), 1,
|
|
92 |
&dp->dp_root_dir_obj);
|
1544
|
93 |
if (err)
|
|
94 |
goto out;
|
|
95 |
|
|
96 |
err = dsl_dir_open_obj(dp, dp->dp_root_dir_obj,
|
|
97 |
NULL, dp, &dp->dp_root_dir);
|
|
98 |
if (err)
|
|
99 |
goto out;
|
789
|
100 |
|
1544
|
101 |
err = dsl_pool_open_mos_dir(dp, &dp->dp_mos_dir);
|
|
102 |
if (err)
|
|
103 |
goto out;
|
|
104 |
|
|
105 |
out:
|
789
|
106 |
rw_exit(&dp->dp_config_rwlock);
|
1544
|
107 |
if (err)
|
|
108 |
dsl_pool_close(dp);
|
|
109 |
else
|
|
110 |
*dpp = dp;
|
789
|
111 |
|
1544
|
112 |
return (err);
|
789
|
113 |
}
|
|
114 |
|
|
115 |
void
|
|
116 |
dsl_pool_close(dsl_pool_t *dp)
|
|
117 |
{
|
|
118 |
/* drop our reference from dsl_pool_open() */
|
1544
|
119 |
if (dp->dp_mos_dir)
|
|
120 |
dsl_dir_close(dp->dp_mos_dir, dp);
|
|
121 |
if (dp->dp_root_dir)
|
|
122 |
dsl_dir_close(dp->dp_root_dir, dp);
|
789
|
123 |
|
|
124 |
/* undo the dmu_objset_open_impl(mos) from dsl_pool_open() */
|
1544
|
125 |
if (dp->dp_meta_objset)
|
|
126 |
dmu_objset_evict(NULL, dp->dp_meta_objset->os);
|
789
|
127 |
|
|
128 |
txg_list_destroy(&dp->dp_dirty_datasets);
|
|
129 |
txg_list_destroy(&dp->dp_dirty_dirs);
|
|
130 |
list_destroy(&dp->dp_synced_objsets);
|
|
131 |
|
|
132 |
arc_flush();
|
|
133 |
txg_fini(dp);
|
|
134 |
kmem_free(dp, sizeof (dsl_pool_t));
|
|
135 |
}
|
|
136 |
|
|
137 |
dsl_pool_t *
|
|
138 |
dsl_pool_create(spa_t *spa, uint64_t txg)
|
|
139 |
{
|
|
140 |
int err;
|
|
141 |
dsl_pool_t *dp = dsl_pool_open_impl(spa, txg);
|
|
142 |
dmu_tx_t *tx = dmu_tx_create_assigned(dp, txg);
|
|
143 |
dp->dp_meta_objset = &dmu_objset_create_impl(spa,
|
|
144 |
NULL, DMU_OST_META, tx)->os;
|
|
145 |
|
|
146 |
/* create the pool directory */
|
|
147 |
err = zap_create_claim(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
|
|
148 |
DMU_OT_OBJECT_DIRECTORY, DMU_OT_NONE, 0, tx);
|
|
149 |
ASSERT3U(err, ==, 0);
|
|
150 |
|
|
151 |
/* create and open the root dir */
|
|
152 |
dsl_dataset_create_root(dp, &dp->dp_root_dir_obj, tx);
|
1544
|
153 |
VERIFY(0 == dsl_dir_open_obj(dp, dp->dp_root_dir_obj,
|
|
154 |
NULL, dp, &dp->dp_root_dir));
|
789
|
155 |
|
|
156 |
/* create and open the meta-objset dir */
|
1544
|
157 |
VERIFY(0 == dsl_dir_create_sync(dp->dp_root_dir, MOS_DIR_NAME, tx));
|
789
|
158 |
ASSERT3U(err, ==, 0);
|
1544
|
159 |
VERIFY(0 == dsl_pool_open_mos_dir(dp, &dp->dp_mos_dir));
|
789
|
160 |
|
|
161 |
dmu_tx_commit(tx);
|
|
162 |
|
|
163 |
return (dp);
|
|
164 |
}
|
|
165 |
|
|
166 |
void
|
|
167 |
dsl_pool_sync(dsl_pool_t *dp, uint64_t txg)
|
|
168 |
{
|
|
169 |
dmu_tx_t *tx;
|
|
170 |
objset_impl_t *mosi = dp->dp_meta_objset->os;
|
|
171 |
|
|
172 |
tx = dmu_tx_create_assigned(dp, txg);
|
|
173 |
|
|
174 |
do {
|
|
175 |
dsl_dir_t *dd;
|
|
176 |
dsl_dataset_t *ds;
|
|
177 |
|
|
178 |
while (ds = txg_list_remove(&dp->dp_dirty_datasets, txg)) {
|
|
179 |
if (!list_link_active(&ds->ds_synced_link))
|
|
180 |
list_insert_tail(&dp->dp_synced_objsets, ds);
|
|
181 |
dsl_dataset_sync(ds, tx);
|
|
182 |
}
|
|
183 |
while (dd = txg_list_remove(&dp->dp_dirty_dirs, txg))
|
|
184 |
dsl_dir_sync(dd, tx);
|
|
185 |
/*
|
|
186 |
* We need to loop since dsl_dir_sync() could create a
|
|
187 |
* new (dirty) objset.
|
|
188 |
* XXX - isn't this taken care of by the spa's sync to
|
|
189 |
* convergence loop?
|
|
190 |
*/
|
|
191 |
} while (!txg_list_empty(&dp->dp_dirty_datasets, txg));
|
|
192 |
|
|
193 |
if (list_head(&mosi->os_dirty_dnodes[txg & TXG_MASK]) != NULL ||
|
|
194 |
list_head(&mosi->os_free_dnodes[txg & TXG_MASK]) != NULL) {
|
|
195 |
dmu_objset_sync(mosi, tx);
|
|
196 |
dprintf_bp(&dp->dp_meta_rootbp, "meta objset rootbp is %s", "");
|
|
197 |
spa_set_rootblkptr(dp->dp_spa, &dp->dp_meta_rootbp);
|
|
198 |
}
|
|
199 |
|
|
200 |
dmu_tx_commit(tx);
|
|
201 |
}
|
|
202 |
|
|
203 |
void
|
|
204 |
dsl_pool_zil_clean(dsl_pool_t *dp)
|
|
205 |
{
|
|
206 |
dsl_dataset_t *ds;
|
|
207 |
|
|
208 |
while (ds = list_head(&dp->dp_synced_objsets)) {
|
|
209 |
list_remove(&dp->dp_synced_objsets, ds);
|
|
210 |
ASSERT(ds->ds_user_ptr != NULL);
|
|
211 |
zil_clean(((objset_impl_t *)ds->ds_user_ptr)->os_zil);
|
|
212 |
}
|
|
213 |
}
|
|
214 |
|
|
215 |
int
|
|
216 |
dsl_pool_sync_context(dsl_pool_t *dp)
|
|
217 |
{
|
|
218 |
/*
|
|
219 |
* Yeah, this is cheesy. But the SPA needs some way to let
|
|
220 |
* the sync threads invoke spa_open() and spa_close() while
|
|
221 |
* it holds the namespace lock. I'm certainly open to better
|
|
222 |
* ideas for how to determine whether the current thread is
|
|
223 |
* operating on behalf of spa_sync(). This works for now.
|
|
224 |
*/
|
|
225 |
return (curthread == dp->dp_tx.tx_sync_thread ||
|
|
226 |
BP_IS_HOLE(&dp->dp_meta_rootbp));
|
|
227 |
}
|
|
228 |
|
|
229 |
uint64_t
|
|
230 |
dsl_pool_adjustedsize(dsl_pool_t *dp, boolean_t netfree)
|
|
231 |
{
|
|
232 |
uint64_t space, resv;
|
|
233 |
|
|
234 |
/*
|
|
235 |
* Reserve about 1% (1/128), or at least 16MB, for allocation
|
|
236 |
* efficiency.
|
|
237 |
* XXX The intent log is not accounted for, so it must fit
|
|
238 |
* within this slop.
|
|
239 |
*
|
|
240 |
* If we're trying to assess whether it's OK to do a free,
|
|
241 |
* cut the reservation in half to allow forward progress
|
|
242 |
* (e.g. make it possible to rm(1) files from a full pool).
|
|
243 |
*/
|
|
244 |
space = spa_get_space(dp->dp_spa);
|
|
245 |
resv = MAX(space >> 7, SPA_MINDEVSIZE >> 2);
|
|
246 |
if (netfree)
|
|
247 |
resv >>= 1;
|
|
248 |
|
|
249 |
return (space - resv);
|
|
250 |
}
|