mirror of
git://sourceware.org/git/lvm2.git
synced 2026-02-04 12:32:46 +03:00
Compare commits
13 Commits
dm_v1_02_2
...
v2_02_40
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a586a89547 | ||
|
|
1905eacf15 | ||
|
|
858ec0d740 | ||
|
|
76cfd406ca | ||
|
|
9dbaad859d | ||
|
|
95d43e17b3 | ||
|
|
09a2dff8de | ||
|
|
57208f879a | ||
|
|
149638431d | ||
|
|
30d2940c67 | ||
|
|
5ee86fc5d0 | ||
|
|
a03d0e2c3f | ||
|
|
8bd367d58d |
14
WHATS_NEW
14
WHATS_NEW
@@ -1,5 +1,15 @@
|
||||
Version 2.02.40 -
|
||||
================================
|
||||
Version 2.02.40 - 19th September 2008
|
||||
=====================================
|
||||
Allow lvremove to remove LVs from VGs with missing PVs.
|
||||
In VG with PVs missing, by default allow activation of LVs that are complete.
|
||||
Track PARTIAL_LV and MISSING_PV flags internally.
|
||||
Require --force with --removemissing in vgreduce to remove partial LVs.
|
||||
No longer write out PARTIAL flag into metadata backups.
|
||||
Treat new default activation/missing_stripe_filler "error" as an error target.
|
||||
Remove internal partial_mode.
|
||||
Add device/md_chunk_alignment to lvm.conf.
|
||||
Pass struct physical_volume to pe_align and adjust for md chunk size.
|
||||
Store sysfs location in struct cmd_context.
|
||||
Avoid shuffling remaining mirror images when removing one, retaining primary.
|
||||
Add missing LV error target activation in _remove_mirror_images.
|
||||
Prevent resizing an LV while lvconvert is using it.
|
||||
|
||||
@@ -413,9 +413,6 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
}
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_PARTIAL_MODE)
|
||||
init_partial(1);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
@@ -454,9 +451,6 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_PARTIAL_MODE)
|
||||
init_partial(0);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
|
||||
@@ -93,6 +93,11 @@ devices {
|
||||
# 1 enables; 0 disables.
|
||||
md_component_detection = 1
|
||||
|
||||
# By default, if a PV is placed directly upon an md device, LVM2
|
||||
# will align its data blocks with the the chunk_size exposed in sysfs.
|
||||
# 1 enables; 0 disables.
|
||||
md_chunk_alignment = 1
|
||||
|
||||
# If, while scanning the system for PVs, LVM2 encounters a device-mapper
|
||||
# device that has its I/O suspended, it waits for it to become accessible.
|
||||
# Set this to 1 to skip such devices. This should only be needed
|
||||
@@ -266,11 +271,13 @@ global {
|
||||
}
|
||||
|
||||
activation {
|
||||
# Device used in place of missing stripes if activating incomplete volume.
|
||||
# For now, you need to set this up yourself first (e.g. with 'dmsetup')
|
||||
# For example, you could make it return I/O errors using the 'error'
|
||||
# target or make it return zeros.
|
||||
missing_stripe_filler = "/dev/ioerror"
|
||||
# How to fill in missing stripes if activating an incomplete volume.
|
||||
# Using "error" will make inaccessible parts of the device return
|
||||
# I/O errors on access. You can instead use a device path, in which
|
||||
# case, that device will be used to in place of missing stripes.
|
||||
# But note that using anything other than "error" with mirrored
|
||||
# or snapshotted volumes is likely to result in data corruption.
|
||||
missing_stripe_filler = "error"
|
||||
|
||||
# How much stack (in KB) to reserve for use while devices suspended
|
||||
reserved_stack = 256
|
||||
|
||||
@@ -1027,6 +1027,12 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((!lv->vg->cmd->partial_activation) && (lv->status & PARTIAL_LV)) {
|
||||
log_error("Refusing activation of partial LV %s. Use --partial to override.",
|
||||
lv->name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Activating '%s'.", lv->name);
|
||||
return 1;
|
||||
|
||||
@@ -47,7 +47,6 @@ struct dev_manager {
|
||||
|
||||
struct cmd_context *cmd;
|
||||
|
||||
const char *stripe_filler;
|
||||
void *target_state;
|
||||
uint32_t pvmove_mirror_count;
|
||||
|
||||
@@ -59,8 +58,6 @@ struct lv_layer {
|
||||
const char *old_name;
|
||||
};
|
||||
|
||||
static const char *stripe_filler = NULL;
|
||||
|
||||
static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *layer)
|
||||
{
|
||||
char *dlid;
|
||||
@@ -443,13 +440,6 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
dm->cmd = cmd;
|
||||
dm->mem = mem;
|
||||
|
||||
if (!stripe_filler) {
|
||||
stripe_filler = find_config_tree_str(cmd,
|
||||
"activation/missing_stripe_filler",
|
||||
DEFAULT_STRIPE_FILLER);
|
||||
}
|
||||
dm->stripe_filler = stripe_filler;
|
||||
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
|
||||
goto_bad;
|
||||
|
||||
@@ -699,6 +689,68 @@ bad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
struct lv_segment *seg, int s)
|
||||
{
|
||||
char *id, *name;
|
||||
char errid[32];
|
||||
struct dm_tree_node *node;
|
||||
struct lv_segment *seg_i;
|
||||
int segno = -1, i = 0;;
|
||||
uint64_t size = seg->len * seg->lv->vg->extent_size;
|
||||
|
||||
list_iterate_items(seg_i, &seg->lv->segments) {
|
||||
if (seg == seg_i)
|
||||
segno = i;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (segno < 0) {
|
||||
log_error("_add_error_device called with bad segment");
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
sprintf(errid, "missing_%d_%d", segno, s);
|
||||
|
||||
if (!(id = build_dlid(dm, seg->lv->lvid.s, errid)))
|
||||
return_NULL;
|
||||
|
||||
if (!(name = build_dm_name(dm->mem, seg->lv->vg->name,
|
||||
seg->lv->name, errid)))
|
||||
return_NULL;
|
||||
if (!(node = dm_tree_add_new_dev(dtree, name, id, 0, 0, 0, 0, 0)))
|
||||
return_NULL;
|
||||
if (!dm_tree_node_add_error_target(node, size))
|
||||
return_NULL;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
|
||||
struct lv_segment *seg, int s)
|
||||
{
|
||||
char *dlid;
|
||||
uint64_t extent_size = seg->lv->vg->extent_size;
|
||||
|
||||
if (!strcmp(dm->cmd->stripe_filler, "error")) {
|
||||
/*
|
||||
* FIXME, the tree pointer is first field of dm_tree_node, but
|
||||
* we don't have the struct definition available.
|
||||
*/
|
||||
struct dm_tree **tree = (struct dm_tree **) node;
|
||||
dlid = _add_error_device(dm, *tree, seg, s);
|
||||
if (!dlid)
|
||||
return_0;
|
||||
dm_tree_node_add_target_area(node, NULL, dlid,
|
||||
extent_size * seg_le(seg, s));
|
||||
} else
|
||||
dm_tree_node_add_target_area(node,
|
||||
dm->cmd->stripe_filler,
|
||||
NULL, UINT64_C(0));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
struct dm_tree_node *node, uint32_t start_area,
|
||||
uint32_t areas)
|
||||
@@ -712,11 +764,10 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
(!seg_pvseg(seg, s) ||
|
||||
!seg_pv(seg, s) ||
|
||||
!seg_dev(seg, s))) ||
|
||||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
|
||||
dm_tree_node_add_target_area(node,
|
||||
dm->stripe_filler,
|
||||
NULL, UINT64_C(0));
|
||||
else if (seg_type(seg, s) == AREA_PV)
|
||||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) {
|
||||
if (!_add_error_area(dm, node, seg, s))
|
||||
return_0;
|
||||
} else if (seg_type(seg, s) == AREA_PV)
|
||||
dm_tree_node_add_target_area(node,
|
||||
dev_name(seg_dev(seg, s)),
|
||||
NULL,
|
||||
|
||||
@@ -75,6 +75,49 @@ static int _get_env_vars(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _get_sysfs_dir(struct cmd_context *cmd)
|
||||
{
|
||||
static char proc_mounts[PATH_MAX];
|
||||
static char *split[4], buffer[PATH_MAX + 16];
|
||||
FILE *fp;
|
||||
char *sys_mnt = NULL;
|
||||
|
||||
cmd->sysfs_dir[0] = '\0';
|
||||
if (!*cmd->proc_dir) {
|
||||
log_debug("No proc filesystem found: skipping sysfs detection");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dm_snprintf(proc_mounts, sizeof(proc_mounts),
|
||||
"%s/mounts", cmd->proc_dir) < 0) {
|
||||
log_error("Failed to create /proc/mounts string for sysfs detection");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(fp = fopen(proc_mounts, "r"))) {
|
||||
log_sys_error("_get_sysfs_dir: fopen %s", proc_mounts);
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
if (dm_split_words(buffer, 4, 0, split) == 4 &&
|
||||
!strcmp(split[2], "sysfs")) {
|
||||
sys_mnt = split[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", proc_mounts);
|
||||
|
||||
if (!sys_mnt) {
|
||||
log_error("Failed to find sysfs mount point");
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(cmd->sysfs_dir, sys_mnt, sizeof(cmd->sysfs_dir));
|
||||
}
|
||||
|
||||
static void _init_logging(struct cmd_context *cmd)
|
||||
{
|
||||
int append = 1;
|
||||
@@ -154,6 +197,7 @@ static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
const char *read_ahead;
|
||||
struct stat st;
|
||||
|
||||
/* umask */
|
||||
cmd->default_settings.umask = find_config_tree_int(cmd,
|
||||
@@ -189,6 +233,8 @@ static int _process_config(struct cmd_context *cmd)
|
||||
cmd->proc_dir[0] = '\0';
|
||||
}
|
||||
|
||||
_get_sysfs_dir(cmd);
|
||||
|
||||
/* activation? */
|
||||
cmd->default_settings.activation = find_config_tree_int(cmd,
|
||||
"global/activation",
|
||||
@@ -218,6 +264,24 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->stripe_filler = find_config_tree_str(cmd,
|
||||
"activation/missing_stripe_filler",
|
||||
DEFAULT_STRIPE_FILLER);
|
||||
if (strcmp(cmd->stripe_filler, "error")) {
|
||||
if (stat(cmd->stripe_filler, &st)) {
|
||||
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
|
||||
"is invalid,", cmd->stripe_filler);
|
||||
log_warn(" stat failed: %s", strerror(errno));
|
||||
log_warn("Falling back to \"error\" missing_stripe_filler.");
|
||||
cmd->stripe_filler = "error";
|
||||
} else if (!S_ISBLK(st.st_mode)) {
|
||||
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
|
||||
"is not a block device.", cmd->stripe_filler);
|
||||
log_warn("Falling back to \"error\" missing_stripe_filler.");
|
||||
cmd->stripe_filler = "error";
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -534,7 +598,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
*/
|
||||
if (find_config_tree_bool(cmd, "devices/sysfs_scan",
|
||||
DEFAULT_SYSFS_SCAN)) {
|
||||
if ((filters[nr_filt] = sysfs_filter_create(cmd->proc_dir)))
|
||||
if ((filters[nr_filt] = sysfs_filter_create(cmd->sysfs_dir)))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
@@ -936,6 +1000,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
|
||||
cmd->args = the_args;
|
||||
cmd->is_static = is_static;
|
||||
cmd->is_long_lived = is_long_lived;
|
||||
cmd->handles_missing_pvs = 0;
|
||||
cmd->hosttags = 0;
|
||||
list_init(&cmd->formats);
|
||||
list_init(&cmd->segtypes);
|
||||
|
||||
@@ -66,8 +66,10 @@ struct cmd_context {
|
||||
struct command *command;
|
||||
struct arg *args;
|
||||
char **argv;
|
||||
unsigned is_static; /* Static binary? */
|
||||
unsigned is_long_lived; /* Optimises persistent_filter handling */
|
||||
unsigned is_static:1; /* Static binary? */
|
||||
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
|
||||
unsigned handles_missing_pvs:1;
|
||||
unsigned partial_activation:1;
|
||||
|
||||
struct dev_filter *filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
@@ -81,6 +83,7 @@ struct cmd_context {
|
||||
|
||||
struct archive_params *archive_params;
|
||||
struct backup_params *backup_params;
|
||||
const char *stripe_filler;
|
||||
|
||||
/* List of defined tags */
|
||||
struct list tags;
|
||||
@@ -89,6 +92,7 @@ struct cmd_context {
|
||||
char sys_dir[PATH_MAX];
|
||||
char dev_dir[PATH_MAX];
|
||||
char proc_dir[PATH_MAX];
|
||||
char sysfs_dir[PATH_MAX];
|
||||
};
|
||||
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_MD_CHUNK_ALIGNMENT 1
|
||||
#define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
@@ -91,7 +92,7 @@
|
||||
# define DEFAULT_ACTIVATION 0
|
||||
#endif
|
||||
|
||||
#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
|
||||
#define DEFAULT_STRIPE_FILLER "error"
|
||||
#define DEFAULT_MIRROR_REGION_SIZE 512 /* KB */
|
||||
#define DEFAULT_INTERVAL 15
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Luca Berra
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "xlate.h"
|
||||
#include "filter.h"
|
||||
|
||||
#ifdef linux
|
||||
|
||||
@@ -124,6 +125,62 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve chunk size from md device using sysfs.
|
||||
*/
|
||||
unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev)
|
||||
{
|
||||
char path[PATH_MAX+1], buffer[64];
|
||||
FILE *fp;
|
||||
struct stat info;
|
||||
unsigned long chunk_size = 0UL;
|
||||
|
||||
if (MAJOR(dev->dev) != md_major())
|
||||
return 0;
|
||||
|
||||
if (!sysfs_dir || !*sysfs_dir)
|
||||
return_0;
|
||||
|
||||
if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/md/chunk_size",
|
||||
sysfs_dir, MAJOR(dev->dev), MINOR(dev->dev)) < 0) {
|
||||
log_error("dm_snprintf md chunk_size failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* old sysfs structure */
|
||||
if (stat(path, &info) &&
|
||||
dm_snprintf(path, PATH_MAX, "%s/block/md%d/md/chunk_size",
|
||||
sysfs_dir, MINOR(dev->dev)) < 0) {
|
||||
log_error("dm_snprintf old md chunk size failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fp = fopen(path, "r"))) {
|
||||
log_sys_error("fopen", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
log_sys_error("fgets", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sscanf(buffer, "%lu", &chunk_size) != 1) {
|
||||
log_error("sysfs file %s not in expected format: %s", path,
|
||||
buffer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_very_verbose("Found chunksize %lu for md device %s.", chunk_size,
|
||||
dev_name(dev));
|
||||
|
||||
out:
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", path);
|
||||
|
||||
return chunk_size;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int dev_is_md(struct device *dev __attribute((unused)),
|
||||
@@ -132,4 +189,10 @@ int dev_is_md(struct device *dev __attribute((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long dev_md_chunk_size(const char *sysfs_dir __attribute((unused)),
|
||||
struct device *dev __attribute((unused)))
|
||||
{
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -93,6 +93,7 @@ const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||
|
||||
/* Does device contain md superblock? If so, where? */
|
||||
int dev_is_md(struct device *dev, uint64_t *sb);
|
||||
unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev);
|
||||
|
||||
int is_partitioned_dev(struct device *dev);
|
||||
|
||||
|
||||
@@ -578,10 +578,7 @@ void vgdisplay_full(const struct volume_group *vg)
|
||||
struct lv_list *lvl;
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
else
|
||||
active_pvs = vg->pv_count;
|
||||
active_pvs = vg->pv_count - vg_missing_pv_count(vg);
|
||||
|
||||
log_print("--- Volume group ---");
|
||||
log_print("VG Name %s", vg->name);
|
||||
@@ -664,10 +661,7 @@ void vgdisplay_colons(const struct volume_group *vg)
|
||||
const char *access;
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
else
|
||||
active_pvs = vg->pv_count;
|
||||
active_pvs = vg->pv_count - vg_missing_pv_count(vg);
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs)
|
||||
if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT))
|
||||
|
||||
@@ -20,47 +20,11 @@
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
static int _locate_sysfs_blocks(const char *proc, char *path, size_t len,
|
||||
static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
|
||||
unsigned *sysfs_depth)
|
||||
{
|
||||
char proc_mounts[PATH_MAX];
|
||||
FILE *fp;
|
||||
char *split[4], buffer[PATH_MAX + 16];
|
||||
const char *sys_mnt = NULL;
|
||||
struct stat info;
|
||||
|
||||
if (!*proc) {
|
||||
log_verbose("No proc filesystem found: skipping sysfs filter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(proc_mounts, sizeof(proc_mounts),
|
||||
"%s/mounts", proc) < 0) {
|
||||
log_error("Failed to create /proc/mounts string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fp = fopen(proc_mounts, "r"))) {
|
||||
log_sys_error("fopen %s", proc_mounts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
if (dm_split_words(buffer, 4, 0, split) == 4 &&
|
||||
!strcmp(split[2], "sysfs")) {
|
||||
sys_mnt = split[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", proc_mounts);
|
||||
|
||||
if (!sys_mnt) {
|
||||
log_error("Failed to find sysfs mount point");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* unified classification directory for all kernel subsystems
|
||||
*
|
||||
@@ -70,7 +34,7 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len,
|
||||
* `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
|
||||
*
|
||||
*/
|
||||
if (dm_snprintf(path, len, "%s/%s", sys_mnt,
|
||||
if (dm_snprintf(path, len, "%s/%s", sysfs_dir,
|
||||
"subsystem/block/devices") >= 0) {
|
||||
if (!stat(path, &info)) {
|
||||
*sysfs_depth = 0;
|
||||
@@ -87,7 +51,7 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len,
|
||||
* `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
|
||||
*
|
||||
*/
|
||||
if (dm_snprintf(path, len, "%s/%s", sys_mnt, "class/block") >= 0) {
|
||||
if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "class/block") >= 0) {
|
||||
if (!stat(path, &info)) {
|
||||
*sysfs_depth = 0;
|
||||
return 1;
|
||||
@@ -112,7 +76,7 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len,
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
if (dm_snprintf(path, len, "%s/%s", sys_mnt, "block") >= 0) {
|
||||
if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "block") >= 0) {
|
||||
if (!stat(path, &info)) {
|
||||
*sysfs_depth = 1;
|
||||
return 1;
|
||||
@@ -321,7 +285,7 @@ static void _destroy(struct dev_filter *f)
|
||||
dm_pool_destroy(ds->mem);
|
||||
}
|
||||
|
||||
struct dev_filter *sysfs_filter_create(const char *proc)
|
||||
struct dev_filter *sysfs_filter_create(const char *sysfs_dir)
|
||||
{
|
||||
char sys_block[PATH_MAX];
|
||||
unsigned sysfs_depth;
|
||||
@@ -329,7 +293,12 @@ struct dev_filter *sysfs_filter_create(const char *proc)
|
||||
struct dev_set *ds;
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block), &sysfs_depth))
|
||||
if (!*sysfs_dir) {
|
||||
log_verbose("No proc filesystem found: skipping sysfs filter");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth))
|
||||
return NULL;
|
||||
|
||||
if (!(mem = dm_pool_create("sysfs", 256))) {
|
||||
@@ -357,7 +326,7 @@ struct dev_filter *sysfs_filter_create(const char *proc)
|
||||
|
||||
#else
|
||||
|
||||
struct dev_filter *sysfs_filter_create(const char *proc __attribute((unused)))
|
||||
struct dev_filter *sysfs_filter_create(const char *sysfs_dir __attribute((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
#include "config.h"
|
||||
#include "dev-cache.h"
|
||||
|
||||
struct dev_filter *sysfs_filter_create(const char *proc);
|
||||
struct dev_filter *sysfs_filter_create(const char *sysfs_dir);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -356,7 +356,7 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!_read_pvd(dev, &dl->pvd))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
|
||||
@@ -212,7 +212,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
struct pv_disk *pvd, struct physical_volume *pv);
|
||||
|
||||
int import_vg(struct dm_pool *mem,
|
||||
struct volume_group *vg, struct disk_list *dl, int partial);
|
||||
struct volume_group *vg, struct disk_list *dl);
|
||||
int export_vg(struct vg_disk *vgd, struct volume_group *vg);
|
||||
|
||||
int import_lv(struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "segtype.h"
|
||||
|
||||
/* VG consistency checks */
|
||||
static int _check_vgs(struct list *pvs, int *partial)
|
||||
static int _check_vgs(struct list *pvs)
|
||||
{
|
||||
struct list *pvh, *t;
|
||||
struct disk_list *dl = NULL;
|
||||
@@ -33,8 +33,6 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
uint32_t exported = 0;
|
||||
int first_time = 1;
|
||||
|
||||
*partial = 0;
|
||||
|
||||
/*
|
||||
* If there are exported and unexported PVs, ignore exported ones.
|
||||
* This means an active VG won't be affected if disks are inserted
|
||||
@@ -98,10 +96,6 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
dl->vgd.pe_total, dl->vgd.pe_allocated,
|
||||
dl->vgd.pvg_total);
|
||||
list_del(pvh);
|
||||
if (partial_mode()) {
|
||||
*partial = 1;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
pv_count++;
|
||||
@@ -111,9 +105,6 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
if (pv_count != first->vgd.pv_cur) {
|
||||
log_error("%d PV(s) found for VG %s: expected %d",
|
||||
pv_count, first->pvd.vg_name, first->vgd.pv_cur);
|
||||
if (!partial_mode())
|
||||
return 0;
|
||||
*partial = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -125,7 +116,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
struct dm_pool *mem = fid->fmt->cmd->mem;
|
||||
struct volume_group *vg = dm_pool_alloc(mem, sizeof(*vg));
|
||||
struct disk_list *dl;
|
||||
int partial;
|
||||
|
||||
if (!vg)
|
||||
goto_bad;
|
||||
@@ -142,12 +132,12 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
if (!_check_vgs(pvs))
|
||||
goto_bad;
|
||||
|
||||
dl = list_item(pvs->n, struct disk_list);
|
||||
|
||||
if (!import_vg(mem, vg, dl, partial))
|
||||
if (!import_vg(mem, vg, dl))
|
||||
goto_bad;
|
||||
|
||||
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
|
||||
@@ -95,6 +95,7 @@ int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
pv->pe_start = pvd->pe_start;
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->pe_align = 0;
|
||||
|
||||
/* Fix up pv size if missing or impossibly large */
|
||||
if (!pv->size || pv->size > (1ULL << 62)) {
|
||||
@@ -213,7 +214,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute((unused))
|
||||
}
|
||||
|
||||
int import_vg(struct dm_pool *mem,
|
||||
struct volume_group *vg, struct disk_list *dl, int partial)
|
||||
struct volume_group *vg, struct disk_list *dl)
|
||||
{
|
||||
struct vg_disk *vgd = &dl->vgd;
|
||||
memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
|
||||
@@ -235,10 +236,10 @@ int import_vg(struct dm_pool *mem,
|
||||
if (vgd->vg_status & VG_EXTENDABLE)
|
||||
vg->status |= RESIZEABLE_VG;
|
||||
|
||||
if (partial || (vgd->vg_access & VG_READ))
|
||||
if (vgd->vg_access & VG_READ)
|
||||
vg->status |= LVM_READ;
|
||||
|
||||
if (!partial && (vgd->vg_access & VG_WRITE))
|
||||
if (vgd->vg_access & VG_WRITE)
|
||||
vg->status |= LVM_WRITE;
|
||||
|
||||
if (vgd->vg_access & VG_CLUSTERED)
|
||||
@@ -254,9 +255,6 @@ int import_vg(struct dm_pool *mem,
|
||||
vg->max_pv = vgd->pv_max;
|
||||
vg->alloc = ALLOC_NORMAL;
|
||||
|
||||
if (partial)
|
||||
vg->status |= PARTIAL_VG;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,6 +173,7 @@ int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
pv->pe_start = POOL_PE_START;
|
||||
pv->pe_count = pv->size / POOL_PE_SIZE;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->pe_align = 0;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
@@ -134,10 +134,8 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
int r1, r2;
|
||||
|
||||
init_partial(1);
|
||||
r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
|
||||
r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
|
||||
init_partial(0);
|
||||
|
||||
return r1 && r2;
|
||||
}
|
||||
@@ -146,9 +144,7 @@ int archive_display_file(struct cmd_context *cmd, const char *file)
|
||||
{
|
||||
int r;
|
||||
|
||||
init_partial(1);
|
||||
r = archive_list_file(cmd, file);
|
||||
init_partial(0);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -393,7 +389,7 @@ void check_current_backup(struct volume_group *vg)
|
||||
char path[PATH_MAX];
|
||||
struct volume_group *vg_backup;
|
||||
|
||||
if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
|
||||
if (vg->status & EXPORTED_VG)
|
||||
return;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s",
|
||||
|
||||
@@ -31,12 +31,12 @@ struct flag {
|
||||
static struct flag _vg_flags[] = {
|
||||
{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
|
||||
{RESIZEABLE_VG, "RESIZEABLE", STATUS_FLAG},
|
||||
{PARTIAL_VG, "PARTIAL", STATUS_FLAG},
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{CLUSTERED, "CLUSTERED", STATUS_FLAG},
|
||||
{SHARED, "SHARED", STATUS_FLAG},
|
||||
{PARTIAL_VG, NULL, 0},
|
||||
{PRECOMMITTED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
@@ -44,6 +44,7 @@ static struct flag _vg_flags[] = {
|
||||
static struct flag _pv_flags[] = {
|
||||
{ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG},
|
||||
{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
|
||||
{MISSING_PV, "MISSING", COMPATIBLE_FLAG},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -62,6 +63,8 @@ static struct flag _lv_flags[] = {
|
||||
{SNAPSHOT, NULL, 0},
|
||||
{ACTIVATE_EXCL, NULL, 0},
|
||||
{CONVERTING, NULL, 0},
|
||||
{PARTIAL_LV, NULL, 0},
|
||||
{POSTORDER_FLAG, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -155,7 +158,16 @@ int read_flags(uint32_t *status, int type, struct config_value *cv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!flags[f].description && (type & STATUS_FLAG)) {
|
||||
if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) {
|
||||
/*
|
||||
* Exception: We no longer write this flag out, but it
|
||||
* might be encountered in old backup files, so restore
|
||||
* it in that case. It is never part of live metadata
|
||||
* though, so only vgcfgrestore needs to be concerned
|
||||
* by this case.
|
||||
*/
|
||||
s |= PARTIAL_VG;
|
||||
} else if (!flags[f].description && (type & STATUS_FLAG)) {
|
||||
log_err("Unknown status flag '%s'.", cv->v.str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1166,7 +1166,7 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
if (!pvmetadatacopies)
|
||||
return 1;
|
||||
|
||||
alignment = pe_align() << SECTOR_SHIFT;
|
||||
alignment = pe_align(pv) << SECTOR_SHIFT;
|
||||
disk_size = pv->size << SECTOR_SHIFT;
|
||||
pe_start <<= SECTOR_SHIFT;
|
||||
pe_end <<= SECTOR_SHIFT;
|
||||
@@ -1333,7 +1333,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
|
||||
/* Set pe_start to first aligned sector after any metadata
|
||||
* areas that begin before pe_start */
|
||||
pv->pe_start = pe_align();
|
||||
pv->pe_start = pe_align(pv);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (pv->dev == mdac->area.dev &&
|
||||
@@ -1342,9 +1342,9 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
(pv->pe_start << SECTOR_SHIFT))) {
|
||||
pv->pe_start = (mdac->area.start + mdac->area.size)
|
||||
>> SECTOR_SHIFT;
|
||||
adjustment = pv->pe_start % pe_align();
|
||||
adjustment = pv->pe_start % pe_align(pv);
|
||||
if (adjustment)
|
||||
pv->pe_start += (pe_align() - adjustment);
|
||||
pv->pe_start += (pe_align(pv) - adjustment);
|
||||
}
|
||||
}
|
||||
if (!add_da
|
||||
|
||||
@@ -194,11 +194,6 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
else
|
||||
log_error("Couldn't find device with uuid '%s'.",
|
||||
buffer);
|
||||
|
||||
if (partial_mode())
|
||||
vg->status |= PARTIAL_VG;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
|
||||
@@ -211,6 +206,9 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pv->dev)
|
||||
pv->status |= MISSING_PV;
|
||||
|
||||
/* Late addition */
|
||||
_read_int64(pvn, "dev_size", &pv->size);
|
||||
|
||||
@@ -243,6 +241,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
pv->pe_size = vg->extent_size;
|
||||
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->pe_align = 0;
|
||||
pv->fmt = fid->fmt;
|
||||
|
||||
/* Fix up pv size if missing or impossibly large */
|
||||
@@ -799,11 +798,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
|
||||
dm_hash_destroy(pv_hash);
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
vg->status &= ~LVM_WRITE;
|
||||
vg->status |= LVM_READ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finished.
|
||||
*/
|
||||
|
||||
@@ -315,9 +315,6 @@ static int _lock_for_cluster(unsigned char cmd, uint32_t flags, const char *name
|
||||
args[0] = flags & 0x7F; /* Maskoff lock flags */
|
||||
args[1] = flags & 0xC0; /* Bitmap flags */
|
||||
|
||||
if (partial_mode())
|
||||
args[1] |= LCK_PARTIAL_MODE;
|
||||
|
||||
if (mirror_in_sync())
|
||||
args[1] |= LCK_MIRROR_NOSYNC_MODE;
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
/*
|
||||
* Additional lock bits for cluster communication
|
||||
*/
|
||||
#define LCK_PARTIAL_MODE 0x00000001U /* Running in partial mode */
|
||||
#define LCK_MIRROR_NOSYNC_MODE 0x00000002U /* Mirrors don't require sync */
|
||||
#define LCK_DMEVENTD_MONITOR_MODE 0x00000004U /* Register with dmeventd */
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ static struct str_list _log_dev_alias;
|
||||
|
||||
static int _verbose_level = VERBOSE_BASE_LEVEL;
|
||||
static int _test = 0;
|
||||
static int _partial = 0;
|
||||
static int _md_filtering = 0;
|
||||
static int _pvmove = 0;
|
||||
static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */
|
||||
@@ -154,11 +153,6 @@ void init_test(int level)
|
||||
_test = level;
|
||||
}
|
||||
|
||||
void init_partial(int level)
|
||||
{
|
||||
_partial = level;
|
||||
}
|
||||
|
||||
void init_md_filtering(int level)
|
||||
{
|
||||
_md_filtering = level;
|
||||
@@ -254,11 +248,6 @@ int test_mode()
|
||||
return _test;
|
||||
}
|
||||
|
||||
int partial_mode()
|
||||
{
|
||||
return _partial;
|
||||
}
|
||||
|
||||
int md_filtering()
|
||||
{
|
||||
return _md_filtering;
|
||||
|
||||
@@ -64,7 +64,6 @@ void fin_syslog(void);
|
||||
|
||||
void init_verbose(int level);
|
||||
void init_test(int level);
|
||||
void init_partial(int level);
|
||||
void init_md_filtering(int level);
|
||||
void init_pvmove(int level);
|
||||
void init_full_scan_done(int level);
|
||||
@@ -84,7 +83,6 @@ void init_error_message_produced(int error_message_produced);
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
|
||||
int test_mode(void);
|
||||
int partial_mode(void);
|
||||
int md_filtering(void);
|
||||
int pvmove_mode(void);
|
||||
int full_scan_done(void);
|
||||
|
||||
@@ -71,6 +71,13 @@ struct pv_segment;
|
||||
//#define PRECOMMITTED 0x00200000U /* VG - internal use only */
|
||||
#define CONVERTING 0x00400000U /* LV */
|
||||
|
||||
#define MISSING_PV 0x00800000U /* PV */
|
||||
#define PARTIAL_LV 0x01000000U /* LV - derived flag, not
|
||||
written out in metadata*/
|
||||
|
||||
//#define POSTORDER_FLAG 0x02000000U /* Not a real flag, reserved for
|
||||
// temporary use inside vg_read. */
|
||||
|
||||
#define LVM_READ 0x00000100U /* LV VG */
|
||||
#define LVM_WRITE 0x00000200U /* LV VG */
|
||||
#define CLUSTERED 0x00000400U /* VG */
|
||||
@@ -168,6 +175,7 @@ struct physical_volume {
|
||||
uint64_t pe_start;
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_alloc_count;
|
||||
unsigned long pe_align;
|
||||
|
||||
struct list segments; /* Ordered pv_segments covering complete PV */
|
||||
struct list tags;
|
||||
@@ -563,6 +571,7 @@ uint64_t pv_pe_start(const pv_t *pv);
|
||||
uint32_t pv_pe_count(const pv_t *pv);
|
||||
uint32_t pv_pe_alloc_count(const pv_t *pv);
|
||||
|
||||
int vg_missing_pv_count(const vg_t *vg);
|
||||
uint32_t vg_status(const vg_t *vg);
|
||||
#define vg_is_clustered(vg) (vg_status((vg)) & CLUSTERED)
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "display.h"
|
||||
#include "locking.h"
|
||||
#include "archiver.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
@@ -64,9 +65,25 @@ static struct pv_list *_find_pv_in_vg(const struct volume_group *vg,
|
||||
static struct physical_volume *_find_pv_in_vg_by_uuid(const struct volume_group *vg,
|
||||
const struct id *id);
|
||||
|
||||
unsigned long pe_align(void)
|
||||
unsigned long pe_align(struct physical_volume *pv)
|
||||
{
|
||||
return MAX(65536UL, lvm_getpagesize()) >> SECTOR_SHIFT;
|
||||
if (pv->pe_align)
|
||||
goto out;
|
||||
|
||||
pv->pe_align = MAX(65536UL, lvm_getpagesize()) >> SECTOR_SHIFT;
|
||||
|
||||
/*
|
||||
* Align to chunk size of underlying md device if present
|
||||
*/
|
||||
if (pv->dev &&
|
||||
find_config_tree_bool(pv->fmt->cmd, "devices/md_chunk_alignment",
|
||||
DEFAULT_MD_CHUNK_ALIGNMENT))
|
||||
pv->pe_align = MAX(pv->pe_align,
|
||||
dev_md_chunk_size(pv->fmt->cmd->sysfs_dir,
|
||||
pv->dev));
|
||||
|
||||
out:
|
||||
return pv->pe_align;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,8 +143,8 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
|
||||
|
||||
/* FIXME Do proper rounding-up alignment? */
|
||||
/* Reserved space for label; this holds 0 for PVs created by LVM1 */
|
||||
if (pv->pe_start < pe_align())
|
||||
pv->pe_start = pe_align();
|
||||
if (pv->pe_start < pe_align(pv))
|
||||
pv->pe_start = pe_align(pv);
|
||||
|
||||
/*
|
||||
* pe_count must always be calculated by pv_setup
|
||||
@@ -317,9 +334,9 @@ int vg_remove_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct pv_list *pvl;
|
||||
int ret = 1;
|
||||
|
||||
if (!vg || !consistent || (vg_status(vg) & PARTIAL_VG)) {
|
||||
log_error("Volume group \"%s\" not found or inconsistent.",
|
||||
vg_name);
|
||||
if (!vg || !consistent || vg_missing_pv_count(vg)) {
|
||||
log_error("Volume group \"%s\" not found, is inconsistent "
|
||||
"or has PVs missing.", vg_name);
|
||||
log_error("Consider vgreduce --removemissing if metadata "
|
||||
"is inconsistent.");
|
||||
return 0;
|
||||
@@ -471,19 +488,15 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg;
|
||||
struct dm_pool *mem = cmd->mem;
|
||||
int consistent = 0;
|
||||
int old_partial;
|
||||
|
||||
if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
|
||||
return_NULL;
|
||||
|
||||
/* is this vg name already in use ? */
|
||||
old_partial = partial_mode();
|
||||
init_partial(1);
|
||||
if (vg_read(cmd, vg_name, NULL, &consistent)) {
|
||||
log_err("A volume group called '%s' already exists.", vg_name);
|
||||
goto bad;
|
||||
}
|
||||
init_partial(old_partial);
|
||||
|
||||
if (!id_create(&vg->id)) {
|
||||
log_err("Couldn't create uuid for volume group '%s'.", vg_name);
|
||||
@@ -771,7 +784,7 @@ static void _free_pv(struct dm_pool *mem, struct physical_volume *pv)
|
||||
dm_pool_free(mem, pv);
|
||||
}
|
||||
|
||||
static struct physical_volume *_alloc_pv(struct dm_pool *mem)
|
||||
static struct physical_volume *_alloc_pv(struct dm_pool *mem, struct device *dev)
|
||||
{
|
||||
struct physical_volume *pv = dm_pool_zalloc(mem, sizeof(*pv));
|
||||
|
||||
@@ -787,7 +800,9 @@ static struct physical_volume *_alloc_pv(struct dm_pool *mem)
|
||||
pv->pe_start = 0;
|
||||
pv->pe_count = 0;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->pe_align = 0;
|
||||
pv->fmt = NULL;
|
||||
pv->dev = dev;
|
||||
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
@@ -808,7 +823,7 @@ static struct physical_volume *_pv_create(const struct format_type *fmt,
|
||||
uint64_t pvmetadatasize, struct list *mdas)
|
||||
{
|
||||
struct dm_pool *mem = fmt->cmd->mem;
|
||||
struct physical_volume *pv = _alloc_pv(mem);
|
||||
struct physical_volume *pv = _alloc_pv(mem, dev);
|
||||
|
||||
if (!pv)
|
||||
return NULL;
|
||||
@@ -821,8 +836,6 @@ static struct physical_volume *_pv_create(const struct format_type *fmt,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
pv->dev = dev;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", pv_dev_name(pv));
|
||||
goto bad;
|
||||
@@ -1174,6 +1187,157 @@ int vgs_are_compatible(struct cmd_context *cmd __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct _lv_postorder_baton {
|
||||
int (*fn)(struct logical_volume *lv, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static int _lv_postorder_visit(struct logical_volume *,
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data);
|
||||
|
||||
static int _lv_postorder_level(struct logical_volume *lv, void *data)
|
||||
{
|
||||
struct _lv_postorder_baton *baton = data;
|
||||
int r =_lv_postorder_visit(lv, baton->fn, baton->data);
|
||||
lv->status |= POSTORDER_FLAG;
|
||||
return r;
|
||||
};
|
||||
|
||||
static int _lv_each_dependency(struct logical_volume *lv,
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data)
|
||||
{
|
||||
int i, s;
|
||||
struct lv_segment *lvseg;
|
||||
|
||||
struct logical_volume *deps[] = {
|
||||
lv->snapshot ? lv->snapshot->origin : 0,
|
||||
lv->snapshot ? lv->snapshot->cow : 0 };
|
||||
for (i = 0; i < sizeof(deps) / sizeof(*deps); ++i) {
|
||||
if (deps[i] && !fn(deps[i], data))
|
||||
return_0;
|
||||
}
|
||||
|
||||
list_iterate_items(lvseg, &lv->segments) {
|
||||
if (lvseg->log_lv && !fn(lvseg->log_lv, data))
|
||||
return_0;
|
||||
for (s = 0; s < lvseg->area_count; ++s) {
|
||||
if (seg_type(lvseg, s) == AREA_LV && !fn(seg_lv(lvseg,s), data))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
|
||||
{
|
||||
if (!(lv->status & POSTORDER_FLAG))
|
||||
return 1;
|
||||
lv->status &= ~POSTORDER_FLAG;
|
||||
|
||||
if (!_lv_each_dependency(lv, _lv_postorder_cleanup, data))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_postorder_visit(struct logical_volume *lv,
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data)
|
||||
{
|
||||
struct _lv_postorder_baton baton;
|
||||
int r;
|
||||
|
||||
if (lv->status & POSTORDER_FLAG)
|
||||
return 1;
|
||||
|
||||
baton.fn = fn;
|
||||
baton.data = data;
|
||||
r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
|
||||
if (r) {
|
||||
r = fn(lv, data);
|
||||
log_verbose("visited %s", lv->name);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will walk the LV dependency graph in depth-first order and in the
|
||||
* postorder, call a callback function "fn". The void *data is passed along all
|
||||
* the calls. The callback may return zero to indicate an error and terminate
|
||||
* the depth-first walk. The error is propagated to return value of
|
||||
* _lv_postorder.
|
||||
*/
|
||||
static int _lv_postorder(struct logical_volume *lv,
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data)
|
||||
{
|
||||
int r;
|
||||
r = _lv_postorder_visit(lv, fn, data);
|
||||
_lv_postorder_cleanup(lv, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct _lv_mark_if_partial_baton {
|
||||
int partial;
|
||||
};
|
||||
|
||||
static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data)
|
||||
{
|
||||
struct _lv_mark_if_partial_baton *baton = data;
|
||||
if (lv->status & PARTIAL_LV)
|
||||
baton->partial = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
|
||||
{
|
||||
int s;
|
||||
struct _lv_mark_if_partial_baton baton;
|
||||
struct lv_segment *lvseg;
|
||||
|
||||
list_iterate_items(lvseg, &lv->segments) {
|
||||
for (s = 0; s < lvseg->area_count; ++s) {
|
||||
if (seg_type(lvseg, s) == AREA_PV) {
|
||||
if (seg_pv(lvseg, s)->status & MISSING_PV)
|
||||
lv->status |= PARTIAL_LV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
baton.partial = 0;
|
||||
_lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton);
|
||||
|
||||
if (baton.partial)
|
||||
lv->status |= PARTIAL_LV;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_mark_if_partial(struct logical_volume *lv)
|
||||
{
|
||||
return _lv_postorder(lv, _lv_mark_if_partial_single, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is
|
||||
* propagated transitively, so LVs referencing other LVs are marked
|
||||
* partial as well, if any of their referenced LVs are marked partial.
|
||||
*/
|
||||
static int _vg_mark_partial_lvs(struct volume_group *vg)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv = lvl->lv;
|
||||
if (!_lv_mark_if_partial(lv))
|
||||
return_0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_validate(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
@@ -1278,8 +1442,13 @@ int vg_write(struct volume_group *vg)
|
||||
return_0;
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
log_error("Cannot change metadata for partial volume group %s",
|
||||
vg->name);
|
||||
log_error("Cannot update partial volume group %s.", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg_missing_pv_count(vg) && !vg->cmd->handles_missing_pvs) {
|
||||
log_error("Cannot update volume group %s while physical "
|
||||
"volumes are missing.", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1478,9 +1647,20 @@ static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_missing_pv_count(const vg_t *vg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pv_list *pvl;
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->status & MISSING_PV)
|
||||
++ ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Caller sets consistent to 1 if it's safe for vg_read to correct
|
||||
* inconsistent metadata on disk (i.e. the VG write lock is held).
|
||||
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
|
||||
* This guarantees only consistent metadata is returned.
|
||||
* If consistent is 0, caller must check whether consistent == 1 on return
|
||||
* and take appropriate action if it isn't (e.g. abort; get write lock
|
||||
* and call vg_read again).
|
||||
@@ -1519,6 +1699,11 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if ((correct_vg = lvmcache_get_vg(vgid, precommitted))) {
|
||||
if (vg_missing_pv_count(correct_vg)) {
|
||||
log_verbose("There are %d physical volumes missing.",
|
||||
vg_missing_pv_count(correct_vg));
|
||||
_vg_mark_partial_lvs(correct_vg);
|
||||
}
|
||||
*consistent = 1;
|
||||
return correct_vg;
|
||||
}
|
||||
@@ -1614,7 +1799,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (list_size(&correct_vg->pvs) != list_size(pvids)) {
|
||||
if (list_size(&correct_vg->pvs) != list_size(pvids)
|
||||
+ vg_missing_pv_count(correct_vg)) {
|
||||
log_debug("Cached VG %s had incorrect PV list",
|
||||
vgname);
|
||||
|
||||
@@ -1623,6 +1809,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
else
|
||||
correct_vg = NULL;
|
||||
} else list_iterate_items(pvl, &correct_vg->pvs) {
|
||||
if (pvl->pv->status & MISSING_PV)
|
||||
continue;
|
||||
if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
|
||||
log_debug("Cached VG %s had incorrect PV list",
|
||||
vgname);
|
||||
@@ -1705,15 +1893,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
if (!*consistent)
|
||||
return correct_vg;
|
||||
|
||||
/* Don't touch partial volume group metadata */
|
||||
/* Should be fixed manually with vgcfgbackup/restore etc. */
|
||||
if ((correct_vg->status & PARTIAL_VG)) {
|
||||
log_error("Inconsistent metadata copies found for "
|
||||
"partial volume group %s", vgname);
|
||||
*consistent = 0;
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
/* Don't touch if vgids didn't match */
|
||||
if (inconsistent_vgid) {
|
||||
log_error("Inconsistent metadata UUIDs found for "
|
||||
@@ -1752,6 +1931,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (vg_missing_pv_count(correct_vg)) {
|
||||
log_verbose("There are %d physical volumes missing.",
|
||||
vg_missing_pv_count(correct_vg));
|
||||
_vg_mark_partial_lvs(correct_vg);
|
||||
}
|
||||
|
||||
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
|
||||
log_error("WARNING: Interrupted pvmove detected in "
|
||||
"volume group %s", correct_vg->name);
|
||||
@@ -1811,11 +1996,10 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
if ((vg = _vg_read(cmd, NULL, vgid,
|
||||
&consistent, precommitted)) &&
|
||||
!strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
|
||||
|
||||
if (!consistent) {
|
||||
log_error("Volume group %s metadata is "
|
||||
"inconsistent", vg->name);
|
||||
if (!partial_mode())
|
||||
return NULL;
|
||||
}
|
||||
return vg;
|
||||
}
|
||||
@@ -1843,6 +2027,7 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
if ((vg = _vg_read(cmd, vgname, vgid, &consistent,
|
||||
precommitted)) &&
|
||||
!strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
|
||||
|
||||
if (!consistent) {
|
||||
log_error("Volume group %s metadata is "
|
||||
"inconsistent", vgname);
|
||||
@@ -1976,7 +2161,6 @@ static int _get_pvs(struct cmd_context *cmd, struct list **pvslist)
|
||||
struct list *vgids;
|
||||
struct volume_group *vg;
|
||||
int consistent = 0;
|
||||
int old_partial;
|
||||
int old_pvmove;
|
||||
|
||||
lvmcache_label_scan(cmd, 0);
|
||||
@@ -1998,9 +2182,7 @@ static int _get_pvs(struct cmd_context *cmd, struct list **pvslist)
|
||||
|
||||
/* Read every VG to ensure cache consistency */
|
||||
/* Orphan VG is last on list */
|
||||
old_partial = partial_mode();
|
||||
old_pvmove = pvmove_mode();
|
||||
init_partial(1);
|
||||
init_pvmove(1);
|
||||
list_iterate_items(strl, vgids) {
|
||||
vgid = strl->str;
|
||||
@@ -2025,7 +2207,6 @@ static int _get_pvs(struct cmd_context *cmd, struct list **pvslist)
|
||||
list_add(results, pvh);
|
||||
}
|
||||
init_pvmove(old_pvmove);
|
||||
init_partial(old_partial);
|
||||
|
||||
if (pvslist)
|
||||
*pvslist = results;
|
||||
|
||||
@@ -61,6 +61,14 @@
|
||||
//#define MIRROR_NOTSYNCED 0x00080000U /* LV */
|
||||
#define ACTIVATE_EXCL 0x00100000U /* LV - internal use only */
|
||||
#define PRECOMMITTED 0x00200000U /* VG - internal use only */
|
||||
//#define CONVERTING 0x00400000U /* LV */
|
||||
|
||||
//#define MISSING_PV 0x00800000U /* PV */
|
||||
//#define PARTIAL_LV 0x01000000U /* LV - derived flag, not
|
||||
// written out in metadata*/
|
||||
|
||||
#define POSTORDER_FLAG 0x02000000U /* Not a real flag, reserved for
|
||||
temporary use inside vg_read. */
|
||||
|
||||
//#define LVM_READ 0x00000100U /* LV VG */
|
||||
//#define LVM_WRITE 0x00000200U /* LV VG */
|
||||
@@ -239,7 +247,7 @@ struct format_handler {
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
unsigned long pe_align(void);
|
||||
unsigned long pe_align(struct physical_volume *pv);
|
||||
int vg_validate(struct volume_group *vg);
|
||||
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
@@ -179,7 +179,7 @@ int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage)
|
||||
/* Place this one at the end */
|
||||
mirrored_seg->areas[i-1] = area;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -491,7 +491,6 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
struct logical_volume *detached_log_lv = NULL;
|
||||
struct logical_volume *lv1 = NULL;
|
||||
struct lv_segment *mirrored_seg = first_seg(lv);
|
||||
struct lv_segment_area area;
|
||||
uint32_t old_area_count = mirrored_seg->area_count;
|
||||
uint32_t new_area_count = mirrored_seg->area_count;
|
||||
struct lv_list *lvl;
|
||||
|
||||
@@ -439,7 +439,7 @@ static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_
|
||||
else
|
||||
repstr[2] = '-';
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
if (vg_missing_pv_count(vg))
|
||||
repstr[3] = 'p';
|
||||
else
|
||||
repstr[3] = '-';
|
||||
|
||||
@@ -300,12 +300,16 @@ in \fBlvm\fP (8).
|
||||
.TP
|
||||
\fBactivation\fP \(em Settings affecting device-mapper activation
|
||||
.IP
|
||||
\fBmissing_stripe_filler\fP \(em When activating an incomplete
|
||||
logical volume in partial mode, this missing data is replaced
|
||||
with this device. It could perhaps be a block device that always
|
||||
returns an error when it is accessed, or one that always
|
||||
returns zeros. See \fBlvcreate\fP (8) for how to create
|
||||
such devices.
|
||||
\fBmissing_stripe_filler\fP \(em When activating an incomplete logical
|
||||
volume in partial mode, this option dictates how the missing data is
|
||||
replaced. A value of "error" will cause activation to create error
|
||||
mappings for the missing data, meaning that read access to missing
|
||||
portions of the volume will result in I/O errors. You can instead also
|
||||
use a device path, and in that case this device will be used in place of
|
||||
missing stripes. However, note that using anything other than
|
||||
"error" with mirrored or snapshotted volumes is likely to result in data
|
||||
corruption. For instructions on how to create a device that always
|
||||
returns zeros, see \fBlvcreate\fP (8).
|
||||
.IP
|
||||
\fBmirror_region_size\fP \(em Unit size in KB for copy operations
|
||||
when mirroring.
|
||||
|
||||
@@ -18,11 +18,13 @@ See \fBlvm\fP for common options.
|
||||
Removes all empty physical volumes if none are given on command line.
|
||||
.TP
|
||||
.I \-\-removemissing
|
||||
Removes all missing physical volumes from the volume group and makes
|
||||
the volume group consistent again.
|
||||
Removes all missing physical volumes from the volume group, if there are no
|
||||
logical volumes allocated on those. This resumes normal operation of the volume
|
||||
group (new logical volumes may again be created, changed and so on).
|
||||
|
||||
It's a good idea to run this option with --test first to find out what it
|
||||
would remove before running it for real.
|
||||
If this is not possible (there are logical volumes referencing the missing
|
||||
physical volumes) and you cannot or do not want to remove them manually, you
|
||||
can run this option with --force to have vgreduce remove any partial LVs.
|
||||
|
||||
Any logical volumes and dependent snapshots that were partly on the
|
||||
missing disks get removed completely. This includes those parts
|
||||
|
||||
@@ -850,13 +850,15 @@ xx(vgreduce,
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--mirrorsonly]\n"
|
||||
"\t[--removemissing]\n"
|
||||
"\t[-f|--force]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tVolumeGroupName\n"
|
||||
"\t[PhysicalVolumePath...]\n",
|
||||
|
||||
all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG)
|
||||
all_ARG, autobackup_ARG, force_ARG, mirrorsonly_ARG, removemissing_ARG,
|
||||
test_ARG)
|
||||
|
||||
xx(vgremove,
|
||||
"Remove volume group(s)",
|
||||
|
||||
@@ -710,13 +710,13 @@ static int _get_settings(struct cmd_context *cmd)
|
||||
cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
|
||||
cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
|
||||
cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0;
|
||||
cmd->partial_activation = 0;
|
||||
|
||||
if (arg_count(cmd, partial_ARG)) {
|
||||
init_partial(1);
|
||||
cmd->partial_activation = 1;
|
||||
log_print("Partial mode. Incomplete volume groups will "
|
||||
"be activated read-only.");
|
||||
} else
|
||||
init_partial(0);
|
||||
}
|
||||
|
||||
if (arg_count(cmd, ignorelockingfailure_ARG))
|
||||
init_ignorelockingfailure(1);
|
||||
@@ -826,6 +826,7 @@ static void _apply_settings(struct cmd_context *cmd)
|
||||
|
||||
cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG,
|
||||
cmd->current_settings.fmt);
|
||||
cmd->handles_missing_pvs = 0;
|
||||
}
|
||||
|
||||
static char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
@@ -31,6 +31,8 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
|
||||
&lvremove_single);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
|
||||
/* FIXME Check partition type is LVM unless --force is given */
|
||||
|
||||
/* Is there a pv here already? */
|
||||
/* FIXME Use partial mode here? */
|
||||
pv = pv_read(cmd, name, NULL, NULL, 0);
|
||||
|
||||
/*
|
||||
@@ -272,13 +271,11 @@ static int pvcreate_validate_params(struct cmd_context *cmd,
|
||||
if (arg_count(cmd, restorefile_ARG)) {
|
||||
pp->restorefile = arg_str_value(cmd, restorefile_ARG, "");
|
||||
/* The uuid won't already exist */
|
||||
init_partial(1);
|
||||
if (!(vg = backup_read_vg(cmd, NULL, pp->restorefile))) {
|
||||
log_error("Unable to read volume group from %s",
|
||||
pp->restorefile);
|
||||
return 0;
|
||||
}
|
||||
init_partial(0);
|
||||
if (!(existing_pv = find_pv_in_vg_by_uuid(vg, pp->idp))) {
|
||||
log_error("Can't find uuid %s in backup file %s",
|
||||
uuid, pp->restorefile);
|
||||
|
||||
@@ -96,8 +96,7 @@ int vgcfgbackup(struct cmd_context *cmd, int argc, char **argv)
|
||||
int ret;
|
||||
char *last_filename = NULL;
|
||||
|
||||
if (partial_mode())
|
||||
init_pvmove(1);
|
||||
init_pvmove(1);
|
||||
|
||||
ret = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, &last_filename,
|
||||
&vg_backup_single);
|
||||
|
||||
103
tools/vgreduce.c
103
tools/vgreduce.c
@@ -16,7 +16,7 @@
|
||||
#include "tools.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
|
||||
static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
|
||||
{
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
@@ -31,8 +31,9 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
|
||||
log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name);
|
||||
|
||||
if (pvl->pv->pe_alloc_count) {
|
||||
log_error("LVs still present on PV with UUID %s: Can't remove "
|
||||
"from VG %s", uuid, vg->name);
|
||||
if (!silent)
|
||||
log_error("LVs still present on PV with UUID %s: "
|
||||
"Can't remove from VG %s", uuid, vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -130,16 +131,43 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct lv_list *lvl;
|
||||
int r = 1;
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs)
|
||||
if (lvl->lv->status & PARTIAL_LV) {
|
||||
log_warn("WARNING: Partial LV %s needs to be repaired "
|
||||
"or removed. ", lvl->lv->name);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
cmd->handles_missing_pvs = 1;
|
||||
log_warn("WARNING: There are still partial LVs in VG %s.", vg->name);
|
||||
log_warn("To remove them unconditionally use: vgreduce --removemissing --force.");
|
||||
log_warn("Proceeding to remove empty missing PVs.");
|
||||
}
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev && !(pvl->pv->status & MISSING_PV))
|
||||
continue;
|
||||
if (r && !_remove_pv(vg, pvl, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh, *pvht;
|
||||
struct list *lvh, *lvht;
|
||||
struct pv_list *pvl;
|
||||
struct lv_list *lvl, *lvl2, *lvlt;
|
||||
struct logical_volume *lv;
|
||||
struct physical_volume *pv;
|
||||
struct lv_segment *seg, *mirrored_seg;
|
||||
struct lv_segment_area area;
|
||||
unsigned s;
|
||||
uint32_t mimages, remove_log;
|
||||
int list_unsafe, only_mirror_images_found;
|
||||
@@ -183,20 +211,8 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove missing PVs */
|
||||
list_iterate_safe(pvh, pvht, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if (pvl->pv->dev)
|
||||
continue;
|
||||
if (!_remove_pv(vg, pvl))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* VG is now consistent */
|
||||
vg->status &= ~PARTIAL_VG;
|
||||
vg->status |= LVM_WRITE;
|
||||
|
||||
init_partial(0);
|
||||
if (!_consolidate_vg(cmd, vg))
|
||||
return_0;
|
||||
|
||||
/* FIXME Recovery. For now people must clean up by hand. */
|
||||
|
||||
@@ -209,14 +225,11 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
if (!test_mode()) {
|
||||
/* Suspend lvs_changed */
|
||||
init_partial(1);
|
||||
if (!suspend_lvs(cmd, &lvs_changed)) {
|
||||
stack;
|
||||
init_partial(0);
|
||||
vg_revert(vg);
|
||||
return 0;
|
||||
}
|
||||
init_partial(0);
|
||||
}
|
||||
|
||||
if (!vg_commit(vg)) {
|
||||
@@ -440,26 +453,26 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
char *vg_name;
|
||||
int ret = 1;
|
||||
int consistent = 1;
|
||||
int fixed = 1;
|
||||
int repairing = arg_count(cmd, removemissing_ARG);
|
||||
|
||||
if (!argc && !arg_count(cmd, removemissing_ARG)) {
|
||||
if (!argc && !repairing) {
|
||||
log_error("Please give volume group name and "
|
||||
"physical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!argc && arg_count(cmd, removemissing_ARG)) {
|
||||
|
||||
if (!argc && repairing) {
|
||||
log_error("Please give volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, mirrorsonly_ARG) &&
|
||||
!arg_count(cmd, removemissing_ARG)) {
|
||||
if (arg_count(cmd, mirrorsonly_ARG) && !repairing) {
|
||||
log_error("--mirrorsonly requires --removemissing");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc == 1 && !arg_count(cmd, all_ARG)
|
||||
&& !arg_count(cmd, removemissing_ARG)) {
|
||||
if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) {
|
||||
log_error("Please enter physical volume paths or option -a");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
@@ -470,7 +483,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc > 1 && arg_count(cmd, removemissing_ARG)) {
|
||||
if (argc > 1 && repairing) {
|
||||
log_error("Please only specify the volume group");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
@@ -491,8 +504,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent) &&
|
||||
!arg_count(cmd, removemissing_ARG)) {
|
||||
if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent)
|
||||
&& !repairing) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
@@ -503,16 +516,15 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, removemissing_ARG)) {
|
||||
if (vg && consistent) {
|
||||
if (repairing) {
|
||||
if (vg && consistent && !vg_missing_pv_count(vg)) {
|
||||
log_error("Volume group \"%s\" is already consistent",
|
||||
vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
init_partial(1);
|
||||
consistent = 0;
|
||||
consistent = !arg_count(cmd, force_ARG);
|
||||
if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
@@ -523,16 +535,17 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!archive(vg)) {
|
||||
init_partial(0);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!_make_vg_consistent(cmd, vg)) {
|
||||
init_partial(0);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (arg_count(cmd, force_ARG)) {
|
||||
if (!_make_vg_consistent(cmd, vg)) {
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
} else
|
||||
fixed = _consolidate_vg(cmd, vg);
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||
log_error("Failed to write out a consistent VG for %s",
|
||||
@@ -543,7 +556,9 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
backup(vg);
|
||||
|
||||
log_print("Wrote out consistent volume group %s", vg_name);
|
||||
if (fixed)
|
||||
log_print("Wrote out consistent volume group %s",
|
||||
vg_name);
|
||||
|
||||
} else {
|
||||
if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) {
|
||||
|
||||
Reference in New Issue
Block a user