summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--WHATS_NEW4
-rw-r--r--lib/activate/dev_manager.c13
-rw-r--r--lib/commands/toolcontext.c18
-rw-r--r--lib/config/config.c2
-rw-r--r--lib/device/dev-cache.c146
-rw-r--r--lib/device/dev-cache.h1
-rw-r--r--lib/device/dev-io.c34
-rw-r--r--lib/device/device.h2
-rw-r--r--lib/display/display.c13
-rw-r--r--lib/format1/import-export.c5
-rw-r--r--lib/format1/import-extents.c15
-rw-r--r--lib/format_pool/import_export.c10
-rw-r--r--lib/format_text/export.c5
-rw-r--r--lib/format_text/import_vsn1.c5
-rw-r--r--lib/log/log.c2
-rw-r--r--lib/metadata/lv_alloc.h4
-rw-r--r--lib/metadata/lv_manip.c58
-rw-r--r--lib/metadata/merge.c42
-rw-r--r--lib/metadata/metadata.c56
-rw-r--r--lib/metadata/metadata.h5
-rw-r--r--lib/metadata/mirror.c35
-rw-r--r--lib/metadata/pv_alloc.h8
-rw-r--r--lib/metadata/pv_manip.c227
-rw-r--r--lib/metadata/pv_map.c6
-rw-r--r--lib/report/report.c6
-rw-r--r--lib/striped/striped.c14
-rw-r--r--tools/vgreduce.c9
-rw-r--r--tools/vgremove.c8
-rw-r--r--tools/vgsplit.c2
29 files changed, 625 insertions, 130 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index 0f5aac540..8dd7d2e7f 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,7 +1,9 @@
Version 2.01.10 -
================================
+ Reinstate full PV size when removing from VG.
+ Support loopfiles for testing.
Tidy lv_segment interface.
- Initial pv_segment support.
+ pv_segment support.
vgchange --physicalextentsize
Internal snapshot restructuring.
Remove unused internal non-persistent snapshot option.
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 1a169db48..2ccdd4451 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -760,7 +760,9 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
for (s = start_area; s < areas; s++, *pos += tw) {
trailing_space = (areas - s - 1) ? " " : "";
if ((seg->area[s].type == AREA_PV &&
- (!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
+ (!seg->area[s].u.pv.pvseg ||
+ !seg->area[s].u.pv.pvseg->pv ||
+ !seg->area[s].u.pv.pvseg->pv->dev)) ||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s 0%s", dm->stripe_filler,
@@ -768,9 +770,12 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
else if (seg->area[s].type == AREA_PV)
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s %" PRIu64 "%s",
- dev_name(seg->area[s].u.pv.pv->dev),
- (seg->area[s].u.pv.pv->pe_start +
- (esize * seg->area[s].u.pv.pe)),
+ dev_name(seg->area[s].u.pv.pvseg->
+ pv->dev),
+ (seg->area[s].u.pv.pvseg->pv->
+ pe_start +
+ (esize * seg->area[s].u.pv.pvseg->
+ pe)),
trailing_space);
else {
if (!(dl = hash_lookup(dm->layers,
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 99deaa9db..c4f7a2505 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -493,6 +493,24 @@ static int _init_dev_cache(struct cmd_context *cmd)
}
}
+ if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
+ return 1;
+
+ for (cv = cn->v; cv; cv = cv->next) {
+ if (cv->type != CFG_STRING) {
+ log_error("Invalid string in config file: "
+ "devices/loopfiles");
+ return 0;
+ }
+
+ if (!dev_cache_add_loopfile(cv->v.str)) {
+ log_error("Failed to add loopfile %s to internal "
+ "device cache", cv->v.str);
+ return 0;
+ }
+ }
+
+
return 1;
}
diff --git a/lib/config/config.c b/lib/config/config.c
index 91fc73e1a..71c503c1f 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -235,7 +235,7 @@ int read_config_file(struct config_tree *cft)
return 1;
}
- if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
+ if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
stack;
return 0;
}
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index cafd837ae..e9cc34510 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -44,39 +44,62 @@ static struct {
int has_scanned;
struct list dirs;
+ struct list files;
} _cache;
-#define _alloc(x) pool_alloc(_cache.mem, (x))
+#define _alloc(x) pool_zalloc(_cache.mem, (x))
+#define _strdup(x) pool_strdup(_cache.mem, (x))
#define _free(x) pool_free(_cache.mem, (x))
static int _insert(const char *path, int rec);
struct device *dev_create_file(const char *filename, struct device *dev,
- struct str_list *alias)
+ struct str_list *alias, int use_malloc)
{
int allocate = !dev;
- if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
- log_error("struct device allocation failed");
- return NULL;
- }
- if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
- log_error("struct str_list allocation failed");
- dbg_free(dev);
- return NULL;
- }
- if (!(alias->str = dbg_strdup(filename))) {
- log_error("filename strdup failed");
- if (allocate) {
- dbg_free(dev);
- dbg_free(alias);
+ if (allocate) {
+ if (use_malloc) {
+ if (!(dev = dbg_malloc(sizeof(*dev)))) {
+ log_error("struct device allocation failed");
+ return NULL;
+ }
+ if (!(alias = dbg_malloc(sizeof(*alias)))) {
+ log_error("struct str_list allocation failed");
+ dbg_free(dev);
+ return NULL;
+ }
+ if (!(alias->str = dbg_strdup(filename))) {
+ log_error("filename strdup failed");
+ if (allocate) {
+ dbg_free(dev);
+ dbg_free(alias);
+ }
+ return NULL;
+ }
+ dev->flags = DEV_ALLOCED;
+ } else {
+ if (!(dev = _alloc(sizeof(*dev)))) {
+ log_error("struct device allocation failed");
+ return NULL;
+ }
+ if (!(alias = _alloc(sizeof(*alias)))) {
+ log_error("struct str_list allocation failed");
+ dbg_free(dev);
+ return NULL;
+ }
+ if (!(alias->str = _strdup(filename))) {
+ log_error("filename strdup failed");
+ if (allocate) {
+ dbg_free(dev);
+ dbg_free(alias);
+ }
+ return NULL;
+ }
}
- return NULL;
}
- dev->flags = DEV_REGULAR;
- if (allocate)
- dev->flags |= DEV_ALLOCED;
+ dev->flags |= DEV_REGULAR;
list_init(&dev->aliases);
list_add(&dev->aliases, &alias->list);
dev->end = UINT64_C(0);
@@ -221,12 +244,25 @@ static int _add_alias(struct device *dev, const char *path)
static int _insert_dev(const char *path, dev_t d)
{
struct device *dev;
+ static dev_t loopfile_count = 0;
+ int loopfile = 0;
+
+ /* Generate pretend device numbers for loopfiles */
+ if (!d) {
+ d = ++loopfile_count;
+ loopfile = 1;
+ }
/* is this device already registered ? */
if (!(dev = (struct device *) btree_lookup(_cache.devices,
(uint32_t) d))) {
/* create new device */
- if (!(dev = _dev_create(d))) {
+ if (loopfile) {
+ if (!(dev = dev_create_file(path, NULL, NULL, 0))) {
+ stack;
+ return 0;
+ }
+ } else if (!(dev = _dev_create(d))) {
stack;
return 0;
}
@@ -238,7 +274,7 @@ static int _insert_dev(const char *path, dev_t d)
}
}
- if (!_add_alias(dev, path)) {
+ if (!loopfile && !_add_alias(dev, path)) {
log_err("Couldn't add alias to dev cache.");
return 0;
}
@@ -314,6 +350,28 @@ static int _insert_dir(const char *dir)
return r;
}
+static int _insert_file(const char *path)
+{
+ struct stat info;
+
+ if (stat(path, &info) < 0) {
+ log_sys_very_verbose("stat", path);
+ return 0;
+ }
+
+ if (!S_ISREG(info.st_mode)) {
+ log_debug("%s: Not a regular file", path);
+ return 0;
+ }
+
+ if (!_insert_dev(path, 0)) {
+ stack;
+ return 0;
+ }
+
+ return 1;
+}
+
static int _insert(const char *path, int rec)
{
struct stat info;
@@ -368,6 +426,11 @@ static void _full_scan(int dev_scan)
_insert_dir(dl->dir);
};
+ list_iterate(dh, &_cache.files) {
+ struct dir_list *dl = list_item(dh, struct dir_list);
+ _insert_file(dl->dir);
+ };
+
_cache.has_scanned = 1;
init_full_scan_done(1);
}
@@ -408,6 +471,7 @@ int dev_cache_init(void)
}
list_init(&_cache.dirs);
+ list_init(&_cache.files);
return 1;
@@ -445,6 +509,7 @@ void dev_cache_exit(void)
_cache.devices = NULL;
_cache.has_scanned = 0;
list_init(&_cache.dirs);
+ list_init(&_cache.files);
}
int dev_cache_add_dir(const char *path)
@@ -473,6 +538,32 @@ int dev_cache_add_dir(const char *path)
return 1;
}
+int dev_cache_add_loopfile(const char *path)
+{
+ struct dir_list *dl;
+ struct stat st;
+
+ if (stat(path, &st)) {
+ log_error("Ignoring %s: %s", path, strerror(errno));
+ /* But don't fail */
+ return 1;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_error("Ignoring %s: Not a regular file", path);
+ return 1;
+ }
+
+ if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
+ log_error("dir_list allocation failed for file");
+ return 0;
+ }
+
+ strcpy(dl->dir, path);
+ list_add(&_cache.files, &dl->list);
+ return 1;
+}
+
/* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
@@ -483,6 +574,9 @@ const char *dev_name_confirmed(struct device *dev, int quiet)
const char *name;
int r;
+ if ((dev->flags & DEV_REGULAR))
+ return dev_name(dev);
+
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
@@ -527,6 +621,9 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
struct stat buf;
struct device *d = (struct device *) hash_lookup(_cache.names, name);
+ if (d && (d->flags & DEV_REGULAR))
+ return d;
+
/* If the entry's wrong, remove it */
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
hash_remove(_cache.names, name);
@@ -538,7 +635,8 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
d = (struct device *) hash_lookup(_cache.names, name);
}
- return (d && (!f || f->passes_filter(f, d))) ? d : NULL;
+ return (d && (!f || (d->flags & DEV_REGULAR) ||
+ f->passes_filter(f, d))) ? d : NULL;
}
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
@@ -580,7 +678,7 @@ struct device *dev_iter_get(struct dev_iter *iter)
{
while (iter->current) {
struct device *d = _iter_next(iter);
- if (!iter->filter ||
+ if (!iter->filter || (d->flags & DEV_REGULAR) ||
iter->filter->passes_filter(iter->filter, d))
return d;
}
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 5ddd055d7..b917142ec 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -39,6 +39,7 @@ void dev_cache_scan(int do_scan);
int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
+int dev_cache_add_loopfile(const char *path);
struct device *dev_cache_get(const char *name, struct dev_filter *f);
/*
diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c
index ca3e965d4..836336e6a 100644
--- a/lib/device/dev-io.c
+++ b/lib/device/dev-io.c
@@ -222,11 +222,25 @@ static int _aligned_io(struct device_area *where, void *buffer,
return 1;
}
-/*-----------------------------------------------------------------
- * Public functions
- *---------------------------------------------------------------*/
+static int _dev_get_size_file(const struct device *dev, uint64_t *size)
+{
+ const char *name = dev_name(dev);
+ struct stat info;
-int dev_get_size(const struct device *dev, uint64_t *size)
+ if (stat(name, &info)) {
+ log_sys_error("stat", name);
+ return 0;
+ }
+
+ *size = info.st_size;
+ *size >>= SECTOR_SHIFT; /* Convert to sectors */
+
+ log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
+
+ return 1;
+}
+
+static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
{
int fd;
const char *name = dev_name(dev);
@@ -252,6 +266,18 @@ int dev_get_size(const struct device *dev, uint64_t *size)
return 1;
}
+/*-----------------------------------------------------------------
+ * Public functions
+ *---------------------------------------------------------------*/
+
+int dev_get_size(const struct device *dev, uint64_t *size)
+{
+ if ((dev->flags & DEV_REGULAR))
+ return _dev_get_size_file(dev, size);
+ else
+ return _dev_get_size_dev(dev, size);
+}
+
/* FIXME Unused
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
diff --git a/lib/device/device.h b/lib/device/device.h
index f1698a4ea..afe29e368 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -83,7 +83,7 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len);
void dev_flush(struct device *dev);
struct device *dev_create_file(const char *filename, struct device *dev,
- struct str_list *alias);
+ struct str_list *alias, int use_malloc);
static inline const char *dev_name(const struct device *dev)
{
diff --git a/lib/display/display.c b/lib/display/display.c
index f5d3df057..11726e44f 100644
--- a/lib/display/display.c
+++ b/lib/display/display.c
@@ -451,14 +451,17 @@ void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
{
switch (seg->area[s].type) {
case AREA_PV:
+ /* FIXME Re-check the conditions for 'Missing' */
log_print("%sPhysical volume\t%s", pre,
- seg->area[s].u.pv.pv ?
- dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
+ seg->area[s].u.pv.pvseg->pv ?
+ dev_name(seg->area[s].u.pv.pvseg->pv->dev) :
+ "Missing");
- if (seg->area[s].u.pv.pv)
+ if (seg->area[s].u.pv.pvseg->pv)
log_print("%sPhysical extents\t%d to %d", pre,
- seg->area[s].u.pv.pe,
- seg->area[s].u.pv.pe + seg->area_len - 1);
+ seg->area[s].u.pv.pvseg->pe,
+ seg->area[s].u.pv.pvseg->pe +
+ seg->area_len - 1);
break;
case AREA_LV:
log_print("%sLogical volume\t%s", pre,
diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c
index a3d923284..ca487a1c5 100644
--- a/lib/format1/import-export.c
+++ b/lib/format1/import-export.c
@@ -403,11 +403,12 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
"unsupported by format1", lv->name);
return 0;
}
- if (seg->area[s].u.pv.pv != pv)
+ if (seg->area[s].u.pv.pvseg->pv != pv)
continue; /* not our pv */
for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
- ped = &dl->extents[pe + seg->area[s].u.pv.pe];
+ ped = &dl->extents[pe +
+ seg->area[s].u.pv.pvseg->pe];
ped->lv_num = lv_num;
ped->le_num = (seg->le / seg->area_count) + pe +
s * (lv->le_count / seg->area_count);
diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c
index 2080f0e67..20913a5df 100644
--- a/lib/format1/import-extents.c
+++ b/lib/format1/import-extents.c
@@ -231,7 +231,11 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
return 0;
}
- set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, lvm->map[le].pe);
+ if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
+ lvm->map[le].pe)) {
+ stack;
+ return 0;
+ }
list_add(&lvm->lv->segments, &seg->list);
@@ -306,9 +310,12 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
* Set up start positions of each stripe in this segment
*/
for (st = 0; st < seg->area_count; st++)
- set_lv_segment_area_pv(seg, st,
- lvm->map[le + st * len].pv,
- lvm->map[le + st * len].pe);
+ if (!set_lv_segment_area_pv(seg, st,
+ lvm->map[le + st * len].pv,
+ lvm->map[le + st * len].pe)) {
+ stack;
+ return 0;
+ }
list_add(&lvm->lv->segments, &seg->list);
diff --git a/lib/format_pool/import_export.c b/lib/format_pool/import_export.c
index 5f6a0e35f..79e8279b2 100644
--- a/lib/format_pool/import_export.c
+++ b/lib/format_pool/import_export.c
@@ -238,7 +238,10 @@ static int _add_stripe_seg(struct pool *mem,
}
for (j = 0; j < usp->num_devs; j++)
- set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0);
+ if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) {
+ stack;
+ return 0;
+ }
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
@@ -278,7 +281,10 @@ static int _add_linear_seg(struct pool *mem,
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
- set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0);
+ if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) {
+ stack;
+ return 0;
+ }
list_add(&lv->segments, &seg->list);
*le_cur += seg->len;
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
index a94cbe0cf..310c03f26 100644
--- a/lib/format_text/export.c
+++ b/lib/format_text/export.c
@@ -444,13 +444,14 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_PV:
- if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
+ if (!(name = _get_pv_name(f, seg->area[s].u.pv.pvseg->
+ pv))) {
stack;
return 0;
}
outf(f, "\"%s\", %u%s", name,
- seg->area[s].u.pv.pe,
+ seg->area[s].u.pv.pvseg->pe,
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_LV:
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index 1d8eff078..b5221e04e 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -363,7 +363,10 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
/* FIXME Cope if LV not yet read in */
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
- set_lv_segment_area_pv(seg, s, pv, cv->next->v.i);
+ if (!set_lv_segment_area_pv(seg, s, pv, cv->next->v.i)) {
+ stack;
+ return 0;
+ }
/*
* Adjust extent counts in the pv and vg.
*/
diff --git a/lib/log/log.c b/lib/log/log.c
index e14c35a3a..ace411fc4 100644
--- a/lib/log/log.c
+++ b/lib/log/log.c
@@ -72,7 +72,7 @@ void init_log_direct(const char *log_file, int append)
{
int open_flags = append ? 0 : O_TRUNC;
- dev_create_file(log_file, &_log_dev, &_log_dev_alias);
+ dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1);
if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0))
return;
diff --git a/lib/metadata/lv_alloc.h b/lib/metadata/lv_alloc.h
index e44fe89a1..4607b802c 100644
--- a/lib/metadata/lv_alloc.h
+++ b/lib/metadata/lv_alloc.h
@@ -30,8 +30,8 @@ struct lv_segment *alloc_lv_segment(struct pool *mem,
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
uint32_t allocated);
-void set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
- struct physical_volume *pv, uint32_t pe);
+int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
+ struct physical_volume *pv, uint32_t pe);
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
struct logical_volume *lv, uint32_t le);
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 20bc2ad71..94088c6d6 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -20,6 +20,7 @@
#include "lvm-string.h"
#include "toolcontext.h"
#include "lv_alloc.h"
+#include "pv_alloc.h"
#include "display.h"
#include "segtype.h"
@@ -36,7 +37,7 @@ static void _get_extents(struct lv_segment *seg)
if (seg->area[s].type != AREA_PV)
continue;
- pv = seg->area[s].u.pv.pv;
+ pv = seg->area[s].u.pv.pvseg->pv;
count = seg->area_len;
pv->pe_alloc_count += count;
}
@@ -51,7 +52,7 @@ static void _put_extents(struct lv_segment *seg)
if (seg->area[s].type != AREA_PV)
continue;
- pv = seg->area[s].u.pv.pv;
+ pv = seg->area[s].u.pv.pvseg->pv;
if (pv) {
count = seg->area_len;
@@ -95,13 +96,18 @@ struct lv_segment *alloc_lv_segment(struct pool *mem,
return seg;
}
-void set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
- struct physical_volume *pv, uint32_t pe)
+int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
+ struct physical_volume *pv, uint32_t pe)
{
seg->area[area_num].type = AREA_PV;
- seg->area[area_num].u.pv.pv = pv;
- seg->area[area_num].u.pv.pe = pe;
- seg->area[area_num].u.pv.pvseg = NULL;
+
+ if (!(seg->area[area_num].u.pv.pvseg =
+ assign_peg_to_lvseg(pv, pe, seg->area_len, seg, area_num))) {
+ stack;
+ return 0;
+ }
+
+ return 1;
}
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
@@ -112,6 +118,17 @@ void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
seg->area[area_num].u.lv.le = le;
}
+static void _shrink_lv_segment(struct lv_segment *seg)
+{
+ uint32_t s;
+
+ for (s = 0; s < seg->area_count; s++) {
+ if (seg->area[s].type != AREA_PV)
+ continue;
+ release_pv_segment(seg->area[s].u.pv.pvseg, seg->area_len);
+ }
+}
+
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
uint32_t stripe_size,
struct segment_type *segtype,
@@ -143,7 +160,11 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
for (s = 0; s < area_count; s++) {
struct pv_area *pva = areas[s];
- set_lv_segment_area_pv(seg, s, pva->map->pvl->pv, pva->start);
+ if (!set_lv_segment_area_pv(seg, s, pva->map->pvl->pv,
+ pva->start)) {
+ stack;
+ return 0;
+ }
consume_pv_area(pva, area_len);
}
@@ -267,7 +288,10 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
return 0;
}
- set_lv_segment_area_pv(seg, 0, map->pvl->pv, pva->start);
+ if (!set_lv_segment_area_pv(seg, 0, map->pvl->pv, pva->start)) {
+ stack;
+ return 0;
+ }
list_add(&lv->segments, &seg->list);
@@ -298,8 +322,11 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
}
/* FIXME Remove AREA_PV restriction here? */
- set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe);
- set_lv_segment_area_pv(seg, 1, map->pvl->pv, pva->start);
+ if (!set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe) ||
+ !set_lv_segment_area_pv(seg, 1, map->pvl->pv, pva->start)) {
+ stack;
+ return 0;
+ }
list_add(&lv->segments, &seg->list);
@@ -717,6 +744,8 @@ int lv_reduce(struct format_instance *fi,
/* remove this segment completely */
count -= seg->len;
_put_extents(seg);
+ seg->area_len = 0;
+ _shrink_lv_segment(seg);
list_del(segh);
} else {
/* reduce this segment */
@@ -732,6 +761,7 @@ int lv_reduce(struct format_instance *fi,
}
seg->area_len -=
count / (striped ? seg->area_count : 1);
+ _shrink_lv_segment(seg);
_get_extents(seg);
count = 0;
}
@@ -751,7 +781,7 @@ int lv_reduce(struct format_instance *fi,
int lv_remove(struct volume_group *vg, struct logical_volume *lv)
{
- struct list *segh;
+ struct lv_segment *seg;
struct lv_list *lvl;
/* find the lv list */
@@ -761,8 +791,8 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
}
/* iterate through the lv's segments freeing off the pe's */
- list_iterate(segh, &lv->segments)
- _put_extents(list_item(segh, struct lv_segment));
+ list_iterate_items(seg, &lv->segments)
+ _put_extents(seg);
vg->lv_count--;
vg->free_count += lv->le_count;
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index ecfd8379e..68d153eea 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -17,6 +17,7 @@
#include "metadata.h"
#include "toolcontext.h"
#include "lv_alloc.h"
+#include "pv_alloc.h"
#include "str_list.h"
#include "segtype.h"
@@ -85,7 +86,6 @@ int lv_check_segments(struct logical_volume *lv)
static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
uint32_t le)
{
- size_t len;
struct lv_segment *split_seg;
uint32_t s;
uint32_t offset = le - seg->le;
@@ -108,10 +108,6 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
return 0;
}
- /* FIXME Avoid the memcpy */
- len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
- memcpy(split_seg, seg, len);
-
if (!str_list_dup(lv->vg->cmd->mem, &split_seg->tags, &seg->tags)) {
log_error("LV segment tags duplication failed");
return 0;
@@ -122,25 +118,43 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
if (seg->segtype->flags & SEG_AREAS_STRIPED)
area_offset /= seg->area_count;
+ split_seg->area_len -= area_offset;
+ seg->area_len = area_offset;
+
+ split_seg->len -= offset;
+ seg->len = offset;
+
+ split_seg->le = seg->le + seg->len;
+
/* Adjust the PV mapping */
for (s = 0; s < seg->area_count; s++) {
+ split_seg->area[s].type = seg->area[s].type;
+
/* Split area at the offset */
switch (seg->area[s].type) {
case AREA_LV:
+ split_seg->area[s].u.lv.lv = seg->area[s].u.lv.lv;
split_seg->area[s].u.lv.le =
- seg->area[s].u.lv.le + area_offset;
+ seg->area[s].u.lv.le + seg->area_len;
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
seg->le, s, le, seg->area[s].u.lv.lv->name,
split_seg->area[s].u.lv.le);
break;
case AREA_PV:
- split_seg->area[s].u.pv.pe =
- seg->area[s].u.pv.pe + area_offset;
+ if (!assign_peg_to_lvseg(seg->area[s].u.pv.pvseg->pv,
+ seg->area[s].u.pv.pvseg->pe +
+ seg->area_len,
+ seg->area[s].u.pv.pvseg->len -
+ seg->area_len,
+ split_seg, s)) {
+ stack;
+ return 0;
+ }
log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
seg->le, s, le,
- dev_name(seg->area[s].u.pv.pv->dev),
- split_seg->area[s].u.pv.pe);
+ dev_name(seg->area[s].u.pv.pvseg->pv->dev),
+ split_seg->area[s].u.pv.pvseg->pe);
break;
default:
@@ -150,14 +164,6 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
}
}
- split_seg->area_len -= area_offset;
- seg->area_len = area_offset;
-
- split_seg->len -= offset;
- seg->len = offset;
-
- split_seg->le = seg->le + seg->len;
-
/* Add split off segment to the list _after_ the original one */
list_add_h(&seg->list, &split_seg->list);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index bad3f5bf0..d11529cc8 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -101,9 +101,14 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
return 0;
}
- pvl->pv = pv;
+ if (!alloc_pv_segment_whole_pv(mem, pv)) {
+ stack;
+ return NULL;
+ }
+ pvl->pv = pv;
list_add(&vg->pvs, &pvl->list);
+
vg->pv_count++;
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
@@ -335,6 +340,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv;
struct logical_volume *lv;
struct lv_segment *seg;
+ struct pv_segment *pvseg;
uint32_t s;
vg->extent_size = new_size;
@@ -373,6 +379,22 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
stack;
return 0;
}
+
+ /* foreach PV Segment */
+ list_iterate_items(pvseg, &pv->free_segments) {
+ if (!_recalc_extents(&pvseg->pe, dev_name(pv->dev),
+ " PV segment start", old_size,
+ new_size)) {
+ stack;
+ return 0;
+ }
+ if (!_recalc_extents(&pvseg->len, dev_name(pv->dev),
+ " PV segment length", old_size,
+ new_size)) {
+ stack;
+ return 0;
+ }
+ }
}
/* foreach LV */
@@ -419,8 +441,17 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
switch (seg->area[s].type) {
case AREA_PV:
if (!_recalc_extents
- (&seg->area[s].u.pv.pe, lv->name,
- " area start", old_size,
+ (&seg->area[s].u.pv.pvseg->pe,
+ lv->name,
+ " pvseg start", old_size,
+ new_size)) {
+ stack;
+ return 0;
+ }
+ if (!_recalc_extents
+ (&seg->area[s].u.pv.pvseg->len,
+ lv->name,
+ " pvseg length", old_size,
new_size)) {
stack;
return 0;
@@ -658,6 +689,19 @@ struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
return NULL;
}
+/* Find segment at a given physical extent in a PV */
+struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
+{
+ struct pv_segment *peg;
+
+ list_iterate_items(peg, &pv->segments) {
+ if (pe >= peg->pe && pe < peg->pe + peg->len)
+ return peg;
+ }
+
+ return NULL;
+}
+
int vg_remove(struct volume_group *vg)
{
struct list *mdah;
@@ -686,6 +730,12 @@ int vg_write(struct volume_group *vg)
struct list *mdah, *mdah2;
struct metadata_area *mda;
+ if (!check_pv_segments(vg)) {
+ log_error("Internal error: PV segments corrupted in %s.",
+ vg->name);
+ return 0;
+ }
+
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
vg->name);
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 44d330fdd..f9ca1a80d 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -241,8 +241,6 @@ struct lv_segment {
area_type_t type;
union {
struct {
- struct physical_volume *pv;
- uint32_t pe;
struct pv_segment *pvseg;
} pv;
struct {
@@ -486,6 +484,9 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
/* Find LV segment containing given LE */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
+/* Find PV segment containing given LE */
+struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe);
+
/*
* Remove a dev_dir if present.
*/
diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c
index c5e5f9ce7..c6af7ba14 100644
--- a/lib/metadata/mirror.c
+++ b/lib/metadata/mirror.c
@@ -62,12 +62,12 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_PV ||
- seg->area[s].u.pv.pv->dev != pvl->pv->dev)
+ seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev)
continue;
/* Do these PEs need moving? */
list_iterate_items(per, pvl->pe_ranges) {
- pe_start = seg->area[s].u.pv.pe;
+ pe_start = seg->area[s].u.pv.pvseg->pe;
pe_end = pe_start + seg->area_len - 1;
per_end = per->start + per->count - 1;
@@ -107,10 +107,10 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_PV ||
- seg->area[s].u.pv.pv->dev != pvl->pv->dev)
+ seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev)
continue;
- pe_start = seg->area[s].u.pv.pe;
+ pe_start = seg->area[s].u.pv.pvseg->pe;
/* Do these PEs need moving? */
list_iterate_items(per, pvl->pe_ranges) {
@@ -122,8 +122,10 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
log_debug("Matched PE range %u-%u against "
"%s %u len %u", per->start, per_end,
- dev_name(seg->area[s].u.pv.pv->dev),
- seg->area[s].u.pv.pe, seg->area_len);
+ dev_name(seg->area[s].u.pv.pvseg->
+ pv->dev),
+ seg->area[s].u.pv.pvseg->pe,
+ seg->area_len);
/* First time, add LV to list of LVs affected */
if (!lv_used) {
@@ -138,16 +140,16 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
log_very_verbose("Moving %s:%u-%u of %s/%s",
dev_name(pvl->pv->dev),
- seg->area[s].u.pv.pe,
- seg->area[s].u.pv.pe +
+ seg->area[s].u.pv.pvseg->pe,
+ seg->area[s].u.pv.pvseg->pe +
seg->area_len - 1,
lv->vg->name, lv->name);
start_le = lv_mirr->le_count;
if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
seg->area_len, 0u, seg->area_len,
- seg->area[s].u.pv.pv,
- seg->area[s].u.pv.pe,
+ seg->area[s].u.pv.pvseg->pv,
+ seg->area[s].u.pv.pvseg->pe,
PVMOVE, allocatable_pvs,
lv->alloc)) {
log_error("Unable to allocate "
@@ -224,9 +226,12 @@ int remove_pvmove_mirrors(struct volume_group *vg,
else
c = 0;
- set_lv_segment_area_pv(seg, s,
- mir_seg->area[c].u.pv.pv,
- mir_seg->area[c].u.pv.pe);
+ if (!set_lv_segment_area_pv(seg, s,
+ mir_seg->area[c].u.pv.pvseg->pv,
+ mir_seg->area[c].u.pv.pvseg->pe)) {
+ stack;
+ return 0;
+ }
/* Replace mirror with old area */
if (!
@@ -262,7 +267,7 @@ const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
continue;
if (seg->area[0].type != AREA_PV)
continue;
- return dev_name(seg->area[0].u.pv.pv->dev);
+ return dev_name(seg->area[0].u.pv.pvseg->pv->dev);
}
return NULL;
@@ -306,7 +311,7 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
seg = list_item(segh, struct lv_segment);
if (seg->area[0].type != AREA_PV)
continue;
- if (seg->area[0].u.pv.pv->dev != dev)
+ if (seg->area[0].u.pv.pvseg->pv->dev != dev)
continue;
return lv;
}
diff --git a/lib/metadata/pv_alloc.h b/lib/metadata/pv_alloc.h
index 88b9a56fb..655f2238e 100644
--- a/lib/metadata/pv_alloc.h
+++ b/lib/metadata/pv_alloc.h
@@ -18,5 +18,13 @@
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv);
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
struct list *peg_old);
+struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe,
+ uint32_t area_len,
+ struct lv_segment *seg,
+ uint32_t area_num);
+int pv_split_segment(struct physical_volume *pv, uint32_t pe);
+int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len);
+int check_pv_segments(struct volume_group *vg);
+void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2);
#endif
diff --git a/lib/metadata/pv_manip.c b/lib/metadata/pv_manip.c
index 2b7ba4f41..0758f743c 100644
--- a/lib/metadata/pv_manip.c
+++ b/lib/metadata/pv_manip.c
@@ -17,10 +17,13 @@
#include "pool.h"
#include "metadata.h"
#include "pv_alloc.h"
+#include "toolcontext.h"
static struct pv_segment *_alloc_pv_segment(struct pool *mem,
struct physical_volume *pv,
- uint32_t pe, uint32_t len)
+ uint32_t pe, uint32_t len,
+ struct lv_segment *lvseg,
+ uint32_t lv_area)
{
struct pv_segment *peg;
@@ -32,8 +35,8 @@ static struct pv_segment *_alloc_pv_segment(struct pool *mem,
peg->pv = pv;
peg->pe = pe;
peg->len = len;
- peg->lvseg = NULL;
- peg->lv_area = 0;
+ peg->lvseg = lvseg;
+ peg->lv_area = lv_area;
list_init(&peg->list);
list_init(&peg->freelist);
@@ -43,18 +46,21 @@ static struct pv_segment *_alloc_pv_segment(struct pool *mem,
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
{
- struct pv_segment *peg;
+ struct pv_segment *peg;
+
+ if (!pv->pe_count)
+ return 1;
/* FIXME Cope with holes in PVs */
- if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count))) {
- stack;
- return 0;
- }
+ if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count, NULL, 0))) {
+ stack;
+ return 0;
+ }
- list_add(&pv->segments, &peg->list);
- list_add(&pv->free_segments, &peg->freelist);
+ list_add(&pv->segments, &peg->list);
+ list_add(&pv->free_segments, &peg->freelist);
- return 1;
+ return 1;
}
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
@@ -67,12 +73,11 @@ int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
list_iterate_items(pego, peg_old) {
if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
- pego->len))) {
+ pego->len, pego->lvseg,
+ pego->lv_area))) {
stack;
return 0;
}
- peg->lvseg = pego->lvseg;
- peg->lv_area = pego->lv_area;
list_add(peg_new, &peg->list);
if (!peg->lvseg)
list_add(peg_free_new, &peg->freelist);
@@ -81,3 +86,197 @@ int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
return 1;
}
+/*
+ * Split peg at given extent.
+ * Second part is always deallocated.
+ */
+static int _pv_split_segment(struct physical_volume *pv, struct pv_segment *peg,
+ uint32_t pe)
+{
+ struct pv_segment *peg_new;
+
+ if (!(peg_new = _alloc_pv_segment(pv->fmt->cmd->mem, peg->pv, pe,
+ peg->len + peg->pe - pe,
+ NULL, 0))) {
+ stack;
+ return 0;
+ }
+
+ peg->len = peg->len - peg_new->len;
+
+ list_add_h(&peg->list, &peg_new->list);
+ list_add_h(&pv->free_segments, &peg_new->freelist);
+
+ return 1;
+}
+
+/*
+ * Ensure there is a PV segment boundary at the given extent.
+ */
+int pv_split_segment(struct physical_volume *pv, uint32_t pe)
+{
+ struct pv_segment *peg;
+
+ if (pe == pv->pe_count)
+ return 1;
+
+ if (!(peg = find_peg_by_pe(pv, pe))) {
+ log_error("Segment with extent %" PRIu32 " in PV %s not found",
+ pe, dev_name(pv->dev));
+ return 0;
+ }
+
+ /* This is a peg start already */
+ if (pe == peg->pe)
+ return 1;
+
+ if (!_pv_split_segment(pv, peg, pe)) {
+ stack;
+ return 0;
+ }
+
+ return 1;
+}
+
+struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
+ uint32_t pe, uint32_t area_len,
+ struct lv_segment *seg,
+ uint32_t area_num)
+{
+ struct pv_segment *peg;
+
+ if (!pv_split_segment(pv, pe) ||
+ !pv_split_segment(pv, pe + area_len)) {
+ stack;
+ return NULL;
+ }
+
+ if (!(peg = find_peg_by_pe(pv, pe))) {
+ log_error("Missing PV segment on %s at %u.",
+ dev_name(pv->dev), pe);
+ return NULL;
+ }
+
+ peg->lvseg = seg;
+ peg->lv_area = area_num;
+
+ list_del(&peg->freelist);
+ list_init(&peg->freelist);
+
+ return peg;
+}
+
+int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len)
+{
+ if (new_area_len == 0) {
+ peg->lvseg = NULL;
+ peg->lv_area = 0;
+
+ /* FIXME merge free space */
+ list_add(&peg->pv->free_segments, &peg->freelist);
+
+ return 1;
+ }
+
+ if (!pv_split_segment(peg->pv, peg->pe + new_area_len)) {
+ stack;
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Only for use by lv_segment merging routines.
+ */
+void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2)
+{
+ peg1->len += peg2->len;
+
+ list_del(&peg2->list);
+
+ if (!list_empty(&peg2->freelist))
+ list_del(&peg2->freelist);
+}
+
+/*
+ * Check all pv_segments in VG for consistency
+ */
+int check_pv_segments(struct volume_group *vg)
+{
+ struct physical_volume *pv;
+ struct pv_list *pvl;
+ struct pv_segment *peg;
+ unsigned s, segno;
+ int free_count, free_total, free_size;
+ uint32_t start_pe;
+ int ret = 1;
+
+ list_iterate_items(pvl, &vg->pvs) {
+ pv = pvl->pv;
+ segno = 0;
+ start_pe = 0;
+ free_total = 0;
+
+ free_count = list_size(&pv->free_segments);
+
+ list_iterate_items(peg, &pv->segments) {
+ free_size = list_size(&peg->freelist);
+ s = peg->lv_area;
+
+ /* FIXME Remove this next line eventually */
+ log_debug("%s %u: %6u %6u: %s(%u:%u)",
+ dev_name(pv->dev), segno++, peg->pe, peg->len,
+ peg->lvseg ? peg->lvseg->lv->name : "NULL",
+ peg->lvseg ? peg->lvseg->le : 0, s);
+ /* FIXME Add details here on failure instead */
+ if (start_pe != peg->pe) {
+ log_debug("Gap in pvsegs: %u, %u",
+ start_pe, peg->pe);
+ ret = 0;
+ }
+ if (peg->lvseg) {
+ if (peg->lvseg->area[s].type != AREA_PV) {
+ log_debug("Wrong lvseg area type");
+ ret = 0;
+ }
+ if (peg->lvseg->area[s].u.pv.pvseg != peg) {
+ log_debug("Inconsistent pvseg pointers");
+ ret = 0;
+ }
+ if (peg->lvseg->area_len != peg->len) {
+ log_debug("Inconsistent length: %u %u",
+ peg->len,
+ peg->lvseg->area_len);
+ ret = 0;
+ }
+ if (free_size) {
+ log_debug("Segment is on free list!");
+ ret = 0;
+ }
+ } else {
+ free_total++;
+ if (!free_size) {
+ log_debug("Seg missing from free list");
+ ret = 0;
+ }
+ if (free_size != free_count) {
+ log_debug("Seg free size inconsistent: "
+ "%u != %u", free_size,
+ free_count);
+ ret = 0;
+ }
+ }
+ start_pe += peg->len;
+ }
+
+ if (free_count != free_total) {
+ log_debug("Free list inconsistent: %u != %u",
+ free_count, free_total);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c
index 118006909..2bfbaa144 100644
--- a/lib/metadata/pv_map.c
+++ b/lib/metadata/pv_map.c
@@ -109,9 +109,9 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
if (seg->area[s].type != AREA_PV)
continue;
if (!_set_allocd(hash,
- seg->area[s].u.pv.pv,
- seg->area[s].u.pv.pe
- + pe)) {
+ seg->area[s].u.pv.pvseg->pv,
+ seg->area[s].u.pv.pvseg->pe
+ + pe)) {
stack;
goto out;
}
diff --git a/lib/report/report.c b/lib/report/report.c
index bc33b0ab5..3eb854005 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -160,8 +160,8 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
extent = seg->area[s].u.lv.le;
break;
case AREA_PV:
- name = dev_name(seg->area[s].u.pv.pv->dev);
- extent = seg->area[s].u.pv.pe;
+ name = dev_name(seg->area[s].u.pv.pvseg->pv->dev);
+ extent = seg->area[s].u.pv.pvseg->pe;
break;
default:
name = "unknown";
@@ -502,7 +502,7 @@ static int _movepv_disp(struct report_handle *rh, struct field *field,
seg = list_item(segh, struct lv_segment);
if (!(seg->status & PVMOVE))
continue;
- name = dev_name(seg->area[0].u.pv.pv->dev);
+ name = dev_name(seg->area[0].u.pv.pvseg->pv->dev);
return _string_disp(rh, field, &name);
}
diff --git a/lib/striped/striped.c b/lib/striped/striped.c
index ccd369d38..dd95454df 100644
--- a/lib/striped/striped.c
+++ b/lib/striped/striped.c
@@ -26,6 +26,7 @@
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
+#include "pv_alloc.h"
static const char *_name(const struct lv_segment *seg)
{
@@ -118,8 +119,10 @@ static int _segments_compatible(struct lv_segment *first,
width = first->area_len;
- if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
- (first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
+ if ((first->area[s].u.pv.pvseg->pv !=
+ second->area[s].u.pv.pvseg->pv) ||
+ (first->area[s].u.pv.pvseg->pe + width !=
+ second->area[s].u.pv.pvseg->pe))
return 0;
}
@@ -131,12 +134,19 @@ static int _segments_compatible(struct lv_segment *first,
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
{
+ uint32_t s;
+
if (!_segments_compatible(seg1, seg2))
return 0;
seg1->len += seg2->len;
seg1->area_len += seg2->area_len;
+ for (s = 0; s < seg1->area_count; s++)
+ if (seg1->area[s].type == AREA_PV)
+ merge_pv_segments(seg1->area[s].u.pv.pvseg,
+ seg2->area[s].u.pv.pvseg);
+
return 1;
}
diff --git a/tools/vgreduce.c b/tools/vgreduce.c
index 80de5525c..70e0ee912 100644
--- a/tools/vgreduce.c
+++ b/tools/vgreduce.c
@@ -134,7 +134,7 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
/* FIXME Also check for segs on deleted LVs */
- pv = seg->area[s].u.pv.pv;
+ pv = seg->area[s].u.pv.pvseg->pv;
if (!pv || !pv->dev) {
if (!_remove_lv(cmd, lv, &list_unsafe)) {
stack;
@@ -190,6 +190,13 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
list_del(&pvl->list);
pv->vg_name = ORPHAN;
+ pv->status = ALLOCATABLE_PV;
+
+ if (!dev_get_size(pv->dev, &pv->size)) {
+ log_error("%s: Couldn't get size.", dev_name(pv->dev));
+ return ECMD_FAILED;
+ }
+
vg->pv_count--;
vg->free_count -= pv->pe_count - pv->pe_alloc_count;
vg->extent_count -= pv->pe_count;
diff --git a/tools/vgremove.c b/tools/vgremove.c
index 7b85e2078..84441085e 100644
--- a/tools/vgremove.c
+++ b/tools/vgremove.c
@@ -56,6 +56,14 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
log_verbose("Removing physical volume \"%s\" from "
"volume group \"%s\"", dev_name(pv->dev), vg_name);
pv->vg_name = ORPHAN;
+ pv->status = ALLOCATABLE_PV;
+
+ if (!dev_get_size(pv->dev, &pv->size)) {
+ log_error("%s: Couldn't get size.", dev_name(pv->dev));
+ ret = ECMD_FAILED;
+ continue;
+ }
+
/* FIXME Write to same sector label was read from */
if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
log_error("Failed to remove physical volume \"%s\""
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index 741075c1f..4762ebd57 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -81,7 +81,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
if (seg->area[s].type != AREA_PV)
continue;
- pv = seg->area[s].u.pv.pv;
+ pv = seg->area[s].u.pv.pvseg->pv;
if (vg_with) {
if (!pv_is_in_vg(vg_with, pv)) {
log_error("Logical Volume %s "