Print this page
%B

@@ -23,10 +23,11 @@
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Portions Copyright 2011 Martin Matuska
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
 /*
  * ZFS ioctls.
  *

@@ -170,10 +171,11 @@
 #include <sys/zfs_onexit.h>
 #include <sys/zvol.h>
 #include <sys/dsl_scan.h>
 #include <sharefs/share.h>
 #include <sys/dmu_objset.h>
+#include <sys/zfeature.h>
 
 #include "zfs_namecheck.h"
 #include "zfs_prop.h"
 #include "zfs_deleg.h"
 #include "zfs_comutil.h"

@@ -233,10 +235,16 @@
 static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *,
     boolean_t *);
 int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *);
 static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp);
 
+static int zfs_prop_activate_feature(dsl_pool_t *dp, zfeature_info_t *feature);
+static int zfs_prop_activate_feature_check(void *arg1, void *arg2,
+    dmu_tx_t *tx);
+static void zfs_prop_activate_feature_sync(void *arg1, void *arg2,
+    dmu_tx_t *tx);
+
 /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
 void
 __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
 {
         const char *newfile;

@@ -2381,11 +2389,46 @@
                         (void) zfs_ioc_userspace_upgrade(zc);
                         kmem_free(zc, sizeof (zfs_cmd_t));
                 }
                 break;
         }
+        case ZFS_PROP_COMPRESSION:
+        {
+                if (intval == ZIO_COMPRESS_LZ4 ||
+                    intval == ZIO_COMPRESS_LZ4HC) {
+                        zfeature_info_t *feature =
+                            &spa_feature_table[SPA_FEATURE_LZ4_COMPRESS];
+                        spa_t *spa;
+                        dsl_pool_t *dp;
 
+                        if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                                return (err);
+
+                        dp = spa->spa_dsl_pool;
+
+                        /*
+                         * Setting the LZ4 compression algorithm activates
+                         * the feature.
+                         */
+                        if (!spa_feature_is_active(spa, feature)) {
+                                if ((err = zfs_prop_activate_feature(dp,
+                                    feature)) != 0) {
+                                        spa_close(spa, FTAG);
+                                        return (err);
+                                }
+                        }
+
+                        spa_close(spa, FTAG);
+                }
+                /*
+                 * We still want the default set action to be performed in the
+                 * caller, we only performed zfeature settings here.
+                 */
+                err = -1;
+                break;
+        }
+
         default:
                 err = -1;
         }
 
         return (err);

@@ -3625,10 +3668,27 @@
                         if (intval == ZIO_COMPRESS_ZLE &&
                             zfs_earlier_version(dsname,
                             SPA_VERSION_ZLE_COMPRESSION))
                                 return (ENOTSUP);
 
+                        if (intval == ZIO_COMPRESS_LZ4 ||
+                            intval == ZIO_COMPRESS_LZ4HC) {
+                                zfeature_info_t *feature =
+                                    &spa_feature_table[
+                                    SPA_FEATURE_LZ4_COMPRESS];
+                                spa_t *spa;
+
+                                if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                                        return (err);
+
+                                if (!spa_feature_is_enabled(spa, feature)) {
+                                        spa_close(spa, FTAG);
+                                        return (ENOTSUP);
+                                }
+                                spa_close(spa, FTAG);
+                        }
+
                         /*
                          * If this is a bootable dataset then
                          * verify that the compression algorithm
                          * is supported for booting. We must return
                          * something other than ENOTSUP since it

@@ -3668,10 +3728,60 @@
         }
 
         return (zfs_secpolicy_setprop(dsname, prop, pair, CRED()));
 }
 
+/*
+ * Activates a feature on a pool in response to a property setting. This
+ * creates a new sync task which modifies the pool to reflect the feature
+ * as being active.
+ */
+static int
+zfs_prop_activate_feature(dsl_pool_t *dp, zfeature_info_t *feature)
+{
+        int err;
+
+        /* EBUSY here indicates that the feature is already active */
+        err = dsl_sync_task_do(dp, zfs_prop_activate_feature_check,
+            zfs_prop_activate_feature_sync, dp->dp_spa, feature, 2);
+
+        if (err != 0 && err != EBUSY)
+                return (err);
+        else
+                return (0);
+}
+
+/*
+ * Checks for a race condition to make sure we don't increment a feature flag
+ * multiple times.
+ */
+/*ARGSUSED*/
+static int
+zfs_prop_activate_feature_check(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+        spa_t *spa = arg1;
+        zfeature_info_t *feature = arg2;
+
+        if (!spa_feature_is_active(spa, feature))
+                return (0);
+        else
+                return (EBUSY);
+}
+
+/*
+ * The callback invoked on feature activation in the sync task caused by
+ * zfs_prop_activate_feature.
+ */
+static void
+zfs_prop_activate_feature_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+        spa_t *spa = arg1;
+        zfeature_info_t *feature = arg2;
+
+        spa_feature_incr(spa, feature, tx);
+}
+
 /*
  * Removes properties from the given props list that fail permission checks
  * needed to clear them and to restore them in case of a receive error. For each
  * property, make sure we have both set and inherit permissions.
  *