1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 #include <sys/spa_impl.h>
  17 #include <sys/vdev_impl.h>
  18 #include <sys/cos_impl.h>
  19 #include <sys/refcount.h>
  20 #include <sys/dmu.h>
  21 #include <sys/dsl_synctask.h>
  22 #include <sys/zap.h>
  23 #include <sys/zfeature.h>
  24 
  25 #include <zfs_prop.h>
  26 
  27 /*
  28  * Support for vdev-specific properties. Similar properties can be set
  29  * on per-pool basis; vdev-specific properties override per-pool ones.
  30  * In addition to path and fru, the supported vdev properties include
  31  * min_active/max_active (request queue length params), and preferred
  32  * read (biases reads toward this device if it is a part of a mirror).
  33  */
  34 
  35 /*
  36  * Add vdev properties for this vdev to nvl_array[index]
  37  */
  38 static void
  39 vdev_add_props(vdev_t *vdev, nvlist_t *nvl_array[], uint_t *index)
  40 {
  41         const char *propname;
  42         zio_priority_t p;
  43 
  44         if (!vdev->vdev_ops->vdev_op_leaf) {
  45                 for (int c = 0; c < vdev->vdev_children; c++) {
  46                         vdev_add_props(vdev->vdev_child[c], nvl_array,
  47                             index);
  48                 }
  49                 return;
  50         }
  51 
  52         propname = vdev_prop_to_name(VDEV_PROP_GUID);
  53         VERIFY0(nvlist_add_uint64(nvl_array[*index], propname,
  54             vdev->vdev_guid));
  55 
  56         for (p = ZIO_PRIORITY_SYNC_READ; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++) {
  57                 uint64_t val = vdev->vdev_queue.vq_class[p].vqc_min_active;
  58                 int prop_id = VDEV_ZIO_PRIO_TO_PROP_MIN(p);
  59 
  60                 ASSERT(VDEV_PROP_MIN_VALID(prop_id));
  61                 propname = vdev_prop_to_name(prop_id);
  62                 VERIFY0(nvlist_add_uint64(nvl_array[*index], propname, val));
  63 
  64                 val = vdev->vdev_queue.vq_class[p].vqc_max_active;
  65                 prop_id = VDEV_ZIO_PRIO_TO_PROP_MAX(p);
  66                 ASSERT(VDEV_PROP_MAX_VALID(prop_id));
  67                 propname = vdev_prop_to_name(prop_id);
  68                 VERIFY0(nvlist_add_uint64(nvl_array[*index], propname, val));
  69         }
  70 
  71         propname = vdev_prop_to_name(VDEV_PROP_PREFERRED_READ);
  72         VERIFY0(nvlist_add_uint64(nvl_array[*index], propname,
  73             vdev->vdev_queue.vq_preferred_read));
  74 
  75         if (vdev->vdev_queue.vq_cos) {
  76                 propname = vdev_prop_to_name(VDEV_PROP_COS);
  77                 VERIFY0(nvlist_add_uint64(nvl_array[*index], propname,
  78                     vdev->vdev_queue.vq_cos->cos_guid));
  79         }
  80 
  81         if (vdev->vdev_spare_group) {
  82                 propname = vdev_prop_to_name(VDEV_PROP_SPAREGROUP);
  83                 VERIFY0(nvlist_add_string(nvl_array[*index], propname,
  84                     vdev->vdev_spare_group));
  85         }
  86 
  87         propname = vdev_prop_to_name(VDEV_PROP_L2ADDDT);
  88         VERIFY0(nvlist_add_uint64(nvl_array[*index], propname,
  89             vdev->vdev_l2ad_ddt));
  90 
  91         (*index)++;
  92 }
  93 
  94 /*
  95  * Get the properties from nvlist and put them in vdev object
  96  */
  97 static void
  98 vdev_parse_props(vdev_t *vdev, nvlist_t *nvl)
  99 {
 100         uint64_t ival;
 101         const char *propname;
 102         char *sval;
 103         zio_priority_t p;
 104 
 105         ASSERT(vdev);
 106 
 107         if (!vdev->vdev_ops->vdev_op_leaf)
 108                 return;
 109 
 110         for (p = ZIO_PRIORITY_SYNC_READ; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++) {
 111                 int prop_id = VDEV_ZIO_PRIO_TO_PROP_MIN(p);
 112 
 113                 ASSERT(VDEV_PROP_MIN_VALID(prop_id));
 114                 propname = vdev_prop_to_name(prop_id);
 115 
 116                 if (nvlist_lookup_uint64(nvl, propname, &ival) == 0)
 117                         vdev->vdev_queue.vq_class[p].vqc_min_active = ival;
 118 
 119                 prop_id = VDEV_ZIO_PRIO_TO_PROP_MAX(p);
 120                 ASSERT(VDEV_PROP_MAX_VALID(prop_id));
 121                 propname = vdev_prop_to_name(prop_id);
 122                 if (nvlist_lookup_uint64(nvl, propname, &ival) == 0)
 123                         vdev->vdev_queue.vq_class[p].vqc_max_active = ival;
 124         }
 125 
 126         propname = vdev_prop_to_name(VDEV_PROP_L2ADDDT);
 127         if (nvlist_lookup_uint64(nvl, propname, &ival) == 0) {
 128                 vdev->vdev_l2ad_ddt = ival;
 129                 /* on import may need to adjust per SPA DDT dev space count */
 130                 if (vdev->vdev_l2ad_ddt == 1) {
 131                         atomic_add_64(&vdev->vdev_spa->spa_l2arc_ddt_devs_size,
 132                             vdev_get_min_asize(vdev));
 133                 }
 134         }
 135 
 136         propname = vdev_prop_to_name(VDEV_PROP_PREFERRED_READ);
 137         if (nvlist_lookup_uint64(nvl, propname, &ival) == 0)
 138                 vdev->vdev_queue.vq_preferred_read = ival;
 139         propname = vdev_prop_to_name(VDEV_PROP_COS);
 140         if (nvlist_lookup_uint64(nvl, propname, &ival) == 0) {
 141                 /*
 142                  * At this time, all CoS properties have been loaded.
 143                  * Lookup CoS by guid and take it if found.
 144                  */
 145                 cos_t *cos = NULL;
 146                 spa_t *spa = vdev->vdev_spa;
 147                 spa_cos_enter(spa);
 148                 cos = spa_lookup_cos_by_guid(spa, ival);
 149                 if (cos) {
 150                         cos_hold(cos);
 151                         vdev->vdev_queue.vq_cos = cos;
 152                 } else {
 153                         cmn_err(CE_WARN, "vdev %s refers to non-existent "
 154                             "CoS %" PRIu64 "\n", vdev->vdev_path, ival);
 155                         vdev->vdev_queue.vq_cos = NULL;
 156                 }
 157                 spa_cos_exit(spa);
 158         }
 159         propname = vdev_prop_to_name(VDEV_PROP_SPAREGROUP);
 160         if (nvlist_lookup_string(nvl, propname, &sval) == 0)
 161                 vdev->vdev_spare_group = spa_strdup(sval);
 162 }
 163 
 164 /*
 165  * Get specific property for a leaf-level vdev by property id or name.
 166  */
 167 static int
 168 spa_vdev_get_common(spa_t *spa, uint64_t guid, char **value,
 169     uint64_t *oval, vdev_prop_t prop)
 170 {
 171         vdev_t *vd;
 172         vdev_queue_class_t *vqc;
 173         zio_priority_t p;
 174 
 175         spa_vdev_state_enter(spa, SCL_ALL);
 176 
 177         if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
 178                 return (spa_vdev_state_exit(spa, NULL, EINVAL));
 179 
 180         if (!vd->vdev_ops->vdev_op_leaf)
 181                 return (spa_vdev_state_exit(spa, NULL, EINVAL));
 182 
 183         vqc = vd->vdev_queue.vq_class;
 184 
 185         switch (prop) {
 186         case VDEV_PROP_L2ADDDT:
 187                 *oval = vd->vdev_l2ad_ddt;
 188                 break;
 189         case VDEV_PROP_PATH:
 190                 if (vd->vdev_path != NULL) {
 191                         *value = vd->vdev_path;
 192                 }
 193                 break;
 194         case VDEV_PROP_GUID:
 195                 *oval = guid;
 196                 break;
 197         case VDEV_PROP_FRU:
 198                 if (vd->vdev_fru != NULL) {
 199                         *value = vd->vdev_fru;
 200                 }
 201                 break;
 202 
 203         case VDEV_PROP_READ_MINACTIVE:
 204         case VDEV_PROP_AREAD_MINACTIVE:
 205         case VDEV_PROP_WRITE_MINACTIVE:
 206         case VDEV_PROP_AWRITE_MINACTIVE:
 207         case VDEV_PROP_SCRUB_MINACTIVE:
 208         case VDEV_PROP_RESILVER_MINACTIVE:
 209                 p = VDEV_PROP_TO_ZIO_PRIO_MIN(prop);
 210                 ASSERT(ZIO_PRIORITY_QUEUEABLE_VALID(p));
 211                 *oval = vqc[p].vqc_min_active;
 212                 break;
 213 
 214         case VDEV_PROP_READ_MAXACTIVE:
 215         case VDEV_PROP_AREAD_MAXACTIVE:
 216         case VDEV_PROP_WRITE_MAXACTIVE:
 217         case VDEV_PROP_AWRITE_MAXACTIVE:
 218         case VDEV_PROP_SCRUB_MAXACTIVE:
 219         case VDEV_PROP_RESILVER_MAXACTIVE:
 220                 p = VDEV_PROP_TO_ZIO_PRIO_MAX(prop);
 221                 ASSERT(ZIO_PRIORITY_QUEUEABLE_VALID(p));
 222                 *oval = vqc[p].vqc_max_active;
 223                 break;
 224 
 225         case VDEV_PROP_PREFERRED_READ:
 226                 *oval = vd->vdev_queue.vq_preferred_read;
 227                 break;
 228 
 229         case VDEV_PROP_COS:
 230                 if (vd->vdev_queue.vq_cos != NULL) {
 231                         *value = vd->vdev_queue.vq_cos->cos_name;
 232                 } else {
 233                         *value = NULL;
 234                         return (spa_vdev_state_exit(spa, NULL, ENOENT));
 235                 }
 236                 break;
 237 
 238         case VDEV_PROP_SPAREGROUP:
 239                 if (vd->vdev_spare_group != NULL) {
 240                         *value = vd->vdev_spare_group;
 241                 } else {
 242                         *value = NULL;
 243                         return (spa_vdev_state_exit(spa, NULL, ENOENT));
 244                 }
 245                 break;
 246 
 247         default:
 248                 return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
 249         }
 250 
 251         return (spa_vdev_state_exit(spa, NULL, 0));
 252 }
 253 
 254 /*
 255  * Update the stored property for this vdev.
 256  */
 257 static int
 258 spa_vdev_set_common(vdev_t *vd, const char *value,
 259     uint64_t ival, vdev_prop_t prop)
 260 {
 261         spa_t *spa = vd->vdev_spa;
 262         cos_t *cos = NULL, *cos_to_release = NULL;
 263         boolean_t sync = B_FALSE;
 264         boolean_t reset_cos = B_FALSE;
 265         vdev_queue_class_t *vqc = vd->vdev_queue.vq_class;
 266         zio_priority_t p;
 267         int64_t ddt_devs_size;
 268         nvlist_t *nvp;
 269         int err;
 270         const char *propname = vdev_prop_to_name(prop);
 271 
 272         ASSERT(spa_writeable(spa));
 273 
 274         spa_vdev_state_enter(spa, SCL_ALL);
 275 
 276         if (!vd->vdev_ops->vdev_op_leaf)
 277                 return (spa_vdev_state_exit(spa, NULL, EINVAL));
 278 
 279         VERIFY0(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP));
 280         if (value == NULL)
 281                 VERIFY0(nvlist_add_uint64(nvp, propname, ival));
 282         else
 283                 VERIFY0(nvlist_add_string(nvp, propname, value));
 284         err = spa_vdev_prop_validate(spa, vd->vdev_guid, nvp);
 285         nvlist_free(nvp);
 286         if (err != 0)
 287                 return (spa_vdev_state_exit(spa, NULL, err));
 288 
 289         switch (prop) {
 290         case VDEV_PROP_L2ADDDT:
 291                 if (vd->vdev_l2ad_ddt != ival) {
 292                         vd->vdev_l2ad_ddt = ival;
 293                         ddt_devs_size = vdev_get_min_asize(vd);
 294                         if (ival == 0)
 295                                 ddt_devs_size *= -1;
 296                         atomic_add_64(&vd->vdev_spa->spa_l2arc_ddt_devs_size,
 297                             ddt_devs_size);
 298                         sync = B_TRUE;
 299                 }
 300                 break;
 301 
 302         case VDEV_PROP_PATH:
 303                 if (vd->vdev_path == NULL) {
 304                         vd->vdev_path = spa_strdup(value);
 305                         sync = B_TRUE;
 306                 } else if (strcmp(value, vd->vdev_path) != 0) {
 307                         spa_strfree(vd->vdev_path);
 308                         vd->vdev_path = spa_strdup(value);
 309                         sync = B_TRUE;
 310                 }
 311                 break;
 312 
 313         case VDEV_PROP_FRU:
 314                 if (vd->vdev_fru == NULL) {
 315                         vd->vdev_fru = spa_strdup(value);
 316                         sync = B_TRUE;
 317                 } else if (strcmp(value, vd->vdev_fru) != 0) {
 318                         spa_strfree(vd->vdev_fru);
 319                         vd->vdev_fru = spa_strdup(value);
 320                         sync = B_TRUE;
 321                 }
 322                 break;
 323 
 324         case VDEV_PROP_READ_MINACTIVE:
 325         case VDEV_PROP_AREAD_MINACTIVE:
 326         case VDEV_PROP_WRITE_MINACTIVE:
 327         case VDEV_PROP_AWRITE_MINACTIVE:
 328         case VDEV_PROP_SCRUB_MINACTIVE:
 329         case VDEV_PROP_RESILVER_MINACTIVE:
 330                 p = VDEV_PROP_TO_ZIO_PRIO_MIN(prop);
 331                 ASSERT(ZIO_PRIORITY_QUEUEABLE_VALID(p));
 332                 vqc[p].vqc_min_active = ival;
 333                 break;
 334 
 335         case VDEV_PROP_READ_MAXACTIVE:
 336         case VDEV_PROP_AREAD_MAXACTIVE:
 337         case VDEV_PROP_WRITE_MAXACTIVE:
 338         case VDEV_PROP_AWRITE_MAXACTIVE:
 339         case VDEV_PROP_SCRUB_MAXACTIVE:
 340         case VDEV_PROP_RESILVER_MAXACTIVE:
 341                 p = VDEV_PROP_TO_ZIO_PRIO_MAX(prop);
 342                 ASSERT(ZIO_PRIORITY_QUEUEABLE_VALID(p));
 343                 vqc[p].vqc_max_active = ival;
 344                 break;
 345 
 346         case VDEV_PROP_PREFERRED_READ:
 347                 vd->vdev_queue.vq_preferred_read = ival;
 348                 break;
 349 
 350         case VDEV_PROP_COS:
 351                 spa_cos_enter(spa);
 352 
 353                 if ((value == NULL || value[0] == '\0') && ival == 0) {
 354                         reset_cos = B_TRUE;
 355                 } else {
 356                         if (ival != 0)
 357                                 cos = spa_lookup_cos_by_guid(spa, ival);
 358                         else
 359                                 cos = spa_lookup_cos_by_name(spa, value);
 360                 }
 361 
 362                 if (!reset_cos && cos == NULL) {
 363                         spa_cos_exit(spa);
 364                         return (spa_vdev_state_exit(spa, NULL, ENOENT));
 365                 }
 366 
 367                 cos_to_release = vd->vdev_queue.vq_cos;
 368 
 369                 if (reset_cos) {
 370                         vd->vdev_queue.vq_cos = NULL;
 371                 } else {
 372                         cos_hold(cos);
 373                         vd->vdev_queue.vq_cos = cos;
 374                 }
 375 
 376                 if (cos_to_release)
 377                         cos_rele(cos_to_release);
 378 
 379                 spa_cos_exit(spa);
 380                 break;
 381 
 382         case VDEV_PROP_SPAREGROUP:
 383                 if (vd->vdev_spare_group == NULL) {
 384                         vd->vdev_spare_group = spa_strdup(value);
 385                         sync = B_TRUE;
 386                 } else if (strcmp(value, vd->vdev_spare_group) != 0) {
 387                         spa_strfree(vd->vdev_spare_group);
 388                         vd->vdev_spare_group = spa_strdup(value);
 389                         sync = B_TRUE;
 390                 }
 391                 break;
 392 
 393         case VDEV_PROP_GUID:
 394         default:
 395                 return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
 396         }
 397 
 398         return (spa_vdev_state_exit(spa, sync ? vd : NULL, 0));
 399 }
 400 
 401 /*
 402  * Set properties (names, values) in this nvlist, indicate if sync is needed
 403  */
 404 static int
 405 spa_vdev_prop_set_nosync(vdev_t *vd, nvlist_t *nvp, boolean_t *needsyncp)
 406 {
 407         int error = 0;
 408         nvpair_t *elem;
 409         vdev_prop_t prop;
 410         boolean_t need_sync = B_FALSE;
 411 
 412         elem = NULL;
 413         while ((elem = nvlist_next_nvpair(nvp, elem)) != NULL) {
 414                 uint64_t ival = 0;
 415                 char *strval = NULL;
 416                 zprop_type_t proptype;
 417                 if ((prop = vdev_name_to_prop(
 418                     nvpair_name(elem))) == ZPROP_INVAL)
 419                         return (ENOTSUP);
 420 
 421                 switch (prop) {
 422                 case VDEV_PROP_L2ADDDT:
 423                 case VDEV_PROP_READ_MINACTIVE:
 424                 case VDEV_PROP_READ_MAXACTIVE:
 425                 case VDEV_PROP_AREAD_MINACTIVE:
 426                 case VDEV_PROP_AREAD_MAXACTIVE:
 427                 case VDEV_PROP_WRITE_MINACTIVE:
 428                 case VDEV_PROP_WRITE_MAXACTIVE:
 429                 case VDEV_PROP_AWRITE_MINACTIVE:
 430                 case VDEV_PROP_AWRITE_MAXACTIVE:
 431                 case VDEV_PROP_SCRUB_MINACTIVE:
 432                 case VDEV_PROP_SCRUB_MAXACTIVE:
 433                 case VDEV_PROP_RESILVER_MAXACTIVE:
 434                 case VDEV_PROP_RESILVER_MINACTIVE:
 435                 case VDEV_PROP_PREFERRED_READ:
 436                 case VDEV_PROP_COS:
 437                 case VDEV_PROP_SPAREGROUP:
 438                         need_sync = B_TRUE;
 439                         break;
 440                 default:
 441                         need_sync = B_FALSE;
 442                 }
 443 
 444                 proptype = vdev_prop_get_type(prop);
 445 
 446                 switch (proptype) {
 447                 case PROP_TYPE_STRING:
 448                         VERIFY0(nvpair_value_string(elem, &strval));
 449                         break;
 450 
 451                 case PROP_TYPE_INDEX:
 452                 case PROP_TYPE_NUMBER:
 453                         if (proptype == PROP_TYPE_INDEX) {
 454                                 const char *unused;
 455                                 VERIFY0(vdev_prop_index_to_string(
 456                                     prop, ival, &unused));
 457                         }
 458                         VERIFY0(nvpair_value_uint64(elem, &ival));
 459                         break;
 460 
 461                 }
 462 
 463                 error = spa_vdev_set_common(vd, strval, ival, prop);
 464         }
 465 
 466         if (needsyncp != NULL)
 467                 *needsyncp = need_sync;
 468 
 469         return (error);
 470 }
 471 
 472 /*
 473  * Store properties of vdevs in the pool in the MOS of that pool
 474  */
 475 static void
 476 spa_vdev_sync_props(void *arg1, dmu_tx_t *tx)
 477 {
 478         spa_t *spa = (spa_t *)arg1;
 479         objset_t *mos = spa->spa_meta_objset;
 480         size_t size, nvsize;
 481         uint64_t *sizep;
 482         vdev_t *root_vdev;
 483         vdev_t *top_vdev;
 484         nvlist_t **nvl_array, *nvl;
 485         dmu_buf_t *db;
 486         char *buf;
 487         uint_t index = 0;
 488         uint_t vdev_cnt = vdev_count_leaf_vdevs(spa->spa_root_vdev) +
 489             spa->spa_l2cache.sav_count + spa->spa_spares.sav_count;
 490 
 491         VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP));
 492         nvl_array = kmem_alloc(vdev_cnt * sizeof (nvlist_t *), KM_SLEEP);
 493 
 494         for (int i = 0; i < vdev_cnt; i++)
 495                 VERIFY0(nvlist_alloc(&nvl_array[i], NV_UNIQUE_NAME, KM_SLEEP));
 496 
 497         mutex_enter(&spa->spa_vdev_props_lock);
 498 
 499         if (spa->spa_vdev_props_object == 0) {
 500                 VERIFY((spa->spa_vdev_props_object =
 501                     dmu_object_alloc(mos, DMU_OT_PACKED_NVLIST,
 502                     SPA_CONFIG_BLOCKSIZE, DMU_OT_PACKED_NVLIST_SIZE,
 503                     sizeof (uint64_t), tx)) > 0);
 504 
 505                 VERIFY0(zap_update(mos,
 506                     DMU_POOL_DIRECTORY_OBJECT,
 507                     DMU_POOL_VDEV_PROPS,
 508                     8, 1, &spa->spa_vdev_props_object, tx));
 509 
 510                 spa_feature_incr(spa, SPA_FEATURE_VDEV_PROPS, tx);
 511         }
 512 
 513         root_vdev = spa->spa_root_vdev;
 514         /* process regular vdevs */
 515         for (int c = 0; c < spa->spa_root_vdev->vdev_children; c++) {
 516                 top_vdev = root_vdev->vdev_child[c];
 517                 vdev_add_props(top_vdev, nvl_array, &index);
 518         }
 519 
 520         /* process aux vdevs */
 521         for (int i = 0; i < spa->spa_l2cache.sav_count; i++) {
 522                 vdev_t *vd = spa->spa_l2cache.sav_vdevs[i];
 523                 vdev_add_props(vd, nvl_array, &index);
 524         }
 525 
 526         for (int i = 0; i < spa->spa_spares.sav_count; i++) {
 527                 vdev_t *vd = spa->spa_spares.sav_vdevs[i];
 528                 vdev_add_props(vd, nvl_array, &index);
 529         }
 530         ASSERT3P(index, ==, vdev_cnt);
 531 
 532         VERIFY0(nvlist_add_nvlist_array(nvl,
 533             DMU_POOL_VDEV_PROPS, nvl_array, vdev_cnt));
 534 
 535         VERIFY0(nvlist_size(nvl, &nvsize, NV_ENCODE_XDR));
 536         size = P2ROUNDUP(nvsize, 8);
 537         buf = kmem_zalloc(size, KM_SLEEP);
 538         VERIFY0(nvlist_pack(nvl, &buf, &size, NV_ENCODE_XDR, KM_SLEEP));
 539 
 540         dmu_write(mos, spa->spa_vdev_props_object, 0, size, buf, tx);
 541 
 542         VERIFY0(dmu_bonus_hold(mos, spa->spa_vdev_props_object, FTAG, &db));
 543         dmu_buf_will_dirty(db, tx);
 544 
 545         sizep = db->db_data;
 546         *sizep = size;
 547 
 548         dmu_buf_rele(db, FTAG);
 549 
 550         kmem_free(buf, size);
 551 
 552         mutex_exit(&spa->spa_vdev_props_lock);
 553 
 554         for (int i = 0; i < vdev_cnt; i++)
 555                 nvlist_free(nvl_array[i]);
 556 
 557         kmem_free(nvl_array, vdev_cnt * sizeof (nvlist_t *));
 558         nvlist_free(nvl);
 559 }
 560 
 561 int
 562 spa_vdev_props_sync_task_do(spa_t *spa)
 563 {
 564         return (dsl_sync_task(spa->spa_name, NULL, spa_vdev_sync_props,
 565             spa, 3, ZFS_SPACE_CHECK_RESERVED));
 566 }
 567 
 568 /*
 569  * Load vdev properties from the vdev_props_object in the MOS
 570  */
 571 int
 572 spa_load_vdev_props(spa_t *spa)
 573 {
 574         objset_t *mos = spa->spa_meta_objset;
 575         vdev_t *vdev;
 576         dmu_buf_t *db;
 577         size_t bufsize = 0;
 578         char *buf;
 579         uint_t nelem;
 580         nvlist_t *nvl, **prop_array;
 581         uint64_t vdev_guid;
 582 
 583         ASSERT(spa);
 584 
 585         if (spa->spa_vdev_props_object == 0)
 586                 return (ENOENT);
 587 
 588         mutex_enter(&spa->spa_vdev_props_lock);
 589 
 590         VERIFY0(dmu_bonus_hold(mos, spa->spa_vdev_props_object, FTAG, &db));
 591         bufsize = *(uint64_t *)db->db_data;
 592         dmu_buf_rele(db, FTAG);
 593 
 594         if (bufsize == 0)
 595                 goto out;
 596 
 597         buf = kmem_alloc(bufsize, KM_SLEEP);
 598         VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP));
 599 
 600         /* read and unpack array of nvlists */
 601         VERIFY0(dmu_read(mos, spa->spa_vdev_props_object,
 602             0, bufsize, buf, DMU_READ_PREFETCH));
 603         VERIFY0(nvlist_unpack(buf, bufsize, &nvl, KM_SLEEP));
 604         VERIFY0(nvlist_lookup_nvlist_array(nvl,
 605             DMU_POOL_VDEV_PROPS, &prop_array, &nelem));
 606         for (uint_t i = 0; i < nelem; i++) {
 607                 VERIFY0(nvlist_lookup_uint64(prop_array[i],
 608                     vdev_prop_to_name(VDEV_PROP_GUID), &vdev_guid));
 609                 vdev = spa_lookup_by_guid(spa, vdev_guid, B_TRUE);
 610                 if (vdev == NULL)
 611                         continue;
 612                 vdev_parse_props(vdev, prop_array[i]);
 613         }
 614         nvlist_free(nvl);
 615 
 616 out:
 617         mutex_exit(&spa->spa_vdev_props_lock);
 618 
 619         return (0);
 620 }
 621 
 622 /*
 623  * Check properties (names, values) in this nvlist
 624  */
 625 int
 626 spa_vdev_prop_validate(spa_t *spa, uint64_t vdev_guid, nvlist_t *props)
 627 {
 628         nvpair_t *elem;
 629         int error = 0;
 630 
 631         if (!spa_feature_is_enabled(spa, SPA_FEATURE_VDEV_PROPS))
 632                 return (SET_ERROR(ENOTSUP));
 633 
 634         elem = NULL;
 635         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 636                 vdev_prop_t prop;
 637                 char *propname;
 638                 uint64_t ival;
 639 
 640                 propname = nvpair_name(elem);
 641 
 642                 if ((prop = vdev_name_to_prop(propname)) == ZPROP_INVAL)
 643                         return (SET_ERROR(EINVAL));
 644 
 645                 switch (prop) {
 646                 case VDEV_PROP_L2ADDDT:
 647                         if (!spa_l2cache_exists(vdev_guid, NULL)) {
 648                                 error = SET_ERROR(ENOTSUP);
 649                                 break;
 650                         }
 651                         error = nvpair_value_uint64(elem, &ival);
 652                         if (!error && ival != 1 && ival != 0)
 653                                 error = SET_ERROR(EINVAL);
 654                         break;
 655 
 656                 case VDEV_PROP_PATH:
 657                 case VDEV_PROP_GUID:
 658                 case VDEV_PROP_FRU:
 659                 case VDEV_PROP_COS:
 660                 case VDEV_PROP_SPAREGROUP:
 661                         break;
 662 
 663                 case VDEV_PROP_READ_MINACTIVE:
 664                 case VDEV_PROP_AREAD_MINACTIVE:
 665                 case VDEV_PROP_WRITE_MINACTIVE:
 666                 case VDEV_PROP_AWRITE_MINACTIVE:
 667                 case VDEV_PROP_SCRUB_MINACTIVE:
 668                 case VDEV_PROP_RESILVER_MINACTIVE:
 669                 case VDEV_PROP_READ_MAXACTIVE:
 670                 case VDEV_PROP_AREAD_MAXACTIVE:
 671                 case VDEV_PROP_WRITE_MAXACTIVE:
 672                 case VDEV_PROP_AWRITE_MAXACTIVE:
 673                 case VDEV_PROP_SCRUB_MAXACTIVE:
 674                 case VDEV_PROP_RESILVER_MAXACTIVE:
 675                         error = nvpair_value_uint64(elem, &ival);
 676                         if (!error && ival > 1000)
 677                                 error = SET_ERROR(EINVAL);
 678                         break;
 679 
 680                 case VDEV_PROP_PREFERRED_READ:
 681                         error = nvpair_value_uint64(elem, &ival);
 682                         if (!error && ival > 10)
 683                                 error = SET_ERROR(EINVAL);
 684                         break;
 685 
 686                 default:
 687                         error = SET_ERROR(EINVAL);
 688                 }
 689 
 690                 if (error)
 691                         break;
 692         }
 693 
 694         return (error);
 695 }
 696 
 697 /*
 698  * Set properties for the vdev and its children
 699  */
 700 int
 701 spa_vdev_prop_set(spa_t *spa, uint64_t vdev_guid, nvlist_t *nvp)
 702 {
 703         int error;
 704         vdev_t  *vd;
 705         boolean_t need_sync = B_FALSE;
 706 
 707         if ((error = spa_vdev_prop_validate(spa, vdev_guid, nvp)) != 0)
 708                 return (error);
 709 
 710         if ((vd = spa_lookup_by_guid(spa, vdev_guid, B_TRUE)) == NULL)
 711                 return (ENOENT);
 712 
 713         if (!vd->vdev_ops->vdev_op_leaf) {
 714                 int i;
 715                 for (i = 0; i < vd->vdev_children; i++) {
 716                         error = spa_vdev_prop_set(spa,
 717                             vd->vdev_child[i]->vdev_guid, nvp);
 718                         if (error != 0)
 719                                 break;
 720                 }
 721 
 722                 return (error);
 723         }
 724 
 725         if ((error = spa_vdev_prop_set_nosync(vd, nvp, &need_sync)) != 0)
 726                 return (error);
 727 
 728         if (need_sync)
 729                 return (spa_vdev_props_sync_task_do(spa));
 730 
 731         return (error);
 732 }
 733 
 734 /*
 735  * Get properties for the vdev, put them on nvlist
 736  */
 737 int
 738 spa_vdev_prop_get(spa_t *spa, uint64_t vdev_guid, nvlist_t **nvp)
 739 {
 740         int err;
 741         vdev_prop_t prop;
 742 
 743         VERIFY0(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP));
 744 
 745         for (prop = VDEV_PROP_PATH; prop < VDEV_NUM_PROPS; prop++) {
 746                 uint64_t ival;
 747                 char *strval = NULL;
 748                 const char *propname = vdev_prop_to_name(prop);
 749 
 750                 /* don't get L2ARC prop for non L2ARC dev, can't set anyway */
 751                 if (prop == VDEV_PROP_L2ADDDT &&
 752                     !spa_l2cache_exists(vdev_guid, NULL))
 753                         continue;
 754 
 755                 if ((err = spa_vdev_get_common(spa, vdev_guid, &strval,
 756                     &ival, prop)) != 0 && (err != ENOENT))
 757                         return (err);
 758 
 759                 if (strval != NULL) {
 760                         VERIFY0(nvlist_add_string(*nvp, propname, strval));
 761                 } else if (err != ENOENT) {
 762                         VERIFY0(nvlist_add_uint64(*nvp, propname, ival));
 763                 }
 764         }
 765 
 766         return (0);
 767 }
 768 
 769 int
 770 spa_vdev_setl2adddt(spa_t *spa, uint64_t guid, const char *newval)
 771 {
 772         vdev_t *vdev;
 773         uint64_t index;
 774 
 775         if ((vdev = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
 776                 return (SET_ERROR(ENOENT));
 777 
 778         if (vdev_prop_string_to_index(VDEV_PROP_L2ADDDT, newval, &index) != 0)
 779                 return (SET_ERROR(EINVAL));
 780 
 781         return (spa_vdev_set_common(vdev, NULL, index, VDEV_PROP_L2ADDDT));
 782 }
 783 
 784 int
 785 spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath)
 786 {
 787         vdev_t *vdev;
 788 
 789         if ((vdev = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
 790                 return (ENOENT);
 791 
 792         return (spa_vdev_set_common(vdev, newpath, 0, VDEV_PROP_PATH));
 793 }
 794 
 795 int
 796 spa_vdev_setfru(spa_t *spa, uint64_t guid, const char *newfru)
 797 {
 798         vdev_t *vdev;
 799 
 800         if ((vdev = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
 801                 return (ENOENT);
 802 
 803         return (spa_vdev_set_common(vdev, newfru, 0, VDEV_PROP_FRU));
 804 }