diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c index a44bba897..80214c9b7 100644 --- a/lib/metadata/cache_manip.c +++ b/lib/metadata/cache_manip.c @@ -89,6 +89,63 @@ int update_cache_pool_params(struct volume_group *vg, unsigned attr, return 1; } +/* + * Validate arguments for converting origin into cached volume with given cache pool. + * + * Always validates origin_lv, and when it is known also cache pool_lv + */ +int validate_lv_cache_create(const struct logical_volume *pool_lv, + const struct logical_volume *origin_lv) +{ + struct lv_segment *seg; + + if (pool_lv) { + if (!lv_is_cache_pool(pool_lv)) { + log_error("Logical volume %s is not a cache pool.", + display_lvname(pool_lv)); + return 0; + } + + if (origin_lv == pool_lv) { + log_error("Can't use same LV %s for cache pool and cache volume.", + display_lvname(pool_lv)); + return 0; + } + + if (!dm_list_empty(&pool_lv->segs_using_this_lv)) { + seg = get_only_segment_using_this_lv(pool_lv); + log_error("Logical volume %s is already in use by %s", + display_lvname(pool_lv), + seg ? display_lvname(seg->lv) : "another LV"); + return 0; + } + } + + /* For now we only support conversion of thin pool data volume */ + if (!lv_is_visible(origin_lv) && !lv_is_thin_pool_data(origin_lv)) { + log_error("Can't convert internal LV %s.", display_lvname(origin_lv)); + return 0; + } + + /* + * Only linear, striped or raid supported. + * FIXME Tidy up all these type restrictions. + */ + if (lv_is_cache_type(origin_lv) || + lv_is_mirror_type(origin_lv) || + lv_is_thin_volume(origin_lv) || lv_is_thin_pool_metadata(origin_lv) || + lv_is_origin(origin_lv) || lv_is_merging_origin(origin_lv) || + lv_is_cow(origin_lv) || lv_is_merging_cow(origin_lv) || + lv_is_external_origin(origin_lv) || + lv_is_virtual(origin_lv)) { + log_error("Cache is not supported with origin LV %s type.", + display_lvname(origin_lv)); + return 0; + } + + return 1; +} + /* * lv_cache_create * @pool @@ -99,57 +156,32 @@ int update_cache_pool_params(struct volume_group *vg, unsigned attr, * * Returns: cache LV on success, NULL on failure */ -struct logical_volume *lv_cache_create(struct logical_volume *pool, - struct logical_volume *origin) +struct logical_volume *lv_cache_create(struct logical_volume *pool_lv, + struct logical_volume *origin_lv) { const struct segment_type *segtype; - struct cmd_context *cmd = pool->vg->cmd; - struct logical_volume *cache_lv; + struct cmd_context *cmd = pool_lv->vg->cmd; + struct logical_volume *cache_lv = origin_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 _corig. - * The origin under the origin would become *_corig_corig - * before renaming the origin above to *_corig. - */ - log_error("Creating a cache LV from an existing cache LV is" - "not yet supported."); - return NULL; - } + if (!validate_lv_cache_create(pool_lv, origin_lv)) + 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"))) + if (!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)) + if (!attach_pool_lv(seg, pool_lv, NULL, NULL)) return_NULL; return cache_lv; } - /* * Cleanup orphan device in the table with temporary activation * since in the suspend() we can't deactivate unused nodes diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index b392bde99..d04d98721 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -1074,6 +1074,8 @@ int update_cache_pool_params(struct volume_group *vg, unsigned attr, int passed_args, uint32_t data_extents, uint64_t *pool_metadata_size, int *chunk_size_calc_method, uint32_t *chunk_size); +int validate_lv_cache_create(const struct logical_volume *pool_lv, + const struct logical_volume *origin_lv); struct logical_volume *lv_cache_create(struct logical_volume *pool, struct logical_volume *origin); int lv_cache_remove(struct logical_volume *cache_lv);