mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-27 00:23:49 +03:00
Compare commits
11 Commits
dm_v1_02_1
...
dm_v1_02_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83edf68ff9 | ||
|
|
c7588f91dd | ||
|
|
30b432adc5 | ||
|
|
7c9733eb5d | ||
|
|
a223c3fea3 | ||
|
|
d5250f4901 | ||
|
|
25f29f4712 | ||
|
|
382af5563d | ||
|
|
8cf3d165d3 | ||
|
|
0fd6ce546f | ||
|
|
b881c372bc |
14
WHATS_NEW
14
WHATS_NEW
@@ -1,5 +1,17 @@
|
||||
Version 2.02.21 -
|
||||
Version 2.02.22 - 13th February 2007
|
||||
====================================
|
||||
Correct -b and -P on a couple of man pages.
|
||||
Add global/units to example.conf.
|
||||
Fix loading of segment_libraries.
|
||||
If a PV reappears after it was removed from its VG, make it an orphan.
|
||||
Don't update metadata automatically if VGIDs don't match.
|
||||
Fix some vgreduce --removemissing command line validation.
|
||||
|
||||
Version 2.02.21 - 30th January 2007
|
||||
===================================
|
||||
Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring.
|
||||
Fix vgsplit to handle mirrors.
|
||||
Reorder fields in reporting field definitions.
|
||||
Fix vgs to treat args as VGs even when PV fields are displayed.
|
||||
Fix md signature check to handle both endiannesses.
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
Version 1.02.18 - 13th February 2007
|
||||
====================================
|
||||
Improve dmeventd messaging protocol: drain pipe and tag messages.
|
||||
|
||||
Version 1.02.17 - 29th January 2007
|
||||
===================================
|
||||
Add recent reporting options to dmsetup man page.
|
||||
|
||||
@@ -146,6 +146,7 @@ static LIST_INIT(_dso_registry);
|
||||
|
||||
/* Structure to keep parsed register variables from client message. */
|
||||
struct message_data {
|
||||
char *id;
|
||||
char *dso_name; /* Name of DSO. */
|
||||
char *device_uuid; /* Mapped device path. */
|
||||
union {
|
||||
@@ -320,6 +321,8 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
|
||||
/* Free message memory. */
|
||||
static void _free_message(struct message_data *message_data)
|
||||
{
|
||||
if (message_data->id)
|
||||
dm_free(message_data->id);
|
||||
if (message_data->dso_name)
|
||||
dm_free(message_data->dso_name);
|
||||
|
||||
@@ -342,7 +345,8 @@ static int _parse_message(struct message_data *message_data)
|
||||
* Retrieve application identifier, mapped device
|
||||
* path and events # string from message.
|
||||
*/
|
||||
if (_fetch_string(&message_data->dso_name, &p, ' ') &&
|
||||
if (_fetch_string(&message_data->id, &p, ' ') &&
|
||||
_fetch_string(&message_data->dso_name, &p, ' ') &&
|
||||
_fetch_string(&message_data->device_uuid, &p, ' ') &&
|
||||
_fetch_string(&message_data->events.str, &p, ' ') &&
|
||||
_fetch_string(&message_data->timeout.str, &p, ' ')) {
|
||||
@@ -875,8 +879,8 @@ static struct dso_data *_load_dso(struct message_data *data)
|
||||
syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,
|
||||
dlerr);
|
||||
data->msg->size =
|
||||
dm_asprintf(&(data->msg->data), "%s dlopen failed: %s",
|
||||
data->dso_name, dlerr);
|
||||
dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s",
|
||||
data->id, data->dso_name, dlerr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1056,7 +1060,8 @@ static int _registered_device(struct message_data *message_data,
|
||||
{
|
||||
struct dm_event_daemon_message *msg = message_data->msg;
|
||||
|
||||
const char *fmt = "%s %s %u";
|
||||
const char *fmt = "%s %s %s %u";
|
||||
const char *id = message_data->id;
|
||||
const char *dso = thread->dso_data->dso_name;
|
||||
const char *dev = thread->device.uuid;
|
||||
unsigned events = ((thread->status == DM_THREAD_RUNNING)
|
||||
@@ -1066,7 +1071,7 @@ static int _registered_device(struct message_data *message_data,
|
||||
if (msg->data)
|
||||
dm_free(msg->data);
|
||||
|
||||
msg->size = dm_asprintf(&(msg->data), fmt, dso, dev, events);
|
||||
msg->size = dm_asprintf(&(msg->data), fmt, id, dso, dev, events);
|
||||
|
||||
_unlock_mutex();
|
||||
|
||||
@@ -1180,7 +1185,8 @@ static int _get_timeout(struct message_data *message_data)
|
||||
_lock_mutex();
|
||||
if ((thread = _lookup_thread_status(message_data))) {
|
||||
msg->size =
|
||||
dm_asprintf(&(msg->data), "%" PRIu32, thread->timeout);
|
||||
dm_asprintf(&(msg->data), "%s %" PRIu32, message_data->id,
|
||||
thread->timeout);
|
||||
} else {
|
||||
msg->data = NULL;
|
||||
msg->size = 0;
|
||||
@@ -1375,17 +1381,32 @@ static int _handle_request(struct dm_event_daemon_message *msg,
|
||||
static int _do_process_request(struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int ret;
|
||||
char *answer;
|
||||
static struct message_data message_data;
|
||||
|
||||
/* Parse the message. */
|
||||
memset(&message_data, 0, sizeof(message_data));
|
||||
message_data.msg = msg;
|
||||
if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
|
||||
if (msg->cmd == DM_EVENT_CMD_HELLO) {
|
||||
ret = 0;
|
||||
answer = dm_strdup(msg->data);
|
||||
if (answer) {
|
||||
msg->size = dm_asprintf(&(msg->data), "%s HELLO", answer);
|
||||
dm_free(answer);
|
||||
} else {
|
||||
msg->size = 0;
|
||||
msg->data = NULL;
|
||||
}
|
||||
} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
|
||||
stack;
|
||||
ret = -EINVAL;
|
||||
} else
|
||||
ret = _handle_request(msg, &message_data);
|
||||
|
||||
msg->cmd = ret;
|
||||
if (!msg->data)
|
||||
msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
|
||||
|
||||
_free_message(&message_data);
|
||||
|
||||
return ret;
|
||||
@@ -1405,16 +1426,9 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
if (!_client_read(fifos, &msg))
|
||||
return;
|
||||
|
||||
msg.cmd = _do_process_request(&msg);
|
||||
if (!msg.data) {
|
||||
msg.data = dm_strdup(strerror(-msg.cmd));
|
||||
if (msg.data)
|
||||
msg.size = strlen(msg.data) + 1;
|
||||
else {
|
||||
msg.size = 0;
|
||||
stack;
|
||||
}
|
||||
}
|
||||
/* _do_process_request fills in msg (if memory allows for
|
||||
data, otherwise just cmd and size = 0) */
|
||||
_do_process_request(&msg);
|
||||
|
||||
if (!_client_write(fifos, &msg))
|
||||
stack;
|
||||
|
||||
@@ -20,6 +20,7 @@ enum dm_event_command {
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
DM_EVENT_CMD_HELLO,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
|
||||
static int _sequence_nr = 0;
|
||||
|
||||
struct dm_event_handler {
|
||||
char *dso;
|
||||
|
||||
@@ -182,6 +184,21 @@ enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler
|
||||
return dmevh->mask;
|
||||
}
|
||||
|
||||
static int _check_message_id(struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int pid, seq_nr;
|
||||
|
||||
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
||||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
||||
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
||||
"Expected %d:%d but received %s", getpid(),
|
||||
_sequence_nr, msg->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* daemon_read
|
||||
* @fifos
|
||||
@@ -260,11 +277,28 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
|
||||
size_t size = 2 * sizeof(uint32_t) + msg->size;
|
||||
char *buf = alloca(size);
|
||||
char drainbuf[128];
|
||||
struct timeval tval = { 0, 0 };
|
||||
|
||||
*((uint32_t *)buf) = htonl(msg->cmd);
|
||||
*((uint32_t *)buf + 1) = htonl(msg->size);
|
||||
memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
|
||||
|
||||
/* drain the answer fifo */
|
||||
while (1) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->server, &fds);
|
||||
tval.tv_usec = 100;
|
||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||
if ((ret < 0) && (errno != EINTR)) {
|
||||
log_error("Unable to talk to event daemon");
|
||||
return 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
read(fifos->server, drainbuf, 127);
|
||||
}
|
||||
|
||||
while (bytes < size) {
|
||||
do {
|
||||
/* Watch daemon write FIFO to be ready for output. */
|
||||
@@ -301,7 +335,7 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
|
||||
{
|
||||
const char *dso = dso_name ? dso_name : "";
|
||||
const char *dev = dev_name ? dev_name : "";
|
||||
const char *fmt = "%s %s %u %" PRIu32;
|
||||
const char *fmt = "%d:%d %s %s %u %" PRIu32;
|
||||
int msg_size;
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
@@ -310,8 +344,10 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
|
||||
* into ASCII message string.
|
||||
*/
|
||||
msg->cmd = cmd;
|
||||
if ((msg_size = dm_asprintf(&(msg->data), fmt, dso, dev, evmask,
|
||||
timeout)) < 0) {
|
||||
if (cmd == DM_EVENT_CMD_HELLO)
|
||||
fmt = "%d:%d HELLO";
|
||||
if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr,
|
||||
dso, dev, evmask, timeout)) < 0) {
|
||||
log_error("_daemon_talk: message allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -326,10 +362,14 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
do {
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
} while (!_check_message_id(msg));
|
||||
|
||||
_sequence_nr++;
|
||||
|
||||
return (int32_t) msg->cmd;
|
||||
}
|
||||
@@ -507,7 +547,9 @@ static int _do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
|
||||
ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
|
||||
if (!ret)
|
||||
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
|
||||
|
||||
/* what is the opposite of init? */
|
||||
_dtr_client(&fifos);
|
||||
@@ -521,7 +563,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
int ret = 1, err;
|
||||
const char *uuid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
@@ -551,7 +593,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
int ret = 1, err;
|
||||
const char *uuid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
@@ -598,15 +640,20 @@ static char *_fetch_string(char **src, const int delimiter)
|
||||
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
char **uuid, enum dm_event_mask *evmask)
|
||||
{
|
||||
char *id = NULL;
|
||||
char *p = msg->data;
|
||||
|
||||
if ((*dso_name = _fetch_string(&p, ' ')) &&
|
||||
if ((id = _fetch_string(&p, ' ')) &&
|
||||
(*dso_name = _fetch_string(&p, ' ')) &&
|
||||
(*uuid = _fetch_string(&p, ' '))) {
|
||||
*evmask = atoi(p);
|
||||
|
||||
dm_free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id)
|
||||
dm_free(id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -621,12 +668,12 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
*/
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
const char *uuid = NULL;
|
||||
char *reply_dso = NULL, *reply_uuid = NULL;
|
||||
enum dm_event_mask reply_mask;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
enum dm_event_mask reply_mask = 0;
|
||||
struct dm_task *dmt = NULL;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
@@ -696,9 +743,17 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
static char *_skip_string(char *src, const int delimiter)
|
||||
{
|
||||
src = srtchr(src, delimiter);
|
||||
if (src && *(src + 1))
|
||||
return src + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
@@ -710,13 +765,20 @@ int dm_event_set_timeout(const char *device_path, uint32_t timeout)
|
||||
int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
|
||||
0, 0)))
|
||||
*timeout = atoi(msg.data);
|
||||
0, 0))) {
|
||||
char *p = _skip_string(msg.data, ' ');
|
||||
if (!p) {
|
||||
log_error("malformed reply from dmeventd '%s'\n",
|
||||
msg.data);
|
||||
return -EIO;
|
||||
}
|
||||
*timeout = atoi(p);
|
||||
}
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
return ret;
|
||||
|
||||
@@ -188,6 +188,9 @@ global {
|
||||
# command. Defaults to off.
|
||||
test = 0
|
||||
|
||||
# Default value for --units argument
|
||||
units = "h"
|
||||
|
||||
# Whether or not to communicate with the kernel device-mapper.
|
||||
# Set to 0 if you want to use the tools to manipulate LVM metadata
|
||||
# without activating any logical volumes.
|
||||
|
||||
@@ -754,7 +754,6 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
struct config_value *cv;
|
||||
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
|
||||
void *lib;
|
||||
struct list *sgtl, *tmp;
|
||||
struct segment_type *segtype2;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@@ -781,18 +780,16 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
segtype->library = lib;
|
||||
list_add(&cmd->segtypes, &segtype->list);
|
||||
|
||||
list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
|
||||
segtype2 = list_item(sgtl, struct segment_type);
|
||||
if (!strcmp(segtype2->name, segtype->name)) {
|
||||
log_error("Duplicate segment type %s: "
|
||||
"unloading shared library %s",
|
||||
segtype->name, cv->v.str);
|
||||
list_del(&segtype->list);
|
||||
segtype->ops->destroy(segtype);
|
||||
dlclose(lib);
|
||||
break;
|
||||
}
|
||||
|
||||
list_iterate_items(segtype2, &cmd->segtypes) {
|
||||
if ((segtype == segtype2) ||
|
||||
strcmp(segtype2->name, segtype->name))
|
||||
continue;
|
||||
log_error("Duplicate segment type %s: "
|
||||
"unloading shared library %s",
|
||||
segtype->name, cv->v.str);
|
||||
list_del(&segtype->list);
|
||||
segtype->ops->destroy(segtype);
|
||||
dlclose(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,6 +963,30 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
return vg;
|
||||
}
|
||||
|
||||
static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
list_iterate_items(pvl2, all_pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
/* PV is not on list so add it. Note that we don't copy it. */
|
||||
if (!(pvl2 = dm_pool_zalloc(vg->cmd->mem, sizeof(*pvl2)))) {
|
||||
log_error("pv_list allocation for '%s' failed",
|
||||
dev_name(pvl->pv->dev));
|
||||
return 0;
|
||||
}
|
||||
pvl2->pv = pvl->pv;
|
||||
list_add(all_pvs, &pvl2->list);
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -982,9 +1006,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
struct volume_group *vg, *correct_vg = NULL;
|
||||
struct metadata_area *mda;
|
||||
int inconsistent = 0;
|
||||
int inconsistent_vgid = 0;
|
||||
int use_precommitted = precommitted;
|
||||
struct list *pvids;
|
||||
struct pv_list *pvl;
|
||||
struct pv_list *pvl, *pvl2;
|
||||
struct list all_pvs;
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!*vgname) {
|
||||
if (use_precommitted) {
|
||||
@@ -1069,6 +1096,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
list_init(&all_pvs);
|
||||
|
||||
/* Failed to find VG where we expected it - full scan and retry */
|
||||
if (!correct_vg) {
|
||||
inconsistent = 0;
|
||||
@@ -1104,13 +1133,25 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
if (!correct_vg) {
|
||||
correct_vg = vg;
|
||||
if (!_update_pv_list(&all_pvs, correct_vg))
|
||||
return_NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((char *)vg->id.uuid,
|
||||
(char *)correct_vg->id.uuid, ID_LEN)) {
|
||||
inconsistent = 1;
|
||||
inconsistent_vgid = 1;
|
||||
}
|
||||
|
||||
/* FIXME Also ensure contents same - checksums same? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
if (vg->seqno > correct_vg->seqno) {
|
||||
if (!_update_pv_list(&all_pvs, vg))
|
||||
return_NULL;
|
||||
correct_vg = vg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1143,17 +1184,42 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata copies found - updating "
|
||||
"to use version %u", correct_vg->seqno);
|
||||
/* Don't touch if vgids didn't match */
|
||||
if (inconsistent_vgid) {
|
||||
log_error("Inconsistent metadata UUIDs found for "
|
||||
"volume group %s", vgname);
|
||||
*consistent = 0;
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata found for VG %s - updating "
|
||||
"to use version %u", vgname, correct_vg->seqno);
|
||||
|
||||
if (!vg_write(correct_vg)) {
|
||||
log_error("Automatic metadata correction failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!vg_commit(correct_vg)) {
|
||||
log_error("Automatic metadata correction commit "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(pvl, &all_pvs) {
|
||||
list_iterate_items(pvl2, &correct_vg->pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
|
||||
return_NULL;
|
||||
log_error("Removing PV %s (%s) that no longer belongs to VG %s",
|
||||
dev_name(pvl->pv->dev), uuid, correct_vg->name);
|
||||
if (!pv_write_orphan(cmd, pvl->pv))
|
||||
return_NULL;
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
|
||||
@@ -1433,3 +1499,25 @@ int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volu
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
const char *old_vg_name = pv->vg_name;
|
||||
|
||||
pv->vg_name = ORPHAN;
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
|
||||
log_error("Failed to clear metadata from physical "
|
||||
"volume \"%s\" after removal from \"%s\"",
|
||||
dev_name(pv->dev), old_vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -423,6 +423,7 @@ struct list *get_vgids(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector);
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
/* pe_start and pe_end relate to any existing data so that new metadata
|
||||
* areas can avoid overlap */
|
||||
|
||||
@@ -868,11 +868,11 @@ static const struct dm_report_object_type _report_types[] = {
|
||||
|
||||
#define STR DM_REPORT_FIELD_TYPE_STRING
|
||||
#define NUM DM_REPORT_FIELD_TYPE_NUMBER
|
||||
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp, desc},
|
||||
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), width, id, head, &_ ## func ## _disp, desc},
|
||||
|
||||
static struct dm_report_field_type _fields[] = {
|
||||
#include "columns.h"
|
||||
{0, "", 0, "", 0, 0, NULL, NULL},
|
||||
{0, 0, 0, 0, "", "", NULL, NULL},
|
||||
};
|
||||
|
||||
#undef STR
|
||||
|
||||
@@ -12,7 +12,7 @@ lvchange \- change attributes of a logical volume
|
||||
[\-\-ignorelockingfailure]
|
||||
[\-\-monitor {y|n}]
|
||||
[\-M/\-\-persistent y/n] [\-\-minor minor]
|
||||
[\-P/\-\-partial y/n]
|
||||
[\-P/\-\-partial]
|
||||
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[\-\-refresh]
|
||||
[\-t/\-\-test]
|
||||
|
||||
@@ -5,7 +5,7 @@ pvmove \- move physical extents
|
||||
.B pvmove
|
||||
[\-\-abort]
|
||||
[\-\-alloc AllocationPolicy]
|
||||
[\-\-background]
|
||||
[\-b/\-\-background]
|
||||
[\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
|
||||
[\-n/\-\-name LogicalVolume]
|
||||
[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
|
||||
@@ -73,7 +73,7 @@ type of on-disk metadata. Metadata can be converted using \fBvgconvert\fP(8).
|
||||
.I \-\-abort
|
||||
Abort any moves in progress.
|
||||
.TP
|
||||
.I \-\-background
|
||||
.I \-b, \-\-background
|
||||
Run the daemon in the background.
|
||||
.TP
|
||||
.I \-i, \-\-interval Seconds
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
. /etc/init.d/functions
|
||||
|
||||
VGCHANGE="/usr/sbin/vgchange"
|
||||
WARN=1
|
||||
|
||||
start()
|
||||
{
|
||||
for ret in 0
|
||||
do
|
||||
ret=0
|
||||
# TODO do we want to separate out already active groups only?
|
||||
VGS=`vgs --noheadings -o name`
|
||||
for vg in $VGS
|
||||
@@ -40,50 +40,58 @@ start()
|
||||
fi
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
return $ret
|
||||
return $ret
|
||||
}
|
||||
|
||||
|
||||
stop()
|
||||
{
|
||||
for ret in 0
|
||||
do
|
||||
ret=0
|
||||
# TODO do we want to separate out already active groups only?
|
||||
if test "$WARN" = "1"; then
|
||||
echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override."
|
||||
return 1
|
||||
fi
|
||||
VGS=`vgs --noheadings -o name`
|
||||
for vg in $VGS
|
||||
do
|
||||
if ! action "Starting monitoring for VG $vg:" $VGCHANGE --monitor n $vg
|
||||
if ! action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n $vg
|
||||
then
|
||||
ret=$?
|
||||
fi
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
ret=1
|
||||
result=1
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
ret=$?
|
||||
result=$?
|
||||
;;
|
||||
|
||||
force-stop)
|
||||
WARN=0
|
||||
stop
|
||||
result=$?
|
||||
;;
|
||||
|
||||
stop)
|
||||
test "$runlevel" = "0" && WARN=0
|
||||
test "$runlevel" = "6" && WARN=0
|
||||
stop
|
||||
ret=$?
|
||||
result=$?
|
||||
;;
|
||||
|
||||
restart)
|
||||
WARN=0
|
||||
if stop
|
||||
then
|
||||
start
|
||||
fi
|
||||
ret=$?
|
||||
result=$?
|
||||
;;
|
||||
|
||||
status)
|
||||
@@ -91,8 +99,8 @@ case "$1" in
|
||||
;;
|
||||
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|status}"
|
||||
echo $"Usage: $0 {start|stop|restart|status|force-stop}"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $ret
|
||||
exit $result
|
||||
|
||||
@@ -427,13 +427,13 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
int ret = 1;
|
||||
int consistent = 1;
|
||||
|
||||
if (!argc & !arg_count(cmd, removemissing_ARG)) {
|
||||
if (!argc && !arg_count(cmd, removemissing_ARG)) {
|
||||
log_error("Please give volume group name and "
|
||||
"physical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!argc & arg_count(cmd, removemissing_ARG)) {
|
||||
if (!argc && arg_count(cmd, removemissing_ARG)) {
|
||||
log_error("Please give volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,9 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
|
||||
if ((lv->status & SNAPSHOT))
|
||||
continue;
|
||||
|
||||
if ((lv->status & MIRRORED))
|
||||
continue;
|
||||
|
||||
/* Ensure all the PVs used by this LV remain in the same */
|
||||
/* VG as each other */
|
||||
vg_with = NULL;
|
||||
@@ -161,6 +164,48 @@ static int _move_snapshots(struct volume_group *vg_from,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _move_mirrors(struct volume_group *vg_from,
|
||||
struct volume_group *vg_to)
|
||||
{
|
||||
struct list *lvh, *lvht;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
int i, seg_in, log_in;
|
||||
|
||||
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
if (!(lv->status & MIRRORED))
|
||||
continue;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
seg_in = 0;
|
||||
for (i = 0; i < seg->area_count; i++)
|
||||
if (_lv_is_in_vg(vg_to, seg_lv(seg, i)))
|
||||
seg_in++;
|
||||
|
||||
log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
|
||||
|
||||
if ((seg_in && seg_in < seg->area_count) ||
|
||||
(seg_in && seg->log_lv && !log_in) ||
|
||||
(!seg_in && seg->log_lv && log_in)) {
|
||||
log_error("Mirror %s split", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg_in == seg->area_count && log_in) {
|
||||
list_del(lvh);
|
||||
list_add(&vg_to->lvs, lvh);
|
||||
|
||||
vg_from->lv_count--;
|
||||
vg_to->lv_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
char *vg_name_from, *vg_name_to;
|
||||
@@ -275,6 +320,10 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!(_move_snapshots(vg_from, vg_to)))
|
||||
goto error;
|
||||
|
||||
/* Move required mirrors across */
|
||||
if (!(_move_mirrors(vg_from, vg_to)))
|
||||
goto error;
|
||||
|
||||
/* FIXME Split mdas properly somehow too! */
|
||||
/* Currently we cheat by sharing the format instance and relying on
|
||||
* vg_write to ignore mdas outside the VG! Done this way, with text
|
||||
|
||||
Reference in New Issue
Block a user