1*730681d8Sjoerg /*	$NetBSD: import-export.c,v 1.2 2014/11/15 01:24:53 joerg Exp $	*/
256a34939Shaad 
356a34939Shaad /*
456a34939Shaad  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
656a34939Shaad  *
756a34939Shaad  * This file is part of LVM2.
856a34939Shaad  *
956a34939Shaad  * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad  * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad  * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad  *
1356a34939Shaad  * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad  * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1656a34939Shaad  */
1756a34939Shaad 
1856a34939Shaad /*
1956a34939Shaad  * Translates between disk and in-core formats.
2056a34939Shaad  */
2156a34939Shaad 
2256a34939Shaad #include "lib.h"
2356a34939Shaad #include "disk-rep.h"
2456a34939Shaad #include "lvm-string.h"
2556a34939Shaad #include "filter.h"
2656a34939Shaad #include "toolcontext.h"
2756a34939Shaad #include "segtype.h"
2856a34939Shaad #include "pv_alloc.h"
2956a34939Shaad #include "display.h"
3056a34939Shaad #include "lvmcache.h"
3156a34939Shaad #include "metadata.h"
3256a34939Shaad 
3356a34939Shaad #include <time.h>
3456a34939Shaad 
_check_vg_name(const char * name)3556a34939Shaad static int _check_vg_name(const char *name)
3656a34939Shaad {
3756a34939Shaad 	return strlen(name) < NAME_LEN;
3856a34939Shaad }
3956a34939Shaad 
4056a34939Shaad /*
4156a34939Shaad  * Extracts the last part of a path.
4256a34939Shaad  */
_create_lv_name(struct dm_pool * mem,const char * full_name)4356a34939Shaad static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
4456a34939Shaad {
4556a34939Shaad 	const char *ptr = strrchr(full_name, '/');
4656a34939Shaad 
4756a34939Shaad 	if (!ptr)
4856a34939Shaad 		ptr = full_name;
4956a34939Shaad 	else
5056a34939Shaad 		ptr++;
5156a34939Shaad 
5256a34939Shaad 	return dm_pool_strdup(mem, ptr);
5356a34939Shaad }
5456a34939Shaad 
import_pv(const struct format_type * fmt,struct dm_pool * mem,struct device * dev,struct volume_group * vg,struct physical_volume * pv,struct pv_disk * pvd,struct vg_disk * vgd)5556a34939Shaad int import_pv(const struct format_type *fmt, struct dm_pool *mem,
5656a34939Shaad 	      struct device *dev, struct volume_group *vg,
5756a34939Shaad 	      struct physical_volume *pv, struct pv_disk *pvd,
5856a34939Shaad 	      struct vg_disk *vgd)
5956a34939Shaad {
6056a34939Shaad 	uint64_t size;
6156a34939Shaad 
6256a34939Shaad 	memset(pv, 0, sizeof(*pv));
6356a34939Shaad 	memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
6456a34939Shaad 
6556a34939Shaad 	pv->dev = dev;
6656a34939Shaad 	if (!*pvd->vg_name)
6756a34939Shaad 		pv->vg_name = fmt->orphan_vg_name;
6856a34939Shaad 	else if (!(pv->vg_name = dm_pool_strdup(mem, (char *)pvd->vg_name))) {
6956a34939Shaad 		log_error("Volume Group name allocation failed.");
7056a34939Shaad 		return 0;
7156a34939Shaad 	}
7256a34939Shaad 
7356a34939Shaad 	memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
7456a34939Shaad 
7556a34939Shaad 	/* Store system_id from first PV if PV belongs to a VG */
7656a34939Shaad 	if (vg && !*vg->system_id)
7756a34939Shaad 		strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
7856a34939Shaad 
7956a34939Shaad 	if (vg &&
8056a34939Shaad 	    strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
8156a34939Shaad 		    log_very_verbose("System ID %s on %s differs from %s for "
8256a34939Shaad 				     "volume group", pvd->system_id,
8356a34939Shaad 				     pv_dev_name(pv), vg->system_id);
8456a34939Shaad 
8556a34939Shaad 	/*
8656a34939Shaad 	 * If exported, we still need to flag in pv->status too because
8756a34939Shaad 	 * we don't always have a struct volume_group when we need this.
8856a34939Shaad 	 */
8956a34939Shaad 	if (pvd->pv_status & VG_EXPORTED)
9056a34939Shaad 		pv->status |= EXPORTED_VG;
9156a34939Shaad 
9256a34939Shaad 	if (pvd->pv_allocatable)
9356a34939Shaad 		pv->status |= ALLOCATABLE_PV;
9456a34939Shaad 
9556a34939Shaad 	pv->size = pvd->pv_size;
9656a34939Shaad 	pv->pe_size = pvd->pe_size;
9756a34939Shaad 	pv->pe_start = pvd->pe_start;
9856a34939Shaad 	pv->pe_count = pvd->pe_total;
9956a34939Shaad 	pv->pe_alloc_count = 0;
10056a34939Shaad 	pv->pe_align = 0;
10156a34939Shaad 
10256a34939Shaad 	/* Fix up pv size if missing or impossibly large */
10356a34939Shaad 	if (!pv->size || pv->size > (1ULL << 62)) {
10456a34939Shaad 		if (!dev_get_size(dev, &pv->size)) {
10556a34939Shaad 			log_error("%s: Couldn't get size.", pv_dev_name(pv));
10656a34939Shaad 			return 0;
10756a34939Shaad 		}
10856a34939Shaad 		log_verbose("Fixing up missing format1 size (%s) "
10956a34939Shaad 			    "for PV %s", display_size(fmt->cmd, pv->size),
11056a34939Shaad 			    pv_dev_name(pv));
11156a34939Shaad 		if (vg) {
11256a34939Shaad 			size = pv->pe_count * (uint64_t) vg->extent_size +
11356a34939Shaad 			       pv->pe_start;
11456a34939Shaad 			if (size > pv->size)
11556a34939Shaad 				log_error("WARNING: Physical Volume %s is too "
11656a34939Shaad 					  "large for underlying device",
11756a34939Shaad 					  pv_dev_name(pv));
11856a34939Shaad 		}
11956a34939Shaad 	}
12056a34939Shaad 
12156a34939Shaad 	dm_list_init(&pv->tags);
12256a34939Shaad 	dm_list_init(&pv->segments);
12356a34939Shaad 
12456a34939Shaad 	if (!alloc_pv_segment_whole_pv(mem, pv))
12556a34939Shaad 		return_0;
12656a34939Shaad 
12756a34939Shaad 	return 1;
12856a34939Shaad }
12956a34939Shaad 
_system_id(struct cmd_context * cmd,char * s,const char * prefix)13056a34939Shaad static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
13156a34939Shaad {
13256a34939Shaad 
13356a34939Shaad 	if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
13456a34939Shaad 			 prefix, cmd->hostname, time(NULL)) < 0) {
13556a34939Shaad 		log_error("Generated system_id too long");
13656a34939Shaad 		return 0;
13756a34939Shaad 	}
13856a34939Shaad 
13956a34939Shaad 	return 1;
14056a34939Shaad }
14156a34939Shaad 
export_pv(struct cmd_context * cmd,struct dm_pool * mem __attribute ((unused)),struct volume_group * vg,struct pv_disk * pvd,struct physical_volume * pv)14256a34939Shaad int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute((unused)),
14356a34939Shaad 	      struct volume_group *vg,
14456a34939Shaad 	      struct pv_disk *pvd, struct physical_volume *pv)
14556a34939Shaad {
14656a34939Shaad 	memset(pvd, 0, sizeof(*pvd));
14756a34939Shaad 
14856a34939Shaad 	pvd->id[0] = 'H';
14956a34939Shaad 	pvd->id[1] = 'M';
15056a34939Shaad 	pvd->version = 1;
15156a34939Shaad 
15256a34939Shaad 	memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN);
15356a34939Shaad 
15456a34939Shaad 	if (pv->vg_name && !is_orphan(pv)) {
15556a34939Shaad 		if (!_check_vg_name(pv->vg_name))
15656a34939Shaad 			return_0;
15756a34939Shaad 		strncpy((char *)pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
15856a34939Shaad 	}
15956a34939Shaad 
16056a34939Shaad 	/* Preserve existing system_id if it exists */
16156a34939Shaad 	if (vg && *vg->system_id)
16256a34939Shaad 		strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id));
16356a34939Shaad 
16456a34939Shaad 	/* Is VG already exported or being exported? */
1657c604eeaShaad 	if (vg && vg_is_exported(vg)) {
16656a34939Shaad 		/* Does system_id need setting? */
16756a34939Shaad 		if (!*vg->system_id ||
16856a34939Shaad 		    strncmp(vg->system_id, EXPORTED_TAG,
16956a34939Shaad 			    sizeof(EXPORTED_TAG) - 1)) {
17056a34939Shaad 			if (!_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
17156a34939Shaad 				return_0;
17256a34939Shaad 		}
17356a34939Shaad 		if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) >
17456a34939Shaad 		    sizeof(pvd->vg_name)) {
17556a34939Shaad 			log_error("Volume group name %s too long to export",
17656a34939Shaad 				  pvd->vg_name);
17756a34939Shaad 			return 0;
17856a34939Shaad 		}
17956a34939Shaad 		strcat((char *)pvd->vg_name, EXPORTED_TAG);
18056a34939Shaad 	}
18156a34939Shaad 
18256a34939Shaad 	/* Is VG being imported? */
1837c604eeaShaad 	if (vg && !vg_is_exported(vg) && *vg->system_id &&
18456a34939Shaad 	    !strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
18556a34939Shaad 		if (!_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG))
18656a34939Shaad 			return_0;
18756a34939Shaad 	}
18856a34939Shaad 
18956a34939Shaad 	/* Generate system_id if PV is in VG */
190*730681d8Sjoerg 	if (!pvd->system_id[0])
19156a34939Shaad 		if (!_system_id(cmd, (char *)pvd->system_id, ""))
19256a34939Shaad 			return_0;
19356a34939Shaad 
19456a34939Shaad 	/* Update internal system_id if we changed it */
19556a34939Shaad 	if (vg &&
19656a34939Shaad 	    (!*vg->system_id ||
19756a34939Shaad 	     strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
19856a34939Shaad 		    strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
19956a34939Shaad 
20056a34939Shaad 	//pvd->pv_major = MAJOR(pv->dev);
20156a34939Shaad 
20256a34939Shaad 	if (pv->status & ALLOCATABLE_PV)
20356a34939Shaad 		pvd->pv_allocatable = PV_ALLOCATABLE;
20456a34939Shaad 
20556a34939Shaad 	pvd->pv_size = pv->size;
20656a34939Shaad 	pvd->lv_cur = 0;	/* this is set when exporting the lv list */
20756a34939Shaad 	if (vg)
20856a34939Shaad 		pvd->pe_size = vg->extent_size;
20956a34939Shaad 	else
21056a34939Shaad 		pvd->pe_size = pv->pe_size;
21156a34939Shaad 	pvd->pe_total = pv->pe_count;
21256a34939Shaad 	pvd->pe_allocated = pv->pe_alloc_count;
21356a34939Shaad 	pvd->pe_start = pv->pe_start;
21456a34939Shaad 
21556a34939Shaad 	return 1;
21656a34939Shaad }
21756a34939Shaad 
import_vg(struct dm_pool * mem,struct volume_group * vg,struct disk_list * dl)21856a34939Shaad int import_vg(struct dm_pool *mem,
21956a34939Shaad 	      struct volume_group *vg, struct disk_list *dl)
22056a34939Shaad {
22156a34939Shaad 	struct vg_disk *vgd = &dl->vgd;
22256a34939Shaad 	memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
22356a34939Shaad 
22456a34939Shaad 	if (!_check_vg_name((char *)dl->pvd.vg_name))
22556a34939Shaad 		return_0;
22656a34939Shaad 
22756a34939Shaad 	if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name)))
22856a34939Shaad 		return_0;
22956a34939Shaad 
23056a34939Shaad 	if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
23156a34939Shaad 		return_0;
23256a34939Shaad 
23356a34939Shaad 	*vg->system_id = '\0';
23456a34939Shaad 
23556a34939Shaad 	if (vgd->vg_status & VG_EXPORTED)
23656a34939Shaad 		vg->status |= EXPORTED_VG;
23756a34939Shaad 
23856a34939Shaad 	if (vgd->vg_status & VG_EXTENDABLE)
23956a34939Shaad 		vg->status |= RESIZEABLE_VG;
24056a34939Shaad 
24156a34939Shaad 	if (vgd->vg_access & VG_READ)
24256a34939Shaad 		vg->status |= LVM_READ;
24356a34939Shaad 
24456a34939Shaad 	if (vgd->vg_access & VG_WRITE)
24556a34939Shaad 		vg->status |= LVM_WRITE;
24656a34939Shaad 
24756a34939Shaad 	if (vgd->vg_access & VG_CLUSTERED)
24856a34939Shaad 		vg->status |= CLUSTERED;
24956a34939Shaad 
25056a34939Shaad 	if (vgd->vg_access & VG_SHARED)
25156a34939Shaad 		vg->status |= SHARED;
25256a34939Shaad 
25356a34939Shaad 	vg->extent_size = vgd->pe_size;
25456a34939Shaad 	vg->extent_count = vgd->pe_total;
25556a34939Shaad 	vg->free_count = vgd->pe_total;
25656a34939Shaad 	vg->max_lv = vgd->lv_max;
25756a34939Shaad 	vg->max_pv = vgd->pv_max;
25856a34939Shaad 	vg->alloc = ALLOC_NORMAL;
25956a34939Shaad 
26056a34939Shaad 	return 1;
26156a34939Shaad }
26256a34939Shaad 
export_vg(struct vg_disk * vgd,struct volume_group * vg)26356a34939Shaad int export_vg(struct vg_disk *vgd, struct volume_group *vg)
26456a34939Shaad {
26556a34939Shaad 	memset(vgd, 0, sizeof(*vgd));
26656a34939Shaad 	memcpy(vgd->vg_uuid, vg->id.uuid, ID_LEN);
26756a34939Shaad 
26856a34939Shaad 	if (vg->status & LVM_READ)
26956a34939Shaad 		vgd->vg_access |= VG_READ;
27056a34939Shaad 
27156a34939Shaad 	if (vg->status & LVM_WRITE)
27256a34939Shaad 		vgd->vg_access |= VG_WRITE;
27356a34939Shaad 
27456a34939Shaad 	if (vg_is_clustered(vg))
27556a34939Shaad 		vgd->vg_access |= VG_CLUSTERED;
27656a34939Shaad 
27756a34939Shaad 	if (vg->status & SHARED)
27856a34939Shaad 		vgd->vg_access |= VG_SHARED;
27956a34939Shaad 
2807c604eeaShaad 	if (vg_is_exported(vg))
28156a34939Shaad 		vgd->vg_status |= VG_EXPORTED;
28256a34939Shaad 
2837c604eeaShaad 	if (vg_is_resizeable(vg))
28456a34939Shaad 		vgd->vg_status |= VG_EXTENDABLE;
28556a34939Shaad 
28656a34939Shaad 	vgd->lv_max = vg->max_lv;
2877c604eeaShaad 	vgd->lv_cur = vg_visible_lvs(vg) + snapshot_count(vg);
28856a34939Shaad 
28956a34939Shaad 	vgd->pv_max = vg->max_pv;
29056a34939Shaad 	vgd->pv_cur = vg->pv_count;
29156a34939Shaad 
29256a34939Shaad 	vgd->pe_size = vg->extent_size;
29356a34939Shaad 	vgd->pe_total = vg->extent_count;
29456a34939Shaad 	vgd->pe_allocated = vg->extent_count - vg->free_count;
29556a34939Shaad 
29656a34939Shaad 	return 1;
29756a34939Shaad }
29856a34939Shaad 
import_lv(struct cmd_context * cmd,struct dm_pool * mem,struct logical_volume * lv,struct lv_disk * lvd)2997c604eeaShaad int import_lv(struct cmd_context *cmd, struct dm_pool *mem,
3007c604eeaShaad 	      struct logical_volume *lv, struct lv_disk *lvd)
30156a34939Shaad {
30256a34939Shaad 	if (!(lv->name = _create_lv_name(mem, (char *)lvd->lv_name)))
30356a34939Shaad 		return_0;
30456a34939Shaad 
30556a34939Shaad 	lv->status |= VISIBLE_LV;
30656a34939Shaad 
30756a34939Shaad 	if (lvd->lv_status & LV_SPINDOWN)
30856a34939Shaad 		lv->status |= SPINDOWN_LV;
30956a34939Shaad 
31056a34939Shaad 	if (lvd->lv_status & LV_PERSISTENT_MINOR) {
31156a34939Shaad 		lv->status |= FIXED_MINOR;
31256a34939Shaad 		lv->minor = MINOR(lvd->lv_dev);
31356a34939Shaad 		lv->major = MAJOR(lvd->lv_dev);
31456a34939Shaad 	} else {
31556a34939Shaad 		lv->major = -1;
31656a34939Shaad 		lv->minor = -1;
31756a34939Shaad 	}
31856a34939Shaad 
31956a34939Shaad 	if (lvd->lv_access & LV_READ)
32056a34939Shaad 		lv->status |= LVM_READ;
32156a34939Shaad 
32256a34939Shaad 	if (lvd->lv_access & LV_WRITE)
32356a34939Shaad 		lv->status |= LVM_WRITE;
32456a34939Shaad 
32556a34939Shaad 	if (lvd->lv_badblock)
32656a34939Shaad 		lv->status |= BADBLOCK_ON;
32756a34939Shaad 
32856a34939Shaad 	/* Drop the unused LV_STRICT here */
32956a34939Shaad 	if (lvd->lv_allocation & LV_CONTIGUOUS)
33056a34939Shaad 		lv->alloc = ALLOC_CONTIGUOUS;
33156a34939Shaad 	else
33256a34939Shaad 		lv->alloc = ALLOC_NORMAL;
33356a34939Shaad 
33456a34939Shaad 	if (!lvd->lv_read_ahead)
3357c604eeaShaad 		lv->read_ahead = cmd->default_settings.read_ahead;
33656a34939Shaad 	else
33756a34939Shaad 		lv->read_ahead = lvd->lv_read_ahead;
33856a34939Shaad 
33956a34939Shaad 	lv->size = lvd->lv_size;
34056a34939Shaad 	lv->le_count = lvd->lv_allocated_le;
34156a34939Shaad 
34256a34939Shaad 	return 1;
34356a34939Shaad }
34456a34939Shaad 
_export_lv(struct lv_disk * lvd,struct volume_group * vg,struct logical_volume * lv,const char * dev_dir)34556a34939Shaad static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
34656a34939Shaad 		       struct logical_volume *lv, const char *dev_dir)
34756a34939Shaad {
34856a34939Shaad 	memset(lvd, 0, sizeof(*lvd));
34956a34939Shaad 	snprintf((char *)lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
35056a34939Shaad 		 dev_dir, vg->name, lv->name);
35156a34939Shaad 
35256a34939Shaad 	strcpy((char *)lvd->vg_name, vg->name);
35356a34939Shaad 
35456a34939Shaad 	if (lv->status & LVM_READ)
35556a34939Shaad 		lvd->lv_access |= LV_READ;
35656a34939Shaad 
35756a34939Shaad 	if (lv->status & LVM_WRITE)
35856a34939Shaad 		lvd->lv_access |= LV_WRITE;
35956a34939Shaad 
36056a34939Shaad 	if (lv->status & SPINDOWN_LV)
36156a34939Shaad 		lvd->lv_status |= LV_SPINDOWN;
36256a34939Shaad 
36356a34939Shaad 	if (lv->status & FIXED_MINOR) {
36456a34939Shaad 		lvd->lv_status |= LV_PERSISTENT_MINOR;
36556a34939Shaad 		lvd->lv_dev = MKDEV(lv->major, lv->minor);
36656a34939Shaad 	} else {
36756a34939Shaad 		lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid));
36856a34939Shaad 	}
36956a34939Shaad 
37056a34939Shaad 	if (lv->read_ahead == DM_READ_AHEAD_AUTO ||
37156a34939Shaad 	    lv->read_ahead == DM_READ_AHEAD_NONE)
37256a34939Shaad 		lvd->lv_read_ahead = 0;
37356a34939Shaad 	else
37456a34939Shaad 		lvd->lv_read_ahead = lv->read_ahead;
37556a34939Shaad 
37656a34939Shaad 	lvd->lv_stripes =
37756a34939Shaad 	    dm_list_item(lv->segments.n, struct lv_segment)->area_count;
37856a34939Shaad 	lvd->lv_stripesize =
37956a34939Shaad 	    dm_list_item(lv->segments.n, struct lv_segment)->stripe_size;
38056a34939Shaad 
38156a34939Shaad 	lvd->lv_size = lv->size;
38256a34939Shaad 	lvd->lv_allocated_le = lv->le_count;
38356a34939Shaad 
38456a34939Shaad 	if (lv->status & BADBLOCK_ON)
38556a34939Shaad 		lvd->lv_badblock = LV_BADBLOCK_ON;
38656a34939Shaad 
38756a34939Shaad 	if (lv->alloc == ALLOC_CONTIGUOUS)
38856a34939Shaad 		lvd->lv_allocation |= LV_CONTIGUOUS;
38956a34939Shaad }
39056a34939Shaad 
export_extents(struct disk_list * dl,uint32_t lv_num,struct logical_volume * lv,struct physical_volume * pv)39156a34939Shaad int export_extents(struct disk_list *dl, uint32_t lv_num,
39256a34939Shaad 		   struct logical_volume *lv, struct physical_volume *pv)
39356a34939Shaad {
39456a34939Shaad 	struct pe_disk *ped;
39556a34939Shaad 	struct lv_segment *seg;
39656a34939Shaad 	uint32_t pe, s;
39756a34939Shaad 
39856a34939Shaad 	dm_list_iterate_items(seg, &lv->segments) {
39956a34939Shaad 		for (s = 0; s < seg->area_count; s++) {
40056a34939Shaad 			if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
40156a34939Shaad 				log_error("Segment type %s in LV %s: "
40256a34939Shaad 					  "unsupported by format1",
40356a34939Shaad 					  seg->segtype->name, lv->name);
40456a34939Shaad 				return 0;
40556a34939Shaad 			}
40656a34939Shaad 			if (seg_type(seg, s) != AREA_PV) {
40756a34939Shaad 				log_error("Non-PV stripe found in LV %s: "
40856a34939Shaad 					  "unsupported by format1", lv->name);
40956a34939Shaad 				return 0;
41056a34939Shaad 			}
41156a34939Shaad 			if (seg_pv(seg, s) != pv)
41256a34939Shaad 				continue;	/* not our pv */
41356a34939Shaad 
41456a34939Shaad 			for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
41556a34939Shaad 				ped = &dl->extents[pe + seg_pe(seg, s)];
41656a34939Shaad 				ped->lv_num = lv_num;
41756a34939Shaad 				ped->le_num = (seg->le / seg->area_count) + pe +
41856a34939Shaad 				    s * (lv->le_count / seg->area_count);
41956a34939Shaad 			}
42056a34939Shaad 		}
42156a34939Shaad 	}
42256a34939Shaad 
42356a34939Shaad 	return 1;
42456a34939Shaad }
42556a34939Shaad 
import_pvs(const struct format_type * fmt,struct dm_pool * mem,struct volume_group * vg,struct dm_list * pvds,struct dm_list * results,uint32_t * count)42656a34939Shaad int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
42756a34939Shaad 	       struct volume_group *vg,
42856a34939Shaad 	       struct dm_list *pvds, struct dm_list *results, uint32_t *count)
42956a34939Shaad {
43056a34939Shaad 	struct disk_list *dl;
43156a34939Shaad 	struct pv_list *pvl;
43256a34939Shaad 
43356a34939Shaad 	*count = 0;
43456a34939Shaad 	dm_list_iterate_items(dl, pvds) {
43556a34939Shaad 		if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
43656a34939Shaad 		    !(pvl->pv = dm_pool_alloc(mem, sizeof(*pvl->pv))))
43756a34939Shaad 			return_0;
43856a34939Shaad 
43956a34939Shaad 		if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd))
44056a34939Shaad 			return_0;
44156a34939Shaad 
44256a34939Shaad 		pvl->pv->fmt = fmt;
44356a34939Shaad 		dm_list_add(results, &pvl->list);
44456a34939Shaad 		(*count)++;
44556a34939Shaad 	}
44656a34939Shaad 
44756a34939Shaad 	return 1;
44856a34939Shaad }
44956a34939Shaad 
_add_lv(struct dm_pool * mem,struct volume_group * vg,struct lv_disk * lvd)45056a34939Shaad static struct logical_volume *_add_lv(struct dm_pool *mem,
45156a34939Shaad 				      struct volume_group *vg,
45256a34939Shaad 				      struct lv_disk *lvd)
45356a34939Shaad {
45456a34939Shaad 	struct logical_volume *lv;
45556a34939Shaad 
4567c604eeaShaad 	if (!(lv = alloc_lv(mem)))
45756a34939Shaad 		return_NULL;
45856a34939Shaad 
4597c604eeaShaad 	lvid_from_lvnum(&lv->lvid, &vg->id, lvd->lv_number);
4607c604eeaShaad 
4617c604eeaShaad 	if (!import_lv(vg->cmd, mem, lv, lvd))
4627c604eeaShaad 		goto_bad;
4637c604eeaShaad 
4647c604eeaShaad 	if (!link_lv_to_vg(vg, lv))
4657c604eeaShaad 		goto_bad;
46656a34939Shaad 
46756a34939Shaad 	return lv;
4687c604eeaShaad bad:
4697c604eeaShaad 	dm_pool_free(mem, lv);
4707c604eeaShaad 	return NULL;
47156a34939Shaad }
47256a34939Shaad 
import_lvs(struct dm_pool * mem,struct volume_group * vg,struct dm_list * pvds)47356a34939Shaad int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds)
47456a34939Shaad {
47556a34939Shaad 	struct disk_list *dl;
47656a34939Shaad 	struct lvd_list *ll;
47756a34939Shaad 	struct lv_disk *lvd;
47856a34939Shaad 
47956a34939Shaad 	dm_list_iterate_items(dl, pvds) {
48056a34939Shaad 		dm_list_iterate_items(ll, &dl->lvds) {
48156a34939Shaad 			lvd = &ll->lvd;
48256a34939Shaad 
48356a34939Shaad 			if (!find_lv(vg, (char *)lvd->lv_name) &&
48456a34939Shaad 			    !_add_lv(mem, vg, lvd))
48556a34939Shaad 				return_0;
48656a34939Shaad 		}
48756a34939Shaad 	}
48856a34939Shaad 
48956a34939Shaad 	return 1;
49056a34939Shaad }
49156a34939Shaad 
49256a34939Shaad /* FIXME: tidy */
export_lvs(struct disk_list * dl,struct volume_group * vg,struct physical_volume * pv,const char * dev_dir)49356a34939Shaad int export_lvs(struct disk_list *dl, struct volume_group *vg,
49456a34939Shaad 	       struct physical_volume *pv, const char *dev_dir)
49556a34939Shaad {
49656a34939Shaad 	int r = 0;
49756a34939Shaad 	struct lv_list *ll;
49856a34939Shaad 	struct lvd_list *lvdl;
49956a34939Shaad 	size_t len;
50056a34939Shaad 	uint32_t lv_num;
50156a34939Shaad 	struct dm_hash_table *lvd_hash;
50256a34939Shaad 
50356a34939Shaad 	if (!_check_vg_name(vg->name))
50456a34939Shaad 		return_0;
50556a34939Shaad 
50656a34939Shaad 	if (!(lvd_hash = dm_hash_create(32)))
50756a34939Shaad 		return_0;
50856a34939Shaad 
50956a34939Shaad 	/*
51056a34939Shaad 	 * setup the pv's extents array
51156a34939Shaad 	 */
51256a34939Shaad 	len = sizeof(struct pe_disk) * dl->pvd.pe_total;
51356a34939Shaad 	if (!(dl->extents = dm_pool_alloc(dl->mem, len)))
51456a34939Shaad 		goto_out;
51556a34939Shaad 	memset(dl->extents, 0, len);
51656a34939Shaad 
51756a34939Shaad 	dm_list_iterate_items(ll, &vg->lvs) {
51856a34939Shaad 		if (ll->lv->status & SNAPSHOT)
51956a34939Shaad 			continue;
52056a34939Shaad 
52156a34939Shaad 		if (!(lvdl = dm_pool_alloc(dl->mem, sizeof(*lvdl))))
52256a34939Shaad 			goto_out;
52356a34939Shaad 
52456a34939Shaad 		_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
52556a34939Shaad 
52656a34939Shaad 		lv_num = lvnum_from_lvid(&ll->lv->lvid);
52756a34939Shaad 		lvdl->lvd.lv_number = lv_num;
52856a34939Shaad 
52956a34939Shaad 		if (!dm_hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd))
53056a34939Shaad 			goto_out;
53156a34939Shaad 
53256a34939Shaad 		if (!export_extents(dl, lv_num + 1, ll->lv, pv))
53356a34939Shaad 			goto_out;
53456a34939Shaad 
53556a34939Shaad 		if (lv_is_origin(ll->lv))
53656a34939Shaad 			lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
53756a34939Shaad 
53856a34939Shaad 		if (lv_is_cow(ll->lv)) {
53956a34939Shaad 			lvdl->lvd.lv_access |= LV_SNAPSHOT;
54056a34939Shaad 			lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
54156a34939Shaad 			lvdl->lvd.lv_snapshot_minor =
54256a34939Shaad 			    lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
54356a34939Shaad 		}
54456a34939Shaad 
54556a34939Shaad 		dm_list_add(&dl->lvds, &lvdl->list);
54656a34939Shaad 		dl->pvd.lv_cur++;
54756a34939Shaad 	}
54856a34939Shaad 
54956a34939Shaad 	r = 1;
55056a34939Shaad 
55156a34939Shaad       out:
55256a34939Shaad 	dm_hash_destroy(lvd_hash);
55356a34939Shaad 	return r;
55456a34939Shaad }
55556a34939Shaad 
55656a34939Shaad /*
55756a34939Shaad  * FIXME: More inefficient code.
55856a34939Shaad  */
import_snapshots(struct dm_pool * mem __attribute ((unused)),struct volume_group * vg,struct dm_list * pvds)55956a34939Shaad int import_snapshots(struct dm_pool *mem __attribute((unused)), struct volume_group *vg,
56056a34939Shaad 		     struct dm_list *pvds)
56156a34939Shaad {
56256a34939Shaad 	struct logical_volume *lvs[MAX_LV];
56356a34939Shaad 	struct disk_list *dl;
56456a34939Shaad 	struct lvd_list *ll;
56556a34939Shaad 	struct lv_disk *lvd;
56656a34939Shaad 	int lvnum;
56756a34939Shaad 	struct logical_volume *org, *cow;
56856a34939Shaad 
56956a34939Shaad 	/* build an index of lv numbers */
57056a34939Shaad 	memset(lvs, 0, sizeof(lvs));
57156a34939Shaad 	dm_list_iterate_items(dl, pvds) {
57256a34939Shaad 		dm_list_iterate_items(ll, &dl->lvds) {
57356a34939Shaad 			lvd = &ll->lvd;
57456a34939Shaad 
57556a34939Shaad 			lvnum = lvd->lv_number;
57656a34939Shaad 
57756a34939Shaad 			if (lvnum >= MAX_LV) {
5787c604eeaShaad 				log_error("Logical volume number "
57956a34939Shaad 					  "out of bounds.");
58056a34939Shaad 				return 0;
58156a34939Shaad 			}
58256a34939Shaad 
58356a34939Shaad 			if (!lvs[lvnum] &&
58456a34939Shaad 			    !(lvs[lvnum] = find_lv(vg, (char *)lvd->lv_name))) {
5857c604eeaShaad 				log_error("Couldn't find logical volume '%s'.",
58656a34939Shaad 					  lvd->lv_name);
58756a34939Shaad 				return 0;
58856a34939Shaad 			}
58956a34939Shaad 		}
59056a34939Shaad 	}
59156a34939Shaad 
59256a34939Shaad 	/*
59356a34939Shaad 	 * Now iterate through yet again adding the snapshots.
59456a34939Shaad 	 */
59556a34939Shaad 	dm_list_iterate_items(dl, pvds) {
59656a34939Shaad 		dm_list_iterate_items(ll, &dl->lvds) {
59756a34939Shaad 			lvd = &ll->lvd;
59856a34939Shaad 
59956a34939Shaad 			if (!(lvd->lv_access & LV_SNAPSHOT))
60056a34939Shaad 				continue;
60156a34939Shaad 
60256a34939Shaad 			lvnum = lvd->lv_number;
60356a34939Shaad 			cow = lvs[lvnum];
60456a34939Shaad 			if (!(org = lvs[lvd->lv_snapshot_minor])) {
6057c604eeaShaad 				log_error("Couldn't find origin logical volume "
60656a34939Shaad 					  "for snapshot '%s'.", lvd->lv_name);
60756a34939Shaad 				return 0;
60856a34939Shaad 			}
60956a34939Shaad 
61056a34939Shaad 			/* we may have already added this snapshot */
61156a34939Shaad 			if (lv_is_cow(cow))
61256a34939Shaad 				continue;
61356a34939Shaad 
61456a34939Shaad 			/* insert the snapshot */
6157c604eeaShaad 			if (!vg_add_snapshot(org, cow, NULL,
61656a34939Shaad 					     org->le_count,
61756a34939Shaad 					     lvd->lv_chunk_size)) {
6187c604eeaShaad 				log_error("Couldn't add snapshot.");
61956a34939Shaad 				return 0;
62056a34939Shaad 			}
62156a34939Shaad 		}
62256a34939Shaad 	}
62356a34939Shaad 
62456a34939Shaad 	return 1;
62556a34939Shaad }
62656a34939Shaad 
export_uuids(struct disk_list * dl,struct volume_group * vg)62756a34939Shaad int export_uuids(struct disk_list *dl, struct volume_group *vg)
62856a34939Shaad {
62956a34939Shaad 	struct uuid_list *ul;
63056a34939Shaad 	struct pv_list *pvl;
63156a34939Shaad 
63256a34939Shaad 	dm_list_iterate_items(pvl, &vg->pvs) {
63356a34939Shaad 		if (!(ul = dm_pool_alloc(dl->mem, sizeof(*ul))))
63456a34939Shaad 			return_0;
63556a34939Shaad 
63656a34939Shaad 		memset(ul->uuid, 0, sizeof(ul->uuid));
63756a34939Shaad 		memcpy(ul->uuid, pvl->pv->id.uuid, ID_LEN);
63856a34939Shaad 
63956a34939Shaad 		dm_list_add(&dl->uuids, &ul->list);
64056a34939Shaad 	}
64156a34939Shaad 	return 1;
64256a34939Shaad }
64356a34939Shaad 
64456a34939Shaad /*
64556a34939Shaad  * This calculates the nasty pv_number field
64656a34939Shaad  * used by LVM1.
64756a34939Shaad  */
export_numbers(struct dm_list * pvds,struct volume_group * vg __attribute ((unused)))64856a34939Shaad void export_numbers(struct dm_list *pvds, struct volume_group *vg __attribute((unused)))
64956a34939Shaad {
65056a34939Shaad 	struct disk_list *dl;
65156a34939Shaad 	int pv_num = 1;
65256a34939Shaad 
65356a34939Shaad 	dm_list_iterate_items(dl, pvds)
65456a34939Shaad 		dl->pvd.pv_number = pv_num++;
65556a34939Shaad }
65656a34939Shaad 
65756a34939Shaad /*
65856a34939Shaad  * Calculate vg_disk->pv_act.
65956a34939Shaad  */
export_pv_act(struct dm_list * pvds)66056a34939Shaad void export_pv_act(struct dm_list *pvds)
66156a34939Shaad {
66256a34939Shaad 	struct disk_list *dl;
66356a34939Shaad 	int act = 0;
66456a34939Shaad 
66556a34939Shaad 	dm_list_iterate_items(dl, pvds)
66656a34939Shaad 		if (dl->pvd.pv_status & PV_ACTIVE)
66756a34939Shaad 			act++;
66856a34939Shaad 
66956a34939Shaad 	dm_list_iterate_items(dl, pvds)
67056a34939Shaad 		dl->vgd.pv_act = act;
67156a34939Shaad }
67256a34939Shaad 
export_vg_number(struct format_instance * fid,struct dm_list * pvds,const char * vg_name,struct dev_filter * filter)67356a34939Shaad int export_vg_number(struct format_instance *fid, struct dm_list *pvds,
67456a34939Shaad 		     const char *vg_name, struct dev_filter *filter)
67556a34939Shaad {
67656a34939Shaad 	struct disk_list *dl;
67756a34939Shaad 	int vg_num;
67856a34939Shaad 
67956a34939Shaad 	if (!get_free_vg_number(fid, filter, vg_name, &vg_num))
68056a34939Shaad 		return_0;
68156a34939Shaad 
68256a34939Shaad 	dm_list_iterate_items(dl, pvds)
68356a34939Shaad 		dl->vgd.vg_number = vg_num;
68456a34939Shaad 
68556a34939Shaad 	return 1;
68656a34939Shaad }
687