master - clvmd: Fix freeze if client dies holding locks.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=be662439331abf...
Commit: be662439331abf6ccb16dd996bfe15eb613b4e53
Parent: 57534733b7750f17f5ffa115306dcb650d8015b9
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Thu Jul 23 23:10:16 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Thu Jul 23 23:10:16 2015 +0100
clvmd: Fix freeze if client dies holding locks.
Simply running concurrent copies of 'pvscan | true' is enough to make
clvmd freeze: pvscan exits on the EPIPE without first releasing the
global lock.
clvmd notices the client disappear but because the cleanup code that
releases the locks is triggered from within some processing after the
next select() returns, and that processing can 'break' after doing just
one action, it sometimes never releases the locks to other clients.
Move the cleanup code before the select.
Check all fds after select().
Improve some debug messages and warn in the unlikely event that
select() capacity could soon be exceeded.
---
WHATS_NEW | 1 +
daemons/clvmd/clvmd-command.c | 4 +-
daemons/clvmd/clvmd.c | 67 +++++++++++++++++++++++++++--------------
3 files changed, 47 insertions(+), 25 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index adf8eb7..03e76c7 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.126 -
================================
+ Fix clvmd freeze if client disappears without first releasing its locks.
Fix lvconvert segfaults while performing snapshots merge.
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
diff --git a/daemons/clvmd/clvmd-command.c b/daemons/clvmd/clvmd-command.c
index 9e59e51..ff068b0 100644
--- a/daemons/clvmd/clvmd-command.c
+++ b/daemons/clvmd/clvmd-command.c
@@ -323,6 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
int lkid;
char *lockname;
+ DEBUGLOG("Client thread cleanup (%p)\n", client);
if (!client->bits.localsock.private)
return;
@@ -331,7 +332,7 @@ void cmd_client_cleanup(struct local_client *client)
dm_hash_iterate(v, lock_hash) {
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
lockname = dm_hash_get_key(lock_hash, v);
- DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
+ DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
(void) sync_unlock(lockname, lkid);
}
@@ -339,7 +340,6 @@ void cmd_client_cleanup(struct local_client *client)
client->bits.localsock.private = NULL;
}
-
static int restart_clvmd(void)
{
const char **argv;
diff --git a/daemons/clvmd/clvmd.c b/daemons/clvmd/clvmd.c
index 6bab3d6..99d01d0 100644
--- a/daemons/clvmd/clvmd.c
+++ b/daemons/clvmd/clvmd.c
@@ -223,6 +223,7 @@ void debuglog(const char *fmt, ...)
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
vfprintf(stderr, fmt, ap);
va_end(ap);
+ fflush(stderr);
break;
case DEBUG_SYSLOG:
if (!syslog_init) {
@@ -598,7 +599,9 @@ int main(int argc, char *argv[])
/* This needs to be started after cluster initialisation
as it may need to take out locks */
- DEBUGLOG("starting LVM thread\n");
+ DEBUGLOG("Starting LVM thread\n");
+ DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
+ local_client_head.fd, &local_client_head, newfd->fd, newfd);
/* Don't let anyone else to do work until we are started */
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
@@ -698,7 +701,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->type = LOCAL_SOCK;
newfd->callback = local_sock_callback;
newfd->bits.localsock.all_success = 1;
- DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
+ DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
*new_client = newfd;
}
return 1;
@@ -850,18 +853,48 @@ static void main_loop(int cmd_timeout)
struct local_client *thisfd;
struct timeval tv = { cmd_timeout, 0 };
int quorate = clops->is_quorate();
+ int client_count = 0;
+ int max_fd = 0;
/* Wait on the cluster FD and all local sockets/pipes */
local_client_head.fd = clops->get_main_cluster_fd();
FD_ZERO(&in);
+ struct local_client *lastfd = &local_client_head;
+ struct local_client *nextfd = local_client_head.next;
+
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
+ client_count++;
+ max_fd = max(max_fd, thisfd->fd);
+ }
+
+ if (max_fd > FD_SETSIZE - 32) {
+ fprintf(stderr, "WARNING: There are too many connections to clvmd. Investigate and take action now!\n");
+ fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
+ }
+
+ for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
+
+ if (thisfd->removeme && !cleanup_zombie(thisfd)) {
+ struct local_client *free_fd = thisfd;
+ lastfd->next = nextfd;
+ DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
+
+ /* Queue cleanup, this also frees the client struct */
+ add_to_lvmqueue(free_fd, NULL, 0, NULL);
+
+ continue;
+ }
+
+ lastfd = thisfd;
+
if (thisfd->removeme)
continue;
/* if the cluster is not quorate then don't listen for new requests */
if ((thisfd->type != LOCAL_RENDEZVOUS &&
thisfd->type != LOCAL_SOCK) || quorate)
- FD_SET(thisfd->fd, &in);
+ if (thisfd->fd < FD_SETSIZE)
+ FD_SET(thisfd->fd, &in);
}
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
@@ -877,31 +910,20 @@ static void main_loop(int cmd_timeout)
}
if (select_status > 0) {
- struct local_client *lastfd = NULL;
char csid[MAX_CSID_LEN];
char buf[max_cluster_message];
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
- if (thisfd->removeme && !cleanup_zombie(thisfd)) {
- struct local_client *free_fd = thisfd;
- lastfd->next = thisfd->next;
- DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
-
- /* Queue cleanup, this also frees the client struct */
- add_to_lvmqueue(free_fd, NULL, 0, NULL);
- break;
- }
-
- if (FD_ISSET(thisfd->fd, &in)) {
+ if (thisfd->fd < FD_SETSIZE && FD_ISSET(thisfd->fd, &in)) {
struct local_client *newfd = NULL;
int ret;
+ /* FIXME Remove from main thread in case it blocks! */
/* Do callback */
ret = thisfd->callback(thisfd, buf, sizeof(buf),
csid, &newfd);
/* Ignore EAGAIN */
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
- lastfd = thisfd;
continue;
}
@@ -917,17 +939,16 @@ static void main_loop(int cmd_timeout)
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
thisfd->removeme = 1;
- break;
+ continue;
}
/* New client...simply add it to the list */
if (newfd) {
newfd->next = thisfd->next;
thisfd->next = newfd;
- break;
+ thisfd = newfd;
}
}
- lastfd = thisfd;
}
}
@@ -1420,7 +1441,7 @@ static int read_from_local_sock(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
thisfd->bits.localsock.cleanup_needed = 1;
- DEBUGLOG("Creating pre&post thread\n");
+ DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
status = pthread_create(&thisfd->bits.localsock.threadid,
&stack_attr, pre_and_post_thread, thisfd);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
@@ -1674,7 +1695,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
sigset_t ss;
int pipe_fd = client->bits.localsock.pipe;
- DEBUGLOG("Pre&post thread (%p), pipe %d\n", client, pipe_fd);
+ DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
pthread_mutex_lock(&client->bits.localsock.mutex);
/* Ignore SIGUSR1 (handled by master process) but enable
@@ -1694,7 +1715,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
if ((status = do_pre_command(client)))
client->bits.localsock.all_success = 0;
- DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe %d\n",
+ DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
client, status, pipe_fd);
/* Tell the parent process we have finished this bit */
@@ -1976,7 +1997,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
{
/* If msg is NULL then this is a cleanup request */
if (cmd->msg == NULL) {
- DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
+ DEBUGLOG("process_work_item: free %p\n", cmd->client);
cmd_client_cleanup(cmd->client);
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
pthread_cond_destroy(&cmd->client->bits.localsock.cond);
7 years, 8 months
master - lvmlockd: improve check for duplicate global locks
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=57534733b7750f...
Commit: 57534733b7750f17f5ffa115306dcb650d8015b9
Parent: 1612c570b6412b68349b055ba3a6dab1796b8f35
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jul 23 10:34:24 2015 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Jul 23 10:39:11 2015 -0500
lvmlockd: improve check for duplicate global locks
When there are duplicate global locks, check if the gl
is still enabled each time a gl or vg lock is acquired
in the lockspace. Once one of the duplicates is disabled,
then other hosts will recognize that the issue is resolved
without needing to restart the lockspaces.
---
daemons/lvmlockd/lvmlockd-core.c | 23 +++++------------------
daemons/lvmlockd/lvmlockd-internal.h | 11 +++++++++++
daemons/lvmlockd/lvmlockd-sanlock.c | 10 ++++++++--
3 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c
index a01c8a6..7375d9e 100644
--- a/daemons/lvmlockd/lvmlockd-core.c
+++ b/daemons/lvmlockd/lvmlockd-core.c
@@ -199,17 +199,6 @@ static struct list_head lockspaces;
static struct list_head lockspaces_inactive;
/*
- * This flag is set to 1 if we see multiple vgs with the global
- * lock enabled. While this is set, we return a special flag
- * with the vg lock result indicating to the lvm command that
- * there is a duplicate gl in the vg which should be resolved.
- * While this is set, find_lockspace_name has the side job of
- * counting the number of lockspaces with enabled gl's so that
- * this can be set back to zero when the duplicates are disabled.
- */
-static int sanlock_gl_dup;
-
-/*
* Client thread reads client requests and writes client results.
*/
static pthread_t client_thread;
@@ -1046,6 +1035,9 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
log_debug("S %s R %s res_lock lm done r_version %u",
ls->name, r->name, r_version);
+ if (sanlock_gl_dup && ls->sanlock_gl_enabled)
+ act->flags |= LD_AF_DUP_GL_LS;
+
/* lm_lock() reads new r_version */
if ((r_version > r->version) || (!r->version && !r->version_zero_valid)) {
@@ -2096,9 +2088,6 @@ static void *lockspace_thread_main(void *arg_in)
act = list_first_entry(&ls->actions, struct action, list);
- if (sanlock_gl_dup && ls->sanlock_gl_enabled)
- act->flags |= LD_AF_DUP_GL_LS;
-
if (act->op == LD_OP_STOP) {
ls->thread_work = 0;
break;
@@ -3855,8 +3844,7 @@ static int print_lockspace(struct lockspace *ls, const char *prefix, int pos, in
"thread_work=%d "
"thread_stop=%d "
"thread_done=%d "
- "sanlock_gl_enabled=%d "
- "sanlock_gl_dup=%d\n",
+ "sanlock_gl_enabled=%d",
prefix,
ls->name,
ls->vg_name,
@@ -3870,8 +3858,7 @@ static int print_lockspace(struct lockspace *ls, const char *prefix, int pos, in
ls->thread_work ? 1 : 0,
ls->thread_stop ? 1 : 0,
ls->thread_done ? 1 : 0,
- ls->sanlock_gl_enabled ? 1 : 0,
- ls->sanlock_gl_dup ? 1 : 0);
+ ls->sanlock_gl_enabled ? 1 : 0);
}
static int print_action(struct action *act, const char *prefix, int pos, int len)
diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h
index 1fd7125..7bbddb4 100644
--- a/daemons/lvmlockd/lvmlockd-internal.h
+++ b/daemons/lvmlockd/lvmlockd-internal.h
@@ -322,6 +322,17 @@ EXTERN int daemon_host_id;
EXTERN const char *daemon_host_id_file;
EXTERN int sanlock_io_timeout;
+/*
+ * This flag is set to 1 if we see multiple vgs with the global
+ * lock enabled. While this is set, we return a special flag
+ * with the vg lock result indicating to the lvm command that
+ * there is a duplicate gl in the vg which should be resolved.
+ * While this is set, find_lockspace_name has the side job of
+ * counting the number of lockspaces with enabled gl's so that
+ * this can be set back to zero when the duplicates are disabled.
+ */
+EXTERN int sanlock_gl_dup;
+
void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c
index 28dac6b..44926da 100644
--- a/daemons/lvmlockd/lvmlockd-sanlock.c
+++ b/daemons/lvmlockd/lvmlockd-sanlock.c
@@ -801,8 +801,6 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
log_debug("S %s able_gl %s", ls->name, gl_name);
ls->sanlock_gl_enabled = enable;
- if (ls->sanlock_gl_dup && !enable)
- ls->sanlock_gl_dup = 0;
if (enable)
strncpy(gl_lsname_sanlock, ls->name, MAX_NAME);
@@ -1254,6 +1252,14 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
rs = &rds->rs;
+ /*
+ * While there are duplicate global locks, keep checking
+ * to see if any have been disabled.
+ */
+ if (sanlock_gl_dup && ls->sanlock_gl_enabled &&
+ (r->type == LD_RT_GL || r->type == LD_RT_VG))
+ ls->sanlock_gl_enabled = gl_is_enabled(ls, ls->lm_data);
+
if (r->type == LD_RT_LV) {
/*
* The lv may have been removed and recreated with a new lease
7 years, 8 months
master - libdm: Use wrappers for all malloc functions.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=1612c570b6412b...
Commit: 1612c570b6412b68349b055ba3a6dab1796b8f35
Parent: b92e5026957c5ca72e6e88304feaf7527ca80af1
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Wed Jul 22 23:03:32 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Wed Jul 22 23:11:48 2015 +0100
libdm: Use wrappers for all malloc functions.
Move the DEBUG_MEM decision inside libdevmapper.so instead of exposing
it in libdevmapper.h which causes failures if the binary and library
were compiled with opposite debugging settings.
---
WHATS_NEW_DM | 1 +
libdm/.exported_symbols | 9 +++
libdm/.exported_symbols.DM_1_02_103 | 7 +++
libdm/libdevmapper.h | 52 +++++++------------
libdm/mm/dbg_malloc.c | 95 +++++++++++++++++++++++++++++++++++
5 files changed, 130 insertions(+), 34 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 57edd8d..3dba5b8 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.103 -
================================
+ Introduce libdevmapper wrappers for all malloc-related functions.
Version 1.02.102 - 7th July 2015
================================
diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols
index 2b85343..6000686 100644
--- a/libdm/.exported_symbols
+++ b/libdm/.exported_symbols
@@ -1,3 +1,12 @@
+dm_bounds_check_debug
+dm_dump_memory_debug
+dm_free_aux
dm_log
dm_log_with_errno
+dm_malloc_aux
+dm_malloc_aux_debug
+dm_realloc_aux
+dm_strdup_aux
dm_task_get_info_with_deferred_remove
+dm_zalloc_aux
+dm_zalloc_aux_debug
diff --git a/libdm/.exported_symbols.DM_1_02_103 b/libdm/.exported_symbols.DM_1_02_103
new file mode 100644
index 0000000..5dea5ea
--- /dev/null
+++ b/libdm/.exported_symbols.DM_1_02_103
@@ -0,0 +1,7 @@
+dm_bounds_check_wrapper
+dm_dump_memory_wrapper
+dm_free_wrapper
+dm_malloc_wrapper
+dm_realloc_wrapper
+dm_strdup_wrapper
+dm_zalloc_wrapper
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index aad2971..6523c70 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -962,44 +962,28 @@ uint32_t dm_tree_get_cookie(struct dm_tree_node *node);
* Memory management
*******************/
-void *dm_malloc_aux(size_t s, const char *file, int line)
+/*
+ * Never use these functions directly - use the macros following instead.
+ */
+void *dm_malloc_wrapper(size_t s, const char *file, int line)
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
-void *dm_malloc_aux_debug(size_t s, const char *file, int line)
- __attribute__((__warn_unused_result__));
-void *dm_zalloc_aux(size_t s, const char *file, int line)
+void *dm_zalloc_wrapper(size_t s, const char *file, int line)
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
-void *dm_zalloc_aux_debug(size_t s, const char *file, int line)
+void *dm_realloc_wrapper(void *p, unsigned int s, const char *file, int line)
__attribute__((__warn_unused_result__));
-char *dm_strdup_aux(const char *str, const char *file, int line)
- __attribute__((__malloc__)) __attribute__((__warn_unused_result__));
-void dm_free_aux(void *p);
-void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
+void dm_free_wrapper(void *ptr);
+char *dm_strdup_wrapper(const char *s, const char *file, int line)
__attribute__((__warn_unused_result__));
-int dm_dump_memory_debug(void);
-void dm_bounds_check_debug(void);
-
-#ifdef DEBUG_MEM
-
-# define dm_malloc(s) dm_malloc_aux_debug((s), __FILE__, __LINE__)
-# define dm_zalloc(s) dm_zalloc_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_zalloc(s) dm_zalloc_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() {}
-
-#endif
-
+int dm_dump_memory_wrapper(void);
+void dm_bounds_check_wrapper(void);
+
+#define dm_malloc(s) dm_malloc_wrapper((s), __FILE__, __LINE__)
+#define dm_zalloc(s) dm_zalloc_wrapper((s), __FILE__, __LINE__)
+#define dm_strdup(s) dm_strdup_wrapper((s), __FILE__, __LINE__)
+#define dm_free(p) dm_free_wrapper(p)
+#define dm_realloc(p, s) dm_realloc_wrapper((p), (s), __FILE__, __LINE__)
+#define dm_dump_memory() dm_dump_memory_wrapper()
+#define dm_bounds_check() dm_bounds_check_wrapper()
/*
* The pool allocator is useful when you are going to allocate
diff --git a/libdm/mm/dbg_malloc.c b/libdm/mm/dbg_malloc.c
index e26f05e..ac71480 100644
--- a/libdm/mm/dbg_malloc.c
+++ b/libdm/mm/dbg_malloc.c
@@ -22,6 +22,22 @@
#include <assert.h>
#include <stdarg.h>
+void *dm_malloc_aux(size_t s, const char *file, int line)
+ __attribute__((__malloc__)) __attribute__((__warn_unused_result__));
+void *dm_malloc_aux_debug(size_t s, const char *file, int line)
+ __attribute__((__malloc__)) __attribute__((__warn_unused_result__));
+void *dm_zalloc_aux(size_t s, const char *file, int line)
+ __attribute__((__malloc__)) __attribute__((__warn_unused_result__));
+void *dm_zalloc_aux_debug(size_t s, const char *file, int line)
+ __attribute__((__malloc__)) __attribute__((__warn_unused_result__));
+void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
+ __attribute__((__warn_unused_result__));
+void dm_free_aux(void *p);
+char *dm_strdup_aux(const char *str, const char *file, int line)
+ __attribute__((__warn_unused_result__));
+int dm_dump_memory_debug(void);
+void dm_bounds_check_debug(void);
+
char *dm_strdup_aux(const char *str, const char *file, int line)
{
char *ret;
@@ -279,3 +295,82 @@ void *dm_zalloc_aux(size_t s, const char *file, int line)
return ptr;
}
+
+#ifdef DEBUG_MEM
+
+void *dm_malloc_wrapper(size_t s, const char *file, int line)
+{
+ return dm_malloc_aux_debug(s, file, line);
+}
+
+void *dm_zalloc_wrapper(size_t s, const char *file, int line)
+{
+ return dm_zalloc_aux_debug(s, file, line);
+}
+
+char *dm_strdup_wrapper(const char *str, const char *file, int line)
+{
+ return dm_strdup_aux(str, file, line);
+}
+
+void dm_free_wrapper(void *ptr)
+{
+ dm_free_aux(ptr);
+}
+
+void *dm_realloc_wrapper(void *p, unsigned int s, const char *file, int line)
+{
+ return dm_realloc_aux(p, s, file, line);
+}
+
+int dm_dump_memory_wrapper(void)
+{
+ return dm_dump_memory_debug();
+}
+
+void dm_bounds_check_wrapper(void)
+{
+ dm_bounds_check_debug();
+}
+
+#else /* !DEBUG_MEM */
+
+void *dm_malloc_wrapper(size_t s, const char *file, int line)
+{
+ return dm_malloc_aux(s, file, line);
+}
+
+void *dm_zalloc_wrapper(size_t s, const char *file, int line)
+{
+ return dm_zalloc_aux(s, file, line);
+}
+
+char *dm_strdup_wrapper(const char *str,
+ const char *file __attribute__((unused)),
+ int line __attribute__((unused)))
+{
+ return strdup(str);
+}
+
+void dm_free_wrapper(void *ptr)
+{
+ free(ptr);
+}
+
+void *dm_realloc_wrapper(void *p, unsigned int s,
+ const char *file __attribute__((unused)),
+ int line __attribute__((unused)))
+{
+ return realloc(p, s);
+}
+
+int dm_dump_memory_wrapper(void)
+{
+ return 1;
+}
+
+void dm_bounds_check_wrapper(void)
+{
+}
+
+#endif /* DEBUG_MEM */
7 years, 8 months
master - pvscan: skip autoactivation for lockd VGs
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b92e5026957c5c...
Commit: b92e5026957c5ca72e6e88304feaf7527ca80af1
Parent: 27e6aee3904d195de658505b3bacc65601344d46
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jul 22 14:53:46 2015 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jul 22 15:44:20 2015 -0500
pvscan: skip autoactivation for lockd VGs
pvscan autoactivation does not work for lockd VGs because
lock start is needed on a lockd VG before locking can be
done for it. Add a check to skip the attempt at autoactivate
rather than calling it, knowing it will fail.
Add a comment explaining why pvscan --cache works fine for
lockd VGs without locks, and why autoactivate is not done.
---
lib/cache/lvmetad.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 60f0277..856b30f 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -952,6 +952,51 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
+ /*
+ * pvscan --cache does not perform any lvmlockd locking, and
+ * pvscan --cache -aay skips autoactivation in lockd VGs.
+ *
+ * pvscan --cache populates lvmetad with VG metadata from disk.
+ * No lvmlockd locking is needed. It is expected that lockd VG
+ * metadata that is read by pvscan and populated in lvmetad may
+ * be immediately stale due to changes to the VG from other hosts
+ * during or after this pvscan. This is normal and not a problem.
+ * When a subsequent lvm command uses the VG, it will lock the VG
+ * with lvmlockd, read the VG from lvmetad, and update the cached
+ * copy from disk if necessary.
+ *
+ * pvscan --cache -aay does not activate LVs in lockd VGs because
+ * activation requires locking, and a lock-start operation is needed
+ * on a lockd VG before any locking can be performed in it.
+ *
+ * An equivalent of pvscan --cache -aay for lockd VGs is:
+ * 1. pvscan --cache
+ * 2. vgchange --lock-start
+ * 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
+ *
+ * [We could eventually add support for autoactivating lockd VGs
+ * using pvscan by incorporating the lock start step (which can
+ * take a long time), but there may be a better option than
+ * continuing to overload pvscan.]
+ *
+ * Stages of starting a lockd VG:
+ *
+ * . pvscan --cache populates lockd VGs in lvmetad without locks,
+ * and this initial cached copy may quickly become stale.
+ *
+ * . vgchange --lock-start VG reads the VG without the VG lock
+ * because no locks are available until the locking is started.
+ * It only uses the VG name and lock_type from the VG metadata,
+ * and then only uses it to start the VG lockspace in lvmlockd.
+ *
+ * . Further lvm commands, e.g. activation, can then lock the VG
+ * with lvmlockd and use current VG metdata.
+ */
+ if (handler && vg && is_lockd_type(vg->lock_type)) {
+ log_debug_lvmetad("Skip pvscan activation for lockd type VG %s", vg->name);
+ handler = NULL;
+ }
+
if (result && handler) {
status = daemon_reply_str(reply, "status", "<missing>");
vgname = daemon_reply_str(reply, "vgname", "<missing>");
7 years, 8 months
master - lvconvert: merge polling fixes for lockd
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=27e6aee3904d19...
Commit: 27e6aee3904d195de658505b3bacc65601344d46
Parent: 8bfcefe11a2ce594d1f6e8ef5a1b17e80786ceab
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jul 22 11:42:57 2015 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jul 22 12:28:06 2015 -0500
lvconvert: merge polling fixes for lockd
. the poll check will eventually call finish which will
write the VG, so an ex VG lock is needed from lvmlockd.
. fix missing unlock on poll error path
. remove the lockd locking while monitoring the progress
of the command, as suggested by the earlier FIXME comment,
as it's not needed.
---
tools/lvconvert.c | 10 +------
tools/polldaemon.c | 61 +++++++++++++++++++++++++++++-----------------------
2 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 0c5e2bd..6a0e0ca 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3410,10 +3410,7 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
cmd->handles_missing_pvs = 1;
}
- /*
- * The VG lock will be released when the command exits.
- * Commands that poll the LV will reacquire the VG lock.
- */
+ /* Unlock on error paths not required, it's automatic when command exits. */
if (!lockd_vg(cmd, lp->vg_name, "ex", 0, &lockd_state))
goto_out;
@@ -3461,10 +3458,7 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
bad:
unlock_vg(cmd, lp->vg_name);
- /*
- * The command may sit and monitor progress for some time,
- * and we do not need or want the VG lock held during that.
- */
+ /* Unlock here so it's not held during polling. */
lockd_vg(cmd, lp->vg_name, "un", 0, &lockd_state);
release_vg(vg);
diff --git a/tools/polldaemon.c b/tools/polldaemon.c
index bbe4641..4527efb 100644
--- a/tools/polldaemon.c
+++ b/tools/polldaemon.c
@@ -136,17 +136,22 @@ static void _sleep_and_rescan_devices(struct daemon_parms *parms)
int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
struct daemon_parms *parms)
{
- struct volume_group *vg;
+ struct volume_group *vg = NULL;
struct logical_volume *lv;
int finished = 0;
uint32_t lockd_state = 0;
+ int ret;
/* Poll for completion */
while (!finished) {
if (parms->wait_before_testing)
_sleep_and_rescan_devices(parms);
- if (!lockd_vg(cmd, id->vg_name, "sh", 0, &lockd_state)) {
+ /*
+ * An ex VG lock is needed because the check can call finish_copy
+ * which writes the VG.
+ */
+ if (!lockd_vg(cmd, id->vg_name, "ex", 0, &lockd_state)) {
log_error("ABORTING: Can't lock VG for %s.", id->display_name);
return 0;
}
@@ -154,10 +159,12 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
/* Locks the (possibly renamed) VG again */
vg = vg_read(cmd, id->vg_name, NULL, READ_FOR_UPDATE, lockd_state);
if (vg_read_error(vg)) {
- release_vg(vg);
- log_error("ABORTING: Can't reread VG for %s.", id->display_name);
/* What more could we do here? */
- return 0;
+ log_error("ABORTING: Can't reread VG for %s.", id->display_name);
+ release_vg(vg);
+ vg = NULL;
+ ret = 0;
+ goto out;
}
lv = find_lv(vg, id->lv_name);
@@ -174,9 +181,8 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
else
log_print_unless_silent("Can't find LV in %s for %s.",
vg->name, id->display_name);
-
- unlock_and_release_vg(cmd, vg, vg->name);
- return 1;
+ ret = 1;
+ goto out;
}
/*
@@ -185,13 +191,13 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
*/
if (!lv_is_active_locally(lv)) {
log_print_unless_silent("%s: Interrupted: No longer active.", id->display_name);
- unlock_and_release_vg(cmd, vg, vg->name);
- return 1;
+ ret = 1;
+ goto out;
}
if (!_check_lv_status(cmd, vg, lv, id->display_name, parms, &finished)) {
- unlock_and_release_vg(cmd, vg, vg->name);
- return_0;
+ ret = 0;
+ goto_out;
}
unlock_and_release_vg(cmd, vg, vg->name);
@@ -215,6 +221,12 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
}
return 1;
+
+out:
+ if (vg)
+ unlock_and_release_vg(cmd, vg, vg->name);
+ lockd_vg(cmd, id->vg_name, "un", 0, &lockd_state);
+ return ret;
}
struct poll_id_list {
@@ -373,21 +385,17 @@ static int report_progress(struct cmd_context *cmd, struct poll_operation_id *id
int ret;
/*
- * FIXME: we don't really need to take the vg lock here,
- * because we only report the progress on the same host
- * where the pvmove/lvconvert is happening. This means
- * that the local pvmove/lvconvert/lvpoll commands are
- * updating the local lvmetad with the latest info they
- * have, and we just need to read the latest info that
- * they have put into lvmetad about their progress.
- * No VG lock is needed to protect anything here
- * (we're just reading the VG), and no VG lock is
- * needed to force a VG read from disk to get changes
- * from other hosts, because the only change to the VG
- * we're interested in is the change done locally.
+ * It's reasonable to expect a lockd_vg("sh") here, but it should
+ * not actually be needed, because we only report the progress on
+ * the same host where the pvmove/lvconvert is happening. This means
+ * that the local pvmove/lvconvert/lvpoll commands are updating the
+ * local lvmetad with the latest info they have, and we just need to
+ * read the latest info that they have put into lvmetad about their
+ * progress. No VG lock is needed to protect anything here (we're
+ * just reading the VG), and no VG lock is needed to force a VG read
+ * from disk to get changes from other hosts, because the only change
+ * to the VG we're interested in is the change done locally.
*/
- if (!lockd_vg(cmd, id->vg_name, "sh", 0, &lockd_state))
- return 0;
vg = vg_read(cmd, id->vg_name, NULL, 0, lockd_state);
if (vg_read_error(vg)) {
@@ -431,7 +439,6 @@ static int report_progress(struct cmd_context *cmd, struct poll_operation_id *id
out:
unlock_and_release_vg(cmd, vg, vg->name);
out_ret:
- lockd_vg(cmd, id->vg_name, "un", 0, &lockd_state);
return ret;
}
7 years, 8 months
master - config: add CFG_SECTION_NO_CHECK flag
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8bfcefe11a2ce5...
Commit: 8bfcefe11a2ce594d1f6e8ef5a1b17e80786ceab
Parent: 00d24511bc5e1ae446867f65b5adfe3e7d404398
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Wed Jul 22 14:19:07 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Wed Jul 22 14:25:42 2015 +0200
config: add CFG_SECTION_NO_CHECK flag
The CFG_SECTION_NO_CHECK flag can be used to mark a section
and its whole subtree as containing settings where checks
won't be made (lvmconfig --validate).
These are setting where we don't know the names and and type
in advance and they're recognized in runtime. As we don't know
the type and name in advance, we can't do any checks here
of course.
Use this flag with great care as it disables config checks
for the whole config subtree found under such section.
This flag is going to be used by subsequent patches from
Zdenek to support some cache settings...
---
lib/config/config.c | 12 ++++++------
lib/config/config.h | 2 ++
lib/config/config_settings.h | 1 +
3 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/lib/config/config.c b/lib/config/config.c
index 35ee3ac..eb8880e 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -1040,9 +1040,14 @@ static int _config_def_check_tree(struct cft_check_handle *handle,
size_t buf_size, struct dm_config_node *root)
{
struct dm_config_node *cn;
+ cfg_def_item_t *def;
int valid, r = 1;
size_t len;
+ def = cfg_def_get_item_p(root->id);
+ if (def->flags & CFG_SECTION_NO_CHECK)
+ return 1;
+
for (cn = root->child; cn; cn = cn->sib) {
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
buf_size, cn)) && !cn->v) {
@@ -1662,14 +1667,9 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
char path[CFG_PATH_MAX_LEN];
char commentline[MAX_COMMENT_LINE+1];
- if (cn->id < 0)
+ if (cn->id <= 0)
return 1;
- if (!cn->id) {
- log_error(INTERNAL_ERROR "Configuration node %s has invalid id.", cn->key);
- return 0;
- }
-
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
return 1;
diff --git a/lib/config/config.h b/lib/config/config.h
index 03319bf..7520fc0 100644
--- a/lib/config/config.h
+++ b/lib/config/config.h
@@ -121,6 +121,8 @@ typedef union {
#define CFG_DISABLED 0x200
/* whether to print integers in octal form (prefixed by "0") */
#define CFG_FORMAT_INT_OCTAL 0x400
+/* whether to disable checks for the whole config section subtree */
+#define CFG_SECTION_NO_CHECK 0x800
/* configuration definition item structure */
typedef struct cfg_def_item {
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index ce03b36..5209531 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -51,6 +51,7 @@
* CFG_DEFAULT_COMMENTED - node's default value is commented out on output
* CFG_DISABLED - configuration is disabled (defaults always used)
* CFG_FORMAT_INT_OCTAL - print integer number in octal form (also prefixed by "0")
+ * CFG_SECTION_NO_CHECK - do not check content of the section at all - use with care!!!
*
* type: Allowed type for the value of simple configuation setting, one of:
* CFG_TYPE_BOOL
7 years, 8 months
master - lvconvert: remove unused struct members
by okozina
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=00d24511bc5e1a...
Commit: 00d24511bc5e1ae446867f65b5adfe3e7d404398
Parent: 03762f42c18812b95c550fefcdf531e0ff2f78b0
Author: Ondrej Kozina <okozina(a)redhat.com>
AuthorDate: Wed Jul 22 12:56:43 2015 +0200
Committer: Ondrej Kozina <okozina(a)redhat.com>
CommitterDate: Wed Jul 22 12:56:43 2015 +0200
lvconvert: remove unused struct members
---
tools/lvconvert.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index d979e84..0c5e2bd 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -40,9 +40,6 @@ struct lvconvert_params {
int wait_completion;
int need_polling;
- int is_merging_origin;
- int is_merging_origin_thin;
-
int thin_chunk_size_calc_policy;
uint32_t chunk_size;
uint32_t region_size;
7 years, 8 months
master - lvconvert: retain retcode consistency
by okozina
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=03762f42c18812...
Commit: 03762f42c18812b95c550fefcdf531e0ff2f78b0
Parent: ae88bf03a1d109a342a8ad31196c3ef8fa1a5b65
Author: Ondrej Kozina <okozina(a)redhat.com>
AuthorDate: Wed Jul 22 12:26:28 2015 +0200
Committer: Ondrej Kozina <okozina(a)redhat.com>
CommitterDate: Wed Jul 22 12:26:46 2015 +0200
lvconvert: retain retcode consistency
Always return the highest retcode caught during convert command
(regression in commit ae88bf03a1d109a342a8ad31196c3ef8fa1a5b65).
Also minor code cleanup.
---
tools/lvconvert.c | 26 ++++++++++++--------------
1 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 58428b7..d979e84 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3367,7 +3367,7 @@ static struct convert_poll_id_list* _convert_poll_id_list_create(struct cmd_cont
if (!(idl->id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s))) {
dm_pool_free(cmd->mem, idl);
- return NULL;
+ return_NULL;
}
idl->is_merging_origin = lv_is_merging_origin(lv);
@@ -3391,11 +3391,9 @@ static int _convert_and_add_to_poll_list(struct cmd_context *cmd,
if (!lv_info(cmd, lp->lv_to_poll, 0, &info, 0, 0) || !info.exists)
log_print_unless_silent("Conversion starts after activation.");
else {
- idl = _convert_poll_id_list_create(cmd, lp->lv_to_poll);
- if (!idl)
+ if (!(idl = _convert_poll_id_list_create(cmd, lp->lv_to_poll)))
return_ECMD_FAILED;
- else
- dm_list_add(&lp->idls, &idl->list);
+ dm_list_add(&lp->idls, &idl->list);
}
}
@@ -3490,21 +3488,21 @@ static int _lvconvert_merge_single(struct cmd_context *cmd, struct logical_volum
int lvconvert(struct cmd_context * cmd, int argc, char **argv)
{
- int ret;
+ int poll_ret, ret;
struct convert_poll_id_list *idl;
struct lvconvert_params lp = {
.target_attr = ~0,
};
struct processing_handle *handle = NULL;
+ dm_list_init(&lp.idls);
+
if (!(handle = init_processing_handle(cmd))) {
log_error("Failed to initialize processing handle.");
ret = ECMD_FAILED;
goto out;
}
- dm_list_init(&lp.idls);
-
handle->custom_handle = &lp;
if (!_read_params(cmd, argc, argv, &lp)) {
@@ -3519,12 +3517,12 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
ret = lvconvert_single(cmd, &lp);
dm_list_iterate_items(idl, &lp.idls) {
- ret = _lvconvert_poll_by_id(cmd, idl->id,
- lp.wait_completion ? 0 : 1U,
- idl->is_merging_origin,
- idl->is_merging_origin_thin);
- if (ret != ECMD_PROCESSED)
- goto out;
+ poll_ret = _lvconvert_poll_by_id(cmd, idl->id,
+ lp.wait_completion ? 0 : 1U,
+ idl->is_merging_origin,
+ idl->is_merging_origin_thin);
+ if (poll_ret > ret)
+ ret = poll_ret;
}
out:
7 years, 8 months
master - lvconvert: fix polling outside of core lvconvert
by okozina
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ae88bf03a1d109...
Commit: ae88bf03a1d109a342a8ad31196c3ef8fa1a5b65
Parent: c3fddb0fbbcabf73d3bcf2786cea31c179f13fae
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jul 15 13:02:54 2015 -0500
Committer: Ondrej Kozina <okozina(a)redhat.com>
CommitterDate: Wed Jul 22 10:38:02 2015 +0200
lvconvert: fix polling outside of core lvconvert
Recent change to move the polling outside of core lvconvert
code was wrongly using 'lv' and 'vg' structs which can't be
used outside of the core code, which caused seg fault.
Properly isolate all use of lv structs within the core of
the lvconvert code, saving any information necessary,
(esp lvid). After the core of lvconvert is done, use
the saved information to do polling.
FIXME: the need for is_merging_origin and is_merging_origin_thin
in this patch is ugly, and a cleaner way should be found to deal
with that than what is done here.
Also it effectively removed all hacks in _lvconvert_merge_single
performing ugly: VG reread, unlock, polling, lock sequence.
Moreover all polling operations are postponed after all conversions
are finished.
lvm2 (while locking via lvmlockd) should now be able to run with
or without lvmpolld while performing poll operations originating
in lvconvert command.
Signed-off-by: Ondrej Kozina <okozina(a)redhat.com>
---
WHATS_NEW | 1 +
tools/lvconvert.c | 198 ++++++++++++++++++++++++++---------------------------
2 files changed, 98 insertions(+), 101 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 22a0233..adf8eb7 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.126 -
================================
+ Fix lvconvert segfaults while performing snapshots merge.
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
Fix alloc segfault when extending LV with fewer stripes than in first seg.
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index e673f53..58428b7 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -17,7 +17,6 @@
#include "polldaemon.h"
#include "lv_alloc.h"
#include "lvconvert_poll.h"
-#include "lvmpolld-client.h"
struct lvconvert_params {
int cache;
@@ -41,6 +40,9 @@ struct lvconvert_params {
int wait_completion;
int need_polling;
+ int is_merging_origin;
+ int is_merging_origin_thin;
+
int thin_chunk_size_calc_policy;
uint32_t chunk_size;
uint32_t region_size;
@@ -69,6 +71,7 @@ struct lvconvert_params {
struct dm_list *replace_pvh;
struct logical_volume *lv_to_poll;
+ struct dm_list idls;
uint32_t pool_metadata_extents;
int passed_args;
@@ -81,6 +84,13 @@ struct lvconvert_params {
thin_discards_t discards;
};
+struct convert_poll_id_list {
+ struct dm_list list;
+ struct poll_operation_id *id;
+ unsigned is_merging_origin:1;
+ unsigned is_merging_origin_thin:1;
+};
+
static int _lvconvert_validate_names(struct lvconvert_params *lp)
{
int i, j;
@@ -763,26 +773,41 @@ static struct poll_operation_id *_create_id(struct cmd_context *cmd,
return id;
}
+static int _lvconvert_poll_by_id(struct cmd_context *cmd, struct poll_operation_id *id,
+ unsigned background,
+ int is_merging_origin,
+ int is_merging_origin_thin)
+{
+ if (is_merging_origin)
+ return poll_daemon(cmd, background,
+ (MERGING | (is_merging_origin_thin ? THIN_VOLUME : SNAPSHOT)),
+ is_merging_origin_thin ? &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns,
+ "Merged", id);
+ else
+ return poll_daemon(cmd, background, CONVERTING,
+ &_lvconvert_mirror_fns, "Converted", id);
+}
+
int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
unsigned background)
{
- int is_thin, r;
+ int r;
struct poll_operation_id *id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s);
+ int is_merging_origin = 0;
+ int is_merging_origin_thin = 0;
if (!id) {
log_error("Failed to allocate poll identifier for lvconvert.");
return ECMD_FAILED;
}
+ /* FIXME: check this in polling instead */
if (lv_is_merging_origin(lv)) {
- is_thin = seg_is_thin_volume(find_snapshot(lv));
- r = poll_daemon(cmd, background,
- (MERGING | (is_thin ? THIN_VOLUME : SNAPSHOT)),
- is_thin ? &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns,
- "Merged", id);
- } else
- r = poll_daemon(cmd, background, CONVERTING,
- &_lvconvert_mirror_fns, "Converted", id);
+ is_merging_origin = 1;
+ is_merging_origin_thin = seg_is_thin_volume(find_snapshot(lv));
+ }
+
+ r = _lvconvert_poll_by_id(cmd, id, background, is_merging_origin, is_merging_origin_thin);
_destroy_id(cmd, id);
@@ -3028,7 +3053,7 @@ static int _lvconvert_pool(struct cmd_context *cmd,
return_0;
/*
- * Create a new lock for a thin pool LV. A cache pool LV has no lock.
+ * Create a new lock for a thin pool LV. A cache pool LV has no lock.
* Locks are removed from existing LVs that are being converted to
* data and meta LVs (they are unlocked and deleted below.)
*/
@@ -3330,17 +3355,51 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_PROCESSED;
}
-static int _poll_logical_volume(struct cmd_context *cmd, struct logical_volume *lv,
- int wait_completion)
+static struct convert_poll_id_list* _convert_poll_id_list_create(struct cmd_context *cmd,
+ const struct logical_volume *lv)
{
+ struct convert_poll_id_list *idl = (struct convert_poll_id_list *) dm_pool_alloc(cmd->mem, sizeof(struct convert_poll_id_list));
+
+ if (!idl) {
+ log_error("Convert poll ID list allocation failed.");
+ return NULL;
+ }
+
+ if (!(idl->id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s))) {
+ dm_pool_free(cmd->mem, idl);
+ return NULL;
+ }
+
+ idl->is_merging_origin = lv_is_merging_origin(lv);
+ idl->is_merging_origin_thin = idl->is_merging_origin && seg_is_thin_volume(find_snapshot(lv));
+
+ return idl;
+}
+
+static int _convert_and_add_to_poll_list(struct cmd_context *cmd,
+ struct lvconvert_params *lp,
+ struct logical_volume *lv)
+{
+ int ret;
struct lvinfo info;
+ struct convert_poll_id_list *idl;
- if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) {
- log_print_unless_silent("Conversion starts after activation.");
- return ECMD_PROCESSED;
+ /* _lvconvert_single() call may alter the reference in lp->lv_to_poll */
+ if ((ret = _lvconvert_single(cmd, lv, lp)) != ECMD_PROCESSED)
+ stack;
+ else if (lp->need_polling) {
+ if (!lv_info(cmd, lp->lv_to_poll, 0, &info, 0, 0) || !info.exists)
+ log_print_unless_silent("Conversion starts after activation.");
+ else {
+ idl = _convert_poll_id_list_create(cmd, lp->lv_to_poll);
+ if (!idl)
+ return_ECMD_FAILED;
+ else
+ dm_list_add(&lp->idls, &idl->list);
+ }
}
- return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U);
+ return ret;
}
static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp)
@@ -3402,7 +3461,8 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
goto_bad;
lp->lv_to_poll = lv;
- ret = _lvconvert_single(cmd, lv, lp);
+ ret = _convert_and_add_to_poll_list(cmd, lp, lv);
+
bad:
unlock_vg(cmd, lp->vg_name);
@@ -3412,10 +3472,6 @@ bad:
*/
lockd_vg(cmd, lp->vg_name, "un", 0, &lockd_state);
- if (ret == ECMD_PROCESSED && lp->need_polling)
- ret = _poll_logical_volume(cmd, lp->lv_to_poll,
- lp->wait_completion);
-
release_vg(vg);
out:
init_ignore_suspended_devices(saved_ignore_suspended_devices);
@@ -3426,84 +3482,16 @@ static int _lvconvert_merge_single(struct cmd_context *cmd, struct logical_volum
struct processing_handle *handle)
{
struct lvconvert_params *lp = (struct lvconvert_params *) handle->custom_handle;
- const char *vg_name;
- struct volume_group *vg_fresh;
- struct logical_volume *lv_fresh;
- int ret = ECMD_FAILED;
- uint32_t lockd_state = 0; /* dummy placeholder, lvmlockd doesn't use this path */
-
- /*
- * FIXME can't trust lv's VG to be current given that caller
- * is process_each_lv() -- _poll_logical_volume() may have
- * already updated the VG's metadata in an earlier iteration.
- * - preemptively drop the VG lock, as is needed for
- * _poll_logical_volume(), refresh LV (and VG in the process).
- */
-
- vg_name = lv->vg->name;
- unlock_vg(cmd, vg_name);
- vg_fresh = vg_read(cmd, vg_name, NULL, READ_FOR_UPDATE, lockd_state);
- if (vg_read_error(vg_fresh)) {
- log_error("ABORTING: Can't reread VG %s", vg_name);
- goto out;
- }
-
- if (!(lv_fresh = find_lv(vg_fresh, lv->name))) {
- log_error("ABORTING: Can't find LV %s in VG %s", lv->name, vg_name);
- unlock_vg(cmd, vg_name);
- goto out;
- }
-
- lp->lv_to_poll = lv_fresh;
- if ((ret = _lvconvert_single(cmd, lv_fresh, lp)) != ECMD_PROCESSED)
- stack;
-
- if (ret == ECMD_PROCESSED && lp->need_polling) {
- /*
- * Must drop VG lock, because lvconvert_poll() needs it,
- * then reacquire it after polling completes
- */
- unlock_vg(cmd, vg_name);
-
- if ((ret = _poll_logical_volume(cmd, lp->lv_to_poll,
- lp->wait_completion)) != ECMD_PROCESSED)
- stack;
-
- /* use LCK_VG_WRITE to match lvconvert()'s READ_FOR_UPDATE */
- if (!lock_vol(cmd, vg_name, LCK_VG_WRITE, NULL)) {
- log_error("ABORTING: Can't relock VG for %s "
- "after polling finished", vg_name);
- ret = ECMD_FAILED;
- }
- }
-out:
- release_vg(vg_fresh);
- return ret;
-}
-
-/*
- * process_each_lv locks the VG, reads the VG, calls this which starts the
- * conversion, then unlocks the VG. The lvpoll command will come along later
- * and lock the VG, read the VG, check the progress, unlock the VG, sleep and
- * repeat until done.
- */
-
-static int _lvconvert_lvmpolld_merge_single(struct cmd_context *cmd, struct logical_volume *lv,
- struct processing_handle *handle)
-{
- struct lvconvert_params *lp = (struct lvconvert_params *) handle->custom_handle;
- int ret;
lp->lv_to_poll = lv;
- if ((ret = _lvconvert_single(cmd, lv, lp)) != ECMD_PROCESSED)
- stack;
- return ret;
+ return _convert_and_add_to_poll_list(cmd, lp, lv);
}
int lvconvert(struct cmd_context * cmd, int argc, char **argv)
{
int ret;
+ struct convert_poll_id_list *idl;
struct lvconvert_params lp = {
.target_attr = ~0,
};
@@ -3515,6 +3503,8 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
goto out;
}
+ dm_list_init(&lp.idls);
+
handle->custom_handle = &lp;
if (!_read_params(cmd, argc, argv, &lp)) {
@@ -3522,18 +3512,24 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
goto_out;
}
- if (lp.merge) {
+ if (lp.merge)
ret = process_each_lv(cmd, argc, argv, READ_FOR_UPDATE, handle,
- lvmpolld_use() ? &_lvconvert_lvmpolld_merge_single :
- &_lvconvert_merge_single);
-
- if (ret == ECMD_PROCESSED && lvmpolld_use() && lp.need_polling) {
- if ((ret = _poll_logical_volume(cmd, lp.lv_to_poll, lp.wait_completion)) != ECMD_PROCESSED)
- stack;
- }
- } else
+ &_lvconvert_merge_single);
+ else
ret = lvconvert_single(cmd, &lp);
+
+ dm_list_iterate_items(idl, &lp.idls) {
+ ret = _lvconvert_poll_by_id(cmd, idl->id,
+ lp.wait_completion ? 0 : 1U,
+ idl->is_merging_origin,
+ idl->is_merging_origin_thin);
+ if (ret != ECMD_PROCESSED)
+ goto out;
+ }
+
out:
+ if (!dm_list_empty(&lp.idls))
+ dm_pool_free(cmd->mem, dm_list_item(dm_list_first(&lp.idls), struct convert_poll_id_list));
if (lp.policy_settings)
dm_config_destroy(lp.policy_settings);
destroy_processing_handle(cmd, handle);
7 years, 8 months
master - wiping: add "Wiping skipped." for the message context to be complete
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=c3fddb0fbbcabf...
Commit: c3fddb0fbbcabf73d3bcf2786cea31c179f13fae
Parent: 697fb353dc5ecf813199c598eed07983868fdd56
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Jul 21 11:00:43 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jul 21 11:00:43 2015 +0200
wiping: add "Wiping skipped." for the message context to be complete
---
lib/device/dev-type.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 873e02e..db40792 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -530,6 +530,7 @@ static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
#define MSG_FAILED_SIG_OFFSET "Failed to get offset of the %s signature on %s."
#define MSG_FAILED_SIG_LENGTH "Failed to get length of the %s signature on %s."
+#define MSG_WIPING_SKIPPED " Wiping skipped."
static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
uint32_t types_to_exclude, uint32_t types_no_prompt,
@@ -549,7 +550,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
log_error(MSG_FAILED_SIG_OFFSET, type, name);
return 0;
} else {
- log_error("WARNING: " MSG_FAILED_SIG_OFFSET, type, name);
+ log_error("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
@@ -558,7 +559,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
log_error(MSG_FAILED_SIG_LENGTH, type, name);
return 0;
} else {
- log_warn("WARNING: " MSG_FAILED_SIG_LENGTH, type, name);
+ log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
@@ -568,7 +569,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
log_error(MSG_FAILED_SIG_OFFSET, type, name);
return 0;
} else {
- log_warn("WARNING: " MSG_FAILED_SIG_OFFSET, type, name);
+ log_warn("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
@@ -577,7 +578,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
log_error(MSG_FAILED_SIG_LENGTH, type, name);
return 0;
} else {
- log_warn("WARNING: " MSG_FAILED_SIG_LENGTH, type, name);
+ log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
7 years, 8 months