xref: /dragonfly/contrib/lvm2/dist/lib/format1/import-extents.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*        $NetBSD: import-extents.c,v 1.1.1.2 2009/12/02 00:26:49 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 "disk-rep.h"
21 #include "lv_alloc.h"
22 #include "display.h"
23 #include "segtype.h"
24 
25 /*
26  * After much thought I have decided it is easier,
27  * and probably no less efficient, to convert the
28  * pe->le map to a full le->pe map, and then
29  * process this to get the segments form that
30  * we're after.  Any code which goes directly from
31  * the pe->le map to segments would be gladly
32  * accepted, if it is less complicated than this
33  * file.
34  */
35 struct pe_specifier {
36           struct physical_volume *pv;
37           uint32_t pe;
38 };
39 
40 struct lv_map {
41           struct logical_volume *lv;
42           uint32_t stripes;
43           uint32_t stripe_size;
44           struct pe_specifier *map;
45 };
46 
_create_lv_maps(struct dm_pool * mem,struct volume_group * vg)47 static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem,
48                                                     struct volume_group *vg)
49 {
50           struct dm_hash_table *maps = dm_hash_create(32);
51           struct lv_list *ll;
52           struct lv_map *lvm;
53 
54           if (!maps) {
55                     log_error("Unable to create hash table for holding "
56                                 "extent maps.");
57                     return NULL;
58           }
59 
60           dm_list_iterate_items(ll, &vg->lvs) {
61                     if (ll->lv->status & SNAPSHOT)
62                               continue;
63 
64                     if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm))))
65                               goto_bad;
66 
67                     lvm->lv = ll->lv;
68                     if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map)
69                                                        * ll->lv->le_count)))
70                               goto_bad;
71 
72                     if (!dm_hash_insert(maps, ll->lv->name, lvm))
73                               goto_bad;
74           }
75 
76           return maps;
77 
78       bad:
79           dm_hash_destroy(maps);
80           return NULL;
81 }
82 
_fill_lv_array(struct lv_map ** lvs,struct dm_hash_table * maps,struct disk_list * dl)83 static int _fill_lv_array(struct lv_map **lvs,
84                                 struct dm_hash_table *maps, struct disk_list *dl)
85 {
86           struct lvd_list *ll;
87           struct lv_map *lvm;
88 
89           memset(lvs, 0, sizeof(*lvs) * MAX_LV);
90 
91           dm_list_iterate_items(ll, &dl->lvds) {
92                     if (!(lvm = dm_hash_lookup(maps, strrchr((char *)ll->lvd.lv_name, '/')
93                                                   + 1))) {
94                               log_error("Physical volume (%s) contains an "
95                                           "unknown logical volume (%s).",
96                                         dev_name(dl->dev), ll->lvd.lv_name);
97                               return 0;
98                     }
99 
100                     lvm->stripes = ll->lvd.lv_stripes;
101                     lvm->stripe_size = ll->lvd.lv_stripesize;
102 
103                     lvs[ll->lvd.lv_number] = lvm;
104           }
105 
106           return 1;
107 }
108 
_fill_maps(struct dm_hash_table * maps,struct volume_group * vg,struct dm_list * pvds)109 static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg,
110                           struct dm_list *pvds)
111 {
112           struct disk_list *dl;
113           struct physical_volume *pv;
114           struct lv_map *lvms[MAX_LV], *lvm;
115           struct pe_disk *e;
116           uint32_t i, lv_num, le;
117 
118           dm_list_iterate_items(dl, pvds) {
119                     pv = find_pv(vg, dl->dev);
120                     e = dl->extents;
121 
122                     /* build an array of lv's for this pv */
123                     if (!_fill_lv_array(lvms, maps, dl))
124                               return_0;
125 
126                     for (i = 0; i < dl->pvd.pe_total; i++) {
127                               lv_num = e[i].lv_num;
128 
129                               if (lv_num == UNMAPPED_EXTENT)
130                                         continue;
131 
132                               else {
133                                         lv_num--;
134                                         lvm = lvms[lv_num];
135 
136                                         if (!lvm) {
137                                                   log_error("Invalid LV in extent map "
138                                                               "(PV %s, PE %" PRIu32
139                                                               ", LV %" PRIu32
140                                                               ", LE %" PRIu32 ")",
141                                                               dev_name(pv->dev), i,
142                                                               lv_num, e[i].le_num);
143                                                   return 0;
144                                         }
145 
146                                         le = e[i].le_num;
147 
148                                         if (le >= lvm->lv->le_count) {
149                                                   log_error("logical extent number "
150                                                               "out of bounds");
151                                                   return 0;
152                                         }
153 
154                                         if (lvm->map[le].pv) {
155                                                   log_error("logical extent (%u) "
156                                                               "already mapped.", le);
157                                                   return 0;
158                                         }
159 
160                                         lvm->map[le].pv = pv;
161                                         lvm->map[le].pe = i;
162                               }
163                     }
164           }
165 
166           return 1;
167 }
168 
_check_single_map(struct lv_map * lvm)169 static int _check_single_map(struct lv_map *lvm)
170 {
171           uint32_t i;
172 
173           for (i = 0; i < lvm->lv->le_count; i++) {
174                     if (!lvm->map[i].pv) {
175                               log_error("Logical volume (%s) contains an incomplete "
176                                           "mapping table.", lvm->lv->name);
177                               return 0;
178                     }
179           }
180 
181           return 1;
182 }
183 
_check_maps_are_complete(struct dm_hash_table * maps)184 static int _check_maps_are_complete(struct dm_hash_table *maps)
185 {
186           struct dm_hash_node *n;
187           struct lv_map *lvm;
188 
189           for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) {
190                     lvm = (struct lv_map *) dm_hash_get_data(maps, n);
191 
192                     if (!_check_single_map(lvm))
193                               return_0;
194           }
195           return 1;
196 }
197 
_area_length(struct lv_map * lvm,uint32_t le)198 static uint32_t _area_length(struct lv_map *lvm, uint32_t le)
199 {
200           uint32_t len = 0;
201 
202           do
203                     len++;
204           while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
205                      (lvm->map[le].pv &&
206                       lvm->map[le + len].pe == lvm->map[le].pe + len));
207 
208           return len;
209 }
210 
_read_linear(struct cmd_context * cmd,struct lv_map * lvm)211 static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
212 {
213           uint32_t le = 0, len;
214           struct lv_segment *seg;
215           struct segment_type *segtype;
216 
217           if (!(segtype = get_segtype_from_string(cmd, "striped")))
218                     return_0;
219 
220           while (le < lvm->lv->le_count) {
221                     len = _area_length(lvm, le);
222 
223                     if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
224                                                        len, 0, 0, NULL, 1, len, 0, 0, 0))) {
225                               log_error("Failed to allocate linear segment.");
226                               return 0;
227                     }
228 
229                     if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
230                                                       lvm->map[le].pe))
231                               return_0;
232 
233                     dm_list_add(&lvm->lv->segments, &seg->list);
234 
235                     le += seg->len;
236           }
237 
238           return 1;
239 }
240 
_check_stripe(struct lv_map * lvm,uint32_t area_count,uint32_t area_len,uint32_t base_le,uint32_t total_area_len)241 static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
242                                uint32_t area_len, uint32_t base_le,
243                                uint32_t total_area_len)
244 {
245           uint32_t st;
246 
247           /*
248            * Is the next physical extent in every stripe adjacent to the last?
249            */
250           for (st = 0; st < area_count; st++)
251                     if ((lvm->map[base_le + st * total_area_len + area_len].pv !=
252                          lvm->map[base_le + st * total_area_len].pv) ||
253                         (lvm->map[base_le + st * total_area_len].pv &&
254                          lvm->map[base_le + st * total_area_len + area_len].pe !=
255                          lvm->map[base_le + st * total_area_len].pe + area_len))
256                               return 0;
257 
258           return 1;
259 }
260 
_read_stripes(struct cmd_context * cmd,struct lv_map * lvm)261 static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
262 {
263           uint32_t st, first_area_le = 0, total_area_len;
264           uint32_t area_len;
265           struct lv_segment *seg;
266           struct segment_type *segtype;
267 
268           /*
269            * Work out overall striped length
270            */
271           if (lvm->lv->le_count % lvm->stripes) {
272                     log_error("Number of stripes (%u) incompatible "
273                                 "with logical extent count (%u) for %s",
274                                 lvm->stripes, lvm->lv->le_count, lvm->lv->name);
275           }
276 
277           total_area_len = lvm->lv->le_count / lvm->stripes;
278 
279           if (!(segtype = get_segtype_from_string(cmd, "striped")))
280                     return_0;
281 
282           while (first_area_le < total_area_len) {
283                     area_len = 1;
284 
285                     /*
286                      * Find how many extents are contiguous in all stripes
287                      * and so can form part of this segment
288                      */
289                     while (_check_stripe(lvm, lvm->stripes,
290                                              area_len, first_area_le, total_area_len))
291                               area_len++;
292 
293                     if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
294                                                        lvm->stripes * first_area_le,
295                                                        lvm->stripes * area_len,
296                                                        0, lvm->stripe_size, NULL,
297                                                        lvm->stripes,
298                                                        area_len, 0, 0, 0))) {
299                               log_error("Failed to allocate striped segment.");
300                               return 0;
301                     }
302 
303                     /*
304                      * Set up start positions of each stripe in this segment
305                      */
306                     for (st = 0; st < seg->area_count; st++)
307                               if (!set_lv_segment_area_pv(seg, st,
308                                     lvm->map[first_area_le + st * total_area_len].pv,
309                                     lvm->map[first_area_le + st * total_area_len].pe))
310                                         return_0;
311 
312                     dm_list_add(&lvm->lv->segments, &seg->list);
313 
314                     first_area_le += area_len;
315           }
316 
317           return 1;
318 }
319 
_build_segments(struct cmd_context * cmd,struct lv_map * lvm)320 static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm)
321 {
322           return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) :
323                     _read_linear(cmd, lvm));
324 }
325 
_build_all_segments(struct cmd_context * cmd,struct dm_hash_table * maps)326 static int _build_all_segments(struct cmd_context *cmd, struct dm_hash_table *maps)
327 {
328           struct dm_hash_node *n;
329           struct lv_map *lvm;
330 
331           for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) {
332                     lvm = (struct lv_map *) dm_hash_get_data(maps, n);
333                     if (!_build_segments(cmd, lvm))
334                               return_0;
335           }
336 
337           return 1;
338 }
339 
import_extents(struct cmd_context * cmd,struct volume_group * vg,struct dm_list * pvds)340 int import_extents(struct cmd_context *cmd, struct volume_group *vg,
341                        struct dm_list *pvds)
342 {
343           int r = 0;
344           struct dm_pool *scratch = dm_pool_create("lvm1 import_extents", 10 * 1024);
345           struct dm_hash_table *maps;
346 
347           if (!scratch)
348                     return_0;
349 
350           if (!(maps = _create_lv_maps(scratch, vg))) {
351                     log_error("Couldn't allocate logical volume maps.");
352                     goto out;
353           }
354 
355           if (!_fill_maps(maps, vg, pvds)) {
356                     log_error("Couldn't fill logical volume maps.");
357                     goto out;
358           }
359 
360           if (!_check_maps_are_complete(maps) && !(vg->status & PARTIAL_VG))
361                     goto_out;
362 
363           if (!_build_all_segments(cmd, maps)) {
364                     log_error("Couldn't build extent segments.");
365                     goto out;
366           }
367           r = 1;
368 
369       out:
370           if (maps)
371                     dm_hash_destroy(maps);
372           dm_pool_destroy(scratch);
373           return r;
374 }
375