1 /* |
1 /* |
2 * CDDL HEADER START |
2 * CDDL HEADER START |
3 * |
3 * |
4 * The contents of this file are subject to the terms of the |
4 * The contents of this file are subject to the terms of the |
5 * Common Development and Distribution License, Version 1.0 only |
5 * Common Development and Distribution License (the "License"). |
6 * (the "License"). You may not use this file except in compliance |
6 * You may not use this file except in compliance with the License. |
7 * with the License. |
|
8 * |
7 * |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
10 * or http://www.opensolaris.org/os/licensing. |
9 * or http://www.opensolaris.org/os/licensing. |
11 * See the License for the specific language governing permissions |
10 * See the License for the specific language governing permissions |
12 * and limitations under the License. |
11 * and limitations under the License. |
359 vdev_t * |
358 vdev_t * |
360 vdev_alloc(spa_t *spa, nvlist_t *nv, vdev_t *parent, uint_t id, int alloctype) |
359 vdev_alloc(spa_t *spa, nvlist_t *nv, vdev_t *parent, uint_t id, int alloctype) |
361 { |
360 { |
362 vdev_ops_t *ops; |
361 vdev_ops_t *ops; |
363 char *type; |
362 char *type; |
364 uint64_t guid = 0; |
363 uint64_t guid = 0, offline = 0; |
365 vdev_t *vd; |
364 vdev_t *vd; |
366 |
365 |
367 ASSERT(spa_config_held(spa, RW_WRITER)); |
366 ASSERT(spa_config_held(spa, RW_WRITER)); |
368 |
367 |
369 if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) |
368 if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) |
415 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ASIZE, |
414 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ASIZE, |
416 &vd->vdev_asize); |
415 &vd->vdev_asize); |
417 } |
416 } |
418 |
417 |
419 /* |
418 /* |
420 * If we're a leaf vdev, try to load the DTL object. |
419 * If we're a leaf vdev, try to load the DTL object |
421 */ |
420 * and the offline state. |
|
421 */ |
|
422 vd->vdev_offline = B_FALSE; |
422 if (vd->vdev_ops->vdev_op_leaf && alloctype == VDEV_ALLOC_LOAD) { |
423 if (vd->vdev_ops->vdev_op_leaf && alloctype == VDEV_ALLOC_LOAD) { |
423 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_DTL, |
424 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_DTL, |
424 &vd->vdev_dtl.smo_object); |
425 &vd->vdev_dtl.smo_object); |
|
426 |
|
427 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &offline) |
|
428 == 0) |
|
429 vd->vdev_offline = offline; |
425 } |
430 } |
426 |
431 |
427 /* |
432 /* |
428 * Add ourselves to the parent's list of children. |
433 * Add ourselves to the parent's list of children. |
429 */ |
434 */ |
1339 } |
1344 } |
1340 |
1345 |
1341 int |
1346 int |
1342 vdev_online(spa_t *spa, const char *path) |
1347 vdev_online(spa_t *spa, const char *path) |
1343 { |
1348 { |
1344 vdev_t *vd; |
1349 vdev_t *rvd, *vd; |
1345 |
1350 uint64_t txg; |
1346 spa_config_enter(spa, RW_WRITER); |
1351 |
1347 |
1352 txg = spa_vdev_enter(spa); |
1348 if ((vd = vdev_lookup_by_path(spa->spa_root_vdev, path)) == NULL) { |
1353 |
1349 spa_config_exit(spa); |
1354 rvd = spa->spa_root_vdev; |
1350 return (ENODEV); |
1355 if ((vd = vdev_lookup_by_path(rvd, path)) == NULL) |
1351 } |
1356 return (spa_vdev_exit(spa, NULL, txg, ENODEV)); |
1352 |
1357 |
1353 dprintf("ONLINE: %s\n", vdev_description(vd)); |
1358 dprintf("ONLINE: %s\n", vdev_description(vd)); |
1354 |
1359 |
1355 vd->vdev_offline = B_FALSE; |
1360 vd->vdev_offline = B_FALSE; |
|
1361 vd->vdev_tmpoffline = B_FALSE; |
1356 |
1362 |
1357 /* |
1363 /* |
1358 * Clear the error counts. The idea is that you expect to see all |
1364 * Clear the error counts. The idea is that you expect to see all |
1359 * zeroes when everything is working, so if you've just onlined a |
1365 * zeroes when everything is working, so if you've just onlined a |
1360 * device, you don't want to keep hearing about errors from before. |
1366 * device, you don't want to keep hearing about errors from before. |
1363 vd->vdev_stat.vs_write_errors = 0; |
1369 vd->vdev_stat.vs_write_errors = 0; |
1364 vd->vdev_stat.vs_checksum_errors = 0; |
1370 vd->vdev_stat.vs_checksum_errors = 0; |
1365 |
1371 |
1366 vdev_reopen(vd->vdev_top, NULL); |
1372 vdev_reopen(vd->vdev_top, NULL); |
1367 |
1373 |
1368 spa_config_exit(spa); |
1374 spa_config_set(spa, spa_config_generate(spa, rvd, txg, 0)); |
|
1375 |
|
1376 vdev_config_dirty(vd->vdev_top); |
|
1377 |
|
1378 (void) spa_vdev_exit(spa, NULL, txg, 0); |
1369 |
1379 |
1370 VERIFY(spa_scrub(spa, POOL_SCRUB_RESILVER, B_TRUE) == 0); |
1380 VERIFY(spa_scrub(spa, POOL_SCRUB_RESILVER, B_TRUE) == 0); |
1371 |
1381 |
1372 return (0); |
1382 return (0); |
1373 } |
1383 } |
1374 |
1384 |
1375 int |
1385 int |
1376 vdev_offline(spa_t *spa, const char *path) |
1386 vdev_offline(spa_t *spa, const char *path, int istmp) |
1377 { |
1387 { |
1378 vdev_t *vd; |
1388 vdev_t *rvd, *vd; |
1379 |
1389 uint64_t txg; |
1380 spa_config_enter(spa, RW_WRITER); |
1390 |
1381 |
1391 txg = spa_vdev_enter(spa); |
1382 if ((vd = vdev_lookup_by_path(spa->spa_root_vdev, path)) == NULL) { |
1392 |
1383 spa_config_exit(spa); |
1393 rvd = spa->spa_root_vdev; |
1384 return (ENODEV); |
1394 if ((vd = vdev_lookup_by_path(rvd, path)) == NULL) |
1385 } |
1395 return (spa_vdev_exit(spa, NULL, txg, ENODEV)); |
1386 |
1396 |
1387 dprintf("OFFLINE: %s\n", vdev_description(vd)); |
1397 dprintf("OFFLINE: %s\n", vdev_description(vd)); |
|
1398 |
|
1399 /* vdev is already offlined, do nothing */ |
|
1400 if (vd->vdev_offline) |
|
1401 return (spa_vdev_exit(spa, NULL, txg, 0)); |
1388 |
1402 |
1389 /* |
1403 /* |
1390 * If this device's top-level vdev has a non-empty DTL, |
1404 * If this device's top-level vdev has a non-empty DTL, |
1391 * don't allow the device to be offlined. |
1405 * don't allow the device to be offlined. |
1392 * |
1406 * |
1393 * XXX -- we should make this more precise by allowing the offline |
1407 * XXX -- we should make this more precise by allowing the offline |
1394 * as long as the remaining devices don't have any DTL holes. |
1408 * as long as the remaining devices don't have any DTL holes. |
1395 */ |
1409 */ |
1396 if (vd->vdev_top->vdev_dtl_map.sm_space != 0) { |
1410 if (vd->vdev_top->vdev_dtl_map.sm_space != 0) |
1397 spa_config_exit(spa); |
1411 return (spa_vdev_exit(spa, NULL, txg, EBUSY)); |
1398 return (EBUSY); |
|
1399 } |
|
1400 |
1412 |
1401 /* |
1413 /* |
1402 * Set this device to offline state and reopen its top-level vdev. |
1414 * Set this device to offline state and reopen its top-level vdev. |
1403 * If this action results in the top-level vdev becoming unusable, |
1415 * If this action results in the top-level vdev becoming unusable, |
1404 * undo it and fail the request. |
1416 * undo it and fail the request. |
1406 vd->vdev_offline = B_TRUE; |
1418 vd->vdev_offline = B_TRUE; |
1407 vdev_reopen(vd->vdev_top, NULL); |
1419 vdev_reopen(vd->vdev_top, NULL); |
1408 if (vdev_is_dead(vd->vdev_top)) { |
1420 if (vdev_is_dead(vd->vdev_top)) { |
1409 vd->vdev_offline = B_FALSE; |
1421 vd->vdev_offline = B_FALSE; |
1410 vdev_reopen(vd->vdev_top, NULL); |
1422 vdev_reopen(vd->vdev_top, NULL); |
1411 spa_config_exit(spa); |
1423 return (spa_vdev_exit(spa, NULL, txg, EBUSY)); |
1412 return (EBUSY); |
1424 } |
1413 } |
1425 |
1414 |
1426 vd->vdev_tmpoffline = istmp; |
1415 spa_config_exit(spa); |
1427 if (istmp) |
1416 |
1428 return (spa_vdev_exit(spa, NULL, txg, 0)); |
1417 return (0); |
1429 |
|
1430 spa_config_set(spa, spa_config_generate(spa, rvd, txg, 0)); |
|
1431 |
|
1432 vdev_config_dirty(vd->vdev_top); |
|
1433 |
|
1434 return (spa_vdev_exit(spa, NULL, txg, 0)); |
1418 } |
1435 } |
1419 |
1436 |
1420 int |
1437 int |
1421 vdev_error_setup(spa_t *spa, const char *path, int mode, int mask, uint64_t arg) |
1438 vdev_error_setup(spa_t *spa, const char *path, int mode, int mask, uint64_t arg) |
1422 { |
1439 { |