4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/dmu_objset.h>
30 #include <sys/dmu_tx.h>
31 #include <sys/dsl_dataset.h>
32 #include <sys/dsl_dir.h>
33 #include <sys/dsl_prop.h>
34 #include <sys/dsl_synctask.h>
36 #include <sys/zio_checksum.h> /* for the default checksum value */
38 #include <sys/fs/zfs.h>
43 dodefault(const char *propname
, int intsz
, int numint
, void *buf
)
48 * The setonce properties are read-only, BUT they still
49 * have a default value that can be used as the initial
52 if ((prop
= zfs_name_to_prop(propname
)) == ZPROP_INVAL
||
53 (zfs_prop_readonly(prop
) && !zfs_prop_setonce(prop
)))
56 if (zfs_prop_get_type(prop
) == PROP_TYPE_STRING
) {
59 (void) strncpy(buf
, zfs_prop_default_string(prop
),
62 if (intsz
!= 8 || numint
< 1)
65 *(uint64_t *)buf
= zfs_prop_default_numeric(prop
);
72 dsl_prop_get_dd(dsl_dir_t
*dd
, const char *propname
,
73 int intsz
, int numint
, void *buf
, char *setpoint
)
76 objset_t
*mos
= dd
->dd_pool
->dp_meta_objset
;
79 ASSERT(RW_LOCK_HELD(&dd
->dd_pool
->dp_config_rwlock
));
84 prop
= zfs_name_to_prop(propname
);
87 * Note: dd may be NULL, therefore we shouldn't dereference it
90 for (; dd
!= NULL
; dd
= dd
->dd_parent
) {
91 ASSERT(RW_LOCK_HELD(&dd
->dd_pool
->dp_config_rwlock
));
92 err
= zap_lookup(mos
, dd
->dd_phys
->dd_props_zapobj
,
93 propname
, intsz
, numint
, buf
);
96 dsl_dir_name(dd
, setpoint
);
101 * Break out of this loop for non-inheritable properties.
103 if (prop
!= ZPROP_INVAL
&& !zfs_prop_inheritable(prop
))
107 err
= dodefault(propname
, intsz
, numint
, buf
);
113 dsl_prop_get_ds(dsl_dataset_t
*ds
, const char *propname
,
114 int intsz
, int numint
, void *buf
, char *setpoint
)
116 ASSERT(RW_LOCK_HELD(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
));
118 if (ds
->ds_phys
->ds_props_obj
) {
119 int err
= zap_lookup(ds
->ds_dir
->dd_pool
->dp_meta_objset
,
120 ds
->ds_phys
->ds_props_obj
, propname
, intsz
, numint
, buf
);
123 dsl_dataset_name(ds
, setpoint
);
128 return (dsl_prop_get_dd(ds
->ds_dir
, propname
,
129 intsz
, numint
, buf
, setpoint
));
133 * Register interest in the named property. We'll call the callback
134 * once to notify it of the current property value, and again each time
135 * the property changes, until this callback is unregistered.
137 * Return 0 on success, errno if the prop is not an integer value.
140 dsl_prop_register(dsl_dataset_t
*ds
, const char *propname
,
141 dsl_prop_changed_cb_t
*callback
, void *cbarg
)
143 dsl_dir_t
*dd
= ds
->ds_dir
;
144 dsl_pool_t
*dp
= dd
->dd_pool
;
146 dsl_prop_cb_record_t
*cbr
;
150 need_rwlock
= !RW_WRITE_HELD(&dp
->dp_config_rwlock
);
152 rw_enter(&dp
->dp_config_rwlock
, RW_READER
);
154 err
= dsl_prop_get_ds(ds
, propname
, 8, 1, &value
, NULL
);
157 rw_exit(&dp
->dp_config_rwlock
);
161 cbr
= kmem_alloc(sizeof (dsl_prop_cb_record_t
), KM_SLEEP
);
163 cbr
->cbr_propname
= kmem_alloc(strlen(propname
)+1, KM_SLEEP
);
164 (void) strcpy((char *)cbr
->cbr_propname
, propname
);
165 cbr
->cbr_func
= callback
;
166 cbr
->cbr_arg
= cbarg
;
167 mutex_enter(&dd
->dd_lock
);
168 list_insert_head(&dd
->dd_prop_cbs
, cbr
);
169 mutex_exit(&dd
->dd_lock
);
171 cbr
->cbr_func(cbr
->cbr_arg
, value
);
173 VERIFY(0 == dsl_dir_open_obj(dp
, dd
->dd_object
,
176 rw_exit(&dp
->dp_config_rwlock
);
177 /* Leave dir open until this callback is unregistered */
182 dsl_prop_get(const char *dsname
, const char *propname
,
183 int intsz
, int numints
, void *buf
, char *setpoint
)
188 err
= dsl_dataset_hold(dsname
, FTAG
, &ds
);
192 rw_enter(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
, RW_READER
);
193 err
= dsl_prop_get_ds(ds
, propname
, intsz
, numints
, buf
, setpoint
);
194 rw_exit(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
);
196 dsl_dataset_rele(ds
, FTAG
);
201 * Get the current property value. It may have changed by the time this
202 * function returns, so it is NOT safe to follow up with
203 * dsl_prop_register() and assume that the value has not changed in
206 * Return 0 on success, ENOENT if ddname is invalid.
209 dsl_prop_get_integer(const char *ddname
, const char *propname
,
210 uint64_t *valuep
, char *setpoint
)
212 return (dsl_prop_get(ddname
, propname
, 8, 1, valuep
, setpoint
));
216 * Unregister this callback. Return 0 on success, ENOENT if ddname is
217 * invalid, ENOMSG if no matching callback registered.
220 dsl_prop_unregister(dsl_dataset_t
*ds
, const char *propname
,
221 dsl_prop_changed_cb_t
*callback
, void *cbarg
)
223 dsl_dir_t
*dd
= ds
->ds_dir
;
224 dsl_prop_cb_record_t
*cbr
;
226 mutex_enter(&dd
->dd_lock
);
227 for (cbr
= list_head(&dd
->dd_prop_cbs
);
228 cbr
; cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
229 if (cbr
->cbr_ds
== ds
&&
230 cbr
->cbr_func
== callback
&&
231 cbr
->cbr_arg
== cbarg
&&
232 strcmp(cbr
->cbr_propname
, propname
) == 0)
237 mutex_exit(&dd
->dd_lock
);
241 list_remove(&dd
->dd_prop_cbs
, cbr
);
242 mutex_exit(&dd
->dd_lock
);
243 kmem_free((void*)cbr
->cbr_propname
, strlen(cbr
->cbr_propname
)+1);
244 kmem_free(cbr
, sizeof (dsl_prop_cb_record_t
));
246 /* Clean up from dsl_prop_register */
247 dsl_dir_close(dd
, cbr
);
252 * Return the number of callbacks that are registered for this dataset.
255 dsl_prop_numcb(dsl_dataset_t
*ds
)
257 dsl_dir_t
*dd
= ds
->ds_dir
;
258 dsl_prop_cb_record_t
*cbr
;
261 mutex_enter(&dd
->dd_lock
);
262 for (cbr
= list_head(&dd
->dd_prop_cbs
);
263 cbr
; cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
264 if (cbr
->cbr_ds
== ds
)
267 mutex_exit(&dd
->dd_lock
);
273 dsl_prop_changed_notify(dsl_pool_t
*dp
, uint64_t ddobj
,
274 const char *propname
, uint64_t value
, int first
)
277 dsl_prop_cb_record_t
*cbr
;
278 objset_t
*mos
= dp
->dp_meta_objset
;
284 ASSERT(RW_WRITE_HELD(&dp
->dp_config_rwlock
));
285 err
= dsl_dir_open_obj(dp
, ddobj
, NULL
, FTAG
, &dd
);
291 * If the prop is set here, then this change is not
292 * being inherited here or below; stop the recursion.
294 err
= zap_lookup(mos
, dd
->dd_phys
->dd_props_zapobj
, propname
,
297 dsl_dir_close(dd
, FTAG
);
300 ASSERT3U(err
, ==, ENOENT
);
303 mutex_enter(&dd
->dd_lock
);
304 for (cbr
= list_head(&dd
->dd_prop_cbs
); cbr
;
305 cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
306 uint64_t propobj
= cbr
->cbr_ds
->ds_phys
->ds_props_obj
;
308 if (strcmp(cbr
->cbr_propname
, propname
) != 0)
312 * If the property is set on this ds, then it is not
313 * inherited here; don't call the callback.
315 if (propobj
&& 0 == zap_lookup(mos
, propobj
, propname
,
319 cbr
->cbr_func(cbr
->cbr_arg
, value
);
321 mutex_exit(&dd
->dd_lock
);
323 za
= kmem_alloc(sizeof (zap_attribute_t
), KM_SLEEP
);
324 for (zap_cursor_init(&zc
, mos
,
325 dd
->dd_phys
->dd_child_dir_zapobj
);
326 zap_cursor_retrieve(&zc
, za
) == 0;
327 zap_cursor_advance(&zc
)) {
328 dsl_prop_changed_notify(dp
, za
->za_first_integer
,
329 propname
, value
, FALSE
);
331 kmem_free(za
, sizeof (zap_attribute_t
));
332 zap_cursor_fini(&zc
);
333 dsl_dir_close(dd
, FTAG
);
336 struct prop_set_arg
{
345 dsl_prop_set_sync(void *arg1
, void *arg2
, cred_t
*cr
, dmu_tx_t
*tx
)
347 dsl_dataset_t
*ds
= arg1
;
348 struct prop_set_arg
*psa
= arg2
;
349 objset_t
*mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
350 uint64_t zapobj
, intval
;
355 isint
= (dodefault(psa
->name
, 8, 1, &intval
) == 0);
357 if (dsl_dataset_is_snapshot(ds
)) {
358 ASSERT(spa_version(ds
->ds_dir
->dd_pool
->dp_spa
) >=
359 SPA_VERSION_SNAP_PROPS
);
360 if (ds
->ds_phys
->ds_props_obj
== 0) {
361 dmu_buf_will_dirty(ds
->ds_dbuf
, tx
);
362 ds
->ds_phys
->ds_props_obj
=
364 DMU_OT_DSL_PROPS
, DMU_OT_NONE
, 0, tx
);
366 zapobj
= ds
->ds_phys
->ds_props_obj
;
368 zapobj
= ds
->ds_dir
->dd_phys
->dd_props_zapobj
;
371 if (psa
->numints
== 0) {
372 int err
= zap_remove(mos
, zapobj
, psa
->name
, tx
);
373 ASSERT(err
== 0 || err
== ENOENT
);
375 VERIFY(0 == dsl_prop_get_ds(ds
,
376 psa
->name
, 8, 1, &intval
, NULL
));
379 VERIFY(0 == zap_update(mos
, zapobj
, psa
->name
,
380 psa
->intsz
, psa
->numints
, psa
->buf
, tx
));
382 intval
= *(uint64_t *)psa
->buf
;
386 if (dsl_dataset_is_snapshot(ds
)) {
387 dsl_prop_cb_record_t
*cbr
;
389 * It's a snapshot; nothing can inherit this
390 * property, so just look for callbacks on this
393 mutex_enter(&ds
->ds_dir
->dd_lock
);
394 for (cbr
= list_head(&ds
->ds_dir
->dd_prop_cbs
); cbr
;
395 cbr
= list_next(&ds
->ds_dir
->dd_prop_cbs
, cbr
)) {
396 if (cbr
->cbr_ds
== ds
&&
397 strcmp(cbr
->cbr_propname
, psa
->name
) == 0)
398 cbr
->cbr_func(cbr
->cbr_arg
, intval
);
400 mutex_exit(&ds
->ds_dir
->dd_lock
);
402 dsl_prop_changed_notify(ds
->ds_dir
->dd_pool
,
403 ds
->ds_dir
->dd_object
, psa
->name
, intval
, TRUE
);
407 (void) snprintf(valbuf
, sizeof (valbuf
),
408 "%lld", (longlong_t
)intval
);
411 valstr
= (char *)psa
->buf
;
413 spa_history_internal_log((psa
->numints
== 0) ? LOG_DS_INHERIT
:
414 LOG_DS_PROPSET
, ds
->ds_dir
->dd_pool
->dp_spa
, tx
, cr
,
415 "%s=%s dataset = %llu", psa
->name
, valstr
, ds
->ds_object
);
419 dsl_prop_set_uint64_sync(dsl_dir_t
*dd
, const char *name
, uint64_t val
,
420 cred_t
*cr
, dmu_tx_t
*tx
)
422 objset_t
*mos
= dd
->dd_pool
->dp_meta_objset
;
423 uint64_t zapobj
= dd
->dd_phys
->dd_props_zapobj
;
425 ASSERT(dmu_tx_is_syncing(tx
));
427 VERIFY(0 == zap_update(mos
, zapobj
, name
, sizeof (val
), 1, &val
, tx
));
429 dsl_prop_changed_notify(dd
->dd_pool
, dd
->dd_object
, name
, val
, TRUE
);
431 spa_history_internal_log(LOG_DS_PROPSET
, dd
->dd_pool
->dp_spa
, tx
, cr
,
432 "%s=%llu dataset = %llu", name
, (u_longlong_t
)val
,
433 dd
->dd_phys
->dd_head_dataset_obj
);
437 dsl_prop_set(const char *dsname
, const char *propname
,
438 int intsz
, int numints
, const void *buf
)
442 struct prop_set_arg psa
;
445 * We must do these checks before we get to the syncfunc, since
448 if (strlen(propname
) >= ZAP_MAXNAMELEN
)
449 return (ENAMETOOLONG
);
450 if (intsz
* numints
>= ZAP_MAXVALUELEN
)
453 err
= dsl_dataset_hold(dsname
, FTAG
, &ds
);
457 if (dsl_dataset_is_snapshot(ds
) &&
458 spa_version(ds
->ds_dir
->dd_pool
->dp_spa
) < SPA_VERSION_SNAP_PROPS
) {
459 dsl_dataset_rele(ds
, FTAG
);
465 psa
.numints
= numints
;
467 err
= dsl_sync_task_do(ds
->ds_dir
->dd_pool
,
468 NULL
, dsl_prop_set_sync
, ds
, &psa
, 2);
470 dsl_dataset_rele(ds
, FTAG
);
475 * Iterate over all properties for this dataset and return them in an nvlist.
478 dsl_prop_get_all(objset_t
*os
, nvlist_t
**nvp
, boolean_t local
)
480 dsl_dataset_t
*ds
= os
->os
->os_dsl_dataset
;
481 dsl_dir_t
*dd
= ds
->ds_dir
;
482 boolean_t snapshot
= dsl_dataset_is_snapshot(ds
);
484 dsl_pool_t
*dp
= dd
->dd_pool
;
485 objset_t
*mos
= dp
->dp_meta_objset
;
486 uint64_t propobj
= ds
->ds_phys
->ds_props_obj
;
488 VERIFY(nvlist_alloc(nvp
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
490 if (local
&& snapshot
&& !propobj
)
493 rw_enter(&dp
->dp_config_rwlock
, RW_READER
);
495 char setpoint
[MAXNAMELEN
];
501 dsl_dataset_name(ds
, setpoint
);
504 dsl_dir_name(dd
, setpoint
);
505 propobj
= dd
->dd_phys
->dd_props_zapobj
;
506 dd_next
= dd
->dd_parent
;
509 for (zap_cursor_init(&zc
, mos
, propobj
);
510 (err
= zap_cursor_retrieve(&zc
, &za
)) == 0;
511 zap_cursor_advance(&zc
)) {
513 zfs_prop_t prop
= zfs_name_to_prop(za
.za_name
);
515 /* Skip non-inheritable properties. */
516 if (prop
!= ZPROP_INVAL
&&
517 !zfs_prop_inheritable(prop
) &&
518 (dd
!= ds
->ds_dir
|| (snapshot
&& dd
!= dd_next
)))
521 /* Skip properties not valid for this type. */
522 if (snapshot
&& prop
!= ZPROP_INVAL
&&
523 !zfs_prop_valid_for_type(prop
, ZFS_TYPE_SNAPSHOT
))
526 /* Skip properties already defined */
527 if (nvlist_lookup_nvlist(*nvp
, za
.za_name
,
531 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
,
533 if (za
.za_integer_length
== 1) {
537 char *tmp
= kmem_alloc(za
.za_num_integers
,
539 err
= zap_lookup(mos
, propobj
,
540 za
.za_name
, 1, za
.za_num_integers
, tmp
);
542 kmem_free(tmp
, za
.za_num_integers
);
545 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
,
547 kmem_free(tmp
, za
.za_num_integers
);
552 ASSERT(za
.za_integer_length
== 8);
553 (void) nvlist_add_uint64(propval
, ZPROP_VALUE
,
554 za
.za_first_integer
);
557 VERIFY(nvlist_add_string(propval
, ZPROP_SOURCE
,
559 VERIFY(nvlist_add_nvlist(*nvp
, za
.za_name
,
561 nvlist_free(propval
);
563 zap_cursor_fini(&zc
);
569 * If we are just after the props that have been set
570 * locally, then we are done after the first iteration.
577 rw_exit(&dp
->dp_config_rwlock
);
583 dsl_prop_nvlist_add_uint64(nvlist_t
*nv
, zfs_prop_t prop
, uint64_t value
)
587 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
588 VERIFY(nvlist_add_uint64(propval
, ZPROP_VALUE
, value
) == 0);
589 VERIFY(nvlist_add_nvlist(nv
, zfs_prop_to_name(prop
), propval
) == 0);
590 nvlist_free(propval
);
594 dsl_prop_nvlist_add_string(nvlist_t
*nv
, zfs_prop_t prop
, const char *value
)
598 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
599 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
, value
) == 0);
600 VERIFY(nvlist_add_nvlist(nv
, zfs_prop_to_name(prop
), propval
) == 0);
601 nvlist_free(propval
);