mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
160 lines
3.5 KiB
C
160 lines
3.5 KiB
C
/*
|
|
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
|
*
|
|
* This file is released under the LGPL.
|
|
*/
|
|
|
|
#include "lib.h"
|
|
#include "disk-rep.h"
|
|
|
|
/*
|
|
* Only works with powers of 2.
|
|
*/
|
|
static inline ulong _round_up(ulong n, ulong size)
|
|
{
|
|
size--;
|
|
return (n + size) & ~size;
|
|
}
|
|
|
|
static inline ulong _div_up(ulong n, ulong size)
|
|
{
|
|
return _round_up(n, size) / size;
|
|
}
|
|
|
|
/*
|
|
* Each chunk of metadata should be aligned to
|
|
* METADATA_ALIGN.
|
|
*/
|
|
static uint32_t _next_base(struct data_area *area)
|
|
{
|
|
return _round_up(area->base + area->size, METADATA_ALIGN);
|
|
}
|
|
|
|
/*
|
|
* Quick calculation based on pe_start.
|
|
*/
|
|
static int _adjust_pe_on_disk(struct pv_disk *pvd)
|
|
{
|
|
uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
|
|
|
|
if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
|
|
return 0;
|
|
|
|
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
|
|
return 1;
|
|
}
|
|
|
|
static void _calc_simple_layout(struct pv_disk *pvd)
|
|
{
|
|
pvd->pv_on_disk.base = METADATA_BASE;
|
|
pvd->pv_on_disk.size = PV_SIZE;
|
|
|
|
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
|
|
pvd->vg_on_disk.size = VG_SIZE;
|
|
|
|
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
|
|
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
|
|
|
|
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
|
|
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
|
|
|
|
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
|
|
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
|
|
}
|
|
|
|
int _check_vg_limits(struct disk_list *dl)
|
|
{
|
|
if (dl->vgd.lv_max > MAX_LV) {
|
|
log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
|
|
"for VG '%s'", dl->vgd.lv_max, MAX_LV - 1,
|
|
dl->pvd.vg_name);
|
|
return 0;
|
|
}
|
|
|
|
if (dl->vgd.pv_max > MAX_PV) {
|
|
log_error("MaxPhysicalVolumes of %d exceeds format limit of %d "
|
|
"for VG '%s'", dl->vgd.pv_max, MAX_PV - 1,
|
|
dl->pvd.vg_name);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* This assumes pe_count and pe_start have already
|
|
* been calculated correctly.
|
|
*/
|
|
int calculate_layout(struct disk_list *dl)
|
|
{
|
|
struct pv_disk *pvd = &dl->pvd;
|
|
|
|
_calc_simple_layout(pvd);
|
|
if (!_adjust_pe_on_disk(pvd)) {
|
|
log_error("Insufficient space for metadata and PE's.");
|
|
return 0;
|
|
}
|
|
|
|
if (!_check_vg_limits(dl))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* The number of extents that can fit on a disk is metadata format dependant.
|
|
*/
|
|
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
|
|
uint32_t max_extent_count)
|
|
{
|
|
struct pv_disk *pvd = dbg_malloc(sizeof(*pvd));
|
|
uint32_t end;
|
|
|
|
if (!pvd) {
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Guess how many extents will fit, bearing in mind that
|
|
* one is going to be knocked off at the start of the
|
|
* next loop.
|
|
*/
|
|
if (max_extent_count)
|
|
pvd->pe_total = max_extent_count + 1;
|
|
else
|
|
pvd->pe_total = (pv->size / extent_size);
|
|
|
|
if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
|
|
log_error("Too few extents on %s. Try smaller extent size.",
|
|
dev_name(pv->dev));
|
|
dbg_free(pvd);
|
|
return 0;
|
|
}
|
|
|
|
do {
|
|
pvd->pe_total--;
|
|
_calc_simple_layout(pvd);
|
|
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
|
|
SECTOR_SIZE - 1) >> SECTOR_SHIFT);
|
|
|
|
pvd->pe_start = _round_up(end, PE_ALIGN);
|
|
|
|
} while ((pvd->pe_start + (pvd->pe_total * extent_size))
|
|
> pv->size);
|
|
|
|
if (pvd->pe_total > MAX_PE_TOTAL) {
|
|
log_error("Metadata extent limit (%u) exceeded for %s - "
|
|
"%u required", MAX_PE_TOTAL, dev_name(pv->dev),
|
|
pvd->pe_total);
|
|
dbg_free(pvd);
|
|
return 0;
|
|
}
|
|
|
|
pv->pe_count = pvd->pe_total;
|
|
pv->pe_start = pvd->pe_start;
|
|
/* We can't set pe_size here without breaking LVM1 compatibility */
|
|
dbg_free(pvd);
|
|
return 1;
|
|
}
|