1 /*        $NetBSD: merge.c,v 1.1.1.1 2008/12/22 00:18:07 haad Exp $   */
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "lib.h"
19 #include "metadata.h"
20 #include "toolcontext.h"
21 #include "lv_alloc.h"
22 #include "pv_alloc.h"
23 #include "str_list.h"
24 #include "segtype.h"
25 
26 /*
27  * Attempt to merge two adjacent segments.
28  * Currently only supports striped segments on AREA_PV.
29  * Returns success if successful, in which case 'first'
30  * gets adjusted to contain both areas.
31  */
_merge(struct lv_segment * first,struct lv_segment * second)32 static int _merge(struct lv_segment *first, struct lv_segment *second)
33 {
34           if (!first || !second || first->segtype != second->segtype ||
35               !first->segtype->ops->merge_segments) return 0;
36 
37           return first->segtype->ops->merge_segments(first, second);
38 }
39 
lv_merge_segments(struct logical_volume * lv)40 int lv_merge_segments(struct logical_volume *lv)
41 {
42           struct dm_list *segh, *t;
43           struct lv_segment *current, *prev = NULL;
44 
45           if (lv->status & LOCKED || lv->status & PVMOVE)
46                     return 1;
47 
48           dm_list_iterate_safe(segh, t, &lv->segments) {
49                     current = dm_list_item(segh, struct lv_segment);
50 
51                     if (_merge(prev, current))
52                               dm_list_del(&current->list);
53                     else
54                               prev = current;
55           }
56 
57           return 1;
58 }
59 
60 /*
61  * Verify that an LV's segments are consecutive, complete and don't overlap.
62  */
check_lv_segments(struct logical_volume * lv,int complete_vg)63 int check_lv_segments(struct logical_volume *lv, int complete_vg)
64 {
65           struct lv_segment *seg, *seg2;
66           uint32_t le = 0;
67           unsigned seg_count = 0, seg_found;
68           int r = 1;
69           uint32_t area_multiplier, s;
70           struct seg_list *sl;
71 
72           dm_list_iterate_items(seg, &lv->segments) {
73                     seg_count++;
74                     if (seg->le != le) {
75                               log_error("LV %s invalid: segment %u should begin at "
76                                           "LE %" PRIu32 " (found %" PRIu32 ").",
77                                           lv->name, seg_count, le, seg->le);
78                               r = 0;
79                     }
80 
81                     area_multiplier = segtype_is_striped(seg->segtype) ?
82                                                   seg->area_count : 1;
83 
84                     if (seg->area_len * area_multiplier != seg->len) {
85                               log_error("LV %s: segment %u has inconsistent "
86                                           "area_len %u",
87                                           lv->name, seg_count, seg->area_len);
88                               r = 0;
89                     }
90 
91                     if (complete_vg && seg->log_lv) {
92                               if (!seg_is_mirrored(seg)) {
93                                         log_error("LV %s: segment %u has log LV but "
94                                                     "is not mirrored",
95                                                     lv->name, seg_count);
96                                         r = 0;
97                               }
98 
99                               if (!(seg->log_lv->status & MIRROR_LOG)) {
100                                         log_error("LV %s: segment %u log LV %s is not "
101                                                     "a mirror log",
102                                                      lv->name, seg_count, seg->log_lv->name);
103                                         r = 0;
104                               }
105 
106                               if (!(seg2 = first_seg(seg->log_lv)) ||
107                                   find_mirror_seg(seg2) != seg) {
108                                         log_error("LV %s: segment %u log LV does not "
109                                                     "point back to mirror segment",
110                                                      lv->name, seg_count);
111                                         r = 0;
112                               }
113                     }
114 
115                     if (complete_vg && seg->status & MIRROR_IMAGE) {
116                               if (!find_mirror_seg(seg) ||
117                                   !seg_is_mirrored(find_mirror_seg(seg))) {
118                                         log_error("LV %s: segment %u mirror image "
119                                                     "is not mirrored",
120                                                     lv->name, seg_count);
121                                         r = 0;
122                               }
123                     }
124 
125                     if (seg_is_snapshot(seg)) {
126                               if (seg->cow && seg->cow == seg->origin) {
127                                         log_error("LV %s: segment %u has same LV %s for "
128                                                     "both origin and snapshot",
129                                                     lv->name, seg_count, seg->cow->name);
130                                         r = 0;
131                               }
132                     }
133 
134                     for (s = 0; s < seg->area_count; s++) {
135                               if (seg_type(seg, s) == AREA_UNASSIGNED) {
136                                         log_error("LV %s: segment %u has unassigned "
137                                                     "area %u.",
138                                                     lv->name, seg_count, s);
139                                         r = 0;
140                               } else if (seg_type(seg, s) == AREA_PV) {
141                                         if (!seg_pvseg(seg, s) ||
142                                             seg_pvseg(seg, s)->lvseg != seg ||
143                                             seg_pvseg(seg, s)->lv_area != s) {
144                                                   log_error("LV %s: segment %u has "
145                                                               "inconsistent PV area %u",
146                                                               lv->name, seg_count, s);
147                                                   r = 0;
148                                         }
149                               } else {
150                                         if (!seg_lv(seg, s) ||
151                                             seg_lv(seg, s)->vg != lv->vg ||
152                                             seg_lv(seg, s) == lv) {
153                                                   log_error("LV %s: segment %u has "
154                                                               "inconsistent LV area %u",
155                                                               lv->name, seg_count, s);
156                                                   r = 0;
157                                         }
158 
159                                         if (complete_vg && seg_lv(seg, s) &&
160                                             (seg_lv(seg, s)->status & MIRROR_IMAGE) &&
161                                             (!(seg2 = find_seg_by_le(seg_lv(seg, s),
162                                                                           seg_le(seg, s))) ||
163                                              find_mirror_seg(seg2) != seg)) {
164                                                   log_error("LV %s: segment %u mirror "
165                                                               "image %u missing mirror ptr",
166                                                               lv->name, seg_count, s);
167                                                   r = 0;
168                                         }
169 
170 /* FIXME I don't think this ever holds?
171                                         if (seg_le(seg, s) != le) {
172                                                   log_error("LV %s: segment %u has "
173                                                               "inconsistent LV area %u "
174                                                               "size",
175                                                               lv->name, seg_count, s);
176                                                   r = 0;
177                                         }
178  */
179                                         seg_found = 0;
180                                         dm_list_iterate_items(sl, &seg_lv(seg, s)->segs_using_this_lv)
181                                                   if (sl->seg == seg)
182                                                             seg_found++;
183                                         if (!seg_found) {
184                                                   log_error("LV %s segment %d uses LV %s,"
185                                                               " but missing ptr from %s to %s",
186                                                               lv->name, seg_count,
187                                                               seg_lv(seg, s)->name,
188                                                               seg_lv(seg, s)->name, lv->name);
189                                                   r = 0;
190                                         } else if (seg_found > 1) {
191                                                   log_error("LV %s has duplicated links "
192                                                               "to LV %s segment %d",
193                                                               seg_lv(seg, s)->name,
194                                                               lv->name, seg_count);
195                                                   r = 0;
196                                         }
197                               }
198                     }
199 
200                     le += seg->len;
201           }
202 
203           dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
204                     seg = sl->seg;
205                     seg_found = 0;
206                     for (s = 0; s < seg->area_count; s++) {
207                               if (seg_type(seg, s) != AREA_LV)
208                                         continue;
209                               if (lv == seg_lv(seg, s))
210                                         seg_found++;
211                     }
212                     if (seg->log_lv == lv)
213                               seg_found++;
214                     if (!seg_found) {
215                               log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32
216                                           ", but missing ptr from %s to %s",
217                                           lv->name, seg->lv->name, seg->le,
218                                           seg->le + seg->len - 1,
219                                           seg->lv->name, lv->name);
220                               r = 0;
221                     } else if (seg_found != sl->count) {
222                               log_error("Reference count mismatch: LV %s has %d "
223                                           "links to LV %s:%" PRIu32 "-%" PRIu32
224                                           ", which has %d links",
225                                           lv->name, sl->count, seg->lv->name, seg->le,
226                                           seg->le + seg->len - 1, seg_found);
227                               r = 0;
228                     }
229 
230                     seg_found = 0;
231                     dm_list_iterate_items(seg2, &seg->lv->segments)
232                               if (sl->seg == seg2) {
233                                         seg_found++;
234                                         break;
235                               }
236                     if (!seg_found) {
237                               log_error("LV segment %s:%" PRIu32 "-%" PRIu32
238                                           "is incorrectly listed as being used by LV %s",
239                                           seg->lv->name, seg->le, seg->le + seg->len - 1,
240                                           lv->name);
241                               r = 0;
242                     }
243           }
244 
245           if (le != lv->le_count) {
246                     log_error("LV %s: inconsistent LE count %u != %u",
247                                 lv->name, le, lv->le_count);
248                     r = 0;
249           }
250 
251           return r;
252 }
253 
254 /*
255  * Split the supplied segment at the supplied logical extent
256  * NB Use LE numbering that works across stripes PV1: 0,2,4 PV2: 1,3,5 etc.
257  */
_lv_split_segment(struct logical_volume * lv,struct lv_segment * seg,uint32_t le)258 static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
259                                    uint32_t le)
260 {
261           struct lv_segment *split_seg;
262           uint32_t s;
263           uint32_t offset = le - seg->le;
264           uint32_t area_offset;
265 
266           if (!seg_can_split(seg)) {
267                     log_error("Unable to split the %s segment at LE %" PRIu32
268                                 " in LV %s", seg->segtype->name, le, lv->name);
269                     return 0;
270           }
271 
272           /* Clone the existing segment */
273           if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype,
274                                                      seg->lv, seg->le, seg->len,
275                                                      seg->status, seg->stripe_size,
276                                                      seg->log_lv,
277                                                      seg->area_count, seg->area_len,
278                                                      seg->chunk_size, seg->region_size,
279                                                      seg->extents_copied))) {
280                     log_error("Couldn't allocate cloned LV segment.");
281                     return 0;
282           }
283 
284           if (!str_list_dup(lv->vg->cmd->mem, &split_seg->tags, &seg->tags)) {
285                     log_error("LV segment tags duplication failed");
286                     return 0;
287           }
288 
289           /* In case of a striped segment, the offset has to be / stripes */
290           area_offset = offset;
291           if (seg_is_striped(seg))
292                     area_offset /= seg->area_count;
293 
294           split_seg->area_len -= area_offset;
295           seg->area_len = area_offset;
296 
297           split_seg->len -= offset;
298           seg->len = offset;
299 
300           split_seg->le = seg->le + seg->len;
301 
302           /* Adjust the PV mapping */
303           for (s = 0; s < seg->area_count; s++) {
304                     seg_type(split_seg, s) = seg_type(seg, s);
305 
306                     /* Split area at the offset */
307                     switch (seg_type(seg, s)) {
308                     case AREA_LV:
309                               if (!set_lv_segment_area_lv(split_seg, s, seg_lv(seg, s),
310                                                                 seg_le(seg, s) + seg->area_len, 0))
311                                         return_0;
312                               log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
313                                           seg->le, s, le, seg_lv(seg, s)->name,
314                                           seg_le(split_seg, s));
315                               break;
316 
317                     case AREA_PV:
318                               if (!(seg_pvseg(split_seg, s) =
319                                    assign_peg_to_lvseg(seg_pv(seg, s),
320                                                              seg_pe(seg, s) +
321                                                                  seg->area_len,
322                                                              seg_pvseg(seg, s)->len -
323                                                                  seg->area_len,
324                                                              split_seg, s)))
325                                         return_0;
326                               log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
327                                           seg->le, s, le,
328                                           dev_name(seg_dev(seg, s)),
329                                           seg_pe(split_seg, s));
330                               break;
331 
332                     case AREA_UNASSIGNED:
333                               log_error("Unassigned area %u found in segment", s);
334                               return 0;
335                     }
336           }
337 
338           /* Add split off segment to the list _after_ the original one */
339           dm_list_add_h(&seg->list, &split_seg->list);
340 
341           return 1;
342 }
343 
344 /*
345  * Ensure there's a segment boundary at the given logical extent
346  */
lv_split_segment(struct logical_volume * lv,uint32_t le)347 int lv_split_segment(struct logical_volume *lv, uint32_t le)
348 {
349           struct lv_segment *seg;
350 
351           if (!(seg = find_seg_by_le(lv, le))) {
352                     log_error("Segment with extent %" PRIu32 " in LV %s not found",
353                                 le, lv->name);
354                     return 0;
355           }
356 
357           /* This is a segment start already */
358           if (le == seg->le)
359                     return 1;
360 
361           if (!_lv_split_segment(lv, seg, le))
362                     return_0;
363 
364           if (!vg_validate(lv->vg))
365                     return_0;
366 
367           return 1;
368 }
369