mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
writecache: cachesettings in lvchange and lvs
lvchange --cachesettings lvs -o+cache_settings
This commit is contained in:
parent
ce772bfab9
commit
1ee42f1391
@ -1096,6 +1096,7 @@ int lv_is_cow(const struct logical_volume *lv);
|
||||
int lv_is_cache_origin(const struct logical_volume *lv);
|
||||
int lv_is_writecache_origin(const struct logical_volume *lv);
|
||||
int lv_is_writecache_cachevol(const struct logical_volume *lv);
|
||||
int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem);
|
||||
|
||||
int lv_is_integrity_origin(const struct logical_volume *lv);
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "lib/metadata/lv_alloc.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/config/defaults.h"
|
||||
#include "lib/datastruct/str_list.h"
|
||||
|
||||
int lv_is_writecache_origin(const struct logical_volume *lv)
|
||||
{
|
||||
@ -394,3 +395,72 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
|
||||
return _lv_detach_writecache_cachevol_inactive(lv, noflush);
|
||||
}
|
||||
|
||||
static int _writecache_setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem)
|
||||
{
|
||||
char buf[128];
|
||||
char *list_item;
|
||||
int len;
|
||||
|
||||
if (val_str) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s=%s", field, val_str) < 0)
|
||||
return_0;
|
||||
} else {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s=%llu", field, (unsigned long long)val) < 0)
|
||||
return_0;
|
||||
}
|
||||
|
||||
len = strlen(buf) + 1;
|
||||
|
||||
if (!(list_item = dm_pool_zalloc(mem, len)))
|
||||
return_0;
|
||||
|
||||
memcpy(list_item, buf, len);
|
||||
|
||||
if (!str_list_add_no_dup_check(mem, result, list_item))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
if (settings->high_watermark_set)
|
||||
if (!_writecache_setting_str_list_add("high_watermark", settings->high_watermark, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->low_watermark_set)
|
||||
if (!_writecache_setting_str_list_add("low_watermark", settings->low_watermark, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->writeback_jobs_set)
|
||||
if (!_writecache_setting_str_list_add("writeback_jobs", settings->writeback_jobs, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->autocommit_blocks_set)
|
||||
if (!_writecache_setting_str_list_add("autocommit_blocks", settings->autocommit_blocks, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->autocommit_time_set)
|
||||
if (!_writecache_setting_str_list_add("autocommit_time", settings->autocommit_time, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->fua_set)
|
||||
if (!_writecache_setting_str_list_add("fua", (uint64_t)settings->fua, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->nofua_set)
|
||||
if (!_writecache_setting_str_list_add("nofua", (uint64_t)settings->nofua, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->new_key && settings->new_val)
|
||||
if (!_writecache_setting_str_list_add(settings->new_key, 0, settings->new_val, result, mem))
|
||||
errors++;
|
||||
|
||||
if (errors)
|
||||
log_warn("Failed to create list of writecache settings.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1430,6 +1430,16 @@ static int _cache_settings_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct _str_list_append_baton baton;
|
||||
struct dm_list dummy_list; /* dummy list to display "nothing" */
|
||||
|
||||
if (seg_is_writecache(seg)) {
|
||||
if (!(result = str_list_create(mem)))
|
||||
return_0;
|
||||
|
||||
if (!writecache_settings_to_str_list(&seg->writecache_settings, result, mem))
|
||||
return_0;
|
||||
|
||||
return _field_set_string_list(rh, field, result, private, 0, NULL);
|
||||
}
|
||||
|
||||
if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv))
|
||||
setting_seg = seg;
|
||||
|
||||
|
@ -247,7 +247,7 @@ RULE: --profile not --detachprofile
|
||||
RULE: --metadataprofile not --detachprofile
|
||||
RULE: --minrecoveryrate --maxrecoveryrate and LV_raid
|
||||
RULE: --writebehind --writemostly and LV_raid1
|
||||
RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool
|
||||
RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool LV_writecache
|
||||
RULE: --errorwhenfull --discards --zero and LV_thinpool
|
||||
RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
|
||||
RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin
|
||||
|
@ -606,6 +606,78 @@ static int _lvchange_persistent(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_writecache(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
uint32_t *mr)
|
||||
{
|
||||
struct writecache_settings settings = { 0 };
|
||||
uint32_t block_size_sectors = 0;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
int set_count = 0;
|
||||
|
||||
if (!get_writecache_settings(cmd, &settings, &block_size_sectors))
|
||||
return_0;
|
||||
|
||||
if (block_size_sectors && (seg->writecache_block_size != (block_size_sectors * 512))) {
|
||||
log_error("Cannot change existing block size %u bytes.", seg->writecache_block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings.high_watermark_set) {
|
||||
seg->writecache_settings.high_watermark_set = settings.high_watermark_set;
|
||||
seg->writecache_settings.high_watermark = settings.high_watermark;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.low_watermark_set) {
|
||||
seg->writecache_settings.low_watermark_set = settings.low_watermark_set;
|
||||
seg->writecache_settings.low_watermark = settings.low_watermark;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.writeback_jobs_set) {
|
||||
seg->writecache_settings.writeback_jobs_set = settings.writeback_jobs_set;
|
||||
seg->writecache_settings.writeback_jobs = settings.writeback_jobs;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.autocommit_blocks_set) {
|
||||
seg->writecache_settings.autocommit_blocks_set = settings.autocommit_blocks_set;
|
||||
seg->writecache_settings.autocommit_blocks = settings.autocommit_blocks;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.autocommit_time_set) {
|
||||
seg->writecache_settings.autocommit_time_set = settings.autocommit_time_set;
|
||||
seg->writecache_settings.autocommit_time = settings.autocommit_time;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.fua_set) {
|
||||
seg->writecache_settings.fua_set = settings.fua_set;
|
||||
seg->writecache_settings.fua = settings.fua;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.nofua_set) {
|
||||
seg->writecache_settings.nofua_set = settings.nofua_set;
|
||||
seg->writecache_settings.nofua = settings.nofua;
|
||||
set_count++;
|
||||
}
|
||||
|
||||
if (!set_count) {
|
||||
/*
|
||||
* Empty settings can be used to clear all current settings,
|
||||
* lvchange --cachesettings "" vg/lv
|
||||
*/
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt("Clear all writecache settings? ") == 'n') {
|
||||
log_print("No settings changed.");
|
||||
return 1;
|
||||
}
|
||||
memset(&seg->writecache_settings, 0, sizeof(struct writecache_settings));
|
||||
}
|
||||
|
||||
/* Request caller to commit and reload metadata */
|
||||
*mr |= MR_RELOAD;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_cache(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
uint32_t *mr)
|
||||
@ -619,6 +691,9 @@ static int _lvchange_cache(struct cmd_context *cmd,
|
||||
int r = 0, is_clean;
|
||||
uint32_t chunk_size = 0; /* FYI: lvchange does NOT support its change */
|
||||
|
||||
if (lv_is_writecache(lv))
|
||||
return _lvchange_writecache(cmd, lv, mr);
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv))
|
||||
|
@ -5389,157 +5389,6 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
|
||||
char *key, char *val, uint32_t *block_size_sectors)
|
||||
{
|
||||
/* special case: block_size is not a setting but is set with the --cachesettings option */
|
||||
if (!strncmp(key, "block_size", strlen("block_size"))) {
|
||||
uint32_t block_size = 0;
|
||||
if (sscanf(val, "%u", &block_size) != 1)
|
||||
goto_bad;
|
||||
if (block_size == 512)
|
||||
*block_size_sectors = 1;
|
||||
else if (block_size == 4096)
|
||||
*block_size_sectors = 8;
|
||||
else
|
||||
goto_bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "high_watermark", strlen("high_watermark"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->high_watermark) != 1)
|
||||
goto_bad;
|
||||
if (settings->high_watermark > 100)
|
||||
goto_bad;
|
||||
settings->high_watermark_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "low_watermark", strlen("low_watermark"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->low_watermark) != 1)
|
||||
goto_bad;
|
||||
if (settings->low_watermark > 100)
|
||||
goto_bad;
|
||||
settings->low_watermark_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "writeback_jobs", strlen("writeback_jobs"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->writeback_jobs) != 1)
|
||||
goto_bad;
|
||||
settings->writeback_jobs_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "autocommit_blocks", strlen("autocommit_blocks"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_blocks) != 1)
|
||||
goto_bad;
|
||||
settings->autocommit_blocks_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "autocommit_time", strlen("autocommit_time"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_time) != 1)
|
||||
goto_bad;
|
||||
settings->autocommit_time_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "fua", strlen("fua"))) {
|
||||
if (settings->nofua_set) {
|
||||
log_error("Setting fua and nofua cannot both be set.");
|
||||
return 0;
|
||||
}
|
||||
if (sscanf(val, "%u", &settings->fua) != 1)
|
||||
goto_bad;
|
||||
settings->fua_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "nofua", strlen("nofua"))) {
|
||||
if (settings->fua_set) {
|
||||
log_error("Setting fua and nofua cannot both be set.");
|
||||
return 0;
|
||||
}
|
||||
if (sscanf(val, "%u", &settings->nofua) != 1)
|
||||
goto_bad;
|
||||
settings->nofua_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (settings->new_key) {
|
||||
log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_warn("Unrecognized writecache setting \"%s\" may cause activation failure.", key);
|
||||
if (yes_no_prompt("Use unrecognized writecache setting? [y/n]: ") == 'n') {
|
||||
log_error("Aborting writecache conversion.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_warn("Using unrecognized writecache setting: %s = %s.", key, val);
|
||||
|
||||
settings->new_key = dm_pool_strdup(cmd->mem, key);
|
||||
settings->new_val = dm_pool_strdup(cmd->mem, val);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Invalid setting: %s", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
|
||||
uint32_t *block_size_sectors)
|
||||
{
|
||||
struct arg_value_group_list *group;
|
||||
const char *str;
|
||||
char key[64];
|
||||
char val[64];
|
||||
int num;
|
||||
int pos;
|
||||
|
||||
/*
|
||||
* "grouped" means that multiple --cachesettings options can be used.
|
||||
* Each option is also allowed to contain multiple key = val pairs.
|
||||
*/
|
||||
|
||||
dm_list_iterate_items(group, &cmd->arg_value_groups) {
|
||||
if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
|
||||
continue;
|
||||
|
||||
if (!(str = grouped_arg_str_value(group->arg_values, cachesettings_ARG, NULL)))
|
||||
break;
|
||||
|
||||
pos = 0;
|
||||
|
||||
while (pos < strlen(str)) {
|
||||
/* scan for "key1=val1 key2 = val2 key3= val3" */
|
||||
|
||||
memset(key, 0, sizeof(key));
|
||||
memset(val, 0, sizeof(val));
|
||||
|
||||
if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
|
||||
log_error("Invalid setting at: %s", str+pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos += num;
|
||||
|
||||
if (!_get_one_writecache_setting(cmd, settings, key, val, block_size_sectors))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->high_watermark_set && settings->low_watermark_set &&
|
||||
(settings->high_watermark <= settings->low_watermark)) {
|
||||
log_error("High watermark must be greater than low watermark.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume *lv_fast,
|
||||
@ -5642,7 +5491,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
block_size_sectors = DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS;
|
||||
|
||||
if (!_get_writecache_settings(cmd, &settings, &block_size_sectors)) {
|
||||
if (!get_writecache_settings(cmd, &settings, &block_size_sectors)) {
|
||||
log_error("Invalid writecache settings.");
|
||||
goto bad;
|
||||
}
|
||||
|
150
tools/toollib.c
150
tools/toollib.c
@ -1184,6 +1184,156 @@ out:
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
|
||||
char *key, char *val, uint32_t *block_size_sectors)
|
||||
{
|
||||
/* special case: block_size is not a setting but is set with the --cachesettings option */
|
||||
if (!strncmp(key, "block_size", strlen("block_size"))) {
|
||||
uint32_t block_size = 0;
|
||||
if (sscanf(val, "%u", &block_size) != 1)
|
||||
goto_bad;
|
||||
if (block_size == 512)
|
||||
*block_size_sectors = 1;
|
||||
else if (block_size == 4096)
|
||||
*block_size_sectors = 8;
|
||||
else
|
||||
goto_bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "high_watermark", strlen("high_watermark"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->high_watermark) != 1)
|
||||
goto_bad;
|
||||
if (settings->high_watermark > 100)
|
||||
goto_bad;
|
||||
settings->high_watermark_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "low_watermark", strlen("low_watermark"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->low_watermark) != 1)
|
||||
goto_bad;
|
||||
if (settings->low_watermark > 100)
|
||||
goto_bad;
|
||||
settings->low_watermark_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "writeback_jobs", strlen("writeback_jobs"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->writeback_jobs) != 1)
|
||||
goto_bad;
|
||||
settings->writeback_jobs_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "autocommit_blocks", strlen("autocommit_blocks"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_blocks) != 1)
|
||||
goto_bad;
|
||||
settings->autocommit_blocks_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "autocommit_time", strlen("autocommit_time"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_time) != 1)
|
||||
goto_bad;
|
||||
settings->autocommit_time_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "fua", strlen("fua"))) {
|
||||
if (settings->nofua_set) {
|
||||
log_error("Setting fua and nofua cannot both be set.");
|
||||
return 0;
|
||||
}
|
||||
if (sscanf(val, "%u", &settings->fua) != 1)
|
||||
goto_bad;
|
||||
settings->fua_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "nofua", strlen("nofua"))) {
|
||||
if (settings->fua_set) {
|
||||
log_error("Setting fua and nofua cannot both be set.");
|
||||
return 0;
|
||||
}
|
||||
if (sscanf(val, "%u", &settings->nofua) != 1)
|
||||
goto_bad;
|
||||
settings->nofua_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (settings->new_key) {
|
||||
log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_warn("Unrecognized writecache setting \"%s\" may cause activation failure.", key);
|
||||
if (yes_no_prompt("Use unrecognized writecache setting? [y/n]: ") == 'n') {
|
||||
log_error("Aborting writecache conversion.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_warn("Using unrecognized writecache setting: %s = %s.", key, val);
|
||||
|
||||
settings->new_key = dm_pool_strdup(cmd->mem, key);
|
||||
settings->new_val = dm_pool_strdup(cmd->mem, val);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Invalid setting: %s", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
|
||||
uint32_t *block_size_sectors)
|
||||
{
|
||||
struct arg_value_group_list *group;
|
||||
const char *str;
|
||||
char key[64];
|
||||
char val[64];
|
||||
int num;
|
||||
int pos;
|
||||
|
||||
/*
|
||||
* "grouped" means that multiple --cachesettings options can be used.
|
||||
* Each option is also allowed to contain multiple key = val pairs.
|
||||
*/
|
||||
|
||||
dm_list_iterate_items(group, &cmd->arg_value_groups) {
|
||||
if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
|
||||
continue;
|
||||
|
||||
if (!(str = grouped_arg_str_value(group->arg_values, cachesettings_ARG, NULL)))
|
||||
break;
|
||||
|
||||
pos = 0;
|
||||
|
||||
while (pos < strlen(str)) {
|
||||
/* scan for "key1=val1 key2 = val2 key3= val3" */
|
||||
|
||||
memset(key, 0, sizeof(key));
|
||||
memset(val, 0, sizeof(val));
|
||||
|
||||
if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
|
||||
log_error("Invalid setting at: %s", str+pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos += num;
|
||||
|
||||
if (!_get_one_writecache_setting(cmd, settings, key, val, block_size_sectors))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->high_watermark_set && settings->low_watermark_set &&
|
||||
(settings->high_watermark <= settings->low_watermark)) {
|
||||
log_error("High watermark must be greater than low watermark.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME move to lib */
|
||||
static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
|
||||
|
@ -217,6 +217,9 @@ int get_cache_params(struct cmd_context *cmd,
|
||||
const char **name,
|
||||
struct dm_config_tree **settings);
|
||||
|
||||
int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
|
||||
uint32_t *block_size_sectors);
|
||||
|
||||
int change_tag(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct physical_volume *pv, int arg);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user