Print this page
5056 ZFS deadlock on db_mtx and dn_holds
Reviewed by: Will Andrews <willa@spectralogic.com>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>


 146                  * that err has a valid post-loop value.
 147                  */
 148                 err = SET_ERROR(ENOENT);
 149         }
 150 
 151         if (err == ENOENT)
 152                 err = dodefault(propname, intsz, numints, buf);
 153 
 154         strfree(inheritstr);
 155         strfree(recvdstr);
 156 
 157         return (err);
 158 }
 159 
 160 int
 161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
 162     int intsz, int numints, void *buf, char *setpoint)
 163 {
 164         zfs_prop_t prop = zfs_name_to_prop(propname);
 165         boolean_t inheritable;
 166         boolean_t snapshot;
 167         uint64_t zapobj;
 168 
 169         ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 170         inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
 171         snapshot = dsl_dataset_is_snapshot(ds);
 172         zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 173 
 174         if (zapobj != 0) {
 175                 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 176                 int err;
 177 
 178                 ASSERT(snapshot);
 179 
 180                 /* Check for a local value. */
 181                 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
 182                 if (err != ENOENT) {
 183                         if (setpoint != NULL && err == 0)
 184                                 dsl_dataset_name(ds, setpoint);
 185                         return (err);
 186                 }
 187 
 188                 /*
 189                  * Skip the check for a received value if there is an explicit
 190                  * inheritance entry.
 191                  */
 192                 if (inheritable) {
 193                         char *inheritstr = kmem_asprintf("%s%s", propname,
 194                             ZPROP_INHERIT_SUFFIX);
 195                         err = zap_contains(mos, zapobj, inheritstr);
 196                         strfree(inheritstr);
 197                         if (err != 0 && err != ENOENT)
 198                                 return (err);
 199                 }
 200 
 201                 if (err == ENOENT) {
 202                         /* Check for a received value. */
 203                         char *recvdstr = kmem_asprintf("%s%s", propname,
 204                             ZPROP_RECVD_SUFFIX);
 205                         err = zap_lookup(mos, zapobj, recvdstr,
 206                             intsz, numints, buf);
 207                         strfree(recvdstr);
 208                         if (err != ENOENT) {
 209                                 if (setpoint != NULL && err == 0)
 210                                         (void) strcpy(setpoint,
 211                                             ZPROP_SOURCE_VAL_RECVD);
 212                                 return (err);
 213                         }
 214                 }
 215         }
 216 
 217         return (dsl_prop_get_dd(ds->ds_dir, propname,
 218             intsz, numints, buf, setpoint, snapshot));
 219 }
 220 
 221 /*
 222  * Register interest in the named property.  We'll call the callback
 223  * once to notify it of the current property value, and again each time
 224  * the property changes, until this callback is unregistered.
 225  *
 226  * Return 0 on success, errno if the prop is not an integer value.
 227  */
 228 int
 229 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 230     dsl_prop_changed_cb_t *callback, void *cbarg)
 231 {
 232         dsl_dir_t *dd = ds->ds_dir;
 233         dsl_pool_t *dp = dd->dd_pool;
 234         uint64_t value;
 235         dsl_prop_cb_record_t *cbr;
 236         int err;
 237 
 238         ASSERT(dsl_pool_config_held(dp));


 528 }
 529 
 530 void
 531 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 532     zprop_source_t source, int intsz, int numints, const void *value,
 533     dmu_tx_t *tx)
 534 {
 535         objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 536         uint64_t zapobj, intval, dummy;
 537         int isint;
 538         char valbuf[32];
 539         const char *valstr = NULL;
 540         char *inheritstr;
 541         char *recvdstr;
 542         char *tbuf = NULL;
 543         int err;
 544         uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 545 
 546         isint = (dodefault(propname, 8, 1, &intval) == 0);
 547 
 548         if (dsl_dataset_is_snapshot(ds)) {
 549                 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
 550                 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
 551                         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 552                         dsl_dataset_phys(ds)->ds_props_obj =
 553                             zap_create(mos,
 554                             DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
 555                 }
 556                 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 557         } else {
 558                 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
 559         }
 560 
 561         if (version < SPA_VERSION_RECVD_PROPS) {
 562                 if (source & ZPROP_SRC_NONE)
 563                         source = ZPROP_SRC_NONE;
 564                 else if (source & ZPROP_SRC_RECEIVED)
 565                         source = ZPROP_SRC_LOCAL;
 566         }
 567 
 568         inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);


 625                 err = zap_remove(mos, zapobj, inheritstr, tx);
 626                 ASSERT(err == 0 || err == ENOENT);
 627                 /* FALLTHRU */
 628         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 629                 /*
 630                  * remove propname$recvd
 631                  */
 632                 err = zap_remove(mos, zapobj, recvdstr, tx);
 633                 ASSERT(err == 0 || err == ENOENT);
 634                 break;
 635         default:
 636                 cmn_err(CE_PANIC, "unexpected property source: %d", source);
 637         }
 638 
 639         strfree(inheritstr);
 640         strfree(recvdstr);
 641 
 642         if (isint) {
 643                 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
 644 
 645                 if (dsl_dataset_is_snapshot(ds)) {
 646                         dsl_prop_cb_record_t *cbr;
 647                         /*
 648                          * It's a snapshot; nothing can inherit this
 649                          * property, so just look for callbacks on this
 650                          * ds here.
 651                          */
 652                         mutex_enter(&ds->ds_dir->dd_lock);
 653                         for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
 654                             cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
 655                                 if (cbr->cbr_ds == ds &&
 656                                     strcmp(cbr->cbr_propname, propname) == 0)
 657                                         cbr->cbr_func(cbr->cbr_arg, intval);
 658                         }
 659                         mutex_exit(&ds->ds_dir->dd_lock);
 660                 } else {
 661                         dsl_prop_changed_notify(ds->ds_dir->dd_pool,
 662                             ds->ds_dir->dd_object, propname, intval, TRUE);
 663                 }
 664 
 665                 (void) snprintf(valbuf, sizeof (valbuf),


 743         if (err != 0)
 744                 return (err);
 745 
 746         version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 747         while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
 748                 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
 749                         dsl_dataset_rele(ds, FTAG);
 750                         return (SET_ERROR(ENAMETOOLONG));
 751                 }
 752                 if (nvpair_type(elem) == DATA_TYPE_STRING) {
 753                         char *valstr = fnvpair_value_string(elem);
 754                         if (strlen(valstr) >= (version <
 755                             SPA_VERSION_STMF_PROP ?
 756                             ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
 757                                 dsl_dataset_rele(ds, FTAG);
 758                                 return (E2BIG);
 759                         }
 760                 }
 761         }
 762 
 763         if (dsl_dataset_is_snapshot(ds) && version < SPA_VERSION_SNAP_PROPS) {
 764                 dsl_dataset_rele(ds, FTAG);
 765                 return (SET_ERROR(ENOTSUP));
 766         }
 767         dsl_dataset_rele(ds, FTAG);
 768         return (0);
 769 }
 770 
 771 void
 772 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
 773     nvlist_t *props, dmu_tx_t *tx)
 774 {
 775         nvpair_t *elem = NULL;
 776 
 777         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 778                 nvpair_t *pair = elem;
 779 
 780                 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
 781                         /*
 782                          * dsl_prop_get_all_impl() returns properties in this
 783                          * format.


 966         if (err == ENOENT)
 967                 err = 0;
 968         return (err);
 969 }
 970 
 971 /*
 972  * Iterate over all properties for this dataset and return them in an nvlist.
 973  */
 974 static int
 975 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
 976     dsl_prop_getflags_t flags)
 977 {
 978         dsl_dir_t *dd = ds->ds_dir;
 979         dsl_pool_t *dp = dd->dd_pool;
 980         objset_t *mos = dp->dp_meta_objset;
 981         int err = 0;
 982         char setpoint[MAXNAMELEN];
 983 
 984         VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 985 
 986         if (dsl_dataset_is_snapshot(ds))
 987                 flags |= DSL_PROP_GET_SNAPSHOT;
 988 
 989         ASSERT(dsl_pool_config_held(dp));
 990 
 991         if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
 992                 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
 993                 dsl_dataset_name(ds, setpoint);
 994                 err = dsl_prop_get_all_impl(mos,
 995                     dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
 996                 if (err)
 997                         goto out;
 998         }
 999 
1000         for (; dd != NULL; dd = dd->dd_parent) {
1001                 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1002                         if (flags & (DSL_PROP_GET_LOCAL |
1003                             DSL_PROP_GET_RECEIVED))
1004                                 break;
1005                         flags |= DSL_PROP_GET_INHERITING;
1006                 }




 146                  * that err has a valid post-loop value.
 147                  */
 148                 err = SET_ERROR(ENOENT);
 149         }
 150 
 151         if (err == ENOENT)
 152                 err = dodefault(propname, intsz, numints, buf);
 153 
 154         strfree(inheritstr);
 155         strfree(recvdstr);
 156 
 157         return (err);
 158 }
 159 
 160 int
 161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
 162     int intsz, int numints, void *buf, char *setpoint)
 163 {
 164         zfs_prop_t prop = zfs_name_to_prop(propname);
 165         boolean_t inheritable;

 166         uint64_t zapobj;
 167 
 168         ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 169         inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));

 170         zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 171 
 172         if (zapobj != 0) {
 173                 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 174                 int err;
 175 
 176                 ASSERT(ds->ds_is_snapshot);
 177 
 178                 /* Check for a local value. */
 179                 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
 180                 if (err != ENOENT) {
 181                         if (setpoint != NULL && err == 0)
 182                                 dsl_dataset_name(ds, setpoint);
 183                         return (err);
 184                 }
 185 
 186                 /*
 187                  * Skip the check for a received value if there is an explicit
 188                  * inheritance entry.
 189                  */
 190                 if (inheritable) {
 191                         char *inheritstr = kmem_asprintf("%s%s", propname,
 192                             ZPROP_INHERIT_SUFFIX);
 193                         err = zap_contains(mos, zapobj, inheritstr);
 194                         strfree(inheritstr);
 195                         if (err != 0 && err != ENOENT)
 196                                 return (err);
 197                 }
 198 
 199                 if (err == ENOENT) {
 200                         /* Check for a received value. */
 201                         char *recvdstr = kmem_asprintf("%s%s", propname,
 202                             ZPROP_RECVD_SUFFIX);
 203                         err = zap_lookup(mos, zapobj, recvdstr,
 204                             intsz, numints, buf);
 205                         strfree(recvdstr);
 206                         if (err != ENOENT) {
 207                                 if (setpoint != NULL && err == 0)
 208                                         (void) strcpy(setpoint,
 209                                             ZPROP_SOURCE_VAL_RECVD);
 210                                 return (err);
 211                         }
 212                 }
 213         }
 214 
 215         return (dsl_prop_get_dd(ds->ds_dir, propname,
 216             intsz, numints, buf, setpoint, ds->ds_is_snapshot));
 217 }
 218 
 219 /*
 220  * Register interest in the named property.  We'll call the callback
 221  * once to notify it of the current property value, and again each time
 222  * the property changes, until this callback is unregistered.
 223  *
 224  * Return 0 on success, errno if the prop is not an integer value.
 225  */
 226 int
 227 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 228     dsl_prop_changed_cb_t *callback, void *cbarg)
 229 {
 230         dsl_dir_t *dd = ds->ds_dir;
 231         dsl_pool_t *dp = dd->dd_pool;
 232         uint64_t value;
 233         dsl_prop_cb_record_t *cbr;
 234         int err;
 235 
 236         ASSERT(dsl_pool_config_held(dp));


 526 }
 527 
 528 void
 529 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 530     zprop_source_t source, int intsz, int numints, const void *value,
 531     dmu_tx_t *tx)
 532 {
 533         objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 534         uint64_t zapobj, intval, dummy;
 535         int isint;
 536         char valbuf[32];
 537         const char *valstr = NULL;
 538         char *inheritstr;
 539         char *recvdstr;
 540         char *tbuf = NULL;
 541         int err;
 542         uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 543 
 544         isint = (dodefault(propname, 8, 1, &intval) == 0);
 545 
 546         if (ds->ds_is_snapshot) {
 547                 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
 548                 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
 549                         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 550                         dsl_dataset_phys(ds)->ds_props_obj =
 551                             zap_create(mos,
 552                             DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
 553                 }
 554                 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 555         } else {
 556                 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
 557         }
 558 
 559         if (version < SPA_VERSION_RECVD_PROPS) {
 560                 if (source & ZPROP_SRC_NONE)
 561                         source = ZPROP_SRC_NONE;
 562                 else if (source & ZPROP_SRC_RECEIVED)
 563                         source = ZPROP_SRC_LOCAL;
 564         }
 565 
 566         inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);


 623                 err = zap_remove(mos, zapobj, inheritstr, tx);
 624                 ASSERT(err == 0 || err == ENOENT);
 625                 /* FALLTHRU */
 626         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 627                 /*
 628                  * remove propname$recvd
 629                  */
 630                 err = zap_remove(mos, zapobj, recvdstr, tx);
 631                 ASSERT(err == 0 || err == ENOENT);
 632                 break;
 633         default:
 634                 cmn_err(CE_PANIC, "unexpected property source: %d", source);
 635         }
 636 
 637         strfree(inheritstr);
 638         strfree(recvdstr);
 639 
 640         if (isint) {
 641                 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
 642 
 643                 if (ds->ds_is_snapshot) {
 644                         dsl_prop_cb_record_t *cbr;
 645                         /*
 646                          * It's a snapshot; nothing can inherit this
 647                          * property, so just look for callbacks on this
 648                          * ds here.
 649                          */
 650                         mutex_enter(&ds->ds_dir->dd_lock);
 651                         for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
 652                             cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
 653                                 if (cbr->cbr_ds == ds &&
 654                                     strcmp(cbr->cbr_propname, propname) == 0)
 655                                         cbr->cbr_func(cbr->cbr_arg, intval);
 656                         }
 657                         mutex_exit(&ds->ds_dir->dd_lock);
 658                 } else {
 659                         dsl_prop_changed_notify(ds->ds_dir->dd_pool,
 660                             ds->ds_dir->dd_object, propname, intval, TRUE);
 661                 }
 662 
 663                 (void) snprintf(valbuf, sizeof (valbuf),


 741         if (err != 0)
 742                 return (err);
 743 
 744         version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 745         while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
 746                 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
 747                         dsl_dataset_rele(ds, FTAG);
 748                         return (SET_ERROR(ENAMETOOLONG));
 749                 }
 750                 if (nvpair_type(elem) == DATA_TYPE_STRING) {
 751                         char *valstr = fnvpair_value_string(elem);
 752                         if (strlen(valstr) >= (version <
 753                             SPA_VERSION_STMF_PROP ?
 754                             ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
 755                                 dsl_dataset_rele(ds, FTAG);
 756                                 return (E2BIG);
 757                         }
 758                 }
 759         }
 760 
 761         if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
 762                 dsl_dataset_rele(ds, FTAG);
 763                 return (SET_ERROR(ENOTSUP));
 764         }
 765         dsl_dataset_rele(ds, FTAG);
 766         return (0);
 767 }
 768 
 769 void
 770 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
 771     nvlist_t *props, dmu_tx_t *tx)
 772 {
 773         nvpair_t *elem = NULL;
 774 
 775         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 776                 nvpair_t *pair = elem;
 777 
 778                 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
 779                         /*
 780                          * dsl_prop_get_all_impl() returns properties in this
 781                          * format.


 964         if (err == ENOENT)
 965                 err = 0;
 966         return (err);
 967 }
 968 
 969 /*
 970  * Iterate over all properties for this dataset and return them in an nvlist.
 971  */
 972 static int
 973 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
 974     dsl_prop_getflags_t flags)
 975 {
 976         dsl_dir_t *dd = ds->ds_dir;
 977         dsl_pool_t *dp = dd->dd_pool;
 978         objset_t *mos = dp->dp_meta_objset;
 979         int err = 0;
 980         char setpoint[MAXNAMELEN];
 981 
 982         VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 983 
 984         if (ds->ds_is_snapshot)
 985                 flags |= DSL_PROP_GET_SNAPSHOT;
 986 
 987         ASSERT(dsl_pool_config_held(dp));
 988 
 989         if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
 990                 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
 991                 dsl_dataset_name(ds, setpoint);
 992                 err = dsl_prop_get_all_impl(mos,
 993                     dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
 994                 if (err)
 995                         goto out;
 996         }
 997 
 998         for (; dd != NULL; dd = dd->dd_parent) {
 999                 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1000                         if (flags & (DSL_PROP_GET_LOCAL |
1001                             DSL_PROP_GET_RECEIVED))
1002                                 break;
1003                         flags |= DSL_PROP_GET_INHERITING;
1004                 }