* Allocate a new vdev. The 'alloctype' is used to control whether we are * creating a new vdev or loading an existing one - the behavior is slightly * different for each case. */
| 639 | * different for each case. |
| 640 | */ |
| 641 | int |
| 642 | vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id, |
| 643 | int alloctype) |
| 644 | { |
| 645 | vdev_ops_t *ops; |
| 646 | char *type; |
| 647 | uint64_t guid = 0, islog; |
| 648 | vdev_t *vd; |
| 649 | vdev_indirect_config_t *vic; |
| 650 | char *tmp = NULL; |
| 651 | int rc; |
| 652 | vdev_alloc_bias_t alloc_bias = VDEV_BIAS_NONE; |
| 653 | boolean_t top_level = (parent && !parent->vdev_parent); |
| 654 | |
| 655 | ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL); |
| 656 | |
| 657 | if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) |
| 658 | return (SET_ERROR(EINVAL)); |
| 659 | |
| 660 | if ((ops = vdev_getops(type)) == NULL) |
| 661 | return (SET_ERROR(EINVAL)); |
| 662 | |
| 663 | /* |
| 664 | * If this is a load, get the vdev guid from the nvlist. |
| 665 | * Otherwise, vdev_alloc_common() will generate one for us. |
| 666 | */ |
| 667 | if (alloctype == VDEV_ALLOC_LOAD) { |
| 668 | uint64_t label_id; |
| 669 | |
| 670 | if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, &label_id) || |
| 671 | label_id != id) |
| 672 | return (SET_ERROR(EINVAL)); |
| 673 | |
| 674 | if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0) |
| 675 | return (SET_ERROR(EINVAL)); |
| 676 | } else if (alloctype == VDEV_ALLOC_SPARE) { |
| 677 | if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0) |
| 678 | return (SET_ERROR(EINVAL)); |
| 679 | } else if (alloctype == VDEV_ALLOC_L2CACHE) { |
| 680 | if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0) |
| 681 | return (SET_ERROR(EINVAL)); |
| 682 | } else if (alloctype == VDEV_ALLOC_ROOTPOOL) { |
| 683 | if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0) |
| 684 | return (SET_ERROR(EINVAL)); |
| 685 | } |
| 686 | |
| 687 | /* |
| 688 | * The first allocated vdev must be of type 'root'. |
| 689 | */ |
| 690 | if (ops != &vdev_root_ops && spa->spa_root_vdev == NULL) |
| 691 | return (SET_ERROR(EINVAL)); |
| 692 | |
| 693 | /* |
| 694 | * Determine whether we're a log vdev. |
| 695 | */ |
| 696 | islog = 0; |
| 697 | (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &islog); |
| 698 | if (islog && spa_version(spa) < SPA_VERSION_SLOGS) |
no test coverage detected