Print this page
    
3006 VERIFY[S,U,P] and ASSERT[S,U,P] frequently check if first argument is zero
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/zhack/zhack.c
          +++ new/usr/src/cmd/zhack/zhack.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2012 by Delphix. All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * zhack is a debugging tool that can write changes to ZFS pool using libzpool
  28   28   * for testing purposes. Altering pools with zhack is unsupported and may
  29   29   * result in corrupted pools.
  30   30   */
  31   31  
  32   32  #include <stdio.h>
  33   33  #include <stdlib.h>
  34   34  #include <ctype.h>
  35   35  #include <sys/zfs_context.h>
  36   36  #include <sys/spa.h>
  37   37  #include <sys/spa_impl.h>
  38   38  #include <sys/dmu.h>
  39   39  #include <sys/zap.h>
  40   40  #include <sys/zfs_znode.h>
  41   41  #include <sys/dsl_synctask.h>
  42   42  #include <sys/vdev.h>
  43   43  #include <sys/fs/zfs.h>
  44   44  #include <sys/dmu_objset.h>
  45   45  #include <sys/dsl_pool.h>
  46   46  #include <sys/zio_checksum.h>
  47   47  #include <sys/zio_compress.h>
  48   48  #include <sys/zfeature.h>
  49   49  #undef ZFS_MAXNAMELEN
  50   50  #undef verify
  51   51  #include <libzfs.h>
  52   52  
  53   53  extern boolean_t zfeature_checks_disable;
  54   54  
  55   55  const char cmdname[] = "zhack";
  56   56  libzfs_handle_t *g_zfs;
  57   57  static importargs_t g_importargs;
  58   58  static char *g_pool;
  59   59  static boolean_t g_readonly;
  60   60  
  61   61  static void
  62   62  usage(void)
  63   63  {
  64   64          (void) fprintf(stderr,
  65   65              "Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
  66   66              "where <subcommand> <args> is one of the following:\n"
  67   67              "\n", cmdname);
  68   68  
  69   69          (void) fprintf(stderr,
  70   70              "    feature stat <pool>\n"
  71   71              "        print information about enabled features\n"
  72   72              "    feature enable [-d desc] <pool> <feature>\n"
  73   73              "        add a new enabled feature to the pool\n"
  74   74              "        -d <desc> sets the feature's description\n"
  75   75              "    feature ref [-md] <pool> <feature>\n"
  76   76              "        change the refcount on the given feature\n"
  77   77              "        -d decrease instead of increase the refcount\n"
  78   78              "        -m add the feature to the label if increasing refcount\n"
  79   79              "\n"
  80   80              "    <feature> : should be a feature guid\n");
  81   81          exit(1);
  82   82  }
  83   83  
  84   84  
  85   85  static void
  86   86  fatal(const char *fmt, ...)
  87   87  {
  88   88          va_list ap;
  89   89  
  90   90          va_start(ap, fmt);
  91   91          (void) fprintf(stderr, "%s: ", cmdname);
  92   92          (void) vfprintf(stderr, fmt, ap);
  93   93          va_end(ap);
  94   94          (void) fprintf(stderr, "\n");
  95   95  
  96   96          exit(1);
  97   97  }
  98   98  
  99   99  /* ARGSUSED */
 100  100  static int
 101  101  space_delta_cb(dmu_object_type_t bonustype, void *data,
 102  102      uint64_t *userp, uint64_t *groupp)
 103  103  {
 104  104          /*
 105  105           * Is it a valid type of object to track?
 106  106           */
 107  107          if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
 108  108                  return (ENOENT);
 109  109          (void) fprintf(stderr, "modifying object that needs user accounting");
 110  110          abort();
 111  111          /* NOTREACHED */
 112  112  }
 113  113  
 114  114  /*
 115  115   * Target is the dataset whose pool we want to open.
 116  116   */
 117  117  static void
 118  118  import_pool(const char *target, boolean_t readonly)
 119  119  {
 120  120          nvlist_t *config;
 121  121          nvlist_t *pools;
 122  122          int error;
 123  123          char *sepp;
 124  124          spa_t *spa;
 125  125          nvpair_t *elem;
 126  126          nvlist_t *props;
 127  127          const char *name;
 128  128  
 129  129          kernel_init(readonly ? FREAD : (FREAD | FWRITE));
 130  130          g_zfs = libzfs_init();
 131  131          ASSERT(g_zfs != NULL);
 132  132  
 133  133          dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
 134  134  
 135  135          g_readonly = readonly;
 136  136  
 137  137          /*
 138  138           * If we only want readonly access, it's OK if we find
 139  139           * a potentially-active (ie, imported into the kernel) pool from the
 140  140           * default cachefile.
 141  141           */
 142  142          if (readonly && spa_open(target, &spa, FTAG) == 0) {
 143  143                  spa_close(spa, FTAG);
 144  144                  return;
 145  145          }
 146  146  
 147  147          g_importargs.unique = B_TRUE;
 148  148          g_importargs.can_be_active = readonly;
 149  149          g_pool = strdup(target);
 150  150          if ((sepp = strpbrk(g_pool, "/@")) != NULL)
 151  151                  *sepp = '\0';
 152  152          g_importargs.poolname = g_pool;
 153  153          pools = zpool_search_import(g_zfs, &g_importargs);
 154  154  
 155  155          if (pools == NULL || nvlist_next_nvpair(pools, NULL) == NULL) {
 156  156                  if (!g_importargs.can_be_active) {
 157  157                          g_importargs.can_be_active = B_TRUE;
 158  158                          if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
 159  159                              spa_open(target, &spa, FTAG) == 0) {
 160  160                                  fatal("cannot import '%s': pool is active; run "
 161  161                                      "\"zpool export %s\" first\n",
 162  162                                      g_pool, g_pool);
 163  163                          }
 164  164                  }
 165  165  
 166  166                  fatal("cannot import '%s': no such pool available\n", g_pool);
 167  167          }
 168  168  
 169  169          elem = nvlist_next_nvpair(pools, NULL);
 170  170          name = nvpair_name(elem);
 171  171          verify(nvpair_value_nvlist(elem, &config) == 0);
 172  172  
 173  173          props = NULL;
 174  174          if (readonly) {
 175  175                  verify(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
 176  176                  verify(nvlist_add_uint64(props,
 177  177                      zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
 178  178          }
 179  179  
 180  180          zfeature_checks_disable = B_TRUE;
 181  181          error = spa_import(name, config, props, ZFS_IMPORT_NORMAL);
 182  182          zfeature_checks_disable = B_FALSE;
 183  183          if (error == EEXIST)
 184  184                  error = 0;
 185  185  
 186  186          if (error)
 187  187                  fatal("can't import '%s': %s", name, strerror(error));
 188  188  }
 189  189  
 190  190  static void
 191  191  zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
 192  192  {
 193  193          int err;
 194  194  
 195  195          import_pool(target, readonly);
 196  196  
 197  197          zfeature_checks_disable = B_TRUE;
 198  198          err = spa_open(target, spa, tag);
 199  199          zfeature_checks_disable = B_FALSE;
 200  200  
 201  201          if (err != 0)
 202  202                  fatal("cannot open '%s': %s", target, strerror(err));
 203  203          if (spa_version(*spa) < SPA_VERSION_FEATURES) {
 204  204                  fatal("'%s' has version %d, features not enabled", target,
 205  205                      (int)spa_version(*spa));
 206  206          }
 207  207  }
 208  208  
 209  209  static void
 210  210  dump_obj(objset_t *os, uint64_t obj, const char *name)
 211  211  {
 212  212          zap_cursor_t zc;
 213  213          zap_attribute_t za;
 214  214  
 215  215          (void) printf("%s_obj:\n", name);
 216  216  
 217  217          for (zap_cursor_init(&zc, os, obj);
 218  218              zap_cursor_retrieve(&zc, &za) == 0;
 219  219              zap_cursor_advance(&zc)) {
 220  220                  if (za.za_integer_length == 8) {
 221  221                          ASSERT(za.za_num_integers == 1);
 222  222                          (void) printf("\t%s = %llu\n",
 223  223                              za.za_name, (u_longlong_t)za.za_first_integer);
 224  224                  } else {
 225  225                          ASSERT(za.za_integer_length == 1);
 226  226                          char val[1024];
 227  227                          VERIFY(zap_lookup(os, obj, za.za_name,
 228  228                              1, sizeof (val), val) == 0);
 229  229                          (void) printf("\t%s = %s\n", za.za_name, val);
 230  230                  }
 231  231          }
 232  232          zap_cursor_fini(&zc);
 233  233  }
 234  234  
 235  235  static void
 236  236  dump_mos(spa_t *spa)
 237  237  {
 238  238          nvlist_t *nv = spa->spa_label_features;
 239  239  
 240  240          (void) printf("label config:\n");
 241  241          for (nvpair_t *pair = nvlist_next_nvpair(nv, NULL);
 242  242              pair != NULL;
 243  243              pair = nvlist_next_nvpair(nv, pair)) {
 244  244                  (void) printf("\t%s\n", nvpair_name(pair));
 245  245          }
 246  246  }
 247  247  
 248  248  static void
 249  249  zhack_do_feature_stat(int argc, char **argv)
 250  250  {
 251  251          spa_t *spa;
 252  252          objset_t *os;
 253  253          char *target;
 254  254  
 255  255          argc--;
 256  256          argv++;
 257  257  
 258  258          if (argc < 1) {
 259  259                  (void) fprintf(stderr, "error: missing pool name\n");
 260  260                  usage();
 261  261          }
 262  262          target = argv[0];
 263  263  
 264  264          zhack_spa_open(target, B_TRUE, FTAG, &spa);
 265  265          os = spa->spa_meta_objset;
 266  266  
 267  267          dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
 268  268          dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
 269  269          dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
 270  270          dump_mos(spa);
 271  271  
 272  272          spa_close(spa, FTAG);
 273  273  }
 274  274  
 275  275  static void
 276  276  feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 277  277  {
 278  278          spa_t *spa = arg1;
 279  279          zfeature_info_t *feature = arg2;
 280  280  
 281  281          spa_feature_enable(spa, feature, tx);
 282  282          spa_history_log_internal(spa, "zhack enable feature", tx,
 283  283              "name=%s can_readonly=%u",
 284  284              feature->fi_guid, feature->fi_can_readonly);
 285  285  }
 286  286  
 287  287  static void
 288  288  zhack_do_feature_enable(int argc, char **argv)
 289  289  {
 290  290          char c;
 291  291          char *desc, *target;
 292  292          spa_t *spa;
 293  293          objset_t *mos;
 294  294          zfeature_info_t feature;
 295  295          zfeature_info_t *nodeps[] = { NULL };
 296  296  
 297  297          /*
 298  298           * Features are not added to the pool's label until their refcounts
 299  299           * are incremented, so fi_mos can just be left as false for now.
 300  300           */
 301  301          desc = NULL;
 302  302          feature.fi_uname = "zhack";
 303  303          feature.fi_mos = B_FALSE;
 304  304          feature.fi_can_readonly = B_FALSE;
 305  305          feature.fi_depends = nodeps;
 306  306  
 307  307          optind = 1;
 308  308          while ((c = getopt(argc, argv, "rmd:")) != -1) {
 309  309                  switch (c) {
 310  310                  case 'r':
 311  311                          feature.fi_can_readonly = B_TRUE;
 312  312                          break;
 313  313                  case 'd':
 314  314                          desc = strdup(optarg);
 315  315                          break;
 316  316                  default:
 317  317                          usage();
 318  318                          break;
 319  319                  }
 320  320          }
 321  321  
 322  322          if (desc == NULL)
 323  323                  desc = strdup("zhack injected");
 324  324          feature.fi_desc = desc;
 325  325  
 326  326          argc -= optind;
 327  327          argv += optind;
 328  328  
 329  329          if (argc < 2) {
 330  330                  (void) fprintf(stderr, "error: missing feature or pool name\n");
 331  331                  usage();
 332  332          }
 333  333          target = argv[0];
 334  334          feature.fi_guid = argv[1];
 335  335  
 336  336          if (!zfeature_is_valid_guid(feature.fi_guid))
  
    | 
      ↓ open down ↓ | 
    336 lines elided | 
    
      ↑ open up ↑ | 
  
 337  337                  fatal("invalid feature guid: %s", feature.fi_guid);
 338  338  
 339  339          zhack_spa_open(target, B_FALSE, FTAG, &spa);
 340  340          mos = spa->spa_meta_objset;
 341  341  
 342  342          if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
 343  343                  fatal("'%s' is a real feature, will not enable");
 344  344          if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
 345  345                  fatal("feature already enabled: %s", feature.fi_guid);
 346  346  
 347      -        VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
      347 +        VERIFY0(dsl_sync_task_do(spa->spa_dsl_pool, NULL,
 348  348              feature_enable_sync, spa, &feature, 5));
 349  349  
 350  350          spa_close(spa, FTAG);
 351  351  
 352  352          free(desc);
 353  353  }
 354  354  
 355  355  static void
 356  356  feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 357  357  {
 358  358          spa_t *spa = arg1;
 359  359          zfeature_info_t *feature = arg2;
 360  360  
 361  361          spa_feature_incr(spa, feature, tx);
 362  362          spa_history_log_internal(spa, "zhack feature incr", tx,
 363  363              "name=%s", feature->fi_guid);
 364  364  }
 365  365  
 366  366  static void
 367  367  feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 368  368  {
 369  369          spa_t *spa = arg1;
 370  370          zfeature_info_t *feature = arg2;
 371  371  
 372  372          spa_feature_decr(spa, feature, tx);
 373  373          spa_history_log_internal(spa, "zhack feature decr", tx,
 374  374              "name=%s", feature->fi_guid);
 375  375  }
 376  376  
 377  377  static void
 378  378  zhack_do_feature_ref(int argc, char **argv)
 379  379  {
 380  380          char c;
 381  381          char *target;
 382  382          boolean_t decr = B_FALSE;
 383  383          spa_t *spa;
 384  384          objset_t *mos;
 385  385          zfeature_info_t feature;
 386  386          zfeature_info_t *nodeps[] = { NULL };
 387  387  
 388  388          /*
 389  389           * fi_desc does not matter here because it was written to disk
 390  390           * when the feature was enabled, but we need to properly set the
 391  391           * feature for read or write based on the information we read off
 392  392           * disk later.
 393  393           */
 394  394          feature.fi_uname = "zhack";
 395  395          feature.fi_mos = B_FALSE;
 396  396          feature.fi_desc = NULL;
 397  397          feature.fi_depends = nodeps;
 398  398  
 399  399          optind = 1;
 400  400          while ((c = getopt(argc, argv, "md")) != -1) {
 401  401                  switch (c) {
 402  402                  case 'm':
 403  403                          feature.fi_mos = B_TRUE;
 404  404                          break;
 405  405                  case 'd':
 406  406                          decr = B_TRUE;
 407  407                          break;
 408  408                  default:
 409  409                          usage();
 410  410                          break;
 411  411                  }
 412  412          }
 413  413          argc -= optind;
 414  414          argv += optind;
 415  415  
 416  416          if (argc < 2) {
 417  417                  (void) fprintf(stderr, "error: missing feature or pool name\n");
 418  418                  usage();
 419  419          }
 420  420          target = argv[0];
 421  421          feature.fi_guid = argv[1];
 422  422  
 423  423          if (!zfeature_is_valid_guid(feature.fi_guid))
 424  424                  fatal("invalid feature guid: %s", feature.fi_guid);
 425  425  
 426  426          zhack_spa_open(target, B_FALSE, FTAG, &spa);
 427  427          mos = spa->spa_meta_objset;
 428  428  
 429  429          if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
 430  430                  fatal("'%s' is a real feature, will not change refcount");
 431  431  
 432  432          if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
 433  433              feature.fi_guid)) {
 434  434                  feature.fi_can_readonly = B_FALSE;
  
    | 
      ↓ open down ↓ | 
    77 lines elided | 
    
      ↑ open up ↑ | 
  
 435  435          } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
 436  436              feature.fi_guid)) {
 437  437                  feature.fi_can_readonly = B_TRUE;
 438  438          } else {
 439  439                  fatal("feature is not enabled: %s", feature.fi_guid);
 440  440          }
 441  441  
 442  442          if (decr && !spa_feature_is_active(spa, &feature))
 443  443                  fatal("feature refcount already 0: %s", feature.fi_guid);
 444  444  
 445      -        VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
      445 +        VERIFY0(dsl_sync_task_do(spa->spa_dsl_pool, NULL,
 446  446              decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
 447  447  
 448  448          spa_close(spa, FTAG);
 449  449  }
 450  450  
 451  451  static int
 452  452  zhack_do_feature(int argc, char **argv)
 453  453  {
 454  454          char *subcommand;
 455  455  
 456  456          argc--;
 457  457          argv++;
 458  458          if (argc == 0) {
 459  459                  (void) fprintf(stderr,
 460  460                      "error: no feature operation specified\n");
 461  461                  usage();
 462  462          }
 463  463  
 464  464          subcommand = argv[0];
 465  465          if (strcmp(subcommand, "stat") == 0) {
 466  466                  zhack_do_feature_stat(argc, argv);
 467  467          } else if (strcmp(subcommand, "enable") == 0) {
 468  468                  zhack_do_feature_enable(argc, argv);
 469  469          } else if (strcmp(subcommand, "ref") == 0) {
 470  470                  zhack_do_feature_ref(argc, argv);
 471  471          } else {
 472  472                  (void) fprintf(stderr, "error: unknown subcommand: %s\n",
 473  473                      subcommand);
 474  474                  usage();
 475  475          }
 476  476  
 477  477          return (0);
 478  478  }
 479  479  
 480  480  #define MAX_NUM_PATHS 1024
 481  481  
 482  482  int
 483  483  main(int argc, char **argv)
 484  484  {
 485  485          extern void zfs_prop_init(void);
 486  486  
 487  487          char *path[MAX_NUM_PATHS];
 488  488          const char *subcommand;
 489  489          int rv = 0;
 490  490          char c;
 491  491  
 492  492          g_importargs.path = path;
 493  493  
 494  494          dprintf_setup(&argc, argv);
 495  495          zfs_prop_init();
 496  496  
 497  497          while ((c = getopt(argc, argv, "c:d:")) != -1) {
 498  498                  switch (c) {
 499  499                  case 'c':
 500  500                          g_importargs.cachefile = optarg;
 501  501                          break;
 502  502                  case 'd':
 503  503                          assert(g_importargs.paths < MAX_NUM_PATHS);
 504  504                          g_importargs.path[g_importargs.paths++] = optarg;
 505  505                          break;
 506  506                  default:
 507  507                          usage();
 508  508                          break;
 509  509                  }
 510  510          }
 511  511  
 512  512          argc -= optind;
 513  513          argv += optind;
 514  514          optind = 1;
 515  515  
 516  516          if (argc == 0) {
 517  517                  (void) fprintf(stderr, "error: no command specified\n");
 518  518                  usage();
 519  519          }
 520  520  
 521  521          subcommand = argv[0];
 522  522  
 523  523          if (strcmp(subcommand, "feature") == 0) {
 524  524                  rv = zhack_do_feature(argc, argv);
 525  525          } else {
 526  526                  (void) fprintf(stderr, "error: unknown subcommand: %s\n",
 527  527                      subcommand);
 528  528                  usage();
 529  529          }
 530  530  
 531  531          if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_TRUE) != 0) {
 532  532                  fatal("pool export failed; "
 533  533                      "changes may not be committed to disk\n");
 534  534          }
 535  535  
 536  536          libzfs_fini(g_zfs);
 537  537          kernel_fini();
 538  538  
 539  539          return (rv);
 540  540  }
  
    | 
      ↓ open down ↓ | 
    85 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX