mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o vg_read for format1
This commit is contained in:
parent
7eee377db5
commit
3840b20ac9
277
lib/format1/disk-rep.c
Normal file
277
lib/format1/disk-rep.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
112
lib/format1/disk-rep.h
Normal file
112
lib/format1/disk-rep.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DISK_REP_FORMAT1_H
|
||||
#define DISK_REP_FORMAT1_H
|
||||
|
||||
struct data_area {
|
||||
uint32_t base;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct pv_disk {
|
||||
uint8_t id[2];
|
||||
uint16_t version; /* lvm version */
|
||||
struct data_area pv_on_disk;
|
||||
struct data_area vg_on_disk;
|
||||
struct data_area pv_uuidlist_on_disk;
|
||||
struct data_area lv_on_disk;
|
||||
struct data_area pe_on_disk;
|
||||
uint8_t pv_uuid[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
||||
uint32_t pv_major;
|
||||
uint32_t pv_number;
|
||||
uint32_t pv_status;
|
||||
uint32_t pv_allocatable;
|
||||
uint32_t pv_size;
|
||||
uint32_t lv_cur;
|
||||
uint32_t pe_size;
|
||||
uint32_t pe_total;
|
||||
uint32_t pe_allocated;
|
||||
|
||||
/* only present on version == 2 pv's */
|
||||
uint32_t pe_start;
|
||||
};
|
||||
|
||||
struct lv_disk {
|
||||
uint8_t lv_name[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint32_t lv_access;
|
||||
uint32_t lv_status;
|
||||
uint32_t lv_open;
|
||||
uint32_t lv_dev;
|
||||
uint32_t lv_number;
|
||||
uint32_t lv_mirror_copies; /* for future use */
|
||||
uint32_t lv_recovery; /* " */
|
||||
uint32_t lv_schedule; /* " */
|
||||
uint32_t lv_size;
|
||||
uint32_t lv_snapshot_minor; /* minor number of original */
|
||||
uint16_t lv_chunk_size; /* chunk size of snapshot */
|
||||
uint16_t dummy;
|
||||
uint32_t lv_allocated_le;
|
||||
uint32_t lv_stripes;
|
||||
uint32_t lv_stripesize;
|
||||
uint32_t lv_badblock; /* for future use */
|
||||
uint32_t lv_allocation;
|
||||
uint32_t lv_io_timeout; /* for future use */
|
||||
uint32_t lv_read_ahead;
|
||||
};
|
||||
|
||||
struct vg_disk {
|
||||
uint8_t vg_uuid[UUID_LEN]; /* volume group UUID */
|
||||
uint8_t vg_name_dummy[NAME_LEN-UUID_LEN]; /* rest of v1 VG name */
|
||||
uint32_t vg_number; /* volume group number */
|
||||
uint32_t vg_access; /* read/write */
|
||||
uint32_t vg_status; /* active or not */
|
||||
uint32_t lv_max; /* maximum logical volumes */
|
||||
uint32_t lv_cur; /* current logical volumes */
|
||||
uint32_t lv_open; /* open logical volumes */
|
||||
uint32_t pv_max; /* maximum physical volumes */
|
||||
uint32_t pv_cur; /* current physical volumes FU */
|
||||
uint32_t pv_act; /* active physical volumes */
|
||||
uint32_t dummy;
|
||||
uint32_t vgda; /* volume group descriptor arrays FU */
|
||||
uint32_t pe_size; /* physical extent size in sectors */
|
||||
uint32_t pe_total; /* total of physical extents */
|
||||
uint32_t pe_allocated; /* allocated physical extents */
|
||||
uint32_t pvg_total; /* physical volume groups FU */
|
||||
};
|
||||
|
||||
struct pe_disk {
|
||||
uint16_t lv_num;
|
||||
uint16_t le_num;
|
||||
};
|
||||
|
||||
|
||||
struct uuid_list {
|
||||
struct list_head list;
|
||||
char uuid[NAME_LEN + 1];
|
||||
};
|
||||
|
||||
struct lv_list {
|
||||
struct list_head list;
|
||||
struct lv_disk lv;
|
||||
|
||||
struct disk_list {
|
||||
struct list_head list;
|
||||
struct pv_disk pv;
|
||||
struct vg_disk vg;
|
||||
struct list_head uuids;
|
||||
struct list_head lvs;
|
||||
struct pe_disk *extents;
|
||||
};
|
||||
|
||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
struct pool *mem, struct list_head *results);
|
||||
|
||||
#endif
|
253
lib/format1/format1.c
Normal file
253
lib/format1/format1.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "disk-rep.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "pool.h"
|
||||
#include "hash.h"
|
||||
#include "list.h"
|
||||
|
||||
|
||||
struct v1 {
|
||||
struct pool *mem;
|
||||
struct dev_filter *filter;
|
||||
};
|
||||
|
||||
static int _import_vg(struct volume_group *vg, struct list_head *pvs)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct disk_list *dl;
|
||||
struct vg_disk *first = NULL;
|
||||
|
||||
/* check all the vg's are the same */
|
||||
list_for_each(tmp, pvs) {
|
||||
dl = list_entry(tmp, struct disk_list, list);
|
||||
|
||||
if (!first) {
|
||||
first = &dl->vg;
|
||||
|
||||
memcpy(vg->id, &first->vg_uuid, ID_LEN);
|
||||
vg->name = NULL;
|
||||
vg->status = first->vg_status;
|
||||
vg->access = first->vg_access;
|
||||
vg->extent_size = first->pe_size;
|
||||
vg->extent_count = first->pe_total;
|
||||
vg->free_count = first->pe_total - first->pe_allocated;
|
||||
vg->max_lv = first->lv_max;
|
||||
vg->max_pv = first->pv_max;
|
||||
|
||||
} else if (memcmp(first, &dl->vg, sizeof(*first))) {
|
||||
log_err("vg data differs on pvs\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _import_pvs(struct pool *mem, struct volume_group *vg,
|
||||
struct list_head *pvs)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct disk_list *dl;
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
|
||||
vg->pv_count = 0;
|
||||
list_for_each(tmp, pvs) {
|
||||
dl = list_entry(tmp, struct disk_list, list);
|
||||
pvl = pool_alloc(mem, sizeof(*pvl));
|
||||
|
||||
if (!pvl) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv = &pvl->pv;
|
||||
memcpy(&pv->id, &dl->pv.pv_uuid, ID_LEN);
|
||||
pv->dev = ??;
|
||||
pv->vg_name = pool_strdup(dl->pv.vg_name);
|
||||
|
||||
if (!pv->vg_name) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv->exported = ??;
|
||||
pv->status = dl->pv.pv_status;
|
||||
pv->size = dl->pv.pv_size;
|
||||
pv->pe_size = dl->pv.pv_size;
|
||||
pe_start = dl->pv.pe_start;
|
||||
pe_count = dl->pv.pe_count;
|
||||
pe_allocated = dl->pv.pe_allocated;
|
||||
|
||||
list_add(&pvl->list, vg->pvs);
|
||||
vg->pv_count++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct logical_volume *_find_lv(struct volume_group *vg,
|
||||
const char *name)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct logical_volume *lv;
|
||||
|
||||
list_for_each(tmp, &vg->lvs) {
|
||||
lv = list_entry(tmp, struct logical_volume, list);
|
||||
if (!strcmp(name, lv->name))
|
||||
return lv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct logical_volume *_add_lv(struct volume_group *vg,
|
||||
struct lv_disk *lvd)
|
||||
{
|
||||
struct logical_volume *lv = pool_alloc(mem, sizeof(*lv));
|
||||
|
||||
if (!lv) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(lv->id, 0, sizeof(lv->id));
|
||||
if (!(lv->name = pool_dupstr(lvd->lv_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->access = lvd->lv_access;
|
||||
lv->status = lvd->lv_status;
|
||||
lv->open = lvd->lv_open;
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_lv;
|
||||
lv->map = pool_alloc(mem, sizeof(struct pe_specifier) * lv->le_count);
|
||||
|
||||
if (!lv->map) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _import_lvs(struct pool *mem, struct volume_group *vg,
|
||||
struct list_head *pvs)
|
||||
{
|
||||
struct list_head *tmp, tmp2;
|
||||
struct disk_list *dl;
|
||||
struct lv_disk *lvd;
|
||||
struct logical_volume *lv;
|
||||
int i;
|
||||
|
||||
list_for_each(tmp, pvs) {
|
||||
dl = list_entry(tmp, struct disk_list, list);
|
||||
list_for_each(tmp2, &dl->lvs) {
|
||||
lvd = list_entry(tmp2, struct lv_disk, list);
|
||||
if (!_find_lv(vg, lvd->lvname) && !_add_lv(vg, lvd)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _import_extents(struct pool *mem, struct volume_group *vg,
|
||||
struct list_head *pvs)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct disk_list *dl;
|
||||
struct logical_volume *lv;
|
||||
struct physical_volume *pv;
|
||||
struct pe_disk *e;
|
||||
int i, le;
|
||||
|
||||
list_for_each(tmp, pvs) {
|
||||
dl = list_entry(tmp, struct disk_list, list);
|
||||
pv = _find_pv(vg, dl->pv.pv_name);
|
||||
e = dl->extents;
|
||||
|
||||
for (i = 0; i < dl->pv.pe_total; i++) {
|
||||
if (e[i].lv_num) {
|
||||
if (!(lv = _find_lv_num(vg, e[i].lv_num))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
le = e[i].le_num;
|
||||
lv->map[le].pv = pv;
|
||||
lv->map[le].pe = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group _build_vg(struct pool *mem, struct list_head *pvs)
|
||||
{
|
||||
struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
|
||||
|
||||
if (!vg) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
if (!_import_vg(vg, pvs))
|
||||
goto bad;
|
||||
|
||||
if (!_import_pvs(mem, vg, pvs))
|
||||
goto bad;
|
||||
|
||||
if (!_import_lvs(mem, vg, pvs))
|
||||
goto bad;
|
||||
|
||||
return vg;
|
||||
|
||||
bad:
|
||||
stack;
|
||||
pool_free(mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct volume_group _vg_read(struct io_space *is, const char *vg_name)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list_head pvs;
|
||||
struct volume_group *vg;
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!read_pvs_in_vg(vg_name, is->filter, mem, &pvs)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vg = _build_vg(is->mem, &pvs))) {
|
||||
stack;
|
||||
}
|
||||
|
||||
pool_destroy(mem);
|
||||
return vg;
|
||||
}
|
||||
|
||||
|
||||
struct io_space *create_lvm1_format(struct device_manager *mgr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user