* LVM2 ./WHATS_NEW lib/Makefile.in lib/activate/ ...
@ 2009-10-16 17:41 mornfall
2009-10-16 17:55 ` Alasdair G Kergon
0 siblings, 1 reply; 3+ messages in thread
From: mornfall @ 2009-10-16 17:41 UTC (permalink / raw)
To: lvm-devel
CVSROOT: /cvs/lvm2
Module name: LVM2
Changes by: mornfall at sourceware.org 2009-10-16 17:41:53
Modified files:
. : WHATS_NEW
lib : Makefile.in
lib/activate : activate.c
lib/commands : toolcontext.c toolcontext.h
lib/config : config.c config.h
lib/format_text: export.c text_export.h
lib/metadata : metadata-exported.h metadata.c segtype.c
segtype.h
tools : vgcfgrestore.c
Added files:
lib/unknown : unknown.c
test : t-unknown-segment.sh
Log message:
Handle metadata with unknown segment types more gracefully.
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1296&r2=1.1297
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/Makefile.in.diff?cvsroot=lvm2&r1=1.95&r2=1.96
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/activate/activate.c.diff?cvsroot=lvm2&r1=1.156&r2=1.157
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/commands/toolcontext.c.diff?cvsroot=lvm2&r1=1.85&r2=1.86
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/commands/toolcontext.h.diff?cvsroot=lvm2&r1=1.34&r2=1.35
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/config/config.c.diff?cvsroot=lvm2&r1=1.75&r2=1.76
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/config/config.h.diff?cvsroot=lvm2&r1=1.28&r2=1.29
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_text/export.c.diff?cvsroot=lvm2&r1=1.69&r2=1.70
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_text/text_export.h.diff?cvsroot=lvm2&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.116&r2=1.117
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.290&r2=1.291
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/segtype.c.diff?cvsroot=lvm2&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/segtype.h.diff?cvsroot=lvm2&r1=1.25&r2=1.26
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/unknown/unknown.c.diff?cvsroot=lvm2&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-unknown-segment.sh.diff?cvsroot=lvm2&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/vgcfgrestore.c.diff?cvsroot=lvm2&r1=1.23&r2=1.24
--- LVM2/WHATS_NEW 2009/10/14 04:10:41 1.1296
+++ LVM2/WHATS_NEW 2009/10/16 17:41:49 1.1297
@@ -1,5 +1,6 @@
Version 2.02.54 -
=====================================
+ Handle metadata with unknown segment types more gracefully.
Set default owner and group to null.
Add dmeventd.static to the build.
Disable realtime support code by default.
--- LVM2/lib/Makefile.in 2009/10/12 16:59:20 1.95
+++ LVM2/lib/Makefile.in 2009/10/16 17:41:50 1.96
@@ -47,6 +47,7 @@
device/device.c \
display/display.c \
error/errseg.c \
+ unknown/unknown.c \
filters/filter-composite.c \
filters/filter-persistent.c \
filters/filter-regex.c \
--- LVM2/lib/activate/activate.c 2009/10/01 00:35:29 1.156
+++ LVM2/lib/activate/activate.c 2009/10/16 17:41:50 1.157
@@ -1112,6 +1112,12 @@
goto_out;
}
+ if (lv_has_unknown_segments(lv)) {
+ log_error("Refusing activation of LV %s containing "
+ "an unrecognised segment.", lv->name);
+ goto_out;
+ }
+
if (test_mode()) {
_skip("Activating '%s'.", lv->name);
r = 1;
--- LVM2/lib/commands/toolcontext.c 2009/09/28 16:23:45 1.85
+++ LVM2/lib/commands/toolcontext.c 2009/10/16 17:41:50 1.86
@@ -1085,6 +1085,7 @@
memset(cmd, 0, sizeof(*cmd));
cmd->is_long_lived = is_long_lived;
cmd->handles_missing_pvs = 0;
+ cmd->handles_unknown_segments = 0;
cmd->hosttags = 0;
dm_list_init(&cmd->formats);
dm_list_init(&cmd->segtypes);
--- LVM2/lib/commands/toolcontext.h 2009/09/28 16:23:45 1.34
+++ LVM2/lib/commands/toolcontext.h 2009/10/16 17:41:50 1.35
@@ -69,6 +69,7 @@
char **argv;
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
unsigned handles_missing_pvs:1;
+ unsigned handles_unknown_segments:1;
unsigned partial_activation:1;
unsigned si_unit_consistency:1;
--- LVM2/lib/config/config.c 2009/07/27 21:01:56 1.75
+++ LVM2/lib/config/config.c 2009/10/16 17:41:51 1.76
@@ -71,6 +71,8 @@
struct output_line {
FILE *fp;
struct dm_pool *mem;
+ putline_fn putline;
+ void *putline_baton;
};
static void _get_token(struct parser *p, int tok_prev);
@@ -80,8 +82,8 @@
static struct config_value *_value(struct parser *p);
static struct config_value *_type(struct parser *p);
static int _match_aux(struct parser *p, int t);
-static struct config_value *_create_value(struct parser *p);
-static struct config_node *_create_node(struct parser *p);
+static struct config_value *_create_value(struct dm_pool *mem);
+static struct config_node *_create_node(struct dm_pool *mem);
static char *_dup_tok(struct parser *p);
static const int sep = '/';
@@ -403,10 +405,14 @@
}
line = dm_pool_end_object(outline->mem);
- if (!outline->fp)
- log_print("%s", line);
- else
- fprintf(outline->fp, "%s\n", line);
+ if (outline->putline)
+ outline->putline(line, outline->putline_baton);
+ else {
+ if (!outline->fp)
+ log_print("%s", line);
+ else
+ fprintf(outline->fp, "%s\n", line);
+ }
return 1;
}
@@ -498,6 +504,21 @@
return 1;
}
+int write_config_node(struct config_node *cn, putline_fn putline, void *baton)
+{
+ struct output_line outline;
+ outline.fp = NULL;
+ outline.mem = dm_pool_create("config_line", 1024);
+ outline.putline = putline;
+ outline.putline_baton = baton;
+ if (!_write_config(cn, 0, &outline, 0)) {
+ dm_pool_destroy(outline.mem);
+ return_0;
+ }
+ dm_pool_destroy(outline.mem);
+ return 1;
+}
+
int write_config_file(struct config_tree *cft, const char *file,
int argc, char **argv)
{
@@ -505,6 +526,7 @@
int r = 1;
struct output_line outline;
outline.fp = NULL;
+ outline.putline = NULL;
if (!file)
file = "stdout";
@@ -567,7 +589,7 @@
{
/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
struct config_node *root, *n, *l = NULL;
- if (!(root = _create_node(p)))
+ if (!(root = _create_node(p->mem)))
return_0;
if (!(root->key = _dup_tok(p)))
@@ -622,7 +644,7 @@
* Special case for an empty array.
*/
if (!h) {
- if (!(h = _create_value(p)))
+ if (!(h = _create_value(p->mem)))
return NULL;
h->type = CFG_EMPTY_ARRAY;
@@ -637,7 +659,7 @@
static struct config_value *_type(struct parser *p)
{
/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
- struct config_value *v = _create_value(p);
+ struct config_value *v = _create_value(p->mem);
if (!v)
return NULL;
@@ -833,9 +855,9 @@
/*
* memory management
*/
-static struct config_value *_create_value(struct parser *p)
+static struct config_value *_create_value(struct dm_pool *mem)
{
- struct config_value *v = dm_pool_alloc(p->mem, sizeof(*v));
+ struct config_value *v = dm_pool_alloc(mem, sizeof(*v));
if (v)
memset(v, 0, sizeof(*v));
@@ -843,9 +865,9 @@
return v;
}
-static struct config_node *_create_node(struct parser *p)
+static struct config_node *_create_node(struct dm_pool *mem)
{
- struct config_node *n = dm_pool_alloc(p->mem, sizeof(*n));
+ struct config_node *n = dm_pool_alloc(mem, sizeof(*n));
if (n)
memset(n, 0, sizeof(*n));
@@ -1297,3 +1319,33 @@
else
return 0;
}
+
+static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
+{
+ if (!v)
+ return NULL;
+ struct config_value *new = _create_value(mem);
+ new->type = v->type;
+ if (v->type == CFG_STRING)
+ new->v.str = dm_pool_strdup(mem, v->v.str);
+ else
+ new->v = v->v;
+ new->next = _clone_config_value(mem, v->next);
+ return new;
+}
+
+struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
+ int siblings)
+{
+ if (!cn)
+ return NULL;
+ struct config_node *new = _create_node(mem);
+ new->key = dm_pool_strdup(mem, cn->key);
+ new->child = clone_config_node(mem, cn->child, 1);
+ new->v = _clone_config_value(mem, cn->v);
+ if (siblings)
+ new->sib = clone_config_node(mem, cn->sib, siblings);
+ else
+ new->sib = NULL;
+ return new;
+}
--- LVM2/lib/config/config.h 2009/07/27 21:01:58 1.28
+++ LVM2/lib/config/config.h 2009/10/16 17:41:51 1.29
@@ -69,6 +69,10 @@
int read_config_file(struct config_tree *cft);
int write_config_file(struct config_tree *cft, const char *file,
int argc, char **argv);
+
+typedef int (*putline_fn)(const char *line, void *baton);
+int write_config_node(struct config_node *cn, putline_fn putline, void *baton);
+
time_t config_file_timestamp(struct config_tree *cft);
int config_file_changed(struct config_tree *cft);
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
@@ -114,4 +118,6 @@
const char *config_parent_name(const struct config_node *n);
+struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
+ int siblings);
#endif
--- LVM2/lib/format_text/export.c 2009/05/19 09:48:32 1.69
+++ LVM2/lib/format_text/export.c 2009/10/16 17:41:51 1.70
@@ -293,6 +293,16 @@
return r;
}
+static int _out_line(const char *line, void *_f) {
+ struct formatter *f = (struct formatter *) _f;
+ return out_text(f, "%s", line);
+}
+
+int out_config_node(struct formatter *f, const struct config_node *cn)
+{
+ return write_config_node(cn, _out_line, f);
+}
+
static int _print_header(struct formatter *f,
const char *desc)
{
--- LVM2/lib/format_text/text_export.h 2008/03/10 18:51:27 1.4
+++ LVM2/lib/format_text/text_export.h 2009/10/16 17:41:51 1.5
@@ -21,6 +21,7 @@
struct formatter;
struct lv_segment;
+struct config_node;
int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
@@ -31,6 +32,8 @@
int out_text(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
+int out_config_node(struct formatter *f, const struct config_node *cn);
+
int out_areas(struct formatter *f, const struct lv_segment *seg,
const char *type);
--- LVM2/lib/metadata/metadata-exported.h 2009/10/05 20:03:08 1.116
+++ LVM2/lib/metadata/metadata-exported.h 2009/10/16 17:41:52 1.117
@@ -298,6 +298,7 @@
uint32_t region_size; /* For mirrors - in sectors */
uint32_t extents_copied;
struct logical_volume *log_lv;
+ void *segtype_private;
struct dm_list tags;
@@ -734,6 +735,9 @@
#define vg_is_exported(vg) (vg_status((vg)) & EXPORTED_VG)
#define vg_is_resizeable(vg) (vg_status((vg)) & RESIZEABLE_VG)
+int lv_has_unknown_segments(const struct logical_volume *lv);
+int vg_has_unknown_segments(const struct volume_group *vg);
+
struct vgcreate_params {
char *vg_name;
uint32_t extent_size;
--- LVM2/lib/metadata/metadata.c 2009/10/06 16:00:38 1.290
+++ LVM2/lib/metadata/metadata.c 2009/10/16 17:41:52 1.291
@@ -23,6 +23,7 @@
#include "memlock.h"
#include "str_list.h"
#include "pv_alloc.h"
+#include "segtype.h"
#include "activate.h"
#include "display.h"
#include "locking.h"
@@ -738,6 +739,27 @@
return (struct volume_group *)vg;
}
+int lv_has_unknown_segments(const struct logical_volume *lv)
+{
+ struct lv_segment *seg;
+ /* foreach segment */
+ dm_list_iterate_items(seg, &lv->segments)
+ if (seg_unknown(seg))
+ return 1;
+ return 0;
+}
+
+int vg_has_unknown_segments(const struct volume_group *vg)
+{
+ struct lv_list *lvl;
+
+ /* foreach LV */
+ dm_list_iterate_items(lvl, &vg->lvs)
+ if (lv_has_unknown_segments(lvl->lv))
+ return 1;
+ return 0;
+}
+
/*
* Create a VG with default parameters.
* Returns:
@@ -2192,6 +2214,13 @@
return 0;
}
+ if (vg_has_unknown_segments(vg) && !vg->cmd->handles_unknown_segments) {
+ log_error("Cannot update volume group %s with unknown segments in it!",
+ vg->name);
+ return 0;
+ }
+
+
if (dm_list_empty(&vg->fid->metadata_areas)) {
log_error("Aborting vg_write: No metadata areas to write to!");
return 0;
@@ -3317,6 +3346,11 @@
}
}
+ /*
+ * Check that the tool can handle tricky cases -- missing PVs and
+ * unknown segment types.
+ */
+
if (!cmd->handles_missing_pvs && vg_missing_pv_count(vg) &&
(lock_flags & LCK_WRITE)) {
log_error("Cannot change VG %s while PVs are missing!",
@@ -3325,6 +3359,14 @@
goto_bad;
}
+ if (!cmd->handles_unknown_segments && vg_has_unknown_segments(vg) &&
+ (lock_flags & LCK_WRITE)) {
+ log_error("Cannot change VG %s with unknown segments in it!",
+ vg->name);
+ failure |= FAILED_INCONSISTENT; /* FIXME new failure code here? */
+ goto_bad;
+ }
+
failure |= _vg_bad_status_bits(vg, status_flags);
if (failure)
goto_bad;
--- LVM2/lib/metadata/segtype.c 2008/11/03 22:14:29 1.4
+++ LVM2/lib/metadata/segtype.c 2009/10/16 17:41:52 1.5
@@ -27,6 +27,11 @@
return segtype;
}
- log_error("Unrecognised segment type %s", str);
- return NULL;
+ if (!(segtype = init_unknown_segtype(cmd, str)))
+ return_NULL;
+
+ segtype->library = NULL;
+ dm_list_add(&cmd->segtypes, &segtype->list);
+ log_warn("WARNING: Unrecognised segment type %s", str);
+ return segtype;
}
--- LVM2/lib/metadata/segtype.h 2009/10/01 00:35:29 1.25
+++ LVM2/lib/metadata/segtype.h 2009/10/16 17:41:52 1.26
@@ -35,6 +35,7 @@
#define SEG_VIRTUAL 0x00000020U
#define SEG_CANNOT_BE_ZEROED 0x00000040U
#define SEG_MONITORED 0x00000080U
+#define SEG_UNKNOWN 0x80000000U
#define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
#define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
@@ -43,6 +44,7 @@
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
+#define seg_unknown(seg) ((seg)->segtype->flags & SEG_UNKNOWN ? 1 : 0)
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
@@ -105,6 +107,7 @@
struct segment_type *init_zero_segtype(struct cmd_context *cmd);
struct segment_type *init_error_segtype(struct cmd_context *cmd);
struct segment_type *init_free_segtype(struct cmd_context *cmd);
+struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name);
#ifdef SNAPSHOT_INTERNAL
struct segment_type *init_snapshot_segtype(struct cmd_context *cmd);
/cvs/lvm2/LVM2/lib/unknown/unknown.c,v --> standard output
revision 1.1
--- LVM2/lib/unknown/unknown.c
+++ - 2009-10-16 17:41:57.687400000 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "lib.h"
+#include "toolcontext.h"
+#include "segtype.h"
+#include "display.h"
+#include "text_export.h"
+#include "text_import.h"
+#include "config.h"
+#include "str_list.h"
+#include "targets.h"
+#include "lvm-string.h"
+#include "activate.h"
+#include "str_list.h"
+#include "metadata.h"
+
+static const char *_unknown_name(const struct lv_segment *seg)
+{
+
+ return seg->segtype->name;
+}
+
+static int _unknown_text_import(struct lv_segment *seg, const struct config_node *sn,
+ struct dm_hash_table *pv_hash)
+{
+ struct config_node *new, *last = NULL, *current, *head = NULL;
+ log_verbose("importing unknown segment");
+ for (current = sn; current != NULL; current = current->sib) {
+ if (!strcmp(current->key, "type") || !strcmp(current->key, "start_extent") ||
+ !strcmp(current->key, "tags") || !strcmp(current->key, "extent_count"))
+ continue;
+ new = clone_config_node(seg->lv->vg->vgmem, current, 0);
+ if (!new)
+ return_0;
+ if (last)
+ last->sib = new;
+ if (!head)
+ head = new;
+ last = new;
+ }
+ seg->segtype_private = head;
+ return 1;
+}
+
+static int _unknown_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+ struct config_node *cn = seg->segtype_private;
+ return out_config_node(f, cn);
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _unknown_add_target_line(struct dev_manager *dm __attribute((unused)),
+ struct dm_pool *mem __attribute((unused)),
+ struct cmd_context *cmd __attribute((unused)),
+ void **target_state __attribute((unused)),
+ struct lv_segment *seg __attribute((unused)),
+ struct dm_tree_node *node, uint64_t len,
+ uint32_t *pvmove_mirror_count __attribute((unused)))
+{
+ return dm_tree_node_add_error_target(node, len);
+}
+#endif
+
+static void _unknown_destroy(const struct segment_type *segtype)
+{
+ dm_free((void *)segtype);
+}
+
+static struct segtype_handler _unknown_ops = {
+ .name = _unknown_name,
+ .text_import = _unknown_text_import,
+ .text_export = _unknown_text_export,
+#ifdef DEVMAPPER_SUPPORT
+ .add_target_line = _unknown_add_target_line,
+#endif
+ .destroy = _unknown_destroy,
+};
+
+struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name)
+{
+ struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+
+ if (!segtype)
+ return_NULL;
+
+ segtype->cmd = cmd;
+ segtype->ops = &_unknown_ops;
+ segtype->name = dm_pool_strdup(cmd->mem, name);
+ segtype->private = NULL;
+ segtype->flags = SEG_UNKNOWN | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
+
+ log_very_verbose("Initialised segtype: %s", segtype->name);
+
+ return segtype;
+}
/cvs/lvm2/LVM2/test/t-unknown-segment.sh,v --> standard output
revision 1.1
--- LVM2/test/t-unknown-segment.sh
+++ - 2009-10-16 17:41:57.784831000 +0000
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+. ./test-utils.sh
+
+aux prepare_vg 4
+
+lvcreate -l 1 -n $lv1 $vg
+lvcreate -l 2 -m 1 -n $lv2 $vg
+
+vgcfgbackup -f bak0 $vg
+sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0
+vgcfgrestore -f bak0 $vg
+
+# we have on-disk metadata with unknown segments now
+not lvchange -a y $vg/$lv1 # check that activation is refused
+
+vgcfgbackup -f bak1 $vg
+cat bak1
+sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1
+vgcfgrestore -f bak1 $vg
+vgcfgbackup -f bak2 $vg
+
+egrep -v 'description|seqno|creation_time|Generated' < bak0.orig > a
+egrep -v 'description|seqno|creation_time|Generated' < bak2 > b
+diff -u a b
--- LVM2/tools/vgcfgrestore.c 2009/09/14 22:47:50 1.23
+++ LVM2/tools/vgcfgrestore.c 2009/10/16 17:41:53 1.24
@@ -56,6 +56,8 @@
return ECMD_FAILED;
}
+ cmd->handles_unknown_segments = 1;
+
if (!(arg_count(cmd, file_ARG) ?
backup_restore_from_file(cmd, vg_name,
arg_str_value(cmd, file_ARG, "")) :
^ permalink raw reply [flat|nested] 3+ messages in thread
* LVM2 ./WHATS_NEW lib/Makefile.in lib/activate/ ...
2009-10-16 17:41 mornfall
@ 2009-10-16 17:55 ` Alasdair G Kergon
0 siblings, 0 replies; 3+ messages in thread
From: Alasdair G Kergon @ 2009-10-16 17:55 UTC (permalink / raw)
To: lvm-devel
On Fri, Oct 16, 2009 at 05:41:58PM -0000, mornfall at sourceware.org wrote:
> Handle metadata with unknown segment types more gracefully.
Specifically, once you are running a version containing this code,
if the system encounters metadata containing a segment type it does not
recognise (e.g. created by a newer version than this) it 'does the right
thing' and still lets you use and manipulate LVs unaffected by the
new segment type.
Several new segment types will be hitting the source tree very soon.
Alasdair
^ permalink raw reply [flat|nested] 3+ messages in thread
* LVM2 ./WHATS_NEW lib/Makefile.in lib/activate/ ...
@ 2011-08-11 18:24 jbrassow
0 siblings, 0 replies; 3+ messages in thread
From: jbrassow @ 2011-08-11 18:24 UTC (permalink / raw)
To: lvm-devel
CVSROOT: /cvs/lvm2
Module name: LVM2
Changes by: jbrassow at sourceware.org 2011-08-11 18:24:42
Modified files:
. : WHATS_NEW
lib : Makefile.in
lib/activate : activate.c activate.h
lib/metadata : metadata-exported.h
tools : lvconvert.c
Added files:
lib/metadata : raid_manip.c
test : t-lvcreate-raid.sh
Log message:
Add ability to down-convert RAID1 arrays.
Also, add some simple RAID tests to testsuite.
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2068&r2=1.2069
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/Makefile.in.diff?cvsroot=lvm2&r1=1.110&r2=1.111
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/activate/activate.c.diff?cvsroot=lvm2&r1=1.210&r2=1.211
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/activate/activate.h.diff?cvsroot=lvm2&r1=1.78&r2=1.79
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/raid_manip.c.diff?cvsroot=lvm2&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.197&r2=1.198
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvcreate-raid.sh.diff?cvsroot=lvm2&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.167&r2=1.168
--- LVM2/WHATS_NEW 2011/08/11 17:55:29 1.2068
+++ LVM2/WHATS_NEW 2011/08/11 18:24:40 1.2069
@@ -1,5 +1,6 @@
Version 2.02.87 -
===============================
+ Add ability to down-convert RAID1 arrays.
Update udev rules to skip DM flags decoding for removed devices.
Add detect_internal_vg_cache_corruption to lvm.conf, disabled by default.
Use memory pool locking to check for corruption of internal VG structs.
--- LVM2/lib/Makefile.in 2011/08/02 22:07:21 1.110
+++ LVM2/lib/Makefile.in 2011/08/11 18:24:41 1.111
@@ -85,6 +85,7 @@
metadata/pv.c \
metadata/pv_manip.c \
metadata/pv_map.c \
+ metadata/raid_manip.c \
metadata/replicator_manip.c \
metadata/segtype.c \
metadata/snapshot_manip.c \
--- LVM2/lib/activate/activate.c 2011/08/10 20:25:29 1.210
+++ LVM2/lib/activate/activate.c 2011/08/11 18:24:41 1.211
@@ -611,6 +611,11 @@
return r;
}
+int lv_raid_percent(const struct logical_volume *lv, percent_t *percent)
+{
+ return lv_mirror_percent(lv->vg->cmd, lv, 0, percent, NULL);
+}
+
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
{
struct lvinfo info;
--- LVM2/lib/activate/activate.h 2011/06/22 21:31:21 1.78
+++ LVM2/lib/activate/activate.h 2011/08/11 18:24:41 1.79
@@ -93,6 +93,7 @@
int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent);
int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
int wait, percent_t *percent, uint32_t *event_nr);
+int lv_raid_percent(const struct logical_volume *lv, percent_t *percent);
/*
* Return number of LVs in the VG that are active.
/cvs/lvm2/LVM2/lib/metadata/raid_manip.c,v --> standard output
revision 1.1
--- LVM2/lib/metadata/raid_manip.c
+++ - 2011-08-11 18:24:43.628072000 +0000
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "lib.h"
+#include "metadata.h"
+#include "toolcontext.h"
+#include "segtype.h"
+#include "display.h"
+#include "archiver.h"
+#include "activate.h"
+#include "lv_alloc.h"
+#include "lvm-string.h"
+#include "str_list.h"
+#include "memlock.h"
+
+uint32_t lv_raid_image_count(const struct logical_volume *lv)
+{
+ struct lv_segment *seg = first_seg(lv);
+
+ if (!seg_is_raid(seg))
+ return 1;
+
+ return seg->area_count;
+}
+
+/*
+ * lv_is_on_pv
+ * @lv:
+ * @pv:
+ *
+ * If any of the component devices of the LV are on the given PV, 1
+ * is returned; otherwise 0. For example if one of the images of a RAID
+ * (or its metadata device) is on the PV, 1 would be returned for the
+ * top-level LV.
+ * If you wish to check the images themselves, you should pass them.
+ *
+ * FIXME: This should be made more generic, possibly use 'for_each_sub_lv',
+ * and be put in lv_manip.c. 'for_each_sub_lv' does not yet allow us to
+ * short-circuit execution or pass back the values we need yet though...
+ */
+static int lv_is_on_pv(struct logical_volume *lv, struct physical_volume *pv)
+{
+ uint32_t s;
+ struct physical_volume *pv2;
+ struct lv_segment *seg;
+
+ if (!lv)
+ return 0;
+
+ seg = first_seg(lv);
+ if (!seg)
+ return 0;
+
+ /* Check mirror log */
+ if (lv_is_on_pv(seg->log_lv, pv))
+ return 1;
+
+ /* Check stack of LVs */
+ dm_list_iterate_items(seg, &lv->segments) {
+ for (s = 0; s < seg->area_count; s++) {
+ if (seg_type(seg, s) == AREA_PV) {
+ pv2 = seg_pv(seg, s);
+ if (id_equal(&pv->id, &pv2->id))
+ return 1;
+ if (pv->dev && pv2->dev &&
+ (pv->dev->dev == pv2->dev->dev))
+ return 1;
+ }
+
+ if ((seg_type(seg, s) == AREA_LV) &&
+ lv_is_on_pv(seg_lv(seg, s), pv))
+ return 1;
+
+ if (!seg_is_raid(seg))
+ continue;
+
+ /* This is RAID, so we know the meta_area is AREA_LV */
+ if (lv_is_on_pv(seg_metalv(seg, s), pv))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int lv_is_on_pvs(struct logical_volume *lv, struct dm_list *pvs)
+{
+ struct pv_list *pvl;
+
+ dm_list_iterate_items(pvl, pvs)
+ if (lv_is_on_pv(lv, pvl->pv)) {
+ log_debug("%s is on %s", lv->name,
+ pv_dev_name(pvl->pv));
+ return 1;
+ } else
+ log_debug("%s is not on %s", lv->name,
+ pv_dev_name(pvl->pv));
+ return 0;
+}
+
+static int raid_in_sync(struct logical_volume *lv)
+{
+ percent_t sync_percent;
+
+ if (!lv_raid_percent(lv, &sync_percent)) {
+ log_error("Unable to determine sync status of %s/%s.",
+ lv->vg->name, lv->name);
+ return 0;
+ }
+
+ return (sync_percent == PERCENT_100) ? 1 : 0;
+}
+
+/*
+ * _shift_and_rename_image_components
+ * @seg: Top-level RAID segment
+ *
+ * Shift all higher indexed segment areas down to fill in gaps where
+ * there are 'AREA_UNASSIGNED' areas and rename data/metadata LVs so
+ * that their names match their new index. When finished, set
+ * seg->area_count to new reduced total.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int _shift_and_rename_image_components(struct lv_segment *seg)
+{
+ int len;
+ char *shift_name;
+ uint32_t s, missing;
+ struct cmd_context *cmd = seg->lv->vg->cmd;
+
+ /*
+ * All LVs must be properly named for their index before
+ * shifting begins. (e.g. Index '0' must contain *_rimage_0 and
+ * *_rmeta_0. Index 'n' must contain *_rimage_n and *_rmeta_n.)
+ */
+
+ if (!seg_is_raid(seg))
+ return_0;
+
+ if (seg->area_count > 10) {
+ /*
+ * FIXME: Handling more would mean I'd have
+ * to handle double digits
+ */
+ log_error("Unable handle arrays with more than 10 devices");
+ return 0;
+ }
+
+ log_very_verbose("Shifting images in %s", seg->lv->name);
+
+ for (s = 0, missing = 0; s < seg->area_count; s++) {
+ if (seg_type(seg, s) == AREA_UNASSIGNED) {
+ if (seg_metatype(seg, s) != AREA_UNASSIGNED) {
+ log_error(INTERNAL_ERROR "Metadata segment area"
+ " #%d should be AREA_UNASSIGNED", s);
+ return 0;
+ }
+ missing++;
+ continue;
+ }
+ if (!missing)
+ continue;
+
+ log_very_verbose("Shifting %s and %s by %u",
+ seg_metalv(seg, s)->name,
+ seg_lv(seg, s)->name, missing);
+
+ /* Alter rmeta name */
+ shift_name = dm_pool_strdup(cmd->mem, seg_metalv(seg, s)->name);
+ if (!shift_name)
+ return_0;
+ len = strlen(shift_name) - 1;
+ shift_name[len] -= missing;
+ seg_metalv(seg, s)->name = shift_name;
+
+ /* Alter rimage name */
+ shift_name = dm_pool_strdup(cmd->mem, seg_lv(seg, s)->name);
+ if (!shift_name)
+ return_0;
+ len = strlen(shift_name) - 1;
+ shift_name[len] -= missing;
+ seg_lv(seg, s)->name = shift_name;
+
+ seg->areas[s - missing] = seg->areas[s];
+ seg->meta_areas[s - missing] = seg->meta_areas[s];
+ }
+
+ seg->area_count -= missing;
+ return 1;
+}
+
+static int raid_add_images(struct logical_volume *lv,
+ uint32_t new_count, struct dm_list *pvs)
+{
+ /* Not implemented */
+ log_error("Unable to add images to LV, %s/%s",
+ lv->vg->name, lv->name);
+
+ return 0;
+}
+
+/*
+ * _extract_image_components
+ * @seg
+ * @idx: The index in the areas array to remove
+ * @extracted_rmeta: The displaced metadata LV
+ * @extracted_rimage: The displaced data LV
+ *
+ * This function extracts the image components - setting the respective
+ * 'extracted' pointers. It appends '_extracted' to the LVs' names, so that
+ * there are not future conflicts. It does /not/ commit the results.
+ * (IOW, erroring-out requires no unwinding of operations.)
+ *
+ * This function does /not/ attempt to:
+ * 1) shift the 'areas' or 'meta_areas' arrays.
+ * The '[meta_]areas' are left as AREA_UNASSIGNED.
+ * 2) Adjust the seg->area_count
+ * 3) Name the extracted LVs appropriately (appends '_extracted' to names)
+ * These actions must be performed by the caller.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
+ struct logical_volume **extracted_rmeta,
+ struct logical_volume **extracted_rimage)
+{
+ int len;
+ char *tmp_name;
+ struct cmd_context *cmd = seg->lv->vg->cmd;
+ struct logical_volume *data_lv = seg_lv(seg, idx);
+ struct logical_volume *meta_lv = seg_metalv(seg, idx);
+
+ log_very_verbose("Extracting image components %s and %s from %s",
+ data_lv->name, meta_lv->name, seg->lv->name);
+
+ data_lv->status &= ~RAID_IMAGE;
+ meta_lv->status &= ~RAID_META;
+ lv_set_visible(data_lv);
+ lv_set_visible(meta_lv);
+
+ /* release removes data and meta areas */
+ remove_seg_from_segs_using_this_lv(data_lv, seg);
+ remove_seg_from_segs_using_this_lv(meta_lv, seg);
+
+ seg_type(seg, idx) = AREA_UNASSIGNED;
+ seg_metatype(seg, idx) = AREA_UNASSIGNED;
+
+ len = strlen(meta_lv->name) + strlen("_extracted") + 1;
+ tmp_name = dm_pool_alloc(cmd->mem, len);
+ if (!tmp_name)
+ return_0;
+ sprintf(tmp_name, "%s_extracted", meta_lv->name);
+ meta_lv->name = tmp_name;
+
+ len = strlen(data_lv->name) + strlen("_extracted") + 1;
+ tmp_name = dm_pool_alloc(cmd->mem, len);
+ if (!tmp_name)
+ return_0;
+ sprintf(tmp_name, "%s_extracted", data_lv->name);
+ data_lv->name = tmp_name;
+
+ *extracted_rmeta = meta_lv;
+ *extracted_rimage = data_lv;
+
+ return 1;
+}
+
+/*
+ * raid_extract_images
+ * @lv
+ * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
+ * @target_pvs: The list of PVs that are candidates for removal
+ * @shift: If set, use _shift_and_rename_image_components().
+ * Otherwise, leave the [meta_]areas as AREA_UNASSIGNED and
+ * seg->area_count unchanged.
+ * @extracted_[meta|data]_lvs: The LVs removed from the array. If 'shift'
+ * is set, then there will likely be name conflicts.
+ *
+ * This function extracts _both_ portions of the indexed image. It
+ * does /not/ commit the results. (IOW, erroring-out requires no unwinding
+ * of operations.)
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int raid_extract_images(struct logical_volume *lv, uint32_t new_count,
+ struct dm_list *target_pvs, int shift,
+ struct dm_list *extracted_meta_lvs,
+ struct dm_list *extracted_data_lvs)
+{
+ int s, extract, lvl_idx = 0;
+ struct lv_list *lvl_array;
+ struct lv_segment *seg = first_seg(lv);
+ struct logical_volume *rmeta_lv, *rimage_lv;
+
+ extract = seg->area_count - new_count;
+ log_verbose("Extracting %u %s from %s/%s", extract,
+ (extract > 1) ? "images" : "image",
+ lv->vg->name, lv->name);
+
+ lvl_array = dm_pool_alloc(lv->vg->cmd->mem,
+ sizeof(*lvl_array) * extract * 2);
+ if (!lvl_array)
+ return_0;
+
+ for (s = seg->area_count - 1; (s >= 0) && extract; s--) {
+ if (!lv_is_on_pvs(seg_lv(seg, s), target_pvs) ||
+ !lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
+ continue;
+ if (!raid_in_sync(lv) &&
+ (!seg_is_mirrored(seg) || (s == 0))) {
+ log_error("Unable to extract %sRAID image"
+ " while RAID array is not in-sync",
+ seg_is_mirrored(seg) ? "primary " : "");
+ return 0;
+ }
+
+ if (!_extract_image_components(seg, s, &rmeta_lv, &rimage_lv)) {
+ log_error("Failed to extract %s from %s",
+ seg_lv(seg, s)->name, lv->name);
+ return 0;
+ }
+
+ if (shift && !_shift_and_rename_image_components(seg)) {
+ log_error("Failed to shift and rename image components");
+ return 0;
+ }
+
+ lvl_array[lvl_idx].lv = rmeta_lv;
+ lvl_array[lvl_idx + 1].lv = rimage_lv;
+ dm_list_add(extracted_meta_lvs, &(lvl_array[lvl_idx++].list));
+ dm_list_add(extracted_data_lvs, &(lvl_array[lvl_idx++].list));
+
+ extract--;
+ }
+ if (extract) {
+ log_error("Unable to extract enough images to satisfy request");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * lv_raid_change_image_count
+ * @lv
+ * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
+ * @pvs: The list of PVs that are candidates for removal (or empty list)
+ *
+ * RAID arrays have 'images' which are composed of two parts, they are:
+ * - 'rimage': The data/parity holding portion
+ * - 'rmeta' : The metadata holding portion (i.e. superblock/bitmap area)
+ * This function adds or removes _both_ portions of the image and commits
+ * the results.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+int lv_raid_change_image_count(struct logical_volume *lv,
+ uint32_t new_count, struct dm_list *pvs)
+{
+ int r;
+ uint32_t old_count = lv_raid_image_count(lv);
+ struct lv_segment *seg = first_seg(lv);
+ struct dm_list removal_list;
+ struct lv_list *lvl_array, *lvl;
+
+ dm_list_init(&removal_list);
+
+ if (!seg_is_mirrored(seg)) {
+ log_error("Unable to change image count of non-mirrored RAID.");
+ return 0;
+ }
+
+ if (old_count == new_count) {
+ log_verbose("%s/%s already has image count of %d",
+ lv->vg->name, lv->name, new_count);
+ return 1;
+ }
+
+ if (old_count > new_count)
+ r = raid_extract_images(lv, new_count, pvs, 1,
+ &removal_list, &removal_list);
+ else
+ r = raid_add_images(lv, new_count, pvs);
+ if (!r)
+ return 0;
+
+ /* Convert to linear? */
+ if (new_count == 1) {
+ /* Add last metadata area to removal_list */
+ lvl_array = dm_pool_alloc(lv->vg->cmd->mem, 2 * sizeof(*lvl));
+ if (!lvl_array)
+ return_0;
+ lvl_array[0].lv = seg_metalv(seg, 0);
+ remove_seg_from_segs_using_this_lv(seg_metalv(seg, 0), seg);
+ seg_metatype(seg, 0) = AREA_UNASSIGNED;
+ dm_list_add(&removal_list, &(lvl_array[0].list));
+
+ /* Remove RAID layer */
+ seg_lv(seg, 0)->status &= ~RAID_IMAGE;
+ lv_set_visible(seg_lv(seg, 0));
+ lvl_array[1].lv = seg_lv(seg, 0);
+ dm_list_add(&removal_list, &(lvl_array[1].list));
+
+ if (!remove_layer_from_lv(lv, seg_lv(seg, 0)))
+ return_0;
+ lv->status &= ~(MIRRORED | RAID);
+ }
+
+ if (!vg_write(lv->vg)) {
+ log_error("Failed to write changes to %s in %s",
+ lv->name, lv->vg->name);
+ return 0;
+ }
+
+ if (!suspend_lv(lv->vg->cmd, lv)) {
+ log_error("Failed to suspend %s/%s before committing changes",
+ lv->vg->name, lv->name);
+ return 0;
+ }
+
+ if (!vg_commit(lv->vg)) {
+ log_error("Failed to commit changes to %s in %s",
+ lv->name, lv->vg->name);
+ return 0;
+ }
+
+ /*
+ * Bring extracted LVs into existance, so there are no
+ * conflicts for the main RAID device's resume
+ */
+ if (!dm_list_empty(&removal_list)) {
+ dm_list_iterate_items(lvl, &removal_list) {
+ /* If top RAID was EX, use EX */
+ if (lv_is_active_exclusive_locally(lv)) {
+ if (!activate_lv_excl(lv->vg->cmd, lvl->lv))
+ return_0;
+ } else {
+ if (!activate_lv(lv->vg->cmd, lvl->lv))
+ return_0;
+ }
+ }
+ }
+
+ if (!resume_lv(lv->vg->cmd, lv)) {
+ log_error("Failed to resume %s/%s after committing changes",
+ lv->vg->name, lv->name);
+ return 0;
+ }
+
+ /*
+ * Eliminate the extracted LVs
+ */
+ if (!dm_list_empty(&removal_list)) {
+ dm_list_iterate_items(lvl, &removal_list) {
+ if (!deactivate_lv(lv->vg->cmd, lvl->lv))
+ return_0;
+ if (!lv_remove(lvl->lv))
+ return_0;
+ }
+
+ if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+ return_0;
+ }
+
+ return 1;
+}
--- LVM2/lib/metadata/metadata-exported.h 2011/08/11 03:29:52 1.197
+++ LVM2/lib/metadata/metadata-exported.h 2011/08/11 18:24:41 1.198
@@ -737,6 +737,13 @@
int lv_is_slog(const struct logical_volume *lv);
struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
/* -- metadata/replicator_manip.c */
+
+/* ++ metadata/raid_manip.c */
+uint32_t lv_raid_image_count(const struct logical_volume *lv);
+int lv_raid_change_image_count(struct logical_volume *lv,
+ uint32_t new_count, struct dm_list *pvs);
+/* -- metadata/raid_manip.c */
+
struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs,
const char *vg_name, const char *vgid,
uint32_t flags);
/cvs/lvm2/LVM2/test/t-lvcreate-raid.sh,v --> standard output
revision 1.1
--- LVM2/test/t-lvcreate-raid.sh
+++ - 2011-08-11 18:24:43.896171000 +0000
@@ -0,0 +1,122 @@
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+. lib/test
+
+# is_raid_in_sync <VG/LV>
+function is_raid_in_sync()
+{
+ local dm_name
+ local a
+ local b
+ local idx
+
+ dm_name=`echo $1 | sed s:-:--: | sed s:/:-:`
+
+ if ! a=(`dmsetup status $dm_name`); then
+ echo "Unable to get sync status of $1"
+ exit 1
+ fi
+ idx=$((${#a[@]} - 1))
+ b=(`echo ${a[$idx]} | sed s:/:' ':`)
+
+ if [ ${b[0]} != ${b[1]} ]; then
+ echo "$dm_name (${a[3]}) is not in-sync"
+ return 1
+ fi
+
+ echo "$dm_name (${a[3]}) is in-sync"
+ return 0
+}
+
+# wait_for_raid_sync <VG/LV>
+function wait_for_raid_sync()
+{
+ local i=0
+
+ while ! is_raid_in_sync $1; do
+ sleep 2
+ i=$(($i + 1))
+ if [ $i -gt 500 ]; then
+ echo "Sync is taking too long - assume stuck"
+ exit 1
+ fi
+ done
+}
+
+function is_raid_available()
+{
+ local a
+
+ modprobe dm-raid
+ a=(`dmsetup targets | grep raid`)
+ if [ -z $a ]; then
+ echo "RAID target not available"
+ return 1
+ fi
+ if [ ${a[1]} != "v1.1.0" ]; then
+ echo "Bad RAID version"
+ return 1
+ fi
+
+ return 0
+}
+
+########################################################
+# MAIN
+########################################################
+is_raid_available || exit 200
+
+aux prepare_vg 5 80
+
+
+###########################################
+# Create, wait for sync, remove tests
+###########################################
+
+# Create RAID1 (implicit 2-way)
+lvcreate --type raid1 -l 2 -n $lv1 $vg
+wait_for_raid_sync $vg/$lv1
+lvremove -ff $vg
+
+# Create RAID1 (explicit 2-way)
+lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+wait_for_raid_sync $vg/$lv1
+lvremove -ff $vg
+
+# Create RAID1 (explicit 3-way)
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+wait_for_raid_sync $vg/$lv1
+lvremove -ff $vg
+
+# Create RAID 4/5/6 (explicit 3-stripe + parity devs)
+for i in raid4 \
+ raid5 raid5_ls raid5_la raid5_rs raid5_ra \
+ raid6 raid6_zr raid6_nr raid6_nc; do
+
+ lvcreate --type $i -l 3 -i 3 -n $lv1 $vg
+ wait_for_raid_sync $vg/$lv1
+ lvremove -ff $vg
+done
+
+###########################################
+# RAID1 down-convert tests
+###########################################
+
+# 3-way to 2-way
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+wait_for_raid_sync $vg/$lv1
+lvconvert -m 1 $vg/$lv1
+# FIXME: ensure no residual devices
+
+# 2-way to linear
+lvconvert -m 0 $vg/$lv1
+# FIXME: ensure no residual devices
+lvremove -ff $vg
--- LVM2/tools/lvconvert.c 2011/08/10 20:25:31 1.167
+++ LVM2/tools/lvconvert.c 2011/08/11 18:24:42 1.168
@@ -39,7 +39,7 @@
uint32_t stripes;
uint32_t stripe_size;
- struct segment_type *segtype;
+ const struct segment_type *segtype;
alloc_policy_t alloc;
@@ -1366,6 +1366,62 @@
return 1;
}
+static int is_valid_raid_conversion(const struct segment_type *from_segtype,
+ const struct segment_type *to_segtype)
+{
+ if (from_segtype == to_segtype)
+ return 1;
+
+ if (!segtype_is_raid(from_segtype) && !segtype_is_raid(to_segtype))
+ return_0; /* Not converting to or from RAID? */
+
+ return 0;
+}
+
+static int lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
+{
+ int image_count;
+ struct cmd_context *cmd = lv->vg->cmd;
+ struct lv_segment *seg = first_seg(lv);
+
+ if (!arg_count(cmd, type_ARG))
+ lp->segtype = seg->segtype;
+
+ if (arg_count(cmd, mirrors_ARG) && !seg_is_mirrored(seg)) {
+ log_error("'--mirrors/-m' is not compatible with %s",
+ seg->segtype->name);
+ return 0;
+ }
+
+ if (!is_valid_raid_conversion(seg->segtype, lp->segtype)) {
+ log_error("Unable to convert %s/%s from %s to %s",
+ lv->vg->name, lv->name,
+ seg->segtype->name, lp->segtype->name);
+ return 0;
+ }
+
+ /* Change number of RAID1 images */
+ if (arg_count(cmd, mirrors_ARG)) {
+ image_count = lv_raid_image_count(lv);
+ if (lp->mirrors_sign == SIGN_PLUS)
+ image_count += lp->mirrors;
+ else if (lp->mirrors_sign == SIGN_MINUS)
+ image_count -= lp->mirrors;
+ else
+ image_count = lp->mirrors + 1;
+
+ if (image_count < 1) {
+ log_error("Unable to reduce images by specified amount");
+ return 0;
+ }
+
+ return lv_raid_change_image_count(lv, image_count, lp->pvh);
+ }
+
+ log_error("Conversion operation not yet supported.");
+ return 0;
+}
+
static int lvconvert_snapshot(struct cmd_context *cmd,
struct logical_volume *lv,
struct lvconvert_params *lp)
@@ -1580,6 +1636,24 @@
stack;
return ECMD_FAILED;
}
+ } else if (segtype_is_raid(lp->segtype) || (lv->status & RAID)) {
+ if (!archive(lv->vg)) {
+ stack;
+ return ECMD_FAILED;
+ }
+ if (!lvconvert_raid(lv, lp)) {
+ stack;
+ return ECMD_FAILED;
+ }
+
+ if (!(failed_pvs = _failed_pv_list(lv->vg))) {
+ stack;
+ return ECMD_FAILED;
+ }
+
+ /* If repairing and using policies, remove missing PVs from VG */
+ if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG))
+ _remove_missing_empty_pv(lv->vg, failed_pvs);
} else if (arg_count(cmd, mirrors_ARG) ||
arg_count(cmd, splitmirrors_ARG) ||
(lv->status & MIRRORED)) {
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-08-11 18:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-11 18:24 LVM2 ./WHATS_NEW lib/Makefile.in lib/activate/ jbrassow
-- strict thread matches above, loose matches on Subject: below --
2009-10-16 17:41 mornfall
2009-10-16 17:55 ` Alasdair G Kergon
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.