1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Replicator: libdm support

Introducing new API calls:
dm_tree_node_add_replicator_target()
dm_tree_node_add_replicator_dev_target().

Define new typedef dm_replicator_mode_t.
This commit is contained in:
Zdenek Kabelac 2010-05-21 12:24:15 +00:00
parent 04a6dd7731
commit b262f3e19e
4 changed files with 329 additions and 5 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.67 - Version 2.02.67 -
=============================== ===============================
Initial libdm support for Replicator target (API is not stable yet).
Extend process_each_lv_in_vg() with support for list of failed lvnames. Extend process_each_lv_in_vg() with support for list of failed lvnames.
Return ECMD_FAILED for break in process_each_lv() and process_each_segment_in_lv(). Return ECMD_FAILED for break in process_each_lv() and process_each_segment_in_lv().

View File

@ -80,6 +80,8 @@ dm_tree_node_add_crypt_target
dm_tree_node_add_mirror_target dm_tree_node_add_mirror_target
dm_tree_node_add_mirror_target_log dm_tree_node_add_mirror_target_log
dm_tree_node_add_target_area dm_tree_node_add_target_area
dm_tree_node_add_replicator_target
dm_tree_node_add_replicator_dev_target
dm_tree_node_set_read_ahead dm_tree_node_set_read_ahead
dm_tree_skip_lockfs dm_tree_skip_lockfs
dm_tree_use_no_flush_suspend dm_tree_use_no_flush_suspend

View File

@ -439,6 +439,41 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
const char *log_uuid, const char *log_uuid,
unsigned area_count, unsigned area_count,
uint32_t flags); uint32_t flags);
/*
* Replicator operation mode
* Note: API for Replicator is not yet stable
*/
typedef enum {
DM_REPLICATOR_SYNC, /* Synchronous replication */
DM_REPLICATOR_ASYNC_WARN, /* Warn if async replicator is slow */
DM_REPLICATOR_ASYNC_STALL, /* Stall replicator if not fast enough */
DM_REPLICATOR_ASYNC_DROP, /* Drop sites out of sync */
DM_REPLICATOR_ASYNC_FAIL, /* Fail replicator if slow */
NUM_DM_REPLICATOR_MODES
} dm_replicator_mode_t;
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
uint64_t size,
const char *rlog_uuid,
const char *rlog_type,
unsigned rsite_index,
dm_replicator_mode_t mode,
uint32_t async_timeout,
uint64_t fall_behind_data,
uint32_t fall_behind_ios);
int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
uint64_t size,
const char *replicator_uuid, /* Replicator control device */
uint64_t rdevice_index,
const char *rdev_uuid, /* Rimage device name/uuid */
unsigned rsite_index,
const char *slog_uuid,
uint32_t slog_flags, /* Mirror log flags */
uint32_t slog_region_size);
/* End of Replicator API */
int dm_tree_node_add_target_area(struct dm_tree_node *node, int dm_tree_node_add_target_area(struct dm_tree_node *node,
const char *dev_name, const char *dev_name,
const char *dlid, const char *dlid,

View File

@ -27,12 +27,16 @@
/* FIXME Fix interface so this is used only by LVM */ /* FIXME Fix interface so this is used only by LVM */
#define UUID_PREFIX "LVM-" #define UUID_PREFIX "LVM-"
#define REPLICATOR_LOCAL_SITE 0
/* Supported segment types */ /* Supported segment types */
enum { enum {
SEG_CRYPT, SEG_CRYPT,
SEG_ERROR, SEG_ERROR,
SEG_LINEAR, SEG_LINEAR,
SEG_MIRRORED, SEG_MIRRORED,
SEG_REPLICATOR,
SEG_REPLICATOR_DEV,
SEG_SNAPSHOT, SEG_SNAPSHOT,
SEG_SNAPSHOT_ORIGIN, SEG_SNAPSHOT_ORIGIN,
SEG_SNAPSHOT_MERGE, SEG_SNAPSHOT_MERGE,
@ -50,6 +54,8 @@ struct {
{ SEG_ERROR, "error" }, { SEG_ERROR, "error" },
{ SEG_LINEAR, "linear" }, { SEG_LINEAR, "linear" },
{ SEG_MIRRORED, "mirror" }, { SEG_MIRRORED, "mirror" },
{ SEG_REPLICATOR, "replicator" },
{ SEG_REPLICATOR_DEV, "replicator-dev" },
{ SEG_SNAPSHOT, "snapshot" }, { SEG_SNAPSHOT, "snapshot" },
{ SEG_SNAPSHOT_ORIGIN, "snapshot-origin" }, { SEG_SNAPSHOT_ORIGIN, "snapshot-origin" },
{ SEG_SNAPSHOT_MERGE, "snapshot-merge" }, { SEG_SNAPSHOT_MERGE, "snapshot-merge" },
@ -64,6 +70,23 @@ struct seg_area {
struct dm_tree_node *dev_node; struct dm_tree_node *dev_node;
uint64_t offset; uint64_t offset;
unsigned rsite_index; /* Replicator site index */
struct dm_tree_node *slog; /* Replicator sync log node */
uint64_t region_size; /* Replicator sync log size */
uint32_t flags; /* Replicator sync log flags */
};
/* Replicator-log has a list of sites */
/* FIXME: maybe move to seg_area too? */
struct replicator_site {
struct dm_list list;
unsigned rsite_index;
dm_replicator_mode_t mode;
uint32_t async_timeout;
uint32_t fall_behind_ios;
uint64_t fall_behind_data;
}; };
/* Per-segment properties */ /* Per-segment properties */
@ -74,8 +97,8 @@ struct load_segment {
uint64_t size; uint64_t size;
unsigned area_count; /* Linear + Striped + Mirrored + Crypt */ unsigned area_count; /* Linear + Striped + Mirrored + Crypt + Replicator */
struct dm_list areas; /* Linear + Striped + Mirrored + Crypt */ struct dm_list areas; /* Linear + Striped + Mirrored + Crypt + Replicator */
uint32_t stripe_size; /* Striped */ uint32_t stripe_size; /* Striped */
@ -85,7 +108,7 @@ struct load_segment {
struct dm_tree_node *origin; /* Snapshot + Snapshot origin */ struct dm_tree_node *origin; /* Snapshot + Snapshot origin */
struct dm_tree_node *merge; /* Snapshot */ struct dm_tree_node *merge; /* Snapshot */
struct dm_tree_node *log; /* Mirror */ struct dm_tree_node *log; /* Mirror + Replicator */
uint32_t region_size; /* Mirror */ uint32_t region_size; /* Mirror */
unsigned clustered; /* Mirror */ unsigned clustered; /* Mirror */
unsigned mirror_area_count; /* Mirror */ unsigned mirror_area_count; /* Mirror */
@ -97,6 +120,13 @@ struct load_segment {
const char *iv; /* Crypt */ const char *iv; /* Crypt */
uint64_t iv_offset; /* Crypt */ uint64_t iv_offset; /* Crypt */
const char *key; /* Crypt */ const char *key; /* Crypt */
const char *rlog_type; /* Replicator */
struct dm_list rsites; /* Replicator */
unsigned rsite_count; /* Replicator */
unsigned rdevice_count; /* Replicator */
struct dm_tree_node *replicator;/* Replicator-dev */
uint64_t rdevice_index; /* Replicator-dev */
}; };
/* Per-device properties */ /* Per-device properties */
@ -1342,13 +1372,51 @@ static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
struct seg_area *area; struct seg_area *area;
char devbuf[DM_FORMAT_DEV_BUFSIZE]; char devbuf[DM_FORMAT_DEV_BUFSIZE];
unsigned first_time = 1; unsigned first_time = 1;
const char *logtype;
unsigned log_parm_count;
dm_list_iterate_items(area, &seg->areas) { dm_list_iterate_items(area, &seg->areas) {
if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node)) if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
return_0; return_0;
switch (seg->type) {
case SEG_REPLICATOR_DEV:
EMIT_PARAMS(*pos, " %d 1 %s", area->rsite_index, devbuf);
if (first_time)
EMIT_PARAMS(*pos, " nolog 0");
else {
/* Remote devices */
log_parm_count = (area->flags &
(DM_NOSYNC | DM_FORCESYNC)) ? 2 : 1;
if (!area->slog) {
devbuf[0] = 0; /* Only core log parameters */
logtype = "core";
} else {
devbuf[0] = ' '; /* Extra space before device name */
if (!_build_dev_string(devbuf + 1,
sizeof(devbuf) - 1,
area->slog))
return_0;
logtype = "disk";
log_parm_count++; /* Extra sync log device name parameter */
}
EMIT_PARAMS(*pos, " %s %u%s %" PRIu64, logtype,
log_parm_count, devbuf, area->region_size);
logtype = (area->flags & DM_NOSYNC) ?
" nosync" : (area->flags & DM_FORCESYNC) ?
" sync" : NULL;
if (logtype)
EMIT_PARAMS(*pos, logtype);
}
break;
default:
EMIT_PARAMS(*pos, "%s%s %" PRIu64, first_time ? "" : " ", EMIT_PARAMS(*pos, "%s%s %" PRIu64, first_time ? "" : " ",
devbuf, area->offset); devbuf, area->offset);
}
first_time = 0; first_time = 0;
} }
@ -1356,6 +1424,42 @@ static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
return 1; return 1;
} }
static int _replicator_emit_segment_line(const struct load_segment *seg, char *params,
size_t paramsize, int *pos)
{
const struct load_segment *rlog_seg;
struct replicator_site *rsite;
char rlogbuf[DM_FORMAT_DEV_BUFSIZE];
unsigned parm_count;
if (!seg->log || !_build_dev_string(rlogbuf, sizeof(rlogbuf), seg->log))
return_0;
rlog_seg = dm_list_item(dm_list_last(&seg->log->props.segs),
struct load_segment);
EMIT_PARAMS(*pos, "%s 4 %s 0 auto %" PRIu64,
seg->rlog_type, rlogbuf, rlog_seg->size);
dm_list_iterate_items(rsite, &seg->rsites) {
parm_count = (rsite->fall_behind_data
|| rsite->fall_behind_ios
|| rsite->async_timeout) ? 4 : 2;
EMIT_PARAMS(*pos, " blockdev %u %u %s", parm_count, rsite->rsite_index,
(rsite->mode == DM_REPLICATOR_SYNC) ? "synchronous" : "asynchronous");
if (rsite->fall_behind_data)
EMIT_PARAMS(*pos, " data %" PRIu64, rsite->fall_behind_data);
else if (rsite->fall_behind_ios)
EMIT_PARAMS(*pos, " ios %" PRIu32, rsite->fall_behind_ios);
else if (rsite->async_timeout)
EMIT_PARAMS(*pos, " timeout %" PRIu32, rsite->async_timeout);
}
return 1;
}
/* /*
* Returns: 1 on success, 0 on failure * Returns: 1 on success, 0 on failure
*/ */
@ -1499,6 +1603,21 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
if (!r) if (!r)
return_0; return_0;
break; break;
case SEG_REPLICATOR:
if ((r = _replicator_emit_segment_line(seg, params, paramsize,
&pos)) <= 0) {
stack;
return r;
}
break;
case SEG_REPLICATOR_DEV:
if (!seg->replicator || !_build_dev_string(originbuf,
sizeof(originbuf),
seg->replicator))
return_0;
EMIT_PARAMS(pos, "%s %" PRIu64, originbuf, seg->rdevice_index);
break;
case SEG_SNAPSHOT: case SEG_SNAPSHOT:
case SEG_SNAPSHOT_MERGE: case SEG_SNAPSHOT_MERGE:
if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin)) if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
@ -1527,6 +1646,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
switch(seg->type) { switch(seg->type) {
case SEG_ERROR: case SEG_ERROR:
case SEG_REPLICATOR:
case SEG_SNAPSHOT: case SEG_SNAPSHOT:
case SEG_SNAPSHOT_ORIGIN: case SEG_SNAPSHOT_ORIGIN:
case SEG_SNAPSHOT_MERGE: case SEG_SNAPSHOT_MERGE:
@ -1534,6 +1654,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
break; break;
case SEG_CRYPT: case SEG_CRYPT:
case SEG_LINEAR: case SEG_LINEAR:
case SEG_REPLICATOR_DEV:
case SEG_STRIPED: case SEG_STRIPED:
if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0) { if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0) {
stack; stack;
@ -1996,6 +2117,171 @@ int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
return 1; return 1;
} }
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
uint64_t size,
const char *rlog_uuid,
const char *rlog_type,
unsigned rsite_index,
dm_replicator_mode_t mode,
uint32_t async_timeout,
uint64_t fall_behind_data,
uint32_t fall_behind_ios)
{
struct load_segment *rseg;
struct replicator_site *rsite;
/* Local site0 - adds replicator segment and links rlog device */
if (rsite_index == REPLICATOR_LOCAL_SITE) {
if (node->props.segment_count) {
log_error(INTERNAL_ERROR "Attempt to add replicator segment to already used node.");
return 0;
}
if (!(rseg = _add_segment(node, SEG_REPLICATOR, size)))
return_0;
if (!(rseg->log = dm_tree_find_node_by_uuid(node->dtree, rlog_uuid))) {
log_error("Missing replicator log uuid %s.", rlog_uuid);
return 0;
}
if (!_link_tree_nodes(node, rseg->log))
return_0;
if (strcmp(rlog_type, "ringbuffer") != 0) {
log_error("Unsupported replicator log type %s.", rlog_type);
return 0;
}
if (!(rseg->rlog_type = dm_pool_strdup(node->dtree->mem, rlog_type)))
return_0;
dm_list_init(&rseg->rsites);
rseg->rdevice_count = 0;
node->activation_priority = 1;
}
/* Add site to segment */
if (mode == DM_REPLICATOR_SYNC
&& (async_timeout || fall_behind_ios || fall_behind_data)) {
log_error("Async parameters passed for synchronnous replicator.");
return 0;
}
if (node->props.segment_count != 1) {
log_error(INTERNAL_ERROR "Attempt to add remote site area before setting replicator log.");
return 0;
}
rseg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
if (rseg->type != SEG_REPLICATOR) {
log_error(INTERNAL_ERROR "Attempt to use non replicator segment %s.",
dm_segtypes[rseg->type].target);
return 0;
}
if (!(rsite = dm_pool_zalloc(node->dtree->mem, sizeof(*rsite)))) {
log_error("Failed to allocate remote site segment.");
return 0;
}
dm_list_add(&rseg->rsites, &rsite->list);
rseg->rsite_count++;
rsite->mode = mode;
rsite->async_timeout = async_timeout;
rsite->fall_behind_data = fall_behind_data;
rsite->fall_behind_ios = fall_behind_ios;
rsite->rsite_index = rsite_index;
return 1;
}
/* Appends device node to Replicator */
int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
uint64_t size,
const char *replicator_uuid,
uint64_t rdevice_index,
const char *rdev_uuid,
unsigned rsite_index,
const char *slog_uuid,
uint32_t slog_flags,
uint32_t slog_region_size)
{
struct seg_area *area;
struct load_segment *rseg;
struct load_segment *rep_seg;
if (rsite_index == REPLICATOR_LOCAL_SITE) {
/* Site index for local target */
if (!(rseg = _add_segment(node, SEG_REPLICATOR_DEV, size)))
return_0;
if (!(rseg->replicator = dm_tree_find_node_by_uuid(node->dtree, replicator_uuid))) {
log_error("Missing replicator uuid %s.", replicator_uuid);
return 0;
}
/* Local slink0 for replicator must be always initialized first */
if (rseg->replicator->props.segment_count != 1) {
log_error(INTERNAL_ERROR "Attempt to use non replicator segment.");
return 0;
}
rep_seg = dm_list_item(dm_list_last(&rseg->replicator->props.segs), struct load_segment);
if (rep_seg->type != SEG_REPLICATOR) {
log_error(INTERNAL_ERROR "Attempt to use non replicator segment %s.",
dm_segtypes[rep_seg->type].target);
return 0;
}
rep_seg->rdevice_count++;
if (!_link_tree_nodes(node, rseg->replicator))
return_0;
rseg->rdevice_index = rdevice_index;
} else {
/* Local slink0 for replicator must be always initialized first */
if (node->props.segment_count != 1) {
log_error(INTERNAL_ERROR "Attempt to use non replicator-dev segment.");
return 0;
}
rseg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
if (rseg->type != SEG_REPLICATOR_DEV) {
log_error(INTERNAL_ERROR "Attempt to use non replicator-dev segment %s.",
dm_segtypes[rseg->type].target);
return 0;
}
}
if (!(slog_flags & DM_CORELOG) && !slog_uuid) {
log_error("Unspecified sync log uuid.");
return 0;
}
if (!dm_tree_node_add_target_area(node, NULL, rdev_uuid, 0))
return_0;
area = dm_list_item(dm_list_last(&rseg->areas), struct seg_area);
if (!(slog_flags & DM_CORELOG)) {
if (!(area->slog = dm_tree_find_node_by_uuid(node->dtree, slog_uuid))) {
log_error("Couldn't find sync log uuid %s.", slog_uuid);
return 0;
}
if (!_link_tree_nodes(node, area->slog))
return_0;
}
area->flags = slog_flags;
area->region_size = slog_region_size;
area->rsite_index = rsite_index;
return 1;
}
static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset) static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset)
{ {
struct seg_area *area; struct seg_area *area;