diff --git a/lib/datastruct/list.h b/lib/datastruct/list.h index df3d32aea..a0054aa7f 100644 --- a/lib/datastruct/list.h +++ b/lib/datastruct/list.h @@ -63,26 +63,6 @@ static inline struct list *list_next(struct list *head, struct list *elem) return (list_end(head, elem) ? NULL : elem->n); } -#define list_iterate(v, head) \ - for (v = (head)->n; v != head; v = v->n) - -#define list_uniterate(v, head, start) \ - for (v = (start)->p; v != head; v = v->p) - -#define list_iterate_safe(v, t, head) \ - for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) - -static inline unsigned int list_size(const struct list *head) -{ - unsigned int s = 0; - const struct list *v; - - list_iterate(v, head) - s++; - - return s; -} - #define list_item(v, t) \ ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list)) @@ -96,4 +76,28 @@ static inline unsigned int list_size(const struct list *head) /* Given a known element in a known structure, locate the list head */ #define list_head(v, t, e) struct_field(v, t, e, list) +#define list_iterate(v, head) \ + for (v = (head)->n; v != head; v = v->n) + +#define list_uniterate(v, head, start) \ + for (v = (start)->p; v != head; v = v->p) + +#define list_iterate_safe(v, t, head) \ + for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) + +#define list_iterate_items(v, head) \ + for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \ + v = list_item(v->list.n, typeof(*v))) + +static inline unsigned int list_size(const struct list *head) +{ + unsigned int s = 0; + const struct list *v; + + list_iterate(v, head) + s++; + + return s; +} + #endif diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 1efe5add7..0396eaa0f 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -321,7 +321,6 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) _inc_indent(f); list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; if (!(name = _get_pv_name(f, pv))) { @@ -522,7 +521,7 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg) static int _print_lvs(struct formatter *f, struct volume_group *vg) { - struct list *lvh, *segh; + struct list *lvh; struct logical_volume *lv; struct lv_segment *seg; char buffer[256]; @@ -571,9 +570,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) f->nl(f); seg_count = 1; - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); - + list_iterate_items(seg, &lv->segments) { if (!_print_segment(f, vg, seg_count++, seg)) { stack; return 0; diff --git a/lib/metadata/lv_alloc.h b/lib/metadata/lv_alloc.h new file mode 100644 index 000000000..fc087b3cf --- /dev/null +++ b/lib/metadata/lv_alloc.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2003 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + * + * This is the in core representation of a volume group and its + * associated physical and logical volumes. + */ + +#ifndef _LVM_LV_ALLOC_H +#include "pool.h" + +struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t stripes); +#endif diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 7d1943060..93a95fd3e 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -10,6 +10,7 @@ #include "pv_map.h" #include "lvm-string.h" #include "toolcontext.h" +#include "lv_alloc.h" /* * These functions adjust the pe counts in pv's @@ -49,7 +50,7 @@ static void _put_extents(struct lv_segment *seg) } } -static struct lv_segment *_alloc_segment(struct pool *mem, uint32_t stripes) +struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t stripes) { struct lv_segment *seg; uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0])); @@ -75,7 +76,7 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, if (smallest < area_len) area_len = smallest; - if (!(seg = _alloc_segment(lv->vg->cmd->mem, stripes))) { + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, stripes))) { log_err("Couldn't allocate new stripe segment."); return 0; } @@ -188,7 +189,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix, if (count > remaining) count = remaining; - if (!(seg = _alloc_segment(lv->vg->cmd->mem, 1))) { + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 1))) { log_err("Couldn't allocate new stripe segment."); return 0; } @@ -224,7 +225,7 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix, if (count > remaining) count = remaining; - if (!(seg = _alloc_segment(lv->vg->cmd->mem, 2))) { + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 2))) { log_err("Couldn't allocate new mirrored segment."); return 0; } @@ -731,8 +732,11 @@ int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags) lv = list_item(lvh, struct lv_list)->lv; if (!lock_vol(cmd, lv->lvid.s, flags)) { log_error("Failed to lock %s", lv->name); - /* FIXME Only unlock the locked ones */ - unlock_lvs(cmd, lvs); + list_uniterate(lvh, lvs, lvh) { + lv = list_item(lvh, struct lv_list)->lv; + unlock_lv(cmd, lv->lvid.s); + } + return 0; } } diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c index af3217cf6..286a92b8c 100644 --- a/lib/metadata/merge.c +++ b/lib/metadata/merge.c @@ -6,6 +6,8 @@ #include "lib.h" #include "metadata.h" +#include "toolcontext.h" +#include "lv_alloc.h" /* * Test whether two segments could be merged by the current merging code @@ -100,3 +102,89 @@ int lv_check_segments(struct logical_volume *lv) return 1; } +/* + * Split the supplied segment at the supplied logical extent + */ +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; + + if (seg->type == SEG_SNAPSHOT) { + log_error("Unable to split the snapshot segment at LE %" PRIu32 + " in LV %s", le, lv->name); + return 0; + } + + /* Clone the existing segment */ + if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, + seg->area_count))) { + log_error("Couldn't allocate new LV segment."); + return 0; + } + + len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0])); + memcpy(split_seg, seg, len); + + /* In case of a striped segment, the offset has to be / stripes */ + if (seg->type == SEG_STRIPED) + offset /= seg->area_count; + + /* Adjust the PV mapping */ + for (s = 0; s < seg->area_count; s++) { + /* Split area at the offset */ + switch (seg->area[s].type) { + case AREA_LV: + split_seg->area[s].u.lv.le = + seg->area[s].u.lv.le + offset; + break; + + case AREA_PV: + split_seg->area[s].u.pv.pe = + seg->area[s].u.pv.pe + offset; + break; + + default: + log_error("Unrecognised segment type %u", + seg->area[s].type); + return 0; + } + } + + split_seg->area_len = seg->area_len - offset; + seg->area_len = offset; + + /* Add split off segment to the list _after_ the original one */ + list_add_h(&seg->list, &split_seg->list); + + return 1; +} + +/* + * Ensure there's a segment boundary at the given logical extent + */ +int lv_split_segment(struct logical_volume *lv, uint32_t le) +{ + struct lv_segment *seg; + + if (!(seg = find_seg_by_le(lv, le))) { + log_error("Segment with extent %" PRIu32 " in LV %s not found", + le, lv->name); + return 0; + } + + /* This is a segment start already */ + if (le == seg->le) + return 1; + + if (!_lv_split_segment(lv, seg, le)) { + stack; + return 0; + } + + return 1; +} + diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 0e4d3ec0d..24e79fc37 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -468,6 +468,11 @@ int lv_check_segments(struct logical_volume *lv); */ int lv_merge_segments(struct logical_volume *lv); +/* + * Ensure there's a segment boundary at a given LE, splitting if necessary + */ +int lv_split_segment(struct logical_volume *lv, uint32_t le); + /* * Useful functions for managing snapshots. */ diff --git a/libdm/datastruct/list.h b/libdm/datastruct/list.h index df3d32aea..a0054aa7f 100644 --- a/libdm/datastruct/list.h +++ b/libdm/datastruct/list.h @@ -63,26 +63,6 @@ static inline struct list *list_next(struct list *head, struct list *elem) return (list_end(head, elem) ? NULL : elem->n); } -#define list_iterate(v, head) \ - for (v = (head)->n; v != head; v = v->n) - -#define list_uniterate(v, head, start) \ - for (v = (start)->p; v != head; v = v->p) - -#define list_iterate_safe(v, t, head) \ - for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) - -static inline unsigned int list_size(const struct list *head) -{ - unsigned int s = 0; - const struct list *v; - - list_iterate(v, head) - s++; - - return s; -} - #define list_item(v, t) \ ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list)) @@ -96,4 +76,28 @@ static inline unsigned int list_size(const struct list *head) /* Given a known element in a known structure, locate the list head */ #define list_head(v, t, e) struct_field(v, t, e, list) +#define list_iterate(v, head) \ + for (v = (head)->n; v != head; v = v->n) + +#define list_uniterate(v, head, start) \ + for (v = (start)->p; v != head; v = v->p) + +#define list_iterate_safe(v, t, head) \ + for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) + +#define list_iterate_items(v, head) \ + for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \ + v = list_item(v->list.n, typeof(*v))) + +static inline unsigned int list_size(const struct list *head) +{ + unsigned int s = 0; + const struct list *v; + + list_iterate(v, head) + s++; + + return s; +} + #endif