mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-03 01:44:19 +03:00
Compare commits
10 Commits
v2_03_35
...
dev-perf-2
Author | SHA1 | Date | |
---|---|---|---|
|
fadcb63a43 | ||
|
ca74ba6f16 | ||
|
7b6a800e4f | ||
|
c22ed72e7d | ||
|
faf5fddbec | ||
|
f4dc2b9aa3 | ||
|
6de4590cf9 | ||
|
8bfbb623d7 | ||
|
77305127e4 | ||
|
18babdc3ac |
@@ -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.
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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"
|
||||
|
@@ -344,4 +344,6 @@
|
||||
|
||||
#define DEFAULT_DEVICESFILE_BACKUP_LIMIT 50
|
||||
|
||||
#define DEFAULT_VG_COPY_INTERNAL "binary"
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
161
lib/misc/crc.c
161
lib/misc/crc.c
@@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user