Home | History | Annotate | Line # | Download | only in format1
      1      1.1  haad /*	$NetBSD: disk-rep.c,v 1.1.1.2 2009/12/02 00:26:48 haad Exp $	*/
      2      1.1  haad 
      3      1.1  haad /*
      4      1.1  haad  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
      5      1.1  haad  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
      6      1.1  haad  *
      7      1.1  haad  * This file is part of LVM2.
      8      1.1  haad  *
      9      1.1  haad  * This copyrighted material is made available to anyone wishing to use,
     10      1.1  haad  * modify, copy, or redistribute it subject to the terms and conditions
     11      1.1  haad  * of the GNU Lesser General Public License v.2.1.
     12      1.1  haad  *
     13      1.1  haad  * You should have received a copy of the GNU Lesser General Public License
     14      1.1  haad  * along with this program; if not, write to the Free Software Foundation,
     15      1.1  haad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16      1.1  haad  */
     17      1.1  haad 
     18      1.1  haad #include "lib.h"
     19      1.1  haad #include "disk-rep.h"
     20      1.1  haad #include "xlate.h"
     21      1.1  haad #include "filter.h"
     22      1.1  haad #include "lvmcache.h"
     23      1.1  haad 
     24      1.1  haad #include <fcntl.h>
     25      1.1  haad 
     26      1.1  haad #define xx16(v) disk->v = xlate16(disk->v)
     27      1.1  haad #define xx32(v) disk->v = xlate32(disk->v)
     28      1.1  haad #define xx64(v) disk->v = xlate64(disk->v)
     29      1.1  haad 
     30      1.1  haad /*
     31      1.1  haad  * Functions to perform the endian conversion
     32      1.1  haad  * between disk and core.  The same code works
     33      1.1  haad  * both ways of course.
     34      1.1  haad  */
     35      1.1  haad static void _xlate_pvd(struct pv_disk *disk)
     36      1.1  haad {
     37      1.1  haad 	xx16(version);
     38      1.1  haad 
     39      1.1  haad 	xx32(pv_on_disk.base);
     40      1.1  haad 	xx32(pv_on_disk.size);
     41      1.1  haad 	xx32(vg_on_disk.base);
     42      1.1  haad 	xx32(vg_on_disk.size);
     43      1.1  haad 	xx32(pv_uuidlist_on_disk.base);
     44      1.1  haad 	xx32(pv_uuidlist_on_disk.size);
     45      1.1  haad 	xx32(lv_on_disk.base);
     46      1.1  haad 	xx32(lv_on_disk.size);
     47      1.1  haad 	xx32(pe_on_disk.base);
     48      1.1  haad 	xx32(pe_on_disk.size);
     49      1.1  haad 
     50      1.1  haad 	xx32(pv_major);
     51      1.1  haad 	xx32(pv_number);
     52      1.1  haad 	xx32(pv_status);
     53      1.1  haad 	xx32(pv_allocatable);
     54      1.1  haad 	xx32(pv_size);
     55      1.1  haad 	xx32(lv_cur);
     56      1.1  haad 	xx32(pe_size);
     57      1.1  haad 	xx32(pe_total);
     58      1.1  haad 	xx32(pe_allocated);
     59      1.1  haad 	xx32(pe_start);
     60      1.1  haad }
     61      1.1  haad 
     62      1.1  haad static void _xlate_lvd(struct lv_disk *disk)
     63      1.1  haad {
     64      1.1  haad 	xx32(lv_access);
     65      1.1  haad 	xx32(lv_status);
     66      1.1  haad 	xx32(lv_open);
     67      1.1  haad 	xx32(lv_dev);
     68      1.1  haad 	xx32(lv_number);
     69      1.1  haad 	xx32(lv_mirror_copies);
     70      1.1  haad 	xx32(lv_recovery);
     71      1.1  haad 	xx32(lv_schedule);
     72      1.1  haad 	xx32(lv_size);
     73      1.1  haad 	xx32(lv_snapshot_minor);
     74      1.1  haad 	xx16(lv_chunk_size);
     75      1.1  haad 	xx16(dummy);
     76      1.1  haad 	xx32(lv_allocated_le);
     77      1.1  haad 	xx32(lv_stripes);
     78      1.1  haad 	xx32(lv_stripesize);
     79      1.1  haad 	xx32(lv_badblock);
     80      1.1  haad 	xx32(lv_allocation);
     81      1.1  haad 	xx32(lv_io_timeout);
     82      1.1  haad 	xx32(lv_read_ahead);
     83      1.1  haad }
     84      1.1  haad 
     85      1.1  haad static void _xlate_vgd(struct vg_disk *disk)
     86      1.1  haad {
     87      1.1  haad 	xx32(vg_number);
     88      1.1  haad 	xx32(vg_access);
     89      1.1  haad 	xx32(vg_status);
     90      1.1  haad 	xx32(lv_max);
     91      1.1  haad 	xx32(lv_cur);
     92      1.1  haad 	xx32(lv_open);
     93      1.1  haad 	xx32(pv_max);
     94      1.1  haad 	xx32(pv_cur);
     95      1.1  haad 	xx32(pv_act);
     96      1.1  haad 	xx32(dummy);
     97      1.1  haad 	xx32(vgda);
     98      1.1  haad 	xx32(pe_size);
     99      1.1  haad 	xx32(pe_total);
    100      1.1  haad 	xx32(pe_allocated);
    101      1.1  haad 	xx32(pvg_total);
    102      1.1  haad }
    103      1.1  haad 
    104      1.1  haad static void _xlate_extents(struct pe_disk *extents, uint32_t count)
    105      1.1  haad {
    106      1.1  haad 	unsigned i;
    107      1.1  haad 
    108      1.1  haad 	for (i = 0; i < count; i++) {
    109      1.1  haad 		extents[i].lv_num = xlate16(extents[i].lv_num);
    110      1.1  haad 		extents[i].le_num = xlate16(extents[i].le_num);
    111      1.1  haad 	}
    112      1.1  haad }
    113      1.1  haad 
    114      1.1  haad /*
    115      1.1  haad  * Handle both minor metadata formats.
    116      1.1  haad  */
    117      1.1  haad static int _munge_formats(struct pv_disk *pvd)
    118      1.1  haad {
    119      1.1  haad 	uint32_t pe_start;
    120      1.1  haad 	unsigned b, e;
    121      1.1  haad 
    122      1.1  haad 	switch (pvd->version) {
    123      1.1  haad 	case 1:
    124      1.1  haad 		pvd->pe_start = ((pvd->pe_on_disk.base +
    125      1.1  haad 				  pvd->pe_on_disk.size) >> SECTOR_SHIFT);
    126      1.1  haad 		break;
    127      1.1  haad 
    128      1.1  haad 	case 2:
    129      1.1  haad 		pvd->version = 1;
    130      1.1  haad 		pe_start = pvd->pe_start << SECTOR_SHIFT;
    131      1.1  haad 		pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
    132      1.1  haad 		break;
    133      1.1  haad 
    134      1.1  haad 	default:
    135      1.1  haad 		return 0;
    136      1.1  haad 	}
    137      1.1  haad 
    138      1.1  haad 	/* UUID too long? */
    139      1.1  haad 	if (pvd->pv_uuid[ID_LEN]) {
    140      1.1  haad 		/* Retain ID_LEN chars from end */
    141      1.1  haad 		for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) {
    142      1.1  haad 			if (!pvd->pv_uuid[e]) {
    143      1.1  haad 				e--;
    144      1.1  haad 				break;
    145      1.1  haad 			}
    146      1.1  haad 		}
    147      1.1  haad 		for (b = 0; b < ID_LEN; b++) {
    148      1.1  haad 			pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN];
    149      1.1  haad 			/* FIXME Remove all invalid chars */
    150      1.1  haad 			if (pvd->pv_uuid[b] == '/')
    151      1.1  haad 				pvd->pv_uuid[b] = '#';
    152      1.1  haad 		}
    153      1.1  haad 		memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN);
    154      1.1  haad 	}
    155      1.1  haad 
    156      1.1  haad 	/* If UUID is missing, create one */
    157      1.1  haad 	if (pvd->pv_uuid[0] == '\0') {
    158      1.1  haad 		uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number);
    159      1.1  haad 		pvd->pv_uuid[ID_LEN] = '\0';
    160      1.1  haad 	}
    161      1.1  haad 
    162      1.1  haad 	return 1;
    163      1.1  haad }
    164      1.1  haad 
    165      1.1  haad /*
    166      1.1  haad  * If exported, remove "PV_EXP" from end of VG name
    167      1.1  haad  */
    168      1.1  haad static void _munge_exported_vg(struct pv_disk *pvd)
    169      1.1  haad {
    170      1.1  haad 	int l;
    171      1.1  haad 	size_t s;
    172      1.1  haad 
    173      1.1  haad 	/* Return if PV not in a VG */
    174      1.1  haad 	if ((!*pvd->vg_name))
    175      1.1  haad 		return;
    176      1.1  haad 	/* FIXME also check vgd->status & VG_EXPORTED? */
    177      1.1  haad 
    178      1.1  haad 	l = strlen((char *)pvd->vg_name);
    179      1.1  haad 	s = sizeof(EXPORTED_TAG);
    180      1.1  haad 	if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
    181      1.1  haad 		pvd->vg_name[l - s + 1] = '\0';
    182      1.1  haad 		pvd->pv_status |= VG_EXPORTED;
    183      1.1  haad 	}
    184      1.1  haad }
    185      1.1  haad 
    186      1.1  haad int munge_pvd(struct device *dev, struct pv_disk *pvd)
    187      1.1  haad {
    188      1.1  haad 	_xlate_pvd(pvd);
    189      1.1  haad 
    190      1.1  haad 	if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
    191      1.1  haad 		log_very_verbose("%s does not have a valid LVM1 PV identifier",
    192      1.1  haad 				 dev_name(dev));
    193      1.1  haad 		return 0;
    194      1.1  haad 	}
    195      1.1  haad 
    196      1.1  haad 	if (!_munge_formats(pvd)) {
    197      1.1  haad 		log_very_verbose("format1: Unknown metadata version %d "
    198      1.1  haad 				 "found on %s", pvd->version, dev_name(dev));
    199      1.1  haad 		return 0;
    200      1.1  haad 	}
    201      1.1  haad 
    202      1.1  haad 	/* If VG is exported, set VG name back to the real name */
    203      1.1  haad 	_munge_exported_vg(pvd);
    204      1.1  haad 
    205      1.1  haad 	return 1;
    206      1.1  haad }
    207      1.1  haad 
    208      1.1  haad static int _read_pvd(struct device *dev, struct pv_disk *pvd)
    209      1.1  haad {
    210      1.1  haad 	if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
    211      1.1  haad 		log_very_verbose("Failed to read PV data from %s",
    212      1.1  haad 				 dev_name(dev));
    213      1.1  haad 		return 0;
    214      1.1  haad 	}
    215      1.1  haad 
    216      1.1  haad 	return munge_pvd(dev, pvd);
    217      1.1  haad }
    218      1.1  haad 
    219      1.1  haad static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
    220      1.1  haad {
    221      1.1  haad 	if (!dev_read(dev, pos, sizeof(*disk), disk))
    222      1.1  haad 		return_0;
    223      1.1  haad 
    224      1.1  haad 	_xlate_lvd(disk);
    225      1.1  haad 
    226      1.1  haad 	return 1;
    227      1.1  haad }
    228      1.1  haad 
    229      1.1  haad int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
    230      1.1  haad {
    231      1.1  haad 	uint64_t pos = pvd->vg_on_disk.base;
    232      1.1  haad 
    233      1.1  haad 	if (!dev_read(dev, pos, sizeof(*vgd), vgd))
    234      1.1  haad 		return_0;
    235      1.1  haad 
    236      1.1  haad 	_xlate_vgd(vgd);
    237      1.1  haad 
    238      1.1  haad 	if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV))
    239      1.1  haad 		return_0;
    240      1.1  haad 
    241      1.1  haad 	/* If UUID is missing, create one */
    242      1.1  haad 	if (vgd->vg_uuid[0] == '\0')
    243      1.1  haad 		uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number);
    244      1.1  haad 
    245      1.1  haad 	return 1;
    246      1.1  haad }
    247      1.1  haad 
    248      1.1  haad static int _read_uuids(struct disk_list *data)
    249      1.1  haad {
    250      1.1  haad 	unsigned num_read = 0;
    251      1.1  haad 	struct uuid_list *ul;
    252      1.1  haad 	char buffer[NAME_LEN] __attribute((aligned(8)));
    253      1.1  haad 	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
    254      1.1  haad 	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
    255      1.1  haad 
    256      1.1  haad 	while (pos < end && num_read < data->vgd.pv_cur) {
    257      1.1  haad 		if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
    258      1.1  haad 			return_0;
    259      1.1  haad 
    260      1.1  haad 		if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul))))
    261      1.1  haad 			return_0;
    262      1.1  haad 
    263      1.1  haad 		memcpy(ul->uuid, buffer, NAME_LEN);
    264      1.1  haad 		ul->uuid[NAME_LEN - 1] = '\0';
    265      1.1  haad 
    266      1.1  haad 		dm_list_add(&data->uuids, &ul->list);
    267      1.1  haad 
    268      1.1  haad 		pos += NAME_LEN;
    269      1.1  haad 		num_read++;
    270      1.1  haad 	}
    271      1.1  haad 
    272      1.1  haad 	return 1;
    273      1.1  haad }
    274      1.1  haad 
    275      1.1  haad static int _check_lvd(struct lv_disk *lvd)
    276      1.1  haad {
    277      1.1  haad 	return !(lvd->lv_name[0] == '\0');
    278      1.1  haad }
    279      1.1  haad 
    280      1.1  haad static int _read_lvs(struct disk_list *data)
    281      1.1  haad {
    282      1.1  haad 	unsigned int i, lvs_read = 0;
    283      1.1  haad 	uint64_t pos;
    284      1.1  haad 	struct lvd_list *ll;
    285      1.1  haad 	struct vg_disk *vgd = &data->vgd;
    286      1.1  haad 
    287      1.1  haad 	for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) {
    288      1.1  haad 		pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk));
    289      1.1  haad 		ll = dm_pool_alloc(data->mem, sizeof(*ll));
    290      1.1  haad 
    291      1.1  haad 		if (!ll)
    292      1.1  haad 			return_0;
    293      1.1  haad 
    294      1.1  haad 		if (!_read_lvd(data->dev, pos, &ll->lvd))
    295      1.1  haad 			return_0;
    296      1.1  haad 
    297      1.1  haad 		if (!_check_lvd(&ll->lvd))
    298      1.1  haad 			continue;
    299      1.1  haad 
    300      1.1  haad 		lvs_read++;
    301      1.1  haad 		dm_list_add(&data->lvds, &ll->list);
    302      1.1  haad 	}
    303      1.1  haad 
    304      1.1  haad 	return 1;
    305      1.1  haad }
    306      1.1  haad 
    307      1.1  haad static int _read_extents(struct disk_list *data)
    308      1.1  haad {
    309      1.1  haad 	size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
    310      1.1  haad 	struct pe_disk *extents = dm_pool_alloc(data->mem, len);
    311      1.1  haad 	uint64_t pos = data->pvd.pe_on_disk.base;
    312      1.1  haad 
    313      1.1  haad 	if (!extents)
    314      1.1  haad 		return_0;
    315      1.1  haad 
    316      1.1  haad 	if (!dev_read(data->dev, pos, len, extents))
    317      1.1  haad 		return_0;
    318      1.1  haad 
    319      1.1  haad 	_xlate_extents(extents, data->pvd.pe_total);
    320      1.1  haad 	data->extents = extents;
    321      1.1  haad 
    322      1.1  haad 	return 1;
    323      1.1  haad }
    324      1.1  haad 
    325      1.1  haad static void __update_lvmcache(const struct format_type *fmt,
    326      1.1  haad 			      struct disk_list *dl,
    327      1.1  haad 			      struct device *dev, const char *vgid,
    328      1.1  haad 			      unsigned exported)
    329      1.1  haad {
    330      1.1  haad 	struct lvmcache_info *info;
    331      1.1  haad 	const char *vgname = *((char *)dl->pvd.vg_name) ?
    332      1.1  haad 			     (char *)dl->pvd.vg_name : fmt->orphan_vg_name;
    333      1.1  haad 
    334      1.1  haad 	if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev,
    335      1.1  haad 				  vgname, vgid, exported ? EXPORTED_VG : 0))) {
    336      1.1  haad 		stack;
    337      1.1  haad 		return;
    338      1.1  haad 	}
    339      1.1  haad 
    340      1.1  haad 	info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
    341      1.1  haad 	dm_list_init(&info->mdas);
    342      1.1  haad 	info->status &= ~CACHE_INVALID;
    343      1.1  haad }
    344      1.1  haad 
    345      1.1  haad static struct disk_list *__read_disk(const struct format_type *fmt,
    346      1.1  haad 				     struct device *dev, struct dm_pool *mem,
    347      1.1  haad 				     const char *vg_name)
    348      1.1  haad {
    349      1.1  haad 	struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl));
    350      1.1  haad 	const char *name = dev_name(dev);
    351      1.1  haad 
    352      1.1  haad 	if (!dl)
    353      1.1  haad 		return_NULL;
    354      1.1  haad 
    355      1.1  haad 	dl->dev = dev;
    356      1.1  haad 	dl->mem = mem;
    357      1.1  haad 	dm_list_init(&dl->uuids);
    358      1.1  haad 	dm_list_init(&dl->lvds);
    359      1.1  haad 
    360      1.1  haad 	if (!_read_pvd(dev, &dl->pvd))
    361      1.1  haad 		goto_bad;
    362      1.1  haad 
    363      1.1  haad 	/*
    364      1.1  haad 	 * is it an orphan ?
    365      1.1  haad 	 */
    366      1.1  haad 	if (!*dl->pvd.vg_name) {
    367      1.1  haad 		log_very_verbose("%s is not a member of any format1 VG", name);
    368      1.1  haad 
    369      1.1  haad 		__update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
    370      1.1  haad 		return (vg_name) ? NULL : dl;
    371      1.1  haad 	}
    372      1.1  haad 
    373      1.1  haad 	if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) {
    374      1.1  haad 		log_error("Failed to read VG data from PV (%s)", name);
    375      1.1  haad 		__update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
    376      1.1  haad 		goto bad;
    377      1.1  haad 	}
    378      1.1  haad 
    379      1.1  haad 	if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) {
    380      1.1  haad 		log_very_verbose("%s is not a member of the VG %s",
    381      1.1  haad 				 name, vg_name);
    382      1.1  haad 		__update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
    383      1.1  haad 		goto bad;
    384      1.1  haad 	}
    385      1.1  haad 
    386      1.1  haad 	__update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid,
    387      1.1  haad 			  dl->vgd.vg_status & VG_EXPORTED);
    388      1.1  haad 
    389      1.1  haad 	if (!_read_uuids(dl)) {
    390      1.1  haad 		log_error("Failed to read PV uuid list from %s", name);
    391      1.1  haad 		goto bad;
    392      1.1  haad 	}
    393      1.1  haad 
    394      1.1  haad 	if (!_read_lvs(dl)) {
    395      1.1  haad 		log_error("Failed to read LV's from %s", name);
    396      1.1  haad 		goto bad;
    397      1.1  haad 	}
    398      1.1  haad 
    399      1.1  haad 	if (!_read_extents(dl)) {
    400      1.1  haad 		log_error("Failed to read extents from %s", name);
    401      1.1  haad 		goto bad;
    402      1.1  haad 	}
    403      1.1  haad 
    404      1.1  haad 	log_very_verbose("Found %s in %sVG %s", name,
    405      1.1  haad 			 (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
    406      1.1  haad 			 dl->pvd.vg_name);
    407      1.1  haad 
    408      1.1  haad 	return dl;
    409      1.1  haad 
    410      1.1  haad       bad:
    411      1.1  haad 	dm_pool_free(dl->mem, dl);
    412      1.1  haad 	return NULL;
    413      1.1  haad }
    414      1.1  haad 
    415      1.1  haad struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
    416      1.1  haad 			    struct dm_pool *mem, const char *vg_name)
    417      1.1  haad {
    418      1.1  haad 	struct disk_list *dl;
    419      1.1  haad 
    420      1.1  haad 	if (!dev_open(dev))
    421      1.1  haad 		return_NULL;
    422      1.1  haad 
    423      1.1  haad 	dl = __read_disk(fmt, dev, mem, vg_name);
    424      1.1  haad 
    425      1.1  haad 	if (!dev_close(dev))
    426      1.1  haad 		stack;
    427      1.1  haad 
    428      1.1  haad 	return dl;
    429      1.1  haad }
    430      1.1  haad 
    431      1.1  haad static void _add_pv_to_list(struct dm_list *head, struct disk_list *data)
    432      1.1  haad {
    433      1.1  haad 	struct pv_disk *pvd;
    434      1.1  haad 	struct disk_list *diskl;
    435      1.1  haad 
    436      1.1  haad 	dm_list_iterate_items(diskl, head) {
    437      1.1  haad 		pvd = &diskl->pvd;
    438      1.1  haad 		if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid,
    439      1.1  haad 			     sizeof(pvd->pv_uuid))) {
    440  1.1.1.2  haad 			if (!dev_subsystem_part_major(data->dev)) {
    441      1.1  haad 				log_very_verbose("Ignoring duplicate PV %s on "
    442      1.1  haad 						 "%s", pvd->pv_uuid,
    443      1.1  haad 						 dev_name(data->dev));
    444      1.1  haad 				return;
    445      1.1  haad 			}
    446  1.1.1.2  haad 			log_very_verbose("Duplicate PV %s - using %s %s",
    447  1.1.1.2  haad 					 pvd->pv_uuid, dev_subsystem_name(data->dev),
    448  1.1.1.2  haad 					 dev_name(data->dev));
    449      1.1  haad 			dm_list_del(&diskl->list);
    450      1.1  haad 			break;
    451      1.1  haad 		}
    452      1.1  haad 	}
    453      1.1  haad 	dm_list_add(head, &data->list);
    454      1.1  haad }
    455      1.1  haad 
    456      1.1  haad /*
    457      1.1  haad  * Build a list of pv_d's structures, allocated from mem.
    458      1.1  haad  * We keep track of the first object allocated from the pool
    459      1.1  haad  * so we can free off all the memory if something goes wrong.
    460      1.1  haad  */
    461      1.1  haad int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
    462      1.1  haad 		   struct dev_filter *filter, struct dm_pool *mem,
    463      1.1  haad 		   struct dm_list *head)
    464      1.1  haad {
    465      1.1  haad 	struct dev_iter *iter;
    466      1.1  haad 	struct device *dev;
    467      1.1  haad 	struct disk_list *data = NULL;
    468      1.1  haad 	struct lvmcache_vginfo *vginfo;
    469      1.1  haad 	struct lvmcache_info *info;
    470      1.1  haad 
    471      1.1  haad 	/* Fast path if we already saw this VG and cached the list of PVs */
    472      1.1  haad 	if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
    473      1.1  haad 	    vginfo->infos.n) {
    474      1.1  haad 		dm_list_iterate_items(info, &vginfo->infos) {
    475      1.1  haad 			dev = info->dev;
    476      1.1  haad 			if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
    477      1.1  haad 				break;
    478      1.1  haad 			_add_pv_to_list(head, data);
    479      1.1  haad 		}
    480      1.1  haad 
    481      1.1  haad 		/* Did we find the whole VG? */
    482      1.1  haad 		if (!vg_name || is_orphan_vg(vg_name) ||
    483      1.1  haad 		    (data && *data->pvd.vg_name &&
    484      1.1  haad 		     dm_list_size(head) == data->vgd.pv_cur))
    485      1.1  haad 			return 1;
    486      1.1  haad 
    487      1.1  haad 		/* Failed */
    488      1.1  haad 		dm_list_init(head);
    489      1.1  haad 		/* vgcache_del(vg_name); */
    490      1.1  haad 	}
    491      1.1  haad 
    492      1.1  haad 	if (!(iter = dev_iter_create(filter, 1))) {
    493      1.1  haad 		log_error("read_pvs_in_vg: dev_iter_create failed");
    494      1.1  haad 		return 0;
    495      1.1  haad 	}
    496      1.1  haad 
    497      1.1  haad 	/* Otherwise do a complete scan */
    498      1.1  haad 	for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
    499      1.1  haad 		if ((data = read_disk(fmt, dev, mem, vg_name))) {
    500      1.1  haad 			_add_pv_to_list(head, data);
    501      1.1  haad 		}
    502      1.1  haad 	}
    503      1.1  haad 	dev_iter_destroy(iter);
    504      1.1  haad 
    505      1.1  haad 	if (dm_list_empty(head))
    506      1.1  haad 		return 0;
    507      1.1  haad 
    508      1.1  haad 	return 1;
    509      1.1  haad }
    510      1.1  haad 
    511      1.1  haad static int _write_vgd(struct disk_list *data)
    512      1.1  haad {
    513      1.1  haad 	struct vg_disk *vgd = &data->vgd;
    514      1.1  haad 	uint64_t pos = data->pvd.vg_on_disk.base;
    515      1.1  haad 
    516      1.1  haad 	log_debug("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t,
    517      1.1  haad 		  data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd));
    518      1.1  haad 
    519      1.1  haad 	_xlate_vgd(vgd);
    520      1.1  haad 	if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
    521      1.1  haad 		return_0;
    522      1.1  haad 
    523      1.1  haad 	_xlate_vgd(vgd);
    524      1.1  haad 
    525      1.1  haad 	return 1;
    526      1.1  haad }
    527      1.1  haad 
    528      1.1  haad static int _write_uuids(struct disk_list *data)
    529      1.1  haad {
    530      1.1  haad 	struct uuid_list *ul;
    531      1.1  haad 	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
    532      1.1  haad 	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
    533      1.1  haad 
    534      1.1  haad 	dm_list_iterate_items(ul, &data->uuids) {
    535      1.1  haad 		if (pos >= end) {
    536      1.1  haad 			log_error("Too many uuids to fit on %s",
    537      1.1  haad 				  dev_name(data->dev));
    538      1.1  haad 			return 0;
    539      1.1  haad 		}
    540      1.1  haad 
    541      1.1  haad 		log_debug("Writing %s uuidlist to %s at %" PRIu64 " len %d",
    542      1.1  haad 			  data->pvd.vg_name, dev_name(data->dev),
    543      1.1  haad 			  pos, NAME_LEN);
    544      1.1  haad 
    545      1.1  haad 		if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
    546      1.1  haad 			return_0;
    547      1.1  haad 
    548      1.1  haad 		pos += NAME_LEN;
    549      1.1  haad 	}
    550      1.1  haad 
    551      1.1  haad 	return 1;
    552      1.1  haad }
    553      1.1  haad 
    554      1.1  haad static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
    555      1.1  haad {
    556      1.1  haad 	log_debug("Writing %s LV %s metadata to %s at %" PRIu64 " len %"
    557      1.1  haad 		  PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev),
    558      1.1  haad 		  pos, sizeof(*disk));
    559      1.1  haad 
    560      1.1  haad 	_xlate_lvd(disk);
    561      1.1  haad 	if (!dev_write(dev, pos, sizeof(*disk), disk))
    562      1.1  haad 		return_0;
    563      1.1  haad 
    564      1.1  haad 	_xlate_lvd(disk);
    565      1.1  haad 
    566      1.1  haad 	return 1;
    567      1.1  haad }
    568      1.1  haad 
    569      1.1  haad static int _write_lvs(struct disk_list *data)
    570      1.1  haad {
    571      1.1  haad 	struct lvd_list *ll;
    572      1.1  haad 	uint64_t pos, offset;
    573      1.1  haad 
    574      1.1  haad 	pos = data->pvd.lv_on_disk.base;
    575      1.1  haad 
    576      1.1  haad 	if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) {
    577      1.1  haad 		log_error("Couldn't zero lv area on device '%s'",
    578      1.1  haad 			  dev_name(data->dev));
    579      1.1  haad 		return 0;
    580      1.1  haad 	}
    581      1.1  haad 
    582      1.1  haad 	dm_list_iterate_items(ll, &data->lvds) {
    583      1.1  haad 		offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
    584      1.1  haad 		if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
    585      1.1  haad 			log_error("lv_number %d too large", ll->lvd.lv_number);
    586      1.1  haad 			return 0;
    587      1.1  haad 		}
    588      1.1  haad 
    589      1.1  haad 		if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
    590      1.1  haad 			return_0;
    591      1.1  haad 	}
    592      1.1  haad 
    593      1.1  haad 	return 1;
    594      1.1  haad }
    595      1.1  haad 
    596      1.1  haad static int _write_extents(struct disk_list *data)
    597      1.1  haad {
    598      1.1  haad 	size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
    599      1.1  haad 	struct pe_disk *extents = data->extents;
    600      1.1  haad 	uint64_t pos = data->pvd.pe_on_disk.base;
    601      1.1  haad 
    602      1.1  haad 	log_debug("Writing %s extents metadata to %s at %" PRIu64 " len %"
    603      1.1  haad 		  PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
    604      1.1  haad 		  pos, len);
    605      1.1  haad 
    606      1.1  haad 	_xlate_extents(extents, data->pvd.pe_total);
    607      1.1  haad 	if (!dev_write(data->dev, pos, len, extents))
    608      1.1  haad 		return_0;
    609      1.1  haad 
    610      1.1  haad 	_xlate_extents(extents, data->pvd.pe_total);
    611      1.1  haad 
    612      1.1  haad 	return 1;
    613      1.1  haad }
    614      1.1  haad 
    615      1.1  haad static int _write_pvd(struct disk_list *data)
    616      1.1  haad {
    617      1.1  haad 	char *buf;
    618      1.1  haad 	uint64_t pos = data->pvd.pv_on_disk.base;
    619      1.1  haad 	size_t size = data->pvd.pv_on_disk.size;
    620      1.1  haad 
    621      1.1  haad 	if (size < sizeof(struct pv_disk)) {
    622      1.1  haad 		log_error("Invalid PV structure size.");
    623      1.1  haad 		return 0;
    624      1.1  haad 	}
    625      1.1  haad 
    626      1.1  haad 	/* Make sure that the gap between the PV structure and
    627      1.1  haad 	   the next one is zeroed in order to make non LVM tools
    628      1.1  haad 	   happy (idea from AED) */
    629      1.1  haad 	buf = dm_malloc(size);
    630      1.1  haad 	if (!buf) {
    631  1.1.1.2  haad 		log_error("Couldn't allocate temporary PV buffer.");
    632      1.1  haad 		return 0;
    633      1.1  haad 	}
    634      1.1  haad 
    635      1.1  haad 	memset(buf, 0, size);
    636      1.1  haad 	memcpy(buf, &data->pvd, sizeof(struct pv_disk));
    637      1.1  haad 
    638      1.1  haad 	log_debug("Writing %s PV metadata to %s at %" PRIu64 " len %"
    639      1.1  haad 		  PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
    640      1.1  haad 		  pos, size);
    641      1.1  haad 
    642      1.1  haad 	_xlate_pvd((struct pv_disk *) buf);
    643      1.1  haad 	if (!dev_write(data->dev, pos, size, buf)) {
    644      1.1  haad 		dm_free(buf);
    645      1.1  haad 		return_0;
    646      1.1  haad 	}
    647      1.1  haad 
    648      1.1  haad 	dm_free(buf);
    649      1.1  haad 	return 1;
    650      1.1  haad }
    651      1.1  haad 
    652      1.1  haad /*
    653      1.1  haad  * assumes the device has been opened.
    654      1.1  haad  */
    655      1.1  haad static int __write_all_pvd(const struct format_type *fmt __attribute((unused)),
    656      1.1  haad 			   struct disk_list *data)
    657      1.1  haad {
    658      1.1  haad 	const char *pv_name = dev_name(data->dev);
    659      1.1  haad 
    660      1.1  haad 	if (!_write_pvd(data)) {
    661      1.1  haad 		log_error("Failed to write PV structure onto %s", pv_name);
    662      1.1  haad 		return 0;
    663      1.1  haad 	}
    664      1.1  haad 
    665      1.1  haad 	/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
    666      1.1  haad 	/*
    667      1.1  haad 	 * Stop here for orphan pv's.
    668      1.1  haad 	 */
    669      1.1  haad 	if (data->pvd.vg_name[0] == '\0') {
    670      1.1  haad 		/* if (!test_mode())
    671      1.1  haad 		   vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
    672      1.1  haad 		return 1;
    673      1.1  haad 	}
    674      1.1  haad 
    675      1.1  haad 	/* if (!test_mode())
    676      1.1  haad 	   vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
    677      1.1  haad 	   fmt); */
    678      1.1  haad 
    679      1.1  haad 	if (!_write_vgd(data)) {
    680      1.1  haad 		log_error("Failed to write VG data to %s", pv_name);
    681      1.1  haad 		return 0;
    682      1.1  haad 	}
    683      1.1  haad 
    684      1.1  haad 	if (!_write_uuids(data)) {
    685      1.1  haad 		log_error("Failed to write PV uuid list to %s", pv_name);
    686      1.1  haad 		return 0;
    687      1.1  haad 	}
    688      1.1  haad 
    689      1.1  haad 	if (!_write_lvs(data)) {
    690      1.1  haad 		log_error("Failed to write LV's to %s", pv_name);
    691      1.1  haad 		return 0;
    692      1.1  haad 	}
    693      1.1  haad 
    694      1.1  haad 	if (!_write_extents(data)) {
    695      1.1  haad 		log_error("Failed to write extents to %s", pv_name);
    696      1.1  haad 		return 0;
    697      1.1  haad 	}
    698      1.1  haad 
    699      1.1  haad 	return 1;
    700      1.1  haad }
    701      1.1  haad 
    702      1.1  haad /*
    703      1.1  haad  * opens the device and hands to the above fn.
    704      1.1  haad  */
    705      1.1  haad static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
    706      1.1  haad {
    707      1.1  haad 	int r;
    708      1.1  haad 
    709      1.1  haad 	if (!dev_open(data->dev))
    710      1.1  haad 		return_0;
    711      1.1  haad 
    712      1.1  haad 	r = __write_all_pvd(fmt, data);
    713      1.1  haad 
    714      1.1  haad 	if (!dev_close(data->dev))
    715      1.1  haad 		stack;
    716      1.1  haad 
    717      1.1  haad 	return r;
    718      1.1  haad }
    719      1.1  haad 
    720      1.1  haad /*
    721      1.1  haad  * Writes all the given pv's to disk.  Does very
    722      1.1  haad  * little sanity checking, so make sure correct
    723      1.1  haad  * data is passed to here.
    724      1.1  haad  */
    725      1.1  haad int write_disks(const struct format_type *fmt, struct dm_list *pvs)
    726      1.1  haad {
    727      1.1  haad 	struct disk_list *dl;
    728      1.1  haad 
    729      1.1  haad 	dm_list_iterate_items(dl, pvs) {
    730      1.1  haad 		if (!(_write_all_pvd(fmt, dl)))
    731      1.1  haad 			return_0;
    732      1.1  haad 
    733      1.1  haad 		log_very_verbose("Successfully wrote data to %s",
    734      1.1  haad 				 dev_name(dl->dev));
    735      1.1  haad 	}
    736      1.1  haad 
    737      1.1  haad 	return 1;
    738      1.1  haad }
    739