Print this page
    
2619 asynchronous destruction of ZFS file systems
2747 SPA versioning with zfs feature flags
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <gwilson@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
Approved by: Dan McDonald <danmcd@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libzfs/common/libzfs_status.c
          +++ new/usr/src/lib/libzfs/common/libzfs_status.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
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
  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   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright (c) 2012 by Delphix. All rights reserved.
  23   25   */
  24   26  
  25   27  /*
  26   28   * This file contains the functions which analyze the status of a pool.  This
  27   29   * include both the status of an active pool, as well as the status exported
  28   30   * pools.  Returns one of the ZPOOL_STATUS_* defines describing the status of
  29   31   * the pool.  This status is independent (to a certain degree) from the state of
  30   32   * the pool.  A pool's state describes only whether or not it is capable of
  31   33   * providing the necessary fault tolerance for data.  The status describes the
  32   34   * overall status of devices.  A pool that is online can still have a device
  33   35   * that is experiencing errors.
  34   36   *
  35   37   * Only a subset of the possible faults can be detected using 'zpool status',
  36   38   * and not all possible errors correspond to a FMA message ID.  The explanation
  37   39   * is left up to the caller, depending on whether it is a live pool or an
  38   40   * import.
  39   41   */
  40   42  
  41   43  #include <libzfs.h>
  42   44  #include <string.h>
  43   45  #include <unistd.h>
  44   46  #include "libzfs_impl.h"
  45   47  
  46   48  /*
  47   49   * Message ID table.  This must be kept in sync with the ZPOOL_STATUS_* defines
  48   50   * in libzfs.h.  Note that there are some status results which go past the end
  49   51   * of this table, and hence have no associated message ID.
  50   52   */
  51   53  static char *zfs_msgid_table[] = {
  52   54          "ZFS-8000-14",
  53   55          "ZFS-8000-2Q",
  54   56          "ZFS-8000-3C",
  55   57          "ZFS-8000-4J",
  56   58          "ZFS-8000-5E",
  57   59          "ZFS-8000-6X",
  58   60          "ZFS-8000-72",
  59   61          "ZFS-8000-8A",
  60   62          "ZFS-8000-9P",
  61   63          "ZFS-8000-A5",
  62   64          "ZFS-8000-EY",
  63   65          "ZFS-8000-HC",
  64   66          "ZFS-8000-JQ",
  65   67          "ZFS-8000-K4",
  66   68  };
  67   69  
  68   70  #define NMSGID  (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
  69   71  
  70   72  /* ARGSUSED */
  71   73  static int
  72   74  vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
  73   75  {
  74   76          return (state == VDEV_STATE_CANT_OPEN &&
  75   77              aux == VDEV_AUX_OPEN_FAILED);
  76   78  }
  77   79  
  78   80  /* ARGSUSED */
  79   81  static int
  80   82  vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs)
  81   83  {
  82   84          return (state == VDEV_STATE_FAULTED);
  83   85  }
  84   86  
  85   87  /* ARGSUSED */
  86   88  static int
  87   89  vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
  88   90  {
  89   91          return (state == VDEV_STATE_DEGRADED || errs != 0);
  90   92  }
  91   93  
  92   94  /* ARGSUSED */
  93   95  static int
  94   96  vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
  95   97  {
  96   98          return (state == VDEV_STATE_CANT_OPEN);
  97   99  }
  98  100  
  99  101  /* ARGSUSED */
 100  102  static int
 101  103  vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
 102  104  {
 103  105          return (state == VDEV_STATE_OFFLINE);
 104  106  }
 105  107  
 106  108  /* ARGSUSED */
 107  109  static int
 108  110  vdev_removed(uint64_t state, uint64_t aux, uint64_t errs)
 109  111  {
 110  112          return (state == VDEV_STATE_REMOVED);
 111  113  }
 112  114  
 113  115  /*
 114  116   * Detect if any leaf devices that have seen errors or could not be opened.
 115  117   */
 116  118  static boolean_t
 117  119  find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
 118  120  {
 119  121          nvlist_t **child;
 120  122          vdev_stat_t *vs;
 121  123          uint_t c, children;
 122  124          char *type;
 123  125  
 124  126          /*
 125  127           * Ignore problems within a 'replacing' vdev, since we're presumably in
 126  128           * the process of repairing any such errors, and don't want to call them
 127  129           * out again.  We'll pick up the fact that a resilver is happening
 128  130           * later.
 129  131           */
 130  132          verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
 131  133          if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
 132  134                  return (B_FALSE);
 133  135  
 134  136          if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
 135  137              &children) == 0) {
 136  138                  for (c = 0; c < children; c++)
 137  139                          if (find_vdev_problem(child[c], func))
 138  140                                  return (B_TRUE);
 139  141          } else {
 140  142                  verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
 141  143                      (uint64_t **)&vs, &c) == 0);
 142  144  
 143  145                  if (func(vs->vs_state, vs->vs_aux,
 144  146                      vs->vs_read_errors +
 145  147                      vs->vs_write_errors +
 146  148                      vs->vs_checksum_errors))
 147  149                          return (B_TRUE);
 148  150          }
 149  151  
 150  152          return (B_FALSE);
 151  153  }
 152  154  
 153  155  /*
 154  156   * Active pool health status.
 155  157   *
 156  158   * To determine the status for a pool, we make several passes over the config,
 157  159   * picking the most egregious error we find.  In order of importance, we do the
 158  160   * following:
 159  161   *
 160  162   *      - Check for a complete and valid configuration
 161  163   *      - Look for any faulted or missing devices in a non-replicated config
 162  164   *      - Check for any data errors
 163  165   *      - Check for any faulted or missing devices in a replicated config
 164  166   *      - Look for any devices showing errors
 165  167   *      - Check for any resilvering devices
 166  168   *
 167  169   * There can obviously be multiple errors within a single pool, so this routine
 168  170   * only picks the most damaging of all the current errors to report.
 169  171   */
 170  172  static zpool_status_t
 171  173  check_status(nvlist_t *config, boolean_t isimport)
 172  174  {
 173  175          nvlist_t *nvroot;
 174  176          vdev_stat_t *vs;
 175  177          pool_scan_stat_t *ps = NULL;
 176  178          uint_t vsc, psc;
 177  179          uint64_t nerr;
 178  180          uint64_t version;
 179  181          uint64_t stateval;
 180  182          uint64_t suspended;
 181  183          uint64_t hostid = 0;
 182  184  
 183  185          verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
 184  186              &version) == 0);
 185  187          verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
 186  188              &nvroot) == 0);
 187  189          verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
 188  190              (uint64_t **)&vs, &vsc) == 0);
 189  191          verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
 190  192              &stateval) == 0);
 191  193  
 192  194          /*
 193  195           * Currently resilvering a vdev
 194  196           */
 195  197          (void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
 196  198              (uint64_t **)&ps, &psc);
 197  199          if (ps && ps->pss_func == POOL_SCAN_RESILVER &&
 198  200              ps->pss_state == DSS_SCANNING)
 199  201                  return (ZPOOL_STATUS_RESILVERING);
 200  202  
 201  203          /*
 202  204           * Pool last accessed by another system.
 203  205           */
 204  206          (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
 205  207          if (hostid != 0 && (unsigned long)hostid != gethostid() &&
 206  208              stateval == POOL_STATE_ACTIVE)
  
    | 
      ↓ open down ↓ | 
    174 lines elided | 
    
      ↑ open up ↑ | 
  
 207  209                  return (ZPOOL_STATUS_HOSTID_MISMATCH);
 208  210  
 209  211          /*
 210  212           * Newer on-disk version.
 211  213           */
 212  214          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 213  215              vs->vs_aux == VDEV_AUX_VERSION_NEWER)
 214  216                  return (ZPOOL_STATUS_VERSION_NEWER);
 215  217  
 216  218          /*
      219 +         * Unsupported feature(s).
      220 +         */
      221 +        if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
      222 +            vs->vs_aux == VDEV_AUX_UNSUP_FEAT) {
      223 +                nvlist_t *nvinfo;
      224 +
      225 +                verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
      226 +                    &nvinfo) == 0);
      227 +                if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY))
      228 +                        return (ZPOOL_STATUS_UNSUP_FEAT_WRITE);
      229 +                return (ZPOOL_STATUS_UNSUP_FEAT_READ);
      230 +        }
      231 +
      232 +        /*
 217  233           * Check that the config is complete.
 218  234           */
 219  235          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 220  236              vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
 221  237                  return (ZPOOL_STATUS_BAD_GUID_SUM);
 222  238  
 223  239          /*
 224  240           * Check whether the pool has suspended due to failed I/O.
 225  241           */
 226  242          if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
 227  243              &suspended) == 0) {
 228  244                  if (suspended == ZIO_FAILURE_MODE_CONTINUE)
 229  245                          return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
 230  246                  return (ZPOOL_STATUS_IO_FAILURE_WAIT);
 231  247          }
 232  248  
 233  249          /*
 234  250           * Could not read a log.
 235  251           */
 236  252          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 237  253              vs->vs_aux == VDEV_AUX_BAD_LOG) {
 238  254                  return (ZPOOL_STATUS_BAD_LOG);
 239  255          }
 240  256  
 241  257          /*
 242  258           * Bad devices in non-replicated config.
 243  259           */
 244  260          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 245  261              find_vdev_problem(nvroot, vdev_faulted))
 246  262                  return (ZPOOL_STATUS_FAULTED_DEV_NR);
 247  263  
 248  264          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 249  265              find_vdev_problem(nvroot, vdev_missing))
 250  266                  return (ZPOOL_STATUS_MISSING_DEV_NR);
 251  267  
 252  268          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 253  269              find_vdev_problem(nvroot, vdev_broken))
 254  270                  return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
 255  271  
 256  272          /*
 257  273           * Corrupted pool metadata
 258  274           */
 259  275          if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
 260  276              vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
 261  277                  return (ZPOOL_STATUS_CORRUPT_POOL);
 262  278  
 263  279          /*
 264  280           * Persistent data errors.
 265  281           */
 266  282          if (!isimport) {
 267  283                  if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
 268  284                      &nerr) == 0 && nerr != 0)
 269  285                          return (ZPOOL_STATUS_CORRUPT_DATA);
 270  286          }
 271  287  
 272  288          /*
 273  289           * Missing devices in a replicated config.
 274  290           */
 275  291          if (find_vdev_problem(nvroot, vdev_faulted))
 276  292                  return (ZPOOL_STATUS_FAULTED_DEV_R);
 277  293          if (find_vdev_problem(nvroot, vdev_missing))
 278  294                  return (ZPOOL_STATUS_MISSING_DEV_R);
 279  295          if (find_vdev_problem(nvroot, vdev_broken))
 280  296                  return (ZPOOL_STATUS_CORRUPT_LABEL_R);
 281  297  
 282  298          /*
 283  299           * Devices with errors
 284  300           */
 285  301          if (!isimport && find_vdev_problem(nvroot, vdev_errors))
 286  302                  return (ZPOOL_STATUS_FAILING_DEV);
 287  303  
 288  304          /*
 289  305           * Offlined devices
 290  306           */
 291  307          if (find_vdev_problem(nvroot, vdev_offlined))
 292  308                  return (ZPOOL_STATUS_OFFLINE_DEV);
  
    | 
      ↓ open down ↓ | 
    66 lines elided | 
    
      ↑ open up ↑ | 
  
 293  309  
 294  310          /*
 295  311           * Removed device
 296  312           */
 297  313          if (find_vdev_problem(nvroot, vdev_removed))
 298  314                  return (ZPOOL_STATUS_REMOVED_DEV);
 299  315  
 300  316          /*
 301  317           * Outdated, but usable, version
 302  318           */
 303      -        if (version < SPA_VERSION)
      319 +        if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION)
 304  320                  return (ZPOOL_STATUS_VERSION_OLDER);
 305  321  
 306  322          return (ZPOOL_STATUS_OK);
 307  323  }
 308  324  
 309  325  zpool_status_t
 310  326  zpool_get_status(zpool_handle_t *zhp, char **msgid)
 311  327  {
 312  328          zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
 313  329  
 314  330          if (ret >= NMSGID)
 315  331                  *msgid = NULL;
 316  332          else
 317  333                  *msgid = zfs_msgid_table[ret];
 318  334  
 319  335          return (ret);
 320  336  }
 321  337  
 322  338  zpool_status_t
 323  339  zpool_import_status(nvlist_t *config, char **msgid)
 324  340  {
 325  341          zpool_status_t ret = check_status(config, B_TRUE);
 326  342  
 327  343          if (ret >= NMSGID)
 328  344                  *msgid = NULL;
 329  345          else
 330  346                  *msgid = zfs_msgid_table[ret];
 331  347  
 332  348          return (ret);
 333  349  }
 334  350  
 335  351  static void
 336  352  dump_ddt_stat(const ddt_stat_t *dds, int h)
 337  353  {
 338  354          char refcnt[6];
 339  355          char blocks[6], lsize[6], psize[6], dsize[6];
 340  356          char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
 341  357  
 342  358          if (dds == NULL || dds->dds_blocks == 0)
 343  359                  return;
 344  360  
 345  361          if (h == -1)
 346  362                  (void) strcpy(refcnt, "Total");
 347  363          else
 348  364                  zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
 349  365  
 350  366          zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
 351  367          zfs_nicenum(dds->dds_lsize, lsize, sizeof (lsize));
 352  368          zfs_nicenum(dds->dds_psize, psize, sizeof (psize));
 353  369          zfs_nicenum(dds->dds_dsize, dsize, sizeof (dsize));
 354  370          zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
 355  371          zfs_nicenum(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
 356  372          zfs_nicenum(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
 357  373          zfs_nicenum(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
 358  374  
 359  375          (void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
 360  376              refcnt,
 361  377              blocks, lsize, psize, dsize,
 362  378              ref_blocks, ref_lsize, ref_psize, ref_dsize);
 363  379  }
 364  380  
 365  381  /*
 366  382   * Print the DDT histogram and the column totals.
 367  383   */
 368  384  void
 369  385  zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
 370  386  {
 371  387          int h;
 372  388  
 373  389          (void) printf("\n");
 374  390  
 375  391          (void) printf("bucket   "
 376  392              "           allocated             "
 377  393              "          referenced          \n");
 378  394          (void) printf("______   "
 379  395              "______________________________   "
 380  396              "______________________________\n");
 381  397  
 382  398          (void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
 383  399              "refcnt",
 384  400              "blocks", "LSIZE", "PSIZE", "DSIZE",
 385  401              "blocks", "LSIZE", "PSIZE", "DSIZE");
 386  402  
 387  403          (void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
 388  404              "------",
 389  405              "------", "-----", "-----", "-----",
 390  406              "------", "-----", "-----", "-----");
 391  407  
 392  408          for (h = 0; h < 64; h++)
 393  409                  dump_ddt_stat(&ddh->ddh_stat[h], h);
 394  410  
 395  411          dump_ddt_stat(dds_total, -1);
 396  412  
 397  413          (void) printf("\n");
 398  414  }
  
    | 
      ↓ open down ↓ | 
    85 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX