1 /*
   2  * CDDL HEADER START
   3  *
   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  24  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  25  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  26  * Copyright (c) 2014 Integros [integros.com]
  27  * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
  28  */
  29 
  30 #ifdef _KERNEL
  31 #include <sys/systm.h>
  32 #else
  33 #include <errno.h>
  34 #include <string.h>
  35 #endif
  36 #include <sys/debug.h>
  37 #include <sys/fs/zfs.h>
  38 #include <sys/inttypes.h>
  39 #include <sys/types.h>
  40 #include "zfeature_common.h"
  41 
  42 /*
  43  * Set to disable all feature checks while opening pools, allowing pools with
  44  * unsupported features to be opened. Set for testing only.
  45  */
  46 boolean_t zfeature_checks_disable = B_FALSE;
  47 
  48 zfeature_info_t spa_feature_table[SPA_FEATURES];
  49 
  50 /*
  51  * Valid characters for feature guids. This list is mainly for aesthetic
  52  * purposes and could be expanded in the future. There are different allowed
  53  * characters in the guids reverse dns portion (before the colon) and its
  54  * short name (after the colon).
  55  */
  56 static int
  57 valid_char(char c, boolean_t after_colon)
  58 {
  59         return ((c >= 'a' && c <= 'z') ||
  60             (c >= '0' && c <= '9') ||
  61             (after_colon && c == '_') ||
  62             (!after_colon && (c == '.' || c == '-')));
  63 }
  64 
  65 /*
  66  * Every feature guid must contain exactly one colon which separates a reverse
  67  * dns organization name from the feature's "short" name (e.g.
  68  * "com.company:feature_name").
  69  */
  70 boolean_t
  71 zfeature_is_valid_guid(const char *name)
  72 {
  73         int i;
  74         boolean_t has_colon = B_FALSE;
  75 
  76         i = 0;
  77         while (name[i] != '\0') {
  78                 char c = name[i++];
  79                 if (c == ':') {
  80                         if (has_colon)
  81                                 return (B_FALSE);
  82                         has_colon = B_TRUE;
  83                         continue;
  84                 }
  85                 if (!valid_char(c, has_colon))
  86                         return (B_FALSE);
  87         }
  88 
  89         return (has_colon);
  90 }
  91 
  92 boolean_t
  93 zfeature_is_supported(const char *guid)
  94 {
  95         if (zfeature_checks_disable)
  96                 return (B_TRUE);
  97 
  98         for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
  99                 zfeature_info_t *feature = &spa_feature_table[i];
 100                 if (strcmp(guid, feature->fi_guid) == 0)
 101                         return (B_TRUE);
 102         }
 103         return (B_FALSE);
 104 }
 105 
 106 int
 107 zfeature_lookup_name(const char *name, spa_feature_t *res)
 108 {
 109         for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
 110                 zfeature_info_t *feature = &spa_feature_table[i];
 111                 if (strcmp(name, feature->fi_uname) == 0) {
 112                         if (res != NULL)
 113                                 *res = i;
 114                         return (0);
 115                 }
 116         }
 117 
 118         return (ENOENT);
 119 }
 120 
 121 boolean_t
 122 zfeature_depends_on(spa_feature_t fid, spa_feature_t check)
 123 {
 124         zfeature_info_t *feature = &spa_feature_table[fid];
 125 
 126         for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
 127                 if (feature->fi_depends[i] == check)
 128                         return (B_TRUE);
 129         }
 130         return (B_FALSE);
 131 }
 132 
 133 static boolean_t
 134 deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
 135 {
 136         for (int i = 0; deps[i] != SPA_FEATURE_NONE; i++)
 137                 if (deps[i] == feature)
 138                         return (B_TRUE);
 139 
 140         return (B_FALSE);
 141 }
 142 
 143 static void
 144 zfeature_register(spa_feature_t fid, const char *guid, const char *name,
 145     const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
 146 {
 147         zfeature_info_t *feature = &spa_feature_table[fid];
 148         static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
 149 
 150         ASSERT(name != NULL);
 151         ASSERT(desc != NULL);
 152         ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
 153             (flags & ZFEATURE_FLAG_MOS) == 0);
 154         ASSERT3U(fid, <, SPA_FEATURES);
 155         ASSERT(zfeature_is_valid_guid(guid));
 156 
 157         if (deps == NULL)
 158                 deps = nodeps;
 159 
 160         VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) ||
 161             (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET)));
 162 
 163         feature->fi_feature = fid;
 164         feature->fi_guid = guid;
 165         feature->fi_uname = name;
 166         feature->fi_desc = desc;
 167         feature->fi_flags = flags;
 168         feature->fi_depends = deps;
 169 }
 170 
 171 spa_feature_t cos_deps[] = { SPA_FEATURE_VDEV_PROPS, SPA_FEATURE_NONE };
 172 
 173 void
 174 zpool_feature_init(void)
 175 {
 176 
 177         /*
 178          * NOTE: When either adding or changing a feature make sure
 179          * to update the zfs-tests zpool_get configuration file
 180          * at usr/src/test/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
 181          */
 182         zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
 183             "com.delphix:async_destroy", "async_destroy",
 184             "Destroy filesystems asynchronously.",
 185             ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 186 
 187         zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
 188             "com.delphix:empty_bpobj", "empty_bpobj",
 189             "Snapshots use less space.",
 190             ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 191 
 192         zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
 193             "org.illumos:lz4_compress", "lz4_compress",
 194             "LZ4 compression algorithm support.",
 195             ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
 196 
 197         zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
 198             "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
 199             "Crash dumps to multiple vdev pools.",
 200             0, NULL);
 201 
 202         zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
 203             "com.delphix:spacemap_histogram", "spacemap_histogram",
 204             "Spacemaps maintain space histograms.",
 205             ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 206 
 207         zfeature_register(SPA_FEATURE_ENABLED_TXG,
 208             "com.delphix:enabled_txg", "enabled_txg",
 209             "Record txg at which a feature is enabled",
 210             ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 211 
 212         static spa_feature_t hole_birth_deps[] = {
 213                 SPA_FEATURE_ENABLED_TXG,
 214                 SPA_FEATURE_NONE
 215         };
 216         zfeature_register(SPA_FEATURE_HOLE_BIRTH,
 217             "com.delphix:hole_birth", "hole_birth",
 218             "Retain hole birth txg for more precise zfs send",
 219             ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
 220             hole_birth_deps);
 221 
 222         zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
 223             "com.delphix:extensible_dataset", "extensible_dataset",
 224             "Enhanced dataset functionality, used by other features.",
 225             0, NULL);
 226 
 227         static const spa_feature_t bookmarks_deps[] = {
 228                 SPA_FEATURE_EXTENSIBLE_DATASET,
 229                 SPA_FEATURE_NONE
 230         };
 231         zfeature_register(SPA_FEATURE_BOOKMARKS,
 232             "com.delphix:bookmarks", "bookmarks",
 233             "\"zfs bookmark\" command",
 234             ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
 235 
 236         static const spa_feature_t filesystem_limits_deps[] = {
 237                 SPA_FEATURE_EXTENSIBLE_DATASET,
 238                 SPA_FEATURE_NONE
 239         };
 240         zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
 241             "com.joyent:filesystem_limits", "filesystem_limits",
 242             "Filesystem and snapshot limits.",
 243             ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
 244 
 245         zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
 246             "com.delphix:embedded_data", "embedded_data",
 247             "Blocks which compress very well use even less space.",
 248             ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
 249             NULL);
 250 
 251         static const spa_feature_t large_blocks_deps[] = {
 252                 SPA_FEATURE_EXTENSIBLE_DATASET,
 253                 SPA_FEATURE_NONE
 254         };
 255         zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
 256             "org.open-zfs:large_blocks", "large_blocks",
 257             "Support for blocks larger than 128KB.",
 258             ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
 259 
 260         static const spa_feature_t sha512_deps[] = {
 261                 SPA_FEATURE_EXTENSIBLE_DATASET,
 262                 SPA_FEATURE_NONE
 263         };
 264         zfeature_register(SPA_FEATURE_SHA512,
 265             "org.illumos:sha512", "sha512",
 266             "SHA-512/256 hash algorithm.",
 267             ZFEATURE_FLAG_PER_DATASET, sha512_deps);
 268 
 269         static const spa_feature_t skein_deps[] = {
 270                 SPA_FEATURE_EXTENSIBLE_DATASET,
 271                 SPA_FEATURE_NONE
 272         };
 273         zfeature_register(SPA_FEATURE_SKEIN,
 274             "org.illumos:skein", "skein",
 275             "Skein hash algorithm.",
 276             ZFEATURE_FLAG_PER_DATASET, skein_deps);
 277 
 278         static const spa_feature_t edonr_deps[] = {
 279                 SPA_FEATURE_EXTENSIBLE_DATASET,
 280                 SPA_FEATURE_NONE
 281         };
 282         zfeature_register(SPA_FEATURE_EDONR,
 283             "org.illumos:edonr", "edonr",
 284             "Edon-R hash algorithm.",
 285             ZFEATURE_FLAG_PER_DATASET, edonr_deps);
 286 
 287         zfeature_register(SPA_FEATURE_META_DEVICES,
 288             "com.nexenta:meta_devices", "meta_devices",
 289             "Dedicated devices for metadata.", ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 290         zfeature_register(SPA_FEATURE_VDEV_PROPS,
 291             "com.nexenta:vdev_properties", "vdev_properties",
 292             "Vdev-specific properties.", ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 293         zfeature_register(SPA_FEATURE_COS_PROPS,
 294             "com.nexenta:class_of_storage", "class_of_storage",
 295             "Properties for groups of vdevs.", ZFEATURE_FLAG_READONLY_COMPAT,
 296             cos_deps);
 297         zfeature_register(SPA_FEATURE_WBC,
 298             "com.nexenta:wbc", "wbc",
 299             "Write back cache support", 0, NULL);
 300 }