diff --git a/lib/Makefile.in b/lib/Makefile.in index ebac6e57c..c6aa882f5 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -37,6 +37,7 @@ SOURCES=\ label/label.c \ log/log.c \ metadata/lv_manip.c \ + metadata/merge.c \ metadata/metadata.c \ metadata/pv_map.c \ mm/dbg_malloc.c \ diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 7de92ed81..8dbc72fd2 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -9,6 +9,7 @@ #include "log.h" #include "dbg_malloc.h" #include "lvm-string.h" +#include "merge.h" #include @@ -150,7 +151,7 @@ static int _alloc_striped(struct logical_volume *lv, /* sort the areas so we allocate from the biggest */ qsort(areas, index, sizeof(*areas), _comp_area); - if (!_alloc_stripe_area(lv, stripes, stripe_size, areas, + if (!_alloc_stripe_area(lv, stripes, stripe_size, areas, &allocated)) { stack; goto out; @@ -497,6 +498,12 @@ int lv_extend(struct logical_volume *lv, return 0; } + if (!merge_segments(lv)) { + log_err("Couldn't merge segments after extending " + "logical volume."); + return 0; + } + return 1; } diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c new file mode 100644 index 000000000..9c390944c --- /dev/null +++ b/lib/metadata/merge.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the LGPL. + */ + +#include "log.h" +#include "merge.h" + +/* + * Returns success if the segments were + * successfully merged. If the do merge, 'first' + * will be adjusted to contain both areas. + */ +static int _merge(struct stripe_segment *first, struct stripe_segment *second) +{ + int s; + uint32_t width; + + if (!first || + (first->stripes != second->stripes) || + (first->stripe_size != second->stripe_size)) + return 0; + + for (s = 0; s < first->stripes; s++) { + width = first->len / first->stripes; + + if ((first->area[s].pv != second->area[s].pv) || + (first->area[s].pe + width != second->area[s].pe)) + return 0; + } + + /* we should merge */ + first->len += second->len; + + return 1; +} + +int merge_segments(struct logical_volume *lv) +{ + struct list *segh; + struct stripe_segment *current, *prev = NULL; + + list_iterate (segh, &lv->segments) { + current = list_item(segh, struct stripe_segment); + + if (_merge(prev, current)) + list_del(¤t->list); + else + prev = current; + } + + return 1; +} + diff --git a/lib/metadata/merge.h b/lib/metadata/merge.h new file mode 100644 index 000000000..f15b2376a --- /dev/null +++ b/lib/metadata/merge.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the LGPL. + */ + +#ifndef _LVM_MERGE_H +#define _LVM_MERGE_H + +#include "metadata.h" + +/* + * Sometimes (eg, after an lvextend), it is + * possible to merge two adjacent segments into a + * single segment. This function trys to merge as + * many segments as possible. + */ +int merge_segments(struct logical_volume *lv); + +#endif /* _LVM_MERGE_H */