Beispiel #1
0
/*
 * FUNCTION:	assemble_stripe(devconfig_t *request, dlist_t *comps,
 *			devconfig_t **stripe)
 *
 * INPUT:	request	- pointer to a devconfig_t of the current request
 *		comps	- pointer to a list of slice components
 *
 * OUPUT:	stripe	- pointer to a devconfig_t to hold final stripe
 *
 * RETURNS:	int	- 0 on success
 *			 !0 otherwise.
 *
 * PURPOSE:	Helper which creates and populates a stripe devconfig_t
 *		struct using information from the input request and the
 *		list of slice components.
 *
 *		Determines the name of the stripe either from the request
 *		or from the default naming scheme.
 *
 *		Sets the interlace for the stripe if a value is specified
 *		in the request.
 *
 *		Attaches the input list of components to the devconfig.
 */
static int
assemble_stripe(
	devconfig_t	*request,
	dlist_t		*comps,
	devconfig_t	**stripe)
{
	uint64_t ilace = 0;
	char	*name = NULL;
	int	error = 0;

	if ((error = new_devconfig(stripe, TYPE_STRIPE)) == 0) {
	    /* set stripe name, use requested name if specified */
	    if ((error = devconfig_get_name(request, &name)) != 0) {
		if (error != ERR_ATTR_UNSET) {
		    volume_set_error(gettext("error getting requested name\n"));
		} else {
		    error = 0;
		}
	    }

	    if (error == 0) {
		if (name == NULL) {
		    if ((error = get_next_volume_name(&name,
			TYPE_STRIPE)) == 0) {
			error = devconfig_set_name(*stripe, name);
			free(name);
		    }
		} else {
		    error = devconfig_set_name(*stripe, name);
		}
	    }
	}

	if (error == 0) {
	    if ((error = get_stripe_interlace(request, &ilace)) == 0) {
		error = devconfig_set_stripe_interlace(*stripe, ilace);
	    } else if (error == ENOENT) {
		ilace = get_default_stripe_interlace();
		error = 0;
	    }
	}

	if (error == 0) {
	    uint64_t	nbytes = 0;
	    if ((error = compute_usable_stripe_capacity(comps,
		ilace, &nbytes)) == 0) {
		error = devconfig_set_size_in_blocks(*stripe, nbytes/DEV_BSIZE);
	    }
	}

	if (error == 0) {
	    comps = order_stripe_components_alternate_hbas(comps);
	    devconfig_set_components(*stripe, comps);
	} else {
	    free_devconfig(*stripe);
	    *stripe = NULL;
	}

	return (error);
}
/*
 * Get the first component of the given type from the given disk set.
 * If not found, create the component if requested.
 *
 * @return      ENOENT
 *              if the given disk set does not exist, or it exists,
 *              but the requested component does not exist under it
 *              and its creation was not requested
 *
 * @return      0
 *              if the requested component exists or was created
 *
 * @return      non-zero
 *              if the requested component does not exist and could
 *              not be created
 */
static int
defaults_get_singleton_component(
	defaults_t *defaults,
	char *disksetname,
	component_type_t type,
	devconfig_t **component,
	boolean_t create)
{
	int error;
	devconfig_t *diskset;

	/* Get the disk set referred to */
	if ((error = defaults_get_diskset_by_name(
	    defaults, disksetname, &diskset)) != 0) {

	    volume_set_error(
		gettext("could not get defaults for disk set %s"),
		disksetname == NULL ? gettext("<NULL>") : disksetname);

	    return (error);
	}

	/*
	 * Get the singleton component under this disk set, create if
	 * requested
	 */
	return (devconfig_get_component(diskset, type, component, create));
}
Beispiel #3
0
/*
 * FUNCTION:	print_insufficient_resources_msg(char *type)
 *
 * PURPOSE:	Prints a message indicating that there are insufficient
 *		resources.
 *
 *		Also sets the metassist error string indicating why
 *		the metassist command failed.  The volume type is included
 *		for context in this message.
 */
void
print_insufficient_resources_msg(
	char *type)
{
	oprintf(OUTPUT_TERSE,
		gettext("  <-Failed: insufficient resources available\n"));

	volume_set_error(
		gettext("insufficient resources available to complete "
			"requested %s\n"),
		type);
}
Beispiel #4
0
/*
 * Set the named string in the given nvlist_t.
 *
 * @param       attrs
 *              the nvlist_t to search
 *
 * @param       which
 *              the string key for this element in the list
 *
 * @param       val
 *              the value to set
 *
 * @return      0
 *              if successful
 *
 * @return      EINVAL
 *              if there is an invalid argument
 *
 * @return      ENOMEM
 *              if there is insufficient memory
 */
int
set_string(
    nvlist_t *attrs,
    char *which,
    char *val)
{
    int error = 0;

    if ((error = nvlist_add_string(attrs, which, val)) != 0) {
        volume_set_error(
            gettext("nvlist_add_string(%s) failed: %d\n"), which, error);
    }

    return (error);
}
Beispiel #5
0
/*
 * Set the named uint64 in the given nvlist_t.
 *
 * @param       attrs
 *              the nvlist_t to search
 *
 * @param       which
 *              the string key for this element in the list
 *
 * @param       val
 *              the value to set
 *
 * @return      0
 *              if successful
 *
 * @return      EINVAL
 *              if there is an invalid argument
 *
 * @return      ENOMEM
 *              if there is insufficient memory
 */
int
set_uint64(
    nvlist_t *attrs,
    char *which,
    uint64_t val)
{
    int error = 0;

    if ((error = nvlist_add_uint64(attrs, which, val)) != 0) {
        volume_set_error(
            gettext("nvlist_add_int64(%s) failed: %d\n"), which, error);
    }

    return (error);
}
Beispiel #6
0
/*
 * Set the named string array from the given nvlist_t.
 *
 * @param       attrs
 *              the nvlist_t to search
 *
 * @param       which
 *              the string key for this element in the list
 *
 * @param       val
 *              the value of the requested string array
 *
 * @param       nelem
 *              the number of elements in the array
 *
 * @return      0
 *              if successful
 *
 * @return      EINVAL
 *              if there is an invalid argument
 *
 * @return      ENOMEM
 *              if there is insufficient memory
 */
int
set_string_array(
    nvlist_t *attrs,
    char *which,
    char **val,
    uint_t nelem)
{
    int error = 0;

    if ((error = nvlist_add_string_array(
                     attrs, which, val, nelem)) != 0) {
        volume_set_error(
            gettext("nvlist_add_string_array(%s) failed: %d.\n"),
            which, error);
    }

    return (error);
}
Beispiel #7
0
/*
 * FUNCTION:	layout_stripe(devconfig_t *request, uint64_t nbytes,
 *			dlist_t **results)
 *
 * INPUT:	request	- pointer to a devconfig_t of the current request
 *		nbytes	- the desired capacity of the stripe
 *
 * OUPUT:	results	- pointer to a list of composed volumes
 *
 * RETURNS:	int	- 0 on success
 *			 !0 otherwise.
 *
 * PURPOSE:	Main layout driver for composing stripe volumes.
 *
 *		Attempts to construct a stripe of size nbytes.
 *
 *		Basic goal of all strategies is to build wide-thin stripes:
 *		build widest stripe possible across as many HBAs as possible.
 *
 *		Several different layout strategies are tried in order
 *		of preference until one succeeds or there are none left.
 *
 *		1 - stripe across similar HBAs
 *		    . number of components is driven by # of HBAs
 *		    . requires mincomp available HBAs
 *
 *		2 - stripe within a single HBA
 *		    . number of components is driven by # of disks
 *		    . requires at least 1 HBA with mincomp disks
 *
 *		3 - stripe across all available disks on similar HBAs
 *		    . number of components is driven by # of disk
 *		    . requires at least mincomp disks
 *
 *		4 - stripe across all available HBAs
 *		    . number of components is driven by # of HBAs
 *		    . requires at least mincomp HBAs
 *
 *		5 - stripe across all available disks on all HBAs
 *		    . number of components is driven by # of disks
 *		    . requires at least mincomp disks
 *
 *		Each strategy tries to compose a stripe with the
 *		maximum number of components first then reduces the
 *		number of components down to mincomp.
 *
 *		get allowed minimum number of stripe components
 *		get allowed maximum number of stripe components
 *		get available HBAs
 *
 *		group HBAs by characteristics
 *		for (each HBA grouping) and (stripe not composed) {
 *		    select next HBA group
 *		    for (strategy[1,2,3]) and (stripe not composed) {
 *			compose stripe using HBAs in group
 *		    }
 *		}
 *
 *		if (stripe not composed) {
 *		    for (strategy[4,5]) and (stripe not composed) {
 *			compose stripe using all HBAs
 *		    }
 *		}
 *
 *		if (stripe composed) {
 *		    append composed stripe to results
 *		}
 *
 */
int
layout_stripe(
	devconfig_t	*request,
	uint64_t	nbytes,
	dlist_t		**results)
{
	/*
	 * these enums define the # of strategies and the preference order
	 * in which they are tried
	 */
	typedef enum {
		STRIPE_ACROSS_SIMILAR_HBAS_DISK_PER = 0,
		STRIPE_WITHIN_SIMILAR_HBA,
		STRIPE_ACROSS_SIMILAR_HBAS,
		N_SIMILAR_HBA_STRATEGIES
	} similar_hba_strategy_order_t;

	typedef enum {
		STRIPE_ACROSS_ANY_HBAS_DISK_PER = 0,
		STRIPE_ACROSS_ANY_HBAS,
		N_ANY_HBA_STRATEGIES
	} any_hba_strategy_order_t;


	dlist_t		*usable_hbas = NULL;
	dlist_t		*similar_hba_groups = NULL;
	dlist_t		*iter = NULL;
	devconfig_t	*stripe = NULL;

	uint16_t	mincomp	= 0;
	uint16_t	maxcomp	= 0;

	int		error = 0;

	(error = get_usable_hbas(&usable_hbas));
	if (error != 0) {
	    return (error);
	}

	print_layout_volume_msg(devconfig_type_to_str(TYPE_STRIPE), nbytes);

	if (dlist_length(usable_hbas) == 0) {
	    print_no_hbas_msg();
	    volume_set_error(gettext("There are no usable HBAs."));
	    return (-1);
	}

	((error = group_similar_hbas(usable_hbas, &similar_hba_groups)) != 0) ||

	/*
	 * determine the min/max number of stripe components
	 * based on the request, the diskset defaults or the
	 * global defaults.  These are absolute limits, the
	 * actual values are determined by the number of HBAs
	 * and/or disks available.
	 */
	(error = get_stripe_min_comp(request, &mincomp)) ||
	(error = get_stripe_max_comp(request, &maxcomp));
	if (error != 0) {
	    return (error);
	}

	for (iter = similar_hba_groups;
	    (error == 0) && (stripe == NULL) && (iter != NULL);
	    iter = iter->next) {

	    dlist_t *hbas = (dlist_t *)iter->obj;

	    similar_hba_strategy_order_t order;

	    for (order = STRIPE_ACROSS_SIMILAR_HBAS_DISK_PER;
		(order < N_SIMILAR_HBA_STRATEGIES) &&
			(stripe == NULL) && (error == 0);
		order++) {

		dlist_t *selhbas = NULL;
		dlist_t	*disks = NULL;
		int	n = 0;

		switch (order) {

		case STRIPE_ACROSS_SIMILAR_HBAS_DISK_PER:

		    error = select_hbas_with_n_disks(
			    request, hbas, 1, &selhbas, &disks);

		    if (error == 0) {

/* BEGIN CSTYLED */
oprintf(OUTPUT_TERSE,
gettext("  -->Strategy 1: use 1 disk from %d-%d similar HBAs - stripe across HBAs\n"),
	mincomp, maxcomp);
/* END CSTYLED */

			if ((n = dlist_length(selhbas)) >= mincomp) {
			    n = ((n > maxcomp) ? maxcomp : n);
			    error = compose_stripe(
				    request, nbytes, disks, n,
				    mincomp, NULL, &stripe);
			} else {
			    print_insufficient_hbas_msg(n);
			}
		    }

		    break;

		case STRIPE_WITHIN_SIMILAR_HBA:

		    error = select_hbas_with_n_disks(
			    request, hbas, mincomp, &selhbas, &disks);

		    if (error == 0) {

/* BEGIN CSTYLED */
oprintf(OUTPUT_TERSE,
gettext("  -->Strategy 2: use %d-%d disks from any single HBA - stripe within HBA\n"),
	mincomp, maxcomp);
/* END CSTYLED */

			if ((n = dlist_length(selhbas)) > 0) {
			    error = compose_stripe_within_hba(
				    request, selhbas, nbytes,
				    mincomp, maxcomp, &stripe);
			} else {
			    print_insufficient_disks_msg(n);
			}
		    }

		    break;

		case STRIPE_ACROSS_SIMILAR_HBAS:

		    error = select_hbas_with_n_disks(
			    request, hbas, 1, &selhbas, &disks);

		    if (error == 0) {

/* BEGIN CSTYLED */
oprintf(OUTPUT_TERSE,
gettext("  -->Strategy 3: use %d-%d disks from %d similar HBAs - stripe across HBAs\n"),
	mincomp, maxcomp, dlist_length(hbas));
/* END CSTYLED */

			if ((n = dlist_length(selhbas)) > 0) {
			    if ((n = dlist_length(disks)) >= mincomp) {
				n = ((n > maxcomp) ? maxcomp : n);
				error = compose_stripe(
					request, nbytes, disks, n,
					mincomp, NULL, &stripe);
			    } else {
				print_insufficient_disks_msg(n);
			    }
			} else {
			    print_insufficient_hbas_msg(n);
			}
		    }

		    break;

		default:
		    break;
		}

		dlist_free_items(disks, NULL);
		dlist_free_items(selhbas, NULL);
	    }
	}

	for (iter = similar_hba_groups; iter != NULL; iter = iter->next) {
	    dlist_free_items((dlist_t *)iter->obj, NULL);
	}
	dlist_free_items(similar_hba_groups, NULL);

	/*
	 * if striping within similar HBA groups failed,
	 * try across all available HBAs
	 */
	if ((stripe == NULL) && (error == 0)) {

	    any_hba_strategy_order_t order;

	    for (order = STRIPE_ACROSS_ANY_HBAS_DISK_PER;
		(order < N_ANY_HBA_STRATEGIES) &&
			(stripe == NULL) && (error == 0);
		order++) {

		dlist_t	*selhbas = NULL;
		dlist_t	*disks = NULL;
		int	n = 0;

		switch (order) {

		case STRIPE_ACROSS_ANY_HBAS_DISK_PER:

		    error = select_hbas_with_n_disks(
			    request, usable_hbas, 1, &selhbas, &disks);

		    if (error == 0) {

/* BEGIN CSTYLED */
oprintf(OUTPUT_TERSE,
gettext("  -->Strategy 4: use 1 disk from %d-%d available HBAs - stripe across any HBAs\n"),
	mincomp, maxcomp);
/* END CSTYLED */

			if ((n = dlist_length(selhbas)) >= mincomp) {

			    n = ((n > maxcomp) ? maxcomp : n);
			    error = compose_stripe(
				    request, nbytes, disks, n,
				    mincomp, NULL, &stripe);

			} else {
			    print_insufficient_hbas_msg(n);
			}
		    }

		    break;

		case STRIPE_ACROSS_ANY_HBAS:

		    error = select_hbas_with_n_disks(
			    request, usable_hbas, 1, &selhbas, &disks);

		    if (error == 0) {

/* BEGIN CSTYLED */
oprintf(OUTPUT_TERSE,
gettext("  -->Strategy 5: use %d-%d disks from %d available HBA - stripe across any HBAs\n"),
	mincomp, maxcomp, dlist_length(selhbas));
/* END CSTYLED */

			if ((n = dlist_length(disks)) >= mincomp) {

			    n = ((n > maxcomp) ? maxcomp : n);
			    error = compose_stripe(
				    request, nbytes, disks, n,
				    mincomp, NULL, &stripe);

			} else {
			    print_insufficient_disks_msg(n);
			}
		    }

		    break;
		}

		dlist_free_items(disks, NULL);
		dlist_free_items(selhbas, NULL);
	    }
	}

	if (stripe != NULL) {

	    dlist_t *item = NULL;
	    if ((item = dlist_new_item(stripe)) == NULL) {
		error = ENOMEM;
	    } else {
		*results = dlist_append(item, *results, AT_TAIL);
		print_layout_success_msg();
	    }

	} else if (error != 0) {

	    print_debug_failure_msg(
		    devconfig_type_to_str(TYPE_STRIPE),
		    get_error_string(error));

	} else {

	    print_insufficient_resources_msg(
		    devconfig_type_to_str(TYPE_STRIPE));
	    error = -1;
	}

	return (error);
}
/*
 * Constructor: Create a defaults_t struct populated with default
 * values. This defaults_t must be freed.
 *
 * @param       defaults
 *              RETURN: a pointer to a new defaults_t
 *
 * @return      0
 *              if successful
 *
 * @return      non-zero
 *              if an error occurred.  Use get_error_string() to
 *              retrieve the associated error message.
 */
int
new_defaults(
	defaults_t **defaults)
{
	devconfig_t *diskset;
	int error = 0;

	*defaults = (defaults_t *)calloc(1, sizeof (defaults_t));
	if (*defaults == NULL) {
	    volume_set_error(gettext("new_defaults calloc() failed"));
	    return (-1);
	}

	/*
	 * Create initial "global" (disk set-independent) defaults, as
	 * a devconfig_t of type disk set with NULL name
	 */
	if ((error = new_devconfig(&diskset, TYPE_DISKSET)) != 0) {
	    free_defaults(*defaults);
	    return (error);
	}

	/* Append global defaults disk set to disksets */
	defaults_set_disksets(
	    *defaults, dlist_append(dlist_new_item(diskset),
	    defaults_get_disksets(*defaults), AT_TAIL));

	/* Set defaults */
	if ((error = defaults_set_mirror_nsubs(
		*defaults, NULL, DEFAULT_MIRROR_NSUBS)) != 0 ||

	    (error = defaults_set_mirror_read(
		*defaults, NULL, DEFAULT_MIRROR_READ)) != 0 ||

	    (error = defaults_set_mirror_write(
		*defaults, NULL, DEFAULT_MIRROR_WRITE)) != 0 ||

	    (error = defaults_set_mirror_pass(
		*defaults, NULL, DEFAULT_MIRROR_PASS)) != 0 ||

	    (error = defaults_set_mirror_usehsp(
		*defaults, NULL, DEFAULT_MIRROR_USEHSP)) != 0 ||

	    (error = defaults_set_concat_usehsp(
		*defaults, NULL, DEFAULT_CONCAT_USEHSP)) != 0 ||

	    (error = defaults_set_stripe_interlace(
		*defaults, NULL, DEFAULT_STRIPE_INTERLACE)) != 0 ||

	    (error = defaults_set_stripe_mincomp(
		*defaults, NULL, DEFAULT_STRIPE_MINCOMP)) != 0 ||

	    (error = defaults_set_stripe_maxcomp(
		*defaults, NULL, DEFAULT_STRIPE_MAXCOMP)) != 0 ||

	    (error = defaults_set_stripe_usehsp(
		*defaults, NULL, DEFAULT_STRIPE_USEHSP)) != 0 ||

	    (error = defaults_set_volume_redundancy_level(
		*defaults, NULL, DEFAULT_VOLUME_REDUND_LEVEL)) != 0 ||

	    (error = defaults_set_volume_npaths(
		*defaults, NULL, DEFAULT_VOLUME_NPATHS)) != 0 ||

	    (error = defaults_set_volume_usehsp(
		*defaults, NULL, DEFAULT_VOLUME_USEHSP)) != 0) {

	    free_defaults(*defaults);
	    return (error);
	}

	return (0);
}