1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-02-23 13:57:47 +03:00

Reinstate full PV size when removing from VG.

Support loopfiles for testing.
Complete the pv_segment support.
This commit is contained in:
Alasdair Kergon 2005-05-03 17:28:23 +00:00
parent 40e896bc5b
commit 87dbf462cb
29 changed files with 625 additions and 130 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
/*

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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.
*/

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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.
*/

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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\""

View File

@ -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 "