mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-03 08:23:48 +03:00
Compare commits
28 Commits
old-dm_v1_
...
v1_02_02
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab931b177d | ||
|
|
9aa3465513 | ||
|
|
6c70fc1a6c | ||
|
|
1ccc39962a | ||
|
|
99c941fc85 | ||
|
|
19729fdcc2 | ||
|
|
02e17998ce | ||
|
|
459e00c67a | ||
|
|
292f665650 | ||
|
|
93bbb79569 | ||
|
|
273e724f2b | ||
|
|
5d2615c56f | ||
|
|
bfaaf21330 | ||
|
|
dcb8415b7a | ||
|
|
699e1c75ce | ||
|
|
465b6e613e | ||
|
|
05fa105855 | ||
|
|
d7a0cdebe5 | ||
|
|
b049ab31eb | ||
|
|
6db4dcff7a | ||
|
|
3eeaef00ec | ||
|
|
8bf4c38a00 | ||
|
|
3a32b09ad1 | ||
|
|
6315982752 | ||
|
|
374a171e82 | ||
|
|
fc5d801f91 | ||
|
|
5146641848 | ||
|
|
cdd0ac42cf |
20
WHATS_NEW
20
WHATS_NEW
@@ -1,5 +1,21 @@
|
||||
Version 2.02.00 -
|
||||
===================================
|
||||
Version 2.02.02
|
||||
====================================
|
||||
Add some activation logic to remove_mirror_images().
|
||||
lvconvert can remove specified PVs from a mirror.
|
||||
lvconvert turns an existing LV into a mirror.
|
||||
Allow signed mirrors arguments.
|
||||
Move create_mirror_log() into toollib.
|
||||
Determine parallel PVs to avoid with ALLOC_NORMAL allocation.
|
||||
Fix lv_empty.
|
||||
|
||||
Version 2.02.01 - 23rd November 2005
|
||||
====================================
|
||||
Fix lvdisplay cmdline to accept snapshots.
|
||||
Fix open RO->RW promotion.
|
||||
Fix missing vg_revert in lvcreate error path.
|
||||
|
||||
Version 2.02.00 - 10th November 2005
|
||||
====================================
|
||||
Extend allocation areas to avoid overflow with contiguous with other PVs.
|
||||
Stop lvcreate attempting to wipe zero or error segments.
|
||||
Added new lvs table attributes.
|
||||
|
||||
14
WHATS_NEW_DM
14
WHATS_NEW_DM
@@ -1,4 +1,16 @@
|
||||
Version 1.02.00 -
|
||||
Version 1.02.02 -
|
||||
=============================
|
||||
Export dm_task_update_nodes.
|
||||
Use names instead of numbers in messages when ioctls fail.
|
||||
|
||||
Version 1.02.01 - 23 Nov 2005
|
||||
=============================
|
||||
Resume snapshot-origins last.
|
||||
Drop leading zeros from dm_format_dev.
|
||||
Suppress attempt to reload identical table.
|
||||
Additional LVM- prefix matching for transitional period.
|
||||
|
||||
Version 1.02.00 - 10 Nov 2005
|
||||
=============================
|
||||
Added activation functions to library.
|
||||
Added return macros.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
dm_register_for_event
|
||||
dm_unregister_for_event
|
||||
dm_get_registered_device
|
||||
dm_set_event_timeout
|
||||
dm_get_event_timeout
|
||||
|
||||
@@ -1,51 +1,56 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the device-mapper userspace tools.
|
||||
#
|
||||
# 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 General Public License v.2.
|
||||
# of the GNU Lesser General Public License v.2.1.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
interface = @interface@
|
||||
|
||||
TARGETS = dmevent dmeventd
|
||||
INSTALL_TYPE = install_dynamic
|
||||
SOURCES = libdevmapper-event.c \
|
||||
dmeventd.c
|
||||
|
||||
SOURCES = noop.c
|
||||
CLEAN_TARGETS = dmevent.o dmeventd.o
|
||||
LIB_STATIC = libdevmapper-event.a
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
LIB_SHARED = libdmeventdnoop.dylib
|
||||
LIB_SHARED = libdevmapper-event.dylib
|
||||
else
|
||||
LIB_SHARED = libdmeventdnoop.so
|
||||
LIB_SHARED = libdevmapper-event.so
|
||||
endif
|
||||
|
||||
LDFLAGS += -ldl -ldevmapper -lmultilog
|
||||
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
libdmeventdnoop.so: noop.o
|
||||
.PHONY: install_dynamic install_static
|
||||
|
||||
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmevent.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog $(LIBS)
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -lpthread -ldmevent $(LIBS)
|
||||
ifeq ("@STATIC_LINK@", "yes")
|
||||
INSTALL_TYPE += install_static
|
||||
endif
|
||||
|
||||
install: $(INSTALL_TYPE)
|
||||
|
||||
.PHONY: install_dynamic
|
||||
install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION)
|
||||
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
|
||||
$(includedir)/libdevmapper-event.h
|
||||
|
||||
install_dynamic: dmeventd
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd
|
||||
install_static: libdevmapper-event.a
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/libdevmapper-event.a.$(LIB_VERSION)
|
||||
$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a
|
||||
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdm-event.h"
|
||||
#include "libmultilog.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
|
||||
static char default_dso_name[] = "noop"; /* default DSO is noop */
|
||||
static int default_reg = 1; /* default action is register */
|
||||
static uint32_t timeout;
|
||||
|
||||
struct event_ops {
|
||||
int (*dm_register_for_event)(char *dso_name, char *device,
|
||||
enum event_type event_types);
|
||||
int (*dm_unregister_for_event)(char *dso_name, char *device,
|
||||
enum event_type event_types);
|
||||
int (*dm_get_registered_device)(char **dso_name, char **device,
|
||||
enum event_type *event_types, int next);
|
||||
int (*dm_set_event_timeout)(char *device, uint32_t time);
|
||||
int (*dm_get_event_timeout)(char *device, uint32_t *time);
|
||||
};
|
||||
|
||||
/* Display help. */
|
||||
static void print_usage(char *name)
|
||||
{
|
||||
char *cmd = strrchr(name, '/');
|
||||
|
||||
cmd = cmd ? cmd + 1 : name;
|
||||
printf("Usage::\n"
|
||||
"%s [options] <device>\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -d <dso> Specify the DSO to use.\n"
|
||||
" -h Print this usage.\n"
|
||||
" -l List registered devices.\n"
|
||||
" -r Register for event (default).\n"
|
||||
" -t <timeout> (un)register for timeout event.\n"
|
||||
" -u Unregister for event.\n"
|
||||
"\n", cmd);
|
||||
}
|
||||
|
||||
/* Parse command line arguments. */
|
||||
static int parse_argv(int argc, char **argv, char **dso_name_arg,
|
||||
char **device_arg, int *reg, int *list)
|
||||
{
|
||||
int c;
|
||||
const char *options = "d:hlrt:u";
|
||||
|
||||
while ((c = getopt(argc, argv, options)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
*dso_name_arg = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
*list = 1;
|
||||
break;
|
||||
case 'r':
|
||||
*reg = 1;
|
||||
break;
|
||||
case 't':
|
||||
events = TIMEOUT;
|
||||
if (sscanf(optarg, "%"SCNu32, &timeout) != 1){
|
||||
fprintf(stderr, "invalid timeout '%s'\n",
|
||||
optarg);
|
||||
timeout = 0;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
*reg = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option '%c'.\n"
|
||||
"Try '-h' for help.\n", c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
if (!*list) {
|
||||
fprintf(stderr, "You need to specify a device.\n");
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
*device_arg = argv[optind];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int lookup_symbol(void *dl, void **symbol, const char *name)
|
||||
{
|
||||
if ((*symbol = dlsym(dl, name)))
|
||||
return 1;
|
||||
|
||||
fprintf(stderr, "error looking up %s symbol: %s\n", name, dlerror());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lookup_symbols(void *dl, struct event_ops *e)
|
||||
{
|
||||
return lookup_symbol(dl, (void *) &e->dm_register_for_event,
|
||||
"dm_register_for_event") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_unregister_for_event,
|
||||
"dm_unregister_for_event") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_get_registered_device,
|
||||
"dm_get_registered_device") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_set_event_timeout,
|
||||
"dm_set_event_timeout") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_get_event_timeout,
|
||||
"dm_get_event_timeout");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *dl;
|
||||
struct event_ops e;
|
||||
int list = 0, next = 0, ret, reg = default_reg;
|
||||
char *device, *device_arg = NULL, *dso_name, *dso_name_arg = NULL;
|
||||
|
||||
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, ®, &list))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (device_arg) {
|
||||
if (!(device = strdup(device_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else
|
||||
device = NULL;
|
||||
|
||||
if (dso_name_arg) {
|
||||
if (!(dso_name = strdup(dso_name_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (!(dso_name = strdup(default_dso_name)))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* FIXME: use -v/-q options to set this */
|
||||
multilog_add_type(standard, NULL);
|
||||
multilog_init_verbose(standard, _LOG_DEBUG);
|
||||
|
||||
if (!(dl = dlopen("libdmevent.so", RTLD_NOW))){
|
||||
fprintf(stderr, "Cannot dlopen libdmevent.so: %s\n", dlerror());
|
||||
goto out;
|
||||
}
|
||||
if (!(lookup_symbols(dl, &e)))
|
||||
goto out;
|
||||
if (list) {
|
||||
while (1) {
|
||||
if ((ret= e.dm_get_registered_device(&dso_name,
|
||||
&device,
|
||||
&events, next)))
|
||||
break;
|
||||
printf("%s %s 0x%x", dso_name, device, events);
|
||||
if (events & TIMEOUT){
|
||||
if ((ret = e.dm_get_event_timeout(device,
|
||||
&timeout))) {
|
||||
ret = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
printf(" %"PRIu32"\n", timeout);
|
||||
} else
|
||||
printf("\n");
|
||||
if (device_arg)
|
||||
break;
|
||||
|
||||
next = 1;
|
||||
}
|
||||
|
||||
ret = (ret && device_arg) ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((ret = reg ? e.dm_register_for_event(dso_name, device, events) :
|
||||
e.dm_unregister_for_event(dso_name, device, events))) {
|
||||
fprintf(stderr, "Failed to %sregister %s: %s\n",
|
||||
reg ? "": "un", device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
if (reg && (events & TIMEOUT) &&
|
||||
((ret = e.dm_set_event_timeout(device, timeout)))){
|
||||
fprintf(stderr, "Failed to set timeout for %s: %s\n",
|
||||
device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
printf("%s %sregistered successfully.\n",
|
||||
device, reg ? "" : "un");
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
multilog_del_type(standard);
|
||||
|
||||
if (device)
|
||||
free(device);
|
||||
if (dso_name)
|
||||
free(dso_name);
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
12
daemons/dmeventd/dmeventd.h
Normal file
12
daemons/dmeventd/dmeventd.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef __DMEVENTD_DOT_H__
|
||||
#define __DMEVENTD_DOT_H__
|
||||
|
||||
#define EXIT_LOCKFILE_INUSE 2
|
||||
#define EXIT_DESC_CLOSE_FAILURE 3
|
||||
#define EXIT_OPEN_PID_FAILURE 4
|
||||
#define EXIT_FIFO_FAILURE 5
|
||||
#define EXIT_CHDIR_FAILURE 6
|
||||
|
||||
void dmeventd(void);
|
||||
|
||||
#endif /* __DMEVENTD_DOT_H__ */
|
||||
465
daemons/dmeventd/libdevmapper-event.c
Normal file
465
daemons/dmeventd/libdevmapper-event.c
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
//#include "libmultilog.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* Set by any of the external fxns the first time one of them is called */
|
||||
/* FIXME Unused */
|
||||
// static int _logging = 0;
|
||||
|
||||
/* Fetch a string off src and duplicate it into *dest. */
|
||||
/* FIXME: move to seperate module to share with the daemon. */
|
||||
static const char delimiter = ' ';
|
||||
static char *fetch_string(char **src)
|
||||
{
|
||||
char *p, *ret;
|
||||
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((ret = strdup(*src)))
|
||||
*src += strlen(ret) + 1;
|
||||
|
||||
if (p)
|
||||
*p = delimiter;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse a device message from the daemon. */
|
||||
static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
char **device, enum dm_event_type *events)
|
||||
{
|
||||
char *p = msg->msg;
|
||||
|
||||
if ((*dso_name = fetch_string(&p)) &&
|
||||
(*device = fetch_string(&p))) {
|
||||
*events = atoi(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Read message from daemon. */
|
||||
static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
errno = 0;
|
||||
/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
|
||||
/* FIXME errno != EOF? RTFM! */
|
||||
while (bytes < sizeof(*msg) && errno != EOF) {
|
||||
do {
|
||||
/* Watch daemon read FIFO for input. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->server, &fds);
|
||||
/* FIXME Check for errors e.g. EBADF */
|
||||
} while (select(fifos->server+1, &fds, NULL, NULL, NULL) != 1);
|
||||
|
||||
ret = read(fifos->server, msg, sizeof(*msg) - bytes);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
}
|
||||
|
||||
// log_print("%s: \"%s\"\n", __func__, msg->msg);
|
||||
return bytes == sizeof(*msg);
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
|
||||
// log_print("%s: \"%s\"\n", __func__, msg->msg);
|
||||
errno = 0;
|
||||
/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
|
||||
while (bytes < sizeof(*msg) && errno != EIO) {
|
||||
do {
|
||||
/* Watch daemon write FIFO to be ready for output. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->client, &fds);
|
||||
/* FIXME Check for errors e.g. EBADF */
|
||||
} while (select(fifos->client +1, NULL, &fds, NULL, NULL) != 1);
|
||||
|
||||
ret = write(fifos->client, msg, sizeof(*msg) - bytes);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
}
|
||||
|
||||
return bytes == sizeof(*msg);
|
||||
}
|
||||
|
||||
static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg,
|
||||
int cmd, char *dso_name, char *device,
|
||||
enum dm_event_type events, uint32_t timeout)
|
||||
{
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
/*
|
||||
* Set command and pack the arguments
|
||||
* into ASCII message string.
|
||||
*/
|
||||
msg->opcode.cmd = cmd;
|
||||
|
||||
if (sizeof(msg->msg) <= snprintf(msg->msg, sizeof(msg->msg),
|
||||
"%s %s %u %"PRIu32,
|
||||
dso_name ? dso_name : "",
|
||||
device ? device : "",
|
||||
events, timeout)) {
|
||||
stack;
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write command and message to and
|
||||
* read status return code from daemon.
|
||||
*/
|
||||
if (!daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return msg->opcode.status;
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t daemon_running = 0;
|
||||
|
||||
static void daemon_running_signal_handler(int sig)
|
||||
{
|
||||
daemon_running = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* start_daemon
|
||||
*
|
||||
* This function forks off a process (dmeventd) that will handle
|
||||
* the events. A signal must be returned from the child to
|
||||
* indicate when it is ready to handle requests. The parent
|
||||
* (this function) returns 1 if there is a daemon running.
|
||||
*
|
||||
* Returns: 1 on success, 0 otherwise
|
||||
*/
|
||||
static int start_daemon(void)
|
||||
{
|
||||
int pid, ret=0;
|
||||
int old_mask;
|
||||
void *old_hand;
|
||||
|
||||
/* Must be able to acquire signal */
|
||||
old_hand = signal(SIGUSR1, &daemon_running_signal_handler);
|
||||
if (old_hand == SIG_ERR) {
|
||||
log_error("Unable to setup signal handler.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
/* FIXME Deprecated. Try posix sigprocmask instead. */
|
||||
old_mask = siggetmask();
|
||||
old_mask &= ~sigmask(SIGUSR1);
|
||||
old_mask = sigsetmask(old_mask);
|
||||
#endif
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
log_error("Unable to fork.\n");
|
||||
else if (pid) { /* parent waits for child to get ready for requests */
|
||||
int status;
|
||||
|
||||
/* FIXME Better way to do this? */
|
||||
while (!waitpid(pid, &status, WNOHANG) && !daemon_running)
|
||||
sleep(1);
|
||||
|
||||
if (daemon_running) {
|
||||
log_print("dmeventd started.\n");
|
||||
ret = 1;
|
||||
} else {
|
||||
switch (WEXITSTATUS(status)) {
|
||||
case EXIT_LOCKFILE_INUSE:
|
||||
/*
|
||||
* Note, this is ok... we still have daemon
|
||||
* that we can communicate with...
|
||||
*/
|
||||
log_print("Starting dmeventd failed: "
|
||||
"dmeventd already running.\n");
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
log_error("Unable to start dmeventd.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
signal(SIGUSR1, SIG_IGN); /* don't care about error */
|
||||
|
||||
/* dmeventd function is responsible for properly setting **
|
||||
** itself up. It must never return - only exit. This is**
|
||||
** why it is followed by an EXIT_FAILURE */
|
||||
dmeventd();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* FIXME What if old_hand is SIG_ERR? */
|
||||
if (signal(SIGUSR1, old_hand) == SIG_ERR)
|
||||
log_error("Unable to reset signal handler.");
|
||||
sigsetmask(old_mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize client. */
|
||||
static int init_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
/* FIXME Is fifo the most suitable method? */
|
||||
/* FIXME Why not share comms/daemon code with something else e.g. multipath? */
|
||||
|
||||
/* init fifos */
|
||||
memset(fifos, 0, sizeof(*fifos));
|
||||
fifos->client_path = DM_EVENT_FIFO_CLIENT;
|
||||
fifos->server_path = DM_EVENT_FIFO_SERVER;
|
||||
|
||||
/* FIXME The server should be responsible for these, not the client. */
|
||||
/* Create fifos */
|
||||
if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
|
||||
((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
|
||||
log_error("%s: Failed to create a fifo.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Warn/abort if perms are wrong - not something to fix silently. */
|
||||
/* If they were already there, make sure permissions are ok. */
|
||||
if (chmod(fifos->client_path, 0600)) {
|
||||
log_error("Unable to set correct file permissions on %s",
|
||||
fifos->client_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chmod(fifos->server_path, 0600)) {
|
||||
log_error("Unable to set correct file permissions on %s",
|
||||
fifos->server_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the fifo used to read from the daemon.
|
||||
* Allows daemon to create its write fifo...
|
||||
*/
|
||||
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
|
||||
log_error("%s: open server fifo %s\n",
|
||||
__func__, fifos->server_path);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lock out anyone else trying to do communication with the daemon. */
|
||||
/* FIXME Why failure not retry? How do multiple processes communicate? */
|
||||
if (flock(fifos->server, LOCK_EX) < 0){
|
||||
log_error("%s: flock %s\n", __func__, fifos->server_path);
|
||||
close(fifos->server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Anyone listening? If not, errno will be ENXIO */
|
||||
if ((fifos->client = open(fifos->client_path,
|
||||
O_WRONLY | O_NONBLOCK)) < 0) {
|
||||
if (errno != ENXIO) {
|
||||
log_error("%s: open client fifo %s\n",
|
||||
__func__, fifos->client_path);
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Unnecessary if daemon was started before calling this */
|
||||
if (!start_daemon()) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Unnecessary if daemon was started before calling this */
|
||||
/* Daemon is started, retry the open */
|
||||
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
|
||||
if (fifos->client < 0) {
|
||||
log_error("%s: open client fifo %s\n",
|
||||
__func__, fifos->client_path);
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dtr_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
if (flock(fifos->server, LOCK_UN))
|
||||
log_error("flock unlock %s\n", fifos->server_path);
|
||||
|
||||
close(fifos->client);
|
||||
close(fifos->server);
|
||||
}
|
||||
|
||||
/* Check, if a block device exists. */
|
||||
static int device_exists(char *device)
|
||||
{
|
||||
struct stat st_buf;
|
||||
char path2[PATH_MAX];
|
||||
|
||||
if (!device)
|
||||
return 0;
|
||||
|
||||
if (device[0] == '/') /* absolute path */
|
||||
return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
|
||||
|
||||
if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
|
||||
return 0;
|
||||
|
||||
return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
|
||||
}
|
||||
|
||||
/* Handle the event (de)registration call and return negative error codes. */
|
||||
static int do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
char *dso_name, char *device, enum dm_event_type events,
|
||||
uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_fifos fifos;
|
||||
|
||||
/* FIXME Start the daemon here if it's not running e.g. exclusive lock file */
|
||||
|
||||
if (!init_client(&fifos)) {
|
||||
stack;
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
|
||||
|
||||
/* what is the opposite of init? */
|
||||
dtr_client(&fifos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* External library interface. */
|
||||
int dm_event_register(char *dso_name, char *device_path,
|
||||
enum dm_event_type events)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
|
||||
return do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 0);
|
||||
}
|
||||
|
||||
int dm_event_unregister(char *dso_name, char *device_path,
|
||||
enum dm_event_type events)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
|
||||
return do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 0);
|
||||
}
|
||||
|
||||
int dm_event_get_registered_device(char **dso_name, char **device_path,
|
||||
enum dm_event_type *events, int next)
|
||||
{
|
||||
int ret;
|
||||
char *dso_name_arg = NULL, *device_path_arg = NULL;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
&msg, *dso_name, *device_path, *events, 0)))
|
||||
ret = parse_message(&msg, &dso_name_arg, &device_path_arg,
|
||||
events);
|
||||
|
||||
if (next){
|
||||
if (*dso_name)
|
||||
free(*dso_name);
|
||||
if (*device_path)
|
||||
free(*device_path);
|
||||
*dso_name = dso_name_arg;
|
||||
*device_path = device_path_arg;
|
||||
} else {
|
||||
if (!(*dso_name))
|
||||
*dso_name = dso_name_arg;
|
||||
if (!(*device_path))
|
||||
*device_path = device_path_arg;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dm_event_set_timeout(char *device_path, uint32_t timeout)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
|
||||
NULL, device_path, 0, timeout);
|
||||
}
|
||||
|
||||
int dm_event_get_timeout(char *device_path, uint32_t *timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
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.msg);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
99
daemons/dmeventd/libdevmapper-event.h
Normal file
99
daemons/dmeventd/libdevmapper-event.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that this file is released only as part of a technology preview
|
||||
* and its contents may change in future updates in ways that do not
|
||||
* preserve compatibility.
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMEVENT_H
|
||||
#define LIB_DMEVENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* FIXME This stuff must be configurable. */
|
||||
|
||||
#define DM_EVENT_DAEMON "/sbin/dmeventd"
|
||||
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
|
||||
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DM_EVENT_DEFAULT_TIMEOUT 10
|
||||
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dm_event_command {
|
||||
DM_EVENT_CMD_ACTIVE = 1,
|
||||
DM_EVENT_CMD_REGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct dm_event_daemon_message {
|
||||
union {
|
||||
unsigned int cmd; /* FIXME Use fixed size. */
|
||||
int status; /* FIXME Use fixed size. */
|
||||
} opcode;
|
||||
char msg[252]; /* FIXME Why is this 252 ? */
|
||||
} __attribute__((packed)); /* FIXME Do this properly! */
|
||||
|
||||
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct dm_event_fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
|
||||
/* Event type definitions. */
|
||||
/* FIXME Use masks to separate the types and provide for extension. */
|
||||
enum dm_event_type {
|
||||
DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x02, /* Report all of them. */
|
||||
|
||||
DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
|
||||
|
||||
DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
|
||||
/* FIXME Use a mask. */
|
||||
#define DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
|
||||
DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
/* FIXME Missing consts? */
|
||||
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
|
||||
int dm_event_unregister(char *dso_name, char *device,
|
||||
enum dm_event_type events);
|
||||
int dm_event_get_registered_device(char **dso_name, char **device,
|
||||
enum dm_event_type *events, int next);
|
||||
int dm_event_set_timeout(char *device, uint32_t timeout);
|
||||
int dm_event_get_timeout(char *device, uint32_t *timeout);
|
||||
|
||||
/* Prototypes for DSO interface. */
|
||||
void process_event(const char *device, enum dm_event_type event);
|
||||
int register_device(const char *device);
|
||||
int unregister_device(const char *device);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Create test devices for dmeventd
|
||||
#
|
||||
|
||||
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
|
||||
|
||||
echo "0 1024 zero" > /tmp/tmp.$$
|
||||
dmsetup create test /tmp/tmp.$$
|
||||
dmsetup create test1 /tmp/tmp.$$
|
||||
|
||||
kill -15 $$
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdm-event.h"
|
||||
#include "libmultilog.h"
|
||||
|
||||
|
||||
void process_event(char *device, enum event_type event)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s, Event %d\n",
|
||||
__FILE__, __func__, __LINE__, device, event);
|
||||
}
|
||||
|
||||
int register_device(char *device)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(char *device)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -845,7 +845,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
dm_tree_node_get_context(dnode))
|
||||
return 1;
|
||||
|
||||
/* FIXME How do we determine whether a pre-existing node need reloading or not? */
|
||||
if (!(lvlayer = dm_pool_alloc(dm->mem, sizeof(*lvlayer)))) {
|
||||
log_error("_add_new_lv_to_dtree: pool alloc failed for %s %s.", lv->name, layer);
|
||||
return 0;
|
||||
|
||||
@@ -418,7 +418,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) {
|
||||
log_error("%s: fstat failed: Has device name changed?", name);
|
||||
dev_close_immediate(dev);
|
||||
dev->open_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -509,11 +508,9 @@ static int _dev_close(struct device *dev, int immediate)
|
||||
if (dev->open_count > 0)
|
||||
dev->open_count--;
|
||||
|
||||
if (immediate && dev->open_count) {
|
||||
if (immediate && dev->open_count)
|
||||
log_debug("%s: Immediate close attempt while still referenced",
|
||||
dev_name(dev));
|
||||
dev->open_count = 0;
|
||||
}
|
||||
|
||||
/* Close unless device is known to belong to a locked VG */
|
||||
if (immediate ||
|
||||
|
||||
@@ -52,7 +52,8 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc);
|
||||
alloc_policy_t alloc,
|
||||
struct list *parallel_areas);
|
||||
|
||||
int lv_add_segment(struct alloc_handle *ah,
|
||||
uint32_t first_area, uint32_t num_areas,
|
||||
@@ -83,4 +84,7 @@ int lv_add_more_mirrored_areas(struct logical_volume *lv,
|
||||
|
||||
void alloc_destroy(struct alloc_handle *ah);
|
||||
|
||||
struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -24,6 +24,18 @@
|
||||
#include "display.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* PVs used by a segment of an LV
|
||||
*/
|
||||
struct seg_pvs {
|
||||
struct list list;
|
||||
|
||||
struct list pvs; /* struct pv_list */
|
||||
|
||||
uint32_t le;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Find first unused LV number.
|
||||
*/
|
||||
@@ -342,13 +354,16 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty an LV
|
||||
* Empty an LV.
|
||||
*/
|
||||
int lv_empty(struct logical_volume *lv)
|
||||
{
|
||||
return _lv_reduce(lv, 0, lv->le_count);
|
||||
return _lv_reduce(lv, lv->le_count, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove given number of extents from LV.
|
||||
*/
|
||||
int lv_reduce(struct logical_volume *lv, uint32_t extents)
|
||||
{
|
||||
return _lv_reduce(lv, extents, 1);
|
||||
@@ -391,6 +406,10 @@ struct alloc_handle {
|
||||
uint32_t log_count; /* Number of parallel 1-extent logs */
|
||||
uint32_t total_area_len; /* Total number of parallel extents */
|
||||
|
||||
struct physical_volume *mirrored_pv; /* FIXME Remove this */
|
||||
uint32_t mirrored_pe; /* FIXME Remove this */
|
||||
struct list *parallel_areas; /* PVs to avoid */
|
||||
|
||||
struct alloced_area log_area; /* Extent used for log */
|
||||
struct list alloced_areas[0]; /* Lists of areas in each stripe */
|
||||
};
|
||||
@@ -404,7 +423,9 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
|
||||
uint32_t mirrors,
|
||||
uint32_t stripes,
|
||||
uint32_t log_count,
|
||||
struct physical_volume *mirrored_pv)
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
struct list *parallel_areas)
|
||||
{
|
||||
struct alloc_handle *ah;
|
||||
uint32_t s, area_count;
|
||||
@@ -458,6 +479,10 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
|
||||
for (s = 0; s < ah->area_count; s++)
|
||||
list_init(&ah->alloced_areas[s]);
|
||||
|
||||
ah->mirrored_pv = mirrored_pv;
|
||||
ah->mirrored_pe = mirrored_pe;
|
||||
ah->parallel_areas = parallel_areas;
|
||||
|
||||
return ah;
|
||||
}
|
||||
|
||||
@@ -646,7 +671,6 @@ static int _check_contiguous(struct lv_segment *prev_lvseg,
|
||||
/*
|
||||
* Choose sets of parallel areas to use, respecting any constraints.
|
||||
*/
|
||||
/* FIXME Also accept existing areas new space must be parallel to */
|
||||
static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
struct list *pvms, struct pv_area **areas,
|
||||
uint32_t areas_size, unsigned can_split,
|
||||
@@ -655,10 +679,15 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
struct pv_area *pva;
|
||||
struct pv_list *pvl;
|
||||
unsigned already_found_one = 0;
|
||||
unsigned contiguous = 0, contiguous_count = 0;
|
||||
unsigned ix;
|
||||
unsigned ix_offset = 0; /* Offset for non-contiguous allocations */
|
||||
uint32_t max_parallel; /* Maximum extents to allocate */
|
||||
uint32_t next_le;
|
||||
struct seg_pvs *spvs;
|
||||
struct list *parallel_pvs;
|
||||
|
||||
/* FIXME Do calculations on free extent counts before selecting space */
|
||||
/* FIXME Select log PV appropriately if there isn't one yet */
|
||||
@@ -676,6 +705,25 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
do {
|
||||
ix = 0;
|
||||
|
||||
parallel_pvs = NULL;
|
||||
max_parallel = needed;
|
||||
|
||||
/*
|
||||
* If there are existing parallel PVs, avoid them and reduce
|
||||
* the maximum we can allocate in one go accordingly.
|
||||
*/
|
||||
if (ah->parallel_areas) {
|
||||
list_iterate_items(spvs, ah->parallel_areas) {
|
||||
next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated;
|
||||
if (next_le >= spvs->le) {
|
||||
if (next_le + max_parallel > spvs->le + spvs->len)
|
||||
max_parallel = spvs->le + spvs->len - next_le;
|
||||
parallel_pvs = &spvs->pvs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the smallest area of each PV that is at least the
|
||||
* size we need into areas array. If there isn't one
|
||||
@@ -686,10 +734,18 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
if (list_empty(&pvm->areas))
|
||||
continue; /* Next PV */
|
||||
|
||||
/* Don't allocate onto the log pv */
|
||||
if ((alloc != ALLOC_ANYWHERE) && ah->log_count &&
|
||||
(pvm->pv == ah->log_area.pv))
|
||||
continue; /* Next PV */
|
||||
if (alloc != ALLOC_ANYWHERE) {
|
||||
/* Don't allocate onto the log pv */
|
||||
if (ah->log_count &&
|
||||
pvm->pv == ah->log_area.pv)
|
||||
continue; /* Next PV */
|
||||
|
||||
/* Avoid PVs used by existing parallel areas */
|
||||
if (parallel_pvs)
|
||||
list_iterate_items(pvl, parallel_pvs)
|
||||
if (pvm->pv == pvl->pv)
|
||||
goto next_pv;
|
||||
}
|
||||
|
||||
already_found_one = 0;
|
||||
/* First area in each list is the largest */
|
||||
@@ -700,17 +756,17 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
pvm->pv,
|
||||
pva, areas)) {
|
||||
contiguous_count++;
|
||||
break; /* Next PV */
|
||||
goto next_pv;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is it big enough on its own? */
|
||||
if ((pva->count < needed - *allocated) &&
|
||||
if ((pva->count < max_parallel - *allocated) &&
|
||||
((!can_split && !ah->log_count) ||
|
||||
(already_found_one &&
|
||||
!(alloc == ALLOC_ANYWHERE))))
|
||||
break; /* Next PV */
|
||||
goto next_pv;
|
||||
|
||||
if (!already_found_one ||
|
||||
alloc == ALLOC_ANYWHERE) {
|
||||
@@ -720,8 +776,9 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
|
||||
areas[ix + ix_offset - 1] = pva;
|
||||
|
||||
break; /* Next PV */
|
||||
goto next_pv;
|
||||
}
|
||||
next_pv:
|
||||
if (ix >= areas_size)
|
||||
break;
|
||||
}
|
||||
@@ -743,7 +800,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
|
||||
/* First time around, use smallest area as log_area */
|
||||
/* FIXME decide which PV to use at top of function instead */
|
||||
if (!_alloc_parallel_area(ah, needed, areas,
|
||||
if (!_alloc_parallel_area(ah, max_parallel, areas,
|
||||
allocated,
|
||||
(ah->log_count && !ah->log_area.len) ?
|
||||
*(areas + ix_offset + ix - 1) :
|
||||
@@ -764,13 +821,11 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
*/
|
||||
static int _allocate(struct alloc_handle *ah,
|
||||
struct volume_group *vg,
|
||||
struct logical_volume *lv, uint32_t status,
|
||||
uint32_t new_extents,
|
||||
struct list *allocatable_pvs,
|
||||
uint32_t stripes, uint32_t mirrors,
|
||||
struct segment_type *segtype,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe)
|
||||
struct logical_volume *lv, uint32_t status,
|
||||
uint32_t new_extents,
|
||||
struct list *allocatable_pvs,
|
||||
uint32_t stripes, uint32_t mirrors,
|
||||
struct segment_type *segtype)
|
||||
{
|
||||
struct pv_area **areas;
|
||||
uint32_t allocated = lv ? lv->le_count : 0;
|
||||
@@ -781,12 +836,12 @@ static int _allocate(struct alloc_handle *ah,
|
||||
struct list *pvms;
|
||||
uint32_t areas_size;
|
||||
|
||||
if (allocated >= new_extents) {
|
||||
if (allocated >= new_extents && !ah->log_count) {
|
||||
log_error("_allocate called with no work to do!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS))
|
||||
if (ah->mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS))
|
||||
can_split = 0;
|
||||
|
||||
if (lv && !list_empty(&lv->segments))
|
||||
@@ -906,7 +961,8 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc)
|
||||
alloc_policy_t alloc,
|
||||
struct list *parallel_areas)
|
||||
{
|
||||
struct alloc_handle *ah;
|
||||
|
||||
@@ -929,15 +985,15 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
alloc = vg->alloc;
|
||||
|
||||
if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
|
||||
stripes, log_count, mirrored_pv))) {
|
||||
stripes, log_count, mirrored_pv,
|
||||
mirrored_pe, parallel_areas))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!segtype_is_virtual(segtype) &&
|
||||
!_allocate(ah, vg, lv, status, (lv ? lv->le_count : 0) + extents,
|
||||
allocatable_pvs,
|
||||
stripes, mirrors, segtype, mirrored_pv, mirrored_pe)) {
|
||||
allocatable_pvs, stripes, mirrors, segtype)) {
|
||||
stack;
|
||||
alloc_destroy(ah);
|
||||
return NULL;
|
||||
@@ -1098,8 +1154,7 @@ int lv_add_more_mirrored_areas(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
break;
|
||||
seg = first_seg(lv);
|
||||
|
||||
old_area_count = seg->area_count;
|
||||
new_area_count = old_area_count + num_extra_areas;
|
||||
@@ -1139,7 +1194,7 @@ int lv_extend(struct logical_volume *lv,
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
|
||||
extents, mirrored_pv, mirrored_pe, status,
|
||||
allocatable_pvs, alloc))) {
|
||||
allocatable_pvs, alloc, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1272,3 +1327,116 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
/* Recursively process each PV used by part of an LV */
|
||||
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len,
|
||||
int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs),
|
||||
struct seg_pvs *spvs)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
uint32_t remaining_seg_len, area_len, area_multiple;
|
||||
|
||||
if (!(seg = find_seg_by_le(lv, le))) {
|
||||
log_error("Failed to find segment for %s extent %" PRIu32,
|
||||
lv->name, le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remaining logical length of segment */
|
||||
remaining_seg_len = seg->len - (le - seg->le);
|
||||
|
||||
if (len > remaining_seg_len)
|
||||
remaining_seg_len = len;
|
||||
|
||||
if (spvs->len > remaining_seg_len)
|
||||
spvs->len = remaining_seg_len;
|
||||
|
||||
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
|
||||
area_len = remaining_seg_len / area_multiple;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_LV) {
|
||||
if (!_for_each_pv(cmd, seg_lv(seg, s),
|
||||
seg_le(seg, s) + (le - seg->le) / area_multiple,
|
||||
area_len, fn, spvs)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else if (seg_type(seg, s) == AREA_PV) {
|
||||
if (!fn(cmd, seg_pvseg(seg, s), spvs)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
|
||||
/* FIXME Don't add again if it's already on the list! */
|
||||
|
||||
if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
|
||||
log_error("pv_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvl->pv = peg->pv;
|
||||
|
||||
/* FIXME Use ordered list to facilitate comparison */
|
||||
list_add(&spvs->pvs, &pvl->list);
|
||||
|
||||
/* FIXME Add mirror logs, snapshot cow LVs etc. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct list of segments of LVs showing which PVs they use.
|
||||
*/
|
||||
struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct list *parallel_areas;
|
||||
struct seg_pvs *spvs;
|
||||
uint32_t current_le = 0;
|
||||
|
||||
if (!(parallel_areas = dm_pool_alloc(cmd->mem, sizeof(*parallel_areas)))) {
|
||||
log_error("parallel_areas allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(parallel_areas);
|
||||
|
||||
do {
|
||||
if (!(spvs = dm_pool_zalloc(cmd->mem, sizeof(*spvs)))) {
|
||||
log_error("allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(&spvs->pvs);
|
||||
|
||||
spvs->le = current_le;
|
||||
spvs->len = lv->le_count - current_le;
|
||||
|
||||
list_add(parallel_areas, &spvs->list);
|
||||
|
||||
/* Find next segment end */
|
||||
/* FIXME Unnecessary nesting! */
|
||||
if (!_for_each_pv(cmd, lv, current_le, lv->le_count, _add_pvs, spvs)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_le = spvs->le + spvs->len;
|
||||
} while (current_le < lv->le_count);
|
||||
|
||||
/* FIXME Merge adjacent segments with identical PV lists (avoids need for contiguous allocation attempts between successful allocations) */
|
||||
|
||||
return parallel_areas;
|
||||
}
|
||||
|
||||
@@ -561,8 +561,14 @@ int create_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors);
|
||||
int remove_all_mirror_images(struct logical_volume *lv);
|
||||
int add_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t num_mirrors,
|
||||
uint32_t existing_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype);
|
||||
|
||||
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct list *removable_pvs, int remove_log);
|
||||
/*
|
||||
* Given mirror image or mirror log segment, find corresponding mirror segment
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "locking.h" /* FIXME Should not be used in this file */
|
||||
|
||||
struct lv_segment *find_mirror_seg(struct lv_segment *seg)
|
||||
{
|
||||
@@ -62,6 +63,9 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
|
||||
|
||||
list_init(&lv_from->segments);
|
||||
|
||||
lv_to->le_count = lv_from->le_count;
|
||||
lv_to->size = lv_from->size;
|
||||
|
||||
lv_from->le_count = 0;
|
||||
lv_from->size = 0;
|
||||
}
|
||||
@@ -69,65 +73,163 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
|
||||
/*
|
||||
* Reduce mirrored_seg to num_mirrors images.
|
||||
*/
|
||||
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors)
|
||||
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct list *removable_pvs, int remove_log)
|
||||
{
|
||||
uint32_t m;
|
||||
uint32_t s, s1;
|
||||
struct logical_volume *sub_lv;
|
||||
struct logical_volume *log_lv = NULL;
|
||||
struct logical_volume *lv1 = NULL;
|
||||
struct physical_volume *pv;
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment_area area;
|
||||
int all_pvs_removable, pv_found;
|
||||
struct pv_list *pvl;
|
||||
uint32_t old_area_count = mirrored_seg->area_count;
|
||||
uint32_t new_area_count = mirrored_seg->area_count;
|
||||
|
||||
log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
|
||||
PRIu32 " image(s)%s.",
|
||||
old_area_count, num_mirrors,
|
||||
remove_log ? " and no log volume" : "");
|
||||
|
||||
/* Move removable_pvs to end of array */
|
||||
if (removable_pvs) {
|
||||
for (s = 0; s < mirrored_seg->area_count; s++) {
|
||||
all_pvs_removable = 1;
|
||||
sub_lv = seg_lv(mirrored_seg, s);
|
||||
list_iterate_items(seg, &sub_lv->segments) {
|
||||
for (s1 = 0; s1 < seg->area_count; s1++) {
|
||||
if (seg_type(seg, s1) != AREA_PV)
|
||||
/* FIXME Recurse for AREA_LV */
|
||||
continue;
|
||||
|
||||
pv = seg_pv(seg, s1);
|
||||
|
||||
pv_found = 0;
|
||||
list_iterate_items(pvl, removable_pvs) {
|
||||
if (pv->dev->dev == pvl->pv->dev->dev) {
|
||||
pv_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pv_found) {
|
||||
all_pvs_removable = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!all_pvs_removable)
|
||||
break;
|
||||
}
|
||||
if (all_pvs_removable) {
|
||||
/* Swap segment to end */
|
||||
new_area_count--;
|
||||
area = mirrored_seg->areas[new_area_count];
|
||||
mirrored_seg->areas[new_area_count] = mirrored_seg->areas[s];
|
||||
mirrored_seg->areas[s] = area;
|
||||
}
|
||||
/* Found enough matches? */
|
||||
if (new_area_count == num_mirrors)
|
||||
break;
|
||||
}
|
||||
if (new_area_count == mirrored_seg->area_count) {
|
||||
log_error("No mirror images found using specified PVs.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
|
||||
seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
|
||||
seg_lv(mirrored_seg, m)->status |= VISIBLE_LV;
|
||||
}
|
||||
|
||||
mirrored_seg->area_count = num_mirrors;
|
||||
|
||||
/* If no more mirrors, remove mirror layer */
|
||||
if (num_mirrors == 1) {
|
||||
lv1 = seg_lv(mirrored_seg, 0);
|
||||
_move_lv_segments(mirrored_seg->lv, lv1);
|
||||
mirrored_seg->lv->status &= ~MIRRORED;
|
||||
remove_log = 1;
|
||||
}
|
||||
|
||||
if (remove_log) {
|
||||
log_lv = mirrored_seg->log_lv;
|
||||
mirrored_seg->log_lv = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* To successfully remove these unwanted LVs we need to
|
||||
* remove the LVs from the mirror set, commit that metadata
|
||||
* then deactivate and remove them fully.
|
||||
*/
|
||||
|
||||
/* FIXME lv1 has no segments here so shouldn't be written to disk! */
|
||||
|
||||
if (!vg_write(mirrored_seg->lv->vg)) {
|
||||
log_error("intermediate VG write failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!suspend_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
|
||||
log_error("Failed to lock %s", mirrored_seg->lv->name);
|
||||
vg_revert(mirrored_seg->lv->vg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_commit(mirrored_seg->lv->vg)) {
|
||||
resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
|
||||
|
||||
if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
|
||||
log_error("Problem reactivating %s", mirrored_seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Delete the 'orphan' LVs */
|
||||
for (m = num_mirrors; m < old_area_count; m++) {
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mirrored_seg->area_count = num_mirrors;
|
||||
if (lv1) {
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_lv) {
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remove_all_mirror_images(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct logical_volume *lv1;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
if (!remove_mirror_images(seg, 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->log_lv && !lv_remove(seg->log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv1 = seg_lv(seg, 0);
|
||||
|
||||
_move_lv_segments(lv, lv1);
|
||||
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->status &= ~MIRRORED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add mirror images to an existing mirror
|
||||
*/
|
||||
/* FIXME
|
||||
int add_mirror_images(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_areas,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
static int _create_layers_for_mirror(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_mirrors,
|
||||
@@ -161,7 +263,10 @@ static int _create_layers_for_mirror(struct alloc_handle *ah,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_add_segment(ah, m, 1, img_lvs[m],
|
||||
if (m < first_area)
|
||||
continue;
|
||||
|
||||
if (!lv_add_segment(ah, m - first_area, 1, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
0, NULL, 0, 0, 0, NULL)) {
|
||||
@@ -219,6 +324,30 @@ int create_mirror_layers(struct alloc_handle *ah,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t num_mirrors,
|
||||
uint32_t existing_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype)
|
||||
{
|
||||
struct logical_volume **img_lvs;
|
||||
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
|
||||
log_error("img_lvs allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_create_layers_for_mirror(ah, 0, num_mirrors,
|
||||
lv, segtype,
|
||||
img_lvs)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace any LV segments on given PV with temporary mirror.
|
||||
* Returns list of LVs changed.
|
||||
|
||||
@@ -22,9 +22,11 @@ dm_task_set_major
|
||||
dm_task_set_minor
|
||||
dm_task_set_sector
|
||||
dm_task_set_message
|
||||
dm_task_suppress_identical_reload
|
||||
dm_task_add_target
|
||||
dm_task_no_open_count
|
||||
dm_task_skip_lockfs
|
||||
dm_task_update_nodes
|
||||
dm_task_run
|
||||
dm_get_next_target
|
||||
dm_set_dev_dir
|
||||
@@ -61,11 +63,12 @@ dm_tree_node_add_target_area
|
||||
dm_is_dm_major
|
||||
dm_mknodes
|
||||
dm_malloc_aux
|
||||
dm_malloc_aux_debug
|
||||
dm_strdup
|
||||
dm_free_aux
|
||||
dm_realloc_aux
|
||||
dm_dump_memory
|
||||
dm_bounds_check
|
||||
dm_dump_memory_debug
|
||||
dm_bounds_check_debug
|
||||
dm_pool_create
|
||||
dm_pool_destroy
|
||||
dm_pool_alloc
|
||||
|
||||
@@ -17,14 +17,6 @@ top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
interface = @interface@
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
SUBDIRS += event
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += event
|
||||
endif
|
||||
|
||||
SOURCES =\
|
||||
datastruct/bitset.c \
|
||||
datastruct/hash.c \
|
||||
|
||||
@@ -236,7 +236,7 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (!set_selinux_context(control, S_IFCHR)) {
|
||||
if (!dm_set_selinux_context(control, S_IFCHR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -672,11 +672,13 @@ static int _dm_task_run_v1(struct dm_task *dmt)
|
||||
#ifdef DM_IOCTLS
|
||||
else if (ioctl(_control_fd, command, dmi) < 0) {
|
||||
if (_log_suppress)
|
||||
log_verbose("device-mapper ioctl cmd %d failed: %s",
|
||||
_IOC_NR(command), strerror(errno));
|
||||
log_verbose("device-mapper: %s ioctl failed: %s",
|
||||
_cmd_data_v1[dmt->type].name,
|
||||
strerror(errno));
|
||||
else
|
||||
log_error("device-mapper ioctl cmd %d failed: %s",
|
||||
_IOC_NR(command), strerror(errno));
|
||||
log_error("device-mapper: %s ioctl failed: %s",
|
||||
_cmd_data_v1[dmt->type].name,
|
||||
strerror(errno));
|
||||
goto bad;
|
||||
}
|
||||
#else /* Userspace alternative for testing */
|
||||
@@ -875,7 +877,7 @@ int dm_format_dev(char *buf, int bufsize, uint32_t dev_major,
|
||||
if (bufsize < 8)
|
||||
return 0;
|
||||
|
||||
r = snprintf(buf, bufsize, "%03u:%03u", dev_major, dev_minor);
|
||||
r = snprintf(buf, bufsize, "%u:%u", dev_major, dev_minor);
|
||||
if (r < 0 || r > bufsize - 1)
|
||||
return 0;
|
||||
|
||||
@@ -966,6 +968,12 @@ int dm_task_set_ro(struct dm_task *dmt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_suppress_identical_reload(struct dm_task *dmt)
|
||||
{
|
||||
dmt->suppress_identical_reload = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_newname(struct dm_task *dmt, const char *newname)
|
||||
{
|
||||
if (!(dmt->newname = dm_strdup(newname))) {
|
||||
@@ -1342,6 +1350,71 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _reload_with_suppression_v4(struct dm_task *dmt)
|
||||
{
|
||||
struct dm_task *task;
|
||||
struct target *t1, *t2;
|
||||
int matches = 1;
|
||||
int r;
|
||||
|
||||
/* New task to get existing table information */
|
||||
if (!(task = dm_task_create(DM_DEVICE_TABLE))) {
|
||||
log_error("Failed to create device-mapper task struct");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy across relevant fields */
|
||||
if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
|
||||
dm_task_destroy(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) {
|
||||
dm_task_destroy(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
task->major = dmt->major;
|
||||
task->minor = dmt->minor;
|
||||
|
||||
r = dm_task_run(task);
|
||||
|
||||
if (!r) {
|
||||
dm_task_destroy(task);
|
||||
return r;
|
||||
}
|
||||
|
||||
t1 = dmt->head;
|
||||
t2 = task->head;
|
||||
|
||||
while (t1 && t2) {
|
||||
if ((t1->start != t2->start) ||
|
||||
(t1->length != t2->length) ||
|
||||
(strcmp(t1->type, t2->type)) ||
|
||||
(strcmp(t1->params, t2->params))) {
|
||||
matches = 0;
|
||||
break;
|
||||
}
|
||||
t1 = t1->next;
|
||||
t2 = t2->next;
|
||||
}
|
||||
|
||||
if (matches && !t1 && !t2) {
|
||||
dmt->dmi.v4 = task->dmi.v4;
|
||||
task->dmi.v4 = NULL;
|
||||
dm_task_destroy(task);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dm_task_destroy(task);
|
||||
|
||||
/* Now do the original reload */
|
||||
dmt->suppress_identical_reload = 0;
|
||||
r = dm_task_run(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
unsigned repeat_count)
|
||||
{
|
||||
@@ -1383,13 +1456,15 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */
|
||||
else {
|
||||
if (_log_suppress)
|
||||
log_verbose("device-mapper ioctl "
|
||||
"cmd %d failed: %s",
|
||||
_IOC_NR(command), strerror(errno));
|
||||
log_verbose("device-mapper: %s ioctl "
|
||||
"failed: %s",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
strerror(errno));
|
||||
else
|
||||
log_error("device-mapper ioctl "
|
||||
"cmd %d failed: %s",
|
||||
_IOC_NR(command), strerror(errno));
|
||||
log_error("device-mapper: %s ioctl "
|
||||
"failed: %s",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
strerror(errno));
|
||||
dm_free(dmi);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1399,6 +1474,11 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
return dmi;
|
||||
}
|
||||
|
||||
void dm_task_update_nodes(void)
|
||||
{
|
||||
update_devs();
|
||||
}
|
||||
|
||||
int dm_task_run(struct dm_task *dmt)
|
||||
{
|
||||
struct dm_ioctl *dmi;
|
||||
@@ -1426,6 +1506,9 @@ int dm_task_run(struct dm_task *dmt)
|
||||
!dmt->uuid && dmt->major <= 0)
|
||||
return _mknodes_v4(dmt);
|
||||
|
||||
if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload)
|
||||
return _reload_with_suppression_v4(dmt);
|
||||
|
||||
if (!_open_control())
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ struct dm_task {
|
||||
uint64_t sector;
|
||||
int no_open_count;
|
||||
int skip_lockfs;
|
||||
int suppress_identical_reload;
|
||||
|
||||
char *uuid;
|
||||
};
|
||||
|
||||
@@ -145,6 +145,7 @@ int dm_task_set_message(struct dm_task *dmt, const char *message);
|
||||
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
|
||||
int dm_task_no_open_count(struct dm_task *dmt);
|
||||
int dm_task_skip_lockfs(struct dm_task *dmt);
|
||||
int dm_task_suppress_identical_reload(struct dm_task *dmt);
|
||||
|
||||
/*
|
||||
* Use these to prepare for a create or reload.
|
||||
@@ -168,6 +169,12 @@ void *dm_get_next_target(struct dm_task *dmt,
|
||||
*/
|
||||
int dm_task_run(struct dm_task *dmt);
|
||||
|
||||
/*
|
||||
* Call this to make or remove the device nodes associated with previously
|
||||
* issued commands.
|
||||
*/
|
||||
void dm_task_update_nodes(void);
|
||||
|
||||
/*
|
||||
* Configure the device-mapper directory
|
||||
*/
|
||||
@@ -342,30 +349,34 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
|
||||
* Memory management
|
||||
*******************/
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line);
|
||||
#define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__)
|
||||
|
||||
char *dm_strdup(const char *str);
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line);
|
||||
void *dm_malloc_aux_debug(size_t s, const char *file, int line);
|
||||
void dm_free_aux(void *p);
|
||||
void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line);
|
||||
int dm_dump_memory_debug(void);
|
||||
void dm_bounds_check_debug(void);
|
||||
|
||||
#ifdef DEBUG_MEM
|
||||
|
||||
void dm_free_aux(void *p);
|
||||
void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line);
|
||||
int dm_dump_memory(void);
|
||||
void dm_bounds_check(void);
|
||||
|
||||
# define dm_malloc(s) dm_malloc_aux_debug((s), __FILE__, __LINE__)
|
||||
# define dm_free(p) dm_free_aux(p)
|
||||
# define dm_realloc(p, s) dm_realloc_aux(p, s, __FILE__, __LINE__)
|
||||
# define dm_dump_memory() dm_dump_memory_debug()
|
||||
# define dm_bounds_check() dm_bounds_check_debug()
|
||||
|
||||
#else
|
||||
|
||||
# define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__)
|
||||
# define dm_free(p) free(p)
|
||||
# define dm_realloc(p, s) realloc(p, s)
|
||||
# define dm_dump_memory()
|
||||
# define dm_bounds_check()
|
||||
# define dm_dump_memory() {}
|
||||
# define dm_bounds_check() {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The pool allocator is useful when you are going to allocate
|
||||
* lots of memory, use the memory for a bit, and then free the
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#define MAX_TARGET_PARAMSIZE 500000
|
||||
|
||||
/* FIXME Fix interface so this is used only by LVM */
|
||||
#define UUID_PREFIX "LVM-"
|
||||
|
||||
/* Supported segment types */
|
||||
enum {
|
||||
SEG_ERROR,
|
||||
@@ -112,6 +115,8 @@ struct dm_tree_node {
|
||||
struct list uses; /* Nodes this node uses */
|
||||
struct list used_by; /* Nodes that use this node */
|
||||
|
||||
int activation_priority; /* 0 gets activated first */
|
||||
|
||||
void *context; /* External supplied context */
|
||||
|
||||
struct load_properties props; /* For creation/table (re)load */
|
||||
@@ -310,6 +315,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
|
||||
node->uuid = uuid;
|
||||
node->info = *info;
|
||||
node->context = context;
|
||||
node->activation_priority = 0;
|
||||
|
||||
list_init(&node->uses);
|
||||
list_init(&node->used_by);
|
||||
@@ -348,8 +354,15 @@ static struct dm_tree_node *_find_dm_tree_node(struct dm_tree *dtree,
|
||||
static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
|
||||
const char *uuid)
|
||||
{
|
||||
/* FIXME Do we need to cope with missing LVM- prefix too? */
|
||||
return dm_hash_lookup(dtree->uuids, uuid);
|
||||
struct dm_tree_node *node;
|
||||
|
||||
if ((node = dm_hash_lookup(dtree->uuids, uuid)))
|
||||
return node;
|
||||
|
||||
if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
|
||||
return NULL;
|
||||
|
||||
return dm_hash_lookup(dtree->uuids, uuid + sizeof(UUID_PREFIX) - 1);
|
||||
}
|
||||
|
||||
static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,
|
||||
@@ -653,13 +666,13 @@ static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_
|
||||
if (uuid_prefix_len <= 4)
|
||||
return 0;
|
||||
|
||||
if (!strncmp(uuid, "LVM-", 4))
|
||||
if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
|
||||
return 0;
|
||||
|
||||
if (strncmp(uuid_prefix, "LVM-", 4))
|
||||
if (strncmp(uuid_prefix, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
|
||||
return 0;
|
||||
|
||||
if (!strncmp(uuid, uuid_prefix + 4, uuid_prefix_len - 4))
|
||||
if (!strncmp(uuid, uuid_prefix + sizeof(UUID_PREFIX) - 1, uuid_prefix_len - (sizeof(UUID_PREFIX) - 1)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -1026,7 +1039,7 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
}
|
||||
|
||||
/* Ignore if it doesn't belong to this VG */
|
||||
if (uuid_prefix && strncmp(uuid, uuid_prefix, uuid_prefix_len))
|
||||
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
|
||||
continue;
|
||||
|
||||
if (dm_tree_node_num_children(child, 0))
|
||||
@@ -1045,6 +1058,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
struct dm_info newinfo;
|
||||
const char *name;
|
||||
const char *uuid;
|
||||
int priority;
|
||||
|
||||
/* Activate children first */
|
||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||
@@ -1058,36 +1072,53 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
|
||||
if (dm_tree_node_num_children(child, 0))
|
||||
dm_tree_activate_children(child, uuid_prefix, uuid_prefix_len);
|
||||
}
|
||||
|
||||
if (!(name = dm_tree_node_get_name(child))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
handle = NULL;
|
||||
|
||||
/* Rename? */
|
||||
if (child->props.new_name) {
|
||||
if (!_rename_node(name, child->props.new_name, child->info.major, child->info.minor)) {
|
||||
log_error("Failed to rename %s (%" PRIu32
|
||||
":%" PRIu32 ") to %s", name, child->info.major,
|
||||
child->info.minor, child->props.new_name);
|
||||
return 0;
|
||||
for (priority = 0; priority < 2; priority++) {
|
||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||
if (!(uuid = dm_tree_node_get_uuid(child))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
child->name = child->props.new_name;
|
||||
child->props.new_name = NULL;
|
||||
|
||||
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
|
||||
continue;
|
||||
|
||||
if (priority != child->activation_priority)
|
||||
continue;
|
||||
|
||||
if (!(name = dm_tree_node_get_name(child))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Rename? */
|
||||
if (child->props.new_name) {
|
||||
if (!_rename_node(name, child->props.new_name, child->info.major, child->info.minor)) {
|
||||
log_error("Failed to rename %s (%" PRIu32
|
||||
":%" PRIu32 ") to %s", name, child->info.major,
|
||||
child->info.minor, child->props.new_name);
|
||||
return 0;
|
||||
}
|
||||
child->name = child->props.new_name;
|
||||
child->props.new_name = NULL;
|
||||
}
|
||||
|
||||
if (!child->info.inactive_table && !child->info.suspended)
|
||||
continue;
|
||||
|
||||
if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
|
||||
log_error("Unable to resume %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, child->info.major,
|
||||
child->info.minor);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update cached info */
|
||||
child->info = newinfo;
|
||||
}
|
||||
|
||||
if (!child->info.inactive_table && !child->info.suspended)
|
||||
continue;
|
||||
|
||||
if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
|
||||
log_error("Unable to resume %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, child->info.major,
|
||||
child->info.minor);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update cached info */
|
||||
child->info = newinfo;
|
||||
}
|
||||
|
||||
handle = NULL;
|
||||
@@ -1343,8 +1374,15 @@ static int _load_node(struct dm_tree_node *dnode)
|
||||
if (!_emit_segment(dmt, seg, &seg_start))
|
||||
goto_out;
|
||||
|
||||
if ((r = dm_task_run(dmt)))
|
||||
if (!dm_task_suppress_identical_reload(dmt))
|
||||
log_error("Failed to suppress reload of identical tables.");
|
||||
|
||||
if ((r = dm_task_run(dmt))) {
|
||||
r = dm_task_get_info(dmt, &dnode->info);
|
||||
if (r && !dnode->info.inactive_table)
|
||||
log_verbose("Suppressed %s identical table reload.",
|
||||
dnode->name);
|
||||
}
|
||||
|
||||
dnode->props.segment_count = 0;
|
||||
|
||||
@@ -1352,7 +1390,6 @@ out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
@@ -1371,8 +1408,8 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
continue;
|
||||
|
||||
/* Ignore if it doesn't belong to this VG */
|
||||
if (uuid_prefix && child->info.exists &&
|
||||
strncmp(child->uuid, uuid_prefix, uuid_prefix_len))
|
||||
if (child->info.exists &&
|
||||
!_uuid_prefix_matches(child->uuid, uuid_prefix, uuid_prefix_len))
|
||||
continue;
|
||||
|
||||
if (dm_tree_node_num_children(child, 0))
|
||||
@@ -1402,6 +1439,9 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
if (!dm_tree_node_num_children(child, 1))
|
||||
continue;
|
||||
|
||||
if (!child->info.inactive_table && !child->info.suspended)
|
||||
continue;
|
||||
|
||||
if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
|
||||
log_error("Unable to resume %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, child->info.major,
|
||||
@@ -1435,7 +1475,7 @@ int dm_tree_children_use_uuid(struct dm_tree_node *dnode,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
|
||||
if (_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
|
||||
return 1;
|
||||
|
||||
if (dm_tree_node_num_children(child, 0))
|
||||
@@ -1492,6 +1532,9 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
|
||||
if (!_link_tree_nodes(dnode, origin_node))
|
||||
return_0;
|
||||
|
||||
/* Resume snapshot origins after new snapshots */
|
||||
dnode->activation_priority = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMEVENT_H
|
||||
#define LIB_DMEVENT_H
|
||||
|
||||
#include "list.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DAEMON "/sbin/dmeventd"
|
||||
#define LOCKFILE "/var/lock/dmeventd"
|
||||
#define FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DEFAULT_TIMEOUT 10
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dmeventd_command {
|
||||
CMD_ACTIVE = 1,
|
||||
CMD_REGISTER_FOR_EVENT,
|
||||
CMD_UNREGISTER_FOR_EVENT,
|
||||
CMD_GET_REGISTERED_DEVICE,
|
||||
CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
CMD_SET_TIMEOUT,
|
||||
CMD_GET_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct daemon_message {
|
||||
union {
|
||||
unsigned int cmd;
|
||||
int status;
|
||||
} opcode;
|
||||
char msg[252];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
|
||||
/* Event type definitions. */
|
||||
enum event_type {
|
||||
SINGLE = 0x01, /* Report multiple errors just once. */
|
||||
MULTI = 0x02, /* Report all of them. */
|
||||
SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
|
||||
DEVICE_ERROR = 0x08, /* Device failure. */
|
||||
PATH_ERROR = 0x10, /* Failure on an io path. */
|
||||
ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
|
||||
SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
#define ALL_ERRORS (SECTOR_ERROR | DEVICE_ERROR | PATH_ERROR | ADAPTOR_ERROR)
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
int dm_register_for_event(char *dso_name, char *device, enum event_type events);
|
||||
int dm_unregister_for_event(char *dso_name, char *device,
|
||||
enum event_type events);
|
||||
int dm_get_registered_device(char **dso_name, char **device,
|
||||
enum event_type *events, int next);
|
||||
int dm_set_event_timeout(char *device, uint32_t timeout);
|
||||
int dm_get_event_timeout(char *device, uint32_t *timeout);
|
||||
|
||||
/* Prototypes for DSO interface. */
|
||||
void process_event(char *device, enum event_type event);
|
||||
int register_device(char *device);
|
||||
int unregister_device(char *device);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -28,8 +28,6 @@ char *dm_strdup(const char *str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEM
|
||||
|
||||
struct memblock {
|
||||
struct memblock *prev, *next; /* All allocated blocks are linked */
|
||||
size_t length; /* Size of the requested block */
|
||||
@@ -51,7 +49,7 @@ static struct {
|
||||
static struct memblock *_head = 0;
|
||||
static struct memblock *_tail = 0;
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
void *dm_malloc_aux_debug(size_t s, const char *file, int line)
|
||||
{
|
||||
struct memblock *nb;
|
||||
size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
|
||||
@@ -72,9 +70,7 @@ void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
nb->file = file;
|
||||
nb->line = line;
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
dm_bounds_check();
|
||||
#endif
|
||||
|
||||
/* setup fields */
|
||||
nb->magic = nb + 1;
|
||||
@@ -125,9 +121,7 @@ void dm_free_aux(void *p)
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
dm_bounds_check();
|
||||
#endif
|
||||
|
||||
/* sanity check */
|
||||
assert(mb->magic == p);
|
||||
@@ -171,7 +165,7 @@ void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
|
||||
void *r;
|
||||
struct memblock *mb = ((struct memblock *) p) - 1;
|
||||
|
||||
r = dm_malloc_aux(s, file, line);
|
||||
r = dm_malloc_aux_debug(s, file, line);
|
||||
|
||||
if (p) {
|
||||
memcpy(r, p, mb->length);
|
||||
@@ -181,7 +175,7 @@ void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_dump_memory(void)
|
||||
int dm_dump_memory_debug(void)
|
||||
{
|
||||
unsigned long tot = 0;
|
||||
struct memblock *mb;
|
||||
@@ -216,7 +210,7 @@ int dm_dump_memory(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_bounds_check(void)
|
||||
void dm_bounds_check_debug(void)
|
||||
{
|
||||
struct memblock *mb = _head;
|
||||
while (mb) {
|
||||
@@ -230,8 +224,6 @@ void dm_bounds_check(void)
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
{
|
||||
if (s > 50000000) {
|
||||
@@ -242,5 +234,3 @@ void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -85,7 +85,7 @@ arg(size_ARG, 'L', "size", size_mb_arg)
|
||||
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign)
|
||||
arg(persistent_ARG, 'M', "persistent", yes_no_arg)
|
||||
arg(major_ARG, 'j', "major", major_arg)
|
||||
arg(mirrors_ARG, 'm', "mirrors", int_arg)
|
||||
arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign)
|
||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg)
|
||||
arg(maps_ARG, 'm', "maps", NULL)
|
||||
arg(name_ARG, 'n', "name", string_arg)
|
||||
|
||||
@@ -85,11 +85,12 @@ xx(lvconvert,
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
"\t[-m|--mirrors Mirrors]\n"
|
||||
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n",
|
||||
|
||||
alloc_ARG, mirrors_ARG, test_ARG)
|
||||
alloc_ARG, mirrors_ARG, regionsize_ARG, test_ARG)
|
||||
|
||||
xx(lvcreate,
|
||||
"Create a logical volume",
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
struct lvconvert_params {
|
||||
const char *lv_name;
|
||||
uint32_t mirrors;
|
||||
sign_t mirrors_sign;
|
||||
uint32_t region_size;
|
||||
|
||||
alloc_policy_t alloc;
|
||||
|
||||
@@ -40,7 +43,29 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
|
||||
lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
|
||||
|
||||
/*
|
||||
* --regionsize is only valid when converting an LV into a mirror.
|
||||
* This is checked when we know the state of the LV being converted.
|
||||
*/
|
||||
if (arg_count(cmd, regionsize_ARG)) {
|
||||
if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
|
||||
log_error("Negative regionsize is invalid");
|
||||
return 0;
|
||||
}
|
||||
lp->region_size = 2 * arg_uint_value(cmd, regionsize_ARG, 0);
|
||||
} else
|
||||
lp->region_size = 2 * find_config_int(cmd->cft->root,
|
||||
"activation/mirror_region_size",
|
||||
DEFAULT_MIRROR_REGION_SIZE);
|
||||
|
||||
if (lp->region_size & (lp->region_size - 1)) {
|
||||
log_error("Region size (%" PRIu32 ") must be a power of 2",
|
||||
lp->region_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give logical volume path");
|
||||
@@ -61,8 +86,33 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t existing_mirrors;
|
||||
// struct alloc_handle *ah = NULL;
|
||||
// struct logical_volume *log_lv;
|
||||
struct alloc_handle *ah = NULL;
|
||||
struct logical_volume *log_lv;
|
||||
struct list *parallel_areas;
|
||||
struct segment_type *segtype;
|
||||
|
||||
seg = first_seg(lv);
|
||||
existing_mirrors = seg->area_count;
|
||||
|
||||
/* Adjust required number of mirrors */
|
||||
if (lp->mirrors_sign == SIGN_PLUS)
|
||||
lp->mirrors = existing_mirrors + lp->mirrors;
|
||||
else if (lp->mirrors_sign == SIGN_MINUS) {
|
||||
if (lp->mirrors >= existing_mirrors) {
|
||||
log_error("Logical volume %s only has %" PRIu32 " mirrors.",
|
||||
lv->name, existing_mirrors);
|
||||
return 0;
|
||||
}
|
||||
lp->mirrors = existing_mirrors - lp->mirrors;
|
||||
} else
|
||||
lp->mirrors += 1;
|
||||
|
||||
if (arg_count(cmd, regionsize_ARG) && (lv->status & MIRRORED) &&
|
||||
(lp->region_size != seg->region_size)) {
|
||||
log_error("Mirror log region size cannot be changed on "
|
||||
"an existing mirror.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((lp->mirrors == 1)) {
|
||||
if (!(lv->status & MIRRORED)) {
|
||||
@@ -70,8 +120,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
lv->name);
|
||||
return 1;
|
||||
}
|
||||
/* FIXME If allocatable_pvs supplied only remove those */
|
||||
if (!remove_all_mirror_images(lv)) {
|
||||
|
||||
if (!remove_mirror_images(seg, 1, lp->pv_count ? lp->pvh : NULL, 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -82,8 +132,6 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
"mirror segments.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
seg = first_seg(lv);
|
||||
existing_mirrors = seg->area_count;
|
||||
if (lp->mirrors == existing_mirrors) {
|
||||
log_error("Logical volume %s already has %"
|
||||
PRIu32 " mirror(s).", lv->name,
|
||||
@@ -100,18 +148,58 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
"supported yet.");
|
||||
return 0;
|
||||
} else {
|
||||
if (!remove_mirror_images(seg, lp->mirrors)) {
|
||||
/* Reduce number of mirrors */
|
||||
if (!remove_mirror_images(seg, lp->mirrors, lp->pv_count ? lp->pvh : NULL, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Make existing LV into mirror set */
|
||||
/* FIXME Share code with lvcreate */
|
||||
/* region size, log_name, create log_lv, zero it */
|
||||
// Allocate (mirrors) new areas & log - replace mirrored_pv with mirrored_lv
|
||||
// Restructure as mirror - add existing param to create_mirror_layers
|
||||
log_error("Adding mirror images is not supported yet.");
|
||||
return 0;
|
||||
|
||||
/* FIXME Why is this restriction here? Fix it! */
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg_is_striped(seg) && seg->area_count > 1) {
|
||||
log_error("Mirrors of striped volumes are not yet supported.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype = get_segtype_from_string(cmd, "striped");
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
|
||||
lp->mirrors - 1, 1,
|
||||
lv->le_count * (lp->mirrors - 1),
|
||||
NULL, 0, 0, lp->pvh,
|
||||
lp->alloc,
|
||||
parallel_areas))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size);
|
||||
|
||||
if (!(log_lv = create_mirror_log(cmd, lv->vg, ah,
|
||||
lp->alloc,
|
||||
lv->name))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!create_mirror_layers(ah, 1, lp->mirrors, lv,
|
||||
segtype, 0, lp->region_size,
|
||||
log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -291,6 +291,10 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
|
||||
if (lp->mirrors == 1)
|
||||
log_print("Redundant mirrors argument: default is 0");
|
||||
if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
|
||||
log_error("Mirrors argument may not be negative");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->snapshot) {
|
||||
@@ -432,9 +436,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
const char *tag;
|
||||
int consistent = 1;
|
||||
struct alloc_handle *ah = NULL;
|
||||
char *log_name, lv_name_buf[128];
|
||||
char lv_name_buf[128];
|
||||
const char *lv_name;
|
||||
size_t len;
|
||||
|
||||
status |= lp->permission | VISIBLE_LV;
|
||||
|
||||
@@ -584,71 +587,25 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
}
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
/* FIXME Calculate how many extents needed for the log */
|
||||
|
||||
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
|
||||
lp->mirrors, 1, lp->extents,
|
||||
NULL, 0, 0, pvh, lp->alloc,
|
||||
NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->region_size = adjusted_mirror_region_size(vg->extent_size,
|
||||
lp->extents,
|
||||
lp->region_size);
|
||||
|
||||
/* FIXME Calculate how many extents needed for the log */
|
||||
|
||||
len = strlen(lv_name) + 32;
|
||||
if (!(log_name = alloca(len)) ||
|
||||
!(generate_log_name_format(vg, lv_name, log_name, len))) {
|
||||
log_error("log_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(log_lv = lv_create_empty(vg->fid, log_name, NULL,
|
||||
VISIBLE_LV | LVM_READ | LVM_WRITE,
|
||||
lp->alloc, 0, vg))) {
|
||||
stack;
|
||||
if (!(log_lv = create_mirror_log(cmd, vg, ah, lp->alloc,
|
||||
lv_name))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
|
||||
lp->mirrors, 1, lp->extents,
|
||||
NULL, 0, 0, pvh, lp->alloc))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_add_log_segment(ah, log_lv)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store mirror log on disk(s) */
|
||||
if (!vg_write(vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
backup(vg);
|
||||
|
||||
if (!vg_commit(vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to activate mirror log. "
|
||||
"Remove new LVs and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (activation() && !zero_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to wipe mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to deactivate mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
}
|
||||
|
||||
if (!(lv = lv_create_empty(vg->fid, lv_name ? lv_name : "lvol%d", NULL,
|
||||
@@ -761,6 +718,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
|
||||
if (!suspend_lv(cmd, org)) {
|
||||
log_error("Failed to suspend origin %s", org->name);
|
||||
vg_revert(vg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
static int _lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
|
||||
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
|
||||
!(lv_is_cow(lv)))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (arg_count(cmd, colon_ARG))
|
||||
|
||||
@@ -168,6 +168,10 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
|
||||
else
|
||||
log_print("Mirrors not supported. Ignoring.");
|
||||
if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
|
||||
log_error("Mirrors argument may not be negative");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_count(cmd, stripesize_ARG)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -1074,3 +1075,71 @@ int zero_lv(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct alloc_handle *ah,
|
||||
alloc_policy_t alloc,
|
||||
const char *lv_name)
|
||||
{
|
||||
struct logical_volume *log_lv;
|
||||
char *log_name;
|
||||
size_t len;
|
||||
|
||||
len = strlen(lv_name) + 32;
|
||||
if (!(log_name = alloca(len)) ||
|
||||
!(generate_log_name_format(vg, lv_name, log_name, len))) {
|
||||
log_error("log_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(log_lv = lv_create_empty(vg->fid, log_name, NULL,
|
||||
VISIBLE_LV | LVM_READ | LVM_WRITE,
|
||||
alloc, 0, vg))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!lv_add_log_segment(ah, log_lv)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store mirror log on disk(s) */
|
||||
if (!vg_write(vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
backup(vg);
|
||||
|
||||
if (!vg_commit(vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to activate mirror log. "
|
||||
"Remove new LVs and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (activation() && !zero_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to wipe mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to deactivate mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
|
||||
return log_lv;
|
||||
error:
|
||||
/* FIXME Attempt to clean up. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,12 @@ int validate_vg_name(struct cmd_context *cmd, const char *vg_name);
|
||||
int generate_log_name_format(struct volume_group *vg, const char *lv_name,
|
||||
char *buffer, size_t size);
|
||||
|
||||
struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct alloc_handle *ah,
|
||||
alloc_policy_t alloc,
|
||||
const char *lv_name);
|
||||
|
||||
int zero_lv(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user