1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-03 01:44:19 +03:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Zdenek Kabelac
fadcb63a43 WHATS_NEW: update 2024-10-14 11:31:40 -05:00
Zdenek Kabelac
ca74ba6f16 device_mapper: slight improvement of tok_match
Reduce amount of unnecessary instructions for some code paths.
2024-10-14 11:31:40 -05:00
Zdenek Kabelac
7b6a800e4f import_vsn1: increate hash size
With larger amount of LV hashing buckets within VG,
until better structures for dynamic handling of LV elements will be used.
2024-10-14 11:31:40 -05:00
Zdenek Kabelac
c22ed72e7d device_mapper: slight reorder for _get_token
For most common part check for '#' when it's known it's not a space.
And also when we checked for '\n' we dont need to check again isspace().
2024-10-14 11:31:40 -05:00
Zdenek Kabelac
faf5fddbec device_mapper: nodes and values with strings
Avoid double pool allocation call by placing string
directly after the node/value structure end.

It would be likely better to not copy the string at all
and derefence it from the original string however that
is much larger rework - and also for unescaping we would
need to allocate anyway.
2024-10-14 11:31:40 -05:00
Zdenek Kabelac
f4dc2b9aa3 crc: add newer zlib code
This code is faster when calculating crc32 checksum for larger
block areas. There is also SIMD variant present in the code,
however ATM the influence on performance of lvm2 is not that big..
2024-10-14 11:31:40 -05:00
Zdenek Kabelac
6de4590cf9 crc: move static table
Move static table upward in the code so it can be shared with
another 'crc' implementation.
2024-10-14 11:31:40 -05:00
David Teigland
8bfbb623d7 config: set vg_copy_internal to binary for testing 2024-10-14 11:31:40 -05:00
David Teigland
77305127e4 vg: use vg_copy_struct in second location 2024-10-14 11:31:40 -05:00
David Teigland
18babdc3ac vg: copy alternative to reimporting
One vg struct is copied to another vg struct, rather than
importing vg metadata text to create the new vg struct.

Enable with global/vg_copy_internal="binary"
2024-10-09 15:49:03 -05:00
13 changed files with 1187 additions and 112 deletions

View File

@@ -157,6 +157,7 @@ Version 2.03.17 - 10th November 2022
Switch to use mallinfo2 and use it only with glibc.
Error out in lvm shell if using a cmd argument not supported in the shell.
Fix lvm shell's lastlog command to report previous pre-command failures.
Keep libaio locked in memory in critical section.
Extend VDO and VDOPOOL without flushing and locking fs.
Add --valuesonly option to lvmconfig to print only values without keys.
Updates configure with recent autoconf tooling.

View File

@@ -70,7 +70,8 @@ static struct dm_config_value *_value(struct parser *p);
static struct dm_config_value *_type(struct parser *p);
static int _match_aux(struct parser *p, int t);
static struct dm_config_value *_create_value(struct dm_pool *mem);
static struct dm_config_node *_create_node(struct dm_pool *mem);
static struct dm_config_value *_create_str_value(struct dm_pool *mem, const char *str, size_t str_len);
static struct dm_config_node *_create_node(struct dm_pool *mem, const char *key, size_t key_len);
static char *_dup_tok(struct parser *p);
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
@@ -84,14 +85,19 @@ static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
} \
} while(0)
/* match token */
static int _tok_match(const char *str, const char *b, const char *e)
{
while (*str && (b != e)) {
if (*str++ != *b++)
while (b < e) {
if (*str != *b)
return 0;
if (!*str)
return 0;
++str;
++b;
}
return !(*str || (b != e));
return !*str; /* token is matching for \0 end */
}
struct dm_config_tree *dm_config_create(void)
@@ -467,23 +473,33 @@ int dm_config_write_node_out(const struct dm_config_node *cn,
/*
* parser
*/
static char *_dup_string_tok(struct parser *p)
static const char *_string_tok(struct parser *p, size_t *len)
{
char *str;
ptrdiff_t d = p->te - p->tb;
p->tb++, p->te--; /* strip "'s */
if (p->te < p->tb) {
if (d < 2) {
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): "
"expected a string token.",
p->tb - p->fb + 1, p->line);
return NULL;
}
if (!(str = _dup_tok(p)))
*len = (size_t)(d - 2); /* strip "'s */
return p->tb + 1;
}
static char *_dup_string_tok(struct parser *p)
{
const char *tok;
size_t len;
char *str;
if (!(tok = _string_tok(p, &len)))
return_NULL;
p->te++;
if (!(str = _dup_token(p->mem, tok, tok + len)))
return_NULL;
return str;
}
@@ -505,10 +521,9 @@ static struct dm_config_node *_make_node(struct dm_pool *mem,
{
struct dm_config_node *n;
if (!(n = _create_node(mem)))
if (!(n = _create_node(mem, key_b, key_e - key_b)))
return_NULL;
n->key = _dup_token(mem, key_b, key_e);
if (parent) {
n->parent = parent;
n->sib = parent->child;
@@ -669,16 +684,14 @@ static struct dm_config_value *_value(struct parser *p)
static struct dm_config_value *_type(struct parser *p)
{
/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct dm_config_value *v = _create_value(p->mem);
char *str;
if (!v) {
log_error("Failed to allocate type value");
return NULL;
}
struct dm_config_value *v;
const char *str;
size_t len;
switch (p->t) {
case TOK_INT:
if (!(v = _create_value(p->mem)))
break;
v->type = DM_CFG_INT;
errno = 0;
v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
@@ -699,6 +712,8 @@ static struct dm_config_value *_type(struct parser *p)
break;
case TOK_FLOAT:
if (!(v = _create_value(p->mem)))
break;
v->type = DM_CFG_FLOAT;
errno = 0;
v->v.f = strtod(p->tb, NULL); /* FIXME: check error */
@@ -710,31 +725,31 @@ static struct dm_config_value *_type(struct parser *p)
break;
case TOK_STRING:
v->type = DM_CFG_STRING;
if (!(v->v.str = _dup_string_tok(p)))
if (!(str = _string_tok(p, &len)))
return_NULL;
match(TOK_STRING);
if ((v = _create_str_value(p->mem, str, len))) {
v->type = DM_CFG_STRING;
match(TOK_STRING);
}
break;
case TOK_STRING_BARE:
v->type = DM_CFG_STRING;
if (!(v->v.str = _dup_tok(p)))
return_NULL;
match(TOK_STRING_BARE);
if ((v = _create_str_value(p->mem, p->tb, p->te - p->tb))) {
v->type = DM_CFG_STRING;
match(TOK_STRING_BARE);
}
break;
case TOK_STRING_ESCAPED:
v->type = DM_CFG_STRING;
if (!(str = _dup_string_tok(p)))
if (!(str = _string_tok(p, &len)))
return_NULL;
dm_unescape_double_quotes(str);
v->v.str = str;
match(TOK_STRING_ESCAPED);
if ((v = _create_str_value(p->mem, str, len))) {
v->type = DM_CFG_STRING;
dm_unescape_double_quotes((char*)v->v.str);
match(TOK_STRING_ESCAPED);
}
break;
default:
@@ -742,6 +757,12 @@ static struct dm_config_value *_type(struct parser *p)
p->tb - p->fb + 1, p->line);
return NULL;
}
if (!v) {
log_error("Failed to allocate type value.");
return NULL;
}
return v;
}
@@ -883,16 +904,19 @@ static void _get_token(struct parser *p, int tok_prev)
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
if (*p->te == '#')
if (!isspace(*p->te)) {
if (*p->te != '#')
break;
while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
++p->te;
}
else if (!isspace(*p->te))
break;
while ((p->te != p->fe) && isspace(*p->te)) {
while (p->te != p->fe) {
if (*p->te == '\n')
++p->line;
else if (!isspace(*p->te))
break;
++p->te;
}
@@ -908,9 +932,46 @@ static struct dm_config_value *_create_value(struct dm_pool *mem)
return dm_pool_zalloc(mem, sizeof(struct dm_config_value));
}
static struct dm_config_node *_create_node(struct dm_pool *mem)
static struct dm_config_value *_create_str_value(struct dm_pool *mem, const char *str, size_t str_len)
{
return dm_pool_zalloc(mem, sizeof(struct dm_config_node));
struct dm_config_value *cv;
char *str_buf;
if (!(cv = dm_pool_alloc(mem, sizeof(struct dm_config_value) + str_len + 1)))
return_NULL;
memset(cv, 0, sizeof(*cv));
if (str) {
str_buf = (char *)(cv + 1);
if (str_len)
memcpy(str_buf, str, str_len);
str_buf[str_len] = '\0';
cv->v.str = str_buf;
}
return cv;
}
static struct dm_config_node *_create_node(struct dm_pool *mem, const char *key, size_t key_len)
{
struct dm_config_node *cn;
char *key_buf;
if (!(cn = dm_pool_alloc(mem, sizeof(struct dm_config_node) + key_len + 1)))
return_NULL;
memset(cn, 0, sizeof(*cn));
if (key) {
key_buf = (char *)(cn + 1);
if (key_len)
memcpy(key_buf, key, key_len);
key_buf[key_len] = '\0';
cn->key = key_buf;
}
return cn;
}
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e)
@@ -1327,19 +1388,19 @@ static struct dm_config_value *_clone_config_value(struct dm_pool *mem,
{
struct dm_config_value *new_cv;
if (!(new_cv = _create_value(mem))) {
log_error("Failed to clone config value.");
return NULL;
if (v->type == DM_CFG_STRING) {
if (!(new_cv = _create_str_value(mem, v->v.str, strlen(v->v.str)))) {
}
} else {
if (!(new_cv = _create_value(mem))) {
log_error("Failed to clone config value.");
return NULL;
}
new_cv->v = v->v;
}
new_cv->type = v->type;
if (v->type == DM_CFG_STRING) {
if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
log_error("Failed to clone config string value.");
return NULL;
}
} else
new_cv->v = v->v;
if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
return_NULL;
@@ -1356,16 +1417,11 @@ struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const
return NULL;
}
if (!(new_cn = _create_node(mem))) {
if (!(new_cn = _create_node(mem, cn->key, cn->key ? strlen(cn->key) : 0))) {
log_error("Failed to clone config node.");
return NULL;
}
if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
log_error("Failed to clone config node key.");
return NULL;
}
new_cn->id = cn->id;
if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
@@ -1385,14 +1441,11 @@ struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const c
{
struct dm_config_node *cn;
if (!(cn = _create_node(cft->mem))) {
if (!(cn = _create_node(cft->mem, key, strlen(key)))) {
log_error("Failed to create config node.");
return NULL;
}
if (!(cn->key = dm_pool_strdup(cft->mem, key))) {
log_error("Failed to create config node's key.");
return NULL;
}
cn->parent = NULL;
cn->v = NULL;

View File

@@ -659,6 +659,7 @@ static int _process_config(struct cmd_context *cmd)
mode_t old_umask;
const char *dev_ext_info_src = NULL;
const char *read_ahead;
const char *str;
struct stat st;
const struct dm_config_node *cn;
const struct dm_config_value *cv;
@@ -816,6 +817,12 @@ static int _process_config(struct cmd_context *cmd)
cmd->check_pv_dev_sizes = find_config_tree_bool(cmd, metadata_check_pv_device_sizes_CFG, NULL);
cmd->event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
if ((str = find_config_tree_str(cmd, global_vg_copy_internal_CFG, NULL))) {
if (!strcmp(str, "binary"))
cmd->vg_copy_binary = 1;
}
if (!process_profilable_config(cmd))
return_0;

View File

@@ -218,6 +218,7 @@ struct cmd_context {
unsigned device_ids_invalid:1;
unsigned device_ids_auto_import:1;
unsigned get_vgname_from_options:1; /* used by lvconvert */
unsigned vg_copy_binary:1;
/*
* Devices and filtering.

View File

@@ -1387,6 +1387,13 @@ cfg(global_io_memory_size_CFG, "io_memory_size", global_CFG_SECTION, CFG_DEFAULT
"This value should usually not be decreased from the default; setting\n"
"it too low can result in lvm failing to read VGs.\n")
cfg(global_vg_copy_internal_CFG, "vg_copy_internal", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_VG_COPY_INTERNAL, vsn(2, 3, 27), NULL, 0, NULL,
"The method that lvm uses for internal VG structure copying.\n"
"\"binary\" copies between binary structures to improve performance\n"
"with large metadata (experimental.) \"text\" exports a binary\n"
"struct to text format, and reimports text to a new binary\n"
"structure (traditional.)\n")
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
"The --noudevsync option overrides this setting.\n"

View File

@@ -344,4 +344,6 @@
#define DEFAULT_DEVICESFILE_BACKUP_LIMIT 50
#define DEFAULT_VG_COPY_INTERNAL "binary"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -647,15 +647,36 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
*
* 'Lazy' creation of such VG might improve performance, but we
* lose important validation that written metadata can be parsed. */
if (!(cft = config_tree_from_string_without_dup_node_check(write_buf))) {
log_error("Error parsing metadata for VG %s.", vg->name);
goto out;
}
release_vg(vg->vg_precommitted);
vg->vg_precommitted = import_vg_from_config_tree(vg->cmd, vg->fid, cft);
dm_config_destroy(cft);
if (!vg->vg_precommitted)
vg->vg_precommitted = NULL;
if (!vg->cmd->vg_copy_binary) {
if (!(cft = config_tree_from_string_without_dup_node_check(write_buf))) {
log_error("Error parsing metadata for VG %s.", vg->name);
goto out;
}
vg->vg_precommitted = import_vg_from_config_tree(vg->cmd, vg->fid, cft);
dm_config_destroy(cft);
} else {
vg->vg_precommitted = vg_copy_struct(vg);
if (!vg->vg_precommitted) {
log_debug("vg_copy_struct failed, trying text import.");
if (!(cft = config_tree_from_string_without_dup_node_check(write_buf))) {
log_error("Error parsing metadata for VG %s.", vg->name);
goto out;
}
vg->vg_precommitted = import_vg_from_config_tree(vg->cmd, vg->fid, cft);
dm_config_destroy(cft);
}
}
if (!vg->vg_precommitted) {
log_error("Failed to copy vg struct.");
goto_out;
}
log_debug("Saved vg struct %p as precommitted", vg->vg_precommitted);
fidtc->checksum = checksum = calc_crc(INITIAL_CRC, (uint8_t *)write_buf, new_size);
}

View File

@@ -1085,7 +1085,7 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
* The lv hash memorizes the lv section names -> lv
* structures.
*/
if (!(lv_hash = dm_hash_create(1023))) {
if (!(lv_hash = dm_hash_create(8181))) {
log_error("Couldn't create lv hash table.");
goto bad;
}

View File

@@ -9569,8 +9569,10 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (seg_is_raid(lp) && lp->raidintegrity) {
log_debug("Adding integrity to new LV");
if (!lv_add_integrity_to_raid(lv, &lp->integrity_settings, lp->pvh, NULL))
if (!lv_add_integrity_to_raid(lv, &lp->integrity_settings, lp->pvh, NULL)) {
stack;
goto revert_new_lv;
}
}
/* Do not scan this LV until properly zeroed/wiped. */
@@ -9643,6 +9645,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
first_seg(pool_lv)->transaction_id = seg->transaction_id;
first_seg(lv)->device_id = 0; /* no delete of never existing thin device */
}
stack;
goto revert_new_lv;
}
/* At this point remove pool messages, snapshot is active */
@@ -9798,6 +9801,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return_NULL;
}
stack;
goto deactivate_and_revert_new_lv;
}
} else if (lp->snapshot) {
@@ -9819,8 +9823,10 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (lp->virtual_extents &&
!(origin_lv = _create_virtual_origin(cmd, vg, lv->name,
(lp->permission & ~LVM_WRITE),
lp->virtual_extents)))
lp->virtual_extents))) {
stack;
goto revert_new_lv;
}
/* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE))
@@ -9862,9 +9868,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
out:
if (!lv)
log_debug("No LV created.");
return lv;
deactivate_and_revert_new_lv:
log_debug("Deactivate and revert new lv");
if (!sync_local_dev_names(lv->vg->cmd))
log_error("Failed to sync local devices before reverting %s.",
display_lvname(lv));
@@ -9875,6 +9884,7 @@ deactivate_and_revert_new_lv:
}
revert_new_lv:
log_debug("Revert new lv");
if (!lockd_lv(cmd, lv, "un", LDLV_PERSISTENT))
log_warn("WARNING: Failed to unlock %s.", display_lvname(lv));
lockd_free_lv(vg->cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);

View File

@@ -1439,6 +1439,21 @@ char *top_level_lv_name(struct volume_group *vg, const char *lv_name);
struct generic_logical_volume *get_or_create_glv(struct dm_pool *mem, struct logical_volume *lv, int *glv_created);
struct glv_list *get_or_create_glvl(struct dm_pool *mem, struct logical_volume *lv, int *glv_created);
struct logical_volume *get_data_from_pool(struct logical_volume *pool_lv);
struct logical_volume *get_meta_from_pool(struct logical_volume *pool_lv);
struct logical_volume *get_pool_from_thin(struct logical_volume *thin_lv);
struct logical_volume *get_pool_from_cache(struct logical_volume *cache_lv);
struct logical_volume *get_pool_from_vdo(struct logical_volume *vdo_lv);
struct logical_volume *get_origin_from_cache(struct logical_volume *cache_lv);
struct logical_volume *get_origin_from_writecache(struct logical_volume *writecache_lv);
struct logical_volume *get_origin_from_integrity(struct logical_volume *integrity_lv);
struct logical_volume *get_origin_from_thin(struct logical_volume *thin_lv);
struct logical_volume *get_merge_lv_from_thin(struct logical_volume *thin_lv);
struct logical_volume *get_external_lv_from_thin(struct logical_volume *thin_lv);
struct logical_volume *get_origin_from_snap(struct logical_volume *snap_lv);
struct logical_volume *get_cow_from_snap(struct logical_volume *snap_lv);
struct logical_volume *get_fast_from_writecache(struct logical_volume *writecache_lv);
/*
* Begin skeleton for external LVM library
*/
@@ -1514,4 +1529,8 @@ int lv_raid_integrity_total_mismatches(struct cmd_context *cmd, const struct log
int setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem);
struct volume_group *vg_copy_struct(struct volume_group *vgo);
void insert_segment(struct logical_volume *lv, struct lv_segment *seg);
#endif

View File

@@ -4346,6 +4346,8 @@ const struct logical_volume *lv_committed(const struct logical_volume *lv)
found_lv = lv; /* Use uncommitted LV as best effort */
}
log_debug("lv_committed %s from vg_committed %p", display_lvname(found_lv), vg);
return found_lv;
}
@@ -5173,9 +5175,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
goto out;
}
if (!(vg->vg_committed = import_vg_from_config_tree(cmd, vg->fid, vg->committed_cft))) {
log_error("Failed to import written VG.");
goto out;
if (!(vg->vg_committed = vg_copy_struct(vg))) {
if (!(vg->vg_committed = import_vg_from_config_tree(cmd, vg->fid, vg->committed_cft))) {
log_error("Failed to import written VG.");
goto out;
}
}
} else {
if (vg->vg_precommitted)

View File

@@ -15,10 +15,14 @@
#include "lib/misc/lib.h"
#include "lib/metadata/metadata.h"
#include "lib/metadata/lv_alloc.h"
#include "lib/metadata/segtype.h"
#include "lib/metadata/pv_alloc.h"
#include "lib/display/display.h"
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/format_text/archiver.h"
#include "lib/datastruct/str_list.h"
struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
const char *vg_name)
@@ -757,3 +761,858 @@ void vg_backup_if_needed(struct volume_group *vg)
vg->needs_backup = 0;
backup(vg->vg_committed);
}
void insert_segment(struct logical_volume *lv, struct lv_segment *seg)
{
struct lv_segment *comp;
dm_list_iterate_items(comp, &lv->segments) {
if (comp->le > seg->le) {
dm_list_add(&comp->list, &seg->list);
return;
}
}
lv->le_count += seg->len;
dm_list_add(&lv->segments, &seg->list);
}
struct logical_volume *get_data_from_pool(struct logical_volume *pool_lv)
{
/* works for cache pool, thin pool, vdo pool */
/* first_seg() = dm_list_first_entry(&lv->segments) */
/* seg_lv(seg, n) = seg->areas[n].u.lv.lv */
return seg_lv(first_seg(pool_lv), 0);
}
struct logical_volume *get_meta_from_pool(struct logical_volume *pool_lv)
{
/* works for cache pool, thin pool, vdo pool */
/* first_seg() = dm_list_first_entry(&lv->segments) */
/* seg_lv(seg, n) = seg->areas[n].u.lv.lv */
return first_seg(pool_lv)->metadata_lv;
}
struct logical_volume *get_pool_from_thin(struct logical_volume *thin_lv)
{
return first_seg(thin_lv)->pool_lv;
}
struct logical_volume *get_pool_from_cache(struct logical_volume *cache_lv)
{
return first_seg(cache_lv)->pool_lv;
}
struct logical_volume *get_pool_from_vdo(struct logical_volume *vdo_lv)
{
return seg_lv(first_seg(vdo_lv), 0);
}
struct logical_volume *get_origin_from_cache(struct logical_volume *cache_lv)
{
return seg_lv(first_seg(cache_lv), 0);
}
struct logical_volume *get_origin_from_writecache(struct logical_volume *writecache_lv)
{
return seg_lv(first_seg(writecache_lv), 0);
}
struct logical_volume *get_origin_from_integrity(struct logical_volume *integrity_lv)
{
return seg_lv(first_seg(integrity_lv), 0);
}
struct logical_volume *get_origin_from_thin(struct logical_volume *thin_lv)
{
return first_seg(thin_lv)->origin;
}
struct logical_volume *get_merge_lv_from_thin(struct logical_volume *thin_lv)
{
return first_seg(thin_lv)->merge_lv;
}
struct logical_volume *get_external_lv_from_thin(struct logical_volume *thin_lv)
{
return first_seg(thin_lv)->external_lv;
}
struct logical_volume *get_origin_from_snap(struct logical_volume *snap_lv)
{
return first_seg(snap_lv)->origin;
}
struct logical_volume *get_cow_from_snap(struct logical_volume *snap_lv)
{
return first_seg(snap_lv)->cow;
}
struct logical_volume *get_fast_from_writecache(struct logical_volume *writecache_lv)
{
return first_seg(writecache_lv)->writecache;
}
/*
* When reading from text:
* - pv comes from looking up the "pv0" key in pv_hash
* - pe comes from text field
* - pv and pe are passed to set_lv_segment_area_pv() to
* create the pv_segment structs, and connect them to
* the lv_segment.
*
* When copying the struct:
* - pv comes from looking up the pv id in vg->pvs
* - pe comes from the original pvseg struct
* - pv and pe are passed to set_lv_segment_area_pv() to
* create the pv_segment structs, and connect them to
* the lv_segment (same as when reading from text.)
*
* set_lv_segment_area_pv(struct lv_segment *seg, uint32_t s,
* struct physical_volume *pv, uint32_t pe);
* does:
*
* seg_pvseg(seg, s) =
* assign_peg_to_lvseg(pv, pe, seg->area_len, seg, s);
*
* does:
*
* seg->areas[s].u.pv.pvseg =
* assign_peg_to_lvseg(pv, pe, area_len, seg, s);
*
* struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
* uint32_t pe, uint32_t area_len,
* struct lv_segment *seg, uint32_t s);
*
* This does multiple things:
* 1. creates pv_segment and connects it to lv_segment
* 2. creates pv->segments list of all pv_segments on the pv
* 3. updates pv->pe_alloc_count, vg->free_count
*/
static int _areas_copy_struct(struct volume_group *vg,
struct logical_volume *lv,
struct lv_segment *seg,
struct volume_group *vgo,
struct logical_volume *lvo,
struct lv_segment *sego,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash)
{
uint32_t s;
/* text_import_areas */
for (s = 0; s < sego->area_count; s++) {
seg->areas[s].type = sego->areas[s].type;
if (sego->areas[s].type == AREA_PV) {
struct physical_volume *area_pvo;
struct physical_volume *area_pv;
if (!(area_pvo = sego->areas[s].u.pv.pvseg->pv))
goto_bad;
if (!(area_pv = dm_hash_lookup_binary(pv_hash, &area_pvo->id, ID_LEN)))
goto_bad;
if (!set_lv_segment_area_pv(seg, s, area_pv, sego->areas[s].u.pv.pvseg->pe))
goto_bad;
} else if (sego->areas[s].type == AREA_LV) {
struct logical_volume *area_lvo;
struct logical_volume *area_lv;
if (!(area_lvo = sego->areas[s].u.lv.lv))
goto_bad;
if (!(area_lv = dm_hash_lookup(lv_hash, area_lvo->name)))
goto_bad;
if (!set_lv_segment_area_lv(seg, s, area_lv, sego->areas[s].u.lv.le, 0))
goto_bad;
}
}
return 1;
bad:
return 0;
}
static int _thin_messages_copy_struct(struct volume_group *vgo, struct volume_group *vg,
struct logical_volume *lvo, struct logical_volume *lv,
struct lv_segment *sego, struct lv_segment *seg,
struct dm_hash_table *lv_hash)
{
struct lv_thin_message *mso;
struct lv_thin_message *ms;
struct logical_volume *ms_lvo;
struct logical_volume *ms_lv;
if (dm_list_empty(&sego->thin_messages))
return 1;
dm_list_iterate_items(mso, &sego->thin_messages) {
if (!(ms = dm_pool_alloc(vg->vgmem, sizeof(*ms))))
goto_bad;
ms->type = mso->type;
switch (ms->type) {
case DM_THIN_MESSAGE_CREATE_SNAP:
case DM_THIN_MESSAGE_CREATE_THIN:
if (!(ms_lvo = mso->u.lv))
goto_bad;
if (!(ms_lv = dm_hash_lookup(lv_hash, ms_lvo->name)))
goto_bad;
ms->u.lv = ms_lv;
break;
case DM_THIN_MESSAGE_DELETE:
ms->u.delete_id = mso->u.delete_id;
break;
default:
break;
}
dm_list_add(&seg->thin_messages, &ms->list);
}
return 1;
bad:
return 0;
}
static struct lv_segment *_seg_copy_struct(struct volume_group *vg,
struct logical_volume *lv,
struct volume_group *vgo,
struct logical_volume *lvo,
struct lv_segment *sego,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash)
{
struct dm_pool *mem = vg->vgmem;
struct lv_segment *seg;
uint32_t s;
if (!(seg = dm_pool_zalloc(mem, sizeof(*seg))))
return_NULL;
if (sego->area_count && sego->areas &&
!(seg->areas = dm_pool_zalloc(mem, sego->area_count * sizeof(*seg->areas))))
return_NULL;
/*
* This is a more accurate copy of the original segment:
* if (sego->area_count && sego->meta_areas &&
* !(seg->meta_areas = dm_pool_zalloc(mem, sego->area_count * sizeof(*seg->meta_areas))))
* return_NULL;
*
* But it causes a segfault in for_each_sub_lv, which seems to want meta_areas allocated
* in the copy even when it's null in the original. So, this copies alloc_lv_segment
* which always allocates meta_areas.
*/
if (segtype_is_raid_with_meta(sego->segtype)) {
if (!(seg->meta_areas = dm_pool_zalloc(mem, sego->area_count * sizeof(*seg->meta_areas))))
return_NULL;
}
/* see _read_segment, alloc_lv_segment */
dm_list_init(&seg->tags);
dm_list_init(&seg->origin_list);
dm_list_init(&seg->thin_messages);
seg->lv = lv;
seg->segtype = sego->segtype;
seg->le = sego->le;
seg->len = sego->len;
seg->status = sego->status;
seg->area_count = sego->area_count;
seg->area_len = sego->area_len;
if (!dm_list_empty(&sego->tags) && !str_list_dup(mem, &seg->tags, &sego->tags))
goto_bad;
/*
* _read_segment, ->text_import(), i.e. _foo_text_import()
*/
if (seg_is_striped_target(sego)) {
/* see _striped_text_import, N.B. not "seg_is_striped" */
seg->stripe_size = sego->stripe_size;
if (!_areas_copy_struct(vg, lv, seg, vgo, lvo, sego, pv_hash, lv_hash))
goto_bad;
} else if (seg_is_cache_pool(sego)) {
struct logical_volume *data_lvo;
struct logical_volume *meta_lvo;
struct logical_volume *data_lv;
struct logical_volume *meta_lv;
/* see _cache_pool_text_import */
seg->cache_metadata_format = sego->cache_metadata_format;
seg->chunk_size = sego->chunk_size;
seg->cache_mode = sego->cache_mode;
if (sego->policy_name)
seg->policy_name = dm_pool_strdup(mem, sego->policy_name);
if (sego->policy_settings)
seg->policy_settings = dm_config_clone_node_with_mem(mem, sego->policy_settings, 0);
if (!(data_lvo = get_data_from_pool(lvo)))
goto_bad;
if (!(meta_lvo = get_meta_from_pool(lvo)))
goto_bad;
if (!(data_lv = dm_hash_lookup(lv_hash, data_lvo->name)))
goto_bad;
if (!(meta_lv = dm_hash_lookup(lv_hash, meta_lvo->name)))
goto_bad;
if (!attach_pool_data_lv(seg, data_lv))
goto_bad;
if (!attach_pool_metadata_lv(seg, meta_lv))
goto_bad;
} else if (seg_is_cache(sego)) {
struct logical_volume *pool_lvo;
struct logical_volume *origin_lvo;
struct logical_volume *pool_lv;
struct logical_volume *origin_lv;
/* see _cache_text_import */
seg->cache_metadata_format = sego->cache_metadata_format;
seg->chunk_size = sego->chunk_size;
seg->cache_mode = sego->cache_mode;
if (sego->policy_name)
seg->policy_name = dm_pool_strdup(mem, sego->policy_name);
if (sego->policy_settings)
seg->policy_settings = dm_config_clone_node_with_mem(mem, sego->policy_settings, 0);
seg->cleaner_policy = sego->cleaner_policy;
seg->metadata_start = sego->metadata_start;
seg->metadata_len = sego->metadata_len;
seg->data_start = sego->data_start;
seg->data_len = sego->data_len;
if (sego->metadata_id) {
if (!(seg->metadata_id = dm_pool_zalloc(mem, sizeof(struct id))))
goto_bad;
memcpy(seg->metadata_id, sego->metadata_id, sizeof(struct id));
}
if (sego->data_id) {
if (!(seg->data_id = dm_pool_zalloc(mem, sizeof(struct id))))
goto_bad;
memcpy(seg->data_id, sego->data_id, sizeof(struct id));
}
if (!(pool_lvo = get_pool_from_cache(lvo)))
goto_bad;
if (!(origin_lvo = get_origin_from_cache(lvo)))
goto_bad;
if (!(pool_lv = dm_hash_lookup(lv_hash, pool_lvo->name)))
goto_bad;
if (!(origin_lv = dm_hash_lookup(lv_hash, origin_lvo->name)))
goto_bad;
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
goto_bad;
if (!attach_pool_lv(seg, pool_lv, NULL, NULL, NULL))
goto_bad;
} else if (seg_is_integrity(sego)) {
struct logical_volume *origin_lvo;
struct logical_volume *origin_lv;
struct logical_volume *meta_lvo;
struct logical_volume *meta_lv;
const char *hash;
/* see _integrity_text_import */
if (!(origin_lvo = get_origin_from_integrity(lvo)))
goto_bad;
if (!(origin_lv = dm_hash_lookup(lv_hash, origin_lvo->name)))
goto_bad;
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
goto_bad;
seg->origin = origin_lv;
if ((meta_lvo = sego->integrity_meta_dev)) {
if (!(meta_lv = dm_hash_lookup(lv_hash, meta_lvo->name)))
goto_bad;
seg->integrity_meta_dev = meta_lv;
if (!add_seg_to_segs_using_this_lv(meta_lv, seg))
goto_bad;
}
seg->integrity_data_sectors = sego->integrity_data_sectors;
seg->integrity_recalculate = sego->integrity_recalculate;
memcpy(&seg->integrity_settings, &sego->integrity_settings, sizeof(seg->integrity_settings));
if ((hash = sego->integrity_settings.internal_hash)) {
if (!(seg->integrity_settings.internal_hash = dm_pool_strdup(mem, hash)))
goto_bad;
}
} else if (seg_is_mirror(sego)) {
struct logical_volume *log_lv;
/* see _mirrored_text_import */
seg->extents_copied = sego->extents_copied;
seg->region_size = sego->region_size;
if (sego->log_lv) {
if (!(log_lv = dm_hash_lookup(lv_hash, sego->log_lv->name)))
goto_bad;
seg->log_lv = log_lv;
}
if (!_areas_copy_struct(vg, lv, seg, vgo, lvo, sego, pv_hash, lv_hash))
goto_bad;
} else if (seg_is_thin_pool(sego)) {
struct logical_volume *data_lvo;
struct logical_volume *meta_lvo;
struct logical_volume *data_lv;
struct logical_volume *meta_lv;
/* see _thin_pool_text_import */
if (!(data_lvo = get_data_from_pool(lvo)))
goto_bad;
if (!(meta_lvo = get_meta_from_pool(lvo)))
goto_bad;
if (!(data_lv = dm_hash_lookup(lv_hash, data_lvo->name)))
goto_bad;
if (!(meta_lv = dm_hash_lookup(lv_hash, meta_lvo->name)))
goto_bad;
if (!attach_pool_data_lv(seg, data_lv))
goto_bad;
if (!attach_pool_metadata_lv(seg, meta_lv))
goto_bad;
seg->transaction_id = sego->transaction_id;
seg->chunk_size = sego->chunk_size;
seg->discards = sego->discards;
seg->zero_new_blocks = sego->zero_new_blocks;
seg->crop_metadata = sego->crop_metadata;
if (!_thin_messages_copy_struct(vgo, vg, lvo, lv, sego, seg, lv_hash))
goto_bad;
} else if (seg_is_thin_volume(sego)) {
struct logical_volume *pool_lvo;
struct logical_volume *origin_lvo;
struct logical_volume *merge_lvo;
struct logical_volume *external_lvo;
struct logical_volume *pool_lv = NULL;
struct logical_volume *origin_lv = NULL;
struct logical_volume *merge_lv = NULL;
struct logical_volume *external_lv = NULL;
/* see _thin_text_import */
if (!(pool_lvo = get_pool_from_thin(lvo)))
goto_bad;
if (!(pool_lv = dm_hash_lookup(lv_hash, pool_lvo->name)))
goto_bad;
if ((origin_lvo = get_origin_from_thin(lvo))) {
if (!(origin_lv = dm_hash_lookup(lv_hash, origin_lvo->name)))
goto_bad;
}
if ((merge_lvo = get_merge_lv_from_thin(lvo))) {
if (!(merge_lv = dm_hash_lookup(lv_hash, merge_lvo->name)))
goto_bad;
}
if ((external_lvo = get_external_lv_from_thin(lvo))) {
if (!(external_lv = dm_hash_lookup(lv_hash, external_lvo->name)))
goto_bad;
}
if (!attach_pool_lv(seg, pool_lv, origin_lv, NULL, merge_lv))
goto_bad;
if (!attach_thin_external_origin(seg, external_lv))
goto_bad;
seg->transaction_id = sego->transaction_id;
seg->device_id = sego->device_id;
} else if (seg_is_snapshot(sego)) {
struct logical_volume *origin_lvo;
struct logical_volume *cow_lvo;
struct logical_volume *origin_lv;
struct logical_volume *cow_lv;
/* see _snap_text_import */
if (!(origin_lvo = get_origin_from_snap(lvo)))
goto_bad;
if (!(cow_lvo = get_cow_from_snap(lvo)))
goto_bad;
if (!(origin_lv = dm_hash_lookup(lv_hash, origin_lvo->name)))
goto_bad;
if (!(cow_lv = dm_hash_lookup(lv_hash, cow_lvo->name)))
goto_bad;
init_snapshot_seg(seg, origin_lv, cow_lv, sego->chunk_size,
(sego->status & MERGING) ? 1 : 0);
} else if (seg_is_writecache(sego)) {
struct logical_volume *origin_lvo;
struct logical_volume *fast_lvo;
struct logical_volume *origin_lv;
struct logical_volume *fast_lv;
/* see _writecache_text_import */
if (!(origin_lvo = get_origin_from_writecache(lvo)))
goto_bad;
if (!(fast_lvo = get_fast_from_writecache(lvo)))
goto_bad;
if (!(origin_lv = dm_hash_lookup(lv_hash, origin_lvo->name)))
goto_bad;
if (!(fast_lv = dm_hash_lookup(lv_hash, fast_lvo->name)))
goto_bad;
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
return_0;
seg->writecache_block_size = sego->writecache_block_size;
seg->origin = origin_lv;
seg->writecache = fast_lv;
if (!add_seg_to_segs_using_this_lv(fast_lv, seg))
return_0;
memcpy(&seg->writecache_settings, &sego->writecache_settings, sizeof(seg->writecache_settings));
if (sego->writecache_settings.new_key &&
!(seg->writecache_settings.new_key = dm_pool_strdup(vg->vgmem, sego->writecache_settings.new_key)))
goto_bad;
if (sego->writecache_settings.new_val &&
!(seg->writecache_settings.new_val = dm_pool_strdup(vg->vgmem, sego->writecache_settings.new_val)))
goto_bad;
} else if (seg_is_raid(sego)) {
struct logical_volume *area_lvo;
struct logical_volume *area_lv;
/* see _raid_text_import_areas */
seg->region_size = sego->region_size;
seg->stripe_size = sego->stripe_size;
seg->data_copies = sego->data_copies;
seg->writebehind = sego->writebehind;
seg->min_recovery_rate = sego->min_recovery_rate;
seg->max_recovery_rate = sego->max_recovery_rate;
seg->data_offset = sego->data_offset;
seg->reshape_len = sego->reshape_len;
for (s = 0; s < sego->area_count; s++) {
if (!(area_lvo = sego->areas[s].u.lv.lv))
goto_bad;
if (!(area_lv = dm_hash_lookup(lv_hash, area_lvo->name)))
goto_bad;
if (!set_lv_segment_area_lv(seg, s, area_lv, 0, RAID_IMAGE))
goto_bad;
if (!sego->meta_areas)
continue;
if (!(area_lvo = sego->meta_areas[s].u.lv.lv))
continue;
if (!(area_lv = dm_hash_lookup(lv_hash, area_lvo->name)))
goto_bad;
if (!set_lv_segment_area_lv(seg, s, area_lv, 0, RAID_META))
goto_bad;
}
} else if (seg_is_vdo_pool(sego)) {
struct logical_volume *data_lvo;
struct logical_volume *data_lv;
if (!(data_lvo = get_data_from_pool(lvo)))
goto_bad;
if (!(data_lv = dm_hash_lookup(lv_hash, data_lvo->name)))
goto_bad;
seg->vdo_pool_header_size = sego->vdo_pool_header_size;
seg->vdo_pool_virtual_extents = sego->vdo_pool_virtual_extents;
memcpy(&seg->vdo_params, &sego->vdo_params, sizeof(seg->vdo_params));
if (!set_lv_segment_area_lv(seg, 0, data_lv, 0, LV_VDO_POOL_DATA))
goto_bad;
} else if (seg_is_vdo(sego)) {
struct logical_volume *pool_lvo;
struct logical_volume *pool_lv;
uint32_t vdo_offset;
if (!(pool_lvo = get_pool_from_vdo(lvo)))
goto_bad;
if (!(pool_lv = dm_hash_lookup(lv_hash, pool_lvo->name)))
goto_bad;
vdo_offset = sego->areas[0].u.lv.le; /* or seg_le(seg, 0)) */
if (!set_lv_segment_area_lv(seg, 0, pool_lv, vdo_offset, LV_VDO_POOL))
goto_bad;
} else if (seg_is_zero(sego) || seg_is_error(sego)) {
/* nothing to copy */
} else {
log_error("Missing copy for lv %s segtype %s.",
display_lvname(lvo), sego->segtype->name);
goto bad;
}
return seg;
bad:
return NULL;
}
/* _read_lvsegs, _read_segments, _read_segment, alloc_lv_segment, ->text_import */
static int _lvsegs_copy_struct(struct volume_group *vg,
struct logical_volume *lv,
struct volume_group *vgo,
struct logical_volume *lvo,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash)
{
struct lv_segment *sego;
struct lv_segment *seg;
/* see _read_segment */
dm_list_iterate_items(sego, &lvo->segments) {
/* see _read_segment */
if (!(seg = _seg_copy_struct(vg, lv, vgo, lvo, sego, pv_hash, lv_hash)))
goto_bad;
/* last step in _read_segment */
/* adds seg to lv->segments and sets lv->le_count */
insert_segment(lv, seg);
}
return 1;
bad:
return 0;
}
static struct logical_volume *_lv_copy_struct(struct volume_group *vg,
struct volume_group *vgo,
struct logical_volume *lvo,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash)
{
struct dm_pool *mem = vg->vgmem;
struct logical_volume *lv;
if (!(lv = alloc_lv(mem)))
return NULL;
if (!(lv->name = dm_pool_strdup(mem, lvo->name)))
goto_bad;
if (lvo->profile && !(lv->profile = add_profile(lvo->vg->cmd, lvo->profile->name, CONFIG_PROFILE_METADATA)))
goto_bad;
if (lvo->hostname && !(lv->hostname = dm_pool_strdup(mem, lvo->hostname)))
goto_bad;
if (lvo->lock_args && !(lv->lock_args = dm_pool_strdup(mem, lvo->lock_args)))
goto_bad;
if (!dm_list_empty(&lvo->tags) && !str_list_dup(mem, &lv->tags, &lvo->tags))
goto_bad;
memcpy(&lv->lvid, &lvo->lvid, sizeof(lvo->lvid));
lv->vg = vg;
lv->status = lvo->status;
lv->alloc = lvo->alloc;
lv->read_ahead = lvo->read_ahead;
lv->major = lvo->major;
lv->minor = lvo->minor;
lv->size = lvo->size;
/* lv->le_count = lvo->le_count; */ /* set by calls to insert_segment() */
lv->origin_count = lvo->origin_count;
lv->external_count = lvo->external_count;
lv->timestamp = lvo->timestamp;
if (!dm_hash_insert(lv_hash, lv->name, lv))
goto_bad;
return lv;
bad:
return NULL;
}
/* _read_pv */
static struct physical_volume *_pv_copy_struct(struct volume_group *vg, struct volume_group *vgo,
struct physical_volume *pvo, struct dm_hash_table *pv_hash)
{
struct dm_pool *mem = vg->vgmem;
struct physical_volume *pv;
if (!(pv = dm_pool_zalloc(mem, sizeof(*pv))))
return_NULL;
if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
goto_bad;
pv->is_labelled = pvo->is_labelled;
memcpy(&pv->id, &pvo->id, sizeof(struct id));
memcpy(&pv->vg_id, &vgo->id, sizeof(struct id));
pv->status = pvo->status;
pv->size = pvo->size;
if (pvo->device_hint && !(pv->device_hint = dm_pool_strdup(mem, pvo->device_hint)))
goto_bad;
if (pvo->device_id && !(pv->device_id = dm_pool_strdup(mem, pvo->device_id)))
goto_bad;
if (pvo->device_id_type && !(pv->device_id_type = dm_pool_strdup(mem, pvo->device_id_type)))
goto_bad;
pv->pe_start = pvo->pe_start;
pv->pe_count = pvo->pe_count;
pv->ba_start = pvo->ba_start;
pv->ba_size = pvo->ba_size;
dm_list_init(&pv->tags);
dm_list_init(&pv->segments);
if (!dm_list_empty(&pvo->tags) && !str_list_dup(mem, &pv->tags, &pvo->tags))
goto_bad;
pv->pe_size = vg->extent_size;
pv->pe_alloc_count = 0;
pv->pe_align = 0;
/* Note: text import uses "pv0" style keys rather than pv id. */
if (!dm_hash_insert_binary(pv_hash, &pv->id, ID_LEN, pv))
goto_bad;
return pv;
bad:
return NULL;
}
/*
* We only need to copy things that are exported to metadata text.
* This struct copy is an alternative to text export+import, so the
* the reference for what to copy are the text export and import
* functions.
*
* There are two parts to copying the struct:
* 1. Setting the values, e.g. new->field = old->field.
* 2. Creating the linkages (pointers/lists) among all of
* the new structs.
*
* Creating the linkages is the complex part, and for that we use
* most of the same functions that text import uses.
*
* In some cases, the functions creating linkage also set values.
* This is not common, but in those cases we need to be careful.
*
* Many parts of the vg struct are not used by the activation code,
* but it's difficult to know exactly what is or isn't used, so we
* try to copy everything, except in cases where we know it's not
* used and implementing it would be complicated.
*/
struct volume_group *vg_copy_struct(struct volume_group *vgo)
{
struct volume_group *vg;
struct logical_volume *lv;
struct pv_list *pvlo;
struct pv_list *pvl;
struct lv_list *lvlo;
struct lv_list *lvl;
struct dm_hash_table *pv_hash = NULL;
struct dm_hash_table *lv_hash = NULL;
if (!(vg = alloc_vg("read_vg", vgo->cmd, vgo->name)))
return NULL;
log_debug("Copying vg struct %p to %p", vgo, vg);
/*
* TODO: put hash tables in vg struct, and also use for text import.
*/
if (!(pv_hash = dm_hash_create(58)))
goto_bad;
if (!(lv_hash = dm_hash_create(8180)))
goto_bad;
vg->seqno = vgo->seqno;
vg->alloc = vgo->alloc;
vg->status = vgo->status;
vg->id = vgo->id;
vg->extent_size = vgo->extent_size;
vg->max_lv = vgo->max_lv;
vg->max_pv = vgo->max_pv;
vg->pv_count = vgo->pv_count;
vg->open_mode = vgo->open_mode;
vg->mda_copies = vgo->mda_copies;
if (vgo->profile && !(vg->profile = add_profile(vgo->cmd, vgo->profile->name, CONFIG_PROFILE_METADATA)))
goto_bad;
if (vgo->system_id && !(vg->system_id = dm_pool_strdup(vg->vgmem, vgo->system_id)))
goto_bad;
if (vgo->lock_type && !(vg->lock_type = dm_pool_strdup(vg->vgmem, vgo->lock_type)))
goto_bad;
if (vgo->lock_args && !(vg->lock_args = dm_pool_strdup(vg->vgmem, vgo->lock_args)))
goto_bad;
if (!dm_list_empty(&vgo->tags) && !str_list_dup(vg->vgmem, &vg->tags, &vgo->tags))
goto_bad;
dm_list_iterate_items(pvlo, &vgo->pvs) {
if (!(pvl = dm_pool_zalloc(vg->vgmem, sizeof(struct pv_list))))
goto_bad;
if (!(pvl->pv = _pv_copy_struct(vg, vgo, pvlo->pv, pv_hash)))
goto_bad;
if (!alloc_pv_segment_whole_pv(vg->vgmem, pvl->pv))
goto_bad;
vg->extent_count += pvl->pv->pe_count;
vg->free_count += pvl->pv->pe_count;
add_pvl_to_vgs(vg, pvl);
}
dm_list_iterate_items(lvlo, &vgo->lvs) {
if (!(lvl = dm_pool_zalloc(vg->vgmem, sizeof(struct lv_list))))
goto_bad;
if (!(lvl->lv = _lv_copy_struct(vg, vgo, lvlo->lv, pv_hash, lv_hash)))
goto_bad;
dm_list_add(&vg->lvs, &lvl->list);
}
if (vgo->pool_metadata_spare_lv &&
!(vg->pool_metadata_spare_lv = dm_hash_lookup(lv_hash, vgo->pool_metadata_spare_lv->name)))
goto_bad;
if (vgo->sanlock_lv &&
!(vg->sanlock_lv = dm_hash_lookup(lv_hash, vgo->sanlock_lv->name)))
goto_bad;
dm_list_iterate_items(lvlo, &vgo->lvs) {
if (!(lv = dm_hash_lookup(lv_hash, lvlo->lv->name)))
goto_bad;
if (!_lvsegs_copy_struct(vg, lv, vgo, lvlo->lv, pv_hash, lv_hash))
goto_bad;
}
/* sanity check */
if ((vg->free_count != vgo->free_count) || (vg->extent_count != vgo->extent_count)) {
log_error("vg copy wrong free_count %u %u extent_count %u %u",
vgo->free_count, vg->free_count, vgo->extent_count, vg->extent_count);
goto_bad;
}
set_pv_devices(vgo->fid, vg);
dm_hash_destroy(pv_hash);
dm_hash_destroy(lv_hash);
return vg;
bad:
dm_hash_destroy(pv_hash);
dm_hash_destroy(lv_hash);
release_vg(vg);
return NULL;
}

View File

@@ -18,6 +18,130 @@
#include "lib/misc/crc.h"
#include "lib/mm/xlate.h"
/*
* CRC-32 byte lookup table generated by crc_gen.c
*
* Precomputed lookup table for CRC computed with 0xedb88320 polynomial.
*/
static const uint32_t _crctab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
#ifdef __x86_64__
/*
* Note that the CRC-32 checksum is merely used for error detection in
* transmission and storage. It is not intended to guard against the malicious
* modification of files (i.e., it is not a cryptographic hash). !!!
*
* This code is based on zlib code from:
*
* https://github.com/vlastavesely/crc32sum
* https://github.com/chromium/chromium/blob/master/third_party/zlib/
*
* SPDX-License-Identifier: GPL-2.0
*/
/*
* ATM Use this code only for X86_64 arch where it was tested
* TODO: check if it speeds also non X86_64 arch
*/
static unsigned int _crc32_lookup[16][256] = { 0 };
static void _initialise_crc32(void)
{
unsigned int i, j;
if (_crc32_lookup[0][1])
return;
for (i = 0; i < 256; i++)
_crc32_lookup[0][i] = _crctab[i];
for (i = 0; i < 256; i++)
for (j = 1; j < 16; j++)
_crc32_lookup[j][i] = (_crc32_lookup[j - 1][i] >> 8) ^
_crc32_lookup[0][_crc32_lookup[j - 1][i] & 0xff];
}
#ifndef DEBUG_CRC32
uint32_t calc_crc(uint32_t initial, const uint8_t *buf, uint32_t size)
#else
static uint32_t _calc_crc_new(uint32_t initial, const uint8_t *buf, uint32_t size)
#endif
{
const uint32_t *ptr = (const uint32_t *) buf;
uint32_t a, b, c, d;
uint32_t crc = initial;
_initialise_crc32();
for (;size >= 16; size -= 16) {
a = xlate32(*ptr++) ^ crc;
b = xlate32(*ptr++);
c = xlate32(*ptr++);
d = xlate32(*ptr++);
crc = _crc32_lookup[ 0][(d >> 24) & 0xff] ^
_crc32_lookup[ 1][(d >> 16) & 0xff] ^
_crc32_lookup[ 2][(d >> 8) & 0xff] ^
_crc32_lookup[ 3][ d & 0xff] ^
_crc32_lookup[ 4][(c >> 24) & 0xff] ^
_crc32_lookup[ 5][(c >> 16) & 0xff] ^
_crc32_lookup[ 6][(c >> 8) & 0xff] ^
_crc32_lookup[ 7][ c & 0xff] ^
_crc32_lookup[ 8][(b >> 24) & 0xff] ^
_crc32_lookup[ 9][(b >> 16) & 0xff] ^
_crc32_lookup[10][(b >> 8) & 0xff] ^
_crc32_lookup[11][ b & 0xff] ^
_crc32_lookup[12][(a >> 24) & 0xff] ^
_crc32_lookup[13][(a >> 16) & 0xff] ^
_crc32_lookup[14][(a >> 8) & 0xff] ^
_crc32_lookup[15][ a & 0xff];
}
buf = (const uint8_t *) ptr;
while (size--)
crc = _crc32_lookup[0][((unsigned char) crc ^ *(buf++))] ^ (crc >> 8);
return crc;
}
#else // __x86_64__
/* Calculate an endian-independent CRC of supplied buffer */
#ifndef DEBUG_CRC32
uint32_t calc_crc(uint32_t initial, const uint8_t *buf, uint32_t size)
@@ -25,41 +149,6 @@ uint32_t calc_crc(uint32_t initial, const uint8_t *buf, uint32_t size)
static uint32_t _calc_crc_new(uint32_t initial, const uint8_t *buf, uint32_t size)
#endif
{
/* CRC-32 byte lookup table generated by crc_gen.c */
static const uint32_t _crctab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
const uint32_t *start = (const uint32_t *) buf;
const uint32_t *end = (const uint32_t *) (buf + (size & 0xfffffffc));
uint32_t crc = initial;
@@ -84,6 +173,8 @@ static uint32_t _calc_crc_new(uint32_t initial, const uint8_t *buf, uint32_t siz
return crc;
}
#endif // __x86_64__
#ifdef DEBUG_CRC32
static uint32_t _calc_crc_old(uint32_t initial, const uint8_t *buf, uint32_t size)
{