diff options
-rw-r--r-- | WHATS_NEW | 4 | ||||
-rw-r--r-- | lib/activate/dev_manager.c | 13 | ||||
-rw-r--r-- | lib/commands/toolcontext.c | 18 | ||||
-rw-r--r-- | lib/config/config.c | 2 | ||||
-rw-r--r-- | lib/device/dev-cache.c | 146 | ||||
-rw-r--r-- | lib/device/dev-cache.h | 1 | ||||
-rw-r--r-- | lib/device/dev-io.c | 34 | ||||
-rw-r--r-- | lib/device/device.h | 2 | ||||
-rw-r--r-- | lib/display/display.c | 13 | ||||
-rw-r--r-- | lib/format1/import-export.c | 5 | ||||
-rw-r--r-- | lib/format1/import-extents.c | 15 | ||||
-rw-r--r-- | lib/format_pool/import_export.c | 10 | ||||
-rw-r--r-- | lib/format_text/export.c | 5 | ||||
-rw-r--r-- | lib/format_text/import_vsn1.c | 5 | ||||
-rw-r--r-- | lib/log/log.c | 2 | ||||
-rw-r--r-- | lib/metadata/lv_alloc.h | 4 | ||||
-rw-r--r-- | lib/metadata/lv_manip.c | 58 | ||||
-rw-r--r-- | lib/metadata/merge.c | 42 | ||||
-rw-r--r-- | lib/metadata/metadata.c | 56 | ||||
-rw-r--r-- | lib/metadata/metadata.h | 5 | ||||
-rw-r--r-- | lib/metadata/mirror.c | 35 | ||||
-rw-r--r-- | lib/metadata/pv_alloc.h | 8 | ||||
-rw-r--r-- | lib/metadata/pv_manip.c | 227 | ||||
-rw-r--r-- | lib/metadata/pv_map.c | 6 | ||||
-rw-r--r-- | lib/report/report.c | 6 | ||||
-rw-r--r-- | lib/striped/striped.c | 14 | ||||
-rw-r--r-- | tools/vgreduce.c | 9 | ||||
-rw-r--r-- | tools/vgremove.c | 8 | ||||
-rw-r--r-- | tools/vgsplit.c | 2 |
29 files changed, 625 insertions, 130 deletions
@@ -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 " |