mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
278 lines
6.0 KiB
C
278 lines
6.0 KiB
C
/*
|
|
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
|
*
|
|
* This file is released under the GPL.
|
|
*
|
|
*/
|
|
|
|
#include "disk-rep.h"
|
|
#include "pool.h"
|
|
|
|
#define xx16(v) disk->v = xlate16(disk->v)
|
|
#define xx32(v) disk->v = xlate32(disk->v)
|
|
#define xx64(v) disk->v = xlate64(disk->v)
|
|
|
|
/*
|
|
* Functions to perform the endian conversion
|
|
* between disk and core. The same code works
|
|
* both ways of course.
|
|
*/
|
|
static void _xlate_pv(struct pv_disk *disk)
|
|
{
|
|
xx16(version);
|
|
|
|
xx32(pv_on_disk.base); xx32(pv_on_disk.size);
|
|
xx32(vg_on_disk.base); xx32(vg_on_disk.size);
|
|
xx32(pv_uuid_on_disk.base); xx32(pv_uuid_on_disk.size);
|
|
xx32(lv_on_disk.base); xx32(lv_on_disk.size);
|
|
xx32(pe_on_disk.base); xx32(pe_on_disk.size);
|
|
|
|
xx32(pv_major);
|
|
xx32(pv_number);
|
|
xx32(pv_status);
|
|
xx32(pv_allocatable);
|
|
xx32(pv_size);
|
|
xx32(lv_cur);
|
|
xx32(pe_size);
|
|
xx32(pe_total);
|
|
xx32(pe_allocated);
|
|
xx32(pe_start);
|
|
|
|
/* FIXME: put v1, v2 munging in here. */
|
|
}
|
|
|
|
static void _xlate_lv(struct lv_disk *disk)
|
|
{
|
|
xx32(lv_access);
|
|
xx32(lv_status);
|
|
xx32(lv_open);
|
|
xx32(lv_dev);
|
|
xx32(lv_number);
|
|
xx32(lv_mirror_copies);
|
|
xx32(lv_recovery);
|
|
xx32(lv_schedule);
|
|
xx32(lv_size);
|
|
xx32(lv_snapshot_minor);
|
|
xx16(lv_chunk_size);
|
|
xx16(dummy);
|
|
xx32(lv_allocated_le);
|
|
xx32(lv_stripes);
|
|
xx32(lv_stripesize);
|
|
xx32(lv_badblock);
|
|
xx32(lv_allocation);
|
|
xx32(lv_io_timeout);
|
|
xx32(lv_read_ahead);
|
|
}
|
|
|
|
static void _xlate_vg(struct vg_disk *disk)
|
|
{
|
|
xx32(vg_number);
|
|
xx32(vg_access);
|
|
xx32(vg_status);
|
|
xx32(lv_max);
|
|
xx32(lv_cur);
|
|
xx32(lv_open);
|
|
xx32(pv_max);
|
|
xx32(pv_cur);
|
|
xx32(pv_act);
|
|
xx32(dummy);
|
|
xx32(vgda);
|
|
xx32(pe_size);
|
|
xx32(pe_total);
|
|
xx32(pe_allocated);
|
|
xx32(pvg_total);
|
|
}
|
|
|
|
static int _read_pv(struct device *dev, struct pv_disk *disk)
|
|
{
|
|
if (dev_read(dev, 0, sizeof(*disk), disk) != sizeof(&disk)) {
|
|
log_error("failed to read pv from disk (%s)", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
_xlate_pv(disk);
|
|
memset(disk->pv_name, 0, sizeof (disk->pv_name));
|
|
strncpy(disk->pv_name, dev->name, sizeof(disk->pv_name) - 1);
|
|
|
|
disk->pv_dev = dev->dev;
|
|
return 1;
|
|
}
|
|
|
|
static int _read_lv(struct device *dev, ulong pos, struct lv_disk *disk)
|
|
{
|
|
if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk)) {
|
|
log_error("failed to read lv from disk (%s)", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
_xlate_lv(disk);
|
|
return 1;
|
|
}
|
|
|
|
static int _read_vg(struct device *dev, ulong pos, struct vg_disk *disk)
|
|
{
|
|
if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk)) {
|
|
log_error("failed to read vg from disk (%s)", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
_xlate_vg(disk);
|
|
return 1;
|
|
}
|
|
|
|
static int _read_uuids(struct device *dev, struct disk_list *data)
|
|
{
|
|
int num_read = 0;
|
|
struct uuid_list *ul;
|
|
char buffer[NAME_LEN];
|
|
ulong pos = data->pv.pv_uuidlist_on_disk.base;
|
|
ulong end = pos + data->pv.pv_uuidlist_on_disk.size;
|
|
|
|
while(pos < end && num_read < ABS_MAX_PV) {
|
|
if (dev_read(dev, pos, sizeof(buffer), buffer) !=
|
|
sizeof(buffer)) {
|
|
log_err("failed to read a pv_uuid from %s\n",
|
|
dev->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!(ul = pool_alloc(data->mem, sizeof(*ul)))) {
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
memcpy(ul->uuid, buffer, NAME_LEN);
|
|
ul->uuid[NAME_LEN] = '\0';
|
|
|
|
list_add(&ui->list, &data->uuids);
|
|
|
|
pos += NAME_LEN;
|
|
num_read++;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int _read_lvs(struct device *dev, struct disk_list *data)
|
|
{
|
|
int i;
|
|
unsigned long pos;
|
|
|
|
for(i = 0; i < data->vg.lv_cur; i++) {
|
|
pos = data->pv.lv_on_disk.base + (i * sizeof(struct lv_list));
|
|
struct lv_list *ll = pool_alloc(sizeof(*ll));
|
|
|
|
if (!ll) {
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
if (!_read_lv(dev, pos, &ll->lv)) {
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
list_add(&ll->list, &data->lvs);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int _read_extents(struct device *dev, struct disk_list *data)
|
|
{
|
|
size_t len = sizeof(struct pe_disk) * data->pv->pe_total;
|
|
struct pe_disk *extents = pool_alloc(data->mem, len);
|
|
unsigned long pos = data->pv.pe_on_disk.base;
|
|
|
|
if (!extents) {
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
if (dev_read(dev, pos, len, extents) != len) {
|
|
log_error("failed to read extents from disk (%s)", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < data->pv->pe_total; i++) {
|
|
extents[i].lv_num = xlate16(extents[i].lv_num);
|
|
extents[i].le_num = xlate16(extents[i].le_num);
|
|
}
|
|
|
|
data->extents = extents;
|
|
return 1;
|
|
}
|
|
|
|
static int _read_all_pv_data(struct device *dev, struct disk_list *data)
|
|
{
|
|
if (!_read_pv(dev, &data->pv)) {
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(data->pv.id, "HM")) {
|
|
log_info("%s does not have a valid PV identifier.\n",
|
|
dev->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!_read_vg(dev, data->pv.pv_vg_on_disk.base, &data->vg)) {
|
|
log_err("failed to read vg data from pv (%s)\n", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!_read_uuids(dev, data)) {
|
|
log_err("failed to read pv uuid list from %s\n", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!_read_lvs(dev, data)) {
|
|
log_err("failed to read lv's from %s\n", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!_read_extents(dev, data)) {
|
|
log_err("failed to read extents from %s\n", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Build a list of pv_d's structures, allocated
|
|
* from mem. We keep track of the first object
|
|
* allocated form the pool so we can free off all
|
|
* the memory if something goes wrong.
|
|
*/
|
|
int read_pvs_in_vg(struct v1 *v, const char *vg_name,
|
|
struct pool *mem, struct list_head *head)
|
|
{
|
|
struct dev_cache_iter *iter = dev_iter_create(v->filter);
|
|
struct device *dev;
|
|
struct disk_list *data = NULL;
|
|
|
|
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
|
struct disk_list *data = pool_alloc(mem, sizeof(*data));
|
|
|
|
if (!data) {
|
|
stack;
|
|
goto bad;
|
|
}
|
|
|
|
if (!first)
|
|
first = data;
|
|
|
|
if (_read_all_pv_data(dev, pvd) &&
|
|
!strcmp(pvd->pv.vg_name, vg_name))
|
|
list_add(&pvd->list, head);
|
|
else
|
|
pool_free(mem, pvd);
|
|
}
|
|
return 1;
|
|
|
|
bad:
|
|
if (first)
|
|
pool_free(mem, first);
|
|
return 0;
|
|
}
|