1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-10-28 20:25:52 +03:00
lvm2/lib/format1/disk-rep.c

464 lines
9.3 KiB
C
Raw Normal View History

2001-10-04 21:48:55 +04:00
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#include "disk-rep.h"
#include "pool.h"
2001-10-08 13:45:16 +04:00
#include "xlate.h"
#include "log.h"
2001-10-04 21:48:55 +04:00
#define fail do {stack; return 0;} while(0)
2001-10-04 21:48:55 +04:00
#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);
2001-10-08 13:45:16 +04:00
xx32(pv_uuidlist_on_disk.base); xx32(pv_uuidlist_on_disk.size);
2001-10-04 21:48:55 +04:00
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);
}
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);
}
2001-10-05 19:20:40 +04:00
static void _xlate_extents(struct pe_disk *extents, int count)
2001-10-04 21:48:55 +04:00
{
2001-10-05 19:20:40 +04:00
int i;
for (i = 0; i < count; i++) {
extents[i].lv_num = xlate16(extents[i].lv_num);
extents[i].le_num = xlate16(extents[i].le_num);
2001-10-04 21:48:55 +04:00
}
2001-10-05 19:20:40 +04:00
}
2001-10-04 21:48:55 +04:00
2001-10-10 13:36:29 +04:00
/*
* Handle both minor metadata formats.
*/
static int _munge_formats(struct pv_disk *pvd)
{
uint32_t pe_start;
switch (pvd->version) {
case 1:
pe_start = (pvd->pe_on_disk.base + pvd->pe_on_disk.size) /
SECTOR_SIZE;
break;
case 2:
pvd->version = 1;
pe_start = pvd->pe_start * SECTOR_SIZE;
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
break;
default:
return 0;
}
return 1;
}
2001-10-08 13:45:16 +04:00
static int _read_pv(struct disk_list *data)
2001-10-05 19:20:40 +04:00
{
struct pv_disk *pvd = &data->pv;
if (dev_read(data->dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd))
fail;
2001-10-05 19:20:40 +04:00
_xlate_pv(pvd);
2001-10-10 13:36:29 +04:00
2001-10-10 16:45:20 +04:00
return 1;
2001-10-04 21:48:55 +04:00
}
static int _read_lv(struct device *dev, ulong pos, struct lv_disk *disk)
{
if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
fail;
2001-10-04 21:48:55 +04:00
_xlate_lv(disk);
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1;
}
2001-10-05 19:20:40 +04:00
static int _read_vg(struct disk_list *data)
2001-10-04 21:48:55 +04:00
{
2001-10-05 19:20:40 +04:00
struct vg_disk *vgd = &data->vg;
unsigned long pos = data->pv.vg_on_disk.base;
if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
fail;
2001-10-05 19:20:40 +04:00
_xlate_vg(vgd);
2001-10-04 21:48:55 +04:00
return 1;
}
2001-10-05 19:20:40 +04:00
static int _read_uuids(struct disk_list *data)
2001-10-04 21:48:55 +04:00
{
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;
2001-10-08 20:08:16 +04:00
while(pos < end && num_read < data->vg.pv_cur) {
2001-10-05 19:20:40 +04:00
if (dev_read(data->dev, pos, sizeof(buffer), buffer) !=
sizeof(buffer))
fail;
2001-10-04 21:48:55 +04:00
if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
fail;
2001-10-04 21:48:55 +04:00
memcpy(ul->uuid, buffer, NAME_LEN);
ul->uuid[NAME_LEN] = '\0';
2001-10-08 13:45:16 +04:00
list_add(&ul->list, &data->uuids);
2001-10-04 21:48:55 +04:00
pos += NAME_LEN;
num_read++;
}
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1;
}
2001-10-05 19:20:40 +04:00
static int _read_lvs(struct disk_list *data)
2001-10-04 21:48:55 +04:00
{
int i;
unsigned long pos;
2001-10-08 13:45:16 +04:00
struct lvd_list *ll;
2001-10-04 21:48:55 +04:00
for(i = 0; i < data->vg.lv_cur; i++) {
2001-10-05 19:20:40 +04:00
pos = data->pv.lv_on_disk.base + (i * sizeof(struct lv_disk));
2001-10-08 13:45:16 +04:00
ll = pool_alloc(data->mem, sizeof(*ll));
2001-10-04 21:48:55 +04:00
if (!ll)
fail;
2001-10-04 21:48:55 +04:00
if (!_read_lv(data->dev, pos, &ll->lv))
fail;
2001-10-04 21:48:55 +04:00
list_add(&ll->list, &data->lvs);
}
return 1;
}
2001-10-05 19:20:40 +04:00
static int _read_extents(struct disk_list *data)
2001-10-04 21:48:55 +04:00
{
2001-10-08 13:45:16 +04:00
size_t len = sizeof(struct pe_disk) * data->pv.pe_total;
2001-10-04 21:48:55 +04:00
struct pe_disk *extents = pool_alloc(data->mem, len);
unsigned long pos = data->pv.pe_on_disk.base;
if (!extents)
fail;
if (dev_read(data->dev, pos, len, extents) != len)
fail;
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
_xlate_extents(extents, data->pv.pe_total);
2001-10-04 21:48:55 +04:00
data->extents = extents;
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1;
}
2001-10-05 19:20:40 +04:00
struct disk_list *read_pv(struct device *dev, struct pool *mem,
const char *vg_name)
2001-10-04 21:48:55 +04:00
{
2001-10-05 19:20:40 +04:00
struct disk_list *data = pool_alloc(mem, sizeof(*data));
data->dev = dev;
data->mem = mem;
2001-10-08 20:08:16 +04:00
INIT_LIST_HEAD(&data->uuids);
INIT_LIST_HEAD(&data->lvs);
2001-10-05 19:20:40 +04:00
2001-10-08 13:45:16 +04:00
if (!_read_pv(data)) {
2001-10-10 16:45:20 +04:00
log_debug("Failed to read PV data from %s", dev->name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
2001-10-08 20:08:16 +04:00
if (data->pv.id[0] != 'H' || data->pv.id[1] != 'M') {
2001-10-10 20:36:32 +04:00
log_very_verbose("%s does not have a valid PV identifier",
2001-10-04 21:48:55 +04:00
dev->name);
2001-10-05 19:20:40 +04:00
goto bad;
}
2001-10-10 17:03:10 +04:00
if (!_munge_formats(&data->pv)) {
2001-10-10 20:36:32 +04:00
log_very_verbose("Unknown metadata version %d found on %s",
2001-10-10 17:03:10 +04:00
data->pv.version, dev->name);
2001-10-10 16:45:20 +04:00
goto bad;
}
2001-10-10 16:28:10 +04:00
/*
* is it an orphan ?
*/
2001-10-10 16:45:20 +04:00
if (data->pv.vg_name == '\0') {
2001-10-10 20:36:32 +04:00
log_very_verbose("%s is not a member of any VG", dev->name);
2001-10-10 16:42:03 +04:00
return data;
2001-10-10 16:45:20 +04:00
}
2001-10-10 16:28:10 +04:00
2001-10-05 19:20:40 +04:00
if (vg_name && strcmp(vg_name, data->pv.vg_name)) {
2001-10-10 16:45:20 +04:00
log_very_verbose("%s is not a member of the VG %s",
2001-10-08 13:45:16 +04:00
dev->name, vg_name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
2001-10-08 13:45:16 +04:00
if (!_read_vg(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to read VG data from PV (%s)", dev->name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
2001-10-05 19:20:40 +04:00
if (!_read_uuids(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to read PV uuid list from %s", dev->name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
2001-10-05 19:20:40 +04:00
if (!_read_lvs(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to read LV's from %s", dev->name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
2001-10-05 19:20:40 +04:00
if (!_read_extents(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to read extents from %s", dev->name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
2001-10-05 19:20:40 +04:00
return data;
bad:
2001-10-08 13:45:16 +04:00
pool_free(data->mem, data);
2001-10-05 19:20:40 +04:00
return NULL;
2001-10-04 21:48:55 +04:00
}
/*
* 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.
*/
2001-10-08 13:45:16 +04:00
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
2001-10-04 21:48:55 +04:00
struct pool *mem, struct list_head *head)
{
2001-10-08 13:45:16 +04:00
struct dev_iter *iter = dev_iter_create(filter);
2001-10-04 21:48:55 +04:00
struct device *dev;
struct disk_list *data = NULL;
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
2001-10-08 13:45:16 +04:00
if ((data = read_pv(dev, mem, vg_name)))
2001-10-05 19:20:40 +04:00
list_add(&data->list, head);
}
2001-10-08 13:45:16 +04:00
dev_iter_destroy(iter);
2001-10-05 19:20:40 +04:00
return 1;
}
static int _write_vg(struct disk_list *data)
{
struct vg_disk *vgd = &data->vg;
unsigned long pos = data->pv.vg_on_disk.base;
_xlate_vg(vgd);
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
fail;
2001-10-05 19:20:40 +04:00
_xlate_vg(vgd);
return 1;
}
static int _write_uuids(struct disk_list *data)
{
struct uuid_list *ul;
struct list_head *tmp;
ulong pos = data->pv.pv_uuidlist_on_disk.base;
ulong end = pos + data->pv.pv_uuidlist_on_disk.size;
list_for_each(tmp, &data->uuids) {
if (pos >= end) {
2001-10-10 16:45:20 +04:00
log_error("Too many uuids to fit on %s",
2001-10-05 19:20:40 +04:00
data->dev->name);
return 0;
}
ul = list_entry(tmp, struct uuid_list, list);
2001-10-10 17:24:16 +04:00
if (dev_write(data->dev, pos, NAME_LEN, ul->uuid) != NAME_LEN)
fail;
2001-10-05 19:20:40 +04:00
pos += NAME_LEN;
}
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
return 1;
}
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
static int _write_lv(struct device *dev, ulong pos, struct lv_disk *disk)
{
_xlate_lv(disk);
if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
fail;
2001-10-05 19:20:40 +04:00
_xlate_lv(disk);
2001-10-04 21:48:55 +04:00
return 1;
2001-10-05 19:20:40 +04:00
}
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
static int _write_lvs(struct disk_list *data)
{
struct list_head *tmp;
2001-10-08 13:45:16 +04:00
unsigned long pos;
2001-10-05 19:20:40 +04:00
list_for_each(tmp, &data->lvs) {
2001-10-08 13:45:16 +04:00
struct lvd_list *ll = list_entry(tmp, struct lvd_list, list);
pos = data->pv.lv_on_disk.base;
2001-10-05 19:20:40 +04:00
if (!_write_lv(data->dev, pos, &ll->lv))
fail;
2001-10-05 19:20:40 +04:00
pos += sizeof(struct lv_disk);
}
return 1;
}
static int _write_extents(struct disk_list *data)
{
size_t len = sizeof(struct pe_disk) * data->pv.pe_total;
struct pe_disk *extents = data->extents;
_xlate_extents(extents, data->pv.pe_total);
if (dev_write(data->dev, 0, len, extents) != len)
fail;
2001-10-05 19:20:40 +04:00
_xlate_extents(extents, data->pv.pe_total);
return 1;
}
static int _write_pv(struct disk_list *data)
{
struct pv_disk *disk = &data->pv;
_xlate_pv(disk);
2001-10-10 16:45:20 +04:00
if (dev_write(data->dev, 0, sizeof(*disk), disk) != sizeof(*disk))
fail;
2001-10-05 19:20:40 +04:00
_xlate_pv(disk);
return 1;
}
static int _write_all_pv(struct disk_list *data)
{
const char *pv_name = data->dev->name;
if (!_write_pv(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to write PV structure onto %s", pv_name);
2001-10-05 19:20:40 +04:00
return 0;
}
2001-10-10 14:05:29 +04:00
/*
* Stop here for orphan pv's.
*/
if (data->pv.vg_name[0] == '\0')
return 1;
2001-10-05 19:20:40 +04:00
if (!_write_vg(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to write VG data to %s", pv_name);
2001-10-05 19:20:40 +04:00
return 0;
}
if (!_write_uuids(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to write PV uuid list to %s", pv_name);
2001-10-05 19:20:40 +04:00
return 0;
}
if (!_write_lvs(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to write LV's to %s", pv_name);
2001-10-05 19:20:40 +04:00
return 0;
}
if (!_write_extents(data)) {
2001-10-10 16:45:20 +04:00
log_error("Failed to write extents to %s", pv_name);
2001-10-05 19:20:40 +04:00
return 0;
}
return 1;
}
/*
* Writes all the given pv's to disk. Does very
* little sanity checking, so make sure correct
* data is passed to here.
*/
2001-10-05 19:20:40 +04:00
int write_pvs(struct list_head *pvs)
{
struct list_head *tmp;
struct disk_list *dl;
list_for_each(tmp, pvs) {
dl = list_entry(tmp, struct disk_list, list);
if (!(_write_all_pv(dl)))
fail;
2001-10-10 16:45:20 +04:00
log_debug("Successfully wrote data to %s", dl->dev->name);
2001-10-05 19:20:40 +04:00
}
return 1;
2001-10-04 21:48:55 +04:00
}