Home | History | Annotate | Line # | Download | only in format1
      1 /*	$NetBSD: layout.c,v 1.1.1.1 2008/12/22 00:18:00 haad Exp $	*/
      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 #include "lib.h"
     19 #include "disk-rep.h"
     20 
     21 /*
     22  * Only works with powers of 2.
     23  */
     24 static uint32_t _round_up(uint32_t n, uint32_t size)
     25 {
     26 	size--;
     27 	return (n + size) & ~size;
     28 }
     29 
     30 /* Unused.
     31 static uint32_t _div_up(uint32_t n, uint32_t size)
     32 {
     33 	return _round_up(n, size) / size;
     34 }
     35 */
     36 
     37 /*
     38  * Each chunk of metadata should be aligned to
     39  * METADATA_ALIGN.
     40  */
     41 static uint32_t _next_base(struct data_area *area)
     42 {
     43 	return _round_up(area->base + area->size, METADATA_ALIGN);
     44 }
     45 
     46 /*
     47  * Quick calculation based on pe_start.
     48  */
     49 static int _adjust_pe_on_disk(struct pv_disk *pvd)
     50 {
     51 	uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
     52 
     53 	if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
     54 		return 0;
     55 
     56 	pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
     57 	return 1;
     58 }
     59 
     60 static void _calc_simple_layout(struct pv_disk *pvd)
     61 {
     62 	pvd->pv_on_disk.base = METADATA_BASE;
     63 	pvd->pv_on_disk.size = PV_SIZE;
     64 
     65 	pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
     66 	pvd->vg_on_disk.size = VG_SIZE;
     67 
     68 	pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
     69 	pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
     70 
     71 	pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
     72 	pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
     73 
     74 	pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
     75 	pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
     76 }
     77 
     78 static int _check_vg_limits(struct disk_list *dl)
     79 {
     80 	if (dl->vgd.lv_max > MAX_LV) {
     81 		log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
     82 			  "for VG '%s'", dl->vgd.lv_max, MAX_LV - 1,
     83 			  dl->pvd.vg_name);
     84 		return 0;
     85 	}
     86 
     87 	if (dl->vgd.pv_max > MAX_PV) {
     88 		log_error("MaxPhysicalVolumes of %d exceeds format limit of %d "
     89 			  "for VG '%s'", dl->vgd.pv_max, MAX_PV - 1,
     90 			  dl->pvd.vg_name);
     91 		return 0;
     92 	}
     93 
     94 	return 1;
     95 }
     96 
     97 /*
     98  * This assumes pe_count and pe_start have already
     99  * been calculated correctly.
    100  */
    101 int calculate_layout(struct disk_list *dl)
    102 {
    103 	struct pv_disk *pvd = &dl->pvd;
    104 
    105 	_calc_simple_layout(pvd);
    106 	if (!_adjust_pe_on_disk(pvd)) {
    107 		log_error("Insufficient space for metadata and PE's.");
    108 		return 0;
    109 	}
    110 
    111 	if (!_check_vg_limits(dl))
    112 		return 0;
    113 
    114 	return 1;
    115 }
    116 
    117 /*
    118  * The number of extents that can fit on a disk is metadata format dependant.
    119  * pe_start is any existing value for pe_start
    120  */
    121 int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
    122 			   uint32_t max_extent_count, uint64_t pe_start)
    123 {
    124 	struct pv_disk *pvd = dm_malloc(sizeof(*pvd));
    125 	uint32_t end;
    126 
    127 	if (!pvd)
    128 		return_0;
    129 
    130 	/*
    131 	 * Guess how many extents will fit, bearing in mind that
    132 	 * one is going to be knocked off at the start of the
    133 	 * next loop.
    134 	 */
    135 	if (max_extent_count)
    136 		pvd->pe_total = max_extent_count + 1;
    137 	else
    138 		pvd->pe_total = (pv->size / extent_size);
    139 
    140 	if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
    141 		log_error("Too few extents on %s.  Try smaller extent size.",
    142 			  pv_dev_name(pv));
    143 		dm_free(pvd);
    144 		return 0;
    145 	}
    146 
    147 	do {
    148 		pvd->pe_total--;
    149 		_calc_simple_layout(pvd);
    150 		end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
    151 			SECTOR_SIZE - 1) >> SECTOR_SHIFT);
    152 
    153 		if (pe_start && end < pe_start)
    154 			end = pe_start;
    155 
    156 		pvd->pe_start = _round_up(end, LVM1_PE_ALIGN);
    157 
    158 	} while ((pvd->pe_start + (pvd->pe_total * extent_size))
    159 		 > pv->size);
    160 
    161 	if (pvd->pe_total > MAX_PE_TOTAL) {
    162 		log_error("Metadata extent limit (%u) exceeded for %s - "
    163 			  "%u required", MAX_PE_TOTAL, pv_dev_name(pv),
    164 			  pvd->pe_total);
    165 		dm_free(pvd);
    166 		return 0;
    167 	}
    168 
    169 	pv->pe_count = pvd->pe_total;
    170 	pv->pe_start = pvd->pe_start;
    171 	/* We can't set pe_size here without breaking LVM1 compatibility */
    172 	dm_free(pvd);
    173 	return 1;
    174 }
    175