/* 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; }
/* * 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; }
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; }
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; }
/* * 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; }
/* * 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; }
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; }
/* * 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; }
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, ¶ms); 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; }
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; }