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:
parent
40e896bc5b
commit
87dbf462cb
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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\""
|
||||
|
@ -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 "
|
||||
|
Loading…
x
Reference in New Issue
Block a user