+static void osd_recordsize_changed_cb(void *arg, uint64_t newval)
+{
+ struct osd_device *osd = arg;
+
+ LASSERT(newval <= osd_spa_maxblocksize(dmu_objset_spa(osd->od_os)));
+ LASSERT(newval >= SPA_MINBLOCKSIZE);
+ LASSERT(ISP2(newval));
+
+ osd->od_max_blksz = newval;
+}
+
+/*
+ * This function unregisters all registered callbacks. It's harmless to
+ * unregister callbacks that were never registered so it is used to safely
+ * unwind a partially completed call to osd_objset_register_callbacks().
+ */
+static void osd_objset_unregister_callbacks(struct osd_device *o)
+{
+ struct dsl_dataset *ds = dmu_objset_ds(o->od_os);
+
+ (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR),
+ osd_xattr_changed_cb, o);
+ (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
+ osd_recordsize_changed_cb, o);
+
+ if (o->arc_prune_cb != NULL) {
+ arc_remove_prune_callback(o->arc_prune_cb);
+ o->arc_prune_cb = NULL;
+ }
+}
+
+/*
+ * Register the required callbacks to be notified when zfs properties
+ * are modified using the 'zfs(8)' command line utility.
+ */
+static int osd_objset_register_callbacks(struct osd_device *o)
+{
+ struct dsl_dataset *ds = dmu_objset_ds(o->od_os);
+ dsl_pool_t *dp = dmu_objset_pool(o->od_os);
+ int rc;
+
+ LASSERT(ds);
+ LASSERT(dp);
+
+ dsl_pool_config_enter(dp, FTAG);
+ rc = -dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_XATTR),
+ osd_xattr_changed_cb, o);
+ if (rc)
+ GOTO(err, rc);
+
+ rc = -dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
+ osd_recordsize_changed_cb, o);
+ if (rc)
+ GOTO(err, rc);
+
+ o->arc_prune_cb = arc_add_prune_callback(arc_prune_func, o);
+err:
+ dsl_pool_config_exit(dp, FTAG);
+ if (rc)
+ osd_objset_unregister_callbacks(o);
+
+ RETURN(rc);
+}
+