1/*	$NetBSD$	*/
2
3/*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2006 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/*
19 * Translates between disk and in-core formats.
20 */
21
22#include "lib.h"
23#include "disk-rep.h"
24#include "lvm-string.h"
25#include "filter.h"
26#include "toolcontext.h"
27#include "segtype.h"
28#include "pv_alloc.h"
29#include "display.h"
30#include "lvmcache.h"
31#include "metadata.h"
32
33#include <time.h>
34
35static int _check_vg_name(const char *name)
36{
37	return strlen(name) < NAME_LEN;
38}
39
40/*
41 * Extracts the last part of a path.
42 */
43static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
44{
45	const char *ptr = strrchr(full_name, '/');
46
47	if (!ptr)
48		ptr = full_name;
49	else
50		ptr++;
51
52	return dm_pool_strdup(mem, ptr);
53}
54
55int import_pv(const struct format_type *fmt, struct dm_pool *mem,
56	      struct device *dev, struct volume_group *vg,
57	      struct physical_volume *pv, struct pv_disk *pvd,
58	      struct vg_disk *vgd)
59{
60	uint64_t size;
61
62	memset(pv, 0, sizeof(*pv));
63	memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
64
65	pv->dev = dev;
66	if (!*pvd->vg_name)
67		pv->vg_name = fmt->orphan_vg_name;
68	else if (!(pv->vg_name = dm_pool_strdup(mem, (char *)pvd->vg_name))) {
69		log_error("Volume Group name allocation failed.");
70		return 0;
71	}
72
73	memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
74
75	/* Store system_id from first PV if PV belongs to a VG */
76	if (vg && !*vg->system_id)
77		strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
78
79	if (vg &&
80	    strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
81		    log_very_verbose("System ID %s on %s differs from %s for "
82				     "volume group", pvd->system_id,
83				     pv_dev_name(pv), vg->system_id);
84
85	/*
86	 * If exported, we still need to flag in pv->status too because
87	 * we don't always have a struct volume_group when we need this.
88	 */
89	if (pvd->pv_status & VG_EXPORTED)
90		pv->status |= EXPORTED_VG;
91
92	if (pvd->pv_allocatable)
93		pv->status |= ALLOCATABLE_PV;
94
95	pv->size = pvd->pv_size;
96	pv->pe_size = pvd->pe_size;
97	pv->pe_start = pvd->pe_start;
98	pv->pe_count = pvd->pe_total;
99	pv->pe_alloc_count = 0;
100	pv->pe_align = 0;
101
102	/* Fix up pv size if missing or impossibly large */
103	if (!pv->size || pv->size > (1ULL << 62)) {
104		if (!dev_get_size(dev, &pv->size)) {
105			log_error("%s: Couldn't get size.", pv_dev_name(pv));
106			return 0;
107		}
108		log_verbose("Fixing up missing format1 size (%s) "
109			    "for PV %s", display_size(fmt->cmd, pv->size),
110			    pv_dev_name(pv));
111		if (vg) {
112			size = pv->pe_count * (uint64_t) vg->extent_size +
113			       pv->pe_start;
114			if (size > pv->size)
115				log_error("WARNING: Physical Volume %s is too "
116					  "large for underlying device",
117					  pv_dev_name(pv));
118		}
119	}
120
121	dm_list_init(&pv->tags);
122	dm_list_init(&pv->segments);
123
124	if (!alloc_pv_segment_whole_pv(mem, pv))
125		return_0;
126
127	return 1;
128}
129
130static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
131{
132
133	if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
134			 prefix, cmd->hostname, time(NULL)) < 0) {
135		log_error("Generated system_id too long");
136		return 0;
137	}
138
139	return 1;
140}
141
142int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute((unused)),
143	      struct volume_group *vg,
144	      struct pv_disk *pvd, struct physical_volume *pv)
145{
146	memset(pvd, 0, sizeof(*pvd));
147
148	pvd->id[0] = 'H';
149	pvd->id[1] = 'M';
150	pvd->version = 1;
151
152	memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN);
153
154	if (pv->vg_name && !is_orphan(pv)) {
155		if (!_check_vg_name(pv->vg_name))
156			return_0;
157		strncpy((char *)pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
158	}
159
160	/* Preserve existing system_id if it exists */
161	if (vg && *vg->system_id)
162		strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id));
163
164	/* Is VG already exported or being exported? */
165	if (vg && vg_is_exported(vg)) {
166		/* Does system_id need setting? */
167		if (!*vg->system_id ||
168		    strncmp(vg->system_id, EXPORTED_TAG,
169			    sizeof(EXPORTED_TAG) - 1)) {
170			if (!_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
171				return_0;
172		}
173		if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) >
174		    sizeof(pvd->vg_name)) {
175			log_error("Volume group name %s too long to export",
176				  pvd->vg_name);
177			return 0;
178		}
179		strcat((char *)pvd->vg_name, EXPORTED_TAG);
180	}
181
182	/* Is VG being imported? */
183	if (vg && !vg_is_exported(vg) && *vg->system_id &&
184	    !strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
185		if (!_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG))
186			return_0;
187	}
188
189	/* Generate system_id if PV is in VG */
190	if (!pvd->system_id || !*pvd->system_id)
191		if (!_system_id(cmd, (char *)pvd->system_id, ""))
192			return_0;
193
194	/* Update internal system_id if we changed it */
195	if (vg &&
196	    (!*vg->system_id ||
197	     strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
198		    strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
199
200	//pvd->pv_major = MAJOR(pv->dev);
201
202	if (pv->status & ALLOCATABLE_PV)
203		pvd->pv_allocatable = PV_ALLOCATABLE;
204
205	pvd->pv_size = pv->size;
206	pvd->lv_cur = 0;	/* this is set when exporting the lv list */
207	if (vg)
208		pvd->pe_size = vg->extent_size;
209	else
210		pvd->pe_size = pv->pe_size;
211	pvd->pe_total = pv->pe_count;
212	pvd->pe_allocated = pv->pe_alloc_count;
213	pvd->pe_start = pv->pe_start;
214
215	return 1;
216}
217
218int import_vg(struct dm_pool *mem,
219	      struct volume_group *vg, struct disk_list *dl)
220{
221	struct vg_disk *vgd = &dl->vgd;
222	memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
223
224	if (!_check_vg_name((char *)dl->pvd.vg_name))
225		return_0;
226
227	if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name)))
228		return_0;
229
230	if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
231		return_0;
232
233	*vg->system_id = '\0';
234
235	if (vgd->vg_status & VG_EXPORTED)
236		vg->status |= EXPORTED_VG;
237
238	if (vgd->vg_status & VG_EXTENDABLE)
239		vg->status |= RESIZEABLE_VG;
240
241	if (vgd->vg_access & VG_READ)
242		vg->status |= LVM_READ;
243
244	if (vgd->vg_access & VG_WRITE)
245		vg->status |= LVM_WRITE;
246
247	if (vgd->vg_access & VG_CLUSTERED)
248		vg->status |= CLUSTERED;
249
250	if (vgd->vg_access & VG_SHARED)
251		vg->status |= SHARED;
252
253	vg->extent_size = vgd->pe_size;
254	vg->extent_count = vgd->pe_total;
255	vg->free_count = vgd->pe_total;
256	vg->max_lv = vgd->lv_max;
257	vg->max_pv = vgd->pv_max;
258	vg->alloc = ALLOC_NORMAL;
259
260	return 1;
261}
262
263int export_vg(struct vg_disk *vgd, struct volume_group *vg)
264{
265	memset(vgd, 0, sizeof(*vgd));
266	memcpy(vgd->vg_uuid, vg->id.uuid, ID_LEN);
267
268	if (vg->status & LVM_READ)
269		vgd->vg_access |= VG_READ;
270
271	if (vg->status & LVM_WRITE)
272		vgd->vg_access |= VG_WRITE;
273
274	if (vg_is_clustered(vg))
275		vgd->vg_access |= VG_CLUSTERED;
276
277	if (vg->status & SHARED)
278		vgd->vg_access |= VG_SHARED;
279
280	if (vg_is_exported(vg))
281		vgd->vg_status |= VG_EXPORTED;
282
283	if (vg_is_resizeable(vg))
284		vgd->vg_status |= VG_EXTENDABLE;
285
286	vgd->lv_max = vg->max_lv;
287	vgd->lv_cur = vg_visible_lvs(vg) + snapshot_count(vg);
288
289	vgd->pv_max = vg->max_pv;
290	vgd->pv_cur = vg->pv_count;
291
292	vgd->pe_size = vg->extent_size;
293	vgd->pe_total = vg->extent_count;
294	vgd->pe_allocated = vg->extent_count - vg->free_count;
295
296	return 1;
297}
298
299int import_lv(struct cmd_context *cmd, struct dm_pool *mem,
300	      struct logical_volume *lv, struct lv_disk *lvd)
301{
302	if (!(lv->name = _create_lv_name(mem, (char *)lvd->lv_name)))
303		return_0;
304
305	lv->status |= VISIBLE_LV;
306
307	if (lvd->lv_status & LV_SPINDOWN)
308		lv->status |= SPINDOWN_LV;
309
310	if (lvd->lv_status & LV_PERSISTENT_MINOR) {
311		lv->status |= FIXED_MINOR;
312		lv->minor = MINOR(lvd->lv_dev);
313		lv->major = MAJOR(lvd->lv_dev);
314	} else {
315		lv->major = -1;
316		lv->minor = -1;
317	}
318
319	if (lvd->lv_access & LV_READ)
320		lv->status |= LVM_READ;
321
322	if (lvd->lv_access & LV_WRITE)
323		lv->status |= LVM_WRITE;
324
325	if (lvd->lv_badblock)
326		lv->status |= BADBLOCK_ON;
327
328	/* Drop the unused LV_STRICT here */
329	if (lvd->lv_allocation & LV_CONTIGUOUS)
330		lv->alloc = ALLOC_CONTIGUOUS;
331	else
332		lv->alloc = ALLOC_NORMAL;
333
334	if (!lvd->lv_read_ahead)
335		lv->read_ahead = cmd->default_settings.read_ahead;
336	else
337		lv->read_ahead = lvd->lv_read_ahead;
338
339	lv->size = lvd->lv_size;
340	lv->le_count = lvd->lv_allocated_le;
341
342	return 1;
343}
344
345static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
346		       struct logical_volume *lv, const char *dev_dir)
347{
348	memset(lvd, 0, sizeof(*lvd));
349	snprintf((char *)lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
350		 dev_dir, vg->name, lv->name);
351
352	strcpy((char *)lvd->vg_name, vg->name);
353
354	if (lv->status & LVM_READ)
355		lvd->lv_access |= LV_READ;
356
357	if (lv->status & LVM_WRITE)
358		lvd->lv_access |= LV_WRITE;
359
360	if (lv->status & SPINDOWN_LV)
361		lvd->lv_status |= LV_SPINDOWN;
362
363	if (lv->status & FIXED_MINOR) {
364		lvd->lv_status |= LV_PERSISTENT_MINOR;
365		lvd->lv_dev = MKDEV(lv->major, lv->minor);
366	} else {
367		lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid));
368	}
369
370	if (lv->read_ahead == DM_READ_AHEAD_AUTO ||
371	    lv->read_ahead == DM_READ_AHEAD_NONE)
372		lvd->lv_read_ahead = 0;
373	else
374		lvd->lv_read_ahead = lv->read_ahead;
375
376	lvd->lv_stripes =
377	    dm_list_item(lv->segments.n, struct lv_segment)->area_count;
378	lvd->lv_stripesize =
379	    dm_list_item(lv->segments.n, struct lv_segment)->stripe_size;
380
381	lvd->lv_size = lv->size;
382	lvd->lv_allocated_le = lv->le_count;
383
384	if (lv->status & BADBLOCK_ON)
385		lvd->lv_badblock = LV_BADBLOCK_ON;
386
387	if (lv->alloc == ALLOC_CONTIGUOUS)
388		lvd->lv_allocation |= LV_CONTIGUOUS;
389}
390
391int export_extents(struct disk_list *dl, uint32_t lv_num,
392		   struct logical_volume *lv, struct physical_volume *pv)
393{
394	struct pe_disk *ped;
395	struct lv_segment *seg;
396	uint32_t pe, s;
397
398	dm_list_iterate_items(seg, &lv->segments) {
399		for (s = 0; s < seg->area_count; s++) {
400			if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
401				log_error("Segment type %s in LV %s: "
402					  "unsupported by format1",
403					  seg->segtype->name, lv->name);
404				return 0;
405			}
406			if (seg_type(seg, s) != AREA_PV) {
407				log_error("Non-PV stripe found in LV %s: "
408					  "unsupported by format1", lv->name);
409				return 0;
410			}
411			if (seg_pv(seg, s) != pv)
412				continue;	/* not our pv */
413
414			for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
415				ped = &dl->extents[pe + seg_pe(seg, s)];
416				ped->lv_num = lv_num;
417				ped->le_num = (seg->le / seg->area_count) + pe +
418				    s * (lv->le_count / seg->area_count);
419			}
420		}
421	}
422
423	return 1;
424}
425
426int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
427	       struct volume_group *vg,
428	       struct dm_list *pvds, struct dm_list *results, uint32_t *count)
429{
430	struct disk_list *dl;
431	struct pv_list *pvl;
432
433	*count = 0;
434	dm_list_iterate_items(dl, pvds) {
435		if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
436		    !(pvl->pv = dm_pool_alloc(mem, sizeof(*pvl->pv))))
437			return_0;
438
439		if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd))
440			return_0;
441
442		pvl->pv->fmt = fmt;
443		dm_list_add(results, &pvl->list);
444		(*count)++;
445	}
446
447	return 1;
448}
449
450static struct logical_volume *_add_lv(struct dm_pool *mem,
451				      struct volume_group *vg,
452				      struct lv_disk *lvd)
453{
454	struct logical_volume *lv;
455
456	if (!(lv = alloc_lv(mem)))
457		return_NULL;
458
459	lvid_from_lvnum(&lv->lvid, &vg->id, lvd->lv_number);
460
461	if (!import_lv(vg->cmd, mem, lv, lvd))
462		goto_bad;
463
464	if (!link_lv_to_vg(vg, lv))
465		goto_bad;
466
467	return lv;
468bad:
469	dm_pool_free(mem, lv);
470	return NULL;
471}
472
473int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds)
474{
475	struct disk_list *dl;
476	struct lvd_list *ll;
477	struct lv_disk *lvd;
478
479	dm_list_iterate_items(dl, pvds) {
480		dm_list_iterate_items(ll, &dl->lvds) {
481			lvd = &ll->lvd;
482
483			if (!find_lv(vg, (char *)lvd->lv_name) &&
484			    !_add_lv(mem, vg, lvd))
485				return_0;
486		}
487	}
488
489	return 1;
490}
491
492/* FIXME: tidy */
493int export_lvs(struct disk_list *dl, struct volume_group *vg,
494	       struct physical_volume *pv, const char *dev_dir)
495{
496	int r = 0;
497	struct lv_list *ll;
498	struct lvd_list *lvdl;
499	size_t len;
500	uint32_t lv_num;
501	struct dm_hash_table *lvd_hash;
502
503	if (!_check_vg_name(vg->name))
504		return_0;
505
506	if (!(lvd_hash = dm_hash_create(32)))
507		return_0;
508
509	/*
510	 * setup the pv's extents array
511	 */
512	len = sizeof(struct pe_disk) * dl->pvd.pe_total;
513	if (!(dl->extents = dm_pool_alloc(dl->mem, len)))
514		goto_out;
515	memset(dl->extents, 0, len);
516
517	dm_list_iterate_items(ll, &vg->lvs) {
518		if (ll->lv->status & SNAPSHOT)
519			continue;
520
521		if (!(lvdl = dm_pool_alloc(dl->mem, sizeof(*lvdl))))
522			goto_out;
523
524		_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
525
526		lv_num = lvnum_from_lvid(&ll->lv->lvid);
527		lvdl->lvd.lv_number = lv_num;
528
529		if (!dm_hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd))
530			goto_out;
531
532		if (!export_extents(dl, lv_num + 1, ll->lv, pv))
533			goto_out;
534
535		if (lv_is_origin(ll->lv))
536			lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
537
538		if (lv_is_cow(ll->lv)) {
539			lvdl->lvd.lv_access |= LV_SNAPSHOT;
540			lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
541			lvdl->lvd.lv_snapshot_minor =
542			    lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
543		}
544
545		dm_list_add(&dl->lvds, &lvdl->list);
546		dl->pvd.lv_cur++;
547	}
548
549	r = 1;
550
551      out:
552	dm_hash_destroy(lvd_hash);
553	return r;
554}
555
556/*
557 * FIXME: More inefficient code.
558 */
559int import_snapshots(struct dm_pool *mem __attribute((unused)), struct volume_group *vg,
560		     struct dm_list *pvds)
561{
562	struct logical_volume *lvs[MAX_LV];
563	struct disk_list *dl;
564	struct lvd_list *ll;
565	struct lv_disk *lvd;
566	int lvnum;
567	struct logical_volume *org, *cow;
568
569	/* build an index of lv numbers */
570	memset(lvs, 0, sizeof(lvs));
571	dm_list_iterate_items(dl, pvds) {
572		dm_list_iterate_items(ll, &dl->lvds) {
573			lvd = &ll->lvd;
574
575			lvnum = lvd->lv_number;
576
577			if (lvnum >= MAX_LV) {
578				log_error("Logical volume number "
579					  "out of bounds.");
580				return 0;
581			}
582
583			if (!lvs[lvnum] &&
584			    !(lvs[lvnum] = find_lv(vg, (char *)lvd->lv_name))) {
585				log_error("Couldn't find logical volume '%s'.",
586					  lvd->lv_name);
587				return 0;
588			}
589		}
590	}
591
592	/*
593	 * Now iterate through yet again adding the snapshots.
594	 */
595	dm_list_iterate_items(dl, pvds) {
596		dm_list_iterate_items(ll, &dl->lvds) {
597			lvd = &ll->lvd;
598
599			if (!(lvd->lv_access & LV_SNAPSHOT))
600				continue;
601
602			lvnum = lvd->lv_number;
603			cow = lvs[lvnum];
604			if (!(org = lvs[lvd->lv_snapshot_minor])) {
605				log_error("Couldn't find origin logical volume "
606					  "for snapshot '%s'.", lvd->lv_name);
607				return 0;
608			}
609
610			/* we may have already added this snapshot */
611			if (lv_is_cow(cow))
612				continue;
613
614			/* insert the snapshot */
615			if (!vg_add_snapshot(org, cow, NULL,
616					     org->le_count,
617					     lvd->lv_chunk_size)) {
618				log_error("Couldn't add snapshot.");
619				return 0;
620			}
621		}
622	}
623
624	return 1;
625}
626
627int export_uuids(struct disk_list *dl, struct volume_group *vg)
628{
629	struct uuid_list *ul;
630	struct pv_list *pvl;
631
632	dm_list_iterate_items(pvl, &vg->pvs) {
633		if (!(ul = dm_pool_alloc(dl->mem, sizeof(*ul))))
634			return_0;
635
636		memset(ul->uuid, 0, sizeof(ul->uuid));
637		memcpy(ul->uuid, pvl->pv->id.uuid, ID_LEN);
638
639		dm_list_add(&dl->uuids, &ul->list);
640	}
641	return 1;
642}
643
644/*
645 * This calculates the nasty pv_number field
646 * used by LVM1.
647 */
648void export_numbers(struct dm_list *pvds, struct volume_group *vg __attribute((unused)))
649{
650	struct disk_list *dl;
651	int pv_num = 1;
652
653	dm_list_iterate_items(dl, pvds)
654		dl->pvd.pv_number = pv_num++;
655}
656
657/*
658 * Calculate vg_disk->pv_act.
659 */
660void export_pv_act(struct dm_list *pvds)
661{
662	struct disk_list *dl;
663	int act = 0;
664
665	dm_list_iterate_items(dl, pvds)
666		if (dl->pvd.pv_status & PV_ACTIVE)
667			act++;
668
669	dm_list_iterate_items(dl, pvds)
670		dl->vgd.pv_act = act;
671}
672
673int export_vg_number(struct format_instance *fid, struct dm_list *pvds,
674		     const char *vg_name, struct dev_filter *filter)
675{
676	struct disk_list *dl;
677	int vg_num;
678
679	if (!get_free_vg_number(fid, filter, vg_name, &vg_num))
680		return_0;
681
682	dm_list_iterate_items(dl, pvds)
683		dl->vgd.vg_number = vg_num;
684
685	return 1;
686}
687