1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/lib/format1/disk-rep.c

763 lines
17 KiB
C
Raw Normal View History

2001-10-04 21:48:55 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
2001-10-04 21:48:55 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
2004-03-30 23:35:44 +04:00
*
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2001-10-04 21:48:55 +04:00
*/
2002-11-18 17:01:16 +03:00
#include "lib.h"
2001-10-04 21:48:55 +04:00
#include "disk-rep.h"
2001-10-08 13:45:16 +04:00
#include "xlate.h"
#include "lvmcache.h"
#include "metadata-exported.h"
2001-10-04 21:48:55 +04:00
#include <fcntl.h>
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_pvd(struct pv_disk *disk)
2001-10-04 21:48:55 +04:00
{
xx16(version);
xx32(pv_on_disk.base);
xx32(pv_on_disk.size);
xx32(vg_on_disk.base);
xx32(vg_on_disk.size);
xx32(pv_uuidlist_on_disk.base);
xx32(pv_uuidlist_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);
2001-10-04 21:48:55 +04:00
xx32(pe_start);
}
static void _xlate_lvd(struct lv_disk *disk)
2001-10-04 21:48:55 +04:00
{
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);
2001-10-04 21:48:55 +04:00
}
static void _xlate_vgd(struct vg_disk *disk)
2001-10-04 21:48:55 +04:00
{
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-04 21:48:55 +04:00
}
static void _xlate_extents(struct pe_disk *extents, uint32_t count)
2001-10-04 21:48:55 +04:00
{
unsigned i;
2001-10-05 19:20:40 +04:00
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;
unsigned b, e;
2001-10-10 13:36:29 +04:00
switch (pvd->version) {
case 1:
pvd->pe_start = ((pvd->pe_on_disk.base +
2002-11-18 17:01:16 +03:00
pvd->pe_on_disk.size) >> SECTOR_SHIFT);
2001-10-10 13:36:29 +04:00
break;
case 2:
pvd->version = 1;
2002-11-18 17:01:16 +03:00
pe_start = pvd->pe_start << SECTOR_SHIFT;
2001-10-10 13:36:29 +04:00
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
break;
default:
return 0;
}
2008-01-30 17:00:02 +03:00
/* UUID too long? */
if (pvd->pv_uuid[ID_LEN]) {
/* Retain ID_LEN chars from end */
2008-01-30 17:00:02 +03:00
for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) {
if (!pvd->pv_uuid[e]) {
e--;
break;
}
}
for (b = 0; b < ID_LEN; b++) {
pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN];
/* FIXME Remove all invalid chars */
if (pvd->pv_uuid[b] == '/')
pvd->pv_uuid[b] = '#';
}
memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN);
2008-01-30 17:00:02 +03:00
}
2004-05-05 01:25:57 +04:00
/* If UUID is missing, create one */
2006-05-10 20:42:03 +04:00
if (pvd->pv_uuid[0] == '\0') {
uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number);
2006-05-10 20:42:03 +04:00
pvd->pv_uuid[ID_LEN] = '\0';
}
2004-05-05 01:25:57 +04:00
2001-10-10 13:36:29 +04:00
return 1;
}
2008-01-30 17:00:02 +03:00
/*
* If exported, remove "PV_EXP" from end of VG name
*/
static void _munge_exported_vg(struct pv_disk *pvd)
2001-10-05 19:20:40 +04:00
{
int l;
size_t s;
/* Return if PV not in a VG */
if ((!*pvd->vg_name))
return;
/* FIXME also check vgd->status & VG_EXPORTED? */
l = strlen((char *)pvd->vg_name);
s = sizeof(EXPORTED_TAG);
if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
pvd->vg_name[l - s + 1] = '\0';
2008-01-30 17:00:02 +03:00
pvd->pv_status |= VG_EXPORTED;
}
}
int munge_pvd(struct device *dev, struct pv_disk *pvd)
{
_xlate_pvd(pvd);
2001-10-10 13:36:29 +04:00
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
2002-11-18 17:01:16 +03:00
log_very_verbose("%s does not have a valid LVM1 PV identifier",
dev_name(dev));
return 0;
}
if (!_munge_formats(pvd)) {
2002-11-18 17:01:16 +03:00
log_very_verbose("format1: Unknown metadata version %d "
"found on %s", pvd->version, dev_name(dev));
2008-09-15 21:06:55 +04:00
return 0;
}
/* If VG is exported, set VG name back to the real name */
_munge_exported_vg(pvd);
2001-10-10 16:45:20 +04:00
return 1;
2001-10-04 21:48:55 +04:00
}
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
2008-09-15 21:06:55 +04:00
return 0;
}
return munge_pvd(dev, pvd);
}
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
2001-10-04 21:48:55 +04:00
{
if (!dev_read(dev, pos, sizeof(*disk), disk))
2008-01-30 16:19:47 +03:00
return_0;
_xlate_lvd(disk);
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1;
}
2006-04-11 02:09:00 +04:00
int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
2001-10-04 21:48:55 +04:00
{
2006-04-11 02:09:00 +04:00
uint64_t pos = pvd->vg_on_disk.base;
if (!dev_read(dev, pos, sizeof(*vgd), vgd))
2008-01-30 16:19:47 +03:00
return_0;
_xlate_vgd(vgd);
2001-10-04 21:48:55 +04:00
if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV))
2008-01-30 16:19:47 +03:00
return_0;
/* If UUID is missing, create one */
if (vgd->vg_uuid[0] == '\0')
uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number);
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
{
unsigned num_read = 0;
2001-10-04 21:48:55 +04:00
struct uuid_list *ul;
char buffer[NAME_LEN] __attribute__((aligned(8)));
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
2001-10-04 21:48:55 +04:00
while (pos < end && num_read < data->vgd.pv_cur) {
if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
2008-01-30 16:19:47 +03:00
return_0;
2001-10-04 21:48:55 +04:00
if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul))))
2008-01-30 16:19:47 +03:00
return_0;
2001-10-04 21:48:55 +04:00
memcpy(ul->uuid, buffer, NAME_LEN);
2001-11-28 02:12:06 +03:00
ul->uuid[NAME_LEN - 1] = '\0';
2001-10-04 21:48:55 +04:00
dm_list_add(&data->uuids, &ul->list);
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;
}
static int _check_lvd(struct lv_disk *lvd)
{
return !(lvd->lv_name[0] == '\0');
}
2001-10-05 19:20:40 +04:00
static int _read_lvs(struct disk_list *data)
2001-10-04 21:48:55 +04:00
{
unsigned int i, lvs_read = 0;
uint64_t pos;
2001-10-08 13:45:16 +04:00
struct lvd_list *ll;
struct vg_disk *vgd = &data->vgd;
2001-10-04 21:48:55 +04:00
for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) {
pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk));
ll = dm_pool_alloc(data->mem, sizeof(*ll));
2001-10-04 21:48:55 +04:00
if (!ll)
2008-01-30 16:19:47 +03:00
return_0;
2001-10-04 21:48:55 +04:00
if (!_read_lvd(data->dev, pos, &ll->lvd))
2008-01-30 16:19:47 +03:00
return_0;
2001-10-04 21:48:55 +04:00
if (!_check_lvd(&ll->lvd))
continue;
lvs_read++;
dm_list_add(&data->lvds, &ll->list);
2001-10-04 21:48:55 +04:00
}
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
{
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
struct pe_disk *extents = dm_pool_alloc(data->mem, len);
uint64_t pos = data->pvd.pe_on_disk.base;
2001-10-04 21:48:55 +04:00
if (!extents)
2008-01-30 16:19:47 +03:00
return_0;
if (!dev_read(data->dev, pos, len, extents))
2008-01-30 16:19:47 +03:00
return_0;
2001-10-04 21:48:55 +04:00
_xlate_extents(extents, data->pvd.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;
}
2006-04-11 02:09:00 +04:00
static void __update_lvmcache(const struct format_type *fmt,
struct disk_list *dl,
struct device *dev, const char *vgid,
unsigned exported)
2006-04-11 02:09:00 +04:00
{
struct lvmcache_info *info;
2008-02-06 18:47:28 +03:00
const char *vgname = *((char *)dl->pvd.vg_name) ?
(char *)dl->pvd.vg_name : fmt->orphan_vg_name;
2006-04-11 02:09:00 +04:00
if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev,
2008-02-06 18:47:28 +03:00
vgname, vgid, exported ? EXPORTED_VG : 0))) {
2006-04-11 02:09:00 +04:00
stack;
return;
}
2012-08-16 22:07:30 +04:00
lvmcache_set_device_size(info, ((uint64_t)xlate32(dl->pvd.pv_size)) << SECTOR_SHIFT);
lvmcache_del_mdas(info);
lvmcache_make_valid(info);
2006-04-11 02:09:00 +04:00
}
static struct disk_list *__read_disk(const struct format_type *fmt,
struct device *dev, struct dm_pool *mem,
const char *vg_name)
2001-10-04 21:48:55 +04:00
{
2006-04-11 02:09:00 +04:00
struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl));
const char *name = dev_name(dev);
2008-01-30 16:19:47 +03:00
if (!dl)
return_NULL;
2001-11-12 19:00:52 +03:00
dl->dev = dev;
dl->mem = mem;
dm_list_init(&dl->uuids);
dm_list_init(&dl->lvds);
2001-10-05 19:20:40 +04:00
if (!_read_pvd(dev, &dl->pvd))
goto_bad;
2001-10-10 16:45:20 +04:00
2001-10-10 16:28:10 +04:00
/*
* is it an orphan ?
*/
if (!*dl->pvd.vg_name) {
log_very_verbose("%s is not a member of any format1 VG", name);
2008-02-06 18:47:28 +03:00
__update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
return (vg_name) ? NULL : dl;
2001-10-10 16:45:20 +04:00
}
2001-10-10 16:28:10 +04:00
2006-04-11 02:09:00 +04:00
if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) {
log_error("Failed to read VG data from PV (%s)", name);
2008-02-06 18:47:28 +03:00
__update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s",
name, vg_name);
2008-02-06 18:47:28 +03:00
__update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
__update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid,
dl->vgd.vg_status & VG_EXPORTED);
2006-04-11 02:09:00 +04:00
if (!_read_uuids(dl)) {
log_error("Failed to read PV uuid list from %s", name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
if (!_read_lvs(dl)) {
log_error("Failed to read LV's from %s", name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
if (!_read_extents(dl)) {
log_error("Failed to read extents from %s", name);
2001-10-05 19:20:40 +04:00
goto bad;
2001-10-04 21:48:55 +04:00
}
log_very_verbose("Found %s in %sVG %s", name,
(dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
dl->pvd.vg_name);
2001-10-29 16:52:23 +03:00
return dl;
2001-10-05 19:20:40 +04:00
bad:
dm_pool_free(dl->mem, dl);
2001-10-05 19:20:40 +04:00
return NULL;
2001-10-04 21:48:55 +04:00
}
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct dm_pool *mem, const char *vg_name)
{
struct disk_list *dl;
if (!dev_open_readonly(dev))
2008-01-30 16:19:47 +03:00
return_NULL;
dl = __read_disk(fmt, dev, mem, vg_name);
if (!dev_close(dev))
stack;
return dl;
}
static void _add_pv_to_list(struct cmd_context *cmd, struct dm_list *head, struct disk_list *data)
{
struct pv_disk *pvd;
2005-06-01 20:51:55 +04:00
struct disk_list *diskl;
dm_list_iterate_items(diskl, head) {
2005-06-01 20:51:55 +04:00
pvd = &diskl->pvd;
if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid,
sizeof(pvd->pv_uuid))) {
if (!dev_subsystem_part_major(cmd->dev_types, data->dev)) {
2002-01-28 00:30:47 +03:00
log_very_verbose("Ignoring duplicate PV %s on "
"%s", pvd->pv_uuid,
2002-01-28 00:30:47 +03:00
dev_name(data->dev));
return;
}
log_very_verbose("Duplicate PV %s - using %s %s",
pvd->pv_uuid, dev_subsystem_name(cmd->dev_types, data->dev),
dev_name(data->dev));
dm_list_del(&diskl->list);
break;
}
}
dm_list_add(head, &data->list);
}
struct _read_pvs_in_vg_baton {
const char *vg_name;
struct dm_list *head;
struct disk_list *data;
struct dm_pool *mem;
int empty;
};
static int _read_pv_in_vg(struct lvmcache_info *info, void *baton)
{
struct _read_pvs_in_vg_baton *b = baton;
b->empty = 0;
if (!lvmcache_device(info) ||
!(b->data = read_disk(lvmcache_fmt(info), lvmcache_device(info), b->mem, b->vg_name)))
return 0; /* stop here */
_add_pv_to_list(lvmcache_fmt(info)->cmd, b->head, b->data);
return 1;
}
2001-10-04 21:48:55 +04:00
/*
2002-01-10 21:12:26 +03:00
* Build a list of pv_d's structures, allocated from mem.
* We keep track of the first object allocated from the pool
* so we can free off all the memory if something goes wrong.
2001-10-04 21:48:55 +04:00
*/
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_filter *filter, struct dm_pool *mem,
struct dm_list *head)
2001-10-04 21:48:55 +04:00
{
struct dev_iter *iter;
2001-10-04 21:48:55 +04:00
struct device *dev;
struct lvmcache_vginfo *vginfo;
struct _read_pvs_in_vg_baton baton;
baton.head = head;
baton.empty = 1;
baton.data = NULL;
baton.mem = mem;
baton.vg_name = vg_name;
/* Fast path if we already saw this VG and cached the list of PVs */
if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL))) {
lvmcache_foreach_pv(vginfo, _read_pv_in_vg, &baton);
if (!baton.empty) {
/* Did we find the whole VG? */
if (!vg_name || is_orphan_vg(vg_name) ||
(baton.data && *baton.data->pvd.vg_name &&
dm_list_size(head) == baton.data->vgd.pv_cur))
return 1;
/* Failed */
dm_list_init(head);
/* vgcache_del(vg_name); */
}
}
if (!(iter = dev_iter_create(filter, 1))) {
log_error("read_pvs_in_vg: dev_iter_create failed");
return 0;
}
/* Otherwise do a complete scan */
2001-10-04 21:48:55 +04:00
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
if ((baton.data = read_disk(fmt, dev, mem, vg_name))) {
_add_pv_to_list(fmt->cmd, head, baton.data);
}
2001-10-05 19:20:40 +04:00
}
2001-10-08 13:45:16 +04:00
dev_iter_destroy(iter);
if (dm_list_empty(head))
2001-10-16 20:25:28 +04:00
return 0;
2001-10-05 19:20:40 +04:00
return 1;
}
static int _write_vgd(struct disk_list *data)
2001-10-05 19:20:40 +04:00
{
struct vg_disk *vgd = &data->vgd;
uint64_t pos = data->pvd.vg_on_disk.base;
2001-10-05 19:20:40 +04:00
log_debug_metadata("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t,
data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd));
2005-08-16 23:00:55 +04:00
_xlate_vgd(vgd);
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
2008-01-30 16:19:47 +03:00
return_0;
_xlate_vgd(vgd);
2001-10-05 19:20:40 +04:00
return 1;
}
static int _write_uuids(struct disk_list *data)
{
struct uuid_list *ul;
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
2001-10-05 19:20:40 +04:00
dm_list_iterate_items(ul, &data->uuids) {
2001-10-05 19:20:40 +04:00
if (pos >= end) {
2001-10-10 16:45:20 +04:00
log_error("Too many uuids to fit on %s",
dev_name(data->dev));
2001-10-05 19:20:40 +04:00
return 0;
}
log_debug_metadata("Writing %s uuidlist to %s at %" PRIu64 " len %d",
data->pvd.vg_name, dev_name(data->dev),
pos, NAME_LEN);
2005-08-16 23:00:55 +04:00
if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
2008-01-30 16:19:47 +03:00
return_0;
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
static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
2001-10-05 19:20:40 +04:00
{
log_debug_metadata("Writing %s LV %s metadata to %s at %" PRIu64 " len %"
PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev),
pos, sizeof(*disk));
2005-08-16 23:00:55 +04:00
_xlate_lvd(disk);
if (!dev_write(dev, pos, sizeof(*disk), disk))
2008-01-30 16:19:47 +03:00
return_0;
_xlate_lvd(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
}
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
static int _write_lvs(struct disk_list *data)
{
2005-06-01 20:51:55 +04:00
struct lvd_list *ll;
uint64_t pos, offset;
2001-10-05 19:20:40 +04:00
pos = data->pvd.lv_on_disk.base;
if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) {
2001-11-14 16:52:38 +03:00
log_error("Couldn't zero lv area on device '%s'",
dev_name(data->dev));
return 0;
}
dm_list_iterate_items(ll, &data->lvds) {
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
2002-11-18 17:01:16 +03:00
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
log_error("lv_number %d too large", ll->lvd.lv_number);
return 0;
}
2001-10-05 19:20:40 +04:00
if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
2008-01-30 16:19:47 +03:00
return_0;
2001-10-05 19:20:40 +04:00
}
return 1;
}
static int _write_extents(struct disk_list *data)
{
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
2001-10-05 19:20:40 +04:00
struct pe_disk *extents = data->extents;
uint64_t pos = data->pvd.pe_on_disk.base;
2001-10-05 19:20:40 +04:00
log_debug_metadata("Writing %s extents metadata to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, len);
2005-08-16 23:00:55 +04:00
_xlate_extents(extents, data->pvd.pe_total);
if (!dev_write(data->dev, pos, len, extents))
2008-01-30 16:19:47 +03:00
return_0;
_xlate_extents(extents, data->pvd.pe_total);
2001-10-05 19:20:40 +04:00
return 1;
}
static int _write_pvd(struct disk_list *data)
2001-10-05 19:20:40 +04:00
{
char *buf;
uint64_t pos = data->pvd.pv_on_disk.base;
size_t size = data->pvd.pv_on_disk.size;
2001-10-05 19:20:40 +04:00
if (size < sizeof(struct pv_disk)) {
log_error("Invalid PV structure size.");
return 0;
}
/* Make sure that the gap between the PV structure and
the next one is zeroed in order to make non LVM tools
happy (idea from AED) */
buf = dm_zalloc(size);
if (!buf) {
log_error("Couldn't allocate temporary PV buffer.");
return 0;
}
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
log_debug_metadata("Writing %s PV metadata to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, size);
2005-08-16 23:00:55 +04:00
_xlate_pvd((struct pv_disk *) buf);
if (!dev_write(data->dev, pos, size, buf)) {
dm_free(buf);
2008-01-30 16:19:47 +03:00
return_0;
}
2001-10-05 19:20:40 +04:00
dm_free(buf);
2001-10-05 19:20:40 +04:00
return 1;
}
/*
* assumes the device has been opened.
*/
static int __write_all_pvd(const struct format_type *fmt __attribute__((unused)),
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
struct disk_list *data, int write_vg_metadata)
2001-10-05 19:20:40 +04:00
{
const char *pv_name = dev_name(data->dev);
2001-10-05 19:20:40 +04:00
if (!_write_pvd(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;
}
2002-11-18 17:01:16 +03:00
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
2001-10-10 14:05:29 +04:00
/*
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
* Stop here for orphan PVs or if VG metadata write not requested.
2001-10-10 14:05:29 +04:00
*/
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
if ((data->pvd.vg_name[0] == '\0') || !write_vg_metadata) {
2002-11-18 17:01:16 +03:00
/* if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
2001-10-10 14:05:29 +04:00
return 1;
}
2002-11-18 17:01:16 +03:00
/* if (!test_mode())
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
fmt); */
2001-10-10 14:05:29 +04:00
if (!_write_vgd(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;
}
/*
* opens the device and hands to the above fn.
*/
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data, int write_vg_metadata)
{
int r;
if (!data->dev)
return_0;
2008-01-30 16:19:47 +03:00
if (!dev_open(data->dev))
return_0;
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
r = __write_all_pvd(fmt, data, write_vg_metadata);
if (!dev_close(data->dev))
stack;
return r;
}
2001-10-05 19:20:40 +04:00
/*
* Writes all the given pv's to disk. Does very
* little sanity checking, so make sure correct
* data is passed to here.
*/
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
int write_disks(const struct format_type *fmt, struct dm_list *pvs, int write_vg_metadata)
2001-10-05 19:20:40 +04:00
{
struct disk_list *dl;
dm_list_iterate_items(dl, pvs) {
pv_write: clean up non-orphan format1 PV write ...to not pollute the common and format-independent code in the abstraction layer above. The format1 pv_write has common code for writing metadata and PV header by calling the "write_disks" fn and when rewriting the header itself only (e.g. just for the purpose of changing the PV UUID) during the pvchange operation, we had to tweak this functionality for the format1 case and we had to assign the PV the orphan state temporarily. This patch removes the need for this format1 tweak and it calls the write_disks with appropriate flag indicating whether this is a PV write call or a VG write call, allowing for metatada update for the latter one. Also, a side effect of the former tweak was that it effectively invalidated the cache (even for the non-format1 PVs) as we assigned it the orphan state temporarily just for the format1 PV write to pass. Also, that tweak made it difficult to directly detect whether a PV was part of a VG or not because the state was incorrect. Also, it's not necessary to backup and restore some PV fields when doing a PV write: orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); ... pv_write(pv) ... pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; ...this is already done by the layer below itself (the _format1_pv_write fn). So let's have this cleaned up so we don't need to be bothered about any 'format1 special case for pv_write' anymore.
2013-03-25 17:30:40 +04:00
if (!(_write_all_pvd(fmt, dl, write_vg_metadata)))
2008-01-30 16:19:47 +03:00
return_0;
log_very_verbose("Successfully wrote data to %s",
2002-01-28 00:30:47 +03:00
dev_name(dl->dev));
2001-10-05 19:20:40 +04:00
}
return 1;
2001-10-04 21:48:55 +04:00
}