mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-27 00:23:49 +03:00
Compare commits
122 Commits
dm_v1_02_0
...
dm_v1_02_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3feba82ccc | ||
|
|
db924da231 | ||
|
|
fc55ae7e6d | ||
|
|
86e757a6ad | ||
|
|
4790715cd3 | ||
|
|
e7e9c60042 | ||
|
|
1c3bc52cc4 | ||
|
|
5227dff0e1 | ||
|
|
33f0b5b7c2 | ||
|
|
0a02968303 | ||
|
|
f7bf658c07 | ||
|
|
8d16a0abad | ||
|
|
c974b97ca3 | ||
|
|
b8025bfebd | ||
|
|
30323b253f | ||
|
|
535c3ede96 | ||
|
|
89fed8ca33 | ||
|
|
f43c77aaed | ||
|
|
96c676b371 | ||
|
|
113047e1a2 | ||
|
|
abed57cb53 | ||
|
|
c01a800a6b | ||
|
|
d648832a2d | ||
|
|
f06833fbd2 | ||
|
|
c561addc94 | ||
|
|
702f5f1f4c | ||
|
|
1273f179e8 | ||
|
|
5d02f60bde | ||
|
|
4cf7a108e8 | ||
|
|
42635c3938 | ||
|
|
ed43dc842b | ||
|
|
49d4db6cd2 | ||
|
|
ea80ab2cae | ||
|
|
382e808b8d | ||
|
|
846befa7e0 | ||
|
|
74dd29f843 | ||
|
|
b0473bffcb | ||
|
|
24dd9ab1a7 | ||
|
|
49d3037e87 | ||
|
|
37ad2bd4e8 | ||
|
|
7d7b332b02 | ||
|
|
ac033b8612 | ||
|
|
a7b98dfe25 | ||
|
|
7fb7c86c46 | ||
|
|
ed036598a9 | ||
|
|
160bb70cdf | ||
|
|
c2e61f3c21 | ||
|
|
18218467f3 | ||
|
|
17e298ad2a | ||
|
|
d031a374f9 | ||
|
|
55f69c98cb | ||
|
|
71f2e4306d | ||
|
|
f8af23a025 | ||
|
|
4ef55a6cd3 | ||
|
|
312f866723 | ||
|
|
0ebe1f6dec | ||
|
|
2ad92e0e6e | ||
|
|
ac8823cdcf | ||
|
|
77565f7ee4 | ||
|
|
d656d90fa8 | ||
|
|
175b3b0834 | ||
|
|
7477e6b714 | ||
|
|
cd6568db69 | ||
|
|
6aff325fb2 | ||
|
|
0d603cfe9c | ||
|
|
34a1f14a17 | ||
|
|
efe1c8a070 | ||
|
|
1575844344 | ||
|
|
221ac1c208 | ||
|
|
57442db759 | ||
|
|
5fdb3e7cd6 | ||
|
|
96f259726c | ||
|
|
4936efba5e | ||
|
|
d5a3559a2f | ||
|
|
114a1c7f52 | ||
|
|
ce5265c203 | ||
|
|
1a575d926f | ||
|
|
85c818a39e | ||
|
|
4ffa2defe4 | ||
|
|
8825157fbb | ||
|
|
966d608dc5 | ||
|
|
b808c89471 | ||
|
|
75d4e6490f | ||
|
|
a82775f544 | ||
|
|
6a22ad0171 | ||
|
|
c854e88186 | ||
|
|
d02203060c | ||
|
|
cf703b0433 | ||
|
|
c0197a72d3 | ||
|
|
e5a543e283 | ||
|
|
b8b029b7d3 | ||
|
|
370f368b1a | ||
|
|
8288b45b4f | ||
|
|
fe529faf8e | ||
|
|
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 |
11
Makefile.in
11
Makefile.in
@@ -24,8 +24,13 @@ endif
|
||||
|
||||
SUBDIRS += lib tools daemons
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
SUBDIRS += dmeventd
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += daemons/clvmd \
|
||||
dmeventd \
|
||||
lib/format1 \
|
||||
lib/format_pool \
|
||||
lib/locking \
|
||||
@@ -40,13 +45,15 @@ include make.tmpl
|
||||
daemons: lib
|
||||
lib: include
|
||||
tools: lib
|
||||
po: tools daemons
|
||||
dmeventd: tools
|
||||
po: tools daemons dmeventd
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
lib.pofile: include.pofile
|
||||
tools.pofile: lib.pofile
|
||||
daemons.pofile: lib.pofile
|
||||
po.pofile: tools.pofile daemons.pofile
|
||||
dmeventd.pofile: tools.pofile
|
||||
po.pofile: tools.pofile daemons.pofile dmeventd.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
|
||||
53
WHATS_NEW
53
WHATS_NEW
@@ -1,5 +1,56 @@
|
||||
Version 2.02.00 -
|
||||
Version 2.02.03 - 14th April 2006
|
||||
=================================
|
||||
vgrename accepts vgid and exported VG.
|
||||
Add --partial to pvs.
|
||||
When choosing between identically-named VGs, also consider creation_host.
|
||||
Provide total log suppression with 2.
|
||||
Fix vgexport/vgimport to set/reset PV exported flag so pv_attr is correct.
|
||||
Add vgid to struct physical_volume and pass with vg_name to some functions.
|
||||
If two or more VGs are found with the same name, use one that is not exported.
|
||||
Whenever vgname is captured, also capture vgid and whether exported.
|
||||
Remove an incorrect unlock_vg() from process_each_lv().
|
||||
Update extent size information in vgchange and vgcreate man pages.
|
||||
Introduce origin_from_cow() and lv_is_visible().
|
||||
pvremove without -f now fails if there's no PV label.
|
||||
Support lvconvert -s.
|
||||
Suppress locking library load failure message if --ignorelockingfailure.
|
||||
Propagate partial mode around cluster.
|
||||
Fix archive file expiration.
|
||||
Fix dmeventd build.
|
||||
clvmd now uses libcman rather than cman ioctls.
|
||||
clvmd will allow new cman to shutdown on request.
|
||||
|
||||
Version 2.02.02 - 7th February 2006
|
||||
===================================
|
||||
Add %.so: %.a make template rule.
|
||||
Switchover library building to use LIB_SUFFIX.
|
||||
Only do lockfs filesystem sync when suspending snapshots.
|
||||
Always print warning if activation is disabled.
|
||||
vgreduce removes mirror images.
|
||||
Add --mirrorsonly to vgreduce.
|
||||
vgreduce replaces active LVs with error segment before removing them.
|
||||
Set block_on_error parameter if available.
|
||||
Add target_version.
|
||||
Add details to format1 'Invalid LV in extent map' error message.
|
||||
Fix lvscan snapshot full display.
|
||||
Bring lvdisplay man page example into line.
|
||||
Add mirror dmeventd library.
|
||||
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.
|
||||
|
||||
39
WHATS_NEW_DM
39
WHATS_NEW_DM
@@ -1,4 +1,41 @@
|
||||
Version 1.02.00 -
|
||||
Version 1.02.04 - 14 Apr 2006
|
||||
=============================
|
||||
Bring dmsetup man page up-to-date.
|
||||
Use name-based device refs if kernel doesn't support device number refs.
|
||||
Fix memory leak (struct dm_ioctl) when struct dm_task is reused.
|
||||
If _create_and_load_v4 fails part way through, revert the creation.
|
||||
dmeventd thread/fifo fixes.
|
||||
Add file & line to dm_strdup_aux().
|
||||
Add setgeometry.
|
||||
|
||||
Version 1.02.03 - 7 Feb 2006
|
||||
============================
|
||||
Add exported functions to set uid, gid and mode.
|
||||
Rename _log to dm_log and export.
|
||||
Add dm_tree_skip_lockfs.
|
||||
Fix dm_strdup debug definition.
|
||||
Fix hash function to avoid using a negative array offset.
|
||||
Don't inline _find in hash.c and tidy signed/unsigned etc.
|
||||
Fix libdevmapper.h #endif.
|
||||
Fix dmsetup version driver version.
|
||||
Add sync, nosync and block_on_error mirror log parameters.
|
||||
Add hweight32.
|
||||
Fix dmeventd build.
|
||||
|
||||
Version 1.02.02 - 2 Dec 2005
|
||||
============================
|
||||
dmeventd added.
|
||||
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.
|
||||
|
||||
30
configure.in
30
configure.in
@@ -35,7 +35,7 @@ case "$host_os" in
|
||||
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
|
||||
LDDEPS="$LDDEPS .export.sym"
|
||||
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
|
||||
SOFLAG="-shared"
|
||||
LIB_SUFFIX="so"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
@@ -49,7 +49,7 @@ case "$host_os" in
|
||||
CLDNOWHOLEARCHIVE=
|
||||
LDDEPS="$LDDEPS"
|
||||
LDFLAGS="$LDFLAGS"
|
||||
SOFLAG="-dynamiclib"
|
||||
LIB_SUFFIX="dylib"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
@@ -355,6 +355,23 @@ AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
|
||||
FSADM=$enableval)
|
||||
AC_MSG_RESULT($FSADM)
|
||||
|
||||
################################################################################
|
||||
dnl -- enable dmeventd handling
|
||||
AC_MSG_CHECKING(whether to use dmeventd)
|
||||
AC_ARG_ENABLE(dmeventd, [ --enable-dmeventd Enable the device-mapper event daemon],
|
||||
DMEVENTD=$enableval)
|
||||
AC_MSG_RESULT($DMEVENTD)
|
||||
|
||||
dnl -- dmeventd currently requires internal mirror support
|
||||
if test x$DMEVENTD = xyes && test x$MIRRORS != xinternal; then
|
||||
AC_MSG_ERROR(
|
||||
--enable-dmeventd currently requires --with-mirrors=internal
|
||||
)
|
||||
fi
|
||||
|
||||
if test x$DMEVENTD = xyes; then
|
||||
CFLAGS="$CFLAGS -DDMEVENTD"
|
||||
fi
|
||||
################################################################################
|
||||
dnl -- Mess with default exec_prefix
|
||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||
@@ -545,7 +562,7 @@ AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(LDDEPS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(SOFLAG)
|
||||
AC_SUBST(LIB_SUFFIX)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LVM_VERSION)
|
||||
AC_SUBST(LVM1_FALLBACK)
|
||||
@@ -563,6 +580,7 @@ AC_SUBST(INTL)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(FSADM)
|
||||
AC_SUBST(DMEVENTD)
|
||||
|
||||
################################################################################
|
||||
dnl -- First and last lines should not contain files to generate in order to
|
||||
@@ -572,6 +590,8 @@ Makefile \
|
||||
make.tmpl \
|
||||
daemons/Makefile \
|
||||
daemons/clvmd/Makefile \
|
||||
dmeventd/Makefile \
|
||||
dmeventd/mirror/Makefile \
|
||||
doc/Makefile \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
@@ -599,3 +619,7 @@ fi
|
||||
if test x$FSADM == xyes; then
|
||||
AC_MSG_WARN(fsadm support is untested)
|
||||
fi
|
||||
|
||||
if test x$DMEVENTD == xyes; then
|
||||
AC_MSG_WARN(dmeventd support is untested)
|
||||
fi
|
||||
|
||||
@@ -46,17 +46,26 @@ endif
|
||||
|
||||
ifeq ("$(CMAN)", "yes")
|
||||
SOURCES += clvmd-cman.c
|
||||
LMLIBS += -ldlm
|
||||
LMLIBS += -ldlm -lcman
|
||||
CFLAGS += -DUSE_CMAN
|
||||
endif
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
LVMLIBS = -llvm -lpthread
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
LVMLIBS += -ldevmapper-event
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
LVMLIBS += -ldevmapper
|
||||
endif
|
||||
|
||||
CFLAGS += -D_REENTRANT -fno-strict-aliasing
|
||||
LIBS += -ldevmapper -llvm -lpthread
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
@@ -46,19 +46,23 @@
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static int cluster_sock;
|
||||
static int num_nodes;
|
||||
static struct cl_cluster_node *nodes = NULL;
|
||||
static struct cman_node *nodes = NULL;
|
||||
static struct cman_node this_node;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static int max_updown_nodes = 50; /* Current size of the allocated array */
|
||||
/* Node up/down status, indexed by nodeid */
|
||||
static int *node_updown = NULL;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
static cman_handle_t c_handle;
|
||||
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
@@ -68,30 +72,23 @@ struct lock_wait {
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
struct sockaddr_cl saddr;
|
||||
int port = CLUSTER_PORT_CLVMD;
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
|
||||
if (cluster_sock == -1) {
|
||||
/* Don't print an error here because we could be just probing for CMAN */
|
||||
c_handle = cman_init(NULL);
|
||||
if (!c_handle) {
|
||||
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
|
||||
return -1;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
fcntl(cluster_sock, F_SETFD, 1);
|
||||
|
||||
/* Bind to our port number on the cluster.
|
||||
Writes to this will block if the cluster loses quorum */
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = port;
|
||||
|
||||
if (bind
|
||||
(cluster_sock, (struct sockaddr *) &saddr,
|
||||
sizeof(struct sockaddr_cl))) {
|
||||
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
|
||||
syslog(LOG_ERR, "Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cman_start_notification(c_handle, event_callback)) {
|
||||
syslog(LOG_ERR, "Can't start cluster event listening");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
@@ -114,63 +111,46 @@ static void _cluster_init_completed(void)
|
||||
|
||||
static int _get_main_cluster_fd()
|
||||
{
|
||||
return cluster_sock;
|
||||
return cman_get_fd(c_handle);
|
||||
}
|
||||
|
||||
static int _get_num_nodes()
|
||||
{
|
||||
return num_nodes;
|
||||
int i;
|
||||
int nnodes = 0;
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
int len = 0;
|
||||
int nodeid = 0;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_flags = 0;
|
||||
iov[0].iov_len = msglen;
|
||||
iov[0].iov_base = buf;
|
||||
if (csid)
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = CLUSTER_PORT_CLVMD;
|
||||
if (csid) {
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
} else { /* Cluster broadcast */
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
len = sendmsg(cluster_sock, &msg, 0);
|
||||
if (len < 0 && errno != EAGAIN)
|
||||
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
|
||||
{
|
||||
log_error(errtext);
|
||||
|
||||
} while (len == -1 && errno == EAGAIN);
|
||||
return len;
|
||||
}
|
||||
return msglen;
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
int i;
|
||||
memset(csid, 0, CMAN_MAX_CSID_LEN);
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodes[i].us)
|
||||
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
|
||||
if (this_node.cn_nodeid == 0) {
|
||||
cman_get_node(c_handle, 0, &this_node);
|
||||
}
|
||||
memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node that known (down mean not running a clvmd) */
|
||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
|
||||
static int _cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *, char *,
|
||||
int))
|
||||
@@ -179,8 +159,8 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
|
||||
if (!node_updown[nodes[i].node_id])
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
|
||||
if (!node_updown[nodes[i].cn_nodeid])
|
||||
somedown = -1;
|
||||
}
|
||||
return somedown;
|
||||
@@ -188,78 +168,63 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
static void process_oob_msg(char *buf, int len, int nodeid)
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[256];
|
||||
switch (buf[0]) {
|
||||
case CLUSTER_OOB_MSG_PORTCLOSED:
|
||||
name_from_nodeid(nodeid, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got OOB message, removing node %s\n", namebuf);
|
||||
char namebuf[MAX_CLUSTER_NAME_LEN];
|
||||
|
||||
node_updown[nodeid] = 0;
|
||||
switch (reason) {
|
||||
case CMAN_REASON_PORTCLOSED:
|
||||
name_from_nodeid(arg, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
|
||||
|
||||
node_updown[arg] = 0;
|
||||
break;
|
||||
|
||||
case CLUSTER_OOB_MSG_STATECHANGE:
|
||||
DEBUGLOG("Got OOB message, Cluster state change\n");
|
||||
case CMAN_REASON_STATECHANGE:
|
||||
DEBUGLOG("Got state change message, re-reading members list\n");
|
||||
get_members();
|
||||
break;
|
||||
|
||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
|
||||
case CMAN_REASON_PORTOPENED:
|
||||
/* Ignore this, wait for startup message from clvmd itself */
|
||||
break;
|
||||
|
||||
case CMAN_REASON_TRY_SHUTDOWN:
|
||||
DEBUGLOG("Got try shutdown, sending OK\n");
|
||||
cman_replyto_shutdown(c_handle, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown OOB message: %d\n", buf[0]);
|
||||
DEBUGLOG("Got unknown event callback message: %d\n", reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
|
||||
static struct local_client *cman_client;
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
|
||||
/* Save this for data_callback */
|
||||
cman_client = fd;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
iov[0].iov_len = len;
|
||||
iov[0].iov_base = buf;
|
||||
return cman_dispatch(c_handle, 0);
|
||||
}
|
||||
|
||||
len = recvmsg(cluster_sock, &msg, MSG_OOB | O_NONBLOCK);
|
||||
if (len < 0 && errno == EAGAIN)
|
||||
return len;
|
||||
|
||||
DEBUGLOG("Read on cluster socket, len = %d\n", len);
|
||||
|
||||
/* A real error */
|
||||
if (len < 0) {
|
||||
log_error("read error on cluster socket: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF - we have left the cluster */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Is it OOB? probably a node gone down */
|
||||
if (msg.msg_flags & MSG_OOB) {
|
||||
process_oob_msg(iov[0].iov_base, len, saddr.scl_nodeid);
|
||||
|
||||
/* Tell the upper layer to ignore this message */
|
||||
len = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
else {
|
||||
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
|
||||
/* Send it back to clvmd */
|
||||
process_message(client, buf, len, csid);
|
||||
}
|
||||
return len;
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid)
|
||||
{
|
||||
/* Ignore looped back messages */
|
||||
if (nodeid == this_node.cn_nodeid)
|
||||
return;
|
||||
process_message(cman_client, buf, len, (char *)&nodeid);
|
||||
}
|
||||
|
||||
static void _add_up_node(char *csid)
|
||||
@@ -290,19 +255,15 @@ static void _cluster_closedown()
|
||||
{
|
||||
unlock_all();
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
close(cluster_sock);
|
||||
cman_finish(c_handle);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
struct cl_listen_request rq;
|
||||
int status;
|
||||
|
||||
rq.port = CLUSTER_PORT_CLVMD;
|
||||
rq.nodeid = nodeid;
|
||||
|
||||
do {
|
||||
status = ioctl(cluster_sock, SIOCCLUSTER_ISLISTENING, &rq);
|
||||
status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
|
||||
if (status < 0 && errno == EBUSY) { /* Don't busywait */
|
||||
sleep(1);
|
||||
errno = EBUSY; /* In case sleep trashes it */
|
||||
@@ -320,19 +281,22 @@ static void count_clvmds_running(void)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
node_updown[nodes[i].node_id] = is_listening(nodes[i].node_id);
|
||||
node_updown[nodes[i].cn_nodeid] = is_listening(nodes[i].cn_nodeid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members()
|
||||
{
|
||||
struct cl_cluster_nodelist nodelist;
|
||||
int retnodes;
|
||||
int status;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
|
||||
num_nodes = cman_get_node_count(c_handle);
|
||||
if (num_nodes == -1) {
|
||||
log_error("Unable to get node count");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
@@ -341,28 +305,19 @@ static void get_members()
|
||||
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cl_cluster_node));
|
||||
nodes = malloc(count_nodes * sizeof(struct cman_node));
|
||||
if (!nodes) {
|
||||
log_error("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
nodelist.max_members = count_nodes;
|
||||
nodelist.nodes = nodes;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
|
||||
if (num_nodes <= 0) {
|
||||
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
|
||||
if (status < 0) {
|
||||
log_error("Unable to get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Sanity check struct */
|
||||
if (nodes[0].size != sizeof(struct cl_cluster_node)) {
|
||||
log_error
|
||||
("sizeof(cl_cluster_node) does not match size returned from the kernel: aborting\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (node_updown == NULL) {
|
||||
node_updown =
|
||||
(int *) malloc(sizeof(int) *
|
||||
@@ -371,7 +326,6 @@ static void get_members()
|
||||
sizeof(int) * max(num_nodes, max_updown_nodes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
static int _csid_from_name(char *csid, char *name)
|
||||
@@ -379,8 +333,8 @@ static int _csid_from_name(char *csid, char *name)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].name) == 0) {
|
||||
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
|
||||
if (strcmp(name, nodes[i].cn_name) == 0) {
|
||||
memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -393,8 +347,8 @@ static int _name_from_csid(char *csid, char *name)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].name);
|
||||
if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -409,8 +363,8 @@ static int name_from_nodeid(int nodeid, char *name)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].node_id) {
|
||||
strcpy(name, nodes[i].name);
|
||||
if (nodeid == nodes[i].cn_nodeid) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -431,7 +385,7 @@ static int nodeid_from_csid(char *csid)
|
||||
|
||||
static int _is_quorate()
|
||||
{
|
||||
return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
|
||||
return cman_is_quorate(c_handle);
|
||||
}
|
||||
|
||||
static void sync_ast_routine(void *arg)
|
||||
|
||||
@@ -56,15 +56,19 @@ struct cluster_ops *init_gulm_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_CMAN
|
||||
# include "cnxman-socket.h"
|
||||
# include <netinet/in.h>
|
||||
# include "libcman.h"
|
||||
# define CMAN_MAX_CSID_LEN 4
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
|
||||
# endif
|
||||
# undef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_NODENAME_LEN
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 1500
|
||||
# define CLUSTER_PORT_CLVMD 11
|
||||
struct cluster_ops *init_cman_cluster(void);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -247,7 +247,7 @@ int main(int argc, char *argv[])
|
||||
if ((clops = init_cman_cluster())) {
|
||||
max_csid_len = CMAN_MAX_CSID_LEN;
|
||||
max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE;
|
||||
max_cluster_member_name_len = CMAN_MAX_CLUSTER_MEMBER_NAME_LEN;
|
||||
max_cluster_member_name_len = CMAN_MAX_NODENAME_LEN;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
|
||||
}
|
||||
#endif
|
||||
@@ -509,6 +509,7 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
int quorate = clops->is_quorate();
|
||||
|
||||
/* Wait on the cluster FD and all local sockets/pipes */
|
||||
local_client_head.fd = clops->get_main_cluster_fd();
|
||||
FD_ZERO(&in);
|
||||
for (thisfd = &local_client_head; thisfd != NULL;
|
||||
thisfd = thisfd->next) {
|
||||
|
||||
@@ -303,6 +303,9 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
}
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_PARTIAL_MODE)
|
||||
init_partial(1);
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, lock_flags, LKM_EXMODE);
|
||||
@@ -331,6 +334,9 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_PARTIAL_MODE)
|
||||
init_partial(0);
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
dm_event_register
|
||||
dm_event_unregister
|
||||
dm_event_get_registered_device
|
||||
dm_event_set_timeout
|
||||
dm_event_get_timeout
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -16,36 +15,41 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
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
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
libdmeventdnoop.so: noop.o
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
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)
|
||||
.PHONY: install_dynamic install_static
|
||||
|
||||
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)
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
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
13
daemons/dmeventd/dmeventd.h
Normal file
13
daemons/dmeventd/dmeventd.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#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)
|
||||
__attribute((noreturn));
|
||||
|
||||
#endif /* __DMEVENTD_DOT_H__ */
|
||||
510
daemons/dmeventd/libdevmapper-event.c
Normal file
510
daemons/dmeventd/libdevmapper-event.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* 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 = dm_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* daemon_read
|
||||
* @fifos
|
||||
* @msg
|
||||
*
|
||||
* Read message from daemon.
|
||||
*
|
||||
* Returns: 0 on failure, 1 on success
|
||||
*/
|
||||
static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
while (bytes < sizeof(*msg)) {
|
||||
do {
|
||||
/* Watch daemon read FIFO for input. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->server, &fds);
|
||||
ret = select(fifos->server+1, &fds, NULL, NULL, NULL);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
/* FIXME Log error */
|
||||
return 0;
|
||||
}
|
||||
} while (ret < 1);
|
||||
|
||||
ret = read(fifos->server, msg, sizeof(*msg) - bytes);
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
/* FIXME Log error */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bytes += ret;
|
||||
}
|
||||
|
||||
return bytes == sizeof(*msg);
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
while (bytes < sizeof(*msg)) {
|
||||
do {
|
||||
/* Watch daemon write FIFO to be ready for output. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->client, &fds);
|
||||
ret = select(fifos->client +1, NULL, &fds, NULL, NULL);
|
||||
if ((ret < 0) && (errno != EINTR)) {
|
||||
/* FIXME Log error */
|
||||
return 0;
|
||||
}
|
||||
} while (ret < 1);
|
||||
|
||||
ret = write(fifos->client, msg, sizeof(*msg) - bytes);
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
/* fixme: log error */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bytes += ret;
|
||||
}
|
||||
|
||||
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) <= (unsigned) 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;
|
||||
void *old_hand;
|
||||
sigset_t set, oset;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (sigemptyset(&set) || sigaddset(&set, SIGUSR1)) {
|
||||
log_error("Unable to fill signal set.");
|
||||
} else if (sigprocmask(SIG_UNBLOCK, &set, &oset)) {
|
||||
log_error("Can't unblock the potentially blocked signal SIGUSR1");
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Sometimes, a single process may perform multiple calls
|
||||
* that result in a daemon starting and exiting. If we
|
||||
* don't reset this, the second (or greater) time the daemon
|
||||
* is started will cause this logic not to work.
|
||||
*/
|
||||
daemon_running = 0;
|
||||
} 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.");
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &oset, NULL))
|
||||
log_error("Unable to reset signal 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 */
|
||||
while ((fifos->client = open(fifos->client_path,
|
||||
O_WRONLY | O_NONBLOCK)) < 0) {
|
||||
if (errno != ENXIO) {
|
||||
log_error("%s: Can't open client fifo %s: %s\n",
|
||||
__func__, fifos->client_path, strerror(errno));
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Unnecessary if daemon was started before calling this */
|
||||
if (!start_daemon()) {
|
||||
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 */
|
||||
/* FIXME Move this to separate 'dm_event_register_handler' - if no daemon here, fail */
|
||||
if (!init_client(&fifos)) {
|
||||
stack;
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
/* FIXME Use separate 'dm_event_register_handler' function to pass in dso? */
|
||||
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
|
||||
|
||||
/* what is the opposite of init? */
|
||||
dtr_client(&fifos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* FIXME remove dso_name - use handle instead */
|
||||
/* FIXME Use uuid not path! */
|
||||
/* External library interface. */
|
||||
int dm_event_register(char *dso_name, char *device_path,
|
||||
enum dm_event_type events)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path)) {
|
||||
log_error("%s: device not found", device_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ret = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 0)) < 0) {
|
||||
log_error("%s: event registration failed: %s", device_path,
|
||||
strerror(-ret));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_event_unregister(char *dso_name, char *device_path,
|
||||
enum dm_event_type events)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path)) {
|
||||
log_error("%s: device not found", device_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ret = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 0)) < 0) {
|
||||
log_error("%s: event deregistration failed: %s", device_path,
|
||||
strerror(-ret));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)
|
||||
dm_free(*dso_name);
|
||||
if (*device_path)
|
||||
dm_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:
|
||||
*/
|
||||
108
daemons/dmeventd/libdevmapper-event.h
Normal file
108
daemons/dmeventd/libdevmapper-event.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 Replace device with standard name/uuid/devno choice */
|
||||
/* Interface changes:
|
||||
First register a handler, passing in a unique ref for the device. */
|
||||
// int dm_event_register_handler(const char *dso_name, const char *device);
|
||||
// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
|
||||
/* Or (better?) add to task structure and use existing functions - run a task to register/unregister events - we may need to run task withe that with the new event mechanism anyway, then the dso calls just hook in.
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
}
|
||||
22
daemons/dmeventd/plugins/Makefile.in
Normal file
22
daemons/dmeventd/plugins/Makefile.in
Normal file
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU 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@
|
||||
|
||||
SUBDIRS += mirror
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
3
daemons/dmeventd/plugins/mirror/.exported_symbols
Normal file
3
daemons/dmeventd/plugins/mirror/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
36
daemons/dmeventd/plugins/mirror/Makefile.in
Normal file
36
daemons/dmeventd/plugins/mirror/Makefile.in
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU 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@
|
||||
|
||||
INCLUDES += -I${top_srcdir}/tools
|
||||
CLDFLAGS += -L${top_srcdir}/tools -ldevmapper -llvm2cmd
|
||||
|
||||
SOURCES = dmeventd_mirror.c
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
LIB_SHARED = libdevmapper-event-lvm2mirror.dylib
|
||||
else
|
||||
LIB_SHARED = libdevmapper-event-lvm2mirror.so
|
||||
endif
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/$<.$(LIB_VERSION)
|
||||
$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$<
|
||||
|
||||
246
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
Normal file
246
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* 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 "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
|
||||
static int _get_mirror_event(char *params)
|
||||
{
|
||||
int i, rtn = ME_INSYNC;
|
||||
int max_args = 30; /* should support at least 8-way mirrors */
|
||||
char *args[max_args];
|
||||
char *dev_status_str;
|
||||
char *log_status_str;
|
||||
char *sync_str;
|
||||
char *p;
|
||||
int log_argc, num_devs, num_failures=0;
|
||||
|
||||
if (max_args <= split_words(params, max_args, args)) {
|
||||
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
*/
|
||||
num_devs = atoi(args[0]);
|
||||
dev_status_str = args[3 + num_devs];
|
||||
log_argc = atoi(args[4 + num_devs]);
|
||||
log_status_str = args[4 + num_devs + log_argc];
|
||||
sync_str = args[1 + num_devs];
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
if (dev_status_str[i] == 'D') {
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
|
||||
num_failures++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bad log device */
|
||||
if (log_status_str[0] == 'D') {
|
||||
syslog(LOG_ERR, "Log device, %s, has failed.\n",
|
||||
args[3 + num_devs + log_argc]);
|
||||
num_failures++;
|
||||
}
|
||||
|
||||
if (num_failures) {
|
||||
rtn = ME_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = strstr(sync_str, "/");
|
||||
if (p) {
|
||||
p[0] = '\0';
|
||||
if (strcmp(sync_str, p+1))
|
||||
rtn = ME_IGNORE;
|
||||
p[0] = '/';
|
||||
} else {
|
||||
/*
|
||||
* How the hell did we get this?
|
||||
* Might mean all our parameters are screwed.
|
||||
*/
|
||||
syslog(LOG_ERR, "Unable to parse sync string.");
|
||||
rtn = ME_IGNORE;
|
||||
}
|
||||
out:
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
|
||||
{
|
||||
return;
|
||||
syslog(LOG_DEBUG, "%s", format);
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
{
|
||||
int r;
|
||||
void *handle;
|
||||
int cmd_size = 256; /* FIXME Use system restriction */
|
||||
char cmd_str[cmd_size];
|
||||
char *vg = NULL, *lv = NULL, *layer = NULL;
|
||||
|
||||
if (strlen(device) > 200)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s",
|
||||
device);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
handle = lvm2_init();
|
||||
lvm2_log_level(handle, 1);
|
||||
r = lvm2_run(handle, cmd_str);
|
||||
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1)? 0: -1;
|
||||
}
|
||||
|
||||
void process_event(const char *device, enum dm_event_type event)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
|
||||
/* FIXME Move inside libdevmapper */
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
syslog(LOG_ERR, "Unable to create dm_task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dm_task_set_name(dmt, device)) {
|
||||
syslog(LOG_ERR, "Unable to set device name.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
syslog(LOG_ERR, "Unable to run task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(_get_mirror_event(params)) {
|
||||
case ME_INSYNC:
|
||||
/* FIXME: all we really know is that this
|
||||
_part_ of the device is in sync
|
||||
Also, this is not an error
|
||||
*/
|
||||
syslog(LOG_NOTICE, "%s is now in-sync\n", device);
|
||||
break;
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s\n", device);
|
||||
if (_remove_failed_devices(device))
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
else
|
||||
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
||||
device);
|
||||
*/
|
||||
break;
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_INFO, "Unknown event received.\n");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
fail:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
}
|
||||
|
||||
int register_device(const char *device)
|
||||
{
|
||||
syslog(LOG_INFO, "Monitoring %s for events\n", device);
|
||||
|
||||
/*
|
||||
* Need some space for allocations. 1024 should be more
|
||||
* than enough for what we need (device mapper name splitting)
|
||||
*/
|
||||
if (!mem_pool)
|
||||
mem_pool = dm_pool_create("mirror_dso", 1024);
|
||||
|
||||
if (!mem_pool)
|
||||
return 0;
|
||||
|
||||
register_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device)
|
||||
{
|
||||
syslog(LOG_INFO, "Stopped monitoring %s for events\n", device);
|
||||
|
||||
if (!(--register_count)) {
|
||||
dm_pool_destroy(mem_pool);
|
||||
mem_pool = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
22
dmeventd/Makefile.in
Normal file
22
dmeventd/Makefile.in
Normal file
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU 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@
|
||||
|
||||
SUBDIRS += mirror
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
3
dmeventd/mirror/.exported_symbols
Normal file
3
dmeventd/mirror/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
36
dmeventd/mirror/Makefile.in
Normal file
36
dmeventd/mirror/Makefile.in
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU 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@
|
||||
|
||||
INCLUDES += -I${top_srcdir}/tools
|
||||
CLDFLAGS += -L${top_srcdir}/tools -ldevmapper -llvm2cmd
|
||||
|
||||
SOURCES = dmeventd_mirror.c
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
LIB_SHARED = libdevmapper-event-lvm2mirror.dylib
|
||||
else
|
||||
LIB_SHARED = libdevmapper-event-lvm2mirror.so
|
||||
endif
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/$<.$(LIB_VERSION)
|
||||
$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$<
|
||||
|
||||
246
dmeventd/mirror/dmeventd_mirror.c
Normal file
246
dmeventd/mirror/dmeventd_mirror.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* 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 "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
|
||||
static int _get_mirror_event(char *params)
|
||||
{
|
||||
int i, rtn = ME_INSYNC;
|
||||
int max_args = 30; /* should support at least 8-way mirrors */
|
||||
char *args[max_args];
|
||||
char *dev_status_str;
|
||||
char *log_status_str;
|
||||
char *sync_str;
|
||||
char *p;
|
||||
int log_argc, num_devs, num_failures=0;
|
||||
|
||||
if (max_args <= split_words(params, max_args, args)) {
|
||||
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
*/
|
||||
num_devs = atoi(args[0]);
|
||||
dev_status_str = args[3 + num_devs];
|
||||
log_argc = atoi(args[4 + num_devs]);
|
||||
log_status_str = args[4 + num_devs + log_argc];
|
||||
sync_str = args[1 + num_devs];
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
if (dev_status_str[i] == 'D') {
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
|
||||
num_failures++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bad log device */
|
||||
if (log_status_str[0] == 'D') {
|
||||
syslog(LOG_ERR, "Log device, %s, has failed.\n",
|
||||
args[3 + num_devs + log_argc]);
|
||||
num_failures++;
|
||||
}
|
||||
|
||||
if (num_failures) {
|
||||
rtn = ME_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = strstr(sync_str, "/");
|
||||
if (p) {
|
||||
p[0] = '\0';
|
||||
if (strcmp(sync_str, p+1))
|
||||
rtn = ME_IGNORE;
|
||||
p[0] = '/';
|
||||
} else {
|
||||
/*
|
||||
* How the hell did we get this?
|
||||
* Might mean all our parameters are screwed.
|
||||
*/
|
||||
syslog(LOG_ERR, "Unable to parse sync string.");
|
||||
rtn = ME_IGNORE;
|
||||
}
|
||||
out:
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
|
||||
{
|
||||
return;
|
||||
syslog(LOG_DEBUG, "%s", format);
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
{
|
||||
int r;
|
||||
void *handle;
|
||||
int cmd_size = 256; /* FIXME Use system restriction */
|
||||
char cmd_str[cmd_size];
|
||||
char *vg = NULL, *lv = NULL, *layer = NULL;
|
||||
|
||||
if (strlen(device) > 200)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s",
|
||||
device);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
handle = lvm2_init();
|
||||
lvm2_log_level(handle, 1);
|
||||
r = lvm2_run(handle, cmd_str);
|
||||
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1)? 0: -1;
|
||||
}
|
||||
|
||||
void process_event(const char *device, enum dm_event_type event)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
|
||||
/* FIXME Move inside libdevmapper */
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
syslog(LOG_ERR, "Unable to create dm_task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dm_task_set_name(dmt, device)) {
|
||||
syslog(LOG_ERR, "Unable to set device name.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
syslog(LOG_ERR, "Unable to run task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(_get_mirror_event(params)) {
|
||||
case ME_INSYNC:
|
||||
/* FIXME: all we really know is that this
|
||||
_part_ of the device is in sync
|
||||
Also, this is not an error
|
||||
*/
|
||||
syslog(LOG_NOTICE, "%s is now in-sync\n", device);
|
||||
break;
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s\n", device);
|
||||
if (_remove_failed_devices(device))
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
else
|
||||
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
||||
device);
|
||||
*/
|
||||
break;
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_INFO, "Unknown event received.\n");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
fail:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
}
|
||||
|
||||
int register_device(const char *device)
|
||||
{
|
||||
syslog(LOG_INFO, "Monitoring %s for events\n", device);
|
||||
|
||||
/*
|
||||
* Need some space for allocations. 1024 should be more
|
||||
* than enough for what we need (device mapper name splitting)
|
||||
*/
|
||||
if (!mem_pool)
|
||||
mem_pool = dm_pool_create("mirror_dso", 1024);
|
||||
|
||||
if (!mem_pool)
|
||||
return 0;
|
||||
|
||||
register_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device)
|
||||
{
|
||||
syslog(LOG_INFO, "Stopped monitoring %s for events\n", device);
|
||||
|
||||
if (!(--register_count)) {
|
||||
dm_pool_destroy(mem_pool);
|
||||
mem_pool = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
@@ -289,4 +289,9 @@ activation {
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
#}
|
||||
|
||||
# Event daemon
|
||||
#
|
||||
#dmeventd {
|
||||
# mirror_library = "libdevmapper-event-lvm2mirror.so"
|
||||
#}
|
||||
|
||||
|
||||
@@ -133,6 +133,10 @@ ifeq ("@HAVE_LIBDL@", "yes")
|
||||
misc/sharedlib.c
|
||||
endif
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
CLDFLAGS += -ldevmapper-event
|
||||
endif
|
||||
|
||||
LIB_STATIC = liblvm.a
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "str_list.h"
|
||||
#include "config.h"
|
||||
#include "filter.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
@@ -75,6 +76,11 @@ int driver_version(char *version, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int target_present(const char *target_name)
|
||||
{
|
||||
return 0;
|
||||
@@ -89,12 +95,12 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, float *percent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
|
||||
uint32_t *event_nr)
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int wait, float *percent, uint32_t *event_nr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -170,8 +176,8 @@ void set_activation(int act)
|
||||
log_verbose("Activation enabled. Device-mapper kernel "
|
||||
"driver will be used.");
|
||||
else
|
||||
log_verbose("Activation disabled. No device-mapper "
|
||||
"interaction will be attempted.");
|
||||
log_print("WARNING: Activation disabled. No device-mapper "
|
||||
"interaction will be attempted.");
|
||||
}
|
||||
|
||||
int activation(void)
|
||||
@@ -277,7 +283,8 @@ int driver_version(char *version, size_t size)
|
||||
return dm_driver_version(version, size);
|
||||
}
|
||||
|
||||
static int _target_present(const char *target_name)
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
@@ -300,6 +307,9 @@ static int _target_present(const char *target_name)
|
||||
|
||||
if (!strcmp(target_name, target->name)) {
|
||||
r = 1;
|
||||
*maj = target->version[0];
|
||||
*min = target->version[1];
|
||||
*patchlevel = target->version[2];
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -314,6 +324,7 @@ static int _target_present(const char *target_name)
|
||||
|
||||
int target_present(const char *target_name, int use_modprobe)
|
||||
{
|
||||
uint32_t maj, min, patchlevel;
|
||||
#ifdef MODPROBE_CMD
|
||||
char module[128];
|
||||
#endif
|
||||
@@ -323,7 +334,7 @@ int target_present(const char *target_name, int use_modprobe)
|
||||
|
||||
#ifdef MODPROBE_CMD
|
||||
if (use_modprobe) {
|
||||
if (_target_present(target_name))
|
||||
if (target_version(target_name, &maj, &min, &patchlevel))
|
||||
return 1;
|
||||
|
||||
if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name)
|
||||
@@ -338,7 +349,7 @@ int target_present(const char *target_name, int use_modprobe)
|
||||
}
|
||||
#endif
|
||||
|
||||
return _target_present(target_name);
|
||||
return target_version(target_name, &maj, &min, &patchlevel);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -396,7 +407,7 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
/*
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, float *percent)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -416,8 +427,8 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
}
|
||||
|
||||
/* FIXME Merge with snapshot_percent */
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wait, float *percent,
|
||||
uint32_t *event_nr)
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int wait, float *percent, uint32_t *event_nr)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -563,18 +574,53 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
return count;
|
||||
}
|
||||
|
||||
static int _register_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
struct list *tmp;
|
||||
struct lv_segment *seg;
|
||||
int (*reg) (struct dm_pool *mem, struct lv_segment *,
|
||||
struct config_tree *cft, int events);
|
||||
|
||||
list_iterate(tmp, &lv->segments) {
|
||||
seg = list_item(tmp, struct lv_segment);
|
||||
|
||||
reg = NULL;
|
||||
|
||||
if (do_reg) {
|
||||
if (seg->segtype->ops->target_register_events)
|
||||
reg = seg->segtype->ops->target_register_events;
|
||||
} else if (seg->segtype->ops->target_unregister_events)
|
||||
reg = seg->segtype->ops->target_unregister_events;
|
||||
|
||||
if (reg)
|
||||
/* FIXME specify events */
|
||||
if (!reg(cmd->mem, seg, cmd->cft, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
int error_if_not_suspended)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct logical_volume *lv, *lv_pre;
|
||||
struct lvinfo info;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
return_0;
|
||||
|
||||
/* Use precommitted metadata if present */
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 1)))
|
||||
return 0;
|
||||
if (!(lv_pre = lv_from_lvid(cmd, lvid_s, 1)))
|
||||
return_0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Suspending '%s'.", lv->name);
|
||||
@@ -588,13 +634,16 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
return error_if_not_suspended ? 0 : 1;
|
||||
|
||||
/* If VG was precommitted, preload devices for the LV */
|
||||
if ((lv->vg->status & PRECOMMITTED)) {
|
||||
if (!_lv_preload(lv)) {
|
||||
if ((lv_pre->vg->status & PRECOMMITTED)) {
|
||||
if (!_lv_preload(lv_pre)) {
|
||||
/* FIXME Revert preloading */
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
if (!_lv_suspend_lv(lv)) {
|
||||
memlock_dec();
|
||||
@@ -645,6 +694,9 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -688,6 +740,9 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
r = _lv_deactivate(lv);
|
||||
memlock_dec();
|
||||
@@ -758,6 +813,9 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ int library_version(char *version, size_t size);
|
||||
int lvm1_present(struct cmd_context *cmd);
|
||||
|
||||
int target_present(const char *target_name, int use_modprobe);
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel);
|
||||
|
||||
void activation_exit(void);
|
||||
|
||||
@@ -68,9 +70,9 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
/*
|
||||
* Returns 1 if percent has been set, else 0.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wait, float *percent,
|
||||
uint32_t *event_nr);
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, float *percent);
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int wait, float *percent, uint32_t *event_nr);
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are active.
|
||||
|
||||
@@ -432,7 +432,8 @@ void dev_manager_exit(void)
|
||||
}
|
||||
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, float *percent)
|
||||
const struct logical_volume *lv,
|
||||
float *percent)
|
||||
{
|
||||
char *name;
|
||||
const char *dlid;
|
||||
@@ -845,7 +846,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;
|
||||
@@ -978,6 +978,8 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
|
||||
goto_out;
|
||||
break;
|
||||
case SUSPEND:
|
||||
if (!lv_is_origin(lv) && !lv_is_cow(lv))
|
||||
dm_tree_skip_lockfs(root);
|
||||
if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
|
||||
goto_out;
|
||||
break;
|
||||
|
||||
@@ -41,7 +41,8 @@ int dev_manager_info(struct dm_pool *mem, const char *name,
|
||||
const struct logical_volume *lv,
|
||||
int mknodes, int with_open_count, struct dm_info *info);
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, float *percent);
|
||||
const struct logical_volume *lv,
|
||||
float *percent);
|
||||
int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, int wait,
|
||||
float *percent, uint32_t *event_nr);
|
||||
|
||||
315
lib/cache/lvmcache.c
vendored
315
lib/cache/lvmcache.c
vendored
@@ -86,7 +86,8 @@ int vgs_locked(void)
|
||||
return _vgs_locked;
|
||||
}
|
||||
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
/* If vgid supplied, require a match. */
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
@@ -96,10 +97,16 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
|
||||
return NULL;
|
||||
|
||||
if (vgid)
|
||||
do
|
||||
if (!strncmp(vgid, vginfo->vgid, sizeof(vginfo->vgid)))
|
||||
return vginfo;
|
||||
while ((vginfo = vginfo->next));
|
||||
|
||||
return vginfo;
|
||||
}
|
||||
|
||||
const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
@@ -107,8 +114,9 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
struct list *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
char vgid_found[ID_LEN + 1];
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname)))
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
|
||||
return NULL;
|
||||
|
||||
/* This function is normally called before reading metadata so
|
||||
@@ -120,6 +128,8 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
list_add(&devs, &devl->list);
|
||||
}
|
||||
|
||||
memcpy(vgid_found, vginfo->vgid, sizeof(vgid_found));
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
@@ -127,6 +137,11 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
dm_free(devl);
|
||||
}
|
||||
|
||||
/* If vginfo changed, caller needs to rescan */
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) ||
|
||||
strncmp(vginfo->vgid, vgid_found, sizeof(vgid_found)))
|
||||
return NULL;
|
||||
|
||||
return vginfo->fmt;
|
||||
}
|
||||
|
||||
@@ -148,6 +163,19 @@ struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
|
||||
return vginfo;
|
||||
}
|
||||
|
||||
const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
if ((vginfo = vginfo_from_vgid(vgid))) {
|
||||
if (mem)
|
||||
return dm_pool_strdup(mem, vginfo->vgname);
|
||||
return vginfo->vgname;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lvmcache_info *info_from_pvid(const char *pvid)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
@@ -232,10 +260,33 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
return r;
|
||||
}
|
||||
|
||||
struct list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct list *vgids;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
lvmcache_label_scan(cmd, full_scan);
|
||||
|
||||
if (!(vgids = str_list_create(cmd->mem))) {
|
||||
log_error("vgids list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(vginfo, &_vginfos) {
|
||||
if (!str_list_add(cmd->mem, vgids,
|
||||
dm_pool_strdup(cmd->mem, vginfo->vgid))) {
|
||||
log_error("strlist allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return vgids;
|
||||
}
|
||||
|
||||
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct list *vgnames;
|
||||
struct lvmcache_vginfo *vgi;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
lvmcache_label_scan(cmd, full_scan);
|
||||
|
||||
@@ -244,9 +295,9 @@ struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(vgi, &_vginfos) {
|
||||
list_iterate_items(vginfo, &_vginfos) {
|
||||
if (!str_list_add(cmd->mem, vgnames,
|
||||
dm_pool_strdup(cmd->mem, vgi->vgname))) {
|
||||
dm_pool_strdup(cmd->mem, vginfo->vgname))) {
|
||||
log_error("strlist allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -297,7 +348,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _drop_vginfo(struct lvmcache_info *info)
|
||||
static int _drop_vginfo(struct lvmcache_info *info)
|
||||
{
|
||||
if (!list_empty(&info->list)) {
|
||||
list_del(&info->list);
|
||||
@@ -306,8 +357,18 @@ static void _drop_vginfo(struct lvmcache_info *info)
|
||||
|
||||
if (info->vginfo && list_empty(&info->vginfo->infos)) {
|
||||
dm_hash_remove(_vgname_hash, info->vginfo->vgname);
|
||||
if (info->vginfo->next) {
|
||||
if (!dm_hash_insert(_vgname_hash, info->vginfo->vgname, info->vginfo->next)) {
|
||||
log_error("vg hash re-insertion failed: %s",
|
||||
info->vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->vginfo->vgname)
|
||||
dm_free(info->vginfo->vgname);
|
||||
if (info->vginfo->creation_host)
|
||||
dm_free(info->vginfo->creation_host);
|
||||
if (*info->vginfo->vgid)
|
||||
dm_hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||
list_del(&info->vginfo->list);
|
||||
@@ -315,6 +376,8 @@ static void _drop_vginfo(struct lvmcache_info *info)
|
||||
}
|
||||
|
||||
info->vginfo = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Unused
|
||||
@@ -356,8 +419,10 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
|
||||
|
||||
if (info->vginfo && *info->vginfo->vgid)
|
||||
dm_hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||
if (!vgid)
|
||||
if (!vgid) {
|
||||
log_debug("lvmcache: %s: clearing VGID", dev_name(info->dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
|
||||
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
|
||||
@@ -367,19 +432,110 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("lvmcache: %s: setting %s VGID to %s", dev_name(info->dev),
|
||||
info->vginfo->vgname, info->vginfo->vgid);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host,
|
||||
struct lvmcache_vginfo *primary_vginfo)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_vginfo *last_vginfo = primary_vginfo;
|
||||
char uuid_primary[64], uuid_new[64];
|
||||
int use_new = 0;
|
||||
|
||||
/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
|
||||
if (primary_vginfo) {
|
||||
if (!id_write_format((struct id *)vgid, uuid_new, sizeof(uuid_new)))
|
||||
return_0;
|
||||
|
||||
if (!id_write_format((struct id *)&primary_vginfo->vgid, uuid_primary,
|
||||
sizeof(uuid_primary)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* If Primary not exported, new exported => keep
|
||||
* Else Primary exported, new not exported => change
|
||||
* Else Primary has hostname for this machine => keep
|
||||
* Else Primary has no hostname, new has one => change
|
||||
* Else New has hostname for this machine => change
|
||||
* Else Keep primary.
|
||||
*/
|
||||
if (!(primary_vginfo->status & EXPORTED_VG) &&
|
||||
(vgstatus & EXPORTED_VG))
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"Existing %s takes precedence over "
|
||||
"exported %s", new_vginfo->vgname,
|
||||
uuid_primary, uuid_new);
|
||||
else if ((primary_vginfo->status & EXPORTED_VG) &&
|
||||
!(vgstatus & EXPORTED_VG)) {
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"%s takes precedence over exported %s",
|
||||
new_vginfo->vgname, uuid_new,
|
||||
uuid_primary);
|
||||
use_new = 1;
|
||||
} else if (primary_vginfo->creation_host &&
|
||||
!strcmp(primary_vginfo->creation_host,
|
||||
primary_vginfo->fmt->cmd->hostname))
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"Existing %s (created here) takes precedence "
|
||||
"over %s", new_vginfo->vgname, uuid_primary,
|
||||
uuid_new);
|
||||
else if (!primary_vginfo->creation_host && creation_host) {
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"%s (with creation_host) takes precedence over %s",
|
||||
new_vginfo->vgname, uuid_new,
|
||||
uuid_primary);
|
||||
use_new = 1;
|
||||
} else if (creation_host &&
|
||||
!strcmp(creation_host,
|
||||
primary_vginfo->fmt->cmd->hostname)) {
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"%s (created here) takes precedence over %s",
|
||||
new_vginfo->vgname, uuid_new,
|
||||
uuid_primary);
|
||||
use_new = 1;
|
||||
}
|
||||
|
||||
if (!use_new) {
|
||||
while (last_vginfo->next)
|
||||
last_vginfo = last_vginfo->next;
|
||||
last_vginfo->next = new_vginfo;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dm_hash_remove(_vgname_hash, primary_vginfo->vgname);
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) {
|
||||
log_error("cache_update: vg hash insertion failed: %s",
|
||||
new_vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (primary_vginfo)
|
||||
new_vginfo->next = primary_vginfo;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vgname(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo, *primary_vginfo;
|
||||
// struct lvmcache_vginfo *old_vginfo, *next;
|
||||
|
||||
/* If vgname is NULL and we don't already have a vgname,
|
||||
* assume ORPHAN - we want every entry to have a vginfo
|
||||
* attached for scanning reasons.
|
||||
*/
|
||||
if (!vgname && !info->vginfo)
|
||||
if (!vgname && !info->vginfo) {
|
||||
vgname = ORPHAN;
|
||||
vgid = ORPHAN;
|
||||
}
|
||||
|
||||
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
|
||||
return 1;
|
||||
@@ -388,7 +544,43 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
_drop_vginfo(info);
|
||||
|
||||
/* Get existing vginfo or create new one */
|
||||
if (!(vginfo = vginfo_from_vgname(vgname))) {
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
|
||||
/*** FIXME - vginfo ends up duplicated instead of renamed.
|
||||
// Renaming? This lookup fails.
|
||||
if ((vginfo = vginfo_from_vgid(vgid))) {
|
||||
next = vginfo->next;
|
||||
old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
|
||||
if (old_vginfo == vginfo) {
|
||||
dm_hash_remove(_vgname_hash, old_vginfo->vgname);
|
||||
if (old_vginfo->next) {
|
||||
if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) {
|
||||
log_error("vg hash re-insertion failed: %s",
|
||||
old_vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else do {
|
||||
if (old_vginfo->next == vginfo) {
|
||||
old_vginfo->next = vginfo->next;
|
||||
break;
|
||||
}
|
||||
} while ((old_vginfo = old_vginfo->next));
|
||||
vginfo->next = NULL;
|
||||
|
||||
dm_free(vginfo->vgname);
|
||||
if (!(vginfo->vgname = dm_strdup(vgname))) {
|
||||
log_error("cache vgname alloc failed for %s", vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Rename so can assume new name does not already exist
|
||||
if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) {
|
||||
log_error("vg hash re-insertion failed: %s",
|
||||
vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
***/
|
||||
if (!(vginfo = dm_malloc(sizeof(*vginfo)))) {
|
||||
log_error("lvmcache_update_vgname: list alloc failed");
|
||||
return 0;
|
||||
@@ -400,9 +592,9 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
return 0;
|
||||
}
|
||||
list_init(&vginfo->infos);
|
||||
if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
|
||||
log_error("cache_update: vg hash insertion failed: %s",
|
||||
vginfo->vgname);
|
||||
primary_vginfo = vginfo_from_vgname(vgname, NULL);
|
||||
if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
|
||||
primary_vginfo)) {
|
||||
dm_free(vginfo->vgname);
|
||||
dm_free(vginfo);
|
||||
return 0;
|
||||
@@ -412,6 +604,9 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
list_add(&_vginfos, &vginfo->list);
|
||||
else
|
||||
list_add_h(&_vginfos, &vginfo->list);
|
||||
/***
|
||||
}
|
||||
***/
|
||||
}
|
||||
|
||||
info->vginfo = vginfo;
|
||||
@@ -420,8 +615,59 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
/* FIXME Check consistency of list! */
|
||||
vginfo->fmt = info->fmt;
|
||||
|
||||
log_debug("lvmcache: %s now %s%s", dev_name(info->dev),
|
||||
*vgname ? "in VG " : "orphaned", vgname);
|
||||
log_debug("lvmcache: %s: now %s%s%s%s%s", dev_name(info->dev),
|
||||
*vgname ? "in VG " : "orphaned", vgname,
|
||||
vginfo->vgid[0] ? " (" : "",
|
||||
vginfo->vgid[0] ? vginfo->vgid : "",
|
||||
vginfo->vgid[0] ? ")" : "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
|
||||
const char *creation_host)
|
||||
{
|
||||
if (!info || !info->vginfo)
|
||||
return 1;
|
||||
|
||||
if ((info->vginfo->status & EXPORTED_VG) != (vgstatus & EXPORTED_VG))
|
||||
log_debug("lvmcache: %s: VG %s %s exported",
|
||||
dev_name(info->dev), info->vginfo->vgname,
|
||||
vgstatus & EXPORTED_VG ? "now" : "no longer");
|
||||
|
||||
info->vginfo->status = vgstatus;
|
||||
|
||||
if (!creation_host)
|
||||
return 1;
|
||||
|
||||
if (info->vginfo->creation_host && !strcmp(creation_host,
|
||||
info->vginfo->creation_host))
|
||||
return 1;
|
||||
|
||||
if (info->vginfo->creation_host)
|
||||
dm_free(info->vginfo->creation_host);
|
||||
|
||||
if (!(info->vginfo->creation_host = dm_strdup(creation_host))) {
|
||||
log_error("cache creation host alloc failed for %s",
|
||||
creation_host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("lvmcache: %s: VG %s: Set creation host to %s.",
|
||||
dev_name(info->dev), info->vginfo->vgname, creation_host);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host)
|
||||
{
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
|
||||
creation_host) ||
|
||||
!_lvmcache_update_vgid(info, vgid) ||
|
||||
!_lvmcache_update_vgstatus(info, vgstatus, creation_host))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -431,20 +677,17 @@ int lvmcache_update_vg(struct volume_group *vg)
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
int vgid_updated = 0;
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||
if ((info = info_from_pvid(pvid_s))) {
|
||||
lvmcache_update_vgname(info, vg->name);
|
||||
if (!vgid_updated) {
|
||||
_lvmcache_update_vgid(info, (char *) &vg->id);
|
||||
vgid_updated = 1;
|
||||
}
|
||||
}
|
||||
if ((info = info_from_pvid(pvid_s)) &&
|
||||
!lvmcache_update_vgname_and_id(info, vg->name,
|
||||
(char *) &vg->id,
|
||||
vg->status, NULL))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -452,7 +695,8 @@ int lvmcache_update_vg(struct volume_group *vg)
|
||||
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid)
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus)
|
||||
{
|
||||
struct label *label;
|
||||
struct lvmcache_info *existing, *info;
|
||||
@@ -548,7 +792,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!lvmcache_update_vgname(info, vgname)) {
|
||||
if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
|
||||
if (!existing) {
|
||||
dm_hash_remove(_pvid_hash, pvid_s);
|
||||
strcpy(info->dev->pvid, "");
|
||||
@@ -558,10 +802,6 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_lvmcache_update_vgid(info, vgid))
|
||||
/* Non-critical */
|
||||
stack;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -576,9 +816,16 @@ static void _lvmcache_destroy_entry(struct lvmcache_info *info)
|
||||
|
||||
static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
|
||||
{
|
||||
if (vginfo->vgname)
|
||||
dm_free(vginfo->vgname);
|
||||
dm_free(vginfo);
|
||||
struct lvmcache_vginfo *next;
|
||||
|
||||
do {
|
||||
next = vginfo->next;
|
||||
if (vginfo->vgname)
|
||||
dm_free(vginfo->vgname);
|
||||
if (vginfo->creation_host)
|
||||
dm_free(vginfo->creation_host);
|
||||
dm_free(vginfo);
|
||||
} while ((vginfo = next));
|
||||
}
|
||||
|
||||
static void _lvmcache_destroy_lockname(int present)
|
||||
|
||||
22
lib/cache/lvmcache.h
vendored
22
lib/cache/lvmcache.h
vendored
@@ -33,15 +33,20 @@ struct cmd_context;
|
||||
struct format_type;
|
||||
struct volume_group;
|
||||
|
||||
/* One per VG */
|
||||
struct lvmcache_vginfo {
|
||||
struct list list; /* Join these vginfos together */
|
||||
struct list infos; /* List head for lvmcache_infos */
|
||||
const struct format_type *fmt;
|
||||
char *vgname; /* "" == orphan */
|
||||
uint32_t status;
|
||||
char vgid[ID_LEN + 1];
|
||||
char _padding[7];
|
||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||
char *creation_host;
|
||||
};
|
||||
|
||||
/* One per device */
|
||||
struct lvmcache_info {
|
||||
struct list list; /* Join VG members together */
|
||||
struct list mdas; /* list head for metadata areas */
|
||||
@@ -64,21 +69,26 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
|
||||
/* Add/delete a device */
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid);
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus);
|
||||
void lvmcache_del(struct lvmcache_info *info);
|
||||
|
||||
/* Update things */
|
||||
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname);
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *hostname);
|
||||
int lvmcache_update_vg(struct volume_group *vg);
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||
void lvmcache_unlock_vgname(const char *vgname);
|
||||
|
||||
/* Queries */
|
||||
const struct format_type *fmt_from_vgname(const char *vgname);
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname);
|
||||
const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid);
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname,
|
||||
const char *vgid);
|
||||
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
|
||||
struct lvmcache_info *info_from_pvid(const char *pvid);
|
||||
const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid);
|
||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
|
||||
int vgs_locked(void);
|
||||
int vgname_is_locked(const char *vgname);
|
||||
@@ -87,4 +97,8 @@ int vgname_is_locked(const char *vgname);
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
/* Returns list of struct str_lists containing pool-allocated copy of vgids */
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
struct list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -657,7 +657,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
|
||||
"format"))) {
|
||||
"format", 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -753,7 +753,7 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
|
||||
"segment type"))) {
|
||||
"segment type", 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
|
||||
|
||||
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#ifdef LVM1_FALLBACK
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -223,11 +223,11 @@ static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_vgd(struct disk_list *data)
|
||||
int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
|
||||
{
|
||||
struct vg_disk *vgd = &data->vgd;
|
||||
uint64_t pos = data->pvd.vg_on_disk.base;
|
||||
if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
|
||||
uint64_t pos = pvd->vg_on_disk.base;
|
||||
|
||||
if (!dev_read(dev, pos, sizeof(*vgd), vgd))
|
||||
fail;
|
||||
|
||||
_xlate_vgd(vgd);
|
||||
@@ -319,13 +319,31 @@ static int _read_extents(struct disk_list *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __update_lvmcache(const struct format_type *fmt,
|
||||
struct disk_list *dl,
|
||||
struct device *dev, const char *vgid,
|
||||
int exported)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
||||
dl->pvd.vg_name, vgid,
|
||||
exported ? EXPORTED_VG : 0))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
|
||||
list_init(&info->mdas);
|
||||
info->status &= ~CACHE_INVALID;
|
||||
}
|
||||
|
||||
static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
struct device *dev, struct dm_pool *mem,
|
||||
const char *vg_name)
|
||||
{
|
||||
struct disk_list *dl = dm_pool_alloc(mem, sizeof(*dl));
|
||||
struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl));
|
||||
const char *name = dev_name(dev);
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!dl) {
|
||||
stack;
|
||||
@@ -342,41 +360,32 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
||||
dl->pvd.vg_name, NULL)))
|
||||
stack;
|
||||
else {
|
||||
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
|
||||
list_init(&info->mdas);
|
||||
info->status &= ~CACHE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
*/
|
||||
if (!*dl->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any format1 VG", name);
|
||||
|
||||
/* Update VG cache */
|
||||
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
|
||||
|
||||
__update_lvmcache(fmt, dl, dev, NULL, 0);
|
||||
return (vg_name) ? NULL : dl;
|
||||
}
|
||||
|
||||
if (!_read_vgd(dl)) {
|
||||
if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) {
|
||||
log_error("Failed to read VG data from PV (%s)", name);
|
||||
__update_lvmcache(fmt, dl, dev, NULL, 0);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Update VG cache with what we found */
|
||||
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
|
||||
|
||||
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
||||
log_very_verbose("%s is not a member of the VG %s",
|
||||
name, vg_name);
|
||||
__update_lvmcache(fmt, dl, dev, NULL, 0);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
__update_lvmcache(fmt, dl, dev, dl->vgd.vg_uuid,
|
||||
dl->vgd.vg_status & VG_EXPORTED);
|
||||
|
||||
if (!_read_uuids(dl)) {
|
||||
log_error("Failed to read PV uuid list from %s", name);
|
||||
goto bad;
|
||||
@@ -461,7 +470,7 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
struct lvmcache_info *info;
|
||||
|
||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
|
||||
vginfo->infos.n) {
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
dev = info->dev;
|
||||
|
||||
@@ -204,7 +204,8 @@ int write_disks(const struct format_type *fmt, struct list *pvds);
|
||||
*/
|
||||
int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd);
|
||||
struct physical_volume *pv, struct pv_disk *pvd,
|
||||
struct vg_disk *vgd);
|
||||
int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct pv_disk *pvd, struct physical_volume *pv);
|
||||
@@ -237,6 +238,7 @@ void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||
|
||||
void export_pv_act(struct list *pvds);
|
||||
int munge_pvd(struct device *dev, struct pv_disk *pvd);
|
||||
int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd);
|
||||
|
||||
/* blech */
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
|
||||
@@ -312,7 +312,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
|
||||
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -396,7 +396,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
|
||||
pv->vg_name, NULL))) {
|
||||
pv->vg_name, NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -502,6 +502,7 @@ static struct metadata_area_ops _metadata_format1_ops = {
|
||||
|
||||
static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||
const char *vgname,
|
||||
const char *vgid,
|
||||
void *private)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
|
||||
@@ -49,7 +49,8 @@ static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
|
||||
|
||||
int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd)
|
||||
struct physical_volume *pv, struct pv_disk *pvd,
|
||||
struct vg_disk *vgd)
|
||||
{
|
||||
memset(pv, 0, sizeof(*pv));
|
||||
memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
|
||||
@@ -60,6 +61,8 @@ int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
|
||||
|
||||
/* Store system_id from first PV if PV belongs to a VG */
|
||||
if (vg && !*vg->system_id)
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
@@ -426,7 +429,7 @@ int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd)) {
|
||||
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -140,7 +140,12 @@ static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg,
|
||||
lvm = lvms[lv_num];
|
||||
|
||||
if (!lvm) {
|
||||
log_err("invalid lv in extent map");
|
||||
log_error("Invalid LV in extent map "
|
||||
"(PV %s, PE %" PRIu32
|
||||
", LV %" PRIu32
|
||||
", LE %" PRIu32 ")",
|
||||
dev_name(pv->dev), i,
|
||||
lv_num, e[i].le_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,11 +58,20 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||
struct vg_disk vgd;
|
||||
struct lvmcache_info *info;
|
||||
const char *vgid = NULL;
|
||||
int exported = 0;
|
||||
|
||||
munge_pvd(dev, pvd);
|
||||
|
||||
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
|
||||
if (*pvd->vg_name && read_vgd(dev, &vgd, pvd)) {
|
||||
vgid = vgd.vg_uuid;
|
||||
exported = pvd->pv_status & VG_EXPORTED;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, vgid,
|
||||
exported))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
|
||||
|
||||
if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
|
||||
(char *) &vgid))) {
|
||||
(char *) &vgid, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -314,7 +314,7 @@ int read_pool_pds(const struct format_type *fmt, const char *vg_name,
|
||||
/*
|
||||
* If the cache scanning doesn't work, this will never work
|
||||
*/
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
|
||||
vginfo->infos.n) {
|
||||
|
||||
if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
|
||||
|
||||
@@ -268,6 +268,7 @@ static struct metadata_area_ops _metadata_format_pool_ops = {
|
||||
|
||||
static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||
const char *vgname,
|
||||
const char *vgid,
|
||||
void *private)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
|
||||
@@ -165,6 +165,7 @@ int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
log_error("Unable to duplicate vg_name string");
|
||||
return 0;
|
||||
}
|
||||
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
|
||||
pv->status = 0;
|
||||
pv->size = pd->pl_blocks;
|
||||
pv->pe_size = POOL_PE_SIZE;
|
||||
|
||||
@@ -207,8 +207,8 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
/* Convert retain_days into the time after which we must retain */
|
||||
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
|
||||
|
||||
/* Assume list is ordered oldest first (by index) */
|
||||
list_iterate_items(bf, archives) {
|
||||
/* Assume list is ordered newest first (by index) */
|
||||
list_iterate_back_items(bf, archives) {
|
||||
/* Get the mtime of the file and unlink if too old */
|
||||
if (stat(bf->path, &sb)) {
|
||||
log_sys_error("stat", bf->path);
|
||||
@@ -311,7 +311,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||
|
||||
if (!(context = create_text_context(cmd, af->path, NULL)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
NULL, context))) {
|
||||
log_error("Couldn't create text instance object.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
if (!(context = create_text_context(cmd, file,
|
||||
cmd->cmd_line)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
NULL, context))) {
|
||||
log_error("Couldn't create text format object.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -286,7 +286,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
/* Attempt to write out using currently active format */
|
||||
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
|
||||
NULL))) {
|
||||
NULL, NULL))) {
|
||||
log_error("Failed to allocate format instance");
|
||||
return 0;
|
||||
}
|
||||
@@ -365,7 +365,7 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
|
||||
|
||||
if (!(context = create_text_context(cmd, file, desc)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
NULL, context))) {
|
||||
log_error("Couldn't create backup object.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
static struct format_instance *_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
void *context);
|
||||
|
||||
struct text_fid_context {
|
||||
@@ -219,7 +220,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
|
||||
error:
|
||||
if ((info = info_from_pvid(dev_area->dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -858,9 +859,11 @@ static int _scan_file(const struct format_type *fmt)
|
||||
}
|
||||
|
||||
/* FIXME stat file to see if it's changed */
|
||||
fid = _create_text_instance(fmt, NULL, NULL);
|
||||
fid = _create_text_instance(fmt, NULL, NULL,
|
||||
NULL);
|
||||
if ((vg = _vg_read_file_name(fid, vgname,
|
||||
path)))
|
||||
/* FIXME Store creation host in vg */
|
||||
lvmcache_update_vg(vg);
|
||||
}
|
||||
|
||||
@@ -871,65 +874,92 @@ static int _scan_file(const struct format_type *fmt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||
char *buf, uint32_t size)
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint32_t *vgstatus, char **creation_host)
|
||||
{
|
||||
struct raw_locn *rlocn;
|
||||
struct mda_header *mdah;
|
||||
unsigned int len;
|
||||
int r = 0;
|
||||
uint32_t wrap = 0;
|
||||
const char *vgname = NULL;
|
||||
unsigned int len = 0;
|
||||
char buf[NAME_LEN + 1];
|
||||
|
||||
if (!dev_open(dev_area->dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fmt, dev_area))) {
|
||||
stack;
|
||||
if (!(mdah = _raw_read_mda_header(fmt, dev_area)))
|
||||
goto_out;
|
||||
|
||||
/* FIXME Cope with returning a list */
|
||||
rlocn = mdah->raw_locns;
|
||||
|
||||
/* Do quick check for a vgname */
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
NAME_LEN, buf))
|
||||
goto_out;
|
||||
|
||||
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
|
||||
len < (NAME_LEN - 1))
|
||||
len++;
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(buf))
|
||||
goto_out;
|
||||
|
||||
/* We found a VG - now check the metadata */
|
||||
if (rlocn->offset + rlocn->size > mdah->size)
|
||||
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
|
||||
|
||||
if (wrap > rlocn->offset) {
|
||||
log_error("%s: metadata too large for circular buffer",
|
||||
dev_name(dev_area->dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
/* FIXME 64-bit */
|
||||
if (!(vgname = text_vgname_import(fmt, dev_area->dev,
|
||||
(off_t) (dev_area->start +
|
||||
rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (dev_area->start +
|
||||
MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, rlocn->checksum,
|
||||
vgid, vgstatus, creation_host)))
|
||||
goto_out;
|
||||
|
||||
while (rlocn->offset) {
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
size, buf)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
len = 0;
|
||||
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
|
||||
len < (size - 1))
|
||||
len++;
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(buf)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
break;
|
||||
|
||||
/* FIXME Cope with returning a list */
|
||||
rlocn++;
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(vgname)) {
|
||||
stack;
|
||||
vgname = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_debug("%s: Found metadata at %" PRIu64 " size %" PRIu64
|
||||
" for %s (%s)",
|
||||
dev_name(dev_area->dev), dev_area->start + rlocn->offset,
|
||||
rlocn->size, vgname, vgid->uuid);
|
||||
|
||||
out:
|
||||
if (!dev_close(dev_area->dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
return vgname;
|
||||
}
|
||||
|
||||
static int _scan_raw(const struct format_type *fmt)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct list *raw_list;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
const char *vgname;
|
||||
struct volume_group *vg;
|
||||
struct format_instance fid;
|
||||
struct id vgid;
|
||||
uint32_t vgstatus;
|
||||
|
||||
raw_list = &((struct mda_lists *) fmt->private)->raws;
|
||||
|
||||
@@ -938,9 +968,9 @@ static int _scan_raw(const struct format_type *fmt)
|
||||
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME We're reading mdah twice here... */
|
||||
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
|
||||
if ((vgname = vgname_from_mda(fmt, &rl->dev_area, &vgid, &vgstatus,
|
||||
NULL))) {
|
||||
if ((vg = _vg_read_raw_area(&fid, vgname,
|
||||
&rl->dev_area, 0)))
|
||||
lvmcache_update_vg(vg);
|
||||
}
|
||||
@@ -1109,7 +1139,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
/* FIXME Test mode don't update cache? */
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
|
||||
ORPHAN, NULL))) {
|
||||
ORPHAN, NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1245,7 +1275,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
/* Have we already cached vgname? */
|
||||
if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
info->vginfo->vgid, info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1256,6 +1286,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
if (info->vginfo && info->vginfo->vgname &&
|
||||
*info->vginfo->vgname &&
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->vginfo->vgid,
|
||||
info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1450,6 +1481,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
/* NULL vgname means use only the supplied context e.g. an archive file */
|
||||
static struct format_instance *_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
void *context)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
@@ -1535,7 +1567,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
|
||||
/* Scan PVs in VG for any further MDAs */
|
||||
lvmcache_label_scan(fmt->cmd, 0);
|
||||
if (!(vginfo = vginfo_from_vgname(vgname))) {
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -1569,7 +1601,6 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
|
||||
out:
|
||||
return fid;
|
||||
|
||||
}
|
||||
|
||||
void *create_text_context(struct cmd_context *cmd, const char *path,
|
||||
|
||||
@@ -54,7 +54,8 @@ int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct list *mda
|
||||
struct device *dev, uint64_t start, uint64_t size);
|
||||
void del_mdas(struct list *mdas);
|
||||
|
||||
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||
char *buf, uint32_t size);
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint32_t *vgstatus, char **creation_host);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,6 +47,10 @@ struct text_vg_version_ops {
|
||||
struct config_tree * cf);
|
||||
void (*read_desc) (struct dm_pool * mem, struct config_tree * cf,
|
||||
time_t *when, char **desc);
|
||||
const char *(*read_vgname) (const struct format_type *fmt,
|
||||
struct config_tree *cft,
|
||||
struct id *vgid, uint32_t *vgstatus,
|
||||
char **creation_host);
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||
@@ -70,5 +74,12 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
checksum_fn_t checksum_fn,
|
||||
uint32_t checksum,
|
||||
time_t *when, char **desc);
|
||||
const char *text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
struct id *vgid, uint32_t *vgstatus,
|
||||
char **creation_host);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,53 @@
|
||||
/* FIXME Use tidier inclusion method */
|
||||
static struct text_vg_version_ops *(_text_vsn_list[2]);
|
||||
|
||||
const char *text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
struct id *vgid, uint32_t *vgstatus,
|
||||
char **creation_host)
|
||||
{
|
||||
struct config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
const char *vgname;
|
||||
|
||||
static int _initialised = 0;
|
||||
|
||||
if (!_initialised) {
|
||||
_text_vsn_list[0] = text_vg_vsn1_init();
|
||||
_text_vsn_list[1] = NULL;
|
||||
_initialised = 1;
|
||||
}
|
||||
|
||||
if (!(cft = create_config_tree(NULL)))
|
||||
goto_out;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
(dev && !read_config_fd(cft, dev, offset, size,
|
||||
offset2, size2, checksum_fn, checksum)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Find a set of version functions that can read this file
|
||||
*/
|
||||
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(vgname = (*vsn)->read_vgname(fmt, cft, vgid, vgstatus,
|
||||
creation_host)))
|
||||
goto_out;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
destroy_config_tree(cft);
|
||||
return vgname;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct device *dev,
|
||||
|
||||
@@ -167,6 +167,8 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
|
||||
|
||||
if (!(cn = find_config_node(pvn, "status"))) {
|
||||
log_error("Couldn't find status flags for physical volume.");
|
||||
return 0;
|
||||
@@ -798,10 +800,59 @@ static void _read_desc(struct dm_pool *mem,
|
||||
*when = u;
|
||||
}
|
||||
|
||||
static const char *_read_vgname(const struct format_type *fmt,
|
||||
struct config_tree *cft, struct id *vgid,
|
||||
uint32_t *vgstatus, char **creation_host)
|
||||
{
|
||||
struct config_node *vgn, *cn;
|
||||
struct dm_pool *mem = fmt->cmd->mem;
|
||||
char *vgname;
|
||||
int old_suppress;
|
||||
|
||||
old_suppress = log_suppress(2);
|
||||
*creation_host = dm_pool_strdup(mem,
|
||||
find_config_str(cft->root,
|
||||
"creation_host", ""));
|
||||
log_suppress(old_suppress);
|
||||
|
||||
/* skip any top-level values */
|
||||
for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
||||
|
||||
if (!vgn) {
|
||||
log_error("Couldn't find volume group in file.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vgname = dm_pool_strdup(mem, vgn->key)))
|
||||
return_0;
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
if (!_read_id(vgid, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(vgn, "status"))) {
|
||||
log_error("Couldn't find status flags for volume group %s.",
|
||||
vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(read_flags(vgstatus, VG_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for volume group %s.",
|
||||
vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vgname;
|
||||
}
|
||||
|
||||
static struct text_vg_version_ops _vsn1_ops = {
|
||||
check_version:_check_version,
|
||||
read_vg:_read_vg,
|
||||
read_desc:_read_desc
|
||||
read_desc:_read_desc,
|
||||
read_vgname:_read_vgname
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void)
|
||||
|
||||
@@ -195,13 +195,16 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
struct disk_locn *dlocn_xl;
|
||||
uint64_t offset;
|
||||
struct metadata_area *mda;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct id vgid;
|
||||
struct mda_context *mdac;
|
||||
const char *vgname;
|
||||
uint32_t vgstatus;
|
||||
char *creation_host;
|
||||
|
||||
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||
|
||||
if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
|
||||
return 0;
|
||||
if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL, 0)))
|
||||
return_0;
|
||||
*label = info->label;
|
||||
|
||||
info->device_size = xlate64(pvhdr->device_size_xl);
|
||||
@@ -232,10 +235,12 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
lvmcache_update_vgname(info, vgnamebuf);
|
||||
}
|
||||
if ((vgname = vgname_from_mda(info->fmt, &mdac->area,
|
||||
&vgid, &vgstatus, &creation_host)) &&
|
||||
!lvmcache_update_vgname_and_id(info, vgname,
|
||||
(char *) &vgid, vgstatus,
|
||||
creation_host))
|
||||
return_0;
|
||||
}
|
||||
|
||||
info->status &= ~CACHE_INVALID;
|
||||
|
||||
@@ -117,15 +117,6 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
goto out;
|
||||
@@ -184,13 +175,11 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
out:
|
||||
if (!found) {
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -272,16 +261,29 @@ int label_read(struct device *dev, struct label **result)
|
||||
char buf[LABEL_SIZE];
|
||||
struct labeller *l;
|
||||
uint64_t sector;
|
||||
int r;
|
||||
struct lvmcache_info *info;
|
||||
int r = 0;
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
goto_out;
|
||||
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
(*result)->sector = sector;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -335,18 +337,35 @@ int label_write(struct device *dev, struct label *label)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Unused */
|
||||
int label_verify(struct device *dev)
|
||||
{
|
||||
struct labeller *l;
|
||||
char buf[LABEL_SIZE];
|
||||
uint64_t sector;
|
||||
struct lvmcache_info *info;
|
||||
int r = 0;
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
return ((l->ops->verify) ? l->ops->verify(l, buf, sector) : 1);
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
goto_out;
|
||||
|
||||
r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void label_destroy(struct label *label)
|
||||
|
||||
@@ -330,6 +330,9 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
args[0] = flags & 0x7F; /* Maskoff lock flags */
|
||||
args[1] = flags & 0xC0; /* Bitmap flags */
|
||||
|
||||
if (partial_mode())
|
||||
args[1] |= LCK_PARTIAL_MODE;
|
||||
|
||||
/*
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
* so we only need to do them on the local node because all
|
||||
|
||||
@@ -72,7 +72,7 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
libname = find_config_str(cft->root, "global/locking_library",
|
||||
DEFAULT_LOCKING_LIB);
|
||||
|
||||
if (!(_locking_lib = load_shared_library(cft, libname, "locking"))) {
|
||||
if (!(_locking_lib = load_shared_library(cft, libname, "locking", 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,11 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
#define LCK_LOCAL 0x00000040 /* Don't propagate to other nodes */
|
||||
#define LCK_CLUSTER_VG 0x00000080 /* VG is clustered */
|
||||
|
||||
/*
|
||||
* Additional lock bits for cluster communication
|
||||
*/
|
||||
#define LCK_PARTIAL_MODE 0x00000001 /* Running in partial mode */
|
||||
|
||||
/*
|
||||
* Common combinations
|
||||
*/
|
||||
|
||||
@@ -90,9 +90,13 @@ void init_syslog(int facility)
|
||||
_syslog = 1;
|
||||
}
|
||||
|
||||
void log_suppress(int suppress)
|
||||
int log_suppress(int suppress)
|
||||
{
|
||||
int old_suppress = _log_suppress;
|
||||
|
||||
_log_suppress = suppress;
|
||||
|
||||
return old_suppress;
|
||||
}
|
||||
|
||||
void release_log_memory(void)
|
||||
@@ -253,6 +257,9 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
const char *message;
|
||||
const char *trformat; /* Translated format string */
|
||||
|
||||
if (_log_suppress == 2)
|
||||
return;
|
||||
|
||||
trformat = _(format);
|
||||
|
||||
if (_lvm2_log_fn) {
|
||||
|
||||
@@ -86,8 +86,9 @@ int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr */
|
||||
void log_suppress(int suppress);
|
||||
/* Suppress messages to stdout/stderr (1) or everywhere (2) */
|
||||
/* Returns previous setting */
|
||||
int log_suppress(int suppress);
|
||||
|
||||
/* Suppress messages to syslog */
|
||||
void syslog_suppress(int suppress);
|
||||
|
||||
@@ -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) * ah->area_multiple;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
|
||||
|
||||
/* Units of 512-byte sectors */
|
||||
pv->pe_size = vg->extent_size;
|
||||
|
||||
@@ -143,13 +145,14 @@ static int _copy_pv(struct physical_volume *pv_to,
|
||||
}
|
||||
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv)
|
||||
const char *vgid, const char *pvid,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct pv_list *pvl;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
|
||||
if (!(vg = vg_read(fmt->cmd, vg_name, vgid, &consistent))) {
|
||||
log_error("get_pv_from_vg_by_id: vg_read failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
@@ -160,7 +163,7 @@ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
vg_name);
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
|
||||
if (!_copy_pv(pv, pvl->pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -239,7 +242,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
/* is this vg name already in use ? */
|
||||
old_partial = partial_mode();
|
||||
init_partial(1);
|
||||
if (vg_read(cmd, vg_name, &consistent)) {
|
||||
if (vg_read(cmd, vg_name, NULL, &consistent)) {
|
||||
log_err("A volume group called '%s' already exists.", vg_name);
|
||||
goto bad;
|
||||
}
|
||||
@@ -286,7 +289,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
|
||||
NULL))) {
|
||||
NULL, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
goto bad;
|
||||
}
|
||||
@@ -496,7 +499,7 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
uint64_t pvmetadatasize, struct list *mdas)
|
||||
{
|
||||
struct dm_pool *mem = fmt->cmd->mem;
|
||||
struct physical_volume *pv = dm_pool_alloc(mem, sizeof(*pv));
|
||||
struct physical_volume *pv = dm_pool_zalloc(mem, sizeof(*pv));
|
||||
|
||||
if (!pv) {
|
||||
stack;
|
||||
@@ -862,7 +865,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
struct volume_group *vg;
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(ORPHAN))) {
|
||||
if (!(vginfo = vginfo_from_vgname(ORPHAN, NULL))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -907,6 +910,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
*/
|
||||
static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
const char *vgid,
|
||||
int *consistent, int precommitted)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
@@ -928,15 +932,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
|
||||
/* Find the vgname in the cache */
|
||||
/* If it's not there we must do full scan to be completely sure */
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
if (!(fmt = fmt_from_vgname(vgname, vgid))) {
|
||||
lvmcache_label_scan(cmd, 0);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
if (!(fmt = fmt_from_vgname(vgname, vgid))) {
|
||||
if (memlock()) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
if (!(fmt = fmt_from_vgname(vgname, vgid))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -947,7 +951,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
use_precommitted = 0;
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
return NULL;
|
||||
}
|
||||
@@ -978,7 +982,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
inconsistent = 0;
|
||||
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
if (!(fmt = fmt_from_vgname(vgname, vgid))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -987,7 +991,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
use_precommitted = 0;
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1069,12 +1073,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int *consistent)
|
||||
const char *vgid, int *consistent)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct lv_list *lvl;
|
||||
|
||||
if (!(vg = _vg_read(cmd, vgname, consistent, 0)))
|
||||
if (!(vg = _vg_read(cmd, vgname, vgid, consistent, 0)))
|
||||
return NULL;
|
||||
|
||||
if (!check_pv_segments(vg)) {
|
||||
@@ -1112,7 +1116,7 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
/* Is corresponding vgname already cached? */
|
||||
if ((vginfo = vginfo_from_vgid(vgid)) &&
|
||||
vginfo->vgname && *vginfo->vgname) {
|
||||
if ((vg = _vg_read(cmd, vginfo->vgname,
|
||||
if ((vg = _vg_read(cmd, vginfo->vgname, vgid,
|
||||
&consistent, precommitted)) &&
|
||||
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
|
||||
if (!consistent) {
|
||||
@@ -1143,7 +1147,7 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
if (!vgname || !*vgname)
|
||||
continue; // FIXME Unnecessary?
|
||||
consistent = 0;
|
||||
if ((vg = _vg_read(cmd, vgname, &consistent,
|
||||
if ((vg = _vg_read(cmd, vgname, vgid, &consistent,
|
||||
precommitted)) &&
|
||||
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
|
||||
if (!consistent) {
|
||||
@@ -1245,13 +1249,18 @@ struct list *get_vgs(struct cmd_context *cmd, int full_scan)
|
||||
return lvmcache_get_vgnames(cmd, full_scan);
|
||||
}
|
||||
|
||||
struct list *get_vgids(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
return lvmcache_get_vgids(cmd, full_scan);
|
||||
}
|
||||
|
||||
struct list *get_pvs(struct cmd_context *cmd)
|
||||
{
|
||||
struct str_list *strl;
|
||||
struct list *results;
|
||||
const char *vgname;
|
||||
const char *vgname, *vgid;
|
||||
struct list *pvh, *tmp;
|
||||
struct list *vgnames;
|
||||
struct list *vgids;
|
||||
struct volume_group *vg;
|
||||
int consistent = 0;
|
||||
int old_partial;
|
||||
@@ -1267,7 +1276,7 @@ struct list *get_pvs(struct cmd_context *cmd)
|
||||
list_init(results);
|
||||
|
||||
/* Get list of VGs */
|
||||
if (!(vgnames = get_vgs(cmd, 0))) {
|
||||
if (!(vgids = get_vgids(cmd, 0))) {
|
||||
log_error("get_pvs: get_vgs failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1278,12 +1287,16 @@ struct list *get_pvs(struct cmd_context *cmd)
|
||||
old_pvmove = pvmove_mode();
|
||||
init_partial(1);
|
||||
init_pvmove(1);
|
||||
list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname)
|
||||
list_iterate_items(strl, vgids) {
|
||||
vgid = strl->str;
|
||||
if (!vgid)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent))) {
|
||||
if (!(vgname = vgname_from_vgid(NULL, vgid))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
if (!(vg = vg_read(cmd, vgname, vgid, &consistent))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ struct physical_volume {
|
||||
struct device *dev;
|
||||
const struct format_type *fmt;
|
||||
const char *vg_name;
|
||||
struct id vgid;
|
||||
|
||||
uint32_t status;
|
||||
uint64_t size;
|
||||
@@ -382,6 +383,7 @@ struct format_handler {
|
||||
*/
|
||||
struct format_instance *(*create_instance) (const struct format_type *
|
||||
fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
void *context);
|
||||
|
||||
/*
|
||||
@@ -403,7 +405,7 @@ int vg_write(struct volume_group *vg);
|
||||
int vg_commit(struct volume_group *vg);
|
||||
int vg_revert(struct volume_group *vg);
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
int *consistent);
|
||||
const char *vgid, int *consistent);
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
struct list *mdas, uint64_t *label_sector,
|
||||
int warnings);
|
||||
@@ -411,6 +413,7 @@ struct list *get_pvs(struct cmd_context *cmd);
|
||||
|
||||
/* Set full_scan to 1 to re-read every (filtered) device label */
|
||||
struct list *get_vgs(struct cmd_context *cmd, int full_scan);
|
||||
struct list *get_vgids(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector);
|
||||
@@ -478,7 +481,8 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id);
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv);
|
||||
const char *vgid, const char *pvid,
|
||||
struct physical_volume *pv);
|
||||
|
||||
/* Find an LV within a given VG */
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
|
||||
@@ -535,11 +539,16 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le);
|
||||
*/
|
||||
int lv_is_origin(const struct logical_volume *lv);
|
||||
int lv_is_cow(const struct logical_volume *lv);
|
||||
int lv_is_visible(const struct logical_volume *lv);
|
||||
|
||||
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
|
||||
|
||||
/* Given a cow LV, return return the snapshot lv_segment that uses it */
|
||||
struct lv_segment *find_cow(const struct logical_volume *lv);
|
||||
|
||||
/* Given a cow LV, return its origin */
|
||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv);
|
||||
|
||||
int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
struct logical_volume *origin, struct logical_volume *cow,
|
||||
union lvid *lvid, uint32_t extent_count,
|
||||
@@ -561,8 +570,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.
|
||||
|
||||
@@ -78,6 +78,12 @@ struct segtype_handler {
|
||||
uint64_t *total_denominator, float *percent);
|
||||
int (*target_present) (void);
|
||||
void (*destroy) (const struct segment_type * segtype);
|
||||
int (*target_register_events) (struct dm_pool *mem,
|
||||
struct lv_segment *seg,
|
||||
struct config_tree *cft, int events);
|
||||
int (*target_unregister_events) (struct dm_pool *mem,
|
||||
struct lv_segment *seg,
|
||||
struct config_tree *cft, int events);
|
||||
};
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
|
||||
@@ -28,12 +28,26 @@ int lv_is_cow(const struct logical_volume *lv)
|
||||
return lv->snapshot ? 1 : 0;
|
||||
}
|
||||
|
||||
int lv_is_visible(const struct logical_volume *lv)
|
||||
{
|
||||
if (lv_is_cow(lv))
|
||||
return lv_is_visible(find_cow(lv)->lv);
|
||||
|
||||
return lv->status & VISIBLE_LV ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Given a cow LV, return the snapshot lv_segment that uses it */
|
||||
struct lv_segment *find_cow(const struct logical_volume *lv)
|
||||
{
|
||||
return lv->snapshot;
|
||||
}
|
||||
|
||||
/* Given a cow LV, return its origin */
|
||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
|
||||
{
|
||||
return lv->snapshot->origin;
|
||||
}
|
||||
|
||||
int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
struct logical_volume *origin,
|
||||
struct logical_volume *cow, union lvid *lvid,
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
#include "lvm-string.h"
|
||||
#include "targets.h"
|
||||
#include "activate.h"
|
||||
#include "sharedlib.h"
|
||||
|
||||
#ifdef DMEVENTD
|
||||
# include <libdevmapper-event.h>
|
||||
#endif
|
||||
|
||||
static int _block_on_error_available = 0;
|
||||
|
||||
enum {
|
||||
MIRR_DISABLED,
|
||||
@@ -221,6 +228,7 @@ static int _add_log(struct dev_manager *dm, struct lv_segment *seg,
|
||||
{
|
||||
unsigned clustered = 0;
|
||||
char *log_dlid = NULL;
|
||||
uint32_t log_flags = 0;
|
||||
|
||||
/*
|
||||
* Use clustered mirror log for non-exclusive activation
|
||||
@@ -237,8 +245,10 @@ static int _add_log(struct dev_manager *dm, struct lv_segment *seg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Add sync parm? */
|
||||
return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count);
|
||||
if (_block_on_error_available && !(seg->status & PVMOVE))
|
||||
log_flags |= DM_BLOCK_ON_ERROR;
|
||||
|
||||
return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count, log_flags);
|
||||
}
|
||||
|
||||
static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem,
|
||||
@@ -316,15 +326,115 @@ static int _target_present(void)
|
||||
{
|
||||
static int checked = 0;
|
||||
static int present = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
unsigned maj2, min2, patchlevel2;
|
||||
char vsn[80];
|
||||
|
||||
if (!checked)
|
||||
if (!checked) {
|
||||
present = target_present("mirror", 1);
|
||||
|
||||
/*
|
||||
* block_on_error available with mirror target >= 1.1
|
||||
* or with 1.0 in RHEL4U3 driver >= 4.5
|
||||
*/
|
||||
/* FIXME Move this into libdevmapper */
|
||||
|
||||
if (target_version("mirror", &maj, &min, &patchlevel) &&
|
||||
maj == 1 &&
|
||||
(min >= 1 ||
|
||||
(min == 0 && driver_version(vsn, sizeof(vsn)) &&
|
||||
sscanf(vsn, "%u.%u.%u", &maj2, &min2, &patchlevel2) == 3 &&
|
||||
maj2 == 4 && min2 == 5 && patchlevel2 == 0))) /* RHEL4U3 */
|
||||
_block_on_error_available = 1;
|
||||
}
|
||||
|
||||
checked = 1;
|
||||
|
||||
return present;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DMEVENTD
|
||||
static int _setup_registration(struct dm_pool *mem, struct config_tree *cft,
|
||||
char **dso)
|
||||
{
|
||||
char *path;
|
||||
const char *libpath;
|
||||
|
||||
if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
|
||||
log_error("Failed to allocate dmeventd library path.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
libpath = find_config_str(cft->root, "dmeventd/mirror_library",
|
||||
DEFAULT_DMEVENTD_MIRROR_LIB);
|
||||
|
||||
get_shared_library_path(cft, libpath, path, PATH_MAX);
|
||||
|
||||
*dso = path;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
/* FIXME Merge these two functions */
|
||||
static int _target_register_events(struct dm_pool *mem,
|
||||
struct lv_segment *seg,
|
||||
struct config_tree *cft, int events)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_setup_registration(mem, cft, &dso)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(name = build_dm_name(mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
/* FIXME Save a returned handle here so we can unregister it later */
|
||||
if (!dm_event_register(dso, name, DM_EVENT_ALL_ERRORS))
|
||||
return_0;
|
||||
|
||||
log_info("Registered %s for events", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _target_unregister_events(struct dm_pool *mem,
|
||||
struct lv_segment *seg,
|
||||
struct config_tree *cft, int events)
|
||||
{
|
||||
char *dso;
|
||||
char *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
/* FIXME Remove this and use handle to avoid config file race */
|
||||
if (!_setup_registration(mem, cft, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
/* FIXME Use handle returned by registration function instead of dso */
|
||||
if (!dm_event_unregister(dso, name, DM_EVENT_ALL_ERRORS))
|
||||
return_0;
|
||||
|
||||
log_info("Unregistered %s for events", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* DMEVENTD */
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
static void _destroy(const struct segment_type *segtype)
|
||||
{
|
||||
@@ -341,6 +451,10 @@ static struct segtype_handler _mirrored_ops = {
|
||||
add_target_line:_add_target_line,
|
||||
target_percent:_target_percent,
|
||||
target_present:_target_present,
|
||||
#ifdef DMEVENTD
|
||||
target_register_events:_target_register_events,
|
||||
target_unregister_events:_target_unregister_events,
|
||||
#endif
|
||||
#endif
|
||||
destroy:_destroy,
|
||||
};
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void _get_library_path(struct config_tree *cft, const char *libname,
|
||||
char *path, int path_len)
|
||||
void get_shared_library_path(struct config_tree *cft, const char *libname,
|
||||
char *path, int path_len)
|
||||
{
|
||||
struct stat info;
|
||||
const char *lib_dir;
|
||||
@@ -38,17 +38,23 @@ static void _get_library_path(struct config_tree *cft, const char *libname,
|
||||
}
|
||||
|
||||
void *load_shared_library(struct config_tree *cft, const char *libname,
|
||||
const char *desc)
|
||||
const char *desc, int silent)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
void *library;
|
||||
|
||||
_get_library_path(cft, libname, path, sizeof(path));
|
||||
get_shared_library_path(cft, libname, path, sizeof(path));
|
||||
|
||||
log_very_verbose("Opening shared %s library %s", desc, path);
|
||||
|
||||
if (!(library = dlopen(path, RTLD_LAZY)))
|
||||
log_error("Unable to open external %s library %s", desc, path);
|
||||
if (!(library = dlopen(path, RTLD_LAZY))) {
|
||||
if (silent && ignorelockingfailure())
|
||||
log_verbose("Unable to open external %s library %s",
|
||||
desc, path);
|
||||
else
|
||||
log_error("Unable to open external %s library %s",
|
||||
desc, path);
|
||||
}
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
@@ -16,5 +16,7 @@
|
||||
#include "config.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
void get_shared_library_path(struct config_tree *cft, const char *libname,
|
||||
char *path, int path_len);
|
||||
void *load_shared_library(struct config_tree *cf, const char *libname,
|
||||
const char *what);
|
||||
const char *what, int silent);
|
||||
|
||||
@@ -324,7 +324,6 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lvinfo info;
|
||||
char *repstr;
|
||||
struct lv_segment *snap_seg;
|
||||
float snap_percent;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
|
||||
@@ -344,7 +343,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
repstr[0] = 'v';
|
||||
else if (lv_is_origin(lv))
|
||||
repstr[0] = 'o';
|
||||
else if (find_cow(lv))
|
||||
else if (lv_is_cow(lv))
|
||||
repstr[0] = 's';
|
||||
else
|
||||
repstr[0] = '-';
|
||||
@@ -377,8 +376,8 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
repstr[4] = 'd'; /* Inactive without table */
|
||||
|
||||
/* Snapshot dropped? */
|
||||
if (info.live_table && (snap_seg = find_cow(lv)) &&
|
||||
(!lv_snapshot_percent(snap_seg->cow, &snap_percent) ||
|
||||
if (info.live_table && lv_is_cow(lv) &&
|
||||
(!lv_snapshot_percent(lv, &snap_percent) ||
|
||||
snap_percent < 0 || snap_percent >= 100)) {
|
||||
repstr[0] = toupper(repstr[0]);
|
||||
if (info.suspended)
|
||||
@@ -491,10 +490,9 @@ static int _origin_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lv_segment *snap_seg;
|
||||
|
||||
if ((snap_seg = find_cow(lv)))
|
||||
return _string_disp(rh, field, &snap_seg->origin->name);
|
||||
if (lv_is_cow(lv))
|
||||
return _string_disp(rh, field, &origin_from_cow(lv)->name);
|
||||
|
||||
field->report_string = "";
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
@@ -527,8 +525,7 @@ static int _lvname_disp(struct report_handle *rh, struct field *field,
|
||||
char *repstr;
|
||||
size_t len;
|
||||
|
||||
/* FIXME Remove need for snapshot special case */
|
||||
if (lv->status & VISIBLE_LV || lv_is_cow(lv)) {
|
||||
if (lv_is_visible(lv)) {
|
||||
repstr = lv->name;
|
||||
return _string_disp(rh, field, &repstr);
|
||||
}
|
||||
@@ -667,11 +664,10 @@ static int _chunksize_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||
struct lv_segment *snap_seg;
|
||||
uint64_t size;
|
||||
|
||||
if ((snap_seg = find_cow(seg->lv)))
|
||||
size = (uint64_t) snap_seg->chunk_size;
|
||||
if (lv_is_cow(seg->lv))
|
||||
size = (uint64_t) find_cow(seg->lv)->chunk_size;
|
||||
else
|
||||
size = 0;
|
||||
|
||||
@@ -840,7 +836,6 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lv_segment *snap_seg;
|
||||
struct lvinfo info;
|
||||
float snap_percent;
|
||||
uint64_t *sortval;
|
||||
@@ -851,16 +846,15 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(snap_seg = find_cow(lv)) ||
|
||||
(lv_info(lv->vg->cmd, snap_seg->cow, &info, 0) && !info.exists)) {
|
||||
if (!lv_is_cow(lv) ||
|
||||
(lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
|
||||
field->report_string = "";
|
||||
*sortval = UINT64_C(0);
|
||||
field->sort_value = sortval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lv_snapshot_percent(snap_seg->cow, &snap_percent)
|
||||
|| snap_percent < 0) {
|
||||
if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
|
||||
field->report_string = "100.00";
|
||||
*sortval = UINT64_C(100);
|
||||
field->sort_value = sortval;
|
||||
|
||||
@@ -2,6 +2,7 @@ dm_lib_release
|
||||
dm_lib_exit
|
||||
dm_driver_version
|
||||
dm_get_library_version
|
||||
dm_log
|
||||
dm_log_init
|
||||
dm_log_init_verbose
|
||||
dm_task_create
|
||||
@@ -22,9 +23,14 @@ dm_task_set_major
|
||||
dm_task_set_minor
|
||||
dm_task_set_sector
|
||||
dm_task_set_message
|
||||
dm_task_set_uid
|
||||
dm_task_set_gid
|
||||
dm_task_set_mode
|
||||
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
|
||||
@@ -58,14 +64,16 @@ dm_tree_node_add_striped_target
|
||||
dm_tree_node_add_mirror_target
|
||||
dm_tree_node_add_mirror_target_log
|
||||
dm_tree_node_add_target_area
|
||||
dm_tree_skip_lockfs
|
||||
dm_is_dm_major
|
||||
dm_mknodes
|
||||
dm_malloc_aux
|
||||
dm_strdup
|
||||
dm_malloc_aux_debug
|
||||
dm_strdup_aux
|
||||
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
|
||||
@@ -100,3 +108,4 @@ dm_hash_get_data
|
||||
dm_hash_get_first
|
||||
dm_hash_get_next
|
||||
dm_set_selinux_context
|
||||
dm_task_set_geometry
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -57,7 +57,7 @@ void dm_bit_union(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
|
||||
*/
|
||||
static inline int _test_word(uint32_t test, int bit)
|
||||
{
|
||||
while (bit < DM_BITS_PER_INT) {
|
||||
while (bit < (int) DM_BITS_PER_INT) {
|
||||
if (test & (0x1 << bit))
|
||||
return bit;
|
||||
bit++;
|
||||
@@ -73,7 +73,10 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit)
|
||||
|
||||
last_bit++; /* otherwise we'll return the same bit again */
|
||||
|
||||
while (last_bit < bs[0]) {
|
||||
/*
|
||||
* bs[0] holds number of bits
|
||||
*/
|
||||
while (last_bit < (int) bs[0]) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (DM_BITS_PER_INT - 1);
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
struct dm_hash_node {
|
||||
struct dm_hash_node *next;
|
||||
void *data;
|
||||
int keylen;
|
||||
unsigned keylen;
|
||||
char key[0];
|
||||
};
|
||||
|
||||
struct dm_hash_table {
|
||||
int num_nodes;
|
||||
int num_slots;
|
||||
unsigned num_nodes;
|
||||
unsigned num_slots;
|
||||
struct dm_hash_node **slots;
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ static unsigned char _nums[] = {
|
||||
209
|
||||
};
|
||||
|
||||
static struct dm_hash_node *_create_node(const char *str, int len)
|
||||
static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||
{
|
||||
struct dm_hash_node *n = dm_malloc(sizeof(*n) + len);
|
||||
|
||||
@@ -68,13 +68,14 @@ static struct dm_hash_node *_create_node(const char *str, int len)
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned _hash(const char *str, uint32_t len)
|
||||
static unsigned long _hash(const unsigned char *str, unsigned len)
|
||||
{
|
||||
unsigned long h = 0, g, i;
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[(int) *str++];
|
||||
h += _nums[*str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
@@ -120,7 +121,7 @@ struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
||||
static void _free_nodes(struct dm_hash_table *t)
|
||||
{
|
||||
struct dm_hash_node *c, *n;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
@@ -136,8 +137,8 @@ void dm_hash_destroy(struct dm_hash_table *t)
|
||||
dm_free(t);
|
||||
}
|
||||
|
||||
static inline struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
{
|
||||
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||
struct dm_hash_node **c;
|
||||
@@ -153,11 +154,12 @@ void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
return *c ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
int dm_hash_insert_binary(struct dm_hash_table *t, const char *key,
|
||||
uint32_t len, void *data)
|
||||
uint32_t len, void *data)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
@@ -214,7 +216,7 @@ unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
|
||||
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
|
||||
{
|
||||
struct dm_hash_node *c;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = c->next)
|
||||
@@ -225,7 +227,7 @@ void dm_hash_wipe(struct dm_hash_table *t)
|
||||
{
|
||||
_free_nodes(t);
|
||||
memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
|
||||
t->num_nodes = 0;
|
||||
t->num_nodes = 0u;
|
||||
}
|
||||
|
||||
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
@@ -241,7 +243,7 @@ void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
|
||||
{
|
||||
struct dm_hash_node *c = NULL;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = s; i < t->num_slots && !c; i++)
|
||||
c = t->slots[i];
|
||||
@@ -257,5 +259,6 @@ struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
|
||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
{
|
||||
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ static struct cmd_data _cmd_data_v1[] = {
|
||||
{ "mknodes", 0, {4, 0, 0} },
|
||||
{ "versions", 0, {4, 1, 0} },
|
||||
{ "message", 0, {4, 2, 0} },
|
||||
{ "setgeometry",0, {4, 6, 0} },
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
|
||||
@@ -59,7 +59,9 @@
|
||||
#define NUMBER_OF_MAJORS 4096
|
||||
|
||||
/* dm major version no for running kernel */
|
||||
static int _dm_version = DM_VERSION_MAJOR;
|
||||
static unsigned _dm_version = DM_VERSION_MAJOR;
|
||||
static unsigned _dm_version_minor = 0;
|
||||
static unsigned _dm_version_patchlevel = 0;
|
||||
static int _log_suppress = 0;
|
||||
|
||||
static dm_bitset_t _dm_bitset = NULL;
|
||||
@@ -103,6 +105,9 @@ static struct cmd_data _cmd_data_v4[] = {
|
||||
#ifdef DM_TARGET_MSG
|
||||
{"message", DM_TARGET_MSG, {4, 2, 0}},
|
||||
#endif
|
||||
#ifdef DM_DEV_SET_GEOMETRY
|
||||
{"setgeometry", DM_DEV_SET_GEOMETRY, {4, 6, 0}},
|
||||
#endif
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@@ -236,10 +241,10 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (!set_selinux_context(control, S_IFCHR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dm_set_selinux_context(control, S_IFCHR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
@@ -672,11 +677,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 */
|
||||
@@ -740,7 +747,7 @@ static int _dm_task_run_v1(struct dm_task *dmt)
|
||||
|
||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
|
||||
{
|
||||
unsigned int *v;
|
||||
unsigned *v;
|
||||
|
||||
#ifdef DM_COMPAT
|
||||
if (_dm_version == 1)
|
||||
@@ -754,6 +761,9 @@ int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
|
||||
|
||||
v = dmt->dmi.v4->version;
|
||||
snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
|
||||
_dm_version_minor = v[1];
|
||||
_dm_version_patchlevel = v[2];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -799,7 +809,7 @@ int dm_check_version(void)
|
||||
if (!_dm_compat)
|
||||
goto bad;
|
||||
|
||||
log_verbose("device-mapper ioctl protocol version %d failed. "
|
||||
log_verbose("device-mapper ioctl protocol version %u failed. "
|
||||
"Trying protocol version 1.", _dm_version);
|
||||
_dm_version = 1;
|
||||
if (_check_version(dmversion, sizeof(dmversion), 0)) {
|
||||
@@ -875,7 +885,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, (size_t) bufsize, "%u:%u", dev_major, dev_minor);
|
||||
if (r < 0 || r > bufsize - 1)
|
||||
return 0;
|
||||
|
||||
@@ -966,6 +976,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))) {
|
||||
@@ -993,6 +1009,23 @@ int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start)
|
||||
{
|
||||
size_t len = strlen(cylinders) + 1 + strlen(heads) + 1 + strlen(sectors) + 1 + strlen(start) + 1;
|
||||
|
||||
if (!(dmt->geometry = dm_malloc(len))) {
|
||||
log_error("dm_task_set_geometry: dm_malloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sprintf(dmt->geometry, "%s %s %s %s", cylinders, heads, sectors, start) < 0) {
|
||||
log_error("dm_task_set_geometry: sprintf failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_no_open_count(struct dm_task *dmt)
|
||||
{
|
||||
dmt->no_open_count = 1;
|
||||
@@ -1020,7 +1053,8 @@ struct target *create_target(uint64_t start, uint64_t len, const char *type,
|
||||
struct target *t = dm_malloc(sizeof(*t));
|
||||
|
||||
if (!t) {
|
||||
log_error("create_target: malloc(%d) failed", sizeof(*t));
|
||||
log_error("create_target: malloc(%" PRIsize_t ") failed",
|
||||
sizeof(*t));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1086,6 +1120,40 @@ static void *_add_target(struct target *t, void *out, void *end)
|
||||
return out;
|
||||
}
|
||||
|
||||
static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
|
||||
{
|
||||
struct dm_names *names;
|
||||
unsigned next = 0;
|
||||
struct dm_task *dmt;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
|
||||
return 0;
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
if (!(names = dm_task_get_names(dmt)))
|
||||
goto out;
|
||||
|
||||
if (!names->dev)
|
||||
goto out;
|
||||
|
||||
do {
|
||||
names = (void *) names + next;
|
||||
if (names->dev == dev) {
|
||||
strncpy(buf, names->name, len);
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
next = names->next;
|
||||
} while (next);
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
{
|
||||
const size_t min_size = 16 * 1024;
|
||||
@@ -1114,11 +1182,26 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (count && dmt->geometry) {
|
||||
log_error("targets and geometry are incompatible");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dmt->newname && (dmt->sector || dmt->message)) {
|
||||
log_error("message and newname are incompatible");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dmt->newname && dmt->geometry) {
|
||||
log_error("geometry and newname are incompatible");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dmt->geometry && (dmt->sector || dmt->message)) {
|
||||
log_error("geometry and message are incompatible");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dmt->sector && !dmt->message) {
|
||||
log_error("message is required with sector");
|
||||
return NULL;
|
||||
@@ -1130,6 +1213,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
if (dmt->message)
|
||||
len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
|
||||
|
||||
if (dmt->geometry)
|
||||
len += strlen(dmt->geometry) + 1;
|
||||
|
||||
/*
|
||||
* Give len a minimum size so that we have space to store
|
||||
* dependencies or status information.
|
||||
@@ -1155,16 +1241,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
dmi->data_size = len;
|
||||
dmi->data_start = sizeof(struct dm_ioctl);
|
||||
|
||||
if (dmt->dev_name)
|
||||
strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));
|
||||
|
||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||
dmi->flags |= DM_SUSPEND_FLAG;
|
||||
if (dmt->read_only)
|
||||
dmi->flags |= DM_READONLY_FLAG;
|
||||
if (dmt->skip_lockfs)
|
||||
dmi->flags |= DM_SKIP_LOCKFS_FLAG;
|
||||
|
||||
if (dmt->minor >= 0) {
|
||||
if (dmt->major <= 0) {
|
||||
log_error("Missing major number for persistent device.");
|
||||
@@ -1174,9 +1250,31 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
dmi->dev = MKDEV(dmt->major, dmt->minor);
|
||||
}
|
||||
|
||||
/* Does driver support device number referencing? */
|
||||
if (_dm_version_minor < 3 && !dmt->dev_name && !dmt->uuid && dmi->dev) {
|
||||
if (!_lookup_dev_name(dmi->dev, dmi->name, sizeof(dmi->name))) {
|
||||
log_error("Unable to find name for device (%" PRIu32
|
||||
":%" PRIu32 ")", dmt->major, dmt->minor);
|
||||
goto bad;
|
||||
}
|
||||
log_verbose("device (%" PRIu32 ":%" PRIu32 ") is %s "
|
||||
"for compatibility with old kernel",
|
||||
dmt->major, dmt->minor, dmi->name);
|
||||
}
|
||||
|
||||
if (dmt->dev_name)
|
||||
strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));
|
||||
|
||||
if (dmt->uuid)
|
||||
strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
|
||||
|
||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||
dmi->flags |= DM_SUSPEND_FLAG;
|
||||
if (dmt->read_only)
|
||||
dmi->flags |= DM_READONLY_FLAG;
|
||||
if (dmt->skip_lockfs)
|
||||
dmi->flags |= DM_SKIP_LOCKFS_FLAG;
|
||||
|
||||
dmi->target_count = count;
|
||||
dmi->event_nr = dmt->event_nr;
|
||||
|
||||
@@ -1196,6 +1294,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
strcpy(tmsg->message, dmt->message);
|
||||
}
|
||||
|
||||
if (dmt->geometry)
|
||||
strcpy(b, dmt->geometry);
|
||||
|
||||
return dmi;
|
||||
|
||||
bad:
|
||||
@@ -1302,6 +1403,9 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
|
||||
task->major = dmt->major;
|
||||
task->minor = dmt->minor;
|
||||
task->uid = dmt->uid;
|
||||
task->gid = dmt->gid;
|
||||
task->mode = dmt->mode;
|
||||
|
||||
r = dm_task_run(task);
|
||||
dm_task_destroy(task);
|
||||
@@ -1330,7 +1434,7 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
task->tail = NULL;
|
||||
dm_task_destroy(task);
|
||||
if (!r)
|
||||
return r;
|
||||
goto revert;
|
||||
|
||||
/* Use the original structure last so the info will be correct */
|
||||
dmt->type = DM_DEVICE_RESUME;
|
||||
@@ -1339,6 +1443,82 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
|
||||
r = dm_task_run(dmt);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
revert:
|
||||
dmt->type = DM_DEVICE_REMOVE;
|
||||
dm_free(dmt->uuid);
|
||||
dmt->uuid = NULL;
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
log_error("Failed to revert device creation.");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1361,7 +1541,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
if (dmt->no_open_count)
|
||||
dmi->flags |= DM_SKIP_BDGET_FLAG;
|
||||
|
||||
log_debug("dm %s %s %s%s%s %s%0.0d%s%0.0d%s"
|
||||
log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
|
||||
"%s%c %.0llu %s [%u]",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||
@@ -1383,13 +1563,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 +1581,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 +1613,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;
|
||||
|
||||
@@ -1484,6 +1674,9 @@ repeat_ioctl:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Was structure reused? */
|
||||
if (dmt->dmi.v4)
|
||||
dm_free(dmt->dmi.v4);
|
||||
dmt->dmi.v4 = dmi;
|
||||
return 1;
|
||||
|
||||
|
||||
@@ -50,9 +50,11 @@ struct dm_task {
|
||||
} dmi;
|
||||
char *newname;
|
||||
char *message;
|
||||
char *geometry;
|
||||
uint64_t sector;
|
||||
int no_open_count;
|
||||
int skip_lockfs;
|
||||
int suppress_identical_reload;
|
||||
|
||||
char *uuid;
|
||||
};
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
*/
|
||||
|
||||
typedef void (*dm_log_fn) (int level, const char *file, int line,
|
||||
const char *f, ...);
|
||||
const char *f, ...)
|
||||
__attribute__ ((format(printf, 4, 5)));
|
||||
|
||||
/*
|
||||
* The library user may wish to register their own
|
||||
@@ -79,7 +80,9 @@ enum {
|
||||
|
||||
DM_DEVICE_LIST_VERSIONS,
|
||||
|
||||
DM_DEVICE_TARGET_MSG
|
||||
DM_DEVICE_TARGET_MSG,
|
||||
|
||||
DM_DEVICE_SET_GEOMETRY
|
||||
};
|
||||
|
||||
struct dm_task;
|
||||
@@ -140,11 +143,16 @@ int dm_task_set_ro(struct dm_task *dmt);
|
||||
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
|
||||
int dm_task_set_minor(struct dm_task *dmt, int minor);
|
||||
int dm_task_set_major(struct dm_task *dmt, int major);
|
||||
int dm_task_set_uid(struct dm_task *dmt, uid_t uid);
|
||||
int dm_task_set_gid(struct dm_task *dmt, gid_t gid);
|
||||
int dm_task_set_mode(struct dm_task *dmt, mode_t mode);
|
||||
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
|
||||
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start);
|
||||
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 +176,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
|
||||
*/
|
||||
@@ -292,6 +306,13 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Skip the filesystem sync when suspending.
|
||||
* Does nothing with other functions.
|
||||
* Use this when no snapshots are involved.
|
||||
*/
|
||||
void dm_tree_skip_lockfs(struct dm_tree_node *dnode);
|
||||
|
||||
/*
|
||||
* Is the uuid prefix present in the tree?
|
||||
* Only returns 0 if every node was checked successfully.
|
||||
@@ -324,11 +345,18 @@ int dm_tree_node_add_striped_target(struct dm_tree_node *node,
|
||||
uint32_t stripe_size);
|
||||
int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
|
||||
uint64_t size);
|
||||
|
||||
/* Mirror log flags */
|
||||
#define DM_NOSYNC 0x00000001 /* Known already in sync */
|
||||
#define DM_FORCESYNC 0x00000002 /* Force resync */
|
||||
#define DM_BLOCK_ON_ERROR 0x00000004 /* On error, suspend I/O */
|
||||
|
||||
int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
|
||||
uint32_t region_size,
|
||||
unsigned clustered,
|
||||
const char *log_uuid,
|
||||
unsigned area_count);
|
||||
unsigned area_count,
|
||||
uint32_t flags);
|
||||
int dm_tree_node_add_target_area(struct dm_tree_node *node,
|
||||
const char *dev_name,
|
||||
const char *dlid,
|
||||
@@ -343,29 +371,34 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
|
||||
*******************/
|
||||
|
||||
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_debug(size_t s, const char *file, int line);
|
||||
char *dm_strdup_aux(const char *str, 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_strdup(s) dm_strdup_aux((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_strdup(s) strdup(s)
|
||||
# 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
|
||||
@@ -498,6 +531,17 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
|
||||
#define dm_bit_copy(bs1, bs2) \
|
||||
memcpy(bs1 + 1, bs2 + 1, ((*bs1 / DM_BITS_PER_INT) + 1) * sizeof(int))
|
||||
|
||||
/* Returns number of set bits */
|
||||
static inline unsigned hweight32(uint32_t i)
|
||||
{
|
||||
unsigned r = (i & 0x55555555) + ((i >> 1) & 0x55555555);
|
||||
|
||||
r = (r & 0x33333333) + ((r >> 2) & 0x33333333);
|
||||
r = (r & 0x0F0F0F0F) + ((r >> 4) & 0x0F0F0F0F);
|
||||
r = (r & 0x00FF00FF) + ((r >> 8) & 0x00FF00FF);
|
||||
return (r & 0x0000FFFF) + ((r >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
/****************
|
||||
* hash functions
|
||||
****************/
|
||||
@@ -532,9 +576,9 @@ struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_no
|
||||
for (v = dm_hash_get_first(h); v; \
|
||||
v = dm_hash_get_next(h, v))
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
/*********
|
||||
* selinux
|
||||
*********/
|
||||
int dm_set_selinux_context(const char *path, mode_t mode);
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
@@ -61,14 +61,14 @@ static void _default_log(int level, const char *file, int line,
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
dm_log_fn _log = _default_log;
|
||||
dm_log_fn dm_log = _default_log;
|
||||
|
||||
void dm_log_init(dm_log_fn fn)
|
||||
{
|
||||
if (fn)
|
||||
_log = fn;
|
||||
dm_log = fn;
|
||||
else
|
||||
_log = _default_log;
|
||||
dm_log = _default_log;
|
||||
}
|
||||
|
||||
void dm_log_init_verbose(int level)
|
||||
@@ -96,7 +96,8 @@ struct dm_task *dm_task_create(int type)
|
||||
struct dm_task *dmt = dm_malloc(sizeof(*dmt));
|
||||
|
||||
if (!dmt) {
|
||||
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
|
||||
log_error("dm_task_create: malloc(%" PRIsize_t ") failed",
|
||||
sizeof(*dmt));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -180,6 +181,27 @@ int dm_task_set_minor(struct dm_task *dmt, int minor)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_uid(struct dm_task *dmt, uid_t uid)
|
||||
{
|
||||
dmt->uid = uid;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_gid(struct dm_task *dmt, gid_t gid)
|
||||
{
|
||||
dmt->gid = gid;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_mode(struct dm_task *dmt, mode_t mode)
|
||||
{
|
||||
dmt->mode = mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
|
||||
const char *ttype, const char *params)
|
||||
{
|
||||
@@ -488,3 +510,4 @@ out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -82,6 +85,8 @@ struct load_segment {
|
||||
uint32_t region_size; /* Mirror */
|
||||
unsigned clustered; /* Mirror */
|
||||
unsigned mirror_area_count; /* Mirror */
|
||||
uint32_t flags; /* Mirror log */
|
||||
char *uuid; /* Clustered mirror log */
|
||||
};
|
||||
|
||||
/* Per-device properties */
|
||||
@@ -112,6 +117,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 */
|
||||
@@ -122,6 +129,7 @@ struct dm_tree {
|
||||
struct dm_hash_table *devs;
|
||||
struct dm_hash_table *uuids;
|
||||
struct dm_tree_node root;
|
||||
int skip_lockfs; /* 1 skips lockfs (for non-snapshots) */
|
||||
};
|
||||
|
||||
/* FIXME Consider exporting this */
|
||||
@@ -134,7 +142,7 @@ static int _dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
|
||||
n = vsnprintf(buf, bufsize, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || (n > bufsize - 1))
|
||||
if (n < 0 || (n > (int) bufsize - 1))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
@@ -153,6 +161,7 @@ struct dm_tree *dm_tree_create(void)
|
||||
dtree->root.dtree = dtree;
|
||||
list_init(&dtree->root.uses);
|
||||
list_init(&dtree->root.used_by);
|
||||
dtree->skip_lockfs = 0;
|
||||
|
||||
if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
|
||||
log_error("dtree pool creation failed");
|
||||
@@ -310,6 +319,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 +358,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 +670,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;
|
||||
@@ -886,12 +903,13 @@ static int _resume_node(const char *name, uint32_t major, uint32_t minor,
|
||||
}
|
||||
|
||||
static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
|
||||
struct dm_info *newinfo)
|
||||
int skip_lockfs, struct dm_info *newinfo)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
int r;
|
||||
|
||||
log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
|
||||
log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s", name, major,
|
||||
minor, skip_lockfs ? "" : " with filesystem sync.");
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) {
|
||||
log_error("Suspend dm_task creation failed for %s", name);
|
||||
@@ -907,6 +925,9 @@ static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
|
||||
if (!dm_task_no_open_count(dmt))
|
||||
log_error("Failed to disable open_count");
|
||||
|
||||
if (skip_lockfs && !dm_task_skip_lockfs(dmt))
|
||||
log_error("Failed to set skip_lockfs flag.");
|
||||
|
||||
if ((r = dm_task_run(dmt)))
|
||||
r = dm_task_get_info(dmt, newinfo);
|
||||
|
||||
@@ -965,6 +986,11 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
|
||||
{
|
||||
dnode->dtree->skip_lockfs = 1;
|
||||
}
|
||||
|
||||
int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len)
|
||||
@@ -1005,7 +1031,8 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
!info.exists)
|
||||
continue;
|
||||
|
||||
if (!_suspend_node(name, info.major, info.minor, &newinfo)) {
|
||||
if (!_suspend_node(name, info.major, info.minor,
|
||||
child->dtree->skip_lockfs, &newinfo)) {
|
||||
log_error("Unable to suspend %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, info.major,
|
||||
info.minor);
|
||||
@@ -1026,7 +1053,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 +1072,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 +1086,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;
|
||||
@@ -1180,10 +1225,12 @@ static int _emit_areas_line(struct dm_task *dmt, struct load_segment *seg, char
|
||||
|
||||
static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uint64_t *seg_start, char *params, size_t paramsize)
|
||||
{
|
||||
unsigned log_parm_count;
|
||||
int pos = 0;
|
||||
int tw;
|
||||
int r;
|
||||
char originbuf[10], cowbuf[10], logbuf[10];
|
||||
const char *logtype;
|
||||
|
||||
switch(seg->type) {
|
||||
case SEG_ERROR:
|
||||
@@ -1192,33 +1239,84 @@ static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uin
|
||||
case SEG_LINEAR:
|
||||
break;
|
||||
case SEG_MIRRORED:
|
||||
log_parm_count = 1; /* Region size */
|
||||
log_parm_count += hweight32(seg->flags); /* [no]sync, block_on_error etc. */
|
||||
|
||||
if (seg->clustered) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "clustered ")) < 0) {
|
||||
if (seg->uuid)
|
||||
log_parm_count++; /* uuid */
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "clustered_")) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
}
|
||||
if (!seg->log) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "core 1 ")) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
} else {
|
||||
|
||||
if (!seg->log)
|
||||
logtype = "core";
|
||||
else {
|
||||
logtype = "disk";
|
||||
log_parm_count++;
|
||||
if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log))
|
||||
return_0;
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "disk 2 %s ", logbuf)) < 0) {
|
||||
}
|
||||
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s %u ", logtype, log_parm_count)) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
|
||||
if (seg->log) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s ", logbuf)) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
}
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u %u ", seg->region_size, seg->mirror_area_count)) < 0) {
|
||||
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u ", seg->region_size)) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
|
||||
if (seg->clustered && seg->uuid) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s ", seg->uuid)) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
}
|
||||
|
||||
if ((seg->flags & DM_NOSYNC)) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "nosync ")) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
} else if ((seg->flags & DM_FORCESYNC)) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "sync ")) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
}
|
||||
|
||||
if ((seg->flags & DM_BLOCK_ON_ERROR)) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "block_on_error ")) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
}
|
||||
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u ", seg->mirror_area_count)) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
|
||||
break;
|
||||
case SEG_SNAPSHOT:
|
||||
if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
|
||||
@@ -1343,8 +1441,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 +1457,6 @@ out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
@@ -1371,8 +1475,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 +1506,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 +1542,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 +1599,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;
|
||||
}
|
||||
|
||||
@@ -1577,7 +1687,8 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
|
||||
uint32_t region_size,
|
||||
unsigned clustered,
|
||||
const char *log_uuid,
|
||||
unsigned area_count)
|
||||
unsigned area_count,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct dm_tree_node *log_node = NULL;
|
||||
struct load_segment *seg;
|
||||
@@ -1594,14 +1705,21 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
|
||||
log_error("Couldn't find mirror log uuid %s.", log_uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_link_tree_nodes(node, log_node))
|
||||
return_0;
|
||||
|
||||
if (!(seg->uuid = dm_pool_strdup(node->dtree->mem, log_uuid))) {
|
||||
log_error("log uuid pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
seg->log = log_node;
|
||||
seg->region_size = region_size;
|
||||
seg->clustered = clustered;
|
||||
seg->mirror_area_count = area_count;
|
||||
seg->flags = flags;
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -20,10 +20,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef linux
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static int _create_dir_recursive(const char *dir)
|
||||
{
|
||||
char *orig, *s;
|
||||
@@ -31,7 +27,7 @@ static int _create_dir_recursive(const char *dir)
|
||||
|
||||
log_verbose("Creating directory \"%s\"", dir);
|
||||
/* Create parent directories */
|
||||
orig = s = strdup(dir);
|
||||
orig = s = dm_strdup(dir);
|
||||
while ((s = strchr(s, '/')) != NULL) {
|
||||
*s = '\0';
|
||||
if (*orig) {
|
||||
@@ -39,13 +35,13 @@ static int _create_dir_recursive(const char *dir)
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
log_error("%s: mkdir failed: %s", orig,
|
||||
strerror(errno));
|
||||
free(orig);
|
||||
dm_free(orig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*s++ = '/';
|
||||
}
|
||||
free(orig);
|
||||
dm_free(orig);
|
||||
|
||||
/* Create final directory */
|
||||
rc = mkdir(dir, 0777);
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
char *dm_strdup(const char *str)
|
||||
char *dm_strdup_aux(const char *str, const char *file, int line)
|
||||
{
|
||||
char *ret = dm_malloc(strlen(str) + 1);
|
||||
char *ret = dm_malloc_aux_debug(strlen(str) + 1, file, line);
|
||||
|
||||
if (ret)
|
||||
strcpy(ret, str);
|
||||
@@ -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;
|
||||
@@ -204,9 +198,9 @@ int dm_dump_memory(void)
|
||||
}
|
||||
str[sizeof(str) - 1] = '\0';
|
||||
|
||||
_log(_LOG_INFO, mb->file, mb->line,
|
||||
"block %d at %p, size %" PRIsize_t "\t [%s]",
|
||||
mb->id, mb->magic, mb->length, str);
|
||||
dm_log(_LOG_INFO, mb->file, mb->line,
|
||||
"block %d at %p, size %" PRIsize_t "\t [%s]",
|
||||
mb->id, mb->magic, mb->length, str);
|
||||
tot += mb->length;
|
||||
}
|
||||
|
||||
@@ -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 @@ void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
|
||||
/* have we got room ? */
|
||||
if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
|
||||
/* allocate new chunk */
|
||||
int needed = s + alignment + sizeof(struct chunk);
|
||||
size_t needed = s + alignment + sizeof(struct chunk);
|
||||
c = _new_chunk(p, (needed > p->chunk_size) ?
|
||||
needed : p->chunk_size);
|
||||
|
||||
|
||||
22
make.tmpl.in
22
make.tmpl.in
@@ -27,11 +27,9 @@ LIBS = @LIBS@
|
||||
CFLAGS += @DEFS@
|
||||
CFLAGS += @CFLAGS@
|
||||
CLDFLAGS += @CLDFLAGS@
|
||||
CLDWHOLEARCHIVE += @CLDWHOLEARCHIVE@
|
||||
CLDNOWHOLEARCHIVE += @CLDNOWHOLEARCHIVE@
|
||||
LDDEPS += @LDDEPS@
|
||||
LDFLAGS += @LDFLAGS@
|
||||
SOFLAG += @SOFLAG@
|
||||
LIB_SUFFIX = @LIB_SUFFIX@
|
||||
|
||||
# Setup directory variables
|
||||
prefix = @prefix@
|
||||
@@ -56,7 +54,7 @@ ifndef MAKEFLAGS
|
||||
MAKEFLAGS = @JOBS@
|
||||
endif
|
||||
|
||||
SUFFIXES = .c .d .o .so .a .po .pot .mo
|
||||
SUFFIXES = .c .d .o .so .a .po .pot .mo .dylib
|
||||
|
||||
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline
|
||||
|
||||
@@ -151,9 +149,21 @@ $(TARGETS): $(OBJECTS)
|
||||
%.so: %.o
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","so")
|
||||
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
|
||||
$(CC) $(SOFLAG) -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) -o $@
|
||||
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
endif
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
|
||||
$(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
endif
|
||||
|
||||
%.so: %.a
|
||||
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(LIBS) -o $@ @CLDWHOLEARCHIVE@ $< @CLDNOWHOLEARCHIVE@
|
||||
|
||||
$(LIB_STATIC): $(OBJECTS)
|
||||
$(RM) $@
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH DMSETUP 8 "Sep 17 2003" "Linux" "MAINTENTANCE COMMANDS"
|
||||
.TH DMSETUP 8 "Apr 06 2006" "Linux" "MAINTENTANCE COMMANDS"
|
||||
.SH NAME
|
||||
dmsetup \- low level logical volume management
|
||||
.SH SYNOPSIS
|
||||
@@ -12,7 +12,7 @@ dmsetup \- low level logical volume management
|
||||
.B dmsetup remove_all
|
||||
.br
|
||||
.B dmsetup suspend
|
||||
.I device_name
|
||||
.I [--nolockfs] device_name
|
||||
.br
|
||||
.B dmsetup resume
|
||||
.I device_name
|
||||
@@ -29,7 +29,7 @@ dmsetup \- low level logical volume management
|
||||
.B dmsetup rename
|
||||
.I device_name new_name
|
||||
.br
|
||||
.B dmsetup ls [--target target_type] [--exec command]
|
||||
.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
|
||||
.br
|
||||
.B dmsetup info
|
||||
.I [device_name]
|
||||
@@ -147,10 +147,17 @@ Outputs some brief information about the device in the form:
|
||||
.IP \fBls
|
||||
.I [--target target_type]
|
||||
.I [--exec command]
|
||||
.I [--tree [-o options]]
|
||||
.br
|
||||
List device names. Optionally only list devices that have at least
|
||||
one target of the specified type. Optionally execute a command for
|
||||
each device. The device name is appended to the supplied command.
|
||||
--tree displays dependencies between devices as a tree.
|
||||
It accepts a comma-separate list of options.
|
||||
Some specify the information displayed against each node:
|
||||
device/nodevice; active, open, rw, uuid.
|
||||
Others specify how the tree is displayed:
|
||||
ascii, utf, vt100; compact, inverted, notrunc.
|
||||
.IP \fBload|reload
|
||||
.I device_name [table_file]
|
||||
.br
|
||||
@@ -183,11 +190,14 @@ Outputs status information for each of the device's targets.
|
||||
With --target, only information relating to the specified target type
|
||||
is displayed.
|
||||
.IP \fBsuspend
|
||||
.I [--nolockfs]
|
||||
.I device_name
|
||||
.br
|
||||
Suspends a device. Any I/O that has already been mapped by the device
|
||||
but has not yet completed will be flushed. Any further I/O to that
|
||||
device will be postponed for as long as the device is suspended.
|
||||
If there's a filesystem on the device which supports the operation,
|
||||
an attempt will be made to sync it first unless --nolockfs is specified.
|
||||
.IP \fBtable
|
||||
.I [--target target_type]
|
||||
.I [device_name]
|
||||
|
||||
@@ -43,8 +43,8 @@ The values are:
|
||||
Display the mapping of logical extents to physical volumes and
|
||||
physical extents.
|
||||
.SH Examples
|
||||
"lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume
|
||||
and its mapping of logical to physical extents. In case snapshot
|
||||
"lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume.
|
||||
If snapshot
|
||||
logical volumes have been created for this original logical volume,
|
||||
this command shows a list of all snapshot logical volumes and their
|
||||
status (active or inactive) as well.
|
||||
|
||||
@@ -17,6 +17,8 @@ vgchange \- change attributes of a volume group
|
||||
.RB [ \-l | \-\-logicalvolume
|
||||
.IR MaxLogicalVolumes ]
|
||||
.RB [ \-P | \-\-partial]
|
||||
.RB [ \-s | \-\-physicalextentsize
|
||||
.IR PhysicalExtentSize [ \fBkKmMgGtT\fR ]]
|
||||
.RB [ -t | \-\-test]
|
||||
.RB [ \-v | \-\-verbose]
|
||||
.RB [ \-\-version ]
|
||||
@@ -59,6 +61,27 @@ exclusively because they can only be used on one node at once.
|
||||
Changes the maximum logical volume number of an existing inactive
|
||||
volume group.
|
||||
.TP
|
||||
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
|
||||
Changes the physical extent size on physical volumes of this volume group.
|
||||
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
|
||||
is the default if no suffix is present.
|
||||
The default is 4 MB and it must be at least 1 KB and a power of 2.
|
||||
|
||||
Before increasing the physical extent size, you might need to use lvresize,
|
||||
pvresize and/or pvmove so that everything fits. For example, every
|
||||
contiguous range of extents used in a logical volume must start and
|
||||
end on an extent boundary.
|
||||
|
||||
If the volume group metadata uses lvm1 format, extents can vary in size from
|
||||
8KB to 16GB and there is a limit of 65534 extents in each logical volume. The
|
||||
default of 4 MB leads to a maximum logical volume size of around 256GB.
|
||||
|
||||
If the volume group metadata uses lvm2 format those restrictions do not apply,
|
||||
but having a large number of extents will slow down the tools but have no
|
||||
impact on I/O performance to the logical volume. The smallest PE is 1KB.
|
||||
|
||||
The 2.4 kernel has a limitation of 2TB per block device.
|
||||
.TP
|
||||
.BR \-x ", " \-\-resizeable { y | n }
|
||||
Enables or disables the extension/reduction of this volume group
|
||||
with/by physical volumes.
|
||||
|
||||
@@ -59,17 +59,22 @@ as described in \fBpvcreate(8)\fP.
|
||||
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
|
||||
Sets the physical extent size on physical volumes of this volume group.
|
||||
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
|
||||
is the default if no suffix is present. Values can be from 8 KB to 16 GB in
|
||||
powers of 2. The default is 4 MB.
|
||||
is the default if no suffix is present.
|
||||
The default is 4 MB and it must be at least 1 KB and a power of 2.
|
||||
|
||||
Once this value has been set, it is difficult to change it without recreating
|
||||
the volume group which would involve backing up and restoring data on any
|
||||
logical volumes.
|
||||
If the volume group metadata uses lvm1 format, there is a limit of 65534
|
||||
extents in each logical volume, so the default of 4 MB leads to a maximum
|
||||
logical volume size of around 256GB.
|
||||
If the volume group metadata uses lvm2 format there is no such restriction,
|
||||
although having a large number of extents will slow down
|
||||
the tools but have no impact on I/O performance to the logical volume.
|
||||
logical volumes. However, if no extents need moving for the new
|
||||
value to apply, it can be altered using vgchange \-s.
|
||||
|
||||
If the volume group metadata uses lvm1 format, extents can vary in size from
|
||||
8KB to 16GB and there is a limit of 65534 extents in each logical volume. The
|
||||
default of 4 MB leads to a maximum logical volume size of around 256GB.
|
||||
|
||||
If the volume group metadata uses lvm2 format those restrictions do not apply,
|
||||
but having a large number of extents will slow down the tools but have no
|
||||
impact on I/O performance to the logical volume. The smallest PE is 1KB.
|
||||
|
||||
The 2.4 kernel has a limitation of 2TB per block device.
|
||||
.SH EXAMPLES
|
||||
To create a volume group named
|
||||
|
||||
@@ -87,6 +87,10 @@ ifeq ("@CMDLIB@", "yes")
|
||||
INSTALL_TARGETS += $(INSTALL_CMDLIB_TARGETS)
|
||||
endif
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
LVMLIBS += -ldevmapper-event -lpthread
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
LVMLIBS += -ldevmapper
|
||||
endif
|
||||
@@ -107,8 +111,6 @@ liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS)
|
||||
$(AR) rs $@ $(OBJECTS)
|
||||
|
||||
liblvm2cmd.so: liblvm2cmd.a $(LDDEPS)
|
||||
$(CC) -o liblvm2cmd.so $(SOFLAG) $(CLDFLAGS) \
|
||||
$(CLDWHOLEARCHIVE) liblvm2cmd.a $(CLDNOWHOLEARCHIVE)
|
||||
|
||||
.commands: commands.h cmdnames.h Makefile
|
||||
$(CC) -E -P cmdnames.h 2> /dev/null | \
|
||||
|
||||
@@ -44,6 +44,7 @@ arg(minor_ARG, '\0', "minor", minor_arg)
|
||||
arg(type_ARG, '\0', "type", segtype_arg)
|
||||
arg(alloc_ARG, '\0', "alloc", alloc_arg)
|
||||
arg(separator_ARG, '\0', "separator", string_arg)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
|
||||
@@ -85,7 +86,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)
|
||||
|
||||
@@ -80,16 +80,26 @@ xx(lvchange,
|
||||
|
||||
xx(lvconvert,
|
||||
"Change logical volume layout",
|
||||
"lvconvert " "\n"
|
||||
"lvconvert "
|
||||
"[-m|--mirrors Mirrors]\n"
|
||||
"\t[--alloc AllocationPolicy]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
"\t[-m|--mirrors Mirrors]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n",
|
||||
"\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n\n"
|
||||
|
||||
alloc_ARG, mirrors_ARG, test_ARG)
|
||||
"lvconvert "
|
||||
"[-s|--snapshot]\n"
|
||||
"\t[-c|--chunksize]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[-Z|--zero {y|n}]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
|
||||
|
||||
alloc_ARG, chunksize_ARG, mirrors_ARG, snapshot_ARG, test_ARG, zero_ARG)
|
||||
|
||||
xx(lvcreate,
|
||||
"Create a logical volume",
|
||||
@@ -526,6 +536,7 @@ xx(pvs,
|
||||
"\t[--nosuffix]\n"
|
||||
"\t[-o|--options [+]Field[,Field]]\n"
|
||||
"\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
|
||||
"\t[-P|--partial] " "\n"
|
||||
"\t[--segments]\n"
|
||||
"\t[--separator Separator]\n"
|
||||
"\t[--unbuffered]\n"
|
||||
@@ -535,8 +546,8 @@ xx(pvs,
|
||||
"\t[PhysicalVolume [PhysicalVolume...]]\n",
|
||||
|
||||
aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
|
||||
nolocking_ARG, nosuffix_ARG, options_ARG, segments_ARG, separator_ARG,
|
||||
sort_ARG, unbuffered_ARG, units_ARG)
|
||||
nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, segments_ARG,
|
||||
separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
|
||||
|
||||
xx(pvscan,
|
||||
"List all physical volumes",
|
||||
@@ -769,6 +780,7 @@ xx(vgreduce,
|
||||
"\t[-A|--autobackup y|n]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--mirrorsonly]\n"
|
||||
"\t[--removemissing]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
@@ -776,7 +788,7 @@ xx(vgreduce,
|
||||
"\tVolumeGroupName\n"
|
||||
"\t[PhysicalVolumePath...]\n",
|
||||
|
||||
all_ARG, autobackup_ARG, removemissing_ARG, test_ARG)
|
||||
all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG)
|
||||
|
||||
xx(vgremove,
|
||||
"Remove volume group(s)",
|
||||
|
||||
@@ -86,8 +86,10 @@ enum {
|
||||
READ_ONLY = 0,
|
||||
COLS_ARG,
|
||||
EXEC_ARG,
|
||||
GID_ARG,
|
||||
MAJOR_ARG,
|
||||
MINOR_ARG,
|
||||
MODE_ARG,
|
||||
NOHEADINGS_ARG,
|
||||
NOLOCKFS_ARG,
|
||||
NOOPENCOUNT_ARG,
|
||||
@@ -95,6 +97,7 @@ enum {
|
||||
OPTIONS_ARG,
|
||||
TARGET_ARG,
|
||||
TREE_ARG,
|
||||
UID_ARG,
|
||||
UUID_ARG,
|
||||
VERBOSE_ARG,
|
||||
VERSION_ARG,
|
||||
@@ -390,6 +393,15 @@ static int _create(int argc, char **argv, void *data)
|
||||
if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _values[MINOR_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _values[UID_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _values[GID_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _values[MODE_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
|
||||
goto out;
|
||||
|
||||
@@ -438,7 +450,8 @@ static int _rename(int argc, char **argv, void *data)
|
||||
|
||||
static int _message(int argc, char **argv, void *data)
|
||||
{
|
||||
int r = 0, sz = 1, i;
|
||||
int r = 0, i;
|
||||
size_t sz = 1;
|
||||
struct dm_task *dmt;
|
||||
char *str;
|
||||
|
||||
@@ -455,7 +468,7 @@ static int _message(int argc, char **argv, void *data)
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!dm_task_set_sector(dmt, atoll(argv[1])))
|
||||
if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
|
||||
goto out;
|
||||
|
||||
argc -= 2;
|
||||
@@ -495,6 +508,39 @@ static int _message(int argc, char **argv, void *data)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _setgeometry(int argc, char **argv, void *data)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
|
||||
return 0;
|
||||
|
||||
if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
|
||||
if (!_set_task_device(dmt, NULL, 0))
|
||||
goto out;
|
||||
} else {
|
||||
if (!_set_task_device(dmt, argv[1], 0))
|
||||
goto out;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
|
||||
goto out;
|
||||
|
||||
/* run the task */
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _version(int argc, char **argv, void *data)
|
||||
{
|
||||
char version[80];
|
||||
@@ -502,7 +548,7 @@ static int _version(int argc, char **argv, void *data)
|
||||
if (dm_get_library_version(version, sizeof(version)))
|
||||
printf("Library version: %s\n", version);
|
||||
|
||||
if (dm_driver_version(version, sizeof(version)))
|
||||
if (!dm_driver_version(version, sizeof(version)))
|
||||
return 0;
|
||||
|
||||
printf("Driver version: %s\n", version);
|
||||
@@ -580,7 +626,7 @@ static int _wait(int argc, char **argv, void *data)
|
||||
}
|
||||
|
||||
return _simple(DM_DEVICE_WAITEVENT, name,
|
||||
(argc > 1) ? atoi(argv[argc - 1]) : 0, 1);
|
||||
(argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
|
||||
}
|
||||
|
||||
static int _process_all(int argc, char **argv,
|
||||
@@ -622,7 +668,7 @@ static int _process_all(int argc, char **argv,
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _display_dev(struct dm_task *dmt, char *name)
|
||||
static void _display_dev(struct dm_task *dmt, const char *name)
|
||||
{
|
||||
struct dm_info info;
|
||||
|
||||
@@ -635,7 +681,7 @@ static int _mknodes(int argc, char **argv, void *data)
|
||||
return dm_mknodes(argc > 1 ? argv[1] : NULL);
|
||||
}
|
||||
|
||||
static int _exec_command(char *name)
|
||||
static int _exec_command(const char *name)
|
||||
{
|
||||
int n;
|
||||
static char path[PATH_MAX];
|
||||
@@ -651,7 +697,7 @@ static int _exec_command(char *name)
|
||||
return 0;
|
||||
|
||||
n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
|
||||
if (n < 0 || n > sizeof(path) - 1)
|
||||
if (n < 0 || n > (int) sizeof(path) - 1)
|
||||
return 0;
|
||||
|
||||
if (!argc) {
|
||||
@@ -704,7 +750,7 @@ static int _status(int argc, char **argv, void *data)
|
||||
char *params;
|
||||
int cmd;
|
||||
struct dm_names *names = (struct dm_names *) data;
|
||||
char *name = NULL;
|
||||
const char *name = NULL;
|
||||
int matched = 0;
|
||||
int ls_only = 0;
|
||||
struct dm_info info;
|
||||
@@ -742,7 +788,7 @@ static int _status(int argc, char **argv, void *data)
|
||||
goto out;
|
||||
|
||||
if (!name)
|
||||
name = (char *) dm_task_get_name(dmt);
|
||||
name = dm_task_get_name(dmt);
|
||||
|
||||
/* Fetch targets and print 'em */
|
||||
do {
|
||||
@@ -1292,6 +1338,7 @@ struct command {
|
||||
|
||||
static struct command _commands[] = {
|
||||
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
|
||||
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
|
||||
"\t [-u|uuid <uuid>] [--notable] [<table_file>]",
|
||||
1, 2, _create},
|
||||
{"remove", "<device>", 0, 1, _remove},
|
||||
@@ -1303,7 +1350,7 @@ static struct command _commands[] = {
|
||||
{"reload", "<device> [<table_file>]", 0, 2, _load},
|
||||
{"rename", "<device> <new_name>", 1, 2, _rename},
|
||||
{"message", "<device> <sector> <message>", 2, -1, _message},
|
||||
{"ls", "[--target <target_type>] [--exec <command>] [--tree]", 0, 0, _ls},
|
||||
{"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
|
||||
{"info", "[<device>]", 0, 1, _info},
|
||||
{"deps", "[<device>]", 0, 1, _deps},
|
||||
{"status", "[<device>] [--target <target_type>]", 0, 1, _status},
|
||||
@@ -1312,6 +1359,7 @@ static struct command _commands[] = {
|
||||
{"mknodes", "[<device>]", 0, 1, _mknodes},
|
||||
{"targets", "", 0, 0, _targets},
|
||||
{"version", "", 0, 0, _version},
|
||||
{"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
|
||||
{NULL, NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
@@ -1326,7 +1374,9 @@ static void _usage(FILE *out)
|
||||
fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
|
||||
fprintf(out, "\n<device> may be device name or -u <uuid> or "
|
||||
"-j <major> -m <minor>\n");
|
||||
fprintf(out, "Table_file contents may be supplied on stdin.\n\n");
|
||||
fprintf(out, "Table_file contents may be supplied on stdin.\n");
|
||||
fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
|
||||
" [no]device, active, open, rw and uuid.\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1418,8 +1468,10 @@ static int _process_switches(int *argc, char ***argv)
|
||||
{"readonly", 0, &ind, READ_ONLY},
|
||||
{"columns", 0, &ind, COLS_ARG},
|
||||
{"exec", 1, &ind, EXEC_ARG},
|
||||
{"gid", 1, &ind, GID_ARG},
|
||||
{"major", 1, &ind, MAJOR_ARG},
|
||||
{"minor", 1, &ind, MINOR_ARG},
|
||||
{"mode", 1, &ind, MODE_ARG},
|
||||
{"noheadings", 0, &ind, NOHEADINGS_ARG},
|
||||
{"nolockfs", 0, &ind, NOLOCKFS_ARG},
|
||||
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
|
||||
@@ -1427,6 +1479,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
{"options", 1, &ind, OPTIONS_ARG},
|
||||
{"target", 1, &ind, TARGET_ARG},
|
||||
{"tree", 0, &ind, TREE_ARG},
|
||||
{"uid", 1, &ind, UID_ARG},
|
||||
{"uuid", 1, &ind, UUID_ARG},
|
||||
{"verbose", 1, &ind, VERBOSE_ARG},
|
||||
{"version", 0, &ind, VERSION_ARG},
|
||||
@@ -1478,7 +1531,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
|
||||
optarg = 0;
|
||||
optind = OPTIND_INIT;
|
||||
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCj:m:no:ru:v",
|
||||
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCGj:m:Mno:ru:Uv",
|
||||
long_options, NULL)) != -1) {
|
||||
if (c == 'c' || c == 'C' || ind == COLS_ARG)
|
||||
_switches[COLS_ARG]++;
|
||||
@@ -1504,6 +1557,19 @@ static int _process_switches(int *argc, char ***argv)
|
||||
_switches[UUID_ARG]++;
|
||||
_uuid = optarg;
|
||||
}
|
||||
if (c == 'G' || ind == GID_ARG) {
|
||||
_switches[GID_ARG]++;
|
||||
_values[GID_ARG] = atoi(optarg);
|
||||
}
|
||||
if (c == 'U' || ind == UID_ARG) {
|
||||
_switches[UID_ARG]++;
|
||||
_values[UID_ARG] = atoi(optarg);
|
||||
}
|
||||
if (c == 'M' || ind == MODE_ARG) {
|
||||
_switches[MODE_ARG]++;
|
||||
/* FIXME Accept modes as per chmod */
|
||||
_values[MODE_ARG] = (int) strtol(optarg, NULL, 8);
|
||||
}
|
||||
if ((ind == EXEC_ARG)) {
|
||||
_switches[EXEC_ARG]++;
|
||||
_command = optarg;
|
||||
|
||||
@@ -13,10 +13,23 @@
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
struct lvconvert_params {
|
||||
int snapshot;
|
||||
int zero;
|
||||
|
||||
const char *origin;
|
||||
const char *lv_name;
|
||||
const char *vg_name;
|
||||
|
||||
uint32_t chunk_size;
|
||||
uint32_t region_size;
|
||||
|
||||
uint32_t mirrors;
|
||||
sign_t mirrors_sign;
|
||||
|
||||
struct segment_type *segtype;
|
||||
|
||||
alloc_policy_t alloc;
|
||||
|
||||
@@ -25,30 +38,164 @@ struct lvconvert_params {
|
||||
struct list *pvh;
|
||||
};
|
||||
|
||||
static int _read_name_params(struct lvconvert_params *lp,
|
||||
struct cmd_context *cmd, int *pargc, char ***pargv)
|
||||
{
|
||||
char *ptr;
|
||||
const char *vg_name = NULL;
|
||||
|
||||
if (lp->snapshot) {
|
||||
if (!*pargc) {
|
||||
log_error("Please specify a logical volume to act as "
|
||||
"the snapshot origin.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->origin = *pargv[0];
|
||||
(*pargv)++, (*pargc)--;
|
||||
if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
|
||||
log_error("The origin name should include the "
|
||||
"volume group.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Strip the volume group from the origin */
|
||||
if ((ptr = strrchr(lp->origin, (int) '/')))
|
||||
lp->origin = ptr + 1;
|
||||
}
|
||||
|
||||
if (!*pargc) {
|
||||
log_error("Please provide logical volume path");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->lv_name = (*pargv)[0];
|
||||
(*pargv)++, (*pargc)--;
|
||||
|
||||
if (strchr(lp->lv_name, '/') &&
|
||||
(vg_name = extract_vgname(cmd, lp->lv_name)) &&
|
||||
lp->vg_name && strcmp(vg_name, lp->vg_name)) {
|
||||
log_error("Please use a single volume group name "
|
||||
"(\"%s\" or \"%s\")", vg_name, lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->vg_name)
|
||||
lp->vg_name = vg_name;
|
||||
|
||||
if (!validate_name(lp->vg_name)) {
|
||||
log_error("Please provide a valid volume group name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ptr = strrchr(lp->lv_name, '/')))
|
||||
lp->lv_name = ptr + 1;
|
||||
|
||||
if (!apply_lvname_restrictions(lp->lv_name))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
|
||||
int argc, char **argv)
|
||||
{
|
||||
memset(lp, 0, sizeof(*lp));
|
||||
|
||||
if (arg_count(cmd, mirrors_ARG) + arg_count(cmd, snapshot_ARG) != 1) {
|
||||
log_error("Exactly one of --mirrors or --snapshot arguments "
|
||||
"required.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, snapshot_ARG))
|
||||
lp->snapshot = 1;
|
||||
|
||||
if (arg_count(cmd, mirrors_ARG)) {
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
|
||||
lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
|
||||
}
|
||||
|
||||
lp->alloc = ALLOC_INHERIT;
|
||||
if (arg_count(cmd, alloc_ARG))
|
||||
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG,
|
||||
lp->alloc);
|
||||
|
||||
if (!arg_count(cmd, mirrors_ARG)) {
|
||||
log_error("--mirrors argument required");
|
||||
if (lp->snapshot) {
|
||||
if (arg_count(cmd, regionsize_ARG)) {
|
||||
log_error("--regionsize is only available with mirrors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
|
||||
log_error("Negative chunk size is invalid");
|
||||
return 0;
|
||||
}
|
||||
lp->chunk_size = 2 * arg_uint_value(cmd, chunksize_ARG, 8);
|
||||
if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
|
||||
(lp->chunk_size & (lp->chunk_size - 1))) {
|
||||
log_error("Chunk size must be a power of 2 in the "
|
||||
"range 4K to 512K");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
|
||||
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
|
||||
return_0;
|
||||
|
||||
lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
|
||||
(lp->segtype->flags &
|
||||
SEG_CANNOT_BE_ZEROED) ?
|
||||
"n" : "y"), "n");
|
||||
|
||||
} else { /* Mirrors */
|
||||
if (arg_count(cmd, chunksize_ARG)) {
|
||||
log_error("--chunksize is only available with "
|
||||
"snapshots");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, zero_ARG)) {
|
||||
log_error("--zero is only available with snapshots");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* --regionsize is only valid if converting an LV into a mirror.
|
||||
* 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 (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (activation() && lp->segtype->ops->target_present &&
|
||||
!lp->segtype->ops->target_present()) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel", lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give logical volume path");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->lv_name = argv[0];
|
||||
argv++, argc--;
|
||||
if (!_read_name_params(lp, cmd, &argc, &argv))
|
||||
return_0;
|
||||
|
||||
lp->pv_count = argc;
|
||||
lp->pvs = argv;
|
||||
@@ -61,8 +208,32 @@ 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;
|
||||
|
||||
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,11 +241,10 @@ 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)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!remove_mirror_images(seg, 1,
|
||||
lp->pv_count ? lp->pvh : NULL, 1))
|
||||
return_0;
|
||||
} else { /* mirrors > 1 */
|
||||
if ((lv->status & MIRRORED)) {
|
||||
if (list_size(&lv->segments) != 1) {
|
||||
@@ -82,8 +252,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,27 +268,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)) {
|
||||
stack;
|
||||
/* Reduce number of mirrors */
|
||||
if (!remove_mirror_images(seg, lp->mirrors,
|
||||
lp->pv_count ?
|
||||
lp->pvh : NULL, 0))
|
||||
return_0;
|
||||
}
|
||||
} else {
|
||||
/* Make existing LV into mirror set */
|
||||
/* FIXME Share code with lvcreate */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* 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;
|
||||
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
|
||||
return_0;
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype,
|
||||
1, lp->mirrors - 1, 1,
|
||||
lv->le_count * (lp->mirrors - 1),
|
||||
NULL, 0, 0, lp->pvh,
|
||||
lp->alloc,
|
||||
parallel_areas)))
|
||||
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,
|
||||
lp->segtype, 0,
|
||||
lp->region_size,
|
||||
log_lv))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!vg_write(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!vg_write(lv->vg))
|
||||
return_0;
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
@@ -147,6 +346,68 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvconvert_snapshot(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
struct logical_volume *org;
|
||||
|
||||
if (!(org = find_lv(lv->vg, lp->origin))) {
|
||||
log_error("Couldn't find origin volume '%s'.", lp->origin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (org->status & (LOCKED|PVMOVE) || lv_is_cow(org)) {
|
||||
log_error("Unable to create a snapshot of a %s LV.",
|
||||
org->status & LOCKED ? "locked" :
|
||||
org->status & PVMOVE ? "pvmove" : "snapshot");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->zero)
|
||||
log_error("WARNING: \"%s\" not zeroed", lv->name);
|
||||
else if (!zero_lv(cmd, lv)) {
|
||||
log_error("Aborting. Failed to wipe snapshot "
|
||||
"exception store.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Couldn't deactivate LV %s.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_add_snapshot(lv->vg->fid, NULL, org, lv, NULL, org->le_count,
|
||||
lp->chunk_size)) {
|
||||
log_error("Couldn't create snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!vg_write(lv->vg))
|
||||
return_0;
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!suspend_lv(cmd, org)) {
|
||||
log_error("Failed to suspend origin %s", org->name);
|
||||
vg_revert(lv->vg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_commit(lv->vg))
|
||||
return_0;
|
||||
|
||||
if (!resume_lv(cmd, org)) {
|
||||
log_error("Problem reactivating origin %s", org->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("Logical volume %s converted to snapshot.", lv->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
@@ -179,6 +440,11 @@ static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return ECMD_FAILED;
|
||||
if (!lvconvert_mirrors(cmd, lv, lp))
|
||||
return ECMD_FAILED;
|
||||
} else if (lp->snapshot) {
|
||||
if (!archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
if (!lvconvert_snapshot(cmd, lv, lp))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
@@ -186,8 +452,6 @@ static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
{
|
||||
const char *vg_name;
|
||||
char *st;
|
||||
int consistent = 1;
|
||||
struct volume_group *vg;
|
||||
struct lv_list *lvl;
|
||||
@@ -199,41 +463,31 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
vg_name = extract_vgname(cmd, lp.lv_name);
|
||||
log_verbose("Checking for existing volume group \"%s\"", lp.vg_name);
|
||||
|
||||
if (!validate_name(vg_name)) {
|
||||
log_error("Please provide a valid volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if ((st = strrchr(lp.lv_name, '/')))
|
||||
lp.lv_name = st + 1;
|
||||
|
||||
log_verbose("Checking for existing volume group \"%s\"", vg_name);
|
||||
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", lp.vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name, &consistent))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
if (!(vg = vg_read(cmd, lp.vg_name, NULL, &consistent))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", lp.vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg_name);
|
||||
log_error("Volume group \"%s\" is exported", lp.vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
log_error("Volume group \"%s\" is read-only", lp.vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(lvl = find_lv_in_vg(vg, lp.lv_name))) {
|
||||
log_error("Logical volume \"%s\" not found in "
|
||||
"volume group \"%s\"", lp.lv_name, vg_name);
|
||||
"volume group \"%s\"", lp.lv_name, lp.vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -249,6 +503,6 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
ret = lvconvert_single(cmd, lvl->lv, &lp);
|
||||
|
||||
error:
|
||||
unlock_vg(cmd, vg_name);
|
||||
unlock_vg(cmd, lp.vg_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -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,16 +436,15 @@ 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;
|
||||
|
||||
/* does VG exist? */
|
||||
log_verbose("Finding volume group \"%s\"", lp->vg_name);
|
||||
|
||||
if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
|
||||
if (!(vg = vg_read(cmd, lp->vg_name, NULL, &consistent))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
@@ -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,7 @@
|
||||
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_is_visible(lv))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (arg_count(cmd, colon_ARG))
|
||||
|
||||
@@ -83,7 +83,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
origin = find_cow(lv)->origin;
|
||||
origin = origin_from_cow(lv);
|
||||
log_verbose("Removing snapshot %s", lv->name);
|
||||
if (!vg_remove_snapshot(lv)) {
|
||||
stack;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user