1/*	$NetBSD$	*/
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 */
35struct pe_specifier {
36	struct physical_volume *pv;
37	uint32_t pe;
38};
39
40struct lv_map {
41	struct logical_volume *lv;
42	uint32_t stripes;
43	uint32_t stripe_size;
44	struct pe_specifier *map;
45};
46
47static 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
83static 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
109static 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
169static 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
184static 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
198static 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
211static 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
241static 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
261static 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
320static 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
326static 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
340int 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