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 }