diff -rupN LVM2.2.02.58//configure LVM2.2.02.61//configure --- LVM2.2.02.58//configure 2010-01-11 21:29:54.000000000 +0530 +++ LVM2.2.02.61//configure 2010-01-22 03:45:45.000000000 +0530 @@ -15531,7 +15531,7 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' ################################################################################ -ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile doc/Makefile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/misc/lvm-version.h lib/snapshot/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/lvm2_monitoring_init_red_hat scripts/Makefile test/Makefile test/api/Makefile tools/Makefile udev/Makefile" +ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile doc/Makefile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/misc/lvm-version.h lib/snapshot/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_monitoring_init_red_hat scripts/Makefile test/Makefile test/api/Makefile tools/Makefile udev/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -16138,6 +16138,7 @@ do "daemons/dmeventd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/Makefile" ;; "daemons/dmeventd/libdevmapper-event.pc") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/libdevmapper-event.pc" ;; "daemons/dmeventd/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/Makefile" ;; + "daemons/dmeventd/plugins/lvm2/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/lvm2/Makefile" ;; "daemons/dmeventd/plugins/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/mirror/Makefile" ;; "daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; @@ -16157,6 +16158,7 @@ do "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; "po/Makefile") CONFIG_FILES="$CONFIG_FILES po/Makefile" ;; "scripts/clvmd_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/clvmd_init_red_hat" ;; + "scripts/cmirrord_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/cmirrord_init_red_hat" ;; "scripts/lvm2_monitoring_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_init_red_hat" ;; "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; diff -rupN LVM2.2.02.58//configure.in LVM2.2.02.61//configure.in --- LVM2.2.02.58//configure.in 2010-01-11 21:21:44.000000000 +0530 +++ LVM2.2.02.61//configure.in 2010-01-22 03:45:45.000000000 +0530 @@ -1156,6 +1156,7 @@ daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile +daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile doc/Makefile @@ -1175,6 +1176,7 @@ liblvm/liblvm2app.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat +scripts/cmirrord_init_red_hat scripts/lvm2_monitoring_init_red_hat scripts/Makefile test/Makefile diff -rupN LVM2.2.02.58//daemons/clvmd/clvmd.c LVM2.2.02.61//daemons/clvmd/clvmd.c --- LVM2.2.02.58//daemons/clvmd/clvmd.c 2009-10-12 14:03:30.000000000 +0530 +++ LVM2.2.02.61//daemons/clvmd/clvmd.c 2010-02-02 14:24:29.000000000 +0530 @@ -342,7 +342,7 @@ int main(int argc, char *argv[]) printf("Protocol version: %d.%d.%d\n", CLVMD_MAJOR_VERSION, CLVMD_MINOR_VERSION, CLVMD_PATCH_VERSION); - exit(1); + exit(0); break; } diff -rupN LVM2.2.02.58//daemons/clvmd/lvm-functions.c LVM2.2.02.61//daemons/clvmd/lvm-functions.c --- LVM2.2.02.58//daemons/clvmd/lvm-functions.c 2010-01-05 21:39:33.000000000 +0530 +++ LVM2.2.02.61//daemons/clvmd/lvm-functions.c 2010-01-26 13:30:03.000000000 +0530 @@ -373,17 +373,22 @@ static int do_activate_lv(char *resource /* If it's suspended then resume it */ if (!lv_info_by_lvid(cmd, resource, &lvi, 0, 0)) - return EIO; + goto error; if (lvi.suspended) if (!lv_resume(cmd, resource)) - return EIO; + goto error; /* Now activate it */ if (!lv_activate(cmd, resource, exclusive)) - return EIO; + goto error; return 0; + +error: + if (oldmode == -1 || oldmode != mode) + (void)hold_unlock(resource); + return EIO; } /* Resume the LV if it was active */ @@ -499,6 +504,9 @@ int do_lock_lv(unsigned char command, un cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0; + /* clvmd should never try to read suspended device */ + init_ignore_suspended_devices(1); + switch (command & LCK_MASK) { case LCK_LV_EXCLUSIVE: status = do_activate_lv(resource, lock_flags, LKM_EXMODE); @@ -627,6 +635,7 @@ int do_refresh_cache() } init_full_scan_done(0); + init_ignore_suspended_devices(1); lvmcache_label_scan(cmd, 2); dm_pool_empty(cmd->mem); @@ -860,6 +869,7 @@ int init_lvm(int using_gulm) /* Check lvm.conf is setup for cluster-LVM */ check_config(); + init_ignore_suspended_devices(1); /* Remove any non-LV locks that may have been left around */ if (using_gulm) diff -rupN LVM2.2.02.58//daemons/cmirrord/clogd.c LVM2.2.02.61//daemons/cmirrord/clogd.c --- LVM2.2.02.58//daemons/cmirrord/clogd.c 2009-09-15 04:27:46.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/clogd.c 2010-01-19 21:28:45.000000000 +0530 @@ -9,44 +9,29 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "logging.h" +#include "common.h" +#include "functions.h" +#include "link_mon.h" +#include "local.h" -#include "configure.h" - -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include - -#include "dm-log-userspace.h" -#include "functions.h" -#include "local.h" -#include "cluster.h" -#include "common.h" -#include "logging.h" -#include "link_mon.h" +#include +#include -static int exit_now = 0; +static volatile sig_atomic_t exit_now = 0; +/* FIXME Review signal handling. Should be volatile sig_atomic_t */ static sigset_t signal_mask; -static int signal_received; +static volatile sig_atomic_t signal_received; static void process_signals(void); static void daemonize(void); static void init_all(void); static void cleanup_all(void); -int main(int argc, char *argv[]) +int main(int argc __attribute((unused)), char *argv[] __attribute((unused))) { daemonize(); @@ -74,7 +59,7 @@ int main(int argc, char *argv[]) * @sig: the signal * */ -static void parent_exit_handler(int sig) +static void parent_exit_handler(int sig __attribute((unused))) { exit_now = 1; } @@ -85,7 +70,7 @@ static void parent_exit_handler(int sig) * * Returns: 0 on success, -1 otherwise */ -static int create_lockfile(char *lockfile) +static int create_lockfile(const char *lockfile) { int fd; struct flock lock; @@ -112,7 +97,8 @@ static int create_lockfile(char *lockfil sprintf(buffer, "%d\n", getpid()); - if(write(fd, buffer, strlen(buffer)) < strlen(buffer)){ + /* FIXME Handle other non-error returns without aborting */ + if (write(fd, buffer, strlen(buffer)) < strlen(buffer)){ close(fd); unlink(lockfile); return -errno; @@ -123,8 +109,9 @@ static int create_lockfile(char *lockfil static void sig_handler(int sig) { + /* FIXME Races - don't touch signal_mask here. */ sigaddset(&signal_mask, sig); - ++signal_received; + signal_received = 1; } static void process_signal(int sig){ @@ -241,6 +228,7 @@ static void daemonize(void) if (create_lockfile(CMIRRORD_PIDFILE)) exit(EXIT_LOCKFILE); + /* FIXME Replace with sigaction. (deprecated) */ signal(SIGINT, &sig_handler); signal(SIGQUIT, &sig_handler); signal(SIGTERM, &sig_handler); diff -rupN LVM2.2.02.58//daemons/cmirrord/cluster.c LVM2.2.02.61//daemons/cmirrord/cluster.c --- LVM2.2.02.58//daemons/cmirrord/cluster.c 2009-09-15 04:27:46.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/cluster.c 2010-01-28 03:58:06.000000000 +0530 @@ -9,31 +9,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include -#include -#include -#include -#include -#include /* These are for OpenAIS CPGs */ -#include -#include -#include -#include -#include +#include "logging.h" +#include "cluster.h" +#include "common.h" +#include "compat.h" +#include "functions.h" +#include "link_mon.h" +#include "local.h" +#include "xlate.h" + #include +#include #include #include - -#include "dm-log-userspace.h" -#include "libdevmapper.h" -#include "functions.h" -#include "local.h" -#include "common.h" -#include "logging.h" -#include "link_mon.h" -#include "cluster.h" +#include +#include /* Open AIS error codes */ #define str_ais_error(x) \ @@ -66,10 +56,6 @@ ((x) == SA_AIS_ERR_NO_SECTIONS) ? "SA_AIS_ERR_NO_SECTIONS" : \ "ais_error_unknown" -#define DM_ULOG_RESPONSE 0x1000 /* in last byte of 32-bit value */ -#define DM_ULOG_CHECKPOINT_READY 21 -#define DM_ULOG_MEMBER_JOIN 22 - #define _RQ_TYPE(x) \ ((x) == DM_ULOG_CHECKPOINT_READY) ? "DM_ULOG_CHECKPOINT_READY": \ ((x) == DM_ULOG_MEMBER_JOIN) ? "DM_ULOG_MEMBER_JOIN": \ @@ -168,6 +154,14 @@ int cluster_send(struct clog_request *rq iov.iov_base = rq; iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size; + rq->u.version[0] = xlate64(CLOG_TFR_VERSION); + rq->u.version[1] = CLOG_TFR_VERSION; + + r = clog_request_to_network(rq); + if (r < 0) + /* FIXME: Better error code for byteswap failure? */ + return -EINVAL; + if (entry->cpg_state != VALID) return -EINVAL; @@ -211,9 +205,9 @@ static struct clog_request *get_matching { struct clog_request *match, *n; - dm_list_iterate_items_safe(match, n, l) + dm_list_iterate_items_gen_safe(match, n, l, u.list) if (match->u_rq.seq == rq->u_rq.seq) { - dm_list_del(&match->list); + dm_list_del(&match->u.list); return match; } @@ -221,7 +215,7 @@ static struct clog_request *get_matching } static char rq_buffer[DM_ULOG_REQUEST_SIZE]; -static int handle_cluster_request(struct clog_cpg *entry, +static int handle_cluster_request(struct clog_cpg *entry __attribute((unused)), struct clog_request *rq, int server) { int r = 0; @@ -298,7 +292,7 @@ static int handle_cluster_response(struc if (dm_list_empty(&entry->working_list)) LOG_ERROR(" [none]"); - dm_list_iterate_items(orig_rq, &entry->working_list) + dm_list_iterate_items_gen(orig_rq, &entry->working_list, u.list) LOG_ERROR(" [%s] %s:%u", SHORT_UUID(orig_rq->u_rq.uuid), _RQ_TYPE(orig_rq->u_rq.request_type), @@ -442,9 +436,9 @@ static int export_checkpoint(struct chec len = snprintf((char *)(name.value), SA_MAX_NAME_LENGTH, "bitmaps_%s_%u", SHORT_UUID(cp->uuid), cp->requester); - name.length = len; + name.length = (SaUint16T)len; - len = strlen(cp->recovering_region) + 1; + len = (int)strlen(cp->recovering_region) + 1; attr.creationFlags = SA_CKPT_WR_ALL_REPLICAS; attr.checkpointSize = cp->bitmap_size * 2 + len; @@ -482,7 +476,7 @@ open_retry: /* * Add section for sync_bits */ - section_id.idLen = snprintf(buf, 32, "sync_bits"); + section_id.idLen = (SaUint16T)snprintf(buf, 32, "sync_bits"); section_id.id = (unsigned char *)buf; section_attr.sectionId = §ion_id; section_attr.expirationTime = SA_TIME_END; @@ -578,7 +572,7 @@ rr_create_retry: } memset(rq, 0, sizeof(*rq)); - dm_list_init(&rq->list); + dm_list_init(&rq->u.list); rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY; rq->originator = cp->requester; /* FIXME: hack to overload meaning of originator */ strncpy(rq->u_rq.uuid, cp->uuid, CPG_MAX_NAME_LENGTH); @@ -611,7 +605,7 @@ static int import_checkpoint(struct clog len = snprintf((char *)(name.value), SA_MAX_NAME_LENGTH, "bitmaps_%s_%u", SHORT_UUID(entry->name.value), my_cluster_id); - name.length = len; + name.length = (SaUint16T)len; open_retry: rv = saCkptCheckpointOpen(ckpt_handle, &name, NULL, @@ -803,8 +797,8 @@ static int resend_requests(struct clog_c entry->resend_requests = 0; - dm_list_iterate_items_safe(rq, n, &entry->working_list) { - dm_list_del(&rq->list); + dm_list_iterate_items_gen_safe(rq, n, &entry->working_list, u.list) { + dm_list_del(&rq->u.list); if (strcmp(entry->name.value, rq->u_rq.uuid)) { LOG_ERROR("[%s] Stray request from another log (%s)", @@ -861,12 +855,12 @@ static int resend_requests(struct clog_c return r; } -static int do_cluster_work(void *data) +static int do_cluster_work(void *data __attribute((unused))) { int r = SA_AIS_OK; - struct clog_cpg *entry; + struct clog_cpg *entry, *tmp; - dm_list_iterate_items(entry, &clog_cpg_list) { + dm_list_iterate_items_safe(entry, tmp, &clog_cpg_list) { r = cpg_dispatch(entry->handle, CPG_DISPATCH_ALL); if (r != SA_AIS_OK) LOG_ERROR("cpg_dispatch failed: %s", str_ais_error(r)); @@ -890,8 +884,8 @@ static int flush_startup_list(struct clo struct clog_request *rq, *n; struct checkpoint_data *new; - dm_list_iterate_items_safe(rq, n, &entry->startup_list) { - dm_list_del(&rq->list); + dm_list_iterate_items_gen_safe(rq, n, &entry->startup_list, u.list) { + dm_list_del(&rq->u.list); if (rq->u_rq.request_type == DM_ULOG_MEMBER_JOIN) { new = prepare_checkpoint(entry, rq->originator); @@ -933,8 +927,8 @@ static int flush_startup_list(struct clo return 0; } -static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gname, - uint32_t nodeid, uint32_t pid, +static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gname __attribute((unused)), + uint32_t nodeid, uint32_t pid __attribute((unused)), void *msg, size_t msg_len) { int i; @@ -945,6 +939,10 @@ static void cpg_message_callback(cpg_han struct clog_request *tmp_rq; struct clog_cpg *match; + if (clog_request_from_network(rq, msg_len) < 0) + /* Error message comes from 'clog_request_from_network' */ + return; + match = find_clog_cpg(handle); if (!match) { LOG_ERROR("Unable to find clog_cpg for cluster message"); @@ -968,8 +966,8 @@ static void cpg_message_callback(cpg_han return; } memcpy(tmp_rq, rq, sizeof(*rq) + rq->u_rq.data_size); - dm_list_init(&tmp_rq->list); - dm_list_add( &match->working_list, &tmp_rq->list); + dm_list_init(&tmp_rq->u.list); + dm_list_add( &match->working_list, &tmp_rq->u.list); } if (rq->u_rq.request_type == DM_ULOG_POSTSUSPEND) { @@ -990,7 +988,7 @@ static void cpg_message_callback(cpg_han SHORT_UUID(rq->u_rq.uuid), nodeid, (dm_list_empty(&match->working_list)) ? " -- working_list empty": ""); - dm_list_iterate_items(tmp_rq, &match->working_list) + dm_list_iterate_items_gen(tmp_rq, &match->working_list, u.list) LOG_COND(log_resend_requests, "[%s] %s/%u", SHORT_UUID(tmp_rq->u_rq.uuid), @@ -1075,8 +1073,8 @@ static void cpg_message_callback(cpg_han memcpy(tmp_rq, rq, sizeof(*rq) + rq->u_rq.data_size); tmp_rq->pit_server = match->lowest_id; - dm_list_init(&tmp_rq->list); - dm_list_add(&match->startup_list, &tmp_rq->list); + dm_list_init(&tmp_rq->u.list); + dm_list_add(&match->startup_list, &tmp_rq->u.list); goto out; } @@ -1159,8 +1157,8 @@ static void cpg_join_callback(struct clo const struct cpg_address *member_list, size_t member_list_entries) { - int i; - int my_pid = getpid(); + unsigned i; + uint32_t my_pid = (uint32_t)getpid(); uint32_t lowest = match->lowest_id; struct clog_request *rq; char dbuf[32]; @@ -1180,7 +1178,7 @@ static void cpg_join_callback(struct clo goto out; memset(dbuf, 0, sizeof(dbuf)); - for (i = 0; i < (member_list_entries-1); i++) + for (i = 0; i < member_list_entries - 1; i++) sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid); sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid); LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]", @@ -1206,8 +1204,8 @@ static void cpg_join_callback(struct clo } rq->u_rq.request_type = DM_ULOG_MEMBER_JOIN; rq->originator = joined->nodeid; - dm_list_init(&rq->list); - dm_list_add(&match->startup_list, &rq->list); + dm_list_init(&rq->u.list); + dm_list_add(&match->startup_list, &rq->u.list); out: /* Find the lowest_id, i.e. the server */ @@ -1238,7 +1236,8 @@ static void cpg_leave_callback(struct cl const struct cpg_address *member_list, size_t member_list_entries) { - int i, j, fd; + unsigned i; + int j, fd; uint32_t lowest = match->lowest_id; struct clog_request *rq, *n; struct checkpoint_data *p_cp, *c_cp; @@ -1256,8 +1255,8 @@ static void cpg_leave_callback(struct cl cluster_postsuspend(match->name.value, match->luid); - dm_list_iterate_items_safe(rq, n, &match->working_list) { - dm_list_del(&rq->list); + dm_list_iterate_items_gen_safe(rq, n, &match->working_list, u.list) { + dm_list_del(&rq->u.list); if (rq->u_rq.request_type == DM_ULOG_POSTSUSPEND) kernel_send(&rq->u_rq); @@ -1286,13 +1285,13 @@ static void cpg_leave_callback(struct cl SHORT_UUID(match->name.value), left->nodeid); free_checkpoint(c_cp); } - dm_list_iterate_items_safe(rq, n, &match->startup_list) { + dm_list_iterate_items_gen_safe(rq, n, &match->startup_list, u.list) { if ((rq->u_rq.request_type == DM_ULOG_MEMBER_JOIN) && (rq->originator == left->nodeid)) { LOG_COND(log_checkpoint, "[%s] Removing pending ckpt from startup list (%u is leaving)", SHORT_UUID(match->name.value), left->nodeid); - dm_list_del(&rq->list); + dm_list_del(&rq->u.list); free(rq); } } @@ -1352,7 +1351,7 @@ static void cpg_leave_callback(struct cl */ i = 1; /* We do not have a DM_ULOG_MEMBER_JOIN entry of our own */ - dm_list_iterate_items(rq, &match->startup_list) + dm_list_iterate_items_gen(rq, &match->startup_list, u.list) if (rq->u_rq.request_type == DM_ULOG_MEMBER_JOIN) i++; @@ -1367,7 +1366,7 @@ static void cpg_leave_callback(struct cl } } -static void cpg_config_callback(cpg_handle_t handle, const struct cpg_name *gname, +static void cpg_config_callback(cpg_handle_t handle, const struct cpg_name *gname __attribute((unused)), const struct cpg_address *member_list, size_t member_list_entries, const struct cpg_address *left_list, @@ -1412,7 +1411,7 @@ cpg_callbacks_t cpg_callbacks = { * * Returns: 1 if checkpoint removed, 0 if no checkpoints, -EXXX on error */ -int remove_checkpoint(struct clog_cpg *entry) +static int remove_checkpoint(struct clog_cpg *entry) { int len; SaNameT name; @@ -1458,7 +1457,7 @@ unlink_retry: int create_cluster_cpg(char *uuid, uint64_t luid) { int r; - int size; + size_t size; struct clog_cpg *new = NULL; struct clog_cpg *tmp; @@ -1482,7 +1481,7 @@ int create_cluster_cpg(char *uuid, uint6 size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ? CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1); strncpy(new->name.value, uuid, size); - new->name.length = size; + new->name.length = (uint32_t)size; new->luid = luid; /* @@ -1526,8 +1525,8 @@ static void abort_startup(struct clog_cp LOG_DBG("[%s] CPG teardown before checkpoint received", SHORT_UUID(del->name.value)); - dm_list_iterate_items_safe(rq, n, &del->startup_list) { - dm_list_del(&rq->list); + dm_list_iterate_items_gen_safe(rq, n, &del->startup_list, u.list) { + dm_list_del(&rq->u.list); LOG_DBG("[%s] Ignoring request from %u: %s", SHORT_UUID(del->name.value), rq->originator, @@ -1640,12 +1639,12 @@ void cluster_debug(void) break; LOG_ERROR(" CKPTs waiting : %d", i); LOG_ERROR(" Working list:"); - dm_list_iterate_items(rq, &entry->working_list) + dm_list_iterate_items_gen(rq, &entry->working_list, u.list) LOG_ERROR(" %s/%u", _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); LOG_ERROR(" Startup list:"); - dm_list_iterate_items(rq, &entry->startup_list) + dm_list_iterate_items_gen(rq, &entry->startup_list, u.list) LOG_ERROR(" %s/%u", _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); diff -rupN LVM2.2.02.58//daemons/cmirrord/cluster.h LVM2.2.02.61//daemons/cmirrord/cluster.h --- LVM2.2.02.58//daemons/cmirrord/cluster.h 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/cluster.h 2010-01-20 08:13:19.000000000 +0530 @@ -9,11 +9,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __CLUSTER_LOG_CLUSTER_DOT_H__ -#define __CLUSTER_LOG_CLUSTER_DOT_H__ +#ifndef _LVM_CLOG_CLUSTER_H +#define _LVM_CLOG_CLUSTER_H -#include "libdevmapper.h" #include "dm-log-userspace.h" +#include "libdevmapper.h" + +#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */ +#define DM_ULOG_CHECKPOINT_READY 21 +#define DM_ULOG_MEMBER_JOIN 22 /* * There is other information in addition to what can @@ -23,7 +27,22 @@ * available. */ struct clog_request { - struct dm_list list; + /* + * If we don't use a union, the structure size will + * vary between 32-bit and 64-bit machines. So, we + * pack two 64-bit version numbers in there to force + * the size of the structure to be the same. + * + * The two version numbers also help us with endian + * issues. The first is always little endian, while + * the second is in native format of the sending + * machine. If the two are equal, there is no need + * to do endian conversions. + */ + union { + uint64_t version[2]; /* LE version and native version */ + struct dm_list list; + } u; /* * 'originator' is the machine from which the requests @@ -54,4 +73,4 @@ int destroy_cluster_cpg(char *uuid); int cluster_send(struct clog_request *rq); -#endif /* __CLUSTER_LOG_CLUSTER_DOT_H__ */ +#endif /* _LVM_CLOG_CLUSTER_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/common.h LVM2.2.02.61//daemons/cmirrord/common.h --- LVM2.2.02.58//daemons/cmirrord/common.h 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/common.h 2010-01-19 02:37:24.000000000 +0530 @@ -9,25 +9,25 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __CLUSTER_LOG_COMMON_DOT_H__ -#define __CLUSTER_LOG_COMMON_DOT_H__ +#ifndef _LVM_CLOG_COMMON_H +#define _LVM_CLOG_COMMON_H /* -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 -*/ - + * If there are problems when forking off to become a daemon, + * the child will exist with one of these codes. This allows + * the parent to know the reason for the failure and print it + * to the launching terminal. + * + * #define EXIT_SUCCESS 0 (from stdlib.h) + * #define EXIT_FAILURE 1 (from stdlib.h) + */ #define EXIT_LOCKFILE 2 - #define EXIT_KERNEL_SOCKET 3 /* Failed netlink socket create */ #define EXIT_KERNEL_BIND 4 #define EXIT_KERNEL_SETSOCKOPT 5 - #define EXIT_CLUSTER_CKPT_INIT 6 /* Failed to init checkpoint */ - #define EXIT_QUEUE_NOMEM 7 - #define DM_ULOG_REQUEST_SIZE 1024 -#endif /* __CLUSTER_LOG_COMMON_DOT_H__ */ +#endif /* _LVM_CLOG_COMMON_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/compat.c LVM2.2.02.61//daemons/cmirrord/compat.c --- LVM2.2.02.58//daemons/cmirrord/compat.c 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/compat.c 2010-01-19 02:37:24.000000000 +0530 @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. All rights reserved. + * + * 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. + */ +#include "logging.h" +#include "cluster.h" +#include "compat.h" +#include "xlate.h" + +#include + +/* + * Older versions of the log daemon communicate with different + * versions of the inter-machine communication structure, which + * varies in size and fields. The older versions append the + * standard upstream version of the structure to every request. + * COMPAT_OFFSET is where the upstream structure starts. + */ +#define COMPAT_OFFSET 256 + +static void v5_data_endian_switch(struct clog_request *rq, int to_network __attribute((unused))) +{ + int i, end; + int64_t *pi64; + uint64_t *pu64; + uint32_t rq_type = rq->u_rq.request_type & ~DM_ULOG_RESPONSE; + + if (rq->u_rq.request_type & DM_ULOG_RESPONSE) { + switch (rq_type) { + case DM_ULOG_CTR: + case DM_ULOG_DTR: + LOG_ERROR("Invalid response type in endian switch"); + exit(EXIT_FAILURE); + + case DM_ULOG_PRESUSPEND: + case DM_ULOG_POSTSUSPEND: + case DM_ULOG_RESUME: + case DM_ULOG_FLUSH: + case DM_ULOG_MARK_REGION: + case DM_ULOG_CLEAR_REGION: + case DM_ULOG_SET_REGION_SYNC: + case DM_ULOG_CHECKPOINT_READY: + case DM_ULOG_MEMBER_JOIN: + case DM_ULOG_STATUS_INFO: + case DM_ULOG_STATUS_TABLE: + /* No outbound data */ + break; + + case DM_ULOG_GET_REGION_SIZE: + case DM_ULOG_GET_SYNC_COUNT: + pu64 = (uint64_t *)rq->u_rq.data; + *pu64 = xlate64(*pu64); + break; + case DM_ULOG_IS_CLEAN: + case DM_ULOG_IN_SYNC: + pi64 = (int64_t *)rq->u_rq.data; + *pi64 = xlate64(*pi64); + break; + case DM_ULOG_GET_RESYNC_WORK: + case DM_ULOG_IS_REMOTE_RECOVERING: + pi64 = (int64_t *)rq->u_rq.data; + pu64 = ((uint64_t *)rq->u_rq.data) + 1; + *pi64 = xlate64(*pi64); + *pu64 = xlate64(*pu64); + break; + default: + LOG_ERROR("Unknown request type, %u", rq_type); + return; + } + } else { + switch (rq_type) { + case DM_ULOG_CTR: + case DM_ULOG_DTR: + LOG_ERROR("Invalid request type in endian switch"); + exit(EXIT_FAILURE); + + case DM_ULOG_PRESUSPEND: + case DM_ULOG_POSTSUSPEND: + case DM_ULOG_RESUME: + case DM_ULOG_GET_REGION_SIZE: + case DM_ULOG_FLUSH: + case DM_ULOG_GET_RESYNC_WORK: + case DM_ULOG_GET_SYNC_COUNT: + case DM_ULOG_STATUS_INFO: + case DM_ULOG_STATUS_TABLE: + case DM_ULOG_CHECKPOINT_READY: + case DM_ULOG_MEMBER_JOIN: + /* No incoming data */ + break; + case DM_ULOG_IS_CLEAN: + case DM_ULOG_IN_SYNC: + case DM_ULOG_IS_REMOTE_RECOVERING: + pu64 = (uint64_t *)rq->u_rq.data; + *pu64 = xlate64(*pu64); + break; + case DM_ULOG_MARK_REGION: + case DM_ULOG_CLEAR_REGION: + end = rq->u_rq.data_size/sizeof(uint64_t); + + pu64 = (uint64_t *)rq->u_rq.data; + for (i = 0; i < end; i++) + pu64[i] = xlate64(pu64[i]); + break; + case DM_ULOG_SET_REGION_SYNC: + pu64 = (uint64_t *)rq->u_rq.data; + pi64 = ((int64_t *)rq->u_rq.data) + 1; + *pu64 = xlate64(*pu64); + *pi64 = xlate64(*pi64); + break; + default: + LOG_ERROR("Unknown request type, %u", rq_type); + exit(EXIT_FAILURE); + } + } +} + +static int v5_endian_to_network(struct clog_request *rq) +{ + int size; + struct dm_ulog_request *u_rq = &rq->u_rq; + + size = sizeof(*rq) + u_rq->data_size; + + u_rq->error = xlate32(u_rq->error); + u_rq->seq = xlate32(u_rq->seq); + u_rq->request_type = xlate32(u_rq->request_type); + u_rq->data_size = xlate64(u_rq->data_size); + + rq->originator = xlate32(rq->originator); + + v5_data_endian_switch(rq, 1); + + return size; +} + +int clog_request_to_network(struct clog_request *rq) +{ + int r; + + /* FIXME: Remove this safety check */ + if (rq->u.version[0] != xlate64(rq->u.version[1])) { + LOG_ERROR("Programmer error: version[0] must be LE"); + exit(EXIT_FAILURE); + } + + /* + * Are we already running in the endian mode we send + * over the wire? + */ + if (rq->u.version[0] == rq->u.version[1]) + return 0; + + r = v5_endian_to_network(rq); + if (r < 0) + return r; + return 0; +} + +static int v5_endian_from_network(struct clog_request *rq) +{ + int size; + struct dm_ulog_request *u_rq = &rq->u_rq; + + u_rq->error = xlate32(u_rq->error); + u_rq->seq = xlate32(u_rq->seq); + u_rq->request_type = xlate32(u_rq->request_type); + u_rq->data_size = xlate64(u_rq->data_size); + + rq->originator = xlate32(rq->originator); + + size = sizeof(*rq) + u_rq->data_size; + + v5_data_endian_switch(rq, 0); + + return size; +} + +int clog_request_from_network(void *data, size_t data_len) +{ + uint64_t *vp = data; + uint64_t version = xlate64(vp[0]); + uint64_t unconverted_version = vp[1]; + struct clog_request *rq = data; + + switch (version) { + case 5: /* Upstream */ + if (version == unconverted_version) + return 0; + break; + case 4: /* RHEL 5.[45] */ + case 3: /* RHEL 5.3 */ + case 2: /* RHEL 5.2 */ + /* FIXME: still need to account for payload */ + if (data_len < (COMPAT_OFFSET + sizeof(*rq))) + return -ENOSPC; + + rq = (struct clog_request *)((char *)data + COMPAT_OFFSET); + break; + default: + LOG_ERROR("Unable to process cluster message: " + "Incompatible version"); + return -EINVAL; + } + + v5_endian_from_network(rq); + return 0; +} diff -rupN LVM2.2.02.58//daemons/cmirrord/compat.h LVM2.2.02.61//daemons/cmirrord/compat.h --- LVM2.2.02.58//daemons/cmirrord/compat.h 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/compat.h 2010-01-19 02:37:24.000000000 +0530 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. All rights reserved. + * + * 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. + */ +#ifndef _LVM_CLOG_COMPAT_H +#define _LVM_CLOG_COMPAT_H + +/* + * The intermachine communication structure version are: + * 0: Unused + * 1: Never in the wild + * 2: RHEL 5.2 + * 3: RHEL 5.3 + * 4: RHEL 5.4, RHEL 5.5 + * 5: RHEL 6, Current Upstream Format + */ +#define CLOG_TFR_VERSION 5 + +int clog_request_to_network(struct clog_request *rq); +int clog_request_from_network(void *data, size_t data_len); + +#endif /* _LVM_CLOG_COMPAT_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/functions.c LVM2.2.02.61//daemons/cmirrord/functions.c --- LVM2.2.02.58//daemons/cmirrord/functions.c 2009-08-28 10:57:09.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/functions.c 2010-01-22 06:13:28.000000000 +0530 @@ -9,27 +9,17 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define _GNU_SOURCE -#define _FILE_OFFSET_BITS 64 +#include "logging.h" +#include "functions.h" -#include -#include -#include -#include -#include #include -#include -#include -#include -//#define __USE_GNU /* for O_DIRECT */ +#include #include +#include +#include +#include #include -#include "libdevmapper.h" -#include "dm-log-userspace.h" -#include "functions.h" -#include "common.h" -#include "cluster.h" -#include "logging.h" +#include #define BYTE_SHIFT 3 @@ -132,18 +122,18 @@ static void log_clear_bit(struct log_c * lc->touched = 1; } -static int find_next_zero_bit(dm_bitset_t bs, int start) +static uint64_t find_next_zero_bit(dm_bitset_t bs, unsigned start) { - while (dm_bit(bs, start++)) - if (start >= (int)bs[0]) - return -1; + for (; dm_bit(bs, start); start++) + if (start >= *bs) + return (uint64_t)-1; - return start - 1; + return start; } static uint64_t count_bits32(dm_bitset_t bs) { - int i, size = ((int)bs[0]/DM_BITS_PER_INT + 1); + unsigned i, size = bs[0]/(unsigned)DM_BITS_PER_INT + 1; unsigned count = 0; for (i = 1; i <= size; i++) @@ -203,7 +193,7 @@ static int rw_log(struct log_c *lc, int { int r; - r = lseek(lc->disk_fd, 0, SEEK_SET); + r = (int)lseek(lc->disk_fd, 0, SEEK_SET); if (r < 0) { LOG_ERROR("[%s] rw_log: lseek failure: %s", SHORT_UUID(lc->uuid), strerror(errno)); @@ -211,6 +201,7 @@ static int rw_log(struct log_c *lc, int } if (do_write) { + /* FIXME Cope with full set of non-error conditions */ r = write(lc->disk_fd, lc->disk_buffer, lc->disk_size); if (r < 0) { LOG_ERROR("[%s] rw_log: write failure: %s", @@ -221,6 +212,7 @@ static int rw_log(struct log_c *lc, int } /* Read */ + /* FIXME Cope with full set of non-error conditions */ r = read(lc->disk_fd, lc->disk_buffer, lc->disk_size); if (r < 0) LOG_ERROR("[%s] rw_log: read failure: %s", @@ -260,7 +252,9 @@ static int read_log(struct log_c *lc) /* Read disk bits into sync_bits */ bitset_size = lc->region_count / 8; bitset_size += (lc->region_count % 8) ? 1 : 0; - memcpy(lc->clean_bits, lc->disk_buffer + 1024, bitset_size); + + /* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */ + memcpy(lc->clean_bits + 1, (char *)lc->disk_buffer + 1024, bitset_size); return 0; } @@ -285,7 +279,9 @@ static int write_log(struct log_c *lc) /* Write disk bits from clean_bits */ bitset_size = lc->region_count / 8; bitset_size += (lc->region_count % 8) ? 1 : 0; - memcpy(lc->disk_buffer + 1024, lc->clean_bits, bitset_size); + + /* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */ + memcpy((char *)lc->disk_buffer + 1024, lc->clean_bits + 1, bitset_size); if (rw_log(lc, 1)) { lc->log_dev_failed = 1; @@ -294,7 +290,8 @@ static int write_log(struct log_c *lc) return 0; } -static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path) +/* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */ +static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path __attribute((unused))) { int r; DIR *dp; @@ -316,6 +313,7 @@ static int find_disk_path(char *major_mi if (r != 2) return -EINVAL; + /* FIXME dm_dir() */ LOG_DBG("Checking /dev/mapper for device %d:%d", major, minor); /* Check /dev/mapper dir */ dp = opendir("/dev/mapper"); @@ -345,17 +343,18 @@ static int find_disk_path(char *major_mi closedir(dp); + /* FIXME Find out why this was here and deal with underlying problem. */ LOG_DBG("Path not found for %d/%d", major, minor); - LOG_DBG("Creating /dev/mapper/%d-%d", major, minor); - sprintf(path_rtn, "/dev/mapper/%d-%d", major, minor); - r = mknod(path_rtn, S_IFBLK | S_IRUSR | S_IWUSR, MKDEV(major, minor)); + return -ENOENT; + // LOG_DBG("Creating /dev/mapper/%d-%d", major, minor); + // sprintf(path_rtn, "/dev/mapper/%d-%d", major, minor); + // r = mknod(path_rtn, S_IFBLK | S_IRUSR | S_IWUSR, MKDEV(major, minor)); /* * If we have to make the path, we unlink it after we open it */ - *unlink_path = 1; - - return r ? -errno : 0; + // *unlink_path = 1; + // return r ? -errno : 0; } static int _clog_ctr(char *uuid, uint64_t luid, @@ -368,7 +367,7 @@ static int _clog_ctr(char *uuid, uint64_ uint64_t region_count; struct log_c *lc = NULL; struct log_c *duplicate; - enum sync sync = DEFAULTSYNC; + enum sync log_sync = DEFAULTSYNC; uint32_t block_on_error = 0; int disk_log = 0; @@ -382,7 +381,7 @@ static int _clog_ctr(char *uuid, uint64_ disk_log = 1; if ((argc < 2) || (argc > 4)) { - LOG_ERROR("Too %s arguments to clustered_disk log type", + LOG_ERROR("Too %s arguments to clustered-disk log type", (argc < 3) ? "few" : "many"); r = -EINVAL; goto fail; @@ -398,7 +397,7 @@ static int _clog_ctr(char *uuid, uint64_ disk_log = 0; if ((argc < 1) || (argc > 3)) { - LOG_ERROR("Too %s arguments to clustered_core log type", + LOG_ERROR("Too %s arguments to clustered-core log type", (argc < 2) ? "few" : "many"); r = -EINVAL; goto fail; @@ -406,7 +405,7 @@ static int _clog_ctr(char *uuid, uint64_ } if (!(region_size = strtoll(argv[disk_log], &p, 0)) || *p) { - LOG_ERROR("Invalid region_size argument to clustered_%s log type", + LOG_ERROR("Invalid region_size argument to clustered-%s log type", (disk_log) ? "disk" : "core"); r = -EINVAL; goto fail; @@ -423,9 +422,9 @@ static int _clog_ctr(char *uuid, uint64_ for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "sync")) - sync = FORCESYNC; + log_sync = FORCESYNC; else if (!strcmp(argv[i], "nosync")) - sync = NOSYNC; + log_sync = NOSYNC; else if (!strcmp(argv[i], "block_on_error")) block_on_error = 1; } @@ -440,7 +439,7 @@ static int _clog_ctr(char *uuid, uint64_ lc->region_size = region_size; lc->region_count = region_count; - lc->sync = sync; + lc->sync = log_sync; lc->block_on_error = block_on_error; lc->sync_search = 0; lc->recovering_region = (uint64_t)-1; @@ -452,7 +451,7 @@ static int _clog_ctr(char *uuid, uint64_ if ((duplicate = get_log(lc->uuid, lc->luid)) || (duplicate = get_pending_log(lc->uuid, lc->luid))) { - LOG_ERROR("[%s/%llu] Log already exists, unable to create.", + LOG_ERROR("[%s/%" PRIu64 "u] Log already exists, unable to create.", SHORT_UUID(lc->uuid), lc->luid); free(lc); return -EINVAL; @@ -473,14 +472,15 @@ static int _clog_ctr(char *uuid, uint64_ r = -ENOMEM; goto fail; } - if (sync == NOSYNC) + if (log_sync == NOSYNC) dm_bit_set_all(lc->sync_bits); - lc->sync_count = (sync == NOSYNC) ? region_count : 0; + lc->sync_count = (log_sync == NOSYNC) ? region_count : 0; + if (disk_log) { page_size = sysconf(_SC_PAGESIZE); - pages = ((int)lc->clean_bits[0])/page_size; - pages += ((int)lc->clean_bits[0])%page_size ? 1 : 0; + pages = *(lc->clean_bits) / page_size; + pages += *(lc->clean_bits) % page_size ? 1 : 0; pages += 1; /* for header */ r = open(disk_path, O_RDWR | O_DIRECT); @@ -572,8 +572,8 @@ static int clog_ctr(struct dm_ulog_reque for (i = 0; i < argc; i++, p = p + strlen(p) + 1) argv[i] = p; - if (strcmp(argv[0], "clustered_disk") && - strcmp(argv[0], "clustered_core")) { + if (strcmp(argv[0], "clustered-disk") && + strcmp(argv[0], "clustered-core")) { LOG_ERROR("Unsupported userspace log type, \"%s\"", argv[0]); free(argv); return -EINVAL; @@ -928,13 +928,13 @@ static int clog_get_region_size(struct d static int clog_is_clean(struct dm_ulog_request *rq) { int64_t *rtn = (int64_t *)rq->data; - uint64_t region = *((uint64_t *)(rq->data)); + uint64_t *region = (uint64_t *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; - *rtn = log_test_bit(lc->clean_bits, region); + *rtn = log_test_bit(lc->clean_bits, *region); rq->data_size = sizeof(*rtn); return 0; @@ -953,7 +953,8 @@ static int clog_is_clean(struct dm_ulog_ static int clog_in_sync(struct dm_ulog_request *rq) { int64_t *rtn = (int64_t *)rq->data; - uint64_t region = *((uint64_t *)(rq->data)); + uint64_t *region_p = (uint64_t *)rq->data; + uint64_t region = *region_p; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) @@ -1224,8 +1225,7 @@ static int clog_get_resync_work(struct d } } - pkg->r = find_next_zero_bit(lc->sync_bits, - lc->sync_search); + pkg->r = find_next_zero_bit(lc->sync_bits, lc->sync_search); if (pkg->r >= lc->region_count) { LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " @@ -1370,11 +1370,11 @@ static int clog_get_sync_count(struct dm return 0; } -static int core_status_info(struct log_c *lc, struct dm_ulog_request *rq) +static int core_status_info(struct log_c *lc __attribute((unused)), struct dm_ulog_request *rq) { char *data = (char *)rq->data; - rq->data_size = sprintf(data, "1 clustered_core"); + rq->data_size = sprintf(data, "1 clustered-core"); return 0; } @@ -1389,7 +1389,7 @@ static int disk_status_info(struct log_c return -errno; } - rq->data_size = sprintf(data, "3 clustered_disk %d:%d %c", + rq->data_size = sprintf(data, "3 clustered-disk %d:%d %c", major(statbuf.st_rdev), minor(statbuf.st_rdev), (lc->log_dev_failed) ? 'D' : 'A'); @@ -1424,7 +1424,7 @@ static int core_status_table(struct log_ { char *data = (char *)rq->data; - rq->data_size = sprintf(data, "clustered_core %u %s%s ", + rq->data_size = sprintf(data, "clustered-core %u %s%s ", lc->region_size, (lc->sync == DEFAULTSYNC) ? "" : (lc->sync == NOSYNC) ? "nosync " : "sync ", @@ -1442,7 +1442,7 @@ static int disk_status_table(struct log_ return -errno; } - rq->data_size = sprintf(data, "clustered_disk %d:%d %u %s%s ", + rq->data_size = sprintf(data, "clustered-disk %d:%d %u %s%s ", major(statbuf.st_rdev), minor(statbuf.st_rdev), lc->region_size, (lc->sync == DEFAULTSYNC) ? "" : @@ -1482,7 +1482,8 @@ static int clog_status_table(struct dm_u */ static int clog_is_remote_recovering(struct dm_ulog_request *rq) { - uint64_t region = *((uint64_t *)(rq->data)); + uint64_t *region_p = (uint64_t *)rq->data; + uint64_t region = *region_p; struct { int64_t is_recovering; uint64_t in_sync_hint; @@ -1639,10 +1640,14 @@ int do_request(struct clog_request *rq, return 0; } -static void print_bits(char *buf, int size, int print) +static void print_bits(dm_bitset_t bs, int print) { - int i; + int i, size; char outbuf[128]; + unsigned char *buf = (unsigned char *)(bs + 1); + + size = (*bs % 8) ? 1 : 0; + size += (*bs / 8); memset(outbuf, 0, sizeof(outbuf)); @@ -1700,7 +1705,7 @@ int push_state(const char *uuid, uint64_ } /* Size in 'int's */ - bitset_size = ((int)lc->clean_bits[0]/DM_BITS_PER_INT) + 1; + bitset_size = (*(lc->clean_bits) / DM_BITS_PER_INT) + 1; /* Size in bytes */ bitset_size *= 4; @@ -1714,14 +1719,18 @@ int push_state(const char *uuid, uint64_ if (!strncmp(which, "sync_bits", 9)) { memcpy(*buf, lc->sync_bits + 1, bitset_size); + LOG_DBG("[%s] storing sync_bits (sync_count = %llu):", SHORT_UUID(uuid), (unsigned long long) count_bits32(lc->sync_bits)); - print_bits(*buf, bitset_size, 0); + + print_bits(lc->sync_bits, 0); } else if (!strncmp(which, "clean_bits", 9)) { memcpy(*buf, lc->clean_bits + 1, bitset_size); + LOG_DBG("[%s] storing clean_bits:", SHORT_UUID(lc->uuid)); - print_bits(*buf, bitset_size, 0); + + print_bits(lc->clean_bits, 0); } return bitset_size; @@ -1754,7 +1763,7 @@ int pull_state(const char *uuid, uint64_ } /* Size in 'int's */ - bitset_size = ((int)lc->clean_bits[0]/DM_BITS_PER_INT) + 1; + bitset_size = (*(lc->clean_bits) /DM_BITS_PER_INT) + 1; /* Size in bytes */ bitset_size *= 4; @@ -1768,15 +1777,19 @@ int pull_state(const char *uuid, uint64_ if (!strncmp(which, "sync_bits", 9)) { lc->resume_override += 1; memcpy(lc->sync_bits + 1, buf, bitset_size); + LOG_DBG("[%s] loading sync_bits (sync_count = %llu):", SHORT_UUID(lc->uuid),(unsigned long long) count_bits32(lc->sync_bits)); - print_bits((char *)lc->sync_bits, bitset_size, 0); + + print_bits(lc->sync_bits, 0); } else if (!strncmp(which, "clean_bits", 9)) { lc->resume_override += 2; memcpy(lc->clean_bits + 1, buf, bitset_size); + LOG_DBG("[%s] loading clean_bits:", SHORT_UUID(lc->uuid)); - print_bits((char *)lc->clean_bits, bitset_size, 0); + + print_bits(lc->sync_bits, 0); } return 0; @@ -1788,9 +1801,10 @@ int log_get_state(struct dm_ulog_request lc = get_log(rq->uuid, rq->luid); if (!lc) + /* FIXME Callers are ignoring this */ return -EINVAL; - return lc->state; + return (int)lc->state; } /* @@ -1819,31 +1833,27 @@ void log_debug(void) dm_list_iterate_items(lc, &log_pending_list) { LOG_ERROR("%s", lc->uuid); LOG_ERROR("sync_bits:"); - print_bits((char *)lc->sync_bits, (int)lc->sync_bits[0], 1); + print_bits(lc->sync_bits, 1); LOG_ERROR("clean_bits:"); - print_bits((char *)lc->clean_bits, (int)lc->sync_bits[0], 1); + print_bits(lc->clean_bits, 1); } dm_list_iterate_items(lc, &log_list) { LOG_ERROR("%s", lc->uuid); - LOG_ERROR(" recoverer : %u", lc->recoverer); - LOG_ERROR(" recovering_region: %llu", - (unsigned long long)lc->recovering_region); + LOG_ERROR(" recoverer : %" PRIu32, lc->recoverer); + LOG_ERROR(" recovering_region: %" PRIu64, lc->recovering_region); LOG_ERROR(" recovery_halted : %s", (lc->recovery_halted) ? "YES" : "NO"); LOG_ERROR("sync_bits:"); - print_bits((char *)lc->sync_bits, (int)lc->sync_bits[0], 1); + print_bits(lc->sync_bits, 1); LOG_ERROR("clean_bits:"); - print_bits((char *)lc->clean_bits, (int)lc->sync_bits[0], 1); + print_bits(lc->clean_bits, 1); LOG_ERROR("Validating %s::", SHORT_UUID(lc->uuid)); r = find_next_zero_bit(lc->sync_bits, 0); - LOG_ERROR(" lc->region_count = %llu", - (unsigned long long)lc->region_count); - LOG_ERROR(" lc->sync_count = %llu", - (unsigned long long)lc->sync_count); - LOG_ERROR(" next zero bit = %llu", - (unsigned long long)r); + LOG_ERROR(" lc->region_count = %" PRIu32, lc->region_count); + LOG_ERROR(" lc->sync_count = %" PRIu64, lc->sync_count); + LOG_ERROR(" next zero bit = %" PRIu64, r); if ((r > lc->region_count) || ((r == lc->region_count) && (lc->sync_count > lc->region_count))) { LOG_ERROR("ADJUSTING SYNC_COUNT"); diff -rupN LVM2.2.02.58//daemons/cmirrord/functions.h LVM2.2.02.61//daemons/cmirrord/functions.h --- LVM2.2.02.58//daemons/cmirrord/functions.h 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/functions.h 2010-01-19 02:37:24.000000000 +0530 @@ -9,8 +9,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __CLOG_FUNCTIONS_DOT_H__ -#define __CLOG_FUNCTIONS_DOT_H__ +#ifndef _LVM_CLOG_FUNCTIONS_H +#define _LVM_CLOG_FUNCTIONS_H #include "dm-log-userspace.h" #include "cluster.h" @@ -31,4 +31,4 @@ int log_get_state(struct dm_ulog_request int log_status(void); void log_debug(void); -#endif /* __CLOG_FUNCTIONS_DOT_H__ */ +#endif /* _LVM_CLOG_FUNCTIONS_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/link_mon.c LVM2.2.02.61//daemons/cmirrord/link_mon.c --- LVM2.2.02.58//daemons/cmirrord/link_mon.c 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/link_mon.c 2010-01-19 21:28:45.000000000 +0530 @@ -9,29 +9,30 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include "logging.h" +#include "link_mon.h" + #include #include - -#include "logging.h" +#include struct link_callback { int fd; - char *name; + const char *name; void *data; int (*callback)(void *data); struct link_callback *next; }; -static int used_pfds = 0; -static int free_pfds = 0; +static unsigned used_pfds = 0; +static unsigned free_pfds = 0; static struct pollfd *pfds = NULL; static struct link_callback *callbacks = NULL; -int links_register(int fd, char *name, int (*callback)(void *data), void *data) +int links_register(int fd, const char *name, int (*callback)(void *data), void *data) { - int i; + unsigned i; struct link_callback *lc; for (i = 0; i < used_pfds; i++) { @@ -71,7 +72,7 @@ int links_register(int fd, char *name, i lc->next = callbacks; callbacks = lc; LOG_DBG("Adding %s/%d", lc->name, lc->fd); - LOG_DBG(" used_pfds = %d, free_pfds = %d", + LOG_DBG(" used_pfds = %u, free_pfds = %u", used_pfds, free_pfds); return 0; @@ -79,7 +80,7 @@ int links_register(int fd, char *name, i int links_unregister(int fd) { - int i; + unsigned i; struct link_callback *p, *c; for (i = 0; i < used_pfds; i++) @@ -93,7 +94,7 @@ int links_unregister(int fd) for (p = NULL, c = callbacks; c; p = c, c = c->next) if (fd == c->fd) { LOG_DBG("Freeing up %s/%d", c->name, c->fd); - LOG_DBG(" used_pfds = %d, free_pfds = %d", + LOG_DBG(" used_pfds = %u, free_pfds = %u", used_pfds, free_pfds); if (p) p->next = c->next; @@ -108,7 +109,8 @@ int links_unregister(int fd) int links_monitor(void) { - int i, r; + unsigned i; + int r; for (i = 0; i < used_pfds; i++) { pfds[i].revents = 0; @@ -133,7 +135,7 @@ int links_monitor(void) int links_issue_callbacks(void) { - int i; + unsigned i; struct link_callback *lc; for (i = 0; i < used_pfds; i++) diff -rupN LVM2.2.02.58//daemons/cmirrord/link_mon.h LVM2.2.02.61//daemons/cmirrord/link_mon.h --- LVM2.2.02.58//daemons/cmirrord/link_mon.h 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/link_mon.h 2010-01-19 02:37:24.000000000 +0530 @@ -9,12 +9,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __LINK_MON_DOT_H__ -#define __LINK_MON_DOT_H__ +#ifndef _LVM_CLOG_LINK_MON_H +#define _LVM_CLOG_LINK_MON_H -int links_register(int fd, char *name, int (*callback)(void *data), void *data); +int links_register(int fd, const char *name, int (*callback)(void *data), void *data); int links_unregister(int fd); int links_monitor(void); int links_issue_callbacks(void); -#endif /* __LINK_MON_DOT_H__ */ +#endif /* _LVM_CLOG_LINK_MON_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/local.c LVM2.2.02.61//daemons/cmirrord/local.c --- LVM2.2.02.58//daemons/cmirrord/local.c 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/local.c 2010-01-19 21:28:45.000000000 +0530 @@ -9,26 +9,20 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include "logging.h" +#include "common.h" +#include "functions.h" +#include "link_mon.h" +#include "local.h" + #include -#include -#include -#include #include -#include #include #include - -#include "dm-log-userspace.h" -#include "functions.h" -#include "cluster.h" -#include "common.h" -#include "logging.h" -#include "link_mon.h" -#include "local.h" +#include #ifndef CN_IDX_DM -#warning Kernel should be at least 2.6.31 +/* Kernel 2.6.31 is required to run this code */ #define CN_IDX_DM 0x7 /* Device Mapper */ #define CN_VAL_DM_USERSPACE_LOG 0x1 #endif @@ -88,9 +82,11 @@ static int kernel_ack(uint32_t seq, int static int kernel_recv(struct clog_request **rq) { int r = 0; - int len; + ssize_t len; + char *foo; struct cn_msg *msg; struct dm_ulog_request *u_rq; + struct nlmsghdr *nlmsg_h; *rq = NULL; memset(recv_buf, 0, sizeof(recv_buf)); @@ -102,16 +98,17 @@ static int kernel_recv(struct clog_reque goto fail; } - switch (((struct nlmsghdr *)recv_buf)->nlmsg_type) { + nlmsg_h = (struct nlmsghdr *)recv_buf; + switch (nlmsg_h->nlmsg_type) { case NLMSG_ERROR: LOG_ERROR("Unable to recv message from kernel: NLMSG_ERROR"); r = -EBADE; goto fail; case NLMSG_DONE: msg = (struct cn_msg *)NLMSG_DATA((struct nlmsghdr *)recv_buf); - len -= sizeof(struct nlmsghdr); + len -= (ssize_t)sizeof(struct nlmsghdr); - if (len < sizeof(struct cn_msg)) { + if (len < (ssize_t)sizeof(struct cn_msg)) { LOG_ERROR("Incomplete request from kernel received"); r = -EBADE; goto fail; @@ -127,10 +124,10 @@ static int kernel_recv(struct clog_reque if (!msg->len) LOG_ERROR("Zero length message received"); - len -= sizeof(struct cn_msg); + len -= (ssize_t)sizeof(struct cn_msg); if (len < msg->len) - LOG_ERROR("len = %d, msg->len = %d", len, msg->len); + LOG_ERROR("len = %zd, msg->len = %" PRIu16, len, msg->len); msg->data[msg->len] = '\0'; /* Cleaner way to ensure this? */ u_rq = (struct dm_ulog_request *)msg->data; @@ -158,13 +155,12 @@ static int kernel_recv(struct clog_reque * beyond what is available to us, but we need only check it * once... perhaps at compile time? */ -// *rq = container_of(u_rq, struct clog_request, u_rq); - *rq = (void *)u_rq - - (sizeof(struct clog_request) - - sizeof(struct dm_ulog_request)); + foo = (char *)u_rq; + foo -= (sizeof(struct clog_request) - sizeof(struct dm_ulog_request)); + *rq = (struct clog_request *) foo; /* Clear the wrapper container fields */ - memset(*rq, 0, (void *)u_rq - (void *)(*rq)); + memset(*rq, 0, (size_t)((char *)u_rq - (char *)(*rq))); break; default: LOG_ERROR("Unknown nlmsg_type"); @@ -178,7 +174,7 @@ fail: return (r == -EAGAIN) ? 0 : r; } -static int kernel_send_helper(void *data, int out_size) +static int kernel_send_helper(void *data, uint16_t out_size) { int r; struct nlmsghdr *nlh; @@ -218,7 +214,7 @@ static int kernel_send_helper(void *data * * Returns: 0 on success, -EXXX on failure */ -static int do_local_work(void *data) +static int do_local_work(void *data __attribute((unused))) { int r; struct clog_request *rq; @@ -331,12 +327,12 @@ static int do_local_work(void *data) int kernel_send(struct dm_ulog_request *u_rq) { int r; - int size; + uint16_t size; if (!u_rq) return -EINVAL; - size = sizeof(struct dm_ulog_request) + u_rq->data_size; + size = (uint16_t)(sizeof(struct dm_ulog_request) + u_rq->data_size); if (!u_rq->data_size && !u_rq->error) { /* An ACK is all that is needed */ @@ -372,7 +368,7 @@ int kernel_send(struct dm_ulog_request * int init_local(void) { int r = 0; - int opt; + unsigned opt; struct sockaddr_nl addr; cn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); diff -rupN LVM2.2.02.58//daemons/cmirrord/local.h LVM2.2.02.61//daemons/cmirrord/local.h --- LVM2.2.02.58//daemons/cmirrord/local.h 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/local.h 2010-01-19 02:37:24.000000000 +0530 @@ -9,12 +9,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __CLUSTER_LOG_LOCAL_DOT_H__ -#define __CLUSTER_LOG_LOCAL_DOT_H__ +#ifndef _LVM_CLOG_LOCAL_H +#define _LVM_CLOG_LOCAL_H int init_local(void); void cleanup_local(void); int kernel_send(struct dm_ulog_request *rq); -#endif /* __CLUSTER_LOG_LOCAL_DOT_H__ */ +#endif /* _LVM_CLOG_LOCAL_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/logging.c LVM2.2.02.61//daemons/cmirrord/logging.c --- LVM2.2.02.58//daemons/cmirrord/logging.c 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/logging.c 2010-01-19 02:37:24.000000000 +0530 @@ -9,10 +9,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include +#include "logging.h" -char *__rq_types_off_by_one[] = { +const char *__rq_types_off_by_one[] = { "DM_ULOG_CTR", "DM_ULOG_DTR", "DM_ULOG_PRESUSPEND", diff -rupN LVM2.2.02.58//daemons/cmirrord/logging.h LVM2.2.02.61//daemons/cmirrord/logging.h --- LVM2.2.02.58//daemons/cmirrord/logging.h 2009-08-13 22:04:07.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/logging.h 2010-01-19 02:37:24.000000000 +0530 @@ -10,16 +10,21 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __CLUSTER_LOG_LOGGING_DOT_H__ -#define __CLUSTER_LOG_LOGGING_DOT_H__ +#ifndef _LVM_CLOG_LOGGING_H +#define _LVM_CLOG_LOGGING_H +#define _GNU_SOURCE +#define _FILE_OFFSET_BITS 64 + +#include #include +#include #include /* SHORT_UUID - print last 8 chars of a string */ #define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x) -extern char *__rq_types_off_by_one[]; +extern const char *__rq_types_off_by_one[]; #define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1] extern int log_tabbing; @@ -69,4 +74,4 @@ extern int log_resend_requests; #define LOG_PRINT(f, arg...) LOG_OUTPUT(LOG_NOTICE, f, ## arg) #define LOG_ERROR(f, arg...) LOG_OUTPUT(LOG_ERR, f, ## arg) -#endif /* __CLUSTER_LOG_LOGGING_DOT_H__ */ +#endif /* _LVM_CLOG_LOGGING_H */ diff -rupN LVM2.2.02.58//daemons/cmirrord/Makefile.in LVM2.2.02.61//daemons/cmirrord/Makefile.in --- LVM2.2.02.58//daemons/cmirrord/Makefile.in 2009-10-05 19:16:01.000000000 +0530 +++ LVM2.2.02.61//daemons/cmirrord/Makefile.in 2010-01-16 01:19:36.000000000 +0530 @@ -21,7 +21,7 @@ CPG_CFLAGS = @CPG_CFLAGS@ SACKPT_LIBS = @SACKPT_LIBS@ SACKPT_CFLAGS = @SACKPT_CFLAGS@ -SOURCES = clogd.c cluster.c functions.c link_mon.c local.c logging.c +SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c TARGETS = cmirrord diff -rupN LVM2.2.02.58//daemons/dmeventd/Makefile.in LVM2.2.02.61//daemons/dmeventd/Makefile.in --- LVM2.2.02.58//daemons/dmeventd/Makefile.in 2009-11-13 18:18:01.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/Makefile.in 2010-01-19 06:40:47.000000000 +0530 @@ -64,8 +64,8 @@ dmeventd: $(LIB_SHARED) $(VERSIONED_SHLI $(CC) $(CFLAGS) $(LDFLAGS) -L. -o $@ dmeventd.o \ $(LVMLIBS) $(LIBS) -rdynamic -dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacedir)/libdevmapper.a - $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacedir) -o $@ \ +dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a + $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \ dmeventd.o $(LVMLIBS) $(LIBS) -rdynamic ifeq ("@PKGCONFIG@", "yes") diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c --- LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c 2010-01-22 03:45:46.000000000 +0530 @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 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 "lib.h" + +#include "lvm2cmd.h" +#include "errors.h" +#include "libdevmapper-event.h" +#include "dmeventd_lvm.h" + +#include +#include + +/* + * register_device() is called first and performs initialisation. + * Only one device may be registered or unregistered at a time. + */ +static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * Number of active registrations. + */ +static int _register_count = 0; +static struct dm_pool *_mem_pool = NULL; +static void *_lvm_handle = NULL; + +/* + * Currently only one event can be processed at a time. + */ +static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* FIXME Remove this: Pass messages back to dmeventd core for processing. */ +static void _temporary_log_fn(int level, + const char *file __attribute((unused)), + int line __attribute((unused)), + int dm_errno __attribute((unused)), + const char *format) +{ + level &= ~_LOG_STDERR; + + if (!strncmp(format, "WARNING: ", 9) && (level < 5)) + syslog(LOG_CRIT, "%s", format); + else + syslog(LOG_DEBUG, "%s", format); +} + +void dmeventd_lvm2_lock(void) +{ + if (pthread_mutex_trylock(&_event_mutex)) { + syslog(LOG_NOTICE, "Another thread is handling an event. Waiting..."); + pthread_mutex_lock(&_event_mutex); + } +} + +void dmeventd_lvm2_unlock(void) +{ + pthread_mutex_unlock(&_event_mutex); +} + +int dmeventd_lvm2_init(void) +{ + int r = 0; + + pthread_mutex_lock(&_register_mutex); + + /* + * 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))) + goto out; + + if (!_lvm_handle) { + lvm2_log_fn(_temporary_log_fn); + if (!(_lvm_handle = lvm2_init())) { + dm_pool_destroy(_mem_pool); + _mem_pool = NULL; + goto out; + } + /* FIXME Temporary: move to dmeventd core */ + lvm2_run(_lvm_handle, "_memlock_inc"); + } + + _register_count++; + r = 1; + +out: + pthread_mutex_unlock(&_register_mutex); + return r; +} + +void dmeventd_lvm2_exit(void) +{ + pthread_mutex_lock(&_register_mutex); + + if (!--_register_count) { + dm_pool_destroy(_mem_pool); + _mem_pool = NULL; + lvm2_run(_lvm_handle, "_memlock_dec"); + lvm2_exit(_lvm_handle); + _lvm_handle = NULL; + } + + pthread_mutex_unlock(&_register_mutex); +} + +struct dm_pool *dmeventd_lvm2_pool(void) +{ + return _mem_pool; +} + +int dmeventd_lvm2_run(const char *cmdline) +{ + return lvm2_run(_lvm_handle, cmdline); +} + diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h --- LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h 2010-01-22 03:45:46.000000000 +0530 @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 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 + */ + +/* + * Wrappers around liblvm2cmd functions for dmeventd plug-ins. + * + * liblvm2cmd is not thread-safe so the locking in this library helps dmeventd + * threads to co-operate in sharing a single instance. + * + * FIXME Either support this properly as a generic liblvm2cmd wrapper or make + * liblvm2cmd thread-safe so this can go away. + */ + +#include "libdevmapper.h" + +#ifndef _DMEVENTD_LVMWRAP_H +#define _DMEVENTD_LVMWRAP_H + +int dmeventd_lvm2_init(void); +void dmeventd_lvm2_exit(void); +int dmeventd_lvm2_run(const char *cmdline); + +void dmeventd_lvm2_lock(void); +void dmeventd_lvm2_unlock(void); + +struct dm_pool *dmeventd_lvm2_pool(void); + +#endif /* _DMEVENTD_LVMWRAP_H */ diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/.exported_symbols LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/.exported_symbols --- LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/.exported_symbols 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/.exported_symbols 2010-01-22 18:08:16.000000000 +0530 @@ -0,0 +1,6 @@ +dmeventd_lvm2_init +dmeventd_lvm2_exit +dmeventd_lvm2_lock +dmeventd_lvm2_unlock +dmeventd_lvm2_pool +dmeventd_lvm2_run diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/Makefile.in LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/Makefile.in --- LVM2.2.02.58//daemons/dmeventd/plugins/lvm2/Makefile.in 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/lvm2/Makefile.in 2010-01-22 03:45:46.000000000 +0530 @@ -0,0 +1,39 @@ +# +# Copyright (C) 2010 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 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@ +top_builddir = @top_builddir@ +VPATH = @srcdir@ + +CLDFLAGS += -L${top_builddir}/tools + +SOURCES = dmeventd_lvm.c + +ifeq ("@LIB_SUFFIX@","dylib") + LIB_SHARED = libdevmapper-event-lvm2.dylib +else + LIB_SHARED = libdevmapper-event-lvm2.so +endif +LIB_VERSION = $(LIB_VERSION_LVM) + +include $(top_builddir)/make.tmpl + +LIBS += -ldevmapper @LIB_PTHREAD@ @LVM2CMD_LIB@ + +install_lvm2: libdevmapper-event-lvm2.$(LIB_SUFFIX) + $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ + $(libdir)/$<.$(LIB_VERSION) + $(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$< + +install: install_lvm2 diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/Makefile.in LVM2.2.02.61//daemons/dmeventd/plugins/Makefile.in --- LVM2.2.02.58//daemons/dmeventd/plugins/Makefile.in 2009-10-03 00:40:33.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/Makefile.in 2010-02-02 19:33:51.000000000 +0530 @@ -17,7 +17,10 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = @srcdir@ -SUBDIRS += mirror snapshot +SUBDIRS += lvm2 mirror snapshot include ../../../make.tmpl +mirror: lvm2 +snapshot: lvm2 + diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/mirror/dmeventd_mirror.c LVM2.2.02.61//daemons/dmeventd/plugins/mirror/dmeventd_mirror.c --- LVM2.2.02.58//daemons/dmeventd/plugins/mirror/dmeventd_mirror.c 2010-01-06 18:56:21.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/mirror/dmeventd_mirror.c 2010-01-22 18:18:58.000000000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2009 Red Hat, Inc. All rights reserved. + * Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -12,18 +12,14 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "lib.h" + #include "lvm2cmd.h" #include "errors.h" +#include "libdevmapper-event.h" +#include "dmeventd_lvm.h" -#include -#include -#include -#include -#include -#include -#include #include -#include #include /* FIXME Replace syslog with multilog */ /* FIXME Missing openlog? */ @@ -34,25 +30,6 @@ #define ME_INSYNC 1 #define ME_FAILURE 2 -/* - * register_device() is called first and performs initialisation. - * Only one device may be registered or unregistered at a time. - */ -static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* - * Number of active registrations. - */ -static int _register_count = 0; - -static struct dm_pool *_mem_pool = NULL; -static void *_lvm_handle = NULL; - -/* - * Currently only one event can be processed at a time. - */ -static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; - static int _process_status_code(const char status_code, const char *dev_name, const char *dev_type, int r) { @@ -155,18 +132,6 @@ out_parse: return ME_IGNORE; } -static void _temporary_log_fn(int level, - const char *file __attribute((unused)), - int line __attribute((unused)), - int dm_errno __attribute((unused)), - const char *format) -{ - if (!strncmp(format, "WARNING: ", 9) && (level < 5)) - syslog(LOG_CRIT, "%s", format); - else - syslog(LOG_DEBUG, "%s", format); -} - static int _remove_failed_devices(const char *device) { int r; @@ -177,7 +142,7 @@ static int _remove_failed_devices(const if (strlen(device) > 200) /* FIXME Use real restriction */ return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */ - if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) { + if (!dm_split_lvm_name(dmeventd_lvm2_pool(), device, &vg, &lv, &layer)) { syslog(LOG_ERR, "Unable to determine VG name from %s", device); return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */ @@ -187,15 +152,13 @@ static int _remove_failed_devices(const if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) { /* 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; /* FIXME Replace with generic error return - reason for failure has already got logged */ } - r = lvm2_run(_lvm_handle, cmd_str); + r = dmeventd_lvm2_run(cmd_str); syslog(LOG_INFO, "Repair of mirrored LV %s/%s %s.", vg, lv, (r == ECMD_PROCESSED) ? "finished successfully" : "failed"); - dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */ return (r == ECMD_PROCESSED) ? 0 : -1; } @@ -209,10 +172,8 @@ void process_event(struct dm_task *dmt, char *params; const char *device = dm_task_get_name(dmt); - if (pthread_mutex_trylock(&_event_mutex)) { - syslog(LOG_NOTICE, "Another thread is handling an event. Waiting..."); - pthread_mutex_lock(&_event_mutex); - } + dmeventd_lvm2_lock(); + do { next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); @@ -255,7 +216,7 @@ void process_event(struct dm_task *dmt, } } while (next); - pthread_mutex_unlock(&_event_mutex); + dmeventd_lvm2_unlock(); } int register_device(const char *device, @@ -264,37 +225,8 @@ int register_device(const char *device, int minor __attribute((unused)), void **unused __attribute((unused))) { - int r = 0; - - pthread_mutex_lock(&_register_mutex); - - /* - * 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))) - goto out; - - if (!_lvm_handle) { - lvm2_log_fn(_temporary_log_fn); - if (!(_lvm_handle = lvm2_init())) { - dm_pool_destroy(_mem_pool); - _mem_pool = NULL; - goto out; - } - lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS); - /* FIXME Temporary: move to dmeventd core */ - lvm2_run(_lvm_handle, "_memlock_inc"); - } - - syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device); - - _register_count++; - r = 1; - -out: - pthread_mutex_unlock(&_register_mutex); - + int r = dmeventd_lvm2_init(); + syslog(LOG_INFO, "Monitoring mirror device %s for events", device); return r; } @@ -304,20 +236,8 @@ int unregister_device(const char *device int minor __attribute((unused)), void **unused __attribute((unused))) { - pthread_mutex_lock(&_register_mutex); - syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n", device); - - if (!--_register_count) { - dm_pool_destroy(_mem_pool); - _mem_pool = NULL; - lvm2_run(_lvm_handle, "_memlock_dec"); - lvm2_exit(_lvm_handle); - _lvm_handle = NULL; - } - - pthread_mutex_unlock(&_register_mutex); - + dmeventd_lvm2_exit(); return 1; } diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/mirror/Makefile.in LVM2.2.02.61//daemons/dmeventd/plugins/mirror/Makefile.in --- LVM2.2.02.58//daemons/dmeventd/plugins/mirror/Makefile.in 2009-10-09 21:34:54.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/mirror/Makefile.in 2010-02-02 19:39:18.000000000 +0530 @@ -1,6 +1,6 @@ # # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -# Copyright (C) 2004-2005, 2008 Red Hat, Inc. All rights reserved. +# Copyright (C) 2004-2005, 2008-2010 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # @@ -17,8 +17,8 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = @srcdir@ -INCLUDES += -I${top_srcdir}/tools -CLDFLAGS += -L${top_builddir}/tools +INCLUDES += -I${top_srcdir}/tools -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 +CLDFLAGS += -L${top_builddir}/tools -L${top_builddir}/daemons/dmeventd/plugins/lvm2 SOURCES = dmeventd_mirror.c @@ -32,11 +32,10 @@ LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl -LIBS += -ldevmapper @LIB_PTHREAD@ @LVM2CMD_LIB@ +LIBS += -ldevmapper @LIB_PTHREAD@ @LVM2CMD_LIB@ -ldevmapper-event-lvm2 install_lvm2: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX) $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ - $(libdir)/$<.$(LIB_VERSION) - $(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$< + $(libdir)/$< install: install_lvm2 diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c LVM2.2.02.61//daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c --- LVM2.2.02.58//daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c 2009-09-17 16:07:24.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c 2010-02-15 18:25:20.000000000 +0530 @@ -12,19 +12,16 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "libdevmapper.h" -#include "libdevmapper-event.h" +#include "lib.h" + #include "lvm2cmd.h" +#include "errors.h" +#include "libdevmapper-event.h" +#include "dmeventd_lvm.h" + #include "lvm-string.h" -#include -#include -#include -#include -#include #include -#include - #include /* FIXME Replace syslog with multilog */ /* FIXME Missing openlog? */ @@ -33,42 +30,15 @@ /* Further warnings at 85%, 90% and 95% fullness. */ #define WARNING_STEP 5 -static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* - * Number of active registrations. - */ -static int _register_count = 0; - -static struct dm_pool *_mem_pool = NULL; -static void *_lvm_handle = NULL; - struct snap_status { int invalid; int used; int max; }; -/* - * Currently only one event can be processed at a time. - */ -static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void _temporary_log_fn(int level, - const char *file __attribute((unused)), - int line __attribute((unused)), - int dm_errno __attribute((unused)), - const char *format) -{ - if (!strncmp(format, "WARNING: ", 9) && (level < 5)) - syslog(LOG_CRIT, "%s", format); - else - syslog(LOG_DEBUG, "%s", format); -} - /* FIXME possibly reconcile this with target_percent when we gain access to regular LVM library here. */ -static void _parse_snapshot_params(char *params, struct snap_status *stat) +static void _parse_snapshot_params(char *params, struct snap_status *status) { char *p; /* @@ -76,10 +46,10 @@ static void _parse_snapshot_params(char * Invalid -- snapshot invalidated * Unknown -- status unknown */ - stat->used = stat->max = 0; + status->used = status->max = 0; if (!strncmp(params, "Invalid", 7)) { - stat->invalid = 1; + status->invalid = 1; return; } @@ -96,8 +66,8 @@ static void _parse_snapshot_params(char *p = '\0'; p++; - stat->used = atoi(params); - stat->max = atoi(p); + status->used = atoi(params); + status->max = atoi(p); } void process_event(struct dm_task *dmt, @@ -108,7 +78,7 @@ void process_event(struct dm_task *dmt, uint64_t start, length; char *target_type = NULL; char *params; - struct snap_status stat = { 0 }; + struct snap_status status = { 0 }; const char *device = dm_task_get_name(dmt); int percent, *percent_warning = (int*)private; @@ -116,34 +86,31 @@ void process_event(struct dm_task *dmt, if (!*percent_warning) return; - if (pthread_mutex_trylock(&_event_mutex)) { - syslog(LOG_NOTICE, "Another thread is handling an event. Waiting..."); - pthread_mutex_lock(&_event_mutex); - } + dmeventd_lvm2_lock(); dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); if (!target_type) goto out; - _parse_snapshot_params(params, &stat); + _parse_snapshot_params(params, &status); /* * If the snapshot has been invalidated or we failed to parse * the status string. Report the full status string to syslog. */ - if (stat.invalid || !stat.max) { + if (status.invalid || !status.max) { syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params); *percent_warning = 0; goto out; } - percent = 100 * stat.used / stat.max; + percent = 100 * status.used / status.max; if (percent >= *percent_warning) { syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent); /* Print warning on the next multiple of WARNING_STEP. */ *percent_warning = (percent / WARNING_STEP) * WARNING_STEP + WARNING_STEP; } out: - pthread_mutex_unlock(&_event_mutex); + dmeventd_lvm2_unlock(); } int register_device(const char *device, @@ -152,40 +119,12 @@ int register_device(const char *device, int minor __attribute((unused)), void **private) { - int r = 0; int *percent_warning = (int*)private; - - pthread_mutex_lock(&_register_mutex); - - /* - * 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("snapshot_dso", 1024))) - goto out; + int r = dmeventd_lvm2_init(); *percent_warning = WARNING_THRESH; /* Print warning if snapshot is full */ - if (!_lvm_handle) { - lvm2_log_fn(_temporary_log_fn); - if (!(_lvm_handle = lvm2_init())) { - dm_pool_destroy(_mem_pool); - _mem_pool = NULL; - goto out; - } - lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS); - /* FIXME Temporary: move to dmeventd core */ - lvm2_run(_lvm_handle, "_memlock_inc"); - } - syslog(LOG_INFO, "Monitoring snapshot %s\n", device); - - _register_count++; - r = 1; - -out: - pthread_mutex_unlock(&_register_mutex); - return r; } @@ -195,20 +134,8 @@ int unregister_device(const char *device int minor __attribute((unused)), void **unused __attribute((unused))) { - pthread_mutex_lock(&_register_mutex); - syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device); - - if (!--_register_count) { - dm_pool_destroy(_mem_pool); - _mem_pool = NULL; - lvm2_run(_lvm_handle, "_memlock_dec"); - lvm2_exit(_lvm_handle); - _lvm_handle = NULL; - } - - pthread_mutex_unlock(&_register_mutex); - + dmeventd_lvm2_exit(); return 1; } diff -rupN LVM2.2.02.58//daemons/dmeventd/plugins/snapshot/Makefile.in LVM2.2.02.61//daemons/dmeventd/plugins/snapshot/Makefile.in --- LVM2.2.02.58//daemons/dmeventd/plugins/snapshot/Makefile.in 2009-10-09 21:34:54.000000000 +0530 +++ LVM2.2.02.61//daemons/dmeventd/plugins/snapshot/Makefile.in 2010-02-02 19:39:18.000000000 +0530 @@ -1,6 +1,6 @@ # # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -# Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. +# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. # # This file is part of the LVM2. # @@ -17,8 +17,8 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = @srcdir@ -INCLUDES += -I${top_srcdir}/tools -CLDFLAGS += -L${top_builddir}/tools +INCLUDES += -I${top_srcdir}/tools -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 +CLDFLAGS += -L${top_builddir}/tools -L${top_builddir}/daemons/dmeventd/plugins/lvm2 SOURCES = dmeventd_snapshot.c @@ -32,11 +32,10 @@ LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl -LIBS += -ldevmapper @LIB_PTHREAD@ @LVM2CMD_LIB@ +LIBS += -ldevmapper @LIB_PTHREAD@ @LVM2CMD_LIB@ -ldevmapper-event-lvm2 install_lvm2: libdevmapper-event-lvm2snapshot.$(LIB_SUFFIX) $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ - $(libdir)/$<.$(LIB_VERSION) - $(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$< + $(libdir)/$< install: install_lvm2 diff -rupN LVM2.2.02.58//include/.symlinks.in LVM2.2.02.61//include/.symlinks.in --- LVM2.2.02.58//include/.symlinks.in 2009-10-03 00:40:34.000000000 +0530 +++ LVM2.2.02.61//include/.symlinks.in 2010-01-22 03:45:46.000000000 +0530 @@ -59,3 +59,4 @@ @top_srcdir@/libdm/misc/dmlib.h @top_srcdir@/libdm/misc/kdev_t.h @top_srcdir@/po/pogen.h +@top_srcdir@/tools/lvm2cmd.h diff -rupN LVM2.2.02.58//lib/activate/activate.c LVM2.2.02.61//lib/activate/activate.c --- LVM2.2.02.58//lib/activate/activate.c 2010-01-13 07:25:43.000000000 +0530 +++ LVM2.2.02.61//lib/activate/activate.c 2010-01-27 18:53:57.000000000 +0530 @@ -492,7 +492,7 @@ int lv_info_by_lvid(struct cmd_context * if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) return 0; - r = _lv_info(cmd, lv, 0, info, with_open_count, with_read_ahead, 0); + r = _lv_info(cmd, lv, 0, info, with_open_count, with_read_ahead, 1); vg_release(lv->vg); return r; diff -rupN LVM2.2.02.58//lib/activate/dev_manager.c LVM2.2.02.61//lib/activate/dev_manager.c --- LVM2.2.02.58//lib/activate/dev_manager.c 2010-01-13 07:25:44.000000000 +0530 +++ LVM2.2.02.61//lib/activate/dev_manager.c 2010-02-10 20:08:24.000000000 +0530 @@ -209,14 +209,16 @@ static int _info(const char *name, const int with_open_count, int with_read_ahead, struct dm_info *info, uint32_t *read_ahead) { + int r = 0; + if (!mknodes && dlid && *dlid) { - if (_info_run(NULL, dlid, info, read_ahead, 0, with_open_count, - with_read_ahead, 0, 0) && + if ((r = _info_run(NULL, dlid, info, read_ahead, 0, with_open_count, + with_read_ahead, 0, 0)) && info->exists) return 1; - else if (_info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info, + else if ((r = _info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info, read_ahead, 0, with_open_count, - with_read_ahead, 0, 0) && + with_read_ahead, 0, 0)) && info->exists) return 1; } @@ -225,7 +227,7 @@ static int _info(const char *name, const return _info_run(name, NULL, info, read_ahead, mknodes, with_open_count, with_read_ahead, 0, 0); - return 0; + return r; } static int _info_by_dev(uint32_t major, uint32_t minor, struct dm_info *info) @@ -249,6 +251,34 @@ int dev_manager_info(struct dm_pool *mem info, read_ahead); } +static const struct dm_info *_cached_info(struct dm_pool *mem, + const struct logical_volume *lv, + struct dm_tree *dtree) +{ + const char *dlid; + struct dm_tree_node *dnode; + const struct dm_info *dinfo; + + if (!(dlid = _build_dlid(mem, lv->lvid.s, NULL))) { + log_error("dlid build failed for %s", lv->name); + return NULL; + } + + /* An activating merging origin won't have a node in the tree yet */ + if (!(dnode = dm_tree_find_node_by_uuid(dtree, dlid))) + return NULL; + + if (!(dinfo = dm_tree_node_get_info(dnode))) { + log_error("failed to get info from tree node for %s", lv->name); + return NULL; + } + + if (!dinfo->exists) + return NULL; + + return dinfo; +} + /* FIXME Interface must cope with multiple targets */ static int _status_run(const char *name, const char *uuid, unsigned long long *s, unsigned long long *l, @@ -362,7 +392,7 @@ static int _lv_has_target_type(struct de &type, ¶ms); if (type && strncmp(type, target_type, strlen(target_type)) == 0) { - if (info.live_table && !info.inactive_table) + if (info.live_table) r = 1; break; } @@ -391,9 +421,9 @@ static percent_range_t _combine_percent_ static int _percent_run(struct dev_manager *dm, const char *name, const char *dlid, const char *target_type, int wait, - struct logical_volume *lv, float *percent, + const struct logical_volume *lv, float *percent, percent_range_t *overall_percent_range, - uint32_t *event_nr) + uint32_t *event_nr, int fail_if_percent_unsupported) { int r = 0; struct dm_task *dmt; @@ -402,7 +432,7 @@ static int _percent_run(struct dev_manag uint64_t start, length; char *type = NULL; char *params = NULL; - struct dm_list *segh = &lv->segments; + const struct dm_list *segh = &lv->segments; struct lv_segment *seg = NULL; struct segment_type *segtype; percent_range_t percent_range = 0, combined_percent_range = 0; @@ -441,18 +471,19 @@ static int _percent_run(struct dev_manag seg = dm_list_item(segh, struct lv_segment); } - /* - * If target status doesn't have 'params' or 'type' is not in the same - * target base class as 'target_type' (e.g. snapshot*, mirror*) skip it - * - allows the situation when 'type' is "snapshot-merge" and - * 'target_type' is "snapshot" - */ - if (!type || !params || strncmp(type, target_type, strlen(target_type))) + if (!type || !params) continue; if (!(segtype = get_segtype_from_string(dm->cmd, target_type))) continue; + if (strcmp(type, target_type)) { + /* If kernel's type isn't an exact match is it compatible? */ + if (!segtype->ops->target_status_compatible || + !segtype->ops->target_status_compatible(type)) + continue; + } + if (segtype->ops->target_percent && !segtype->ops->target_percent(&dm->target_state, &percent_range, dm->mem, @@ -481,9 +512,13 @@ static int _percent_run(struct dev_manag *overall_percent_range = combined_percent_range; } else { *percent = 100; - if (first_time) + if (first_time) { + /* above ->target_percent() was not executed! */ + /* FIXME why return PERCENT_100 et. al. in this case? */ *overall_percent_range = PERCENT_100; - else + if (fail_if_percent_unsupported) + goto_out; + } else *overall_percent_range = combined_percent_range; } @@ -497,21 +532,25 @@ static int _percent_run(struct dev_manag static int _percent(struct dev_manager *dm, const char *name, const char *dlid, const char *target_type, int wait, - struct logical_volume *lv, float *percent, - percent_range_t *overall_percent_range, uint32_t *event_nr) + const struct logical_volume *lv, float *percent, + percent_range_t *overall_percent_range, uint32_t *event_nr, + int fail_if_percent_unsupported) { if (dlid && *dlid) { if (_percent_run(dm, NULL, dlid, target_type, wait, lv, percent, - overall_percent_range, event_nr)) + overall_percent_range, event_nr, + fail_if_percent_unsupported)) return 1; else if (_percent_run(dm, NULL, dlid + sizeof(UUID_PREFIX) - 1, target_type, wait, lv, percent, - overall_percent_range, event_nr)) + overall_percent_range, event_nr, + fail_if_percent_unsupported)) return 1; } if (name && _percent_run(dm, name, NULL, target_type, wait, lv, percent, - overall_percent_range, event_nr)) + overall_percent_range, event_nr, + fail_if_percent_unsupported)) return 1; return 0; @@ -570,6 +609,22 @@ int dev_manager_snapshot_percent(struct { char *name; const char *dlid; + int fail_if_percent_unsupported = 0; + + if (lv_is_merging_origin(lv)) { + /* + * Set 'fail_if_percent_unsupported', otherwise passing + * unsupported LV types to _percent will lead to a default + * successful return with percent_range as PERCENT_100. + * - For a merging origin, this will result in a polldaemon + * that runs infinitely (because completion is PERCENT_0) + * - We unfortunately don't yet _know_ if a snapshot-merge + * target is active (activation is deferred if dev is open); + * so we can't short-circuit origin devices based purely on + * existing LVM LV attributes. + */ + fail_if_percent_unsupported = 1; + } /* * Build a name for the top layer. @@ -585,7 +640,7 @@ int dev_manager_snapshot_percent(struct */ log_debug("Getting device status percentage for %s", name); if (!(_percent(dm, name, dlid, "snapshot", 0, NULL, percent, - percent_range, NULL))) + percent_range, NULL, fail_if_percent_unsupported))) return_0; /* FIXME dm_pool_free ? */ @@ -597,7 +652,7 @@ int dev_manager_snapshot_percent(struct /* FIXME Merge with snapshot_percent, auto-detecting target type */ /* FIXME Cope with more than one target */ int dev_manager_mirror_percent(struct dev_manager *dm, - struct logical_volume *lv, int wait, + const struct logical_volume *lv, int wait, float *percent, percent_range_t *percent_range, uint32_t *event_nr) { @@ -620,7 +675,7 @@ int dev_manager_mirror_percent(struct de log_debug("Getting device mirror status percentage for %s", name); if (!(_percent(dm, name, dlid, "mirror", wait, lv, percent, - percent_range, event_nr))) + percent_range, event_nr, 0))) return_0; return 1; @@ -1051,7 +1106,7 @@ static int _add_segment_to_dtree(struct return_0; /* If this is a snapshot origin, add real LV */ - /* If this is a snapshot origin w/ merging snapshot, add cow and real LV */ + /* If this is a snapshot origin + merging snapshot, add cow + real LV */ if (lv_is_origin(seg->lv) && !layer) { if (vg_is_clustered(seg->lv->vg)) { log_error("Clustered snapshots are not yet supported"); @@ -1110,25 +1165,28 @@ static int _add_new_lv_to_dtree(struct d struct lv_segment *seg; struct lv_layer *lvlayer; struct dm_tree_node *dnode; - struct dm_info dinfo; + const struct dm_info *dinfo; char *name, *dlid, *lv_name; uint32_t max_stripe_size = UINT32_C(0); uint32_t read_ahead = lv->read_ahead; uint32_t read_ahead_flags = UINT32_C(0); uint16_t udev_flags = 0; + /* FIXME Seek a simpler way to lay out the snapshot-merge tree. */ + if (lv_is_origin(lv) && lv_is_merging_origin(lv) && !layer) { /* * Clear merge attributes if merge isn't currently possible: * either origin or merging snapshot are open - * - must refresh info's open_count, so using the tree's - * existing nodes' info isn't an option - * - but use "snapshot-merge" if it is already being used + * - but use "snapshot-merge" if it is already in use + * - open_count is always retrieved (as of dm-ioctl 4.7.0) + * so just use the tree's existing nodes' info */ - if ((dev_manager_info(dm->mem, NULL, lv, - 0, 1, 0, &dinfo, NULL) && dinfo.open_count) || - (dev_manager_info(dm->mem, NULL, find_merging_cow(lv)->cow, - 0, 1, 0, &dinfo, NULL) && dinfo.open_count)) { + if (((dinfo = _cached_info(dm->mem, lv, + dtree)) && dinfo->open_count) || + ((dinfo = _cached_info(dm->mem, find_merging_cow(lv)->cow, + dtree)) && dinfo->open_count)) { + /* FIXME Is there anything simpler to check for instead? */ if (!_lv_has_target_type(dm, lv, NULL, "snapshot-merge")) clear_snapshot_merge(lv); } diff -rupN LVM2.2.02.58//lib/activate/dev_manager.h LVM2.2.02.61//lib/activate/dev_manager.h --- LVM2.2.02.58//lib/activate/dev_manager.h 2009-10-01 06:05:29.000000000 +0530 +++ LVM2.2.02.61//lib/activate/dev_manager.h 2010-01-16 04:28:25.000000000 +0530 @@ -49,7 +49,7 @@ int dev_manager_snapshot_percent(struct float *percent, percent_range_t *percent_range); int dev_manager_mirror_percent(struct dev_manager *dm, - struct logical_volume *lv, int wait, + const struct logical_volume *lv, int wait, float *percent, percent_range_t *percent_range, uint32_t *event_nr); int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv, diff -rupN LVM2.2.02.58//lib/cache/lvmcache.c LVM2.2.02.61//lib/cache/lvmcache.c --- LVM2.2.02.58//lib/cache/lvmcache.c 2010-01-12 00:42:25.000000000 +0530 +++ LVM2.2.02.61//lib/cache/lvmcache.c 2010-02-03 19:38:39.000000000 +0530 @@ -623,7 +623,8 @@ struct volume_group *lvmcache_get_vg(con return vg; } -struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan) +struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan, + int include_internal) { struct dm_list *vgids; struct lvmcache_vginfo *vginfo; @@ -636,6 +637,9 @@ struct dm_list *lvmcache_get_vgids(struc } dm_list_iterate_items(vginfo, &_vginfos) { + if (!include_internal && is_orphan_vg(vginfo->vgname)) + continue; + if (!str_list_add(cmd->mem, vgids, dm_pool_strdup(cmd->mem, vginfo->vgid))) { log_error("strlist allocation failed"); @@ -646,7 +650,8 @@ struct dm_list *lvmcache_get_vgids(struc return vgids; } -struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan) +struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan, + int include_internal) { struct dm_list *vgnames; struct lvmcache_vginfo *vginfo; @@ -659,6 +664,9 @@ struct dm_list *lvmcache_get_vgnames(str } dm_list_iterate_items(vginfo, &_vginfos) { + if (!include_internal && is_orphan_vg(vginfo->vgname)) + continue; + if (!str_list_add(cmd->mem, vgnames, dm_pool_strdup(cmd->mem, vginfo->vgname))) { log_errno(ENOMEM, "strlist allocation failed"); diff -rupN LVM2.2.02.58//lib/cache/lvmcache.h LVM2.2.02.61//lib/cache/lvmcache.h --- LVM2.2.02.58//lib/cache/lvmcache.h 2010-01-05 21:36:43.000000000 +0530 +++ LVM2.2.02.61//lib/cache/lvmcache.h 2010-02-03 19:38:39.000000000 +0530 @@ -98,12 +98,16 @@ int vgs_locked(void); int vgname_is_locked(const char *vgname); /* Returns list of struct str_lists containing pool-allocated copy of vgnames */ -/* Set full_scan to 1 to reread every filtered device label */ -struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan); +/* Set full_scan to 1 to reread every filtered device label. If include_internal + * is not set, return only proper vg names. */ +struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan, + int include_internal); /* Returns list of struct str_lists containing pool-allocated copy of vgids */ -/* Set full_scan to 1 to reread every filtered device label */ -struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan); +/* Set full_scan to 1 to reread every filtered device label. If include_internal + * is not set, return only proper vg ids. */ +struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan, + int include_internal); /* Returns list of struct str_lists containing pool-allocated copy of pvids */ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname, diff -rupN LVM2.2.02.58//lib/commands/toolcontext.c LVM2.2.02.61//lib/commands/toolcontext.c --- LVM2.2.02.58//lib/commands/toolcontext.c 2010-01-08 01:24:21.000000000 +0530 +++ LVM2.2.02.61//lib/commands/toolcontext.c 2010-01-19 18:55:00.000000000 +0530 @@ -1231,12 +1231,21 @@ skip_dlclose: int refresh_filters(struct cmd_context *cmd) { + int r, saved_ignore_suspended_devices = ignore_suspended_devices(); + if (cmd->filter) { cmd->filter->destroy(cmd->filter); cmd->filter = NULL; } - return _init_filters(cmd, 0); + r = _init_filters(cmd, 0); + + /* + * During repair code must not reset suspended flag. + */ + init_ignore_suspended_devices(saved_ignore_suspended_devices); + + return r; } int refresh_toolcontext(struct cmd_context *cmd) diff -rupN LVM2.2.02.58//lib/format_text/format-text.c LVM2.2.02.61//lib/format_text/format-text.c --- LVM2.2.02.58//lib/format_text/format-text.c 2009-12-11 18:46:38.000000000 +0530 +++ LVM2.2.02.61//lib/format_text/format-text.c 2010-02-16 05:23:15.000000000 +0530 @@ -1548,15 +1548,44 @@ static int _populate_pv_fields(struct lv return 1; } +/* + * Copy constructor for a metadata_area. + */ +static struct metadata_area *_mda_copy(struct dm_pool *mem, + struct metadata_area *mda) +{ + struct metadata_area *mda_new; + struct mda_context *mdac, *mdac_new; + + if (!(mda_new = dm_pool_alloc(mem, sizeof(*mda_new)))) { + log_error("metadata_area allocation failed"); + return NULL; + } + /* FIXME: Should have a per-format constructor here */ + mdac = (struct mda_context *) mda->metadata_locn; + if (!(mdac_new = dm_pool_alloc(mem, sizeof(*mdac_new)))) { + log_error("mda_context allocation failed"); + dm_pool_free(mem, mda_new); + return NULL; + } + memcpy(mda_new, mda, sizeof(*mda)); + memcpy(mdac_new, mdac, sizeof(*mdac)); + mda_new->metadata_locn = mdac_new; + + /* FIXME mda 'list' left invalid here */ + + return mda_new; +} + + static int _text_pv_read(const struct format_type *fmt, const char *pv_name, struct physical_volume *pv, struct dm_list *mdas, int scan_label_only) { + struct metadata_area *mda, *mda_new; struct label *label; struct device *dev; struct lvmcache_info *info; - struct metadata_area *mda, *mda_new; - struct mda_context *mdac, *mdac_new; if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) return_0; @@ -1573,18 +1602,9 @@ static int _text_pv_read(const struct fo /* Add copy of mdas to supplied list */ dm_list_iterate_items(mda, &info->mdas) { - mdac = (struct mda_context *) mda->metadata_locn; - if (!(mda_new = dm_pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) { - log_error("metadata_area allocation failed"); - return 0; - } - if (!(mdac_new = dm_pool_alloc(fmt->cmd->mem, sizeof(*mdac_new)))) { - log_error("metadata_area allocation failed"); + mda_new = _mda_copy(fmt->cmd->mem, mda); + if (!mda_new) return 0; - } - memcpy(mda_new, mda, sizeof(*mda)); - memcpy(mdac_new, mdac, sizeof(*mdac)); - mda_new->metadata_locn = mdac_new; dm_list_add(mdas, &mda_new->list); } @@ -1672,7 +1692,7 @@ static int _text_pv_setup(const struct f struct physical_volume *pv, struct volume_group *vg) { struct metadata_area *mda, *mda_new, *mda2; - struct mda_context *mdac, *mdac_new, *mdac2; + struct mda_context *mdac, *mdac2; struct dm_list *pvmdas; struct lvmcache_info *info; int found; @@ -1718,18 +1738,11 @@ static int _text_pv_setup(const struct f if (found) continue; - if (!(mda_new = dm_pool_alloc(fmt->cmd->mem, - sizeof(*mda_new)))) + mda_new = _mda_copy(fmt->cmd->mem, mda); + if (!mda_new) return_0; - - if (!(mdac_new = dm_pool_alloc(fmt->cmd->mem, - sizeof(*mdac_new)))) - return_0; - /* FIXME multiple dev_areas inside area */ - memcpy(mda_new, mda, sizeof(*mda)); - memcpy(mdac_new, mdac, sizeof(*mdac)); - mda_new->metadata_locn = mdac_new; dm_list_add(mdas, &mda_new->list); + /* FIXME multiple dev_areas inside area */ } } @@ -1815,7 +1828,7 @@ static struct format_instance *_text_cre struct format_instance *fid; struct text_fid_context *fidtc; struct metadata_area *mda, *mda_new; - struct mda_context *mdac, *mdac_new; + struct mda_context *mdac; struct dir_list *dl; struct raw_list *rl; struct dm_list *dir_list, *raw_list, *mdas; @@ -1892,21 +1905,10 @@ static struct format_instance *_text_cre dm_list_iterate_items(info, &vginfo->infos) { mdas = &info->mdas; dm_list_iterate_items(mda, mdas) { - mdac = - (struct mda_context *) mda->metadata_locn; - /* FIXME Check it holds this VG */ - if (!(mda_new = dm_pool_alloc(fmt->cmd->mem, - sizeof(*mda_new)))) + mda_new = _mda_copy(fmt->cmd->mem, mda); + if (!mda_new) return_NULL; - - if (!(mdac_new = dm_pool_alloc(fmt->cmd->mem, - sizeof(*mdac_new)))) - return_NULL; - /* FIXME multiple dev_areas inside area */ - memcpy(mda_new, mda, sizeof(*mda)); - memcpy(mdac_new, mdac, sizeof(*mdac)); - mda_new->metadata_locn = mdac_new; dm_list_add(&fid->metadata_areas, &mda_new->list); } } diff -rupN LVM2.2.02.58//lib/locking/locking.c LVM2.2.02.61//lib/locking/locking.c --- LVM2.2.02.58//lib/locking/locking.c 2010-01-13 23:10:17.000000000 +0530 +++ LVM2.2.02.61//lib/locking/locking.c 2010-02-15 22:16:56.000000000 +0530 @@ -219,12 +219,17 @@ static void _update_vg_lock_count(const */ int init_locking(int type, struct cmd_context *cmd) { + int suppress_messages = 0; + + if (ignorelockingfailure() && getenv("LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES")) + suppress_messages = 1; + if (type < 0) type = find_config_tree_int(cmd, "global/locking_type", 1); _blocking_supported = find_config_tree_int(cmd, "global/wait_for_locks", DEFAULT_WAIT_FOR_LOCKS); - + switch (type) { case 0: init_no_locking(&_locking, cmd); @@ -236,8 +241,11 @@ int init_locking(int type, struct cmd_co log_very_verbose("%sFile-based locking selected.", _blocking_supported ? "" : "Non-blocking "); - if (!init_file_locking(&_locking, cmd)) + if (!init_file_locking(&_locking, cmd)) { + log_error_suppress(suppress_messages, + "File-based locking initialisation failed."); break; + } return 1; #ifdef HAVE_LIBDL @@ -249,8 +257,10 @@ int init_locking(int type, struct cmd_co } if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking", find_config_tree_int(cmd, "global/fallback_to_clustered_locking", - DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))) + DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))) { + log_error("External locking initialisation failed."); break; + } #endif #ifdef CLUSTER_LOCKING_INTERNAL @@ -259,8 +269,11 @@ int init_locking(int type, struct cmd_co case 3: log_very_verbose("Cluster locking selected."); - if (!init_cluster_locking(&_locking, cmd)) + if (!init_cluster_locking(&_locking, cmd)) { + log_error_suppress(suppress_messages, + "Internal cluster locking initialisation failed."); break; + } return 1; #endif @@ -280,11 +293,16 @@ int init_locking(int type, struct cmd_co find_config_tree_int(cmd, "locking/fallback_to_local_locking", find_config_tree_int(cmd, "global/fallback_to_local_locking", DEFAULT_FALLBACK_TO_LOCAL_LOCKING))) { - log_warn("WARNING: Falling back to local file-based locking."); - log_warn("Volume Groups with the clustered attribute will " - "be inaccessible."); + log_warn_suppress(suppress_messages, + "WARNING: Falling back to local file-based locking."); + log_warn_suppress(suppress_messages, + "Volume Groups with the clustered attribute will " + "be inaccessible."); if (init_file_locking(&_locking, cmd)) return 1; + else + log_error_suppress(suppress_messages, + "File-based locking initialisation failed."); } if (!ignorelockingfailure()) diff -rupN LVM2.2.02.58//lib/locking/no_locking.c LVM2.2.02.61//lib/locking/no_locking.c --- LVM2.2.02.58//lib/locking/no_locking.c 2009-12-11 18:46:38.000000000 +0530 +++ LVM2.2.02.61//lib/locking/no_locking.c 2010-01-22 15:15:29.000000000 +0530 @@ -72,7 +72,7 @@ static int _readonly_lock_resource(struc (flags & LCK_SCOPE_MASK) == LCK_VG && !(flags & LCK_CACHE) && strcmp(resource, VG_GLOBAL)) { - log_error("Write locks are prohibited with --ignorelockingfailure."); + log_error("Write locks are prohibited with read-only locking."); return 0; } diff -rupN LVM2.2.02.58//lib/log/log.h LVM2.2.02.61//lib/log/log.h --- LVM2.2.02.58//lib/log/log.h 2009-12-17 00:52:12.000000000 +0530 +++ LVM2.2.02.61//lib/log/log.h 2010-02-15 22:16:56.000000000 +0530 @@ -59,7 +59,9 @@ #define log_info(x...) LOG_LINE(_LOG_INFO, x) #define log_notice(x...) LOG_LINE(_LOG_NOTICE, x) #define log_warn(x...) LOG_LINE(_LOG_WARN | _LOG_STDERR, x) +#define log_warn_suppress(s, x...) LOG_LINE(s ? _LOG_NOTICE : _LOG_WARN | _LOG_STDERR, x) #define log_err(x...) LOG_LINE_WITH_ERRNO(_LOG_ERR, EUNCLASSIFIED, x) +#define log_err_suppress(s, x...) LOG_LINE_WITH_ERRNO(s ? _LOG_NOTICE : _LOG_ERR, EUNCLASSIFIED, x) #define log_fatal(x...) LOG_LINE_WITH_ERRNO(_LOG_FATAL, EUNCLASSIFIED, x) #define stack log_debug("") /* Backtrace on error */ @@ -67,6 +69,7 @@ #define log_verbose(args...) log_notice(args) #define log_print(args...) LOG_LINE(_LOG_WARN, args) #define log_error(args...) log_err(args) +#define log_error_suppress(s, args...) log_err_suppress(s, args) #define log_errno(args...) LOG_LINE_WITH_ERRNO(_LOG_ERR, args) /* System call equivalents */ diff -rupN LVM2.2.02.58//lib/metadata/lv_manip.c LVM2.2.02.61//lib/metadata/lv_manip.c --- LVM2.2.02.58//lib/metadata/lv_manip.c 2010-01-14 15:47:12.000000000 +0530 +++ LVM2.2.02.61//lib/metadata/lv_manip.c 2010-01-21 03:23:10.000000000 +0530 @@ -2064,7 +2064,7 @@ int lv_remove_single(struct cmd_context struct volume_group *vg; struct lvinfo info; struct logical_volume *origin = NULL; - int was_merging = 0; + int was_merging = 0, preload_origin = 0; vg = lv->vg; @@ -2130,6 +2130,11 @@ int lv_remove_single(struct cmd_context log_verbose("Removing snapshot %s", lv->name); if (!vg_remove_snapshot(lv)) return_0; + if (was_merging && lv_is_origin(origin)) { + /* snapshot(s) still exist. preload new origin prior to suspend. */ + /* FIXME Seek a simpler way of dealing with this within the tree. */ + preload_origin = 1; + } } log_verbose("Releasing logical volume \"%s\"", lv->name); @@ -2142,21 +2147,21 @@ int lv_remove_single(struct cmd_context if (!vg_write(vg)) return_0; + if (!preload_origin && !vg_commit(vg)) + return_0; + /* If no snapshots left or if we stopped merging, reload */ if (origin && (!lv_is_origin(origin) || was_merging)) { if (!suspend_lv(cmd, origin)) { log_error("Failed to refresh %s without snapshot.", origin->name); return 0; } - if (!vg_commit(vg)) + if (preload_origin && !vg_commit(vg)) return_0; if (!resume_lv(cmd, origin)) { log_error("Failed to resume %s.", origin->name); return 0; } - } else { - if (!vg_commit(vg)) - return_0; } backup(vg); diff -rupN LVM2.2.02.58//lib/metadata/metadata.c LVM2.2.02.61//lib/metadata/metadata.c --- LVM2.2.02.58//lib/metadata/metadata.c 2010-01-07 19:59:53.000000000 +0530 +++ LVM2.2.02.61//lib/metadata/metadata.c 2010-02-14 08:51:37.000000000 +0530 @@ -1348,7 +1348,7 @@ struct physical_volume * pvcreate_single const char *pv_name, struct pvcreate_params *pp) { - void *pv; + struct physical_volume *pv; struct device *dev; struct dm_list mdas; struct pvcreate_params default_pp; @@ -1418,8 +1418,7 @@ struct physical_volume * pvcreate_single log_very_verbose("Writing physical volume data to disk \"%s\"", pv_name); - if (!(pv_write(cmd, (struct physical_volume *)pv, &mdas, - pp->labelsector))) { + if (!(pv_write(cmd, pv, &mdas, pp->labelsector))) { log_error("Failed to write physical volume \"%s\"", pv_name); goto error; } @@ -1444,11 +1443,6 @@ static struct physical_volume *_alloc_pv if (!pv) return_NULL; - if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN))) { - dm_pool_free(mem, pv); - return NULL; - } - pv->pe_size = 0; pv->pe_start = 0; pv->pe_count = 0; @@ -2917,14 +2911,14 @@ static struct volume_group *_vg_read_by_ * allowed to do a full scan here any more. */ // The slow way - full scan required to cope with vgrename - if (!(vgnames = get_vgnames(cmd, 2))) { + if (!(vgnames = get_vgnames(cmd, 2, 0))) { log_error("vg_read_by_vgid: get_vgnames failed"); goto out; } dm_list_iterate_items(strl, vgnames) { vgname = strl->str; - if (!vgname || is_orphan_vg(vgname)) + if (!vgname) continue; // FIXME Unnecessary? consistent = 0; if ((vg = _vg_read(cmd, vgname, vgid, &consistent, @@ -3026,40 +3020,43 @@ static struct physical_volume *_pv_read( if (label_sector && *label_sector) *label_sector = label->sector; - if (!(pv = dm_pool_zalloc(pvmem, sizeof(*pv)))) { + pv = _alloc_pv(pvmem, dev); + if (!pv) { log_error("pv allocation for '%s' failed", pv_name); return NULL; } - dm_list_init(&pv->tags); - dm_list_init(&pv->segments); - /* FIXME Move more common code up here */ if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas, scan_label_only))) { log_error("Failed to read existing physical volume '%s'", pv_name); - return NULL; + goto bad; } if (!pv->size) - return NULL; + goto bad; if (!alloc_pv_segment_whole_pv(pvmem, pv)) - return_NULL; + goto_bad; return pv; +bad: + _free_pv(pvmem, pv); + return NULL; } /* May return empty list */ -struct dm_list *get_vgnames(struct cmd_context *cmd, int full_scan) +struct dm_list *get_vgnames(struct cmd_context *cmd, int full_scan, + int include_internal) { - return lvmcache_get_vgnames(cmd, full_scan); + return lvmcache_get_vgnames(cmd, full_scan, include_internal); } -struct dm_list *get_vgids(struct cmd_context *cmd, int full_scan) +struct dm_list *get_vgids(struct cmd_context *cmd, int full_scan, + int include_internal) { - return lvmcache_get_vgids(cmd, full_scan); + return lvmcache_get_vgids(cmd, full_scan, include_internal); } static int _get_pvs(struct cmd_context *cmd, struct dm_list **pvslist) @@ -3085,7 +3082,7 @@ static int _get_pvs(struct cmd_context * } /* Get list of VGs */ - if (!(vgids = get_vgids(cmd, 0))) { + if (!(vgids = get_vgids(cmd, 0, 1))) { log_error("get_pvs: get_vgids failed"); return 0; } @@ -3606,6 +3603,38 @@ uint64_t pv_size(const struct physical_v return pv_field(pv, size); } +uint64_t pv_dev_size(const struct physical_volume *pv) +{ + uint64_t size; + + if (!dev_get_size(pv->dev, &size)) + size = 0; + return size; +} + +uint64_t pv_size_field(const struct physical_volume *pv) +{ + uint64_t size; + + if (!pv->pe_count) + size = pv->size; + else + size = (uint64_t) pv->pe_count * pv->pe_size; + return size; +} + +uint64_t pv_free(const struct physical_volume *pv) +{ + uint64_t freespace; + + if (!pv->pe_count) + freespace = pv->size; + else + freespace = (uint64_t) + (pv->pe_count - pv->pe_alloc_count) * pv->pe_size; + return freespace; +} + uint64_t pv_status(const struct physical_volume *pv) { return pv_field(pv, status); diff -rupN LVM2.2.02.58//lib/metadata/metadata-exported.h LVM2.2.02.61//lib/metadata/metadata-exported.h --- LVM2.2.02.58//lib/metadata/metadata-exported.h 2010-01-13 07:26:18.000000000 +0530 +++ LVM2.2.02.61//lib/metadata/metadata-exported.h 2010-02-14 08:51:37.000000000 +0530 @@ -25,6 +25,7 @@ #define MAX_STRIPES 128U #define SECTOR_SHIFT 9L +#define SECTOR_SIZE ( 1L << SECTOR_SHIFT ) #define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */ #define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */ #define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1) @@ -398,8 +399,10 @@ void lv_set_visible(struct logical_volum void lv_set_hidden(struct logical_volume *lv); /* Set full_scan to 1 to re-read every (filtered) device label */ -struct dm_list *get_vgnames(struct cmd_context *cmd, int full_scan); -struct dm_list *get_vgids(struct cmd_context *cmd, int full_scan); +struct dm_list *get_vgnames(struct cmd_context *cmd, int full_scan, + int include_internal); +struct dm_list *get_vgids(struct cmd_context *cmd, int full_scan, + int include_internal); int scan_vgs_for_pvs(struct cmd_context *cmd); int pv_write(struct cmd_context *cmd, struct physical_volume *pv, @@ -723,6 +726,9 @@ struct device *pv_dev(const struct physi const char *pv_vg_name(const struct physical_volume *pv); const char *pv_dev_name(const struct physical_volume *pv); uint64_t pv_size(const struct physical_volume *pv); +uint64_t pv_size_field(const struct physical_volume *pv); +uint64_t pv_dev_size(const struct physical_volume *pv); +uint64_t pv_free(const struct physical_volume *pv); uint64_t pv_status(const struct physical_volume *pv); uint32_t pv_pe_size(const struct physical_volume *pv); uint64_t pv_pe_start(const struct physical_volume *pv); diff -rupN LVM2.2.02.58//lib/metadata/metadata.h LVM2.2.02.61//lib/metadata/metadata.h --- LVM2.2.02.58//lib/metadata/metadata.h 2009-09-28 23:16:16.000000000 +0530 +++ LVM2.2.02.61//lib/metadata/metadata.h 2010-02-14 08:51:06.000000000 +0530 @@ -28,7 +28,7 @@ //#define MAX_STRIPES 128U //#define SECTOR_SHIFT 9L -#define SECTOR_SIZE ( 1L << SECTOR_SHIFT ) +//#define SECTOR_SIZE ( 1L << SECTOR_SHIFT ) //#define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */ //#define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */ //#define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1) diff -rupN LVM2.2.02.58//lib/metadata/segtype.h LVM2.2.02.61//lib/metadata/segtype.h --- LVM2.2.02.58//lib/metadata/segtype.h 2009-10-16 23:11:52.000000000 +0530 +++ LVM2.2.02.61//lib/metadata/segtype.h 2010-01-15 22:05:26.000000000 +0530 @@ -77,6 +77,7 @@ struct segtype_handler { struct lv_segment *seg, struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count); + int (*target_status_compatible) (const char *type); int (*target_percent) (void **target_state, percent_range_t *percent_range, struct dm_pool * mem, diff -rupN LVM2.2.02.58//lib/report/columns.h LVM2.2.02.61//lib/report/columns.h --- LVM2.2.02.58//lib/report/columns.h 2009-05-21 08:34:53.000000000 +0530 +++ LVM2.2.02.61//lib/report/columns.h 2010-02-14 08:51:38.000000000 +0530 @@ -78,7 +78,7 @@ FIELD(LVS, lv, STR, "Modules", lvid, 7, FIELD(LABEL, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt", "Type of metadata.") FIELD(LABEL, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid", "Unique identifier.") -FIELD(LABEL, pv, NUM, "DevSize", dev, 7, devsize, "dev_size", "Size of underlying device in current units.") +FIELD(LABEL, pv, NUM, "DevSize", id, 7, devsize, "dev_size", "Size of underlying device in current units.") FIELD(LABEL, pv, STR, "PV", dev, 10, dev_name, "pv_name", "Name.") FIELD(LABEL, pv, NUM, "PMdaFree", id, 9, pvmdafree, "pv_mda_free", "Free metadata area space on this device in current units.") FIELD(LABEL, pv, NUM, "PMdaSize", id, 9, pvmdasize, "pv_mda_size", "Size of smallest metadata area on this device in current units.") diff -rupN LVM2.2.02.58//lib/report/report.c LVM2.2.02.61//lib/report/report.c --- LVM2.2.02.58//lib/report/report.c 2010-01-13 07:25:44.000000000 +0530 +++ LVM2.2.02.61//lib/report/report.c 2010-02-16 01:57:33.000000000 +0530 @@ -50,7 +50,8 @@ static char _alloc_policy_char(alloc_pol } } -static const uint64_t _minusone = UINT64_C(-1); +static const uint64_t _minusone64 = UINT64_C(-1); +static const int32_t _minusone32 = INT32_C(-1); /* * Data-munging functions to prepare each data type for display and sorting @@ -66,7 +67,7 @@ static int _dev_name_disp(struct dm_repo struct dm_report_field *field, const void *data, void *private __attribute((unused))) { - const char *name = dev_name(*(const struct device **) data); + const char *name = dev_name(*(const struct device * const *) data); return dm_report_field_string(rh, field, &name); } @@ -247,7 +248,7 @@ static int _lvkmaj_disp(struct dm_report if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists) return dm_report_field_int(rh, field, &info.major); - return dm_report_field_uint64(rh, field, &_minusone); + return dm_report_field_int32(rh, field, &_minusone32); } static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), @@ -260,7 +261,7 @@ static int _lvkmin_disp(struct dm_report if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists) return dm_report_field_int(rh, field, &info.minor); - return dm_report_field_uint64(rh, field, &_minusone); + return dm_report_field_int32(rh, field, &_minusone32); } static int _lv_mimage_in_sync(const struct logical_volume *lv) @@ -643,7 +644,7 @@ static int _lvreadahead_disp(struct dm_r const struct logical_volume *lv = (const struct logical_volume *) data; if (lv->read_ahead == DM_READ_AHEAD_AUTO) { - dm_report_field_set_value(field, "auto", &_minusone); + dm_report_field_set_value(field, "auto", &_minusone64); return 1; } @@ -659,7 +660,7 @@ static int _lvkreadahead_disp(struct dm_ struct lvinfo info; if (!lv_info(lv->vg->cmd, lv, &info, 0, 1) || !info.exists) - return dm_report_field_uint64(rh, field, &_minusone); + return dm_report_field_int32(rh, field, &_minusone32); return _size32_disp(rh, mem, field, &info.read_ahead, private); } @@ -767,10 +768,7 @@ static int _pvfree_disp(struct dm_report (const struct physical_volume *) data; uint64_t freespace; - if (!pv->pe_count) - freespace = pv->size; - else - freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size; + freespace = pv_free(pv); return _size64_disp(rh, mem, field, &freespace, private); } @@ -783,10 +781,7 @@ static int _pvsize_disp(struct dm_report (const struct physical_volume *) data; uint64_t size; - if (!pv->pe_count) - size = pv->size; - else - size = (uint64_t) pv->pe_count * pv->pe_size; + size = pv_size_field(pv); return _size64_disp(rh, mem, field, &size, private); } @@ -795,11 +790,11 @@ static int _devsize_disp(struct dm_repor struct dm_report_field *field, const void *data, void *private) { - const struct device *dev = *(const struct device **) data; + const struct physical_volume *pv = + (const struct physical_volume *) data; uint64_t size; - if (!dev_get_size(dev, &size)) - size = 0; + size = pv_dev_size(pv); return _size64_disp(rh, mem, field, &size, private); } @@ -879,7 +874,7 @@ static int _pvmdafree_disp(struct dm_rep { struct lvmcache_info *info; uint64_t freespace = UINT64_MAX, mda_free; - const char *pvid = (const char *)(&((struct id *) data)->uuid); + const char *pvid = (const char *)(&((const struct id *) data)->uuid); struct metadata_area *mda; if ((info = info_from_pvid(pvid, 0))) @@ -922,7 +917,7 @@ static int _pvmdasize_disp(struct dm_rep { struct lvmcache_info *info; uint64_t min_mda_size = 0; - const char *pvid = (const char *)(&((struct id *) data)->uuid); + const char *pvid = (const char *)(&((const struct id *) data)->uuid); /* PVs could have 2 mdas of different sizes (rounding effect) */ if ((info = info_from_pvid(pvid, 0))) @@ -1055,7 +1050,7 @@ static int _snpercent_disp(struct dm_rep return 0; } - *sortval = snap_percent * UINT64_C(1000); + *sortval = (uint64_t)(snap_percent * 1000.f); dm_report_field_set_value(field, repstr, sortval); return 1; @@ -1097,7 +1092,7 @@ static int _copypercent_disp(struct dm_r return 0; } - *sortval = percent * UINT64_C(1000); + *sortval = (uint64_t)(percent * 1000.f); dm_report_field_set_value(field, repstr, sortval); return 1; diff -rupN LVM2.2.02.58//lib/snapshot/snapshot.c LVM2.2.02.61//lib/snapshot/snapshot.c --- LVM2.2.02.58//lib/snapshot/snapshot.c 2010-01-13 07:26:18.000000000 +0530 +++ LVM2.2.02.61//lib/snapshot/snapshot.c 2010-01-15 23:16:08.000000000 +0530 @@ -46,10 +46,15 @@ static int _snap_text_import(struct lv_s old_suppress = log_suppress(1); - cow_name = find_config_str(sn, "merging_store", NULL); - if (cow_name) { + if ((cow_name = find_config_str(sn, "merging_store", NULL))) { + if (find_config_str(sn, "cow_store", NULL)) { + log_suppress(old_suppress); + log_error("Both snapshot cow and merging storage were specified."); + return 0; + } merge = 1; - } else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) { + } + else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) { log_suppress(old_suppress); log_error("Snapshot cow storage not specified."); return 0; @@ -92,6 +97,11 @@ static int _snap_text_export(const struc return 1; } +static int _snap_target_status_compatible(const char *type) +{ + return (strcmp(type, "snapshot-merge") == 0); +} + #ifdef DEVMAPPER_SUPPORT static int _snap_target_percent(void **target_state __attribute((unused)), percent_range_t *percent_range, @@ -303,6 +313,7 @@ static struct segtype_handler _snapshot_ .name = _snap_name, .text_import = _snap_text_import, .text_export = _snap_text_export, + .target_status_compatible = _snap_target_status_compatible, #ifdef DEVMAPPER_SUPPORT .target_percent = _snap_target_percent, .target_present = _snap_target_present, diff -rupN LVM2.2.02.58//libdm/datastruct/bitset.h LVM2.2.02.61//libdm/datastruct/bitset.h --- LVM2.2.02.58//libdm/datastruct/bitset.h 2007-08-21 21:56:06.000000000 +0530 +++ LVM2.2.02.61//libdm/datastruct/bitset.h 1970-01-01 05:30:00.000000000 +0530 @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2007 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 _DM_BITSET_H -#define _DM_BITSET_H - -#include "pool.h" - -#include - -typedef uint32_t *bitset_t; - -bitset_t bitset_create(struct pool *mem, unsigned num_bits); -void bitset_destroy(bitset_t bs); - -void bit_union(bitset_t out, bitset_t in1, bitset_t in2); -int bit_get_first(bitset_t bs); -int bit_get_next(bitset_t bs, int last_bit); - -#define BITS_PER_INT (sizeof(int) * CHAR_BIT) - -#define bit(bs, i) \ - (bs[(i / BITS_PER_INT) + 1] & (0x1 << (i & (BITS_PER_INT - 1)))) - -#define bit_set(bs, i) \ - (bs[(i / BITS_PER_INT) + 1] |= (0x1 << (i & (BITS_PER_INT - 1)))) - -#define bit_clear(bs, i) \ - (bs[(i / BITS_PER_INT) + 1] &= ~(0x1 << (i & (BITS_PER_INT - 1)))) - -#define bit_set_all(bs) \ - memset(bs + 1, -1, ((*bs / BITS_PER_INT) + 1) * sizeof(int)) - -#define bit_clear_all(bs) \ - memset(bs + 1, 0, ((*bs / BITS_PER_INT) + 1) * sizeof(int)) - -#define bit_copy(bs1, bs2) \ - memcpy(bs1 + 1, bs2 + 1, ((*bs1 / BITS_PER_INT) + 1) * sizeof(int)) - -#endif diff -rupN LVM2.2.02.58//libdm/datastruct/hash.h LVM2.2.02.61//libdm/datastruct/hash.h --- LVM2.2.02.58//libdm/datastruct/hash.h 2007-08-21 21:56:06.000000000 +0530 +++ LVM2.2.02.61//libdm/datastruct/hash.h 1970-01-01 05:30:00.000000000 +0530 @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2007 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 _DM_HASH_H -#define _DM_HASH_H - -struct hash_table; -struct hash_node; - -typedef void (*iterate_fn) (void *data); - -struct hash_table *hash_create(unsigned size_hint); -void hash_destroy(struct hash_table *t); -void hash_wipe(struct hash_table *t); - -void *hash_lookup(struct hash_table *t, const char *key); -int hash_insert(struct hash_table *t, const char *key, void *data); -void hash_remove(struct hash_table *t, const char *key); - -void *hash_lookup_binary(struct hash_table *t, const char *key, uint32_t len); -int hash_insert_binary(struct hash_table *t, const char *key, uint32_t len, - void *data); -void hash_remove_binary(struct hash_table *t, const char *key, uint32_t len); - -unsigned hash_get_num_entries(struct hash_table *t); -void hash_iter(struct hash_table *t, iterate_fn f); - -char *hash_get_key(struct hash_table *t, struct hash_node *n); -void *hash_get_data(struct hash_table *t, struct hash_node *n); -struct hash_node *hash_get_first(struct hash_table *t); -struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n); - -#define hash_iterate(v, h) \ - for (v = hash_get_first(h); v; \ - v = hash_get_next(h, v)) - -#endif diff -rupN LVM2.2.02.58//libdm/.exported_symbols LVM2.2.02.61//libdm/.exported_symbols --- LVM2.2.02.58//libdm/.exported_symbols 2010-01-13 07:09:45.000000000 +0530 +++ LVM2.2.02.61//libdm/.exported_symbols 2010-02-15 21:51:33.000000000 +0530 @@ -166,5 +166,6 @@ dm_udev_set_sync_support dm_udev_get_sync_support dm_udev_set_checking dm_udev_get_checking +dm_udev_create_cookie dm_udev_complete dm_udev_wait diff -rupN LVM2.2.02.58//libdm/ioctl/libdm-iface.c LVM2.2.02.61//libdm/ioctl/libdm-iface.c --- LVM2.2.02.58//libdm/ioctl/libdm-iface.c 2009-11-13 18:13:22.000000000 +0530 +++ LVM2.2.02.61//libdm/ioctl/libdm-iface.c 2010-02-15 21:51:34.000000000 +0530 @@ -1789,6 +1789,7 @@ int dm_task_run(struct dm_task *dmt) struct dm_ioctl *dmi; unsigned command; int check_udev; + int udev_only; #ifdef DM_COMPAT if (_dm_version == 1) @@ -1847,22 +1848,25 @@ repeat_ioctl: !(dmt->event_nr >> DM_UDEV_FLAGS_SHIFT & DM_UDEV_DISABLE_DM_RULES_FLAG); + udev_only = dmt->cookie_set ? (dmt->event_nr >> DM_UDEV_FLAGS_SHIFT & + DM_UDEV_DISABLE_LIBRARY_FALLBACK) : 0; + switch (dmt->type) { case DM_DEVICE_CREATE: - if (dmt->dev_name && *dmt->dev_name) + if (dmt->dev_name && *dmt->dev_name && !udev_only) add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, check_udev); break; case DM_DEVICE_REMOVE: /* FIXME Kernel needs to fill in dmi->name */ - if (dmt->dev_name) + if (dmt->dev_name && !udev_only) rm_dev_node(dmt->dev_name, check_udev); break; case DM_DEVICE_RENAME: /* FIXME Kernel needs to fill in dmi->name */ - if (dmt->dev_name) + if (dmt->dev_name && !udev_only) rename_dev_node(dmt->dev_name, dmt->newname, check_udev); break; diff -rupN LVM2.2.02.58//libdm/libdevmapper.h LVM2.2.02.61//libdm/libdevmapper.h --- LVM2.2.02.58//libdm/libdevmapper.h 2010-01-14 15:45:23.000000000 +0530 +++ LVM2.2.02.61//libdm/libdevmapper.h 2010-02-15 21:51:33.000000000 +0530 @@ -1084,6 +1084,13 @@ void dm_report_field_set_value(struct dm * snapshot devices. */ #define DM_UDEV_LOW_PRIORITY_FLAG 0x0010 +/* + * DM_UDEV_DISABLE_LIBRARY_FALLBACK is set in case we need to disable + * libdevmapper's node management. We will rely on udev completely + * and there will be no fallback action provided by libdevmapper if + * udev does something improperly. + */ +#define DM_UDEV_DISABLE_LIBRARY_FALLBACK 0x0020 int dm_cookie_supported(void); @@ -1094,6 +1101,7 @@ void dm_udev_set_sync_support(int sync_w int dm_udev_get_sync_support(void); void dm_udev_set_checking(int checking); int dm_udev_get_checking(void); +int dm_udev_create_cookie(uint32_t *cookie); int dm_udev_complete(uint32_t cookie); int dm_udev_wait(uint32_t cookie); diff -rupN LVM2.2.02.58//libdm/libdm-common.c LVM2.2.02.61//libdm/libdm-common.c --- LVM2.2.02.58//libdm/libdm-common.c 2010-01-11 21:06:24.000000000 +0530 +++ LVM2.2.02.61//libdm/libdm-common.c 2010-02-15 21:51:33.000000000 +0530 @@ -1166,6 +1166,16 @@ bad: return 0; } +int dm_udev_create_cookie(uint32_t *cookie) +{ + int semid; + + if (!dm_udev_get_sync_support()) + return 1; + + return _udev_notify_sem_create(cookie, &semid); +} + int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags) { int semid; diff -rupN LVM2.2.02.58//libdm/libdm-deptree.c LVM2.2.02.61//libdm/libdm-deptree.c --- LVM2.2.02.58//libdm/libdm-deptree.c 2010-01-14 15:45:23.000000000 +0530 +++ LVM2.2.02.61//libdm/libdm-deptree.c 2010-01-15 21:30:23.000000000 +0530 @@ -1408,6 +1408,9 @@ static int _mirror_emit_segment_line(str if (!dm_log_userspace) EMIT_PARAMS(pos, "clustered-"); + else + /* For clustered-* type field inserted later */ + log_parm_count++; } if (!seg->log) diff -rupN LVM2.2.02.58//libdm/libdm-report.c LVM2.2.02.61//libdm/libdm-report.c --- LVM2.2.02.58//libdm/libdm-report.c 2010-01-12 02:58:04.000000000 +0530 +++ LVM2.2.02.61//libdm/libdm-report.c 2010-02-16 00:06:48.000000000 +0530 @@ -207,7 +207,7 @@ int dm_report_field_int32(struct dm_repo int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field, const uint64_t *data) { - const int value = *data; + const uint64_t value = *data; uint64_t *sortval; char *repstr; @@ -221,12 +221,12 @@ int dm_report_field_uint64(struct dm_rep return 0; } - if (dm_snprintf(repstr, 21, "%d", value) < 0) { - log_error("dm_report_field_uint64: uint64 too big: %d", value); + if (dm_snprintf(repstr, 21, "%" PRIu64 , value) < 0) { + log_error("dm_report_field_uint64: uint64 too big: %" PRIu64, value); return 0; } - *sortval = (const uint64_t) value; + *sortval = value; field->sort_value = sortval; field->report_string = repstr; @@ -819,8 +819,8 @@ static int _report_headings(struct dm_re */ static int _row_compare(const void *a, const void *b) { - const struct row *rowa = *(const struct row **) a; - const struct row *rowb = *(const struct row **) b; + const struct row *rowa = *(const struct row * const *) a; + const struct row *rowb = *(const struct row * const *) b; const struct dm_report_field *sfa, *sfb; uint32_t cnt; diff -rupN LVM2.2.02.58//libdm/misc/dm-log-userspace.h LVM2.2.02.61//libdm/misc/dm-log-userspace.h --- LVM2.2.02.58//libdm/misc/dm-log-userspace.h 2009-08-14 02:21:41.000000000 +0530 +++ LVM2.2.02.61//libdm/misc/dm-log-userspace.h 2010-01-19 06:40:47.000000000 +0530 @@ -7,7 +7,7 @@ #ifndef __DM_LOG_USERSPACE_H__ #define __DM_LOG_USERSPACE_H__ -#include /* For DM_UUID_LEN */ +#include "dm-ioctl.h" /* For DM_UUID_LEN */ /* * The device-mapper userspace log module consists of a kernel component and diff -rupN LVM2.2.02.58//libdm/mm/pool.h LVM2.2.02.61//libdm/mm/pool.h --- LVM2.2.02.58//libdm/mm/pool.h 2007-08-21 21:56:07.000000000 +0530 +++ LVM2.2.02.61//libdm/mm/pool.h 1970-01-01 05:30:00.000000000 +0530 @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2007 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 _DM_POOL_H -#define _DM_POOL_H - -#include -#include - -/* - * The pool allocator is useful when you are going to allocate - * lots of memory, use the memory for a bit, and then free the - * memory in one go. A surprising amount of code has this usage - * profile. - * - * You should think of the pool as an infinite, contiguous chunk - * of memory. The front of this chunk of memory contains - * allocated objects, the second half is free. pool_alloc grabs - * the next 'size' bytes from the free half, in effect moving it - * into the allocated half. This operation is very efficient. - * - * pool_free frees the allocated object *and* all objects - * allocated after it. It is important to note this semantic - * difference from malloc/free. This is also extremely - * efficient, since a single pool_free can dispose of a large - * complex object. - * - * pool_destroy frees all allocated memory. - * - * eg, If you are building a binary tree in your program, and - * know that you are only ever going to insert into your tree, - * and not delete (eg, maintaining a symbol table for a - * compiler). You can create yourself a pool, allocate the nodes - * from it, and when the tree becomes redundant call pool_destroy - * (no nasty iterating through the tree to free nodes). - * - * eg, On the other hand if you wanted to repeatedly insert and - * remove objects into the tree, you would be better off - * allocating the nodes from a free list; you cannot free a - * single arbitrary node with pool. - */ - -struct pool; - -/* constructor and destructor */ -struct pool *pool_create(const char *name, size_t chunk_hint); -void pool_destroy(struct pool *p); - -/* simple allocation/free routines */ -void *pool_alloc(struct pool *p, size_t s); -void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment); -void pool_empty(struct pool *p); -void pool_free(struct pool *p, void *ptr); - -/* - * Object building routines: - * - * These allow you to 'grow' an object, useful for - * building strings, or filling in dynamic - * arrays. - * - * It's probably best explained with an example: - * - * char *build_string(struct pool *mem) - * { - * int i; - * char buffer[16]; - * - * if (!pool_begin_object(mem, 128)) - * return NULL; - * - * for (i = 0; i < 50; i++) { - * snprintf(buffer, sizeof(buffer), "%d, ", i); - * if (!pool_grow_object(mem, buffer, strlen(buffer))) - * goto bad; - * } - * - * // add null - * if (!pool_grow_object(mem, "\0", 1)) - * goto bad; - * - * return pool_end_object(mem); - * - * bad: - * - * pool_abandon_object(mem); - * return NULL; - *} - * - * So start an object by calling pool_begin_object - * with a guess at the final object size - if in - * doubt make the guess too small. - * - * Then append chunks of data to your object with - * pool_grow_object. Finally get your object with - * a call to pool_end_object. - * - */ -int pool_begin_object(struct pool *p, size_t hint); -int pool_grow_object(struct pool *p, const void *extra, size_t delta); -void *pool_end_object(struct pool *p); -void pool_abandon_object(struct pool *p); - -/* utilities */ -char *pool_strdup(struct pool *p, const char *str); -char *pool_strndup(struct pool *p, const char *str, size_t n); -void *pool_zalloc(struct pool *p, size_t s); - -#endif diff -rupN LVM2.2.02.58//liblvm/.exported_symbols LVM2.2.02.61//liblvm/.exported_symbols --- LVM2.2.02.58//liblvm/.exported_symbols 2009-07-28 18:47:04.000000000 +0530 +++ LVM2.2.02.61//liblvm/.exported_symbols 2010-02-14 08:51:38.000000000 +0530 @@ -3,6 +3,9 @@ lvm_init lvm_quit lvm_config_reload lvm_config_override +lvm_pv_get_dev_size +lvm_pv_get_size +lvm_pv_get_free lvm_pv_get_name lvm_pv_get_uuid lvm_pv_get_mda_count diff -rupN LVM2.2.02.58//liblvm/lvm2app.h LVM2.2.02.61//liblvm/lvm2app.h --- LVM2.2.02.58//liblvm/lvm2app.h 2009-09-15 01:13:12.000000000 +0530 +++ LVM2.2.02.61//liblvm/lvm2app.h 2010-02-16 01:25:49.000000000 +0530 @@ -281,8 +281,6 @@ int lvm_scan(lvm_t libh); * * NOTE: This function normally does not scan devices in the system for LVM * metadata. To scan the system, use lvm_scan. - * NOTE: This function currently returns hidden VG names. These names always - * begin with a "#" and should be filtered out and not used. * * To process the list, use the dm_list iterator functions. For example: * vg_t vg; @@ -315,8 +313,6 @@ struct dm_list *lvm_list_vg_names(lvm_t * * NOTE: This function normally does not scan devices in the system for LVM * metadata. To scan the system, use lvm_scan. - * NOTE: This function currently returns hidden VG names. These names always - * begin with a "#" and should be filtered out and not used. * * \param libh * Handle obtained from lvm_init. @@ -868,6 +864,40 @@ char *lvm_pv_get_name(const pv_t pv); uint64_t lvm_pv_get_mda_count(const pv_t pv); /** + * Get the current size in bytes of a device underlying a + * physical volume. + * + * \param pv + * Physical volume handle. + * + * \return + * Size in bytes. + */ +uint64_t lvm_pv_get_dev_size(const pv_t pv); + +/** + * Get the current size in bytes of a physical volume. + * + * \param pv + * Physical volume handle. + * + * \return + * Size in bytes. + */ +uint64_t lvm_pv_get_size(const pv_t pv); + +/** + * Get the current unallocated space in bytes of a physical volume. + * + * \param pv + * Physical volume handle. + * + * \return + * Free size in bytes. + */ +uint64_t lvm_pv_get_free(const pv_t pv); + +/** * Resize physical volume to new_size bytes. * * NOTE: This function is currently not implemented. diff -rupN LVM2.2.02.58//liblvm/lvm_base.c LVM2.2.02.61//liblvm/lvm_base.c --- LVM2.2.02.58//liblvm/lvm_base.c 2009-07-30 00:08:27.000000000 +0530 +++ LVM2.2.02.61//liblvm/lvm_base.c 2010-01-22 15:15:29.000000000 +0530 @@ -51,7 +51,6 @@ lvm_t lvm_init(const char *system_dir) /* initialize locking */ if (!init_locking(-1, cmd)) { /* FIXME: use EAGAIN as error code here */ - log_error("Locking initialisation failed."); lvm_quit((lvm_t) cmd); return NULL; } diff -rupN LVM2.2.02.58//liblvm/lvm_lv.c LVM2.2.02.61//liblvm/lvm_lv.c --- LVM2.2.02.58//liblvm/lvm_lv.c 2009-08-13 17:47:32.000000000 +0530 +++ LVM2.2.02.61//liblvm/lvm_lv.c 2010-02-14 08:51:06.000000000 +0530 @@ -26,7 +26,7 @@ /* FIXME: have lib/report/report.c _disp function call lv_size()? */ uint64_t lvm_lv_get_size(const lv_t lv) { - return lv_size(lv); + return SECTOR_SIZE*lv_size(lv); } char *lvm_lv_get_uuid(const lv_t lv) @@ -112,7 +112,7 @@ lv_t lvm_vg_create_lv_linear(vg_t vg, co if (!vg_check_write_mode(vg)) return NULL; memset(&lp, 0, sizeof(lp)); - extents = extents_from_size(vg->cmd, size, vg->extent_size); + extents = extents_from_size(vg->cmd, size/SECTOR_SIZE, vg->extent_size); _lv_set_default_params(&lp, vg, name, extents); _lv_set_default_linear_params(vg->cmd, &lp); if (!lv_create_single(vg, &lp)) diff -rupN LVM2.2.02.58//liblvm/lvm_pv.c LVM2.2.02.61//liblvm/lvm_pv.c --- LVM2.2.02.58//liblvm/lvm_pv.c 2009-08-13 17:48:15.000000000 +0530 +++ LVM2.2.02.61//liblvm/lvm_pv.c 2010-02-14 08:51:38.000000000 +0530 @@ -43,6 +43,21 @@ uint64_t lvm_pv_get_mda_count(const pv_t return (uint64_t) pv_mda_count(pv); } +uint64_t lvm_pv_get_dev_size(const pv_t pv) +{ + return (uint64_t) SECTOR_SIZE*pv_dev_size(pv); +} + +uint64_t lvm_pv_get_size(const pv_t pv) +{ + return (uint64_t) SECTOR_SIZE*pv_size_field(pv); +} + +uint64_t lvm_pv_get_free(const pv_t pv) +{ + return (uint64_t) SECTOR_SIZE*pv_free(pv); +} + int lvm_pv_resize(const pv_t pv, uint64_t new_size) { /* FIXME: add pv resize code here */ diff -rupN LVM2.2.02.58//liblvm/lvm_vg.c LVM2.2.02.61//liblvm/lvm_vg.c --- LVM2.2.02.58//liblvm/lvm_vg.c 2009-11-02 01:21:55.000000000 +0530 +++ LVM2.2.02.61//liblvm/lvm_vg.c 2010-02-14 08:51:06.000000000 +0530 @@ -86,7 +86,7 @@ int lvm_vg_set_extent_size(vg_t vg, uint if (!vg_check_write_mode(vg)) return -1; - if (!vg_set_extent_size(vg, new_size)) + if (!vg_set_extent_size(vg, new_size/SECTOR_SIZE)) return -1; return 0; } @@ -256,17 +256,17 @@ uint64_t lvm_vg_is_partial(const vg_t vg /* FIXME: invalid handle? return INTMAX? */ uint64_t lvm_vg_get_size(const vg_t vg) { - return vg_size(vg); + return SECTOR_SIZE*vg_size(vg); } uint64_t lvm_vg_get_free_size(const vg_t vg) { - return vg_free(vg); + return SECTOR_SIZE*vg_free(vg); } uint64_t lvm_vg_get_extent_size(const vg_t vg) { - return vg_extent_size(vg); + return SECTOR_SIZE*vg_extent_size(vg); } uint64_t lvm_vg_get_extent_count(const vg_t vg) @@ -315,19 +315,14 @@ char *lvm_vg_get_name(const vg_t vg) return name; } -/* - * FIXME: These functions currently return hidden VGs. We should either filter - * these out and not return them in the list, or export something like - * is_orphan_vg and tell the caller to filter. - */ struct dm_list *lvm_list_vg_names(lvm_t libh) { - return get_vgnames((struct cmd_context *)libh, 0); + return get_vgnames((struct cmd_context *)libh, 0, 0); } struct dm_list *lvm_list_vg_uuids(lvm_t libh) { - return get_vgids((struct cmd_context *)libh, 0); + return get_vgids((struct cmd_context *)libh, 0, 0); } /* diff -rupN LVM2.2.02.58//make.tmpl.in LVM2.2.02.61//make.tmpl.in --- LVM2.2.02.58//make.tmpl.in 2009-10-09 21:25:31.000000000 +0530 +++ LVM2.2.02.61//make.tmpl.in 2010-01-22 18:50:32.000000000 +0530 @@ -54,7 +54,7 @@ staticdir = $(DESTDIR)@STATICDIR@ udevdir = $(DESTDIR)@udevdir@ interface = @interface@ -interfacedir = $(top_srcdir)/libdm/$(interface) +interfacebuilddir = $(top_builddir)/libdm/$(interface) # setup misc variables # define the ownership variables for the binaries and man pages @@ -78,7 +78,10 @@ CFLAGS += @COPTIMISE_FLAG@ ifeq ("@DEBUG@", "yes") CFLAGS += -g -fno-omit-frame-pointer DEFS += -DDEBUG - DEFS += -DDEBUG_MEM + # memory debugging is not thread-safe yet + ifneq ("@DMEVENTD@", "yes") + DEFS += -DDEBUG_MEM + endif endif ifeq ("@INTL@", "yes") diff -rupN LVM2.2.02.58//man/cmirrord.8.in LVM2.2.02.61//man/cmirrord.8.in --- LVM2.2.02.58//man/cmirrord.8.in 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//man/cmirrord.8.in 2010-01-23 03:18:17.000000000 +0530 @@ -0,0 +1,30 @@ +.TH CMIRRORD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*- +.SH NAME +cmirrord \- cluster mirror log daemon + +.SH SYNOPSIS +.B cmirrord + +.SH DESCRIPTION +cmirrord is the daemon that tracks mirror log information in a cluster. +It is specific to device-mapper based mirrors (and by extension, LVM +cluster mirrors). Cluster mirrors are not possible without this daemon +running. + +This daemon relies on the cluster infrastructure provided by the +Cluster MANager (CMAN), which must be set up and running in order for +cmirrord to function. (The cluster infrastructure is also required for +clvmd.) + +Output is logged via syslog. The USR1 signal can be issued to cmirrord +to gather current status information for debugging purposes. + +Once started, cmirrord will run until it is shutdown via INT signal. If +there are still active cluster mirrors, however, the signal will be +ignored. Active cluster mirrors should be shutdown before stopping the +cluster mirror log daemon. + +.SH SEE ALSO +.BR lvm (8) +.BR clvmd (8) +.BR cluster.conf (5) \ No newline at end of file diff -rupN LVM2.2.02.58//man/dmsetup.8.in LVM2.2.02.61//man/dmsetup.8.in --- LVM2.2.02.58//man/dmsetup.8.in 2010-01-08 01:15:12.000000000 +0530 +++ LVM2.2.02.61//man/dmsetup.8.in 2010-02-15 22:02:24.000000000 +0530 @@ -64,6 +64,11 @@ dmsetup \- low level logical volume mana .B dmsetup mknodes .I [device_name] .br +.B dmsetup udevcreatecookie +.br +.B dmsetup udevreleasecookie +.I [cookie] +.br .B dmsetup udevflags .I cookie .br @@ -127,6 +132,9 @@ Tell the kernel not to supply the open r .IP \fB--notable .br When creating a device, don't load any table. +.IP \fB--udevcookie\ \fIcookie +.br +Use cookie for udev synchronisation. .IP \fB--noudevrules Do not allow udev to manage nodes for devices in device-mapper directory. .br @@ -315,6 +323,26 @@ is displayed. .br Displays the names and versions of the currently-loaded targets. .br +.IP \fBudevcreatecookie +.br +Creates a new cookie to synchronize actions with udev processing. +The output is a cookie value. Normally we don't need to create cookies since +dmsetup creates and destroys them for each action automatically. However, we can +generate one explicitly to group several actions together and use only one +cookie instead. We can define a cookie to use for each relevant command by using +--udevcookie option. Alternatively, we can export this value into the environment +of the dmsetup process as DM_UDEV_COOKIE variable and it will be used automatically +with all subsequent commands until it is unset. +Invoking this command will create system-wide semaphore that needs to be cleaned +up explicitly by calling udevreleasecookie command. +.br +.IP \fBudevreleasecookie +.I [cookie] +.br +Waits for all pending udev processing bound to given cookie value and clean up +the cookie with underlying semaphore. If the cookie is not given directly, +the command will try to use a value defined by DM_UDEV_COOKIE environment variable. +.br .IP \fBudevflags .I cookie .br @@ -412,6 +440,10 @@ for creating devices with holes in them. \fBDM_DEV_DIR\fP The device directory name. Defaults to "/dev" and must be an absolute path. +.TP +\fBDM_UDEV_COOKIE\fP +A cookie to use for all relevant commands to synchronize with udev processing. +It is an alternative to using --udevcookie option. .SH AUTHORS Original version: Joe Thornber (thornber@sistina.com) diff -rupN LVM2.2.02.58//man/lvconvert.8.in LVM2.2.02.61//man/lvconvert.8.in --- LVM2.2.02.58//man/lvconvert.8.in 2010-01-13 07:25:05.000000000 +0530 +++ LVM2.2.02.61//man/lvconvert.8.in 2010-02-06 04:14:37.000000000 +0530 @@ -39,7 +39,7 @@ OriginalLogicalVolume[Path] SnapshotLogi [\-h|\-?|\-\-help] [\-v|\-\-verbose] [\-\-version] -SnapshotLogicalVolume[Path] +SnapshotLogicalVolume[Path]... .br .br @@ -141,7 +141,9 @@ filesystem, is deferred until the next t When merging starts, the resulting logical volume will have the origin's name, minor number and UUID. While the merge is in progress, reads or writes to the origin appear as they were directed to the snapshot being merged. When the -merge finishes, the merged snapshot is removed. +merge finishes, the merged snapshot is removed. Multiple snapshots may +be specified on the commandline or a @tag may be used to specify +multiple snapshots be merged to their respective origin. .br @@ -199,6 +201,14 @@ extents from /dev/sda. .br merges "vg00/lvol1_snap" into its origin. +.br +"lvconvert --merge @some_tag" +.br +If vg00/lvol1, vg00/lvol2, and vg00/lvol3 are all tagged with "some_tag" +each snapshot logical volume will be merged serially, e.g.: vg00/lvol1, +then vg00/lvol2, then vg00/lvol3. If --background were used it would start +all snapshot logical volume merges in parallel. + .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), diff -rupN LVM2.2.02.58//man/lvcreate.8.in LVM2.2.02.61//man/lvcreate.8.in --- LVM2.2.02.58//man/lvcreate.8.in 2010-01-12 19:30:51.000000000 +0530 +++ LVM2.2.02.61//man/lvcreate.8.in 2010-02-03 09:28:08.000000000 +0530 @@ -22,7 +22,7 @@ VolumeGroupName [PhysicalVolumePath[:PE[ .br .B lvcreate -{\-l|\-\-extents LogicalExtentsNumber[%{VG|FREE}] | +{\-l|\-\-extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] | \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]} [\-c|\-\-chunksize ChunkSize] [\-\-noudevsync] @@ -70,14 +70,16 @@ StripeSize must be 2^n (n = 2 to 9) for For metadata in LVM2 format, the stripe size may be a larger power of 2 but must not exceed the physical extent size. .TP -.I \-l, \-\-extents LogicalExtentsNumber[%{VG|PVS|FREE}] +.I \-l, \-\-extents LogicalExtentsNumber[%{VG|PVS|FREE|ORIGIN}] Gives the number of logical extents to allocate for the new logical volume. -This can also be expressed as a percentage of the total space -in the Volume Group with the suffix %VG, of the remaining -free space in the Volume Group with the suffix %FREE, or -of the remaining free space for the specified PhysicalVolume(s) -with the suffix %PVS, +The number can also be expressed as a percentage of the total space +in the Volume Group with the suffix %VG, as a percentage of the +remaining free space in the Volume Group with the suffix %FREE, as a +percentage of the remaining free space for the specified +PhysicalVolume(s) with the suffix %PVS, or (for a snapshot) as a +percentage of the total space in the Origin Logical Volume with the +suffix %ORIGIN. .TP .I \-L, \-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE] Gives the size to allocate for the new logical volume. diff -rupN LVM2.2.02.58//man/lvextend.8.in LVM2.2.02.61//man/lvextend.8.in --- LVM2.2.02.58//man/lvextend.8.in 2009-08-10 22:53:04.000000000 +0530 +++ LVM2.2.02.61//man/lvextend.8.in 2010-02-03 09:28:08.000000000 +0530 @@ -7,7 +7,7 @@ lvextend \- extend the size of a logical [\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help] [\-\-noudevsync] [\-i|\-\-stripes Stripes [\-I|\-\-stripesize StripeSize]] -{\-l|\-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE}] | +{\-l|\-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] | \-L|\-\-size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]} [\-t|\-\-test] [\-v|\-\-verbose] LogicalVolumePath [PhysicalVolumePath[:PE[-PE]]...] @@ -29,7 +29,7 @@ It will continue irrespective of any pos in the background. You should only use this if udev is not running or has rules that ignore the devices LVM2 creates. .TP -.I \-l, \-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE}] +.I \-l, \-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] Extend or set the logical volume size in units of logical extents. With the + sign the value is added to the actual size of the logical volume and without it, the value is taken as an absolute one. @@ -37,8 +37,9 @@ The number can also be expressed as a pe in the Volume Group with the suffix %VG, relative to the existing size of the Logical Volume with the suffix %LV, of the remaining free space for the specified PhysicalVolume(s) with the suffix %PVS, -or as a percentage of the remaining free space in the Volume Group -with the suffix %FREE. +as a percentage of the remaining free space in the Volume Group +with the suffix %FREE, or (for a snapshot) as a percentage of the total +space in the Origin Logical Volume with the suffix %ORIGIN. .TP .I \-L, \-\-size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE] Extend or set the logical volume size in units of megabytes. diff -rupN LVM2.2.02.58//man/lvreduce.8.in LVM2.2.02.61//man/lvreduce.8.in --- LVM2.2.02.58//man/lvreduce.8.in 2009-08-04 13:39:52.000000000 +0530 +++ LVM2.2.02.61//man/lvreduce.8.in 2010-02-03 09:28:08.000000000 +0530 @@ -6,7 +6,7 @@ lvreduce \- reduce the size of a logical [\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-f|\-\-force] [\-h|\-?|\-\-help] [\-\-noudevsync] -{\-l|\-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}] | +{\-l|\-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE|ORIGIN}] | \-L|\-\-size [\-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]} [\-t|\-\-test] [\-v|\-\-verbose] LogicalVolume[Path] @@ -44,15 +44,17 @@ It will continue irrespective of any pos in the background. You should only use this if udev is not running or has rules that ignore the devices LVM2 creates. .TP -.I \-l, \-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}] +.I \-l, \-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE|ORIGIN}] Reduce or set the logical volume size in units of logical extents. With the - sign the value will be subtracted from -the logical volume's actual size and without it the will be taken as -an absolute size. +the logical volume's actual size and without it the value will be taken +as an absolute size. The number can also be expressed as a percentage of the total space -in the Volume Group with the suffix %VG or relative to the existing -size of the Logical Volume with the suffix %LV or as a percentage of the remaining -free space in the Volume Group with the suffix %FREE. +in the Volume Group with the suffix %VG, relative to the existing +size of the Logical Volume with the suffix %LV, as a percentage of the +remaining free space in the Volume Group with the suffix %FREE, or (for +a snapshot) as a percentage of the total space in the Origin Logical +Volume with the suffix %ORIGIN. .TP .I \-L, \-\-size [\-]LogicalVolumeSize[bBsSkKmMgGtTpPeE] Reduce or set the logical volume size in units of megabytes. diff -rupN LVM2.2.02.58//man/lvresize.8.in LVM2.2.02.61//man/lvresize.8.in --- LVM2.2.02.58//man/lvresize.8.in 2009-08-10 22:53:04.000000000 +0530 +++ LVM2.2.02.61//man/lvresize.8.in 2010-02-03 09:28:08.000000000 +0530 @@ -7,7 +7,7 @@ lvresize \- resize a logical volume [\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help] [\-\-noudevsync] [\-i|\-\-stripes Stripes [\-I|\-\-stripesize StripeSize]] -{\-l|\-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE}] | +{\-l|\-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] | \-L|\-\-size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]} [\-t|\-\-test] [\-v|\-\-verbose] LogicalVolumePath [PhysicalVolumePath[:PE[-PE]]...] @@ -33,7 +33,7 @@ It will continue irrespective of any pos in the background. You should only use this if udev is not running or has rules that ignore the devices LVM2 creates. .TP -.I \-l, \-\-extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE}] +.I \-l, \-\-extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] Change or set the logical volume size in units of logical extents. With the + or - sign the value is added to or subtracted from the actual size of the logical volume and without it, the value is taken as an absolute one. @@ -41,8 +41,9 @@ The number can also be expressed as a pe in the Volume Group with the suffix %VG, relative to the existing size of the Logical Volume with the suffix %LV, as a percentage of the remaining free space of the PhysicalVolumes on the command line with the -suffix %PVS, or as a percentage of the remaining free space in the -Volume Group with the suffix %FREE. +suffix %PVS, as a percentage of the remaining free space in the +Volume Group with the suffix %FREE, or (for a snapshot) as a percentage +of the total space in the Origin Logical Volume with the suffix %ORIGIN. .TP .I \-L, \-\-size [+|-]LogicalVolumeSize[bBsSkKmMgGtTpPeE] Change or set the logical volume size in units of megabytes. diff -rupN LVM2.2.02.58//man/Makefile.in LVM2.2.02.61//man/Makefile.in --- LVM2.2.02.58//man/Makefile.in 2009-10-03 00:40:36.000000000 +0530 +++ LVM2.2.02.61//man/Makefile.in 2010-01-19 07:34:34.000000000 +0530 @@ -32,7 +32,16 @@ MAN8=lvchange.8 lvconvert.8 lvcreate.8 l vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \ vgimport.8 vgimportclone.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 \ vgrename.8 vgs.8 vgscan.8 vgsplit.8 $(FSADMMAN) -MAN8CLUSTER=clvmd.8 + +ifneq ("@CLVMD@", "none") + MAN8CLUSTER=clvmd.8 +else + MAN8CLUSTER= +endif +ifeq ("@BUILD_CMIRRORD@", "yes") + MAN8CLUSTER+=cmirrord.8 +endif + MAN8DM=dmsetup.8 MAN5DIR=${mandir}/man5 MAN8DIR=${mandir}/man8 diff -rupN LVM2.2.02.58//scripts/cmirrord_init_red_hat.in LVM2.2.02.61//scripts/cmirrord_init_red_hat.in --- LVM2.2.02.58//scripts/cmirrord_init_red_hat.in 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//scripts/cmirrord_init_red_hat.in 2010-01-22 21:49:38.000000000 +0530 @@ -0,0 +1,106 @@ +#!/bin/bash +# +# chkconfig: - 22 78 +# description: Starts and stops cmirrord +# +# For Red-Hat-based distributions such as Fedora, RHEL, CentOS. +# +### BEGIN INIT INFO +# Provides: cmirrord +# Required-Start: $network $time $local_fs +# Required-Stop: $network $time $local_fs +# Short-Description: Starts and stops cmirrord +# Description: Starts and stops the cluster mirror log daemon +### END INIT INFO + +. /etc/init.d/functions + +DAEMON=cmirrord + +LOCK_FILE="/var/lock/subsys/$DAEMON" + +start() +{ + if ! pidof $DAEMON > /dev/null + then + echo -n "Starting $DAEMON: " + daemon $DAEMON + rtrn=$? + echo + fi + + return $rtrn +} + +stop() +{ + echo -n "Stopping $DAEMON:" + killproc $DAEMON -TERM + rtrn=$? + echo + + return $rtrn +} + +wait_for_finish() +{ + count=0 + + while [ "$count" -le 10 -a -n "`pidof $DAEMON`" ] + do + sleep 1 + count=$((count + 1)) + done + + if [ `pidof $DAEMON` ] + then + return 1 + else + return 0 + fi +} + +cmirror_status() +{ + status $DAEMON +} + +rtrn=1 + +# See how we were called. +case "$1" in + start) + start + rtrn=$? + [ $rtrn = 0 ] && touch $LOCK_FILE + ;; + + stop) + stop + rtrn=$? + [ $rtrn = 0 ] && rm -f $LOCK_FILE + ;; + + restart) + if stop + then + wait_for_finish + start + fi + rtrn=$? + ;; + + status) + cmirror_status + rtrn=$? + if [ $rtrn -eq 0 ]; then + echo "cmirror is running." + fi + ;; + + *) + echo $"Usage: $0 {start|stop|restart|status}" + ;; +esac + +exit $rtrn diff -rupN LVM2.2.02.58//scripts/Makefile.in LVM2.2.02.61//scripts/Makefile.in --- LVM2.2.02.58//scripts/Makefile.in 2009-10-03 00:40:37.000000000 +0530 +++ LVM2.2.02.61//scripts/Makefile.in 2010-01-19 07:34:35.000000000 +0530 @@ -30,4 +30,4 @@ endif install_lvm2: install -DISTCLEAN_TARGETS += clvmd_init_red_hat lvm2_monitoring_init_red_hat +DISTCLEAN_TARGETS += clvmd_init_red_hat cmirrord_init_red_hat lvm2_monitoring_init_red_hat diff -rupN LVM2.2.02.58//test/api/test.c LVM2.2.02.61//test/api/test.c --- LVM2.2.02.58//test/api/test.c 2009-08-13 17:47:32.000000000 +0530 +++ LVM2.2.02.61//test/api/test.c 2010-02-14 08:53:07.000000000 +0530 @@ -450,8 +450,11 @@ static void _pvs_in_vg(char **argv, int } printf("PVs in VG %s:\n", lvm_vg_get_name(vg)); dm_list_iterate_items(pvl, pvs) { - printf("%s (%s): mda_count=%"PRIu64"\n", - lvm_pv_get_name(pvl->pv), lvm_pv_get_uuid(pvl->pv), + printf("%s (%s): size=%"PRIu64", free=%"PRIu64 + ", dev_size=%"PRIu64", mda_count=%"PRIu64"\n", + lvm_pv_get_name(pvl->pv), lvm_pv_get_uuid(pvl->pv), + lvm_pv_get_size(pvl->pv), lvm_pv_get_free(pvl->pv), + lvm_pv_get_dev_size(pvl->pv), lvm_pv_get_mda_count(pvl->pv)); } } diff -rupN LVM2.2.02.58//test/Makefile.in LVM2.2.02.61//test/Makefile.in --- LVM2.2.02.58//test/Makefile.in 2010-01-11 21:18:50.000000000 +0530 +++ LVM2.2.02.61//test/Makefile.in 2010-02-15 22:00:13.000000000 +0530 @@ -31,8 +31,7 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_P T = $(wildcard $(srcdir)/t-*.sh) ifeq ("@UDEV_SYNC@", "yes") -dm_udev_disable_checking = 1 -lvm_udev_disable_checking = 1 +dm_udev_synchronisation = 1 endif ifeq ("@APPLIB@", "yes") @@ -61,8 +60,7 @@ init.sh: $(srcdir)/Makefile.in $(srcdir) echo 'abs_srcdir=$(abs_srcdir)' >> $@-t echo 'abs_builddir=$(abs_builddir)' >> $@-t echo 'export PATH' >> $@-t - echo 'export DM_UDEV_DISABLE_CHECKING=$(dm_udev_disable_checking)' >> $@-t - echo 'export LVM_UDEV_DISABLE_CHECKING=$(lvm_udev_disable_checking)' >> $@-t + echo 'export DM_UDEV_SYNCHRONISATION=$(dm_udev_synchronisation)' >> $@-t chmod a-w $@-t mv $@-t $@ if test "$(srcdir)" != "."; then cp $(srcdir)/test-utils.sh \ diff -rupN LVM2.2.02.58//test/test-utils.sh LVM2.2.02.61//test/test-utils.sh --- LVM2.2.02.58//test/test-utils.sh 2010-01-11 21:13:19.000000000 +0530 +++ LVM2.2.02.61//test/test-utils.sh 2010-02-15 22:00:13.000000000 +0530 @@ -24,7 +24,20 @@ STACKTRACE() { echo "$i ${FUNC}() called from ${BASH_SOURCE[$i]}:${BASH_LINENO[$i]}" i=$(($i + 1)); done -} +} + +init_udev_transaction() { + if test "$DM_UDEV_SYNCHRONISATION" = 1; then + export DM_UDEV_COOKIE=$(dmsetup udevcreatecookie) + fi +} + +finish_udev_transaction() { + if test "$DM_UDEV_SYNCHRONISATION" = 1; then + dmsetup udevreleasecookie + unset DM_UDEV_COOKIE + fi +} teardown() { echo $LOOP @@ -32,16 +45,26 @@ teardown() { test -n "$PREFIX" && { rm -rf $G_root_/dev/$PREFIX* + + init_udev_transaction while dmsetup table | grep -q ^$PREFIX; do for s in `dmsetup table | grep ^$PREFIX| awk '{ print substr($1,1,length($1)-1) }'`; do - dmsetup resume $s 2>/dev/null > /dev/null || true dmsetup remove $s 2>/dev/null > /dev/null || true done done + finish_udev_transaction + } - test -n "$LOOP" && losetup -d $LOOP - test -n "$LOOPFILE" && rm -f $LOOPFILE + # NOTE: SCSI_DEBUG_DEV test must come before the LOOP test because + # prepare_scsi_debug_dev() also sets LOOP to short-circuit prepare_loop() + if [ -n "$SCSI_DEBUG_DEV" ] ; then + modprobe -r scsi_debug + else + test -n "$LOOP" && losetup -d $LOOP + test -n "$LOOPFILE" && rm -f $LOOPFILE + fi + unset devs # devs is set in prepare_devs() } teardown_() { @@ -52,7 +75,6 @@ teardown_() { make_ioerror() { echo 0 10000000 error | dmsetup create ioerror - dmsetup resume ioerror ln -s $G_dev_/mapper/ioerror $G_dev_/ioerror } @@ -94,6 +116,68 @@ prepare_loop() { exit 1 # should not happen } +get_sd_devs_() +{ + # prepare_scsi_debug_dev() requires the ability to lookup + # the scsi_debug created SCSI device in /dev/ + local _devs=$(lvmdiskscan --config 'devices { filter = [ "a|/dev/sd.*|", "r|.*|" ] scan = "/dev/" }' | grep /dev/sd | awk '{ print $1 }') + echo $_devs +} + +# A drop-in replacement for prepare_loop() that uses scsi_debug to create +# a ramdisk-based SCSI device upon which all LVM devices will be created +# - scripts must take care not to use a DEV_SIZE that will enduce OOM-killer +prepare_scsi_debug_dev() +{ + local DEV_SIZE="$1" + shift + local SCSI_DEBUG_PARAMS="$@" + + test -n "$SCSI_DEBUG_DEV" && return 0 + trap 'aux teardown_' EXIT # don't forget to clean up + trap 'set +vex; STACKTRACE; set -vex' ERR + + # Skip test if awk isn't available (required for get_sd_devs_) + which awk || exit 200 + + # Skip test if scsi_debug module is unavailable or is already in use + modinfo scsi_debug || exit 200 + lsmod | grep -q scsi_debug && exit 200 + + # Create the scsi_debug device and determine the new scsi device's name + local devs_before=`get_sd_devs_` + # NOTE: it will _never_ make sense to pass num_tgts param; + # last param wins.. so num_tgts=1 is imposed + modprobe scsi_debug dev_size_mb=$DEV_SIZE $SCSI_DEBUG_PARAMS num_tgts=1 + sleep 2 # allow for async Linux SCSI device registration + + local devs_after=`get_sd_devs_` + for dev1 in $devs_after; do + FOUND=0 + for dev2 in $devs_before; do + if [ "$dev1" = "$dev2" ]; then + FOUND=1 + break + fi + done + if [ $FOUND -eq 0 ]; then + # Create symlink to scsi_debug device in $G_dev_ + SCSI_DEBUG_DEV=$G_dev_/$(basename $dev1) + # Setting $LOOP provides means for prepare_devs() override + LOOP=$SCSI_DEBUG_DEV + ln -snf $dev1 $SCSI_DEBUG_DEV + return 0 + fi + done + exit 1 # should not happen +} + +cleanup_scsi_debug_dev() +{ + aux teardown + unset SCSI_DEBUG_DEV +} + prepare_devs() { local n="$1" test -z "$n" && n=3 @@ -112,6 +196,7 @@ prepare_devs() { local size=$(($loopsz/$n)) + init_udev_transaction for i in `seq 1 $n`; do local name="${PREFIX}$pvname$i" local dev="$G_dev_/mapper/$name" @@ -119,8 +204,8 @@ prepare_devs() { devs="$devs $dev" echo 0 $size linear $LOOP $((($i-1)*$size)) > $name.table dmsetup create $name $name.table - dmsetup resume $name done + finish_udev_transaction # set up some default names vg=${PREFIX}vg @@ -134,6 +219,8 @@ prepare_devs() { } disable_dev() { + + init_udev_transaction for dev in "$@"; do # first we make the device inaccessible echo 0 10000000 error | dmsetup load $dev @@ -141,14 +228,19 @@ disable_dev() { # now let's try to get rid of it if it's unused #dmsetup remove $dev done + finish_udev_transaction + } enable_dev() { + + init_udev_transaction for dev in "$@"; do local name=`echo "$dev" | sed -e 's,.*/,,'` dmsetup create $name $name.table || dmsetup load $name $name.table dmsetup resume $dev done + finish_udev_transaction } backup_dev() { diff -rupN LVM2.2.02.58//test/t-mirror-names.sh LVM2.2.02.61//test/t-mirror-names.sh --- LVM2.2.02.58//test/t-mirror-names.sh 2008-11-10 18:11:52.000000000 +0530 +++ LVM2.2.02.61//test/t-mirror-names.sh 2010-01-23 03:29:42.000000000 +0530 @@ -122,7 +122,7 @@ prepare_lvs_ #COMM "converting mirror names is ${lv1}_mimagetmp_2" lvcreate -l2 -m1 -n $lv1 $vg -lvconvert -m+1 -i1000 -b $vg/$lv1 +lvconvert -m+1 -i+1000 -b $vg/$lv1 convlv=$(lv_convert_lv_ "$vg/$lv1") test "$convlv" = "$lv1"_mimagetmp_2 lv_devices_ $vg/$lv1 "$convlv" "$lv1"_mimage_2 diff -rupN LVM2.2.02.58//test/t-pvcreate-operation-md.sh LVM2.2.02.61//test/t-pvcreate-operation-md.sh --- LVM2.2.02.58//test/t-pvcreate-operation-md.sh 2009-09-30 21:43:53.000000000 +0530 +++ LVM2.2.02.61//test/t-pvcreate-operation-md.sh 2010-01-19 21:29:34.000000000 +0530 @@ -14,7 +14,9 @@ which sfdisk || exit 200 which perl || exit 200 which awk || exit 200 which cut || exit 200 -test -f /proc/mdstat || exit 200 + +test -f /proc/mdstat && grep -q raid0 /proc/mdstat || \ +modprobe raid0 || exit 200 . ./test-utils.sh @@ -66,7 +68,8 @@ check_pv_field_ $mddev pe_start $pv_alig linux_minor=$(echo `uname -r` | cut -d'.' -f3 | cut -d'-' -f1) # Test newer topology-aware alignment detection -if [ $linux_minor -gt 31 ]; then +# - first added to 2.6.31 but not "reliable" until 2.6.33 +if [ $linux_minor -ge 33 ]; then pv_align="256.00k" pvcreate --metadatasize 128k \ --config 'devices { md_chunk_alignment=0 }' $mddev @@ -74,7 +77,7 @@ if [ $linux_minor -gt 31 ]; then fi # partition MD array directly, depends on blkext in Linux >= 2.6.28 -if [ $linux_minor -gt 27 ]; then +if [ $linux_minor -ge 28 ]; then # create one partition sfdisk $mddev <= 2.6.31 sysfs_alignment_offset=/sys/dev/block/${mddev_maj_min}/${base_mddev_p}/alignment_offset - [ -f $sysfs_alignment_offset ] && \ + [ -f $sysfs_alignment_offset -a $linux_minor -ge 33 ] && \ alignment_offset=`cat $sysfs_alignment_offset` || \ alignment_offset=0 diff -rupN LVM2.2.02.58//test/t-snapshot-merge.sh LVM2.2.02.61//test/t-snapshot-merge.sh --- LVM2.2.02.58//test/t-snapshot-merge.sh 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//test/t-snapshot-merge.sh 2010-02-06 04:14:38.000000000 +0530 @@ -0,0 +1,102 @@ +#!/bin/sh +# Copyright (C) 2010 Red Hat, Inc. All rights reserved. +# +# 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 +set -xv + +which mkfs.ext3 || exit 200 + +. ./test-utils.sh + +lvdev_() +{ + echo "$G_dev_/$1/$2" +} + +snap_lv_name_() { + echo ${1}_snap +} + +setup_merge() { + local VG_NAME=$1 + local LV_NAME=$2 + local NUM_EXTRA_SNAPS="$3" + test -z "$NUM_EXTRA_SNAPS" && NUM_EXTRA_SNAPS=0 + local BASE_SNAP_LV_NAME=$(snap_lv_name_ $LV_NAME) + + lvcreate -n $LV_NAME -l 50%FREE $VG_NAME + lvcreate -s -n $BASE_SNAP_LV_NAME -l 20%FREE ${VG_NAME}/${LV_NAME} + mkfs.ext3 $(lvdev_ $VG_NAME $LV_NAME) + + if [ $NUM_EXTRA_SNAPS -gt 0 ]; then + for i in `seq 1 $NUM_EXTRA_SNAPS`; do + lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%FREE ${VG_NAME}/${LV_NAME} + done + fi +} + +aux prepare_vg 1 100 + + +# full merge of a single LV +setup_merge $vg $lv1 + +# now that snapshot LV is created: test if snapshot-merge target is available +$(dmsetup targets | grep -q snapshot-merge) || exit 200 + +lvs -a +lvconvert --merge $vg/$(snap_lv_name_ $lv1) +lvremove -f $vg/$lv1 + + +# "onactivate merge" test -- refresh LV while FS is still mounted; +# verify snapshot-origin target is still being used +setup_merge $vg $lv1 +lvs -a +mkdir test_mnt +mount $(lvdev_ $vg $lv1) test_mnt +lvconvert --merge $vg/$(snap_lv_name_ $lv1) +lvchange --refresh $vg/$lv1 +umount test_mnt +rm -r test_mnt +# an active merge uses the "snapshot-merge" target +dmsetup table ${vg}-${lv1} | grep -q " snapshot-origin " +test $? = 0 +lvremove -f $vg/$lv1 + + +# test multiple snapshot merge; tests copy out that is driven by merge +setup_merge $vg $lv1 1 +lvs -a +lvconvert --merge $vg/$(snap_lv_name_ $lv1) +lvremove -f $vg/$lv1 + +# test merging multiple snapshots that share the same tag +setup_merge $vg $lv1 +setup_merge $vg $lv2 +lvs -a +lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1) +lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2) +lvconvert --merge @this_is_a_test +lvs | not grep $(snap_lv_name_ $lv1) +lvs | not grep $(snap_lv_name_ $lv2) +lvremove -f $vg/$lv1 +lvremove -f $vg/$lv2 + +# FIXME following tests would need to poll merge progress, via periodic lvs? +# Background processes don't lend themselves to lvm testsuite... + +# test: onactivate merge of a single lv + +# test: do onactivate, deactivate the origin LV, reactivate the LV, merge should resume + +# test: multiple onactivate merge + + +vgremove -f "$vg" diff -rupN LVM2.2.02.58//test/t-topology-support.sh LVM2.2.02.61//test/t-topology-support.sh --- LVM2.2.02.58//test/t-topology-support.sh 1970-01-01 05:30:00.000000000 +0530 +++ LVM2.2.02.61//test/t-topology-support.sh 2010-01-19 22:36:50.000000000 +0530 @@ -0,0 +1,101 @@ +# Copyright (C) 2010 Red Hat, Inc. All rights reserved. +# +# 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 + +which mkfs.ext3 || exit 200 + +# Get linux minor version +linux_minor=$(echo `uname -r` | cut -d'.' -f3 | cut -d'-' -f1) + +test $linux_minor -ge 31 || exit 200 + +. ./test-utils.sh + +check_logical_block_size() +{ + local DEV_=$1 + local LOGICAL_BS=$2 + # Verify logical_block_size - requires Linux >= 2.6.31 + SYSFS_LOGICAL_BLOCK_SIZE=`echo /sys/block/$(basename $DEV_)/queue/logical_block_size` + if [ -f "$SYSFS_LOGICAL_BLOCK_SIZE" ] ; then + ACTUAL_LOGICAL_BLOCK_SIZE=`cat $SYSFS_LOGICAL_BLOCK_SIZE` + test $ACTUAL_LOGICAL_BLOCK_SIZE = $LOGICAL_BS + fi +} + +lvdev_() +{ + echo "$G_dev_/$1/$2" +} + +test_snapshot_mount() +{ + lvcreate -L 16M -n $lv1 $vg $dev1 + mkfs.ext3 $(lvdev_ $vg $lv1) + mkdir test_mnt + mount $(lvdev_ $vg $lv1) test_mnt + lvcreate -L 16M -n $lv2 -s $vg/$lv1 + umount test_mnt + # mount the origin + mount $(lvdev_ $vg $lv1) test_mnt + umount test_mnt + # mount the snapshot + mount $(lvdev_ $vg $lv2) test_mnt + umount test_mnt + rm -r test_mnt + vgchange -an $vg + lvremove -f $vg/$lv2 + lvremove -f $vg/$lv1 +} + +# FIXME add more topology-specific tests and validation (striped LVs, etc) + +NUM_DEVS=1 +PER_DEV_SIZE=33 +DEV_SIZE=$(($NUM_DEVS*$PER_DEV_SIZE)) + +# --------------------------------------------- +# Create "desktop-class" 4K drive +# (logical_block_size=512, physical_block_size=4096, alignment_offset=0): +LOGICAL_BLOCK_SIZE=512 +prepare_scsi_debug_dev $DEV_SIZE \ + sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3 +check_logical_block_size $SCSI_DEBUG_DEV $LOGICAL_BLOCK_SIZE + +aux prepare_vg $NUM_DEVS $PER_DEV_SIZE +test_snapshot_mount +vgremove $vg + +cleanup_scsi_debug_dev + +# --------------------------------------------- +# Create "desktop-class" 4K drive w/ 63-sector DOS partition compensation +# (logical_block_size=512, physical_block_size=4096, alignment_offset=3584): +LOGICAL_BLOCK_SIZE=512 +prepare_scsi_debug_dev $DEV_SIZE \ + sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3 lowest_aligned=7 +check_logical_block_size $SCSI_DEBUG_DEV $LOGICAL_BLOCK_SIZE + +aux prepare_vg $NUM_DEVS $PER_DEV_SIZE +test_snapshot_mount +vgremove $vg + +cleanup_scsi_debug_dev + +# --------------------------------------------- +# Create "enterprise-class" 4K drive +# (logical_block_size=4096, physical_block_size=4096, alignment_offset=0): +LOGICAL_BLOCK_SIZE=4096 +prepare_scsi_debug_dev $DEV_SIZE \ + sector_size=$LOGICAL_BLOCK_SIZE +check_logical_block_size $SCSI_DEBUG_DEV $LOGICAL_BLOCK_SIZE + +aux prepare_vg $NUM_DEVS $PER_DEV_SIZE +test_snapshot_mount +vgremove $vg diff -rupN LVM2.2.02.58//tools/commands.h LVM2.2.02.61//tools/commands.h --- LVM2.2.02.58//tools/commands.h 2010-01-13 07:15:16.000000000 +0530 +++ LVM2.2.02.61//tools/commands.h 2010-02-03 09:28:08.000000000 +0530 @@ -151,7 +151,7 @@ xx(lvcreate, "\t[-d|--debug]\n" "\t[-h|-?|--help]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" - "\t{-l|--extents LogicalExtentsNumber |\n" + "\t{-l|--extents LogicalExtentsNumber[%{VG|PVS|FREE}] |\n" "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n" "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n" @@ -178,7 +178,7 @@ xx(lvcreate, "\t[-d|--debug]\n" "\t[-h|-?|--help]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" - "\t{-l|--extents LogicalExtentsNumber[%{VG|LV|PVS|FREE}] |\n" + "\t{-l|--extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |\n" "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n" "\t[-n|--name LogicalVolumeName]\n" @@ -249,7 +249,7 @@ xx(lvextend, "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" - "\t{-l|--extents [+]LogicalExtentsNumber[%{VG|PVS|FREE}] |\n" + "\t{-l|--extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n" "\t -L|--size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-m|--mirrors Mirrors]\n" "\t[-n|--nofsck]\n" @@ -320,7 +320,7 @@ xx(lvreduce, "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" - "\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n" + "\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE|ORIGIN}] |\n" "\t -L|--size [-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-n|--nofsck]\n" "\t[--noudevsync]\n" @@ -376,7 +376,7 @@ xx(lvresize, "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" - "\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE}] |\n" + "\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n" "\t -L|--size [+|-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-n|--nofsck]\n" "\t[--noudevsync]\n" diff -rupN LVM2.2.02.58//tools/dmsetup.c LVM2.2.02.61//tools/dmsetup.c --- LVM2.2.02.58//tools/dmsetup.c 2010-01-14 15:45:23.000000000 +0530 +++ LVM2.2.02.61//tools/dmsetup.c 2010-02-15 21:51:34.000000000 +0530 @@ -45,6 +45,10 @@ # include # include # include +#ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE +# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE +# include +#endif #endif /* FIXME Unused so far */ @@ -96,7 +100,10 @@ extern char *optarg; #define ARGS_MAX 256 #define LOOP_TABLE_SIZE (PATH_MAX + 255) -#define DEFAULT_DM_DEV_DIR "/dev" +#define DEFAULT_DM_DEV_DIR "/dev/" + +#define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR" +#define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE" /* FIXME Should be imported */ #ifndef DM_MAX_TYPE_NAME @@ -127,6 +134,7 @@ enum { NOLOCKFS_ARG, NOOPENCOUNT_ARG, NOTABLE_ARG, + UDEVCOOKIE_ARG, NOUDEVRULES_ARG, NOUDEVSYNC_ARG, OPTIONS_ARG, @@ -165,6 +173,8 @@ static char *_table; static char *_target; static char *_command; static uint32_t _read_ahead_flags; +static uint32_t _udev_cookie; +static int _udev_only; static struct dm_tree *_dtree; static struct dm_report *_report; static report_type_t _report_type; @@ -611,6 +621,12 @@ static int _create(int argc, char **argv udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; + if (_udev_cookie) { + cookie = _udev_cookie; + if (_udev_only) + udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; + } + if (!dm_task_set_cookie(dmt, &cookie, udev_flags) || !dm_task_run(dmt)) goto out; @@ -621,7 +637,8 @@ static int _create(int argc, char **argv r = _display_info(dmt); out: - (void) dm_udev_wait(cookie); + if (!_udev_cookie) + (void) dm_udev_wait(cookie); dm_task_destroy(dmt); return r; @@ -654,6 +671,12 @@ static int _rename(int argc, char **argv udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; + if (_udev_cookie) { + cookie = _udev_cookie; + if (_udev_only) + udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; + } + if (!dm_task_set_cookie(dmt, &cookie, udev_flags) || !dm_task_run(dmt)) goto out; @@ -661,7 +684,8 @@ static int _rename(int argc, char **argv r = 1; out: - (void) dm_udev_wait(cookie); + if (!_udev_cookie) + (void) dm_udev_wait(cookie); dm_task_destroy(dmt); return r; @@ -791,7 +815,7 @@ static int _splitname(int argc, char **a return r; } -static uint32_t _get_cookie_value(char *str_value) +static uint32_t _get_cookie_value(const char *str_value) { unsigned long int value; char *p; @@ -817,7 +841,8 @@ static int _udevflags(int args, char **a "DISABLE_DISK_RULES", "DISABLE_OTHER_RULES", "LOW_PRIORITY", - 0, 0, 0}; + "DISABLE_LIBRARY_FALLBACK", + 0, 0}; if (!(cookie = _get_cookie_value(argv[1]))) return 0; @@ -872,6 +897,22 @@ static int _udevcomplete(int argc, char #ifndef UDEV_SYNC_SUPPORT static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable."; +static int _udevcreatecookie(int argc, char **argv, + void *data __attribute((unused))) +{ + log_error(_cmd_not_supported); + + return 0; +} + +static int _udevreleasecookie(int argc, char **argv, + void *data __attribute((unused))) +{ + log_error(_cmd_not_supported); + + return 0; +} + static int _udevcomplete_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused))) { log_error(_cmd_not_supported); @@ -887,6 +928,102 @@ static int _udevcookies(int argc __attri } #else /* UDEV_SYNC_SUPPORT */ +static int _set_up_udev_support(const char *dev_dir) +{ +#ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE + struct udev *udev; + const char *udev_dev_dir; + size_t udev_dev_dir_len; + int dirs_diff; +#endif + const char *env; + + if (_switches[NOUDEVSYNC_ARG]) + dm_udev_set_sync_support(0); + + if (!_udev_cookie) { + env = getenv(DM_UDEV_COOKIE_ENV_VAR_NAME); + if (env && *env && (_udev_cookie = _get_cookie_value(env))) + log_debug("Using udev transaction 0x%08" PRIX32 + " defined by %s environment variable.", + _udev_cookie, + DM_UDEV_COOKIE_ENV_VAR_NAME); + } + else if (_switches[UDEVCOOKIE_ARG]) + log_debug("Using udev transaction 0x%08" PRIX32 + " defined by --udevcookie option.", + _udev_cookie); + +#ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE + if (!(udev = udev_new()) || + !(udev_dev_dir = udev_get_dev_path(udev)) || + !*udev_dev_dir) { + log_error("Could not get udev dev path."); + return 0; + } + udev_dev_dir_len = strlen(udev_dev_dir); + + /* + * Normally, there's always a fallback action by libdevmapper if udev + * has not done its job correctly, e.g. the nodes were not created. + * If using udev transactions by specifying existing cookie value, + * we need to disable node creation by libdevmapper completely, + * disabling any fallback actions, since any synchronisation happens + * at the end of the transaction only. We need to do this to prevent + * races between udev and libdevmapper but only in case udev "dev path" + * is the same as "dev path" used by libdevmapper. + */ + + /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */ + if (udev_dev_dir[udev_dev_dir_len - 1] != '/') + dirs_diff = strncmp(dev_dir, udev_dev_dir, udev_dev_dir_len); + else + dirs_diff = strcmp(dev_dir, udev_dev_dir); + + _udev_only = _udev_cookie && !dirs_diff; + + if (dirs_diff) { + log_debug("The path %s used for creating device nodes that is " + "set via DM_DEV_DIR environment variable differs from " + "the path %s that is used by udev. All warnings " + "about udev not working correctly while processing " + "particular nodes will be suppressed. These nodes " + "and symlinks will be managed in each directory " + "separately.", dev_dir, udev_dev_dir); + dm_udev_set_checking(0); + } + + udev_unref(udev); +#endif + return 1; +} + +static int _udevcreatecookie(int argc, char **argv, + void *data __attribute((unused))) +{ + uint32_t cookie; + + if (!dm_udev_create_cookie(&cookie)) + return 0; + + printf("0x%08" PRIX32 "\n", cookie); + + return 1; +} + +static int _udevreleasecookie(int argc, char **argv, + void *data __attribute((unused))) +{ + if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1]))) + return 0; + + if (!_udev_cookie) { + log_error("No udev transaction cookie given."); + return 0; + } + + return dm_udev_wait(_udev_cookie); +} static char _yes_no_prompt(const char *prompt, ...) { @@ -1059,6 +1196,12 @@ static int _simple(int task, const char udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; + if (_udev_cookie) { + cookie = _udev_cookie; + if (_udev_only) + udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; + } + if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags)) goto out; @@ -1068,7 +1211,7 @@ static int _simple(int task, const char r = _display_info(dmt); out: - if (udev_wait_flag) + if (!_udev_cookie && udev_wait_flag) (void) dm_udev_wait(cookie); dm_task_destroy(dmt); @@ -2559,6 +2702,8 @@ static struct command _commands[] = { {"table", "[] [--target ] [--showkeys]", 0, 1, _status}, {"wait", " []", 0, 2, _wait}, {"mknodes", "[]", 0, 1, _mknodes}, + {"udevcreatecookie", "", 0, 0, _udevcreatecookie}, + {"udevreleasecookie", "[]", 0, 1, _udevreleasecookie}, {"udevflags", "", 1, 1, _udevflags}, {"udevcomplete", "", 1, 1, _udevcomplete}, {"udevcomplete_all", "", 0, 0, _udevcomplete_all}, @@ -2577,7 +2722,7 @@ static void _usage(FILE *out) fprintf(out, "Usage:\n\n"); fprintf(out, "dmsetup [--version] [-v|--verbose [-v|--verbose ...]]\n" " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n" - " [--noudevrules] [--noudevsync] [-y|--yes]\n" + " [--udevcookie] [--noudevrules] [--noudevsync] [-y|--yes]\n" " [--readahead [+]|auto|none]\n" " [-c|-C|--columns] [-o ] [-O|--sort ]\n" " [--nameprefixes] [--noheadings] [--separator ]\n\n"); @@ -2812,6 +2957,8 @@ error: return 0; } + + static int _process_losetup_switches(const char *base, int *argc, char ***argv, const char *dev_dir) { @@ -2946,6 +3093,7 @@ static int _process_switches(int *argc, {"nolockfs", 0, &ind, NOLOCKFS_ARG}, {"noopencount", 0, &ind, NOOPENCOUNT_ARG}, {"notable", 0, &ind, NOTABLE_ARG}, + {"udevcookie", 1, &ind, UDEVCOOKIE_ARG}, {"noudevrules", 0, &ind, NOUDEVRULES_ARG}, {"noudevsync", 0, &ind, NOUDEVSYNC_ARG}, {"options", 1, &ind, OPTIONS_ARG}, @@ -3059,6 +3207,10 @@ static int _process_switches(int *argc, } if (c == 'y' || ind == YES_ARG) _switches[YES_ARG]++; + if (ind == UDEVCOOKIE_ARG) { + _switches[UDEVCOOKIE_ARG]++; + _udev_cookie = _get_cookie_value(optarg); + } if (ind == NOUDEVRULES_ARG) _switches[NOUDEVRULES_ARG]++; if (ind == NOUDEVSYNC_ARG) @@ -3160,11 +3312,10 @@ int main(int argc, char **argv) struct command *c; int r = 1; const char *dev_dir; - const char *disable_udev_checking; (void) setlocale(LC_ALL, ""); - dev_dir = getenv ("DM_DEV_DIR"); + dev_dir = getenv (DM_DEV_DIR_ENV_VAR_NAME); if (dev_dir && *dev_dir) { if (!dm_set_dev_dir(dev_dir)) { fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n"); @@ -3207,13 +3358,10 @@ int main(int argc, char **argv) if (_switches[COLS_ARG] && !_report_init(c)) goto out; - if (_switches[NOUDEVSYNC_ARG]) - dm_udev_set_sync_support(0); - - disable_udev_checking = getenv("DM_UDEV_DISABLE_CHECKING"); - if ((disable_udev_checking && *disable_udev_checking) && - !strcmp(disable_udev_checking, "1")) - dm_udev_set_checking(0); + #ifdef UDEV_SYNC_SUPPORT + if (!_set_up_udev_support(dev_dir)) + goto out; + #endif doit: if (!c->fn(argc, argv, NULL)) { diff -rupN LVM2.2.02.58//tools/lvconvert.c LVM2.2.02.61//tools/lvconvert.c --- LVM2.2.02.58//tools/lvconvert.c 2010-01-13 07:25:44.000000000 +0530 +++ LVM2.2.02.61//tools/lvconvert.c 2010-02-06 13:14:16.000000000 +0530 @@ -55,7 +55,10 @@ static int _lvconvert_name_params(struct char *ptr; const char *vg_name = NULL; - if (lp->snapshot && !lp->merge) { + if (lp->merge) + return 1; + + if (lp->snapshot) { if (!*pargc) { log_error("Please specify a logical volume to act as " "the snapshot origin."); @@ -105,7 +108,7 @@ static int _lvconvert_name_params(struct if (!apply_lvname_restrictions(lp->lv_name)) return_0; - if (*pargc && (lp->snapshot || lp->merge)) { + if (*pargc && lp->snapshot) { log_error("Too many arguments provided for snapshots"); return 0; } @@ -306,11 +309,16 @@ static int _read_params(struct lvconvert } static struct volume_group *_get_lvconvert_vg(struct cmd_context *cmd, - const char *lv_name, const char *uuid) + const char *name, + const char *uuid __attribute((unused))) { dev_close_all(); - return vg_read_for_update(cmd, extract_vgname(cmd, lv_name), + if (name && !strchr(name, '/')) + return vg_read_for_update(cmd, name, NULL, 0); + + /* 'name' is the full LV name; must extract_vgname() */ + return vg_read_for_update(cmd, extract_vgname(cmd, name), NULL, 0); } @@ -335,6 +343,9 @@ static int _finish_lvconvert_mirror(stru { int r = 0; + if (!(lv->status & CONVERTING)) + return 1; + if (!collapse_mirrored_lv(lv)) { log_error("Failed to remove temporary sync layer."); return 0; @@ -402,7 +413,7 @@ static progress_t _poll_merge_progress(s percent_range_t percent_range; if (!lv_snapshot_percent(lv, &percent, &percent_range)) { - log_error("%s: Failed query for merging percentage", lv->name); + log_error("%s: Failed query for merging percentage. Aborting merge.", lv->name); return PROGRESS_CHECK_FAILED; } else if (percent_range == PERCENT_INVALID) { log_error("%s: Merging snapshot invalidated. Aborting merge.", lv->name); @@ -437,11 +448,19 @@ static struct poll_functions _lvconvert_ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background) { + /* + * FIXME allocate an "object key" structure with split + * out members (vg_name, lv_name, uuid, etc) and pass that + * around the lvconvert and polldaemon code + * - will avoid needless work, e.g. extract_vgname() + * - unfortunately there are enough overloaded "name" dragons in + * the polldaemon, lvconvert, pvmove code that a comprehensive + * audit/rework is needed + */ int len = strlen(lv->vg->name) + strlen(lv->name) + 2; char *uuid = alloca(sizeof(lv->lvid)); char *lv_full_name = alloca(len); - if (!uuid || !lv_full_name) return_0; @@ -967,7 +986,8 @@ static int _lvconvert_mirrors(struct cmd stack; return failure_code; } - lv->status |= CONVERTING; + if (seg->log_lv) + lv->status |= CONVERTING; lp->need_polling = 1; } @@ -1205,8 +1225,8 @@ out: return r; } -static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, - void *handle) +static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, + void *handle) { struct lvconvert_params *lp = handle; @@ -1227,6 +1247,8 @@ static int lvconvert_single(struct cmd_c } if (arg_count(cmd, repair_ARG) && !(lv->status & MIRRORED)) { + if (arg_count(cmd, use_policies_ARG)) + return ECMD_PROCESSED; /* nothing to be done here */ log_error("Can't repair non-mirrored LV \"%s\".", lv->name); return ECMD_FAILED; } @@ -1276,60 +1298,146 @@ static int lvconvert_single(struct cmd_c return ECMD_PROCESSED; } -int lvconvert(struct cmd_context * cmd, int argc, char **argv) +/* + * FIXME move to toollib along with the rest of the drop/reacquire + * VG locking that is used by lvconvert_merge_single() + */ +static struct logical_volume *get_vg_lock_and_logical_volume(struct cmd_context *cmd, + const char *vg_name, + const char *lv_name) { + /* + * Returns NULL if the requested LV doesn't exist; + * otherwise the caller must vg_release(lv->vg) + * - it is also up to the caller to unlock_vg() as needed + */ struct volume_group *vg; - struct lv_list *lvl; - struct lvconvert_params lp; - int ret = ECMD_FAILED; + struct logical_volume* lv = NULL; + + vg = _get_lvconvert_vg(cmd, vg_name, NULL); + if (vg_read_error(vg)) { + vg_release(vg); + log_error("ABORTING: Can't reread VG for %s", vg_name); + return NULL; + } + + if (!(lv = _get_lvconvert_lv(cmd, vg, lv_name, NULL, 0))) { + log_error("ABORTING: Can't find LV %s in VG %s", lv_name, vg_name); + unlock_and_release_vg(cmd, vg, vg_name); + return NULL; + } + + return lv; +} + +static int poll_logical_volume(struct cmd_context *cmd, struct logical_volume *lv, + int wait_completion) +{ struct lvinfo info; - int saved_ignore_suspended_devices = ignore_suspended_devices(); - if (!_read_params(&lp, cmd, argc, argv)) { - stack; - return EINVALID_CMD_LINE; + if (!lv_info(cmd, lv, &info, 1, 0) || !info.exists) { + log_print("Conversion starts after activation."); + return ECMD_PROCESSED; } + return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U); +} + +static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp) +{ + struct logical_volume *lv = NULL; + int ret = ECMD_FAILED; + int saved_ignore_suspended_devices = ignore_suspended_devices(); if (arg_count(cmd, repair_ARG)) { init_ignore_suspended_devices(1); cmd->handles_missing_pvs = 1; } - log_verbose("Checking for existing volume group \"%s\"", lp.vg_name); - - vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0); - if (vg_read_error(vg)) - goto out; - - if (!(lvl = find_lv_in_vg(vg, lp.lv_name))) { - log_error("Logical volume \"%s\" not found in " - "volume group \"%s\"", lp.lv_name, lp.vg_name); - goto bad; - } + lv = get_vg_lock_and_logical_volume(cmd, lp->vg_name, lp->lv_name); + if (!lv) + goto_out; - if (lp.pv_count) { - if (!(lp.pvh = create_pv_list(cmd->mem, vg, lp.pv_count, - lp.pvs, 0))) + if (lp->pv_count) { + if (!(lp->pvh = create_pv_list(cmd->mem, lv->vg, lp->pv_count, + lp->pvs, 0))) goto_bad; } else - lp.pvh = &vg->pvs; - - lp.lv_to_poll = lvl->lv; - ret = lvconvert_single(cmd, lvl->lv, &lp); + lp->pvh = &lv->vg->pvs; + lp->lv_to_poll = lv; + ret = _lvconvert_single(cmd, lv, lp); bad: - unlock_vg(cmd, lp.vg_name); + unlock_vg(cmd, lp->vg_name); - if (ret == ECMD_PROCESSED && lp.need_polling) { - if (!lv_info(cmd, lp.lv_to_poll, &info, 1, 0) || !info.exists) { - log_print("Conversion starts after activation"); - goto out; - } - ret = lvconvert_poll(cmd, lp.lv_to_poll, - lp.wait_completion ? 0 : 1U); - } + if (ret == ECMD_PROCESSED && lp->need_polling) + ret = poll_logical_volume(cmd, lp->lv_to_poll, + lp->wait_completion); + + vg_release(lv->vg); out: init_ignore_suspended_devices(saved_ignore_suspended_devices); - vg_release(vg); return ret; } + +static int lvconvert_merge_single(struct cmd_context *cmd, struct logical_volume *lv, + void *handle) +{ + struct lvconvert_params *lp = handle; + const char *vg_name = NULL; + struct logical_volume *refreshed_lv = NULL; + int ret; + + /* + * 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); + refreshed_lv = get_vg_lock_and_logical_volume(cmd, vg_name, lv->name); + if (!refreshed_lv) + return ECMD_FAILED; + + lp->lv_to_poll = refreshed_lv; + ret = _lvconvert_single(cmd, refreshed_lv, lp); + + 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); + + ret = poll_logical_volume(cmd, lp->lv_to_poll, + lp->wait_completion); + + /* use LCK_VG_WRITE to match lvconvert()'s READ_FOR_UPDATE */ + if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { + log_error("ABORTING: Can't relock VG for %s " + "after polling finished", vg_name); + ret = ECMD_FAILED; + } + } + + vg_release(refreshed_lv->vg); + + return ret; +} + +int lvconvert(struct cmd_context * cmd, int argc, char **argv) +{ + struct lvconvert_params lp; + + if (!_read_params(&lp, cmd, argc, argv)) { + stack; + return EINVALID_CMD_LINE; + } + + if (lp.merge) + return process_each_lv(cmd, argc, argv, READ_FOR_UPDATE, &lp, + &lvconvert_merge_single); + + return lvconvert_single(cmd, &lp); +} diff -rupN LVM2.2.02.58//tools/lvcreate.c LVM2.2.02.61//tools/lvcreate.c --- LVM2.2.02.58//tools/lvcreate.c 2010-01-12 19:30:52.000000000 +0530 +++ LVM2.2.02.61//tools/lvcreate.c 2010-02-03 09:28:08.000000000 +0530 @@ -130,6 +130,7 @@ static int _update_extents_params(struct struct lvcreate_cmdline_params *lcp) { uint32_t pv_extent_count; + struct logical_volume *origin = NULL; if (lcp->size && !(lp->extents = extents_from_size(vg->cmd, lcp->size, @@ -171,6 +172,15 @@ static int _update_extents_params(struct log_error("Please express size as %%VG, %%PVS, or " "%%FREE."); return 0; + case PERCENT_ORIGIN: + if (lp->snapshot && lp->origin && + !(origin = find_lv(vg, lp->origin))) { + log_error("Couldn't find origin volume '%s'.", + lp->origin); + return 0; + } + lp->extents = lp->extents * origin->le_count / 100; + break; case PERCENT_NONE: break; } diff -rupN LVM2.2.02.58//tools/lvmcmdline.c LVM2.2.02.61//tools/lvmcmdline.c --- LVM2.2.02.58//tools/lvmcmdline.c 2010-01-12 00:49:17.000000000 +0530 +++ LVM2.2.02.61//tools/lvmcmdline.c 2010-02-15 21:56:49.000000000 +0530 @@ -42,6 +42,11 @@ extern char *optarg; # define OPTIND_INIT 1 #endif +#ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE +# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE +# include +#endif + /* * Table of valid switches */ @@ -358,6 +363,9 @@ int int_arg_with_sign_and_percent(struct else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") || !strcasecmp(ptr, "FREE")) a->percent = PERCENT_FREE; + else if (!strcasecmp(ptr, "O") || !strcasecmp(ptr, "OR") || + !strcasecmp(ptr, "ORIGIN")) + a->percent = PERCENT_ORIGIN; else return 0; @@ -909,17 +917,45 @@ static void _apply_settings(struct cmd_c cmd->handles_missing_pvs = 0; } -static void _set_udev_checking() +static int _set_udev_checking(struct cmd_context *cmd) { - const char *e; +#ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE + struct udev *udev; + const char *udev_dev_dir; + size_t udev_dev_dir_len; + int dirs_diff; + + if (!(udev = udev_new()) || + !(udev_dev_dir = udev_get_dev_path(udev)) || + !*udev_dev_dir) { + log_error("Could not get udev dev path."); + return 0; + } + udev_dev_dir_len = strlen(udev_dev_dir); + + /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */ + if (udev_dev_dir[udev_dev_dir_len - 1] != '/') + dirs_diff = strncmp(cmd->dev_dir, udev_dev_dir, + udev_dev_dir_len); + else + dirs_diff = strcmp(cmd->dev_dir, udev_dev_dir); - if ((e = getenv("DM_UDEV_DISABLE_CHECKING")) && - !strcmp(e, "1")) + if (dirs_diff) { + log_debug("The path %s used for creating device nodes and " + "symlinks that is set in the configuration differs " + "from the path %s that is used by udev. All warnings " + "about udev not working correctly while processing " + "particular nodes and symlinks will be suppressed. " + "These nodes and symlinks will be managed in each " + "directory separately.", + cmd->dev_dir, udev_dev_dir); dm_udev_set_checking(0); - - if ((e = getenv("LVM_UDEV_DISABLE_CHECKING")) && - !strcmp(e, "1")) init_udev_checking(0); + } + + udev_unref(udev); +#endif + return 1; } static const char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv) @@ -1016,7 +1052,8 @@ int lvm_run_command(struct cmd_context * log_debug("O_DIRECT will be used"); #endif - _set_udev_checking(); + if (!_set_udev_checking(cmd)) + goto_out; if ((ret = _process_common_commands(cmd))) goto_out; @@ -1027,8 +1064,6 @@ int lvm_run_command(struct cmd_context * locking_type = -1; if (!init_locking(locking_type, cmd)) { - log_error("Locking type %d initialisation failed.", - locking_type); ret = ECMD_FAILED; goto out; } @@ -1213,6 +1248,10 @@ static void _fin_commands(void) dm_free(_cmdline.commands[i].valid_args); dm_free(_cmdline.commands); + + _cmdline.commands = NULL; + _cmdline.num_commands = 0; + _cmdline.commands_size = 0; } void lvm_fin(struct cmd_context *cmd) diff -rupN LVM2.2.02.58//tools/lvresize.c LVM2.2.02.61//tools/lvresize.c --- LVM2.2.02.58//tools/lvresize.c 2010-01-06 02:37:31.000000000 +0530 +++ LVM2.2.02.61//tools/lvresize.c 2010-02-03 09:28:08.000000000 +0530 @@ -373,6 +373,13 @@ static int _lvresize(struct cmd_context } else lp->extents = lp->extents * vg->extent_count / 100; break; + case PERCENT_ORIGIN: + if (!lv_is_cow(lv)) { + log_error("Specified LV does not have an origin LV."); + return EINVALID_CMD_LINE; + } + lp->extents = lp->extents * origin_from_cow(lv)->le_count / 100; + break; case PERCENT_NONE: break; } diff -rupN LVM2.2.02.58//tools/Makefile.in LVM2.2.02.61//tools/Makefile.in --- LVM2.2.02.58//tools/Makefile.in 2009-10-13 07:01:10.000000000 +0530 +++ LVM2.2.02.61//tools/Makefile.in 2010-01-19 06:40:47.000000000 +0530 @@ -115,8 +115,8 @@ dmsetup: dmsetup.o $(top_builddir)/libdm $(CC) $(CFLAGS) $(LDFLAGS) -L$(top_builddir)/libdm \ -o $@ dmsetup.o -ldevmapper $(LIBS) $(LIB_PTHREAD) -dmsetup.static: dmsetup.o $(interfacedir)/libdevmapper.a - $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacedir) \ +dmsetup.static: dmsetup.o $(interfacebuilddir)/libdevmapper.a + $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) \ -o $@ dmsetup.o -ldevmapper $(LIBS) $(LIB_PTHREAD) all: device-mapper @@ -125,8 +125,8 @@ lvm: $(OBJECTS) lvm.o $(top_builddir)/li $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) lvm.o \ $(LVMLIBS) $(LIBS) $(LIB_PTHREAD) -rdynamic -lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(interfacedir)/libdevmapper.a - $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacedir) -o $@ \ +lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(interfacebuilddir)/libdevmapper.a + $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) -o $@ \ $(OBJECTS) lvm-static.o $(LVMLIBS) $(LIBS) $(LIB_PTHREAD) \ -rdynamic diff -rupN LVM2.2.02.58//tools/polldaemon.c LVM2.2.02.61//tools/polldaemon.c --- LVM2.2.02.58//tools/polldaemon.c 2010-01-12 00:49:17.000000000 +0530 +++ LVM2.2.02.61//tools/polldaemon.c 2010-01-23 03:29:43.000000000 +0530 @@ -156,8 +156,18 @@ static int _check_lv_status(struct cmd_c return 1; } +static void _sleep_and_rescan_devices(struct daemon_parms *parms) +{ + /* FIXME Use alarm for regular intervals instead */ + if (parms->interval && !parms->aborting) { + sleep(parms->interval); + /* Devices might have changed while we slept */ + init_full_scan_done(0); + } +} + static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const char *uuid, - struct daemon_parms *parms) + struct daemon_parms *parms) { struct volume_group *vg; struct logical_volume *lv; @@ -165,13 +175,8 @@ static int _wait_for_single_lv(struct cm /* Poll for completion */ while (!finished) { - /* FIXME Also needed in vg/lvchange -ay? */ - /* FIXME Use alarm for regular intervals instead */ - if (parms->interval && !parms->aborting) { - sleep(parms->interval); - /* Devices might have changed while we slept */ - init_full_scan_done(0); - } + if (parms->wait_before_testing) + _sleep_and_rescan_devices(parms); /* Locks the (possibly renamed) VG again */ vg = parms->poll_fns->get_copy_vg(cmd, name, uuid); @@ -196,6 +201,21 @@ static int _wait_for_single_lv(struct cm } unlock_and_release_vg(cmd, vg, vg->name); + + /* + * FIXME Sleeping after testing, while preferred, also works around + * unreliable "finished" state checking in _percent_run. If the + * above _check_lv_status is deferred until after the first sleep it + * may be that a polldaemon will run without ever completing. + * + * This happens when one snapshot-merge polldaemon is racing with + * another (polling the same LV). The first to see the LV status + * reach the "finished" state will alter the LV that the other + * polldaemon(s) are polling. These other polldaemon(s) can then + * continue polling an LV that doesn't have a "status". + */ + if (!parms->wait_before_testing) + _sleep_and_rescan_devices(parms); } return 1; @@ -253,17 +273,23 @@ int poll_daemon(struct cmd_context *cmd, struct daemon_parms parms; int daemon_mode = 0; int ret = ECMD_PROCESSED; + sign_t interval_sign; parms.aborting = arg_is_set(cmd, abort_ARG); parms.background = background; + interval_sign = arg_sign_value(cmd, interval_ARG, 0); + if (interval_sign == SIGN_MINUS) + log_error("Argument to --interval cannot be negative"); parms.interval = arg_uint_value(cmd, interval_ARG, DEFAULT_INTERVAL); + parms.wait_before_testing = (interval_sign == SIGN_PLUS); parms.progress_display = 1; parms.progress_title = progress_title; parms.lv_type = lv_type; parms.poll_fns = poll_fns; if (parms.interval && !parms.aborting) - log_verbose("Checking progress every %u seconds", + log_verbose("Checking progress %s waiting every %u seconds", + (parms.wait_before_testing ? "after" : "before"), parms.interval); if (!parms.interval) { diff -rupN LVM2.2.02.58//tools/polldaemon.h LVM2.2.02.61//tools/polldaemon.h --- LVM2.2.02.58//tools/polldaemon.h 2009-09-30 23:45:06.000000000 +0530 +++ LVM2.2.02.61//tools/polldaemon.h 2010-01-23 03:29:43.000000000 +0530 @@ -53,6 +53,7 @@ struct poll_functions { struct daemon_parms { unsigned interval; + unsigned wait_before_testing; unsigned aborting; unsigned background; unsigned outstanding_count; diff -rupN LVM2.2.02.58//tools/pvmove.c LVM2.2.02.61//tools/pvmove.c --- LVM2.2.02.58//tools/pvmove.c 2010-01-06 02:38:34.000000000 +0530 +++ LVM2.2.02.61//tools/pvmove.c 2010-02-06 04:10:50.000000000 +0530 @@ -1,6 +1,6 @@ /* * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -284,9 +284,26 @@ static int _activate_lv(struct cmd_conte return r; } -static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, - struct logical_volume *lv_mirr, - struct dm_list *lvs_changed); +static int _detach_pvmove_mirror(struct cmd_context *cmd, + struct logical_volume *lv_mirr) +{ + struct dm_list lvs_completed; + struct lv_list *lvl; + + /* Update metadata to remove mirror segments and break dependencies */ + dm_list_init(&lvs_completed); + if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) || + !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE, + &lvs_completed)) { + return 0; + } + + dm_list_iterate_items(lvl, &lvs_completed) + /* FIXME Assumes only one pvmove at a time! */ + lvl->lv->status &= ~LOCKED; + + return 1; +} static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv_mirr, @@ -303,8 +320,10 @@ static int _update_metadata(struct cmd_c } /* Suspend lvs_changed */ - if (!suspend_lvs(cmd, lvs_changed)) + if (!suspend_lvs(cmd, lvs_changed)) { + vg_revert(vg); goto_out; + } /* Suspend mirrors on subsequent calls */ if (!first_time) { @@ -324,6 +343,7 @@ static int _update_metadata(struct cmd_c stack; if (!resume_lvs(cmd, lvs_changed)) stack; + vg_revert(vg); goto out; } @@ -338,12 +358,27 @@ static int _update_metadata(struct cmd_c } /* + * FIXME: review ordering of operations above, + * temporary mirror should be preloaded in suspend. + * Also banned operation here when suspended. * Nothing changed yet, try to revert pvmove. */ log_error("Temporary pvmove mirror activation failed."); - if (!_finish_pvmove(cmd, vg, lv_mirr, lvs_changed)) + + /* Ensure that temporary mrror is deactivate even on other nodes. */ + (void)deactivate_lv(cmd, lv_mirr); + + /* Revert metadata */ + if (!_detach_pvmove_mirror(cmd, lv_mirr) || + !lv_remove(lv_mirr) || + !vg_write(vg) || !vg_commit(vg)) log_error("ABORTING: Restoring original configuration " "before pvmove failed. Run pvmove --abort."); + + /* Unsuspend LVs */ + if(!resume_lvs(cmd, lvs_changed)) + stack; + goto out; } } else if (!resume_lv(cmd, lv_mirr)) { @@ -484,22 +519,12 @@ static int _finish_pvmove(struct cmd_con struct dm_list *lvs_changed) { int r = 1; - struct dm_list lvs_completed; - struct lv_list *lvl; - /* Update metadata to remove mirror segments and break dependencies */ - dm_list_init(&lvs_completed); - if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) || - !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE, - &lvs_completed)) { + if (!_detach_pvmove_mirror(cmd, lv_mirr)) { log_error("ABORTING: Removal of temporary mirror failed"); return 0; } - dm_list_iterate_items(lvl, &lvs_completed) - /* FIXME Assumes only one pvmove at a time! */ - lvl->lv->status &= ~LOCKED; - /* Store metadata without dependencies on mirror segments */ if (!vg_write(vg)) { log_error("ABORTING: Failed to write new data locations " @@ -570,7 +595,8 @@ static int _finish_pvmove(struct cmd_con } static struct volume_group *_get_move_vg(struct cmd_context *cmd, - const char *name, const char *uuid) + const char *name, + const char *uuid __attribute((unused))) { struct physical_volume *pv; diff -rupN LVM2.2.02.58//tools/toollib.c LVM2.2.02.61//tools/toollib.c --- LVM2.2.02.58//tools/toollib.c 2010-01-13 07:26:18.000000000 +0530 +++ LVM2.2.02.61//tools/toollib.c 2010-02-03 19:38:40.000000000 +0530 @@ -275,7 +275,7 @@ int process_each_lv(struct cmd_context * if (!argc || !dm_list_empty(&tags)) { log_verbose("Finding all logical volumes"); - if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) { + if (!(vgnames = get_vgnames(cmd, 0, 0)) || dm_list_empty(vgnames)) { log_error("No volume groups found"); return ret_max; } @@ -284,8 +284,6 @@ int process_each_lv(struct cmd_context * vg = NULL; dm_list_iterate_items(strl, vgnames) { vgname = strl->str; - if (is_orphan_vg(vgname)) - continue; /* FIXME Unnecessary? */ vg = vg_read(cmd, vgname, NULL, flags); if (vg_read_error(vg)) { @@ -520,14 +518,13 @@ int process_each_vg(struct cmd_context * if (!argc || !dm_list_empty(&tags)) { log_verbose("Finding all volume groups"); - if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) { + if (!(vgids = get_vgids(cmd, 0, 0)) || dm_list_empty(vgids)) { log_error("No volume groups found"); return ret_max; } dm_list_iterate_items(sl, vgids) { vgid = sl->str; - if (!vgid || !(vg_name = vgname_from_vgid(cmd->mem, vgid)) || - is_orphan_vg(vg_name)) + if (!(vgid) || !(vg_name = vgname_from_vgid(cmd->mem, vgid))) continue; ret_max = _process_one_vg(cmd, vg_name, vgid, &tags, &arg_vgnames, @@ -726,7 +723,7 @@ int process_each_pv(struct cmd_context * if (sigint_caught()) goto out; } - if (!dm_list_empty(&tags) && (vgnames = get_vgnames(cmd, 0)) && + if (!dm_list_empty(&tags) && (vgnames = get_vgnames(cmd, 0, 1)) && !dm_list_empty(vgnames)) { dm_list_iterate_items(sll, vgnames) { vg = vg_read(cmd, sll->str, NULL, flags); diff -rupN LVM2.2.02.58//tools/tools.h LVM2.2.02.61//tools/tools.h --- LVM2.2.02.58//tools/tools.h 2009-11-03 21:20:44.000000000 +0530 +++ LVM2.2.02.61//tools/tools.h 2010-02-03 09:28:08.000000000 +0530 @@ -83,7 +83,8 @@ typedef enum { PERCENT_VG, PERCENT_FREE, PERCENT_LV, - PERCENT_PVS + PERCENT_PVS, + PERCENT_ORIGIN } percent_t; enum { diff -rupN LVM2.2.02.58//tools/vgrename.c LVM2.2.02.61//tools/vgrename.c --- LVM2.2.02.58//tools/vgrename.c 2009-09-15 04:17:50.000000000 +0530 +++ LVM2.2.02.61//tools/vgrename.c 2010-02-03 19:38:40.000000000 +0530 @@ -87,15 +87,14 @@ static int vg_rename_path(struct cmd_con log_verbose("Checking for existing volume group \"%s\"", vg_name_old); /* Avoid duplicates */ - if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) { + if (!(vgids = get_vgids(cmd, 0, 0)) || dm_list_empty(vgids)) { log_error("No complete volume groups found"); return 0; } dm_list_iterate_items(sl, vgids) { vgid = sl->str; - if (!vgid || !(vg_name = vgname_from_vgid(NULL, vgid)) || - is_orphan_vg(vg_name)) + if (!vgid || !(vg_name = vgname_from_vgid(NULL, vgid))) continue; if (!strcmp(vg_name, vg_name_old)) { if (match) { diff -rupN LVM2.2.02.58//udev/11-dm-lvm.rules LVM2.2.02.61//udev/11-dm-lvm.rules --- LVM2.2.02.58//udev/11-dm-lvm.rules 2010-01-08 01:31:55.000000000 +0530 +++ LVM2.2.02.61//udev/11-dm-lvm.rules 2010-02-15 22:08:23.000000000 +0530 @@ -23,7 +23,7 @@ IMPORT{program}="$env{DM_SBIN_PATH}/dmse ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end" # Do not create symlinks for inappropriate subdevices. -ENV{DM_LV_NAME}=="?*_mimage_[0-9]*|pvmove?*|?*_vorigin", GOTO="lvm_disable" +ENV{DM_LV_NAME}=="pvmove?*|?*_vorigin", GOTO="lvm_disable" ENV{DM_LV_LAYER}=="?*", GOTO="lvm_disable" # Create symlinks for top-level devices only. diff -rupN LVM2.2.02.58//VERSION LVM2.2.02.61//VERSION --- LVM2.2.02.58//VERSION 2010-01-14 19:40:33.000000000 +0530 +++ LVM2.2.02.61//VERSION 2010-02-16 05:36:43.000000000 +0530 @@ -1 +1 @@ -2.02.58(1) (2010-01-14) +2.02.61(1) (2010-02-15) diff -rupN LVM2.2.02.58//VERSION_DM LVM2.2.02.61//VERSION_DM --- LVM2.2.02.58//VERSION_DM 2010-01-14 19:40:33.000000000 +0530 +++ LVM2.2.02.61//VERSION_DM 2010-02-16 05:36:43.000000000 +0530 @@ -1 +1 @@ -1.02.42 (2010-01-14) +1.02.44 (2010-02-15) diff -rupN LVM2.2.02.58//WHATS_NEW LVM2.2.02.61//WHATS_NEW --- LVM2.2.02.58//WHATS_NEW 2010-01-14 19:32:34.000000000 +0530 +++ LVM2.2.02.61//WHATS_NEW 2010-02-16 05:23:15.000000000 +0530 @@ -1,3 +1,66 @@ +Version 2.02.61 - 15th February 2010 +==================================== + Fix some consts and floating point gcc warnings. + Fix dm_report_field_uint64 function to accept 64-bit ints. + Change readhead display to use 32-bit -1 const instead of 64-bit. + Add LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES environment variable. + Remove hard-coding that skipped _mimage devices from 11-dm-lvm.rules. + Use udev transactions in test suite. + Set udev state automatically instead of using LVM_UDEV_DISABLE_CHECKING. + Add lvm_pv_get_size, lvm_pv_get_free and lvm_pv_get_dev_size to lvm2app. + Change lvm2app to return all sizes in bytes as documented (not sectors). + Add 'fail_if_percent_unsupported' arg to _percent and _percent_run. + Remove false "failed to find tree node" error when activating merging origin. + Exit with success when lvconvert --repair --use-policies performs no action. + Accept a list of LVs with 'lvconvert --merge @tag' using process_each_lv. + Avoid unnecessary second resync when adding mimage to core-logged mirror. + Exclude internal VG names and uuids from lists returned through liblvm. + Add %ORIGIN support to lv{create,extend,reduce,resize} --extents. + Add _mda_copy to clone a struct metadata_area. + Remove pointless versioned symlinks to dmeventd plugin libraries. + Fix dmeventd snapshot plugin build dependency. + Make clvmd -V return status zero. + Remove unnecessary 'dmsetup resume' following 'dmsetup create' in tests. + Fix cmirrord segfault in clog_cpg list processing when converting mirror log. + Deactivate temporary pvmove mirror cluster-wide when activating it fails. + Always query device by uuid and not name in clvmd. + Add missing metadata vg_reverts in pvmove error paths. + Unlock shared lock in clvmd if activation calls fail. + Return success from dev_manager_info with non-existent uuid if ioctl succeeds. + +Version 2.02.60 - 23rd January 2010 +=================================== + Extend cmirrord man page. + Sleep before first progress check if pvmove/lvconvert interval has prefix '+'. + Default to checking progress before waiting in _wait_for_single_lv. + Fix cmirror initscript (including syntax error). + Eliminate avoidable ioctls for checking open_count in _add_new_lv_to_dtree. + Disable memory debugging if dmeventd is configured. (Not thread-safe.) + Fix first log message prefix in syslog for dmeventd plugins. + Fix exported symbols names for dmeventd lvm2 wrapper plugin. + Make failed locking initialisation messages more descriptive. + +Version 2.02.59 - 21st January 2010 +=================================== + Add libdevmapper-event-lvm2.so to serialise dmeventd plugin liblvm2cmd use. + Cleanup memory initialization and freeing in pv_read() and pv_create(). + Clear pointer and counters after their release in _fin_commands(). + Stop dmeventd trying to access already-removed snapshots. + Remove (fallback) /dev mknod from cmirrord. + Add t-topology-support.sh and t-snapshot-merge.sh tests. + Fix clvmd to never scan suspended devices. + Fix dmeventd build outside source tree. + Assorted cmirror code changes to remove various compiler warnings. + Fix detection of completed snapshot merge. + Add Red Hat cmirror initscript (unfinished). + Add cmirrord man page (incomplete). + Make cluster log communication structures architecture independant. + Fix cluster log in-memory bitmap handling. + Improve snapshot merge metadata import validation. + Improve target type compatibility checking in _percent_run(). + Add 'target_status_compatible' method to 'struct segtype_handler'. + Change underscore to hyphen in table line for clustered log type. + Version 2.02.58 - 14th January 2010 =================================== Cleanup some minor gcc warnings. diff -rupN LVM2.2.02.58//WHATS_NEW_DM LVM2.2.02.61//WHATS_NEW_DM --- LVM2.2.02.58//WHATS_NEW_DM 2010-01-14 19:32:34.000000000 +0530 +++ LVM2.2.02.61//WHATS_NEW_DM 2010-02-16 05:23:15.000000000 +0530 @@ -1,3 +1,15 @@ +Version 1.02.44 - 15th February 2010 +==================================== + Add DM_UDEV_DISABLE_LIBRARY_FALLBACK udev flag to rely on udev only. + Export dm_udev_create_cookie function to create new cookies on demand. + Add --udevcookie, udevcreatecookie and udevreleasecookie to dmsetup. + Set udev state automatically instead of using DM_UDEV_DISABLE_CHECKING. + +Version 1.02.43 - 21st January 2010 +=================================== + Remove bitset, hash and pool headers superceded by libdevmapper.h. + Fix off-by-one error causing bad cluster mirror table construction. + Version 1.02.42 - 14th January 2010 =================================== Add support for the "snapshot-merge" kernel target (2.6.33-rc1).