mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
cache: api update
Change logic and naming of some internal API functions. cache_set_mode() and cache_set_policy() both take segment. cache mode is now correctly 'masked-in'. If the passed segment is 'cache' segment - it will automatically try to find 'defaults' according to profiles if the are NOT specified on command line or they are NOT already set for cache-pool. These defaults are never set for cache-pool.
This commit is contained in:
parent
22a1337a9b
commit
f0c18fceb4
@ -1,5 +1,6 @@
|
||||
Version 2.02.128 -
|
||||
===================================
|
||||
Enhance internal API cache_set_mode() and cache_set_policy().
|
||||
Enhance toollib's get_cache_params().
|
||||
Runtime detect presence of cache smq policy.
|
||||
Add demo cache-mq and cache-smq profiles.
|
||||
|
@ -71,23 +71,15 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
if (dm_config_has_node(sn, "cache_mode")) {
|
||||
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
|
||||
return SEG_LOG_ERROR("cache_mode must be a string in");
|
||||
if (!set_cache_pool_feature(&seg->feature_flags, str))
|
||||
if (!cache_set_mode(seg, str))
|
||||
return SEG_LOG_ERROR("Unknown cache_mode in");
|
||||
} else
|
||||
/* When missed in metadata, it's an old stuff - use writethrough */
|
||||
seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "policy")) {
|
||||
if (!(str = dm_config_find_str(sn, "policy", NULL)))
|
||||
return SEG_LOG_ERROR("policy must be a string in");
|
||||
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
|
||||
return SEG_LOG_ERROR("Failed to duplicate policy in");
|
||||
} else {
|
||||
/* Cannot use 'just' default, so pick one */
|
||||
seg->policy_name = DEFAULT_CACHE_POLICY; /* FIXME make configurable */
|
||||
/* FIXME maybe here should be always 'mq' */
|
||||
log_warn("WARNING: cache_policy undefined, using default \"%s\" policy.",
|
||||
seg->policy_name);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -136,28 +128,33 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
|
||||
{
|
||||
const char *cache_mode;
|
||||
|
||||
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
|
||||
return_0;
|
||||
|
||||
if (!seg->policy_name) {
|
||||
log_error(INTERNAL_ERROR "Policy name for %s is not defined.",
|
||||
display_lvname(seg->lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
|
||||
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
|
||||
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
/*
|
||||
* Cache pool used by a cache LV holds data. Not ideal,
|
||||
* but not worth to break backward compatibility, by shifting
|
||||
* content to cache segment
|
||||
*/
|
||||
if (cache_mode_is_set(seg)) {
|
||||
if (!(cache_mode = get_cache_mode_name(seg)))
|
||||
return_0;
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
}
|
||||
|
||||
if (seg->policy_name) {
|
||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
}
|
||||
if (seg->policy_settings->child)
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -29,7 +29,17 @@
|
||||
#define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
|
||||
#define DM_MAX_HINT_WIDTH (4+16) /* bytes. FIXME Configurable? */
|
||||
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
int cache_mode_is_set(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
return (seg->feature_flags & (DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH)) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *get_cache_mode_name(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
|
||||
return "writeback";
|
||||
@ -46,19 +56,48 @@ const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str)
|
||||
int cache_set_mode(struct lv_segment *seg, const char *str)
|
||||
{
|
||||
struct cmd_context *cmd = seg->lv->vg->cmd;
|
||||
int id;
|
||||
uint64_t mode;
|
||||
|
||||
if (!str && !seg_is_cache(seg))
|
||||
return 1; /* Defaults only for cache */
|
||||
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (!str) {
|
||||
if (cache_mode_is_set(seg))
|
||||
return 1; /* Default already set in cache pool */
|
||||
|
||||
id = allocation_cache_mode_CFG;
|
||||
|
||||
/* If present, check backward compatible settings */
|
||||
if (!find_config_node(cmd, cmd->cft, id) &&
|
||||
find_config_node(cmd, cmd->cft, allocation_cache_pool_cachemode_CFG))
|
||||
id = allocation_cache_pool_cachemode_CFG;
|
||||
|
||||
str = find_config_tree_str(cmd, id, NULL);
|
||||
}
|
||||
|
||||
if (!strcmp(str, "writeback"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
mode = DM_CACHE_FEATURE_WRITEBACK;
|
||||
else if (!strcmp(str, "writethrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passhrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
mode = DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passthrough"))
|
||||
mode = DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
else {
|
||||
log_error("Cache pool feature \"%s\" is unknown.", str);
|
||||
log_error("Cannot set unknown cache mode \"%s\".", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->feature_flags &= ~(DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH);
|
||||
seg->feature_flags |= mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -395,36 +434,72 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
|
||||
}
|
||||
|
||||
int lv_cache_set_policy(struct logical_volume *lv, const char *name,
|
||||
const struct dm_config_tree *settings)
|
||||
int cache_set_policy(struct lv_segment *seg, const char *name,
|
||||
const struct dm_config_tree *settings)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
const struct dm_config_node *cns;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
const int passed_seg_is_cache = seg_is_cache(seg);
|
||||
|
||||
if (lv_is_cache(lv))
|
||||
if (passed_seg_is_cache)
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = settings->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
if (name) {
|
||||
if (!(seg->policy_name = dm_pool_strdup(seg->lv->vg->vgmem, name))) {
|
||||
log_error("Failed to duplicate policy name.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!seg->policy_name && passed_seg_is_cache)
|
||||
seg->policy_name = find_config_tree_str(seg->lv->vg->cmd, allocation_cache_policy_CFG, NULL);
|
||||
|
||||
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
if (settings) {
|
||||
if (!seg->policy_name) {
|
||||
log_error(INTERNAL_ERROR "Can't set policy settings without policy name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name && !(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name))) {
|
||||
log_error("Failed to duplicate policy name.");
|
||||
goto out;
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = settings->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
} else if (passed_seg_is_cache && /* Look for command's profile cache_policies */
|
||||
(cns = find_config_tree_node(seg->lv->vg->cmd, allocation_cache_settings_CFG_SECTION, NULL))) {
|
||||
/* Try to find our section for given policy */
|
||||
for (cn = cns->child; cn; cn = cn->sib) {
|
||||
/* Only matching section names */
|
||||
if (cn->v || strcmp(cn->key, seg->policy_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!cn->child)
|
||||
break;
|
||||
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
|
||||
if (!(new->root = dm_config_clone_node_with_mem(new->mem,
|
||||
cn->child, 1)))
|
||||
goto_out;
|
||||
|
||||
if (!(seg->policy_settings = dm_config_create_node(new, "policy_settings")))
|
||||
goto_out;
|
||||
|
||||
seg->policy_settings->child = new->root;
|
||||
|
||||
break; /* Only first match counts */
|
||||
}
|
||||
}
|
||||
|
||||
restart: /* remove any 'default" nodes */
|
||||
|
@ -131,7 +131,7 @@ char *lvseg_discards_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
|
||||
char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
const char *name = get_cache_pool_cachemode_name(seg);
|
||||
const char *name = get_cache_mode_name(seg);
|
||||
|
||||
if (!name)
|
||||
return_NULL;
|
||||
|
@ -7264,17 +7264,26 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
memlock_unlock(vg->cmd);
|
||||
|
||||
if (seg_is_cache_pool(lp) || seg_is_cache(lp)) {
|
||||
pool_lv = pool_lv ? : lv;
|
||||
if (!lv_cache_set_policy(pool_lv, lp->policy_name, lp->policy_settings))
|
||||
return_NULL; /* revert? */
|
||||
first_seg(pool_lv)->chunk_size = lp->chunk_size;
|
||||
first_seg(pool_lv)->feature_flags = lp->feature_flags;
|
||||
/* TODO: some calc_policy solution for cache ? */
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
|
||||
THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
|
||||
if (!cache_set_mode(first_seg(lv), lp->cache_mode)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
pool_lv = pool_lv ? : lv;
|
||||
if (lp->chunk_size) {
|
||||
first_seg(pool_lv)->chunk_size = lp->chunk_size;
|
||||
/* TODO: some calc_policy solution for cache ? */
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
|
||||
THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
}
|
||||
} else if (seg_is_raid(lp)) {
|
||||
first_seg(lv)->min_recovery_rate = lp->min_recovery_rate;
|
||||
first_seg(lv)->max_recovery_rate = lp->max_recovery_rate;
|
||||
@ -7478,6 +7487,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
lv = tmp_lv;
|
||||
|
||||
if (!cache_set_mode(first_seg(lv), lp->cache_mode))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
if (!lv_update_and_reload(lv)) {
|
||||
/* FIXME Do a better revert */
|
||||
log_error("Aborting. Manual intervention required.");
|
||||
|
@ -1153,8 +1153,11 @@ struct lv_status_cache {
|
||||
dm_percent_t dirty_usage;
|
||||
};
|
||||
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg);
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str);
|
||||
const char *get_cache_mode_name(const struct lv_segment *cache_seg);
|
||||
int cache_mode_is_set(const struct lv_segment *seg);
|
||||
int cache_set_mode(struct lv_segment *cache_seg, const char *str);
|
||||
int cache_set_policy(struct lv_segment *cache_seg, const char *name,
|
||||
const struct dm_config_tree *settings);
|
||||
int update_cache_pool_params(const struct segment_type *segtype,
|
||||
struct volume_group *vg, unsigned attr,
|
||||
int passed_args, uint32_t pool_data_extents,
|
||||
@ -1165,8 +1168,6 @@ int validate_lv_cache_create_origin(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);
|
||||
int lv_cache_set_policy(struct logical_volume *cache_lv, const char *name,
|
||||
const struct dm_config_tree *settings);
|
||||
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
|
||||
/* -- metadata/cache_manip.c */
|
||||
|
||||
|
@ -2079,7 +2079,7 @@ static int _cachemode_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (seg_is_cache_pool(seg)) {
|
||||
if (!(cachemode_str = get_cache_pool_cachemode_name(seg)))
|
||||
if (!(cachemode_str = get_cache_mode_name(seg)))
|
||||
return_0;
|
||||
|
||||
return dm_report_field_string(rh, field, &cachemode_str);
|
||||
|
@ -692,7 +692,7 @@ static int _lvchange_cachepolicy(struct cmd_context *cmd, struct logical_volume
|
||||
|
||||
if (!get_cache_params(cmd, NULL, &name, &settings))
|
||||
goto_out;
|
||||
if (!lv_cache_set_policy(lv, name, settings))
|
||||
if (!cache_set_policy(first_seg(lv), name, settings))
|
||||
goto_out;
|
||||
if (!lv_update_and_reload(lv))
|
||||
goto_out;
|
||||
|
@ -3070,7 +3070,7 @@ mda_write:
|
||||
seg->zero_new_blocks = lp->zero ? 1 : 0;
|
||||
|
||||
if ((lp->policy_name || lp->policy_settings) &&
|
||||
!lv_cache_set_policy(seg->lv, lp->policy_name, lp->policy_settings))
|
||||
!cache_set_policy(seg, lp->policy_name, lp->policy_settings))
|
||||
return_0;
|
||||
|
||||
/* Rename deactivated metadata LV to have _tmeta suffix */
|
||||
@ -3178,6 +3178,12 @@ static int _lvconvert_cache(struct cmd_context *cmd,
|
||||
if (!(cache_lv = lv_cache_create(pool_lv, origin_lv)))
|
||||
return_0;
|
||||
|
||||
if (!cache_set_mode(first_seg(cache_lv), lp->cache_mode))
|
||||
return_0;
|
||||
|
||||
if (!cache_set_policy(first_seg(cache_lv), lp->policy_name, lp->policy_settings))
|
||||
return_0;
|
||||
|
||||
if (!lv_update_and_reload(cache_lv))
|
||||
return_0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user