Ejemplo n.º 1
0
/* Set default for linear segment specific LV parameters */
static void _lv_set_default_linear_params(struct cmd_context *cmd,
					  struct lvcreate_params *lp)
{
	lp->segtype = get_segtype_from_string(cmd, "striped");
	lp->stripes = 1;
	lp->stripe_size = DEFAULT_STRIPESIZE * 2;
}
Ejemplo n.º 2
0
/*
 * Normal snapshot or thinly-provisioned snapshot?
 */
static int _determine_snapshot_type(struct volume_group *vg,
				  struct lvcreate_params *lp)
{
	struct lv_list *lvl;

	if (!(lvl = find_lv_in_vg(vg, lp->origin))) {
		log_error("Snapshot origin LV %s not found in Volume group %s.",
			  lp->origin, vg->name);
		return 0;
	}

	if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) {
		if (!lv_is_thin_volume(lvl->lv)) {
			log_error("Please specify either size or extents with snapshots.");
			return 0;
		}

		lp->thin = 1;
		if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
			return_0;

		lp->pool = first_seg(lvl->lv)->pool_lv->name;
	}

	return 1;
}
Ejemplo n.º 3
0
int segtype_arg(struct cmd_context *cmd, struct arg *a)
{
        if (!(a->ptr = (void *) get_segtype_from_string(cmd, a->value)))
                return 0;

        return 1;
}
Ejemplo n.º 4
0
static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
{
	const struct segment_type *segtype;
	unsigned attr = 0;
	int found = 1;
	static int _clustered_found = -1;

	if (clustered && _clustered_found >= 0)
		return _clustered_found;

	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
		return_0;

	if (activation() && segtype->ops->target_present &&
	    !segtype->ops->target_present(cmd, NULL, clustered ? &attr : NULL))
		found = 0;

	if (activation() && clustered) {
		if (found && (attr & MIRROR_LOG_CLUSTERED))
			_clustered_found = found = 1;
		else
			_clustered_found = found = 0;
	}

	return found;
}
Ejemplo n.º 5
0
/*
 * Some kernels have a bug that they may leak space in the snapshot on crash.
 * If the kernel is buggy, we add some extra space.
 */
static uint64_t _cow_extra_chunks(struct cmd_context *cmd, uint64_t n_chunks)
{
	const struct segment_type *segtype;
	unsigned attrs = 0;

	if (activation() &&
	    (segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)) &&
	    segtype->ops->target_present &&
	    segtype->ops->target_present(cmd, NULL, &attrs) &&
	    (attrs & SNAPSHOT_FEATURE_FIXED_LEAK))
		return 0;

	return (n_chunks + 63) / 64;
}
Ejemplo n.º 6
0
/*
 * lv_cache_create
 * @pool
 * @origin
 *
 * Given a cache_pool and an origin, link the two and create a
 * cached LV.
 *
 * Returns: cache LV on success, NULL on failure
 */
struct logical_volume *lv_cache_create(struct logical_volume *pool,
				       struct logical_volume *origin)
{
	const struct segment_type *segtype;
	struct cmd_context *cmd = pool->vg->cmd;
	struct logical_volume *cache_lv;
	struct lv_segment *seg;

	if (!lv_is_cache_pool(pool)) {
		log_error(INTERNAL_ERROR
			  "%s is not a cache_pool LV", pool->name);
		return NULL;
	}

	if (!dm_list_empty(&pool->segs_using_this_lv)) {
		seg = get_only_segment_using_this_lv(pool);
		log_error("%s is already in use by %s",
			  pool->name, seg ? seg->lv->name : "another LV");
		return NULL;
	}

	if (lv_is_cache_type(origin)) {
		/*
		 * FIXME: We can layer caches, insert_layer_for_lv() would
		 * have to do a better job renaming the LVs in the stack
		 * first so that there isn't a name collision with <name>_corig.
		 * The origin under the origin would become *_corig_corig
		 * before renaming the origin above to *_corig.
		 */
		log_error(INTERNAL_ERROR
			  "The origin, %s, cannot be of cache type",
			  origin->name);
		return NULL;
	}

	if (!(segtype = get_segtype_from_string(cmd, "cache")))
		return_NULL;

	cache_lv = origin;
	if (!(origin = insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig")))
		return_NULL;

	seg = first_seg(cache_lv);
	seg->segtype = segtype;

	if (!attach_pool_lv(seg, pool, NULL, NULL))
		return_NULL;

	return cache_lv;
}
Ejemplo n.º 7
0
static struct lv_segment *_alloc_snapshot_seg(struct logical_volume *lv)
{
	struct lv_segment *seg;
	const struct segment_type *segtype;

	segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_SNAPSHOT);
	if (!segtype) {
		log_error("Failed to find snapshot segtype");
		return NULL;
	}

	if (!(seg = alloc_lv_segment(segtype, lv, 0, lv->le_count, 0, 0, 0,
				     NULL, 0, lv->le_count, 0, 0, 0, 0, NULL))) {
		log_error("Couldn't allocate new snapshot segment.");
		return NULL;
	}

	dm_list_add(&lv->segments, &seg->list);

	return seg;
}
Ejemplo n.º 8
0
/*
 * convert_vdo_pool_lv
 * @data_lv
 * @vtp
 * @virtual_extents
 *
 * Convert given data LV and its target parameters into a VDO LV with VDO pool.
 *
 * Returns: old data LV on success (passed data LV becomes VDO LV), NULL on failure
 */
struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
					   const struct dm_vdo_target_params *vtp,
					   uint32_t *virtual_extents)
{
	const uint64_t header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
	const uint32_t extent_size = data_lv->vg->extent_size;
	struct cmd_context *cmd = data_lv->vg->cmd;
	struct logical_volume *vdo_pool_lv = data_lv;
	const struct segment_type *vdo_pool_segtype;
	struct lv_segment *vdo_pool_seg;
	uint64_t vdo_logical_size = 0;
	uint64_t adjust;

	if (!(vdo_pool_segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_VDO_POOL)))
		return_NULL;

	adjust = (*virtual_extents * (uint64_t) extent_size) % DM_VDO_BLOCK_SIZE;
	if (adjust) {
		*virtual_extents += (DM_VDO_BLOCK_SIZE - adjust) / extent_size;
		log_print_unless_silent("Rounding size up to 4,00 KiB VDO logical extent boundary: %s.",
					display_size(data_lv->vg->cmd, *virtual_extents * (uint64_t) extent_size));
	}

	if (*virtual_extents)
		vdo_logical_size =
			_get_virtual_size(*virtual_extents, extent_size, header_size);

	if (!dm_vdo_validate_target_params(vtp, vdo_logical_size))
		return_0;

	/* Format data LV as VDO volume */
	if (!_format_vdo_pool_data_lv(data_lv, vtp, &vdo_logical_size)) {
		log_error("Cannot format VDO pool volume %s.", display_lvname(data_lv));
		return NULL;
	}

	if (!deactivate_lv(data_lv->vg->cmd, data_lv)) {
		log_error("Aborting. Manual intervention required.");
		return NULL;
	}

	vdo_logical_size -= 2 * header_size;

	if (vdo_logical_size < extent_size) {
		if (!*virtual_extents)
			/* User has not specified size and at least 1 extent is necessary */
			log_error("Cannot create fully fitting VDO volume, "
				  "--virtualsize has to be specified.");

		log_error("Size %s for VDO volume cannot be smaller then extent size %s.",
			  display_size(data_lv->vg->cmd, vdo_logical_size),
			  display_size(data_lv->vg->cmd, extent_size));
		return NULL;
	}

	*virtual_extents = vdo_logical_size / extent_size;

	/* Move segments from existing data_lv into LV_vdata */
	if (!(data_lv = insert_layer_for_lv(cmd, vdo_pool_lv, 0, "_vdata")))
		return_NULL;

	vdo_pool_seg = first_seg(vdo_pool_lv);
	vdo_pool_seg->segtype = vdo_pool_segtype;
	vdo_pool_seg->vdo_params = *vtp;
	vdo_pool_seg->vdo_pool_header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
	vdo_pool_seg->vdo_pool_virtual_extents = *virtual_extents;

	vdo_pool_lv->status |= LV_VDO_POOL;
	data_lv->status |= LV_VDO_POOL_DATA;

	return data_lv;
}
Ejemplo n.º 9
0
static int _percent_run(struct dev_manager *dm, const char *name,
			const char *dlid,
			const char *target_type, int wait,
			const struct logical_volume *lv, float *percent,
			percent_range_t *overall_percent_range,
			uint32_t *event_nr, int fail_if_percent_unsupported)
{
	int r = 0;
	struct dm_task *dmt;
	struct dm_info info;
	void *next = NULL;
	uint64_t start, length;
	char *type = NULL;
	char *params = NULL;
	const struct dm_list *segh = &lv->segments;
	struct lv_segment *seg = NULL;
	struct segment_type *segtype;
	percent_range_t percent_range = 0, combined_percent_range = 0;
	int first_time = 1;

	uint64_t total_numerator = 0, total_denominator = 0;

	*percent = -1;
	*overall_percent_range = PERCENT_INVALID;

	if (!(dmt = _setup_task(name, dlid, event_nr,
				wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0)))
		return_0;

	if (!dm_task_no_open_count(dmt))
		log_error("Failed to disable open_count");

	if (!dm_task_run(dmt))
		goto_out;

	if (!dm_task_get_info(dmt, &info) || !info.exists)
		goto_out;

	if (event_nr)
		*event_nr = info.event_nr;

	do {
		next = dm_get_next_target(dmt, next, &start, &length, &type,
					  &params);
		if (lv) {
			if (!(segh = dm_list_next(&lv->segments, segh))) {
				log_error("Number of segments in active LV %s "
					  "does not match metadata", lv->name);
				goto out;
			}
			seg = dm_list_item(segh, struct lv_segment);
		}

		if (!type || !params)
			continue;

		if (!(segtype = get_segtype_from_string(dm->cmd, target_type)))
			continue;

		if (strcmp(type, target_type)) {
			/* If kernel's type isn't an exact match is it compatible? */
			if (!segtype->ops->target_status_compatible ||
			    !segtype->ops->target_status_compatible(type))
				continue;
		}

		if (segtype->ops->target_percent &&
		    !segtype->ops->target_percent(&dm->target_state,
						  &percent_range, dm->mem,
						  dm->cmd, seg, params,
						  &total_numerator,
						  &total_denominator))
			goto_out;

		if (first_time) {
			combined_percent_range = percent_range;
			first_time = 0;
		} else
			combined_percent_range =
			    _combine_percent_ranges(combined_percent_range,
						    percent_range);
	} while (next);

	if (lv && (segh = dm_list_next(&lv->segments, segh))) {
		log_error("Number of segments in active LV %s does not "
			  "match metadata", lv->name);
		goto out;
	}

	if (total_denominator) {
		*percent = (float) total_numerator *100 / total_denominator;
		*overall_percent_range = combined_percent_range;
	} else {
		*percent = 100;
		if (first_time) {
			/* above ->target_percent() was not executed! */
			/* FIXME why return PERCENT_100 et. al. in this case? */
			*overall_percent_range = PERCENT_100;
			if (fail_if_percent_unsupported)
				goto_out;
		} else
			*overall_percent_range = combined_percent_range;
	}

	log_debug("LV percent: %f", *percent);
	r = 1;

      out:
	dm_task_destroy(dmt);
	return r;
}
Ejemplo n.º 10
0
static int _read_size_params(struct lvcreate_params *lp,
			     struct lvcreate_cmdline_params *lcp,
			     struct cmd_context *cmd)
{
	if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) {
		log_error("Please specify either size or extents (not both)");
		return 0;
	}

	if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) {
		log_error("Please specify either size or extents");
		return 0;
	}

	if (arg_count(cmd, extents_ARG)) {
		if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) {
			log_error("Negative number of extents is invalid");
			return 0;
		}
		lp->extents = arg_uint_value(cmd, extents_ARG, 0);
		lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
	}

	/* Size returned in kilobyte units; held in sectors */
	if (arg_count(cmd, size_ARG)) {
		if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) {
			log_error("Negative size is invalid");
			return 0;
		}
		lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0));
		lcp->percent = PERCENT_NONE;
	}

	/* If size/extents given with thin, then we are creating a thin pool */
	if (seg_is_thin(lp) && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG)))
		lp->create_pool = 1;

	if (!lp->create_pool && arg_count(cmd, poolmetadatasize_ARG)) {
		log_error("--poolmetadatasize may only be specified when allocating the pool.");
		return 0;
	}

	if (arg_count(cmd, virtualsize_ARG)) {
		if (seg_is_thin_pool(lp)) {
			log_error("Virtual size in incompatible with thin_pool segment type.");
			return 0;
		}
		if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) {
			log_error("Negative virtual origin size is invalid");
			return 0;
		}
		/* Size returned in kilobyte units; held in sectors */
		lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG,
						   UINT64_C(0));
		if (!lp->voriginsize) {
			log_error("Virtual origin size may not be zero");
			return 0;
		}
	} else {
		/* No virtual size given and no snapshot, so no thin LV to create. */
		if (seg_is_thin_volume(lp) && !lp->snapshot &&
		    !(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
			return_0;

		lp->thin = 0;
	}

	return 1;
}