From fdb6ec87792ea4aa912eb255329105862961d369 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 15 Dec 2014 18:24:07 -0600 Subject: [PATCH] device-mapper-multipath-0.4.9-71 Add 0103-RH-cleanup-partmaps-code.patch * code refactoring to prepare for next patch Add 0104-RHBZ-631009-deferred-remove.patch * add deferred_remove option to /etc/multipath.conf Add 0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch * Only run kpartx on device activation Add 0106-RHBZ-1159337-fix-double-free.patch * made ev_remove_path exit immediately after failing setup_multipath, since it handles cleaning up the device Add 0107-RHBZ-1169935-no-new-devs.patch * Add new multipathd option '-n' which keeps multipathd from creating any multipath devices that aren't in the /etc/multipath/wwids file. Add 0108-RHBZ-1153832-kpartx-remove-devs.patch * switch from 'kpartx -a' to 'kpartx -u' to remove missing devices as well. Add 0109-RH-read-only-bindings.patch * re-enabled -B option for multipathd --- 0103-RH-cleanup-partmaps-code.patch | 199 +++++ 0104-RHBZ-631009-deferred-remove.patch | 751 ++++++++++++++++++ ...on-mapping-creation-race-with-kpartx.patch | 10 + 0106-RHBZ-1159337-fix-double-free.patch | 20 + 0107-RHBZ-1169935-no-new-devs.patch | 117 +++ 0108-RHBZ-1153832-kpartx-remove-devs.patch | 15 + 0109-RH-read-only-bindings.patch | 27 + device-mapper-multipath.spec | 34 +- 8 files changed, 1172 insertions(+), 1 deletion(-) create mode 100644 0103-RH-cleanup-partmaps-code.patch create mode 100644 0104-RHBZ-631009-deferred-remove.patch create mode 100644 0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch create mode 100644 0106-RHBZ-1159337-fix-double-free.patch create mode 100644 0107-RHBZ-1169935-no-new-devs.patch create mode 100644 0108-RHBZ-1153832-kpartx-remove-devs.patch create mode 100644 0109-RH-read-only-bindings.patch diff --git a/0103-RH-cleanup-partmaps-code.patch b/0103-RH-cleanup-partmaps-code.patch new file mode 100644 index 0000000..57fb402 --- /dev/null +++ b/0103-RH-cleanup-partmaps-code.patch @@ -0,0 +1,199 @@ +--- + libmultipath/devmapper.c | 155 ++++++++++++++++++----------------------------- + 1 file changed, 61 insertions(+), 94 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -1006,8 +1006,9 @@ bad: + return NULL; + } + +-int +-dm_remove_partmaps (const char * mapname, int need_sync) ++static int ++do_foreach_partmaps (const char * mapname, int (*partmap_func)(char *, void *), ++ void *data) + { + struct dm_task *dmt; + struct dm_names *names; +@@ -1059,26 +1060,8 @@ dm_remove_partmaps (const char * mapname + */ + strstr(params, dev_t) + ) { +- /* +- * then it's a kpartx generated partition. +- * remove it. +- */ +- /* +- * if the opencount is 0 maybe some other +- * partitions depend on it. +- */ +- if (dm_get_opencount(names->name)) { +- dm_remove_partmaps(names->name, need_sync); +- if (dm_get_opencount(names->name)) { +- condlog(2, "%s: map in use", +- names->name); +- goto out; +- } +- } +- condlog(4, "partition map %s removed", +- names->name); +- dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name, +- need_sync, 0); ++ if (partmap_func(names->name, data) != 0) ++ goto out; + } + + next = names->next; +@@ -1091,6 +1074,35 @@ out: + return r; + } + ++struct remove_data { ++ int need_sync; ++}; ++ ++static int ++remove_partmap(char *name, void *data) ++{ ++ struct remove_data *rd = (struct remove_data *)data; ++ ++ if (dm_get_opencount(name)) { ++ dm_remove_partmaps(name, rd->need_sync); ++ if (dm_get_opencount(name)) { ++ condlog(2, "%s: map in use", name); ++ return 1; ++ } ++ } ++ condlog(4, "partition map %s removed", name); ++ dm_simplecmd_flush(DM_DEVICE_REMOVE, name, ++ rd->need_sync, 0); ++ return 0; ++} ++ ++int ++dm_remove_partmaps (const char * mapname, int need_sync) ++{ ++ struct remove_data rd = { need_sync }; ++ return do_foreach_partmaps(mapname, remove_partmap, &rd); ++} ++ + static struct dm_info * + alloc_dminfo (void) + { +@@ -1140,86 +1152,41 @@ out: + return r; + } + +-int +-dm_rename_partmaps (char * old, char * new) ++struct rename_data { ++ char *old; ++ char *new; ++ char *delim; ++}; ++ ++static int ++rename_partmap (char *name, void *data) + { +- struct dm_task *dmt; +- struct dm_names *names; +- unsigned next = 0; + char buff[PARAMS_SIZE]; +- unsigned long long size; +- char dev_t[32]; +- int r = 1; + int offset; +- char *delim; +- +- if (!(dmt = dm_task_create(DM_DEVICE_LIST))) +- return 1; ++ struct rename_data *rd = (struct rename_data *)data; + +- dm_task_no_open_count(dmt); +- +- if (!dm_task_run(dmt)) +- goto out; +- +- if (!(names = dm_task_get_names(dmt))) +- goto out; +- +- if (!names->dev) { +- r = 0; /* this is perfectly valid */ +- goto out; +- } ++ if (strncmp(name, rd->old, strlen(rd->old)) != 0) ++ return 0; ++ for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */ ++ snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim, ++ name + offset); ++ dm_rename(name, buff); ++ condlog(4, "partition map %s renamed", name); ++ return 0; ++} + +- if (dm_dev_t(old, &dev_t[0], 32)) +- goto out; ++int ++dm_rename_partmaps (char * old, char * new) ++{ ++ struct rename_data rd; + ++ rd.old = old; ++ rd.new = new; + if (isdigit(new[strlen(new)-1])) +- delim = "p"; ++ rd.delim = "p"; + else +- delim = ""; +- +- do { +- if ( +- /* +- * if devmap target is "linear" +- */ +- (dm_type(names->name, TGT_PART) > 0) && +- +- /* +- * and the multipath mapname and the part mapname start +- * the same +- */ +- !strncmp(names->name, old, strlen(old)) && +- +- /* +- * and we can fetch the map table from the kernel +- */ +- !dm_get_map(names->name, &size, &buff[0]) && +- +- /* +- * and the table maps over the multipath map +- */ +- strstr(buff, dev_t) +- ) { +- /* +- * then it's a kpartx generated partition. +- * Rename it. +- */ +- for (offset = strlen(old); names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do nothing */ +- snprintf(buff, PARAMS_SIZE, "%s%s%s", +- new, delim, names->name + offset); +- dm_rename(names->name, buff); +- condlog(4, "partition map %s renamed", +- names->name); +- } +- +- next = names->next; +- names = (void *) names + next; +- } while (next); +- +- r = 0; +-out: +- dm_task_destroy (dmt); +- return r; ++ rd.delim = ""; ++ return do_foreach_partmaps(old, rename_partmap, &rd); + } + + int diff --git a/0104-RHBZ-631009-deferred-remove.patch b/0104-RHBZ-631009-deferred-remove.patch new file mode 100644 index 0000000..1e1367a --- /dev/null +++ b/0104-RHBZ-631009-deferred-remove.patch @@ -0,0 +1,751 @@ +--- + libmultipath/Makefile | 6 ++ + libmultipath/config.c | 3 + + libmultipath/config.h | 3 + + libmultipath/configure.c | 1 + libmultipath/defaults.h | 1 + libmultipath/devmapper.c | 130 +++++++++++++++++++++++++++++++++++++++------ + libmultipath/devmapper.h | 12 ++-- + libmultipath/dict.c | 116 +++++++++++++++++++++++++++++++++++++++- + libmultipath/propsel.c | 28 +++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 8 ++ + libmultipath/structs_vec.c | 3 - + multipath/multipath.conf.5 | 14 ++++ + multipathd/main.c | 23 +++++-- + 14 files changed, 322 insertions(+), 27 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -337,6 +337,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(user_friendly_names); + merge_num(retain_hwhandler); + merge_num(detect_prio); ++ merge_num(deferred_remove); + + /* + * Make sure features is consistent with +@@ -394,6 +395,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(user_friendly_names); + overwrite_num(retain_hwhandler); + overwrite_num(detect_prio); ++ overwrite_num(deferred_remove); + + /* + * Make sure features is consistent with +@@ -617,6 +619,7 @@ load_config (char * file, struct udev *u + conf->fast_io_fail = DEFAULT_FAST_IO_FAIL; + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; + conf->detect_prio = DEFAULT_DETECT_PRIO; ++ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE; + conf->hw_strmatch = 0; + conf->force_sync = 0; + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -61,6 +61,7 @@ struct hwentry { + int user_friendly_names; + int retain_hwhandler; + int detect_prio; ++ int deferred_remove; + char * bl_product; + }; + +@@ -84,6 +85,7 @@ struct mpentry { + int flush_on_last_del; + int attribute_flags; + int user_friendly_names; ++ int deferred_remove; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -128,6 +130,7 @@ struct config { + int retain_hwhandler; + int detect_prio; + int force_sync; ++ int deferred_remove; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -290,6 +290,7 @@ setup_map (struct multipath * mpp, char + select_dev_loss(mpp); + select_reservation_key(mpp); + select_retain_hwhandler(mpp); ++ select_deferred_remove(mpp); + + sysfs_set_scsi_tmo(mpp); + /* +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -19,6 +19,7 @@ + #define DEFAULT_FAST_IO_FAIL 5 + #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF + #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF ++#define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -103,7 +103,9 @@ dm_lib_prereq (void) + { + char version[64]; + int v[3]; +-#if defined(DM_SUBSYSTEM_UDEV_FLAG0) ++#if defined(LIBDM_API_DEFERRED) ++ int minv[3] = {1, 2, 89}; ++#elif defined(DM_SUBSYSTEM_UDEV_FLAG0) + int minv[3] = {1, 2, 82}; + #elif defined(LIBDM_API_COOKIE) + int minv[3] = {1, 2, 38}; +@@ -202,7 +204,7 @@ dm_prereq (void) + } + + static int +-dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags) { ++dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags, int deferred_remove) { + int r = 0; + int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME || + task == DM_DEVICE_REMOVE)); +@@ -220,7 +222,10 @@ dm_simplecmd (int task, const char *name + if (no_flush) + dm_task_no_flush(dmt); /* for DM_DEVICE_SUSPEND/RESUME */ + #endif +- ++#ifdef LIBDM_API_DEFERRED ++ if (deferred_remove) ++ dm_task_deferred_remove(dmt); ++#endif + if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags)) + goto out; + r = dm_task_run (dmt); +@@ -232,12 +237,18 @@ dm_simplecmd (int task, const char *name + + extern int + dm_simplecmd_flush (int task, const char *name, int needsync, uint16_t udev_flags) { +- return dm_simplecmd(task, name, 0, needsync, udev_flags); ++ return dm_simplecmd(task, name, 0, needsync, udev_flags, 0); + } + + extern int + dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags) { +- return dm_simplecmd(task, name, 1, 1, udev_flags); ++ return dm_simplecmd(task, name, 1, 1, udev_flags, 0); ++} ++ ++extern int ++dm_device_remove (const char *name, int needsync, int deferred_remove) { ++ return dm_simplecmd(DM_DEVICE_REMOVE, name, 0, needsync, 0, ++ deferred_remove); + } + + extern int +@@ -653,7 +664,7 @@ out: + } + + extern int +-_dm_flush_map (const char * mapname, int need_sync) ++_dm_flush_map (const char * mapname, int need_sync, int deferred_remove) + { + int r; + +@@ -663,23 +674,46 @@ _dm_flush_map (const char * mapname, int + if (dm_type(mapname, TGT_MPATH) <= 0) + return 0; /* nothing to do */ + +- if (dm_remove_partmaps(mapname, need_sync)) ++ if (dm_remove_partmaps(mapname, need_sync, deferred_remove)) + return 1; + +- if (dm_get_opencount(mapname)) { ++ if (!deferred_remove && dm_get_opencount(mapname)) { + condlog(2, "%s: map in use", mapname); + return 1; + } + +- r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync, 0); ++ r = dm_device_remove(mapname, need_sync, deferred_remove); + + if (r) { ++ if (deferred_remove && dm_map_present(mapname)) { ++ condlog(4, "multipath map %s remove deferred", ++ mapname); ++ return 2; ++ } + condlog(4, "multipath map %s removed", mapname); + return 0; + } + return 1; + } + ++#ifdef LIBDM_API_DEFERRED ++ ++int ++dm_flush_map_nopaths(const char * mapname, int deferred_remove) ++{ ++ return _dm_flush_map(mapname, 1, deferred_remove); ++} ++ ++#else ++ ++int ++dm_flush_map_nopaths(const char * mapname, int deferred_remove) ++{ ++ return _dm_flush_map(mapname, 1, 0); ++} ++ ++#endif ++ + extern int + dm_suspend_and_flush_map (const char * mapname) + { +@@ -1076,6 +1110,7 @@ out: + + struct remove_data { + int need_sync; ++ int deferred_remove; + }; + + static int +@@ -1084,25 +1119,90 @@ remove_partmap(char *name, void *data) + struct remove_data *rd = (struct remove_data *)data; + + if (dm_get_opencount(name)) { +- dm_remove_partmaps(name, rd->need_sync); +- if (dm_get_opencount(name)) { ++ dm_remove_partmaps(name, rd->need_sync, rd->deferred_remove); ++ if (!rd->deferred_remove && dm_get_opencount(name)) { + condlog(2, "%s: map in use", name); + return 1; + } + } + condlog(4, "partition map %s removed", name); +- dm_simplecmd_flush(DM_DEVICE_REMOVE, name, +- rd->need_sync, 0); ++ dm_device_remove(name, rd->need_sync, rd->deferred_remove); + return 0; + } + + int +-dm_remove_partmaps (const char * mapname, int need_sync) ++dm_remove_partmaps (const char * mapname, int need_sync, int deferred_remove) + { +- struct remove_data rd = { need_sync }; ++ struct remove_data rd = { need_sync, deferred_remove }; + return do_foreach_partmaps(mapname, remove_partmap, &rd); + } + ++#ifdef LIBDM_API_DEFERRED ++ ++static int ++cancel_remove_partmap (char *name, void *unused) ++{ ++ if (dm_message(name, "@cancel_deferred_remove") != 0) ++ condlog(0, "%s: can't cancel deferred remove: %s", name, ++ strerror(errno)); ++ return 0; ++} ++ ++static int ++dm_get_deferred_remove (char * mapname) ++{ ++ int r = -1; ++ struct dm_task *dmt; ++ struct dm_info info; ++ ++ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ return -1; ++ ++ if (!dm_task_set_name(dmt, mapname)) ++ goto out; ++ ++ if (!dm_task_run(dmt)) ++ goto out; ++ ++ if (!dm_task_get_info(dmt, &info)) ++ goto out; ++ ++ r = info.deferred_remove; ++out: ++ dm_task_destroy(dmt); ++ return r; ++} ++ ++int ++dm_cancel_deferred_remove (struct multipath *mpp) ++{ ++ int r = 0; ++ ++ if (!dm_get_deferred_remove(mpp->alias)) ++ return 0; ++ if (mpp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) ++ mpp->deferred_remove = DEFERRED_REMOVE_ON; ++ ++ do_foreach_partmaps(mpp->alias, cancel_remove_partmap, NULL); ++ r = dm_message(mpp->alias, "@cancel_deferred_remove"); ++ if (r) ++ condlog(0, "%s: can't cancel deferred remove: %s", mpp->alias, ++ strerror(errno)); ++ else ++ condlog(2, "%s: canceled deferred remove", mpp->alias); ++ return r; ++} ++ ++#else ++ ++int ++dm_cancel_deferred_remove (struct multipath *mpp) ++{ ++ return 0; ++} ++ ++#endif ++ + static struct dm_info * + alloc_dminfo (void) + { +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -17,15 +17,18 @@ int dm_prereq (void); + int dm_drv_version (unsigned int * version, char * str); + int dm_simplecmd_flush (int, const char *, int, uint16_t); + int dm_simplecmd_noflush (int, const char *, uint16_t); ++int dm_device_remove (const char *, int, int); + int dm_addmap_create (struct multipath *mpp, char *params); + int dm_addmap_reload (struct multipath *mpp, char *params); + int dm_map_present (const char *); + int dm_get_map(const char *, unsigned long long *, char *); + int dm_get_status(char *, char *); + int dm_type(const char *, char *); +-int _dm_flush_map (const char *, int); +-#define dm_flush_map(mapname) _dm_flush_map(mapname, 1) +-#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0) ++int _dm_flush_map (const char *, int, int); ++int dm_flush_map_nopaths(const char * mapname, int deferred_remove); ++#define dm_flush_map(mapname) _dm_flush_map(mapname, 1, 0) ++#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0, 0) ++int dm_cancel_deferred_remove(struct multipath *mpp); + int dm_suspend_and_flush_map(const char * mapname); + int dm_flush_maps (void); + int dm_fail_path(char * mapname, char * path); +@@ -40,7 +43,8 @@ int dm_geteventnr (char *name); + int dm_get_major (char *name); + int dm_get_minor (char *name); + char * dm_mapname(int major, int minor); +-int dm_remove_partmaps (const char * mapname, int need_sync); ++int dm_remove_partmaps (const char * mapname, int need_sync, ++ int deferred_remove); + int dm_get_uuid(char *name, char *uuid); + int dm_get_info (char * mapname, struct dm_info ** dmi); + int dm_rename (char * old, char * new); +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -738,6 +738,29 @@ def_force_sync_handler(vector strvec) + return 0; + } + ++static int ++def_deferred_remove_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->deferred_remove = DEFERRED_REMOVE_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->deferred_remove = DEFERRED_REMOVE_ON; ++ else ++ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1445,6 +1468,33 @@ hw_detect_prio_handler(vector strvec) + return 0; + } + ++static int ++hw_deferred_remove_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->deferred_remove = DEFERRED_REMOVE_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->deferred_remove = DEFERRED_REMOVE_ON; ++ else ++ hwe->deferred_remove = DEFERRED_REMOVE_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -1920,6 +1970,32 @@ mp_names_handler(vector strvec) + return 0; + } + ++static int ++mp_deferred_remove_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "0") == 0)) ++ mpe->deferred_remove = DEFERRED_REMOVE_OFF; ++ else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "1") == 0)) ++ mpe->deferred_remove = DEFERRED_REMOVE_ON; ++ else ++ mpe->deferred_remove = DEFERRED_REMOVE_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2165,7 +2241,7 @@ snprint_mp_reservation_key (char * buff, + return snprintf(buff, len, "0x%" PRIx64, prkey); + } + +- static int ++static int + snprint_mp_user_friendly_names (char * buff, int len, void * data) + { + struct mpentry * mpe = (struct mpentry *)data; +@@ -2179,6 +2255,19 @@ snprint_mp_user_friendly_names (char * b + } + + static int ++snprint_mp_deferred_remove (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->deferred_remove == DEFERRED_REMOVE_UNDEF) ++ return 0; ++ else if (mpe->deferred_remove == DEFERRED_REMOVE_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "yes"); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2507,6 +2596,19 @@ snprint_hw_retain_hwhandler_handler(char + } + + static int ++snprint_hw_deferred_remove(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->deferred_remove == DEFERRED_REMOVE_ON) ++ return snprintf(buff, len, "yes"); ++ else if (hwe->deferred_remove == DEFERRED_REMOVE_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return 0; ++} ++ ++static int + snprint_detect_prio(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2900,6 +3002,15 @@ snprint_def_force_sync(char * buff, int + } + + static int ++snprint_def_deferred_remove(char * buff, int len, void * data) ++{ ++ if (conf->deferred_remove == DEFERRED_REMOVE_ON) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -2968,6 +3079,7 @@ init_keywords(void) + install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio); + install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch); + install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); ++ install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -3032,6 +3144,7 @@ init_keywords(void) + install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names); + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler); + install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio); ++ install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove); + install_sublevel_end(); + + install_keyword_root("multipaths", &multipaths_handler); +@@ -3056,5 +3169,6 @@ init_keywords(void) + install_keyword("gid", &mp_gid_handler, &snprint_mp_gid); + install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key); + install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names); ++ install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -744,6 +744,34 @@ select_retain_hwhandler (struct multipat + } + + extern int ++select_deferred_remove (struct multipath *mp) ++{ ++ if (mp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) { ++ condlog(3, "%s: deferred_remove in progress", mp->alias); ++ return 0; ++ } ++ if (mp->mpe && mp->mpe->deferred_remove) { ++ mp->deferred_remove = mp->mpe->deferred_remove; ++ condlog(3, "%s: deferred_remove = %i (multipath setting)", ++ mp->alias, mp->deferred_remove); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->deferred_remove) { ++ mp->deferred_remove = mp->hwe->deferred_remove; ++ condlog(3, "%s: deferred_remove = %d (controller default)", mp->alias, mp->deferred_remove); ++ return 0; ++ } ++ if (conf->deferred_remove) { ++ mp->deferred_remove = conf->deferred_remove; ++ condlog(3, "%s: deferred_remove = %d (config file default)", mp->alias, mp->deferred_remove); ++ return 0; ++ } ++ mp->deferred_remove = DEFAULT_DEFERRED_REMOVE; ++ condlog(3, "%s: deferred_remove = %d (compiled in default)", mp->alias, mp->deferred_remove); ++ return 0; ++} ++ ++extern int + select_detect_prio (struct path * pp) + { + if (pp->hwe && pp->hwe->detect_prio) { +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -20,3 +20,4 @@ int select_dev_loss(struct multipath *mp + int select_reservation_key(struct multipath *mp); + int select_retain_hwhandler (struct multipath * mp); + int select_detect_prio(struct path * pp); ++int select_deferred_remove(struct multipath *mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -114,6 +114,13 @@ enum detect_prio_states { + DETECT_PRIO_ON, + }; + ++enum deferred_remove_states { ++ DEFERRED_REMOVE_UNDEF, ++ DEFERRED_REMOVE_OFF, ++ DEFERRED_REMOVE_ON, ++ DEFERRED_REMOVE_IN_PROGRESS, ++}; ++ + enum scsi_protocol { + SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ + SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ +@@ -207,6 +214,7 @@ struct multipath { + int attribute_flags; + int fast_io_fail; + int retain_hwhandler; ++ int deferred_remove; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -214,19 +214,30 @@ sync_maps_state(vector mpvec) + } + + static int +-flush_map(struct multipath * mpp, struct vectors * vecs) ++flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths) + { ++ int r; ++ ++ if (nopaths) ++ r = dm_flush_map_nopaths(mpp->alias, mpp->deferred_remove); ++ else ++ r = dm_flush_map(mpp->alias); + /* + * clear references to this map before flushing so we can ignore + * the spurious uevent we may generate with the dm_flush_map call below + */ +- if (dm_flush_map(mpp->alias)) { ++ if (r) { + /* + * May not really be an error -- if the map was already flushed + * from the device mapper by dmsetup(8) for instance. + */ +- condlog(0, "%s: can't flush", mpp->alias); +- return 1; ++ if (r == 1) ++ condlog(0, "%s: can't flush", mpp->alias); ++ else { ++ condlog(2, "%s: devmap deferred remove", mpp->alias); ++ mpp->deferred_remove = DEFERRED_REMOVE_IN_PROGRESS; ++ } ++ return r; + } + else { + dm_lib_release(); +@@ -372,7 +383,7 @@ ev_remove_map (char * devname, char * al + mpp->alias, mpp->dmi->minor, minor); + return 0; + } +- return flush_map(mpp, vecs); ++ return flush_map(mpp, vecs, 0); + } + + static int +@@ -628,7 +639,7 @@ ev_remove_path (struct path *pp, struct + mpp->flush_on_last_del = FLUSH_IN_PROGRESS; + dm_queue_if_no_path(mpp->alias, 0); + } +- if (!flush_map(mpp, vecs)) { ++ if (!flush_map(mpp, vecs, 1)) { + condlog(2, "%s: removed map after" + " removing all paths", + alias); +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -392,6 +392,8 @@ __setup_multipath (struct vectors * vecs + set_no_path_retry(mpp); + select_pg_timeout(mpp); + select_flush_on_last_del(mpp); ++ if (VECTOR_SIZE(mpp->paths) != 0) ++ dm_cancel_deferred_remove(mpp); + } + + return 0; +@@ -565,7 +567,6 @@ int update_multipath (struct vectors *ve + } + } + } +- + return 0; + } + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -420,6 +420,16 @@ only one checker will run at a time. Th + multipathd checkers running in parallel causes significant CPU pressure. The + Default is + .I no ++.TP ++.B deferred_remove ++If set to ++.I yes ++, multipathd will do a deferred remove instead of a regular remove when the ++last path device has been deleted. This means that if the multipath device is ++still in use, it will be freed when the last user closes it. If path is added ++to the multipath device before the last user closes it, the deferred remove ++will be canceled. Default is ++.I no + . + .SH "blacklist section" + The +@@ -521,6 +531,8 @@ section: + .B features + .TP + .B reservation_key ++.TP ++.B deferred_remove + .RE + .PD + .LP +@@ -611,6 +623,8 @@ section: + .B retain_attached_hw_handler + .TP + .B detect_prio ++.TP ++.B deferred_remove + .RE + .PD + .LP +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -36,6 +36,12 @@ ifneq ($(strip $(LIBUDEV_API_RECVBUF)),0 + CFLAGS += -DLIBUDEV_API_RECVBUF + endif + ++LIBDM_API_DEFERRED = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_deferred_remove' /usr/include/libdevmapper.h) ++ ++ifneq ($(strip $(LIBDM_API_DEFERRED)),0) ++ CFLAGS += -DLIBDM_API_DEFERRED ++endif ++ + + all: $(LIBS) + diff --git a/0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch b/0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch new file mode 100644 index 0000000..8c793bb --- /dev/null +++ b/0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch @@ -0,0 +1,10 @@ +diff -purN multipath-tools-130222.orig/multipath/multipath.rules multipath-tools-130222/multipath/multipath.rules +--- multipath-tools-130222.orig/multipath/multipath.rules 2014-11-03 14:37:41.269413134 +0100 ++++ multipath-tools-130222/multipath/multipath.rules 2014-11-03 14:38:43.694281901 +0100 +@@ -45,5 +45,5 @@ ACTION!="change", GOTO="end_mpath" + ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" +-RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" ++ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" + LABEL="end_mpath" diff --git a/0106-RHBZ-1159337-fix-double-free.patch b/0106-RHBZ-1159337-fix-double-free.patch new file mode 100644 index 0000000..cbe4d1e --- /dev/null +++ b/0106-RHBZ-1159337-fix-double-free.patch @@ -0,0 +1,20 @@ +--- + multipathd/main.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -669,9 +669,8 @@ ev_remove_path (struct path *pp, struct + /* + * update our state from kernel + */ +- if (setup_multipath(vecs, mpp)) { +- goto fail; +- } ++ if (setup_multipath(vecs, mpp)) ++ return 1; + sync_map_state(mpp); + + condlog(2, "%s [%s]: path removed from map %s", diff --git a/0107-RHBZ-1169935-no-new-devs.patch b/0107-RHBZ-1169935-no-new-devs.patch new file mode 100644 index 0000000..96d61a4 --- /dev/null +++ b/0107-RHBZ-1169935-no-new-devs.patch @@ -0,0 +1,117 @@ +--- + libmultipath/config.h | 1 + + libmultipath/configure.c | 4 ++-- + libmultipath/wwids.c | 16 +++++++++------- + multipathd/main.c | 8 ++++++-- + multipathd/multipathd.8 | 6 ++++++ + 5 files changed, 24 insertions(+), 11 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -131,6 +131,7 @@ struct config { + int detect_prio; + int force_sync; + int deferred_remove; ++ int no_new_devs; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -776,8 +776,8 @@ coalesce_paths (struct vectors * vecs, v + continue; + + /* If find_multipaths was selected check if the path is valid */ +- if (conf->find_multipaths && !refwwid && +- !should_multipath(pp1, pathvec)) { ++ if ((conf->find_multipaths || conf->no_new_devs) ++ && !refwwid && !should_multipath(pp1, pathvec)) { + orphan_path(pp1); + continue; + } +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -270,13 +270,15 @@ should_multipath(struct path *pp1, vecto + struct path *pp2; + + condlog(4, "checking if %s should be multipathed", pp1->dev); +- vector_foreach_slot(pathvec, pp2, i) { +- if (pp1->dev == pp2->dev) +- continue; +- if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) { +- condlog(3, "found multiple paths with wwid %s, " +- "multipathing %s", pp1->wwid, pp1->dev); +- return 1; ++ if (!conf->no_new_devs) { ++ vector_foreach_slot(pathvec, pp2, i) { ++ if (pp1->dev == pp2->dev) ++ continue; ++ if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) { ++ condlog(3, "found multiple paths with wwid %s, " ++ "multipathing %s", pp1->wwid, pp1->dev); ++ return 1; ++ } + } + } + if (check_wwids_file(pp1->wwid, 0) < 0) { +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -503,7 +503,7 @@ rescan: + return 1; + } + +- if (conf->find_multipaths && ++ if ((conf->find_multipaths || conf->no_new_devs) && + !should_multipath(pp, vecs->pathvec)) { + orphan_path(pp); + return 0; +@@ -1427,6 +1427,7 @@ reconfigure (struct vectors * vecs) + + if (!load_config(DEFAULT_CONFIGFILE, udev)) { + conf->verbosity = old->verbosity; ++ conf->no_new_devs = old->no_new_devs; + conf->daemon = 1; + configure(vecs, 1); + free_config(old); +@@ -1880,12 +1881,15 @@ main (int argc, char *argv[]) + if (!conf) + exit(1); + +- while ((arg = getopt(argc, argv, ":dv:k::")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dnv:k::")) != EOF ) { + switch(arg) { + case 'd': + logsink = 0; + //debug=1; /* ### comment me out ### */ + break; ++ case 'n': ++ conf->no_new_devs = 1; ++ break; + case 'v': + if (sizeof(optarg) > sizeof(char *) || + !isdigit(optarg[0])) +Index: multipath-tools-130222/multipathd/multipathd.8 +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.8 ++++ multipath-tools-130222/multipathd/multipathd.8 +@@ -22,6 +22,12 @@ devmap reconfiguration, so that it can r + .B \-d + Forground Mode. Don't daemonize, and print all messages to stdout and stderr. + .TP ++.B -n ++No new devs mode. When multipathd is started in this mode, it will only ++create multipath devices if the device wwid is listed in /etc/multipath/wwids. ++This means multipathd will never create a device that hasn't never been ++created before. ++.TP + .B -v "level" + Verbosity level. Print additional information while running multipathd. A level of 0 means only print errors. A level of 3 or greater prints debugging information as well. + .TP diff --git a/0108-RHBZ-1153832-kpartx-remove-devs.patch b/0108-RHBZ-1153832-kpartx-remove-devs.patch new file mode 100644 index 0000000..f02551a --- /dev/null +++ b/0108-RHBZ-1153832-kpartx-remove-devs.patch @@ -0,0 +1,15 @@ +--- + multipath/multipath.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -45,5 +45,5 @@ ACTION!="change", GOTO="end_mpath" + ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" +-ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" ++ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -u $tempnode" + LABEL="end_mpath" diff --git a/0109-RH-read-only-bindings.patch b/0109-RH-read-only-bindings.patch new file mode 100644 index 0000000..536c5d4 --- /dev/null +++ b/0109-RH-read-only-bindings.patch @@ -0,0 +1,27 @@ +--- + multipathd/main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1881,7 +1881,7 @@ main (int argc, char *argv[]) + if (!conf) + exit(1); + +- while ((arg = getopt(argc, argv, ":dnv:k::")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dnv:k::B")) != EOF ) { + switch(arg) { + case 'd': + logsink = 0; +@@ -1900,6 +1900,9 @@ main (int argc, char *argv[]) + case 'k': + uxclnt(optarg); + exit(0); ++ case 'B': ++ conf->bindings_read_only = 1; ++ break; + default: + ; + } diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index 657bd00..f478059 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,7 +1,7 @@ Summary: Tools to manage multipath devices using device-mapper Name: device-mapper-multipath Version: 0.4.9 -Release: 70%{?dist} +Release: 71%{?dist} License: GPL+ Group: System Environment/Base URL: http://christophe.varoqui.free.fr/ @@ -110,6 +110,13 @@ Patch0099: 0099-RH-add-all-devs.patch Patch0100: 0100-RHBZ-1067171-multipath-i-update.patch Patch0101: 0101-RH-adapter-name-wildcard.patch Patch0102: 0102-RHBZ-1160478-mpathconf-template.patch +Patch0103: 0103-RH-cleanup-partmaps-code.patch +Patch0104: 0104-RHBZ-631009-deferred-remove.patch +Patch0105: 0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch +Patch0106: 0106-RHBZ-1159337-fix-double-free.patch +Patch0107: 0107-RHBZ-1169935-no-new-devs.patch +Patch0108: 0108-RHBZ-1153832-kpartx-remove-devs.patch +Patch0109: 0109-RH-read-only-bindings.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -263,6 +270,13 @@ kpartx manages partition creation and removal for device-mapper devices. %patch0100 -p1 %patch0101 -p1 %patch0102 -p1 +%patch0103 -p1 +%patch0104 -p1 +%patch0105 -p1 +%patch0106 -p1 +%patch0107 -p1 +%patch0108 -p1 +%patch0109 -p1 cp %{SOURCE1} . %build @@ -361,6 +375,24 @@ bin/systemctl --no-reload enable multipathd.service >/dev/null 2>&1 ||: %{_mandir}/man8/kpartx.8.gz %changelog +* Mon Dec 15 2014 Benjamin Marzinski 0.4.9-71 +- Add 0103-RH-cleanup-partmaps-code.patch + * code refactoring to prepare for next patch +- Add 0104-RHBZ-631009-deferred-remove.patch + * add deferred_remove option to /etc/multipath.conf +- Add 0105-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch + * Only run kpartx on device activation +- Add 0106-RHBZ-1159337-fix-double-free.patch + * made ev_remove_path exit immediately after failing setup_multipath, since + it handles cleaning up the device +- Add 0107-RHBZ-1169935-no-new-devs.patch + * Add new multipathd option '-n' which keeps multipathd from creating any + multipath devices that aren't in the /etc/multipath/wwids file. +- Add 0108-RHBZ-1153832-kpartx-remove-devs.patch + * switch from 'kpartx -a' to 'kpartx -u' to remove missing devices as well. +- Add 0109-RH-read-only-bindings.patch + * re-enabled -B option for multipathd + * Tue Dec 9 2014 Benjamin Marzinski 0.4.9-70 - Add 0102-RHBZ-1160478-mpathconf-template.patch * mpathconf no longer copies the default config template for the