Illumos 6171 - dsl_prop_unregister() slows down dataset eviction.
6171 dsl_prop_unregister() slows down dataset eviction. Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Prakash Surya <prakash.surya@delphix.com> Approved by: Dan McDonald <danmcd@omniti.com> References: https://www.illumos.org/issues/6171 https://github.com/illumos/illumos-gate/commit/03bad06 Porting notes: - Conflicts -3558fd7
Prototype/structure update for Linux -2cf7f52
Linux compat 2.6.39: mount_nodev() -13fe019
Illumos #3464 -241b541
Illumos 5959 - clean up per-dataset feature count code - dsl_prop_unregister() preserved until out of tree consumers like Lustre can transition to dsl_prop_unregister_all(). - Fixing 'space or tab at end of line' in include/sys/dsl_dataset.h Ported-by: kernelOfTruth kerneloftruth@gmail.com Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
parent
5a28a9737a
commit
0eb21616fa
|
@ -184,6 +184,9 @@ typedef struct dsl_dataset {
|
||||||
kmutex_t ds_sendstream_lock;
|
kmutex_t ds_sendstream_lock;
|
||||||
list_t ds_sendstreams;
|
list_t ds_sendstreams;
|
||||||
|
|
||||||
|
/* Protected by our dsl_dir's dd_lock */
|
||||||
|
list_t ds_prop_cbs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
|
* For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
|
||||||
* uses this feature.
|
* uses this feature.
|
||||||
|
|
|
@ -102,7 +102,7 @@ struct dsl_dir {
|
||||||
|
|
||||||
/* Protected by dd_lock */
|
/* Protected by dd_lock */
|
||||||
kmutex_t dd_lock;
|
kmutex_t dd_lock;
|
||||||
list_t dd_prop_cbs; /* list of dsl_prop_cb_record_t's */
|
list_t dd_props; /* list of dsl_prop_record_t's */
|
||||||
timestruc_t dd_snap_cmtime; /* last time snapshot namespace changed */
|
timestruc_t dd_snap_cmtime; /* last time snapshot namespace changed */
|
||||||
uint64_t dd_origin_txg;
|
uint64_t dd_origin_txg;
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,17 @@ struct dsl_dir;
|
||||||
/* The callback func may not call into the DMU or DSL! */
|
/* The callback func may not call into the DMU or DSL! */
|
||||||
typedef void (dsl_prop_changed_cb_t)(void *arg, uint64_t newval);
|
typedef void (dsl_prop_changed_cb_t)(void *arg, uint64_t newval);
|
||||||
|
|
||||||
|
typedef struct dsl_prop_record {
|
||||||
|
list_node_t pr_node; /* link on dd_props */
|
||||||
|
const char *pr_propname;
|
||||||
|
list_t pr_cbs;
|
||||||
|
} dsl_prop_record_t;
|
||||||
|
|
||||||
typedef struct dsl_prop_cb_record {
|
typedef struct dsl_prop_cb_record {
|
||||||
list_node_t cbr_node; /* link on dd_prop_cbs */
|
list_node_t cbr_pr_node; /* link on pr_cbs */
|
||||||
|
list_node_t cbr_ds_node; /* link on ds_prop_cbs */
|
||||||
|
dsl_prop_record_t *cbr_pr;
|
||||||
struct dsl_dataset *cbr_ds;
|
struct dsl_dataset *cbr_ds;
|
||||||
const char *cbr_propname;
|
|
||||||
dsl_prop_changed_cb_t *cbr_func;
|
dsl_prop_changed_cb_t *cbr_func;
|
||||||
void *cbr_arg;
|
void *cbr_arg;
|
||||||
} dsl_prop_cb_record_t;
|
} dsl_prop_cb_record_t;
|
||||||
|
@ -54,10 +61,13 @@ typedef struct dsl_props_arg {
|
||||||
zprop_source_t pa_source;
|
zprop_source_t pa_source;
|
||||||
} dsl_props_arg_t;
|
} dsl_props_arg_t;
|
||||||
|
|
||||||
|
void dsl_prop_init(dsl_dir_t *dd);
|
||||||
|
void dsl_prop_fini(dsl_dir_t *dd);
|
||||||
int dsl_prop_register(struct dsl_dataset *ds, const char *propname,
|
int dsl_prop_register(struct dsl_dataset *ds, const char *propname,
|
||||||
dsl_prop_changed_cb_t *callback, void *cbarg);
|
dsl_prop_changed_cb_t *callback, void *cbarg);
|
||||||
int dsl_prop_unregister(struct dsl_dataset *ds, const char *propname,
|
int dsl_prop_unregister(struct dsl_dataset *ds, const char *propname,
|
||||||
dsl_prop_changed_cb_t *callback, void *cbarg);
|
dsl_prop_changed_cb_t *callback, void *cbarg);
|
||||||
|
void dsl_prop_unregister_all(struct dsl_dataset *ds, void *cbarg);
|
||||||
void dsl_prop_notify_all(struct dsl_dir *dd);
|
void dsl_prop_notify_all(struct dsl_dir *dd);
|
||||||
boolean_t dsl_prop_hascb(struct dsl_dataset *ds);
|
boolean_t dsl_prop_hascb(struct dsl_dataset *ds);
|
||||||
|
|
||||||
|
|
|
@ -688,40 +688,8 @@ dmu_objset_evict(objset_t *os)
|
||||||
for (t = 0; t < TXG_SIZE; t++)
|
for (t = 0; t < TXG_SIZE; t++)
|
||||||
ASSERT(!dmu_objset_is_dirty(os, t));
|
ASSERT(!dmu_objset_is_dirty(os, t));
|
||||||
|
|
||||||
if (ds) {
|
if (ds)
|
||||||
if (!ds->ds_is_snapshot) {
|
dsl_prop_unregister_all(ds, os);
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_CHECKSUM),
|
|
||||||
checksum_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_COMPRESSION),
|
|
||||||
compression_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_COPIES),
|
|
||||||
copies_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_DEDUP),
|
|
||||||
dedup_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_LOGBIAS),
|
|
||||||
logbias_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_SYNC),
|
|
||||||
sync_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_REDUNDANT_METADATA),
|
|
||||||
redundant_metadata_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
|
|
||||||
recordsize_changed_cb, os));
|
|
||||||
}
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE),
|
|
||||||
primary_cache_changed_cb, os));
|
|
||||||
VERIFY0(dsl_prop_unregister(ds,
|
|
||||||
zfs_prop_to_name(ZFS_PROP_SECONDARYCACHE),
|
|
||||||
secondary_cache_changed_cb, os));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os->os_sa)
|
if (os->os_sa)
|
||||||
sa_tear_down(os);
|
sa_tear_down(os);
|
||||||
|
|
|
@ -284,6 +284,7 @@ dsl_dataset_evict(void *dbu)
|
||||||
|
|
||||||
ASSERT(!list_link_active(&ds->ds_synced_link));
|
ASSERT(!list_link_active(&ds->ds_synced_link));
|
||||||
|
|
||||||
|
list_destroy(&ds->ds_prop_cbs);
|
||||||
mutex_destroy(&ds->ds_lock);
|
mutex_destroy(&ds->ds_lock);
|
||||||
mutex_destroy(&ds->ds_opening_lock);
|
mutex_destroy(&ds->ds_opening_lock);
|
||||||
mutex_destroy(&ds->ds_sendstream_lock);
|
mutex_destroy(&ds->ds_sendstream_lock);
|
||||||
|
@ -433,6 +434,9 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
|
||||||
list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t),
|
list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t),
|
||||||
offsetof(dmu_sendarg_t, dsa_link));
|
offsetof(dmu_sendarg_t, dsa_link));
|
||||||
|
|
||||||
|
list_create(&ds->ds_prop_cbs, sizeof (dsl_prop_cb_record_t),
|
||||||
|
offsetof(dsl_prop_cb_record_t, cbr_ds_node));
|
||||||
|
|
||||||
if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
|
if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
|
||||||
spa_feature_t f;
|
spa_feature_t f;
|
||||||
|
|
||||||
|
|
|
@ -147,11 +147,7 @@ dsl_dir_evict(void *dbu)
|
||||||
|
|
||||||
spa_async_close(dd->dd_pool->dp_spa, dd);
|
spa_async_close(dd->dd_pool->dp_spa, dd);
|
||||||
|
|
||||||
/*
|
dsl_prop_fini(dd);
|
||||||
* The props callback list should have been cleaned up by
|
|
||||||
* objset_evict().
|
|
||||||
*/
|
|
||||||
list_destroy(&dd->dd_prop_cbs);
|
|
||||||
mutex_destroy(&dd->dd_lock);
|
mutex_destroy(&dd->dd_lock);
|
||||||
kmem_free(dd, sizeof (dsl_dir_t));
|
kmem_free(dd, sizeof (dsl_dir_t));
|
||||||
}
|
}
|
||||||
|
@ -186,9 +182,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
dd->dd_dbuf = dbuf;
|
dd->dd_dbuf = dbuf;
|
||||||
dd->dd_pool = dp;
|
dd->dd_pool = dp;
|
||||||
mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL);
|
mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
|
dsl_prop_init(dd);
|
||||||
list_create(&dd->dd_prop_cbs, sizeof (dsl_prop_cb_record_t),
|
|
||||||
offsetof(dsl_prop_cb_record_t, cbr_node));
|
|
||||||
|
|
||||||
dsl_dir_snap_cmtime_update(dd);
|
dsl_dir_snap_cmtime_update(dd);
|
||||||
|
|
||||||
|
@ -246,6 +240,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
if (winner != NULL) {
|
if (winner != NULL) {
|
||||||
if (dd->dd_parent)
|
if (dd->dd_parent)
|
||||||
dsl_dir_rele(dd->dd_parent, dd);
|
dsl_dir_rele(dd->dd_parent, dd);
|
||||||
|
dsl_prop_fini(dd);
|
||||||
mutex_destroy(&dd->dd_lock);
|
mutex_destroy(&dd->dd_lock);
|
||||||
kmem_free(dd, sizeof (dsl_dir_t));
|
kmem_free(dd, sizeof (dsl_dir_t));
|
||||||
dd = winner;
|
dd = winner;
|
||||||
|
@ -273,6 +268,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
errout:
|
errout:
|
||||||
if (dd->dd_parent)
|
if (dd->dd_parent)
|
||||||
dsl_dir_rele(dd->dd_parent, dd);
|
dsl_dir_rele(dd->dd_parent, dd);
|
||||||
|
dsl_prop_fini(dd);
|
||||||
mutex_destroy(&dd->dd_lock);
|
mutex_destroy(&dd->dd_lock);
|
||||||
kmem_free(dd, sizeof (dsl_dir_t));
|
kmem_free(dd, sizeof (dsl_dir_t));
|
||||||
dmu_buf_rele(dbuf, tag);
|
dmu_buf_rele(dbuf, tag);
|
||||||
|
|
|
@ -216,6 +216,58 @@ dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
|
||||||
intsz, numints, buf, setpoint, ds->ds_is_snapshot));
|
intsz, numints, buf, setpoint, ds->ds_is_snapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dsl_prop_record_t *
|
||||||
|
dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
|
||||||
|
{
|
||||||
|
dsl_prop_record_t *pr = NULL;
|
||||||
|
|
||||||
|
ASSERT(MUTEX_HELD(&dd->dd_lock));
|
||||||
|
|
||||||
|
for (pr = list_head(&dd->dd_props);
|
||||||
|
pr != NULL; pr = list_next(&dd->dd_props, pr)) {
|
||||||
|
if (strcmp(pr->pr_propname, propname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dsl_prop_record_t *
|
||||||
|
dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
|
||||||
|
{
|
||||||
|
dsl_prop_record_t *pr;
|
||||||
|
|
||||||
|
ASSERT(MUTEX_HELD(&dd->dd_lock));
|
||||||
|
|
||||||
|
pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
|
||||||
|
pr->pr_propname = spa_strdup(propname);
|
||||||
|
list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
|
||||||
|
offsetof(dsl_prop_cb_record_t, cbr_pr_node));
|
||||||
|
list_insert_head(&dd->dd_props, pr);
|
||||||
|
|
||||||
|
return (pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dsl_prop_init(dsl_dir_t *dd)
|
||||||
|
{
|
||||||
|
list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
|
||||||
|
offsetof(dsl_prop_record_t, pr_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dsl_prop_fini(dsl_dir_t *dd)
|
||||||
|
{
|
||||||
|
dsl_prop_record_t *pr;
|
||||||
|
|
||||||
|
while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
|
||||||
|
list_destroy(&pr->pr_cbs);
|
||||||
|
strfree((char *)pr->pr_propname);
|
||||||
|
kmem_free(pr, sizeof (dsl_prop_record_t));
|
||||||
|
}
|
||||||
|
list_destroy(&dd->dd_props);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register interest in the named property. We'll call the callback
|
* Register interest in the named property. We'll call the callback
|
||||||
* once to notify it of the current property value, and again each time
|
* once to notify it of the current property value, and again each time
|
||||||
|
@ -229,6 +281,7 @@ dsl_prop_register(dsl_dataset_t *ds, const char *propname,
|
||||||
{
|
{
|
||||||
dsl_dir_t *dd = ds->ds_dir;
|
dsl_dir_t *dd = ds->ds_dir;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
|
dsl_prop_record_t *pr;
|
||||||
dsl_prop_cb_record_t *cbr;
|
dsl_prop_cb_record_t *cbr;
|
||||||
int err;
|
int err;
|
||||||
ASSERTV(dsl_pool_t *dp = dd->dd_pool);
|
ASSERTV(dsl_pool_t *dp = dd->dd_pool);
|
||||||
|
@ -241,12 +294,16 @@ dsl_prop_register(dsl_dataset_t *ds, const char *propname,
|
||||||
|
|
||||||
cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
|
cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
|
||||||
cbr->cbr_ds = ds;
|
cbr->cbr_ds = ds;
|
||||||
cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP);
|
|
||||||
(void) strcpy((char *)cbr->cbr_propname, propname);
|
|
||||||
cbr->cbr_func = callback;
|
cbr->cbr_func = callback;
|
||||||
cbr->cbr_arg = cbarg;
|
cbr->cbr_arg = cbarg;
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
mutex_enter(&dd->dd_lock);
|
||||||
list_insert_head(&dd->dd_prop_cbs, cbr);
|
pr = dsl_prop_record_find(dd, propname);
|
||||||
|
if (pr == NULL)
|
||||||
|
pr = dsl_prop_record_create(dd, propname);
|
||||||
|
cbr->cbr_pr = pr;
|
||||||
|
list_insert_head(&pr->pr_cbs, cbr);
|
||||||
|
list_insert_head(&ds->ds_prop_cbs, cbr);
|
||||||
mutex_exit(&dd->dd_lock);
|
mutex_exit(&dd->dd_lock);
|
||||||
|
|
||||||
cbr->cbr_func(cbr->cbr_arg, value);
|
cbr->cbr_func(cbr->cbr_arg, value);
|
||||||
|
@ -379,6 +436,9 @@ dsl_prop_predict(dsl_dir_t *dd, const char *propname,
|
||||||
/*
|
/*
|
||||||
* Unregister this callback. Return 0 on success, ENOENT if ddname is
|
* Unregister this callback. Return 0 on success, ENOENT if ddname is
|
||||||
* invalid, or ENOMSG if no matching callback registered.
|
* invalid, or ENOMSG if no matching callback registered.
|
||||||
|
*
|
||||||
|
* NOTE: This function is no longer used internally but has been preserved
|
||||||
|
* to prevent breaking external consumers (Lustre, etc).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
|
dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
|
||||||
|
@ -388,12 +448,12 @@ dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
|
||||||
dsl_prop_cb_record_t *cbr;
|
dsl_prop_cb_record_t *cbr;
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
mutex_enter(&dd->dd_lock);
|
||||||
for (cbr = list_head(&dd->dd_prop_cbs);
|
for (cbr = list_head(&ds->ds_prop_cbs);
|
||||||
cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
|
cbr; cbr = list_next(&ds->ds_prop_cbs, cbr)) {
|
||||||
if (cbr->cbr_ds == ds &&
|
if (cbr->cbr_ds == ds &&
|
||||||
cbr->cbr_func == callback &&
|
cbr->cbr_func == callback &&
|
||||||
cbr->cbr_arg == cbarg &&
|
cbr->cbr_arg == cbarg &&
|
||||||
strcmp(cbr->cbr_propname, propname) == 0)
|
strcmp(cbr->cbr_pr->pr_propname, propname) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,31 +462,43 @@ dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
|
||||||
return (SET_ERROR(ENOMSG));
|
return (SET_ERROR(ENOMSG));
|
||||||
}
|
}
|
||||||
|
|
||||||
list_remove(&dd->dd_prop_cbs, cbr);
|
list_remove(&ds->ds_prop_cbs, cbr);
|
||||||
|
list_remove(&cbr->cbr_pr->pr_cbs, cbr);
|
||||||
mutex_exit(&dd->dd_lock);
|
mutex_exit(&dd->dd_lock);
|
||||||
kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1);
|
|
||||||
kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
|
kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean_t
|
/*
|
||||||
dsl_prop_hascb(dsl_dataset_t *ds)
|
* Unregister all callbacks that are registered with the
|
||||||
|
* given callback argument.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
|
||||||
{
|
{
|
||||||
|
dsl_prop_cb_record_t *cbr, *next_cbr;
|
||||||
|
|
||||||
dsl_dir_t *dd = ds->ds_dir;
|
dsl_dir_t *dd = ds->ds_dir;
|
||||||
boolean_t rv = B_FALSE;
|
|
||||||
dsl_prop_cb_record_t *cbr;
|
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
mutex_enter(&dd->dd_lock);
|
||||||
for (cbr = list_head(&dd->dd_prop_cbs); cbr;
|
next_cbr = list_head(&ds->ds_prop_cbs);
|
||||||
cbr = list_next(&dd->dd_prop_cbs, cbr)) {
|
while (next_cbr != NULL) {
|
||||||
if (cbr->cbr_ds == ds) {
|
cbr = next_cbr;
|
||||||
rv = B_TRUE;
|
next_cbr = list_next(&ds->ds_prop_cbs, cbr);
|
||||||
break;
|
if (cbr->cbr_arg == cbarg) {
|
||||||
|
list_remove(&ds->ds_prop_cbs, cbr);
|
||||||
|
list_remove(&cbr->cbr_pr->pr_cbs, cbr);
|
||||||
|
kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_exit(&dd->dd_lock);
|
mutex_exit(&dd->dd_lock);
|
||||||
return (rv);
|
}
|
||||||
|
|
||||||
|
boolean_t
|
||||||
|
dsl_prop_hascb(dsl_dataset_t *ds)
|
||||||
|
{
|
||||||
|
return (!list_is_empty(&ds->ds_prop_cbs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
|
@ -434,39 +506,51 @@ static int
|
||||||
dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
|
dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
|
||||||
{
|
{
|
||||||
dsl_dir_t *dd = ds->ds_dir;
|
dsl_dir_t *dd = ds->ds_dir;
|
||||||
|
dsl_prop_record_t *pr;
|
||||||
dsl_prop_cb_record_t *cbr;
|
dsl_prop_cb_record_t *cbr;
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
mutex_enter(&dd->dd_lock);
|
||||||
for (cbr = list_head(&dd->dd_prop_cbs); cbr;
|
for (pr = list_head(&dd->dd_props);
|
||||||
cbr = list_next(&dd->dd_prop_cbs, cbr)) {
|
pr; pr = list_next(&dd->dd_props, pr)) {
|
||||||
|
for (cbr = list_head(&pr->pr_cbs); cbr;
|
||||||
|
cbr = list_next(&pr->pr_cbs, cbr)) {
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Callback entries do not have holds on their datasets
|
* Callback entries do not have holds on their
|
||||||
* so that datasets with registered callbacks are still
|
* datasets so that datasets with registered
|
||||||
* eligible for eviction. Unlike operations on callbacks
|
* callbacks are still eligible for eviction.
|
||||||
* for a single dataset, we are performing a recursive
|
* Unlike operations to update properties on a
|
||||||
* descent of related datasets and the calling context
|
* single dataset, we are performing a recursive
|
||||||
* for this iteration only has a dataset hold on the root.
|
* descent of related head datasets. The caller
|
||||||
* Without a hold, the callback's pointer to the dataset
|
* of this function only has a dataset hold on
|
||||||
* could be invalidated by eviction at any time.
|
* the passed in head dataset, not the snapshots
|
||||||
|
* associated with this dataset. Without a hold,
|
||||||
|
* the dataset pointer within callback records
|
||||||
|
* for snapshots can be invalidated by eviction
|
||||||
|
* at any time.
|
||||||
*
|
*
|
||||||
* Use dsl_dataset_try_add_ref() to verify that the
|
* Use dsl_dataset_try_add_ref() to verify
|
||||||
* dataset has not begun eviction processing and to
|
* that the dataset for a snapshot has not
|
||||||
* prevent eviction from occurring for the duration
|
* begun eviction processing and to prevent
|
||||||
* of the callback. If the hold attempt fails, this
|
* eviction from occurring for the duration of
|
||||||
* object is already being evicted and the callback can
|
* the callback. If the hold attempt fails,
|
||||||
* be safely ignored.
|
* this object is already being evicted and the
|
||||||
|
* callback can be safely ignored.
|
||||||
*/
|
*/
|
||||||
if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
|
if (ds != cbr->cbr_ds &&
|
||||||
|
!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname,
|
if (dsl_prop_get_ds(cbr->cbr_ds,
|
||||||
sizeof (value), 1, &value, NULL) == 0)
|
cbr->cbr_pr->pr_propname, sizeof (value), 1,
|
||||||
|
&value, NULL) == 0)
|
||||||
cbr->cbr_func(cbr->cbr_arg, value);
|
cbr->cbr_func(cbr->cbr_arg, value);
|
||||||
|
|
||||||
|
if (ds != cbr->cbr_ds)
|
||||||
dsl_dataset_rele(cbr->cbr_ds, FTAG);
|
dsl_dataset_rele(cbr->cbr_ds, FTAG);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mutex_exit(&dd->dd_lock);
|
mutex_exit(&dd->dd_lock);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
@ -490,6 +574,7 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
const char *propname, uint64_t value, int first)
|
const char *propname, uint64_t value, int first)
|
||||||
{
|
{
|
||||||
dsl_dir_t *dd;
|
dsl_dir_t *dd;
|
||||||
|
dsl_prop_record_t *pr;
|
||||||
dsl_prop_cb_record_t *cbr;
|
dsl_prop_cb_record_t *cbr;
|
||||||
objset_t *mos = dp->dp_meta_objset;
|
objset_t *mos = dp->dp_meta_objset;
|
||||||
zap_cursor_t zc;
|
zap_cursor_t zc;
|
||||||
|
@ -516,18 +601,19 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
mutex_enter(&dd->dd_lock);
|
||||||
for (cbr = list_head(&dd->dd_prop_cbs); cbr;
|
pr = dsl_prop_record_find(dd, propname);
|
||||||
cbr = list_next(&dd->dd_prop_cbs, cbr)) {
|
if (pr != NULL) {
|
||||||
|
for (cbr = list_head(&pr->pr_cbs); cbr;
|
||||||
|
cbr = list_next(&pr->pr_cbs, cbr)) {
|
||||||
uint64_t propobj;
|
uint64_t propobj;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cbr->cbf_ds may be invalidated due to eviction,
|
* cbr->cbr_ds may be invalidated due to eviction,
|
||||||
* requiring the use of dsl_dataset_try_add_ref().
|
* requiring the use of dsl_dataset_try_add_ref().
|
||||||
* See comment block in dsl_prop_notify_all_cb()
|
* See comment block in dsl_prop_notify_all_cb()
|
||||||
* for details.
|
* for details.
|
||||||
*/
|
*/
|
||||||
if (strcmp(cbr->cbr_propname, propname) != 0 ||
|
if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
|
||||||
!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
|
propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
|
||||||
|
@ -536,11 +622,13 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
* If the property is not set on this ds, then it is
|
* If the property is not set on this ds, then it is
|
||||||
* inherited here; call the callback.
|
* inherited here; call the callback.
|
||||||
*/
|
*/
|
||||||
if (propobj == 0 || zap_contains(mos, propobj, propname) != 0)
|
if (propobj == 0 ||
|
||||||
|
zap_contains(mos, propobj, propname) != 0)
|
||||||
cbr->cbr_func(cbr->cbr_arg, value);
|
cbr->cbr_func(cbr->cbr_arg, value);
|
||||||
|
|
||||||
dsl_dataset_rele(cbr->cbr_ds, FTAG);
|
dsl_dataset_rele(cbr->cbr_ds, FTAG);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mutex_exit(&dd->dd_lock);
|
mutex_exit(&dd->dd_lock);
|
||||||
|
|
||||||
za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
|
za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
|
||||||
|
@ -679,10 +767,10 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
|
||||||
* ds here.
|
* ds here.
|
||||||
*/
|
*/
|
||||||
mutex_enter(&ds->ds_dir->dd_lock);
|
mutex_enter(&ds->ds_dir->dd_lock);
|
||||||
for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
|
for (cbr = list_head(&ds->ds_prop_cbs); cbr;
|
||||||
cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
|
cbr = list_next(&ds->ds_prop_cbs, cbr)) {
|
||||||
if (cbr->cbr_ds == ds &&
|
if (strcmp(cbr->cbr_pr->pr_propname,
|
||||||
strcmp(cbr->cbr_propname, propname) == 0)
|
propname) == 0)
|
||||||
cbr->cbr_func(cbr->cbr_arg, intval);
|
cbr->cbr_func(cbr->cbr_arg, intval);
|
||||||
}
|
}
|
||||||
mutex_exit(&ds->ds_dir->dd_lock);
|
mutex_exit(&ds->ds_dir->dd_lock);
|
||||||
|
@ -1158,6 +1246,7 @@ dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
|
||||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||||
EXPORT_SYMBOL(dsl_prop_register);
|
EXPORT_SYMBOL(dsl_prop_register);
|
||||||
EXPORT_SYMBOL(dsl_prop_unregister);
|
EXPORT_SYMBOL(dsl_prop_unregister);
|
||||||
|
EXPORT_SYMBOL(dsl_prop_unregister_all);
|
||||||
EXPORT_SYMBOL(dsl_prop_get);
|
EXPORT_SYMBOL(dsl_prop_get);
|
||||||
EXPORT_SYMBOL(dsl_prop_get_integer);
|
EXPORT_SYMBOL(dsl_prop_get_integer);
|
||||||
EXPORT_SYMBOL(dsl_prop_get_all);
|
EXPORT_SYMBOL(dsl_prop_get_all);
|
||||||
|
|
|
@ -341,38 +341,7 @@ zfs_register_callbacks(zfs_sb_t *zsb)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
unregister:
|
unregister:
|
||||||
/*
|
dsl_prop_unregister_all(ds, zsb);
|
||||||
* We may attempt to unregister some callbacks that are not
|
|
||||||
* registered, but this is OK; it will simply return ENOMSG,
|
|
||||||
* which we will ignore.
|
|
||||||
*/
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ATIME),
|
|
||||||
atime_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RELATIME),
|
|
||||||
relatime_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR),
|
|
||||||
xattr_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
|
|
||||||
blksz_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_READONLY),
|
|
||||||
readonly_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_DEVICES),
|
|
||||||
devices_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SETUID),
|
|
||||||
setuid_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_EXEC),
|
|
||||||
exec_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR),
|
|
||||||
snapdir_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLTYPE),
|
|
||||||
acltype_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT),
|
|
||||||
acl_inherit_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_VSCAN),
|
|
||||||
vscan_changed_cb, zsb);
|
|
||||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_NBMAND),
|
|
||||||
nbmand_changed_cb, zsb);
|
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(zfs_register_callbacks);
|
EXPORT_SYMBOL(zfs_register_callbacks);
|
||||||
|
@ -959,52 +928,9 @@ void
|
||||||
zfs_unregister_callbacks(zfs_sb_t *zsb)
|
zfs_unregister_callbacks(zfs_sb_t *zsb)
|
||||||
{
|
{
|
||||||
objset_t *os = zsb->z_os;
|
objset_t *os = zsb->z_os;
|
||||||
struct dsl_dataset *ds;
|
|
||||||
|
|
||||||
/*
|
if (!dmu_objset_is_snapshot(os))
|
||||||
* Unregister properties.
|
dsl_prop_unregister_all(dmu_objset_ds(os), zsb);
|
||||||
*/
|
|
||||||
if (!dmu_objset_is_snapshot(os)) {
|
|
||||||
ds = dmu_objset_ds(os);
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "atime", atime_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "relatime", relatime_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "xattr", xattr_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "recordsize", blksz_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "readonly", readonly_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "devices", devices_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "setuid", setuid_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "exec", exec_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "acltype", acltype_changed_cb,
|
|
||||||
zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "aclinherit",
|
|
||||||
acl_inherit_changed_cb, zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "vscan",
|
|
||||||
vscan_changed_cb, zsb) == 0);
|
|
||||||
|
|
||||||
VERIFY(dsl_prop_unregister(ds, "nbmand",
|
|
||||||
nbmand_changed_cb, zsb) == 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(zfs_unregister_callbacks);
|
EXPORT_SYMBOL(zfs_unregister_callbacks);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue