1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-11-03 08:23:48 +03:00

Compare commits

...

28 Commits

Author SHA1 Message Date
Alasdair Kergon
ab931b177d dmeventd updates 2005-12-02 15:39:16 +00:00
Alasdair Kergon
9aa3465513 Export dm_task_update_nodes.
Use names instead of numbers in messages when ioctls fail.
2005-12-01 23:11:41 +00:00
Alasdair Kergon
6c70fc1a6c Add some FIXMEs to libdm-event. 2005-11-30 18:35:03 +00:00
Alasdair Kergon
1ccc39962a more lvconvert mirror code 2005-11-29 18:20:23 +00:00
Alasdair Kergon
99c941fc85 Allow signed mirrors arguments.
Move create_mirror_log() into toollib.
2005-11-28 21:00:37 +00:00
Alasdair Kergon
19729fdcc2 Determine parallel PVs to avoid with ALLOC_NORMAL allocation. (untested) 2005-11-28 20:01:00 +00:00
Alasdair Kergon
02e17998ce alloc avoids parallel pvs when supplied 2005-11-24 21:23:55 +00:00
Alasdair Kergon
459e00c67a preparation for parallel_areas changes to allocation code 2005-11-24 20:58:44 +00:00
Alasdair Kergon
292f665650 Fix lv_empty. 2005-11-24 18:46:51 +00:00
Alasdair Kergon
93bbb79569 _find_parallel_space -> _find_segment_space 2005-11-24 18:00:47 +00:00
Alasdair Kergon
273e724f2b post_release 2005-11-23 18:45:30 +00:00
Alasdair Kergon
5d2615c56f post-release 2005-11-23 18:44:59 +00:00
Alasdair Kergon
bfaaf21330 2.02.01 2005-11-23 18:42:45 +00:00
Alasdair Kergon
dcb8415b7a 1.02.01 2005-11-23 18:36:33 +00:00
Alasdair Kergon
699e1c75ce Fix lvdisplay cmdline to accept snapshots. 2005-11-23 16:16:39 +00:00
Alasdair Kergon
465b6e613e Fix open RO->RW promotions. 2005-11-23 16:07:40 +00:00
Alasdair Kergon
05fa105855 Resume snapshot-origins last. 2005-11-22 20:00:35 +00:00
Alasdair Kergon
d7a0cdebe5 Remove a resolved FIXME. 2005-11-22 19:37:14 +00:00
Alasdair Kergon
b049ab31eb Suppress unnecessary resumes. 2005-11-22 19:31:20 +00:00
Alasdair Kergon
6db4dcff7a Drop leading zeros from dm_format_dev.
Suppress attempt to reload identical table.
2005-11-22 18:43:12 +00:00
Alasdair Kergon
3eeaef00ec Additional LVM- prefix matching for transitional period. 2005-11-12 22:46:48 +00:00
Alasdair Kergon
8bf4c38a00 lvcreate vg_revert 2005-11-12 22:42:08 +00:00
Alasdair Kergon
3a32b09ad1 A missing vg_revert in an error path. 2005-11-12 22:00:50 +00:00
Alasdair Kergon
6315982752 more debug fixes 2005-11-11 16:16:37 +00:00
Alasdair Kergon
374a171e82 Fix selinux compile. 2005-11-10 18:31:17 +00:00
Alasdair Kergon
fc5d801f91 fix debug linking 2005-11-10 16:33:04 +00:00
Alasdair Kergon
5146641848 post-release 2005-11-10 16:06:29 +00:00
Alasdair Kergon
cdd0ac42cf pre-release 2005-11-10 15:27:19 +00:00
35 changed files with 1963 additions and 982 deletions

View File

@@ -1 +1 @@
2.02.00-cvs (2005-10-16)
2.02.02-cvs (2005-11-23)

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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, &reg, &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

View 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__ */

View 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:
*/

View 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

View File

@@ -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 $$

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 ||

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
*/

View File

@@ -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.

View File

@@ -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

View File

@@ -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 \

View File

@@ -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;

View File

@@ -53,6 +53,7 @@ struct dm_task {
uint64_t sector;
int no_open_count;
int skip_lockfs;
int suppress_identical_reload;
char *uuid;
};

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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:
*/

View File

@@ -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

View File

@@ -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)

View File

@@ -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",

View File

@@ -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;
}
}
}

View File

@@ -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;
}

View File

@@ -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))

View File

@@ -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)) {

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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.
*