Print this page
4171 clean up spa_feature_*() interfaces
4172 implement extensible_dataset feature for use by other zpool features
Reviewed by: Max Grossman <max.grossman@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/zfeature.c
          +++ new/usr/src/uts/common/fs/zfs/zfeature.c
↓ open down ↓ 153 lines elided ↑ open up ↑
 154  154   * does not exist yet, the bptree object is created as part of the dataset
 155  155   * destroy and async_destroy's reference count is incremented to indicate it
 156  156   * has made an on-disk format change. Later, after the destroyed dataset's
 157  157   * blocks have all been asynchronously freed there is no longer any use for the
 158  158   * bptree object, so it is destroyed and async_destroy's reference count is
 159  159   * decremented back to 0 to indicate that it has undone its on-disk format
 160  160   * changes.
 161  161   */
 162  162  
 163  163  typedef enum {
 164      -        FEATURE_ACTION_ENABLE,
 165  164          FEATURE_ACTION_INCR,
 166  165          FEATURE_ACTION_DECR,
 167  166  } feature_action_t;
 168  167  
 169  168  /*
 170      - * Checks that the features active in the specified object are supported by
      169 + * Checks that the active features in the pool are supported by
 171  170   * this software.  Adds each unsupported feature (name -> description) to
 172  171   * the supplied nvlist.
 173  172   */
 174  173  boolean_t
 175      -feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
      174 +spa_features_check(spa_t *spa, boolean_t for_write,
 176  175      nvlist_t *unsup_feat, nvlist_t *enabled_feat)
 177  176  {
      177 +        objset_t *os = spa->spa_meta_objset;
 178  178          boolean_t supported;
 179  179          zap_cursor_t zc;
 180  180          zap_attribute_t za;
      181 +        uint64_t obj = for_write ?
      182 +            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
 181  183  
 182  184          supported = B_TRUE;
 183  185          for (zap_cursor_init(&zc, os, obj);
 184  186              zap_cursor_retrieve(&zc, &za) == 0;
 185  187              zap_cursor_advance(&zc)) {
 186  188                  ASSERT(za.za_integer_length == sizeof (uint64_t) &&
 187  189                      za.za_num_integers == 1);
 188  190  
 189  191                  if (NULL != enabled_feat) {
 190  192                          fnvlist_add_uint64(enabled_feat, za.za_name,
↓ open down ↓ 1 lines elided ↑ open up ↑
 192  194                  }
 193  195  
 194  196                  if (za.za_first_integer != 0 &&
 195  197                      !zfeature_is_supported(za.za_name)) {
 196  198                          supported = B_FALSE;
 197  199  
 198  200                          if (NULL != unsup_feat) {
 199  201                                  char *desc = "";
 200  202                                  char buf[MAXPATHLEN];
 201  203  
 202      -                                if (zap_lookup(os, desc_obj, za.za_name,
 203      -                                    1, sizeof (buf), buf) == 0)
      204 +                                if (zap_lookup(os, spa->spa_feat_desc_obj,
      205 +                                    za.za_name, 1, sizeof (buf), buf) == 0)
 204  206                                          desc = buf;
 205  207  
 206  208                                  VERIFY(nvlist_add_string(unsup_feat, za.za_name,
 207  209                                      desc) == 0);
 208  210                          }
 209  211                  }
 210  212          }
 211  213          zap_cursor_fini(&zc);
 212  214  
 213  215          return (supported);
 214  216  }
 215  217  
 216      -static int
 217      -feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
 218      -    zfeature_info_t *feature, uint64_t *res)
      218 +/*
      219 + * Note: well-designed features will not need to use this; they should
      220 + * use spa_feature_is_enabled() and spa_feature_is_active() instead.
      221 + * However, this is non-static for zdb and zhack.
      222 + */
      223 +int
      224 +feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)
 219  225  {
 220  226          int err;
 221  227          uint64_t refcount;
 222      -        uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;
      228 +        uint64_t zapobj = feature->fi_can_readonly ?
      229 +            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
 223  230  
 224  231          /*
 225  232           * If the pool is currently being created, the feature objects may not
 226  233           * have been allocated yet.  Act as though all features are disabled.
 227  234           */
 228  235          if (zapobj == 0)
 229  236                  return (SET_ERROR(ENOTSUP));
 230  237  
 231      -        err = zap_lookup(os, zapobj, feature->fi_guid, sizeof (uint64_t), 1,
 232      -            &refcount);
      238 +        err = zap_lookup(spa->spa_meta_objset, zapobj,
      239 +            feature->fi_guid, sizeof (uint64_t), 1, &refcount);
 233  240          if (err != 0) {
 234  241                  if (err == ENOENT)
 235  242                          return (SET_ERROR(ENOTSUP));
 236  243                  else
 237  244                          return (err);
 238  245          }
 239  246          *res = refcount;
 240  247          return (0);
 241  248  }
 242  249  
 243      -static int
 244      -feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj,
 245      -    uint64_t desc_obj, zfeature_info_t *feature, feature_action_t action,
      250 +/*
      251 + * This function is non-static for zhack; it should otherwise not be used
      252 + * outside this file.
      253 + */
      254 +void
      255 +feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
 246  256      dmu_tx_t *tx)
 247  257  {
 248      -        int error;
 249      -        uint64_t refcount;
 250      -        uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;
      258 +        uint64_t zapobj = feature->fi_can_readonly ?
      259 +            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
 251  260  
      261 +        VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid,
      262 +            sizeof (uint64_t), 1, &refcount, tx));
      263 +
      264 +        if (refcount == 0)
      265 +                spa_deactivate_mos_feature(spa, feature->fi_guid);
      266 +        else if (feature->fi_mos)
      267 +                spa_activate_mos_feature(spa, feature->fi_guid);
      268 +}
      269 +
      270 +/*
      271 + * This function is non-static for zhack; it should otherwise not be used
      272 + * outside this file.
      273 + */
      274 +void
      275 +feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
      276 +{
      277 +        uint64_t zapobj = feature->fi_can_readonly ?
      278 +            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
      279 +
 252  280          ASSERT(0 != zapobj);
 253  281          ASSERT(zfeature_is_valid_guid(feature->fi_guid));
      282 +        ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
 254  283  
 255      -        error = zap_lookup(os, zapobj, feature->fi_guid,
 256      -            sizeof (uint64_t), 1, &refcount);
 257      -
 258  284          /*
 259      -         * If we can't ascertain the status of the specified feature, an I/O
 260      -         * error occurred.
      285 +         * If the feature is already enabled, ignore the request.
 261  286           */
 262      -        if (error != 0 && error != ENOENT)
 263      -                return (error);
      287 +        if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
      288 +                return;
 264  289  
      290 +        for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++)
      291 +                spa_feature_enable(spa, feature->fi_depends[i], tx);
      292 +
      293 +        VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj,
      294 +            feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
      295 +            feature->fi_desc, tx));
      296 +        feature_sync(spa, feature, 0, tx);
      297 +}
      298 +
      299 +static void
      300 +feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
      301 +    dmu_tx_t *tx)
      302 +{
      303 +        uint64_t refcount;
      304 +        zfeature_info_t *feature = &spa_feature_table[fid];
      305 +        uint64_t zapobj = feature->fi_can_readonly ?
      306 +            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
      307 +
      308 +        ASSERT3U(fid, <, SPA_FEATURES);
      309 +        ASSERT(0 != zapobj);
      310 +        ASSERT(zfeature_is_valid_guid(feature->fi_guid));
      311 +
      312 +        ASSERT(dmu_tx_is_syncing(tx));
      313 +        ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
      314 +
      315 +        VERIFY0(zap_lookup(spa->spa_meta_objset, zapobj, feature->fi_guid,
      316 +            sizeof (uint64_t), 1, &refcount));
      317 +
 265  318          switch (action) {
 266      -        case FEATURE_ACTION_ENABLE:
 267      -                /*
 268      -                 * If the feature is already enabled, ignore the request.
 269      -                 */
 270      -                if (error == 0)
 271      -                        return (0);
 272      -                refcount = 0;
 273      -                break;
 274  319          case FEATURE_ACTION_INCR:
 275      -                if (error == ENOENT)
 276      -                        return (SET_ERROR(ENOTSUP));
 277      -                if (refcount == UINT64_MAX)
 278      -                        return (SET_ERROR(EOVERFLOW));
      320 +                VERIFY3U(refcount, !=, UINT64_MAX);
 279  321                  refcount++;
 280  322                  break;
 281  323          case FEATURE_ACTION_DECR:
 282      -                if (error == ENOENT)
 283      -                        return (SET_ERROR(ENOTSUP));
 284      -                if (refcount == 0)
 285      -                        return (SET_ERROR(EOVERFLOW));
      324 +                VERIFY3U(refcount, !=, 0);
 286  325                  refcount--;
 287  326                  break;
 288  327          default:
 289  328                  ASSERT(0);
 290  329                  break;
 291  330          }
 292  331  
 293      -        if (action == FEATURE_ACTION_ENABLE) {
 294      -                int i;
 295      -
 296      -                for (i = 0; feature->fi_depends[i] != NULL; i++) {
 297      -                        zfeature_info_t *dep = feature->fi_depends[i];
 298      -
 299      -                        error = feature_do_action(os, read_obj, write_obj,
 300      -                            desc_obj, dep, FEATURE_ACTION_ENABLE, tx);
 301      -                        if (error != 0)
 302      -                                return (error);
 303      -                }
 304      -        }
 305      -
 306      -        error = zap_update(os, zapobj, feature->fi_guid,
 307      -            sizeof (uint64_t), 1, &refcount, tx);
 308      -        if (error != 0)
 309      -                return (error);
 310      -
 311      -        if (action == FEATURE_ACTION_ENABLE) {
 312      -                error = zap_update(os, desc_obj,
 313      -                    feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
 314      -                    feature->fi_desc, tx);
 315      -                if (error != 0)
 316      -                        return (error);
 317      -        }
 318      -
 319      -        if (action == FEATURE_ACTION_INCR && refcount == 1 && feature->fi_mos) {
 320      -                spa_activate_mos_feature(dmu_objset_spa(os), feature->fi_guid);
 321      -        }
 322      -
 323      -        if (action == FEATURE_ACTION_DECR && refcount == 0) {
 324      -                spa_deactivate_mos_feature(dmu_objset_spa(os),
 325      -                    feature->fi_guid);
 326      -        }
 327      -
 328      -        return (0);
      332 +        feature_sync(spa, feature, refcount, tx);
 329  333  }
 330  334  
 331  335  void
 332  336  spa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx)
 333  337  {
 334  338          /*
 335  339           * We create feature flags ZAP objects in two instances: during pool
 336  340           * creation and during pool upgrade.
 337  341           */
 338  342          ASSERT(dsl_pool_sync_context(spa_get_dsl(spa)) || (!spa->spa_sync_on &&
↓ open down ↓ 7 lines elided ↑ open up ↑
 346  350              DMU_POOL_FEATURES_FOR_WRITE, tx);
 347  351          spa->spa_feat_desc_obj = zap_create_link(spa->spa_meta_objset,
 348  352              DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
 349  353              DMU_POOL_FEATURE_DESCRIPTIONS, tx);
 350  354  }
 351  355  
 352  356  /*
 353  357   * Enable any required dependencies, then enable the requested feature.
 354  358   */
 355  359  void
 356      -spa_feature_enable(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
      360 +spa_feature_enable(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
 357  361  {
 358  362          ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
 359      -        VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
 360      -            spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
 361      -            spa->spa_feat_desc_obj, feature, FEATURE_ACTION_ENABLE, tx));
      363 +        ASSERT3U(fid, <, SPA_FEATURES);
      364 +        feature_enable_sync(spa, &spa_feature_table[fid], tx);
 362  365  }
 363  366  
 364  367  void
 365      -spa_feature_incr(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
      368 +spa_feature_incr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
 366  369  {
 367      -        ASSERT(dmu_tx_is_syncing(tx));
 368      -        ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
 369      -        VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
 370      -            spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
 371      -            spa->spa_feat_desc_obj, feature, FEATURE_ACTION_INCR, tx));
      370 +        feature_do_action(spa, fid, FEATURE_ACTION_INCR, tx);
 372  371  }
 373  372  
 374  373  void
 375      -spa_feature_decr(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
      374 +spa_feature_decr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
 376  375  {
 377      -        ASSERT(dmu_tx_is_syncing(tx));
 378      -        ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
 379      -        VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
 380      -            spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
 381      -            spa->spa_feat_desc_obj, feature, FEATURE_ACTION_DECR, tx));
      376 +        feature_do_action(spa, fid, FEATURE_ACTION_DECR, tx);
 382  377  }
 383  378  
 384      -/*
 385      - * This interface is for debugging only. Normal consumers should use
 386      - * spa_feature_is_enabled/spa_feature_is_active.
 387      - */
 388      -int
 389      -spa_feature_get_refcount(spa_t *spa, zfeature_info_t *feature)
 390      -{
 391      -        int err;
 392      -        uint64_t refcount;
 393      -
 394      -        if (spa_version(spa) < SPA_VERSION_FEATURES)
 395      -                return (B_FALSE);
 396      -
 397      -        err = feature_get_refcount(spa->spa_meta_objset,
 398      -            spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
 399      -            feature, &refcount);
 400      -        ASSERT(err == 0 || err == ENOTSUP);
 401      -        return (err == 0 ? refcount : 0);
 402      -}
 403      -
 404  379  boolean_t
 405      -spa_feature_is_enabled(spa_t *spa, zfeature_info_t *feature)
      380 +spa_feature_is_enabled(spa_t *spa, spa_feature_t fid)
 406  381  {
 407  382          int err;
 408  383          uint64_t refcount;
 409  384  
      385 +        ASSERT3U(fid, <, SPA_FEATURES);
 410  386          if (spa_version(spa) < SPA_VERSION_FEATURES)
 411  387                  return (B_FALSE);
 412  388  
 413      -        err = feature_get_refcount(spa->spa_meta_objset,
 414      -            spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
 415      -            feature, &refcount);
      389 +        err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
 416  390          ASSERT(err == 0 || err == ENOTSUP);
 417  391          return (err == 0);
 418  392  }
 419  393  
 420  394  boolean_t
 421      -spa_feature_is_active(spa_t *spa, zfeature_info_t *feature)
      395 +spa_feature_is_active(spa_t *spa, spa_feature_t fid)
 422  396  {
 423  397          int err;
 424  398          uint64_t refcount;
 425  399  
      400 +        ASSERT3U(fid, <, SPA_FEATURES);
 426  401          if (spa_version(spa) < SPA_VERSION_FEATURES)
 427  402                  return (B_FALSE);
 428  403  
 429      -        err = feature_get_refcount(spa->spa_meta_objset,
 430      -            spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
 431      -            feature, &refcount);
      404 +        err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
 432  405          ASSERT(err == 0 || err == ENOTSUP);
 433  406          return (err == 0 && refcount > 0);
 434  407  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX