<font size=2 face="sans-serif">Hello ALL,</font>
<br>
<br><font size=2 face="sans-serif">This patch is based on previous two
series patches, and modified</font>
<br><font size=2>according to Ben's suggestion as bellow: </font>
<br>
<br><font size=2>1) add configuration in the defaults section <br>
uid_attrs "sd:ID_SERIAL dasd:ID_UID" <br>
it would override any other configurations if this <br>
filed is configured and matched; <br>
<br>
2) In uevent processing thread, we will assign wwid<br>
according the label in uevents by this configuration; <br>
<br>
3) this patch will take back: <br>
[PATCH 12/12] libmultipath: use existing wwid when <br>
wwid has already been existed in uevent <br>
<br>
4) if this field is not configured, only do filtering and <br>
no merging works.</font>
<br>
<br><font size=2>I found it is hard to modify patch based on series, so
I only push one</font>
<br><font size=2>patch this time. If it is hard too review, please let
me known, I will</font>
<br><font size=2>split it into a series of small patches.</font>
<br>
<br><font size=2>Thanks,</font>
<br><font size=2>Tang Junhui </font>
<br>
<br>
<br>
<br>
<br><font size=1 color=#5f5f5f face="sans-serif">发件人:
</font><font size=1 face="sans-serif">tang.junhui@zte.com.cn</font>
<br><font size=1 color=#5f5f5f face="sans-serif">收件人:
</font><font size=1 face="sans-serif">christophe.varoqui@opensvc.com,
bmarzins@redhat.com, hare@suse.de, mwilck@suse.com, bart.vanassche@sandisk.com,
</font>
<br><font size=1 color=#5f5f5f face="sans-serif">抄送:
</font><font size=1 face="sans-serif">dm-devel@redhat.com,
zhang.kai16@zte.com.cn, tang.wenjun3@zte.com.cn, tang.junhui@zte.com.cn</font>
<br><font size=1 color=#5f5f5f face="sans-serif">日期:
</font><font size=1 face="sans-serif">2017/01/18
15:39</font>
<br><font size=1 color=#5f5f5f face="sans-serif">主题:
</font><font size=1 face="sans-serif">[PATCH] multipath-tools:
improve processing efficiency for addition and deletion of multipath devices</font>
<br>
<hr noshade>
<br>
<br>
<br><tt><font size=2>From: "tang.junhui" <tang.junhui@zte.com.cn><br>
<br>
Change-Id: I3f81a55fff389f991f915927000b281d7e263cc5<br>
Signed-off-by: tang.junhui <tang.junhui@zte.com.cn><br>
<br>
This patch used to improve processing efficiency for addition and deletion<br>
of multipath devices.<br>
<br>
This patch is tested pass by ZTE multipath automatic testing system.<br>
The modification reduces the system consumption(such as CPU) and shortens<br>
the processing time obviously in scene of massive multipath devices<br>
addition or deletion.<br>
<br>
The main processing flow of code is:<br>
1) add uid_attrs configuration in the defaults section:<br>
It is configured udev attribute which providing a unique path identifier<br>
for corresponding type of path devices. If this field is configured
and<br>
matched with type of device, it would override any other methods
providing<br>
for device unique identifier in config file, and it would activate
merging<br>
uevents according to the identifier to promote effiecncy in processing<br>
uevents. Tt has no default value, so defaultly only uevents filtering<br>
works, and uevents merging does not works, if users want to identify
path<br>
by udev attribute and to activate merging uevents for SCSI and
DAS device,<br>
they can set it's value as:<br>
"sd:ID_SERIAL dasd:ID_UID"<br>
2) uevents accumulation in uevents burst scene:<br>
wait one seconds for more uevents in uevent_listen() in uevents
burst<br>
situations<br>
3) uevents preparing, filtering and merging:<br>
discard unuse uevents and fetch path idendifier from uevents;<br>
filter uevents;<br>
merge uevents.<br>
4) uevents proccessing:<br>
proccess the merged uevents in uev->merge_node list without
calling<br>
domap();<br>
proccess the last uevents uev with calling domap().<br>
<br>
Any comment will be welcome, and it would be appreciated if these<br>
patches would be considered for inclusion in the upstream<br>
multipath-tools.<br>
<br>
Thank you all,<br>
Tang Junhui<br>
---<br>
libmultipath/config.c | 3 +<br>
libmultipath/config.h | 1 +<br>
libmultipath/dict.c | 3 +<br>
libmultipath/discovery.c | 5 +-<br>
libmultipath/discovery.h | 2 +-<br>
libmultipath/list.h | 41 ++++++<br>
libmultipath/propsel.c | 7 +<br>
libmultipath/uevent.c | 319 +++++++++++++++++++++++++++++++++++++++++++--<br>
libmultipath/uevent.h | 2 +<br>
libmultipath/util.c | 40 ++++++<br>
libmultipath/util.h | 1 +<br>
multipath/multipath.conf.5 | 18 +++<br>
multipathd/cli_handlers.c | 4 +-<br>
multipathd/main.c | 93 +++++--------<br>
multipathd/main.h | 4 +-<br>
15 files changed, 468 insertions(+), 75 deletions(-)<br>
<br>
diff --git a/libmultipath/config.c b/libmultipath/config.c<br>
index 15ddbd8..765e91d 100644<br>
--- a/libmultipath/config.c<br>
+++ b/libmultipath/config.c<br>
@@ -488,6 +488,9 @@ free_config (struct config * conf)<br>
if
(conf->uid_attribute)<br>
FREE(conf->uid_attribute);<br>
<br>
+
if (conf->uid_attrs)<br>
+
FREE(conf->uid_attrs);<br>
+<br>
if
(conf->getuid)<br>
FREE(conf->getuid);<br>
<br>
diff --git a/libmultipath/config.h b/libmultipath/config.h<br>
index 9670020..ab85930 100644<br>
--- a/libmultipath/config.h<br>
+++ b/libmultipath/config.h<br>
@@ -153,6 +153,7 @@ struct config {<br>
<br>
char
* multipath_dir;<br>
char
* selector;<br>
+
char * uid_attrs;<br>
char
* uid_attribute;<br>
char
* getuid;<br>
char
* features;<br>
diff --git a/libmultipath/dict.c b/libmultipath/dict.c<br>
index dc21846..0a531d1 100644<br>
--- a/libmultipath/dict.c<br>
+++ b/libmultipath/dict.c<br>
@@ -249,6 +249,8 @@ declare_ovr_snprint(selector, print_str)<br>
declare_mp_handler(selector, set_str)<br>
declare_mp_snprint(selector, print_str)<br>
<br>
+declare_def_handler(uid_attrs, set_str)<br>
+declare_def_snprint(uid_attrs, print_str)<br>
declare_def_handler(uid_attribute, set_str)<br>
declare_def_snprint_defstr(uid_attribute, print_str, DEFAULT_UID_ATTRIBUTE)<br>
declare_ovr_handler(uid_attribute, set_str)<br>
@@ -1367,6 +1369,7 @@ init_keywords(vector keywords)<br>
install_keyword("multipath_dir",
&def_multipath_dir_handler, &snprint_def_multipath_dir);<br>
install_keyword("path_selector",
&def_selector_handler, &snprint_def_selector);<br>
install_keyword("path_grouping_policy",
&def_pgpolicy_handler, &snprint_def_pgpolicy);<br>
+
install_keyword("uid_attrs", &def_uid_attrs_handler, &snprint_def_uid_attrs);<br>
install_keyword("uid_attribute",
&def_uid_attribute_handler, &snprint_def_uid_attribute);<br>
install_keyword("getuid_callout",
&def_getuid_handler, &snprint_def_getuid);<br>
install_keyword("prio",
&def_prio_name_handler, &snprint_def_prio_name);<br>
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c<br>
index d1aec31..14904f2 100644<br>
--- a/libmultipath/discovery.c<br>
+++ b/libmultipath/discovery.c<br>
@@ -33,7 +33,7 @@<br>
<br>
int<br>
alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,<br>
-
int flag, struct path **pp_ptr)<br>
+
char *wwid, int flag, struct path **pp_ptr)<br>
{<br>
int
err = PATHINFO_FAILED;<br>
struct
path * pp;<br>
@@ -51,6 +51,9 @@ alloc_path_with_pathinfo (struct config *conf, struct
udev_device *udevice,<br>
if
(!pp)<br>
return PATHINFO_FAILED;<br>
<br>
+
if(wwid)<br>
+
strncpy(pp->wwid,
wwid, sizeof(pp->wwid));<br>
+<br>
if
(safe_sprintf(pp->dev, "%s", devname)) {<br>
condlog(0, "pp->dev too small");<br>
}
else {<br>
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h<br>
index 3039268..d16a69a 100644<br>
--- a/libmultipath/discovery.h<br>
+++ b/libmultipath/discovery.h<br>
@@ -37,7 +37,7 @@ int path_offline (struct path *);<br>
int get_state (struct path * pp, struct config * conf, int daemon);<br>
int pathinfo (struct path * pp, struct config * conf, int mask);<br>
int alloc_path_with_pathinfo (struct config *conf, struct udev_device
*udevice,<br>
-
int flag, struct path **pp_ptr);<br>
+
char *wwid, int flag, struct path **pp_ptr);<br>
int store_pathinfo (vector pathvec, struct config *conf,<br>
struct udev_device *udevice, int flag,<br>
struct path **pp_ptr);<br>
diff --git a/libmultipath/list.h b/libmultipath/list.h<br>
index ceaa381..2b1dcf3 100644<br>
--- a/libmultipath/list.h<br>
+++ b/libmultipath/list.h<br>
@@ -317,4 +317,45 @@ static inline void list_splice_tail_init(struct list_head
*list,<br>
&pos->member != (head);
\<br>
pos = n, n = list_entry(n->member.next, typeof(*n), member))<br>
<br>
+/**<br>
+ * list_for_each_entry_reverse_safe - iterate backwards over list of given
type safe against removal of list entry<br>
+ * @pos:
the type * to use as a loop counter.<br>
+ * @n:
another
type * to use as temporary storage<br>
+ * @head:
the head for your list.<br>
+ * @member:
the name of the list_struct within the struct.<br>
+ */<br>
+#define list_for_each_entry_reverse_safe(pos, n, head, member)
\<br>
+
for (pos = list_entry((head)->prev, typeof(*pos), member),
\<br>
+
n = list_entry(pos->member.prev, typeof(*pos), member);\<br>
+
&pos->member != (head);
\<br>
+
pos = n, n = list_entry(n->member.prev, typeof(*n),
member))<br>
+<br>
+/**<br>
+ * list_for_some_entry_safe - iterate list from the given begin node to
the given end node safe against removal of list entry<br>
+ * @pos:
the type * to use as a loop counter.<br>
+ * @n:
another
type * to use as temporary storage<br>
+ * @from:
the begin node of the iteration.<br>
+ * @to:
the
end node of the iteration.<br>
+ * @member:
the name of the list_struct within the struct.<br>
+ */<br>
+#define list_for_some_entry_safe(pos, n, from, to, member)
\<br>
+
for (pos = list_entry((from)->next, typeof(*pos), member),
\<br>
+
n = list_entry(pos->member.next, typeof(*pos), member);
\<br>
+
&pos->member != (to);
\<br>
+
pos = n, n = list_entry(n->member.next, typeof(*n),
member))<br>
+<br>
+/**<br>
+ * list_for_some_entry_reverse_safe - iterate backwards list from the
given begin node to the given end node safe against removal of list entry<br>
+ * @pos:
the type * to use as a loop counter.<br>
+ * @n:
another
type * to use as temporary storage<br>
+ * @from:
the begin node of the iteration.<br>
+ * @to:
the
end node of the iteration.<br>
+ * @member:
the name of the list_struct within the struct.<br>
+ */<br>
+#define list_for_some_entry_reverse_safe(pos, n, from, to, member)
\<br>
+
for (pos = list_entry((from)->prev, typeof(*pos), member),
\<br>
+
n = list_entry(pos->member.prev, typeof(*pos), member);
\<br>
+
&pos->member != (to);
\<br>
+
pos = n, n = list_entry(n->member.prev, typeof(*n),
member))<br>
+<br>
#endif /* _LIST_H */<br>
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c<br>
index c0bc616..5a58dc0 100644<br>
--- a/libmultipath/propsel.c<br>
+++ b/libmultipath/propsel.c<br>
@@ -18,6 +18,7 @@<br>
#include "prio.h"<br>
#include "discovery.h"<br>
#include "dict.h"<br>
+#include "util.h"<br>
#include "prioritizers/alua_rtpg.h"<br>
#include <inttypes.h><br>
<br>
@@ -339,6 +340,12 @@ int select_getuid(struct config *conf, struct path
*pp)<br>
{<br>
char
*origin;<br>
<br>
+
pp->uid_attribute = parse_uid_attribute_by_attrs(conf->uid_attrs,
pp->dev);<br>
+
if (pp->uid_attribute) {<br>
+
origin
= "(config file default)";<br>
+
goto
out;<br>
+
}<br>
+<br>
pp_set_ovr(getuid);<br>
pp_set_ovr(uid_attribute);<br>
pp_set_hwe(getuid);<br>
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c<br>
index 7edcce1..7e4ac04 100644<br>
--- a/libmultipath/uevent.c<br>
+++ b/libmultipath/uevent.c<br>
@@ -24,6 +24,7 @@<br>
<br>
#include <unistd.h><br>
#include <stdio.h><br>
+#include <stdbool.h><br>
#include <errno.h><br>
#include <stdlib.h><br>
#include <stddef.h><br>
@@ -38,6 +39,7 @@<br>
#include <linux/netlink.h><br>
#include <pthread.h><br>
#include <sys/mman.h><br>
+#include <sys/time.h><br>
#include <libudev.h><br>
#include <errno.h><br>
<br>
@@ -46,6 +48,14 @@<br>
#include "list.h"<br>
#include "uevent.h"<br>
#include "vector.h"<br>
+#include "structs.h"<br>
+#include "util.h"<br>
+#include "config.h"<br>
+#include "blacklist.h"<br>
+<br>
+#define MAX_ACCUMULATION_COUNT 2048<br>
+#define MAX_ACCUMULATION_TIME 30*1000<br>
+#define MIN_BURST_SPEED 10<br>
<br>
typedef int (uev_trigger)(struct uevent *, void * trigger_data);<br>
<br>
@@ -72,48 +82,300 @@ struct uevent * alloc_uevent (void)<br>
{<br>
struct
uevent *uev = MALLOC(sizeof(struct uevent));<br>
<br>
-
if (uev)<br>
+
if (uev) {<br>
INIT_LIST_HEAD(&uev->node);<br>
+
INIT_LIST_HEAD(&uev->merge_node);<br>
+
}<br>
<br>
return
uev;<br>
}<br>
<br>
void<br>
-service_uevq(struct list_head *tmpq)<br>
+uevq_cleanup(struct list_head *tmpq)<br>
{<br>
struct
uevent *uev, *tmp;<br>
<br>
list_for_each_entry_safe(uev,
tmp, tmpq, node) {<br>
list_del_init(&uev->node);<br>
<br>
-
if
(my_uev_trigger && my_uev_trigger(uev, my_trigger_data))<br>
-
condlog(0, "uevent trigger error");<br>
-<br>
if (uev->udev)<br>
udev_device_unref(uev->udev);<br>
FREE(uev);<br>
}<br>
}<br>
<br>
-static void uevent_cleanup(void *arg)<br>
+void<br>
+uevent_get_wwid(struct uevent *uev)<br>
{<br>
-
struct udev *udev = arg;<br>
+
int i;<br>
+
char *uid_attribute;<br>
+
struct config * conf;<br>
+
<br>
+
conf = get_multipath_config();<br>
+
uid_attribute = parse_uid_attribute_by_attrs(conf->uid_attrs, uev->kernel);<br>
+
put_multipath_config(conf);
<br>
+
<br>
+
if (!uid_attribute)<br>
+
return;<br>
+
<br>
+
for (i = 0; uev->envp[i] != NULL; i++) {<br>
+
if
(!strncmp(uev->envp[i], uid_attribute, strlen(uid_attribute)) &&<br>
+
strlen(uev->envp[i]) > strlen(uid_attribute)) {<br>
+
uev->wwid = uev->envp[i] + strlen(uid_attribute) + 1;<br>
+
break;<br>
+
}<br>
+
}<br>
+
free(uid_attribute);<br>
+}<br>
<br>
-
condlog(3, "Releasing uevent_listen() resources");<br>
-
udev_unref(udev);<br>
+bool<br>
+uevent_need_merge(void)<br>
+{<br>
+
struct config * conf;<br>
+
bool need_merge = false;<br>
+<br>
+
conf = get_multipath_config();<br>
+
if (conf->uid_attrs)<br>
+
need_merge
= true;<br>
+
put_multipath_config(conf);
<br>
+<br>
+
return need_merge;<br>
+}<br>
+<br>
+bool<br>
+uevent_can_discard(struct uevent *uev)<br>
+{<br>
+
char *tmp;<br>
+
char a[11], b[11];<br>
+
struct config * conf;<br>
+<br>
+
/*<br>
+
* keep only block devices, discard partitions<br>
+
*/<br>
+
tmp = strstr(uev->devpath, "/block/");<br>
+
if (tmp == NULL){<br>
+
condlog(4,
"no /block/ in '%s'", uev->devpath);<br>
+
return
true;<br>
+
}<br>
+
if (sscanf(tmp, "/block/%10s", a) != 1 ||<br>
+
sscanf(tmp, "/block/%10[^/]/%10s", a, b) == 2)
{<br>
+
condlog(4,
"discard event on %s", uev->devpath);<br>
+
return
true;<br>
+
}<br>
+<br>
+
/* <br>
+
* do not filter dm devices by devnode<br>
+
*/<br>
+
if (!strncmp(uev->kernel, "dm-", 3))<br>
+
return
false;<br>
+
/* <br>
+
* filter paths devices by devnode<br>
+
*/<br>
+
conf = get_multipath_config();<br>
+
if (filter_devnode(conf->blist_devnode, conf->elist_devnode,<br>
+
uev->kernel) > 0) {<br>
+
put_multipath_config(conf);<br>
+
return
true;<br>
+
}<br>
+
put_multipath_config(conf);<br>
+<br>
+
return false;<br>
+}<br>
+<br>
+bool<br>
+uevent_can_filter(struct uevent *earlier, struct uevent *later)<br>
+{<br>
+<br>
+
/*<br>
+
* filter earlier uvents if path has removed later. Eg:<br>
+
* "add path1 |chang path1 |add path2 |remove path1"<br>
+
* can filter as:<br>
+
* "add path2 |remove path1"<br>
+
* uevents "add path1" and "chang path1" are filtered
out<br>
+
*/<br>
+
if (!strcmp(earlier->kernel, later->kernel) &&<br>
+
!strcmp(later->action,
"remove") &&<br>
+
strncmp(later->kernel,
"dm-", 3)) {<br>
+
return
true;<br>
+
}<br>
+<br>
+
/*<br>
+
* filter change uvents if add uevents exist. Eg:<br>
+
* "change path1| add path1 |add path2"<br>
+
* can filter as:<br>
+
* "add path1 |add path2"<br>
+
* uevent "chang path1" is filtered out<br>
+
*/<br>
+
if (!strcmp(earlier->kernel, later->kernel) &&<br>
+
!strcmp(earlier->action,
"change") &&<br>
+
!strcmp(later->action,
"add") &&<br>
+
strncmp(later->kernel,
"dm-", 3)) {<br>
+
return
true;<br>
+
}<br>
+<br>
+
return false;<br>
+}<br>
+<br>
+bool<br>
+merge_need_stop(struct uevent *earlier, struct uevent *later)<br>
+{<br>
+
/*<br>
+
* dm uevent do not try to merge with left uevents<br>
+
*/<br>
+
if (!strncmp(later->kernel, "dm-", 3))<br>
+
return
true;<br>
+<br>
+
/*<br>
+
* we can not make a jugement without wwid,<br>
+
* so it is sensible to stop merging<br>
+
*/<br>
+
if (!earlier->wwid || !later->wwid)<br>
+
return
true;<br>
+
/*<br>
+
* uevents merging stoped<br>
+
* when we meet an opposite action uevent from the same LUN to AVOID<br>
+
* "add path1 |remove path1 |add path2 |remove path2 |add path3"<br>
+
* to merge as "remove path1, path2" and "add path1,
path2, path3"<br>
+
* OR<br>
+
* "remove path1 |add path1 |remove path2 |add path2 |remove
path3"<br>
+
* to merge as "add path1, path2" and "remove path1,
path2, path3"<br>
+
* SO<br>
+
* when we meet a non-change uevent from the same LUN<br>
+
* with the same wwid and different action<br>
+
* it would be better to stop merging.<br>
+
*/<br>
+
if (!strcmp(earlier->wwid, later->wwid) &&<br>
+
strcmp(earlier->action, later->action) &&<br>
+
strcmp(earlier->action, "change") &&<br>
+
strcmp(later->action, "change"))<br>
+
return
true;<br>
+<br>
+
return false;<br>
+}<br>
+<br>
+bool<br>
+uevent_can_merge(struct uevent *earlier, struct uevent *later)<br>
+{<br>
+
/* merge paths uevents<br>
+
* whose wwids exsit and are same<br>
+
* and actions are same,<br>
+
* and actions are addition or deletion<br>
+
*/<br>
+
if (earlier->wwid && later->wwid &&<br>
+
!strcmp(earlier->wwid, later->wwid) &&<br>
+
!strcmp(earlier->action, later->action) &&<br>
+
strncmp(earlier->action, "change", 6) &&<br>
+
strncmp(earlier->kernel, "dm-", 3)) {<br>
+
return
true;<br>
+
}<br>
+<br>
+
return false;<br>
}<br>
<br>
void<br>
-uevq_cleanup(struct list_head *tmpq)<br>
+uevent_prepare(struct list_head *tmpq)<br>
+{<br>
+
struct uevent *uev, *tmp;<br>
+<br>
+
list_for_each_entry_reverse_safe(uev, tmp, tmpq, node) {<br>
+
if
(uevent_can_discard(uev)) {<br>
+
list_del_init(&uev->node);<br>
+
if (uev->udev)<br>
+
udev_device_unref(uev->udev);<br>
+
FREE(uev);<br>
+
continue;<br>
+
}<br>
+<br>
+
if
(strncmp(uev->kernel, "dm-", 3) &&<br>
+
uevent_need_merge())<br>
+
uevent_get_wwid(uev);<br>
+
}<br>
+}<br>
+<br>
+void<br>
+uevent_filter(struct uevent *later, struct list_head *tmpq)<br>
+{<br>
+
struct uevent *earlier, *tmp;<br>
+<br>
+
list_for_some_entry_reverse_safe(earlier, tmp, &later->node, tmpq,
node) {<br>
+
/*<br>
+
* filter unnessary earlier uevents <br>
+
* by the later uevent<br>
+
*/<br>
+
if
(uevent_can_filter(earlier, later)) {<br>
+
condlog(2, "uevent: %s-%s has filtered by uevent: %s-%s",<br>
+
earlier->kernel,
earlier->action, <br>
+
later->kernel,
later->action);<br>
+<br>
+
list_del_init(&earlier->node);<br>
+
if (earlier->udev)<br>
+
udev_device_unref(earlier->udev);<br>
+
FREE(earlier);<br>
+
}<br>
+
}<br>
+}<br>
+<br>
+void<br>
+uevent_merge(struct uevent *later, struct list_head *tmpq)<br>
+{<br>
+
struct uevent *earlier, *tmp;<br>
+<br>
+
list_for_some_entry_reverse_safe(earlier, tmp, &later->node, tmpq,
node) {<br>
+
if
(merge_need_stop(earlier, later))<br>
+
break;<br>
+
/*<br>
+
* merge earlier uevents to the later uevent<br>
+
*/<br>
+
if
(uevent_can_merge(earlier, later)) {<br>
+
condlog(2, "merged uevent: %s-%s-%s with uevent: %s-%s-%s",<br>
+
earlier->action,
earlier->kernel, earlier->wwid,<br>
+
later->action,
later->kernel, later->wwid);<br>
+<br>
+
list_move(&earlier->node, &later->merge_node);<br>
+
}<br>
+
}<br>
+}<br>
+<br>
+void<br>
+merge_uevq(struct list_head *tmpq)<br>
+{<br>
+
struct uevent *later;<br>
+<br>
+
uevent_prepare(tmpq);<br>
+
list_for_each_entry_reverse(later, tmpq, node) {<br>
+
uevent_filter(later,
tmpq);<br>
+
if(uevent_need_merge())<br>
+
uevent_merge(later, tmpq);<br>
+
}<br>
+}<br>
+<br>
+void<br>
+service_uevq(struct list_head *tmpq)<br>
{<br>
struct
uevent *uev, *tmp;<br>
<br>
list_for_each_entry_safe(uev,
tmp, tmpq, node) {<br>
list_del_init(&uev->node);<br>
+<br>
+
if
(my_uev_trigger && my_uev_trigger(uev, my_trigger_data))<br>
+
condlog(0, "uevent trigger error");<br>
+<br>
+
uevq_cleanup(&uev->merge_node);<br>
+<br>
+
if
(uev->udev)<br>
+
udev_device_unref(uev->udev);<br>
FREE(uev);<br>
}<br>
}<br>
<br>
+static void uevent_cleanup(void *arg)<br>
+{<br>
+
struct udev *udev = arg;<br>
+<br>
+
condlog(3, "Releasing uevent_listen() resources");<br>
+
udev_unref(udev);<br>
+}<br>
+<br>
/*<br>
* Service the uevent queue.<br>
*/<br>
@@ -142,6 +404,7 @@ int uevent_dispatch(int (*uev_trigger)(struct uevent
*, void * trigger_data),<br>
pthread_mutex_unlock(uevq_lockp);<br>
if (!my_uev_trigger)<br>
break;<br>
+
merge_uevq(&uevq_tmp);<br>
service_uevq(&uevq_tmp);<br>
}<br>
condlog(3,
"Terminating uev service queue");<br>
@@ -442,11 +705,43 @@ struct uevent *uevent_from_udev_device(struct udev_device
*dev)<br>
return
uev;<br>
}<br>
<br>
+bool uevent_burst(struct timeval *start_time, int events)<br>
+{<br>
+
struct timeval diff_time, end_time;<br>
+
unsigned long speed;<br>
+
unsigned long eclipse_ms;<br>
+<br>
+
if(events > MAX_ACCUMULATION_COUNT) {<br>
+
condlog(2,
"burst got %u uevents, too much uevents, stopped", events);<br>
+
return
false;<br>
+
}<br>
+<br>
+
gettimeofday(&end_time, NULL);<br>
+
timersub(&end_time, start_time, &diff_time);<br>
+<br>
+
eclipse_ms = diff_time.tv_sec * 1000 + diff_time.tv_usec / 1000;<br>
+<br>
+
if (eclipse_ms == 0)<br>
+
return
true;<br>
+<br>
+
if (eclipse_ms > MAX_ACCUMULATION_TIME) {<br>
+
condlog(2,
"burst continued %lu ms, too long time, stopped", eclipse_ms);<br>
+
return
false;<br>
+
}</font></tt>
<br><tt><font size=2>+<br>
+
speed = (events * 1000) / eclipse_ms;<br>
+
if (speed > MIN_BURST_SPEED)<br>
+
return
true;<br>
+<br>
+
return false;<br>
+}<br>
+<br>
int uevent_listen(struct udev *udev)<br>
{<br>
int
err = 2;<br>
struct
udev_monitor *monitor = NULL;<br>
int
fd, socket_flags, events;<br>
+
struct timeval start_time;<br>
int
need_failback = 1;<br>
int
timeout = 30;<br>
LIST_HEAD(uevlisten_tmp);<br>
@@ -500,6 +795,7 @@ int uevent_listen(struct udev *udev)<br>
}<br>
<br>
events
= 0;<br>
+
gettimeofday(&start_time, NULL);<br>
while
(1) {<br>
struct uevent *uev;<br>
struct udev_device *dev;<br>
@@ -514,7 +810,7 @@ int uevent_listen(struct udev *udev)<br>
errno = 0;<br>
fdcount = poll(&ev_poll, 1, poll_timeout);<br>
if (fdcount && ev_poll.revents & POLLIN) {<br>
-
timeout = 0;<br>
+
timeout = uevent_burst(&start_time, events + 1) ? 1 : 0;<br>
dev
= udev_monitor_receive_device(monitor);<br>
if
(!dev) {<br>
condlog(0, "failed getting udev device");<br>
@@ -547,6 +843,7 @@ int uevent_listen(struct udev *udev)<br>
pthread_mutex_unlock(uevq_lockp);<br>
events
= 0;<br>
}<br>
+
gettimeofday(&start_time,
NULL);<br>
timeout = 30;<br>
}<br>
need_failback
= 0;<br>
diff --git a/libmultipath/uevent.h b/libmultipath/uevent.h<br>
index 9d22dcd..61a4207 100644<br>
--- a/libmultipath/uevent.h<br>
+++ b/libmultipath/uevent.h<br>
@@ -17,11 +17,13 @@ struct udev;<br>
<br>
struct uevent {<br>
struct
list_head node;<br>
+
struct list_head merge_node;<br>
struct
udev_device *udev;<br>
char
buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];<br>
char
*devpath;<br>
char
*action;<br>
char
*kernel;<br>
+
char *wwid;<br>
unsigned
long seqnum;<br>
char
*envp[HOTPLUG_NUM_ENVP];<br>
};<br>
diff --git a/libmultipath/util.c b/libmultipath/util.c<br>
index 03a5738..e5a4a28 100644<br>
--- a/libmultipath/util.c<br>
+++ b/libmultipath/util.c<br>
@@ -261,6 +261,46 @@ dev_t parse_devt(const char *dev_t)<br>
return
makedev(maj, min);<br>
}<br>
<br>
+char *parse_uid_attribute_by_attrs(char *uid_attrs, char *path_dev)<br>
+{<br>
+
char *uid_attribute;<br>
+
char *uid_attr_record;<br>
+
char *dev;<br>
+
char *attr;<br>
+
char *tmp;<br>
+
int count;<br>
+<br>
+
if(!uid_attrs || !path_dev)<br>
+
return
NULL;<br>
+<br>
+
count = get_word(uid_attrs, &uid_attr_record);<br>
+
while (uid_attr_record) {<br>
+
tmp
= strrchr(uid_attr_record, ':');<br>
+
if
(!tmp) {<br>
+
free(uid_attr_record);<br>
+
if (!count)<br>
+
break;<br>
+
count = get_word(uid_attrs + count, &uid_attr_record);<br>
+
continue;<br>
+
}<br>
+
dev
= uid_attr_record;<br>
+
attr
= tmp + 1;<br>
+
*tmp
= '\0';<br>
+<br>
+
if(!strncmp(path_dev,
dev, strlen(dev))) {<br>
+
uid_attribute = STRDUP(attr);<br>
+
free(uid_attr_record);<br>
+
return uid_attribute;<br>
+
}<br>
+<br>
+
free(uid_attr_record);<br>
+
if
(!count)<br>
+
break;<br>
+
count
= get_word(uid_attrs + count, &uid_attr_record);<br>
+
}<br>
+
return NULL;<br>
+}<br>
+<br>
void<br>
setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached)<br>
{<br>
diff --git a/libmultipath/util.h b/libmultipath/util.h<br>
index f3b37ee..793f2b7 100644<br>
--- a/libmultipath/util.h<br>
+++ b/libmultipath/util.h<br>
@@ -12,6 +12,7 @@ size_t strlcat(char *dst, const char *src, size_t size);<br>
int devt2devname (char *, int, char *);<br>
dev_t parse_devt(const char *dev_t);<br>
char *convert_dev(char *dev, int is_path_device);<br>
+char *parse_uid_attribute_by_attrs(char *uid_attrs, char *path_dev);<br>
void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);<br>
<br>
#define safe_sprintf(var, format, args...)
\<br>
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5<br>
index 36589f5..63c63c2 100644<br>
--- a/multipath/multipath.conf.5<br>
+++ b/multipath/multipath.conf.5<br>
@@ -209,6 +209,24 @@ The default is: \fBfailover\fR<br>
.<br>
.<br>
.TP<br>
+.B uid_attrs<br>
+The udev attribute providing a unique path identifier for corresponding
<br>
+type of path devices. If this field is configured and matched with type<br>
+of device, it would override any other methods providing for device<br>
+unique identifier in config file, and it would activate merging uevents<br>
+according to the identifier to promote effiecncy in processing uevents.<br>
+Tt has no default value, if you want to identify path by udev attribute<br>
+and to activate merging uevents for SCSI and DAS device, you can set<br>
+it's value as:<br>
+.RS<br>
+.TP<br>
+\fBuid_attrs "sd:ID_SERIAL dasd:ID_UID"\fR<br>
+.TP<br>
+The default is: \fB<unset>\fR<br>
+.RE<br>
+.<br>
+.<br>
+.TP<br>
.B uid_attribute<br>
The udev attribute providing a unique path identifier.<br>
.RS<br>
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c<br>
index b0eeca6..12f85de 100644<br>
--- a/multipathd/cli_handlers.c<br>
+++ b/multipathd/cli_handlers.c<br>
@@ -670,7 +670,7 @@ cli_add_path (void * v, char ** reply, int * len, void
* data)<br>
pp->checkint = conf->checkint;<br>
}<br>
put_multipath_config(conf);<br>
-
return ev_add_path(pp, vecs);<br>
+
return ev_add_path(pp, vecs, 1);<br>
blacklisted:<br>
*reply
= strdup("blacklisted\n");<br>
*len
= strlen(*reply) + 1;<br>
@@ -692,7 +692,7 @@ cli_del_path (void * v, char ** reply, int * len, void
* data)<br>
condlog(0, "%s: path already removed", param);<br>
return 1;<br>
}<br>
-
return ev_remove_path(pp, vecs);<br>
+
return ev_remove_path(pp, vecs, 1);<br>
}<br>
<br>
int<br>
diff --git a/multipathd/main.c b/multipathd/main.c<br>
index adc3258..e513f7d 100644<br>
--- a/multipathd/main.c<br>
+++ b/multipathd/main.c<br>
@@ -608,7 +608,7 @@ ev_remove_map (char * devname, char * alias, int minor,
struct vectors * vecs)<br>
}<br>
<br>
static int<br>
-uev_add_path (struct uevent *uev, struct vectors * vecs)<br>
+uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)<br>
{<br>
struct
path *pp;<br>
int
ret = 0, i;<br>
@@ -641,7 +641,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)<br>
DI_ALL | DI_BLACKLIST);<br>
put_multipath_config(conf);<br>
if
(r == PATHINFO_OK)<br>
-
ret
= ev_add_path(pp, vecs);<br>
+
ret
= ev_add_path(pp, vecs, need_do_map);<br>
else
if (r == PATHINFO_SKIPPED) {<br>
condlog(3, "%s: remove blacklisted path",<br>
uev->kernel);<br>
@@ -665,7 +665,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)<br>
*/<br>
conf
= get_multipath_config();<br>
ret
= alloc_path_with_pathinfo(conf, uev->udev,<br>
-
DI_ALL, &pp);<br>
+
uev->wwid, DI_ALL, &pp);<br>
put_multipath_config(conf);<br>
if
(!pp) {<br>
if (ret == PATHINFO_SKIPPED)<br>
@@ -681,7 +681,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)<br>
conf = get_multipath_config();<br>
pp->checkint = conf->checkint;<br>
put_multipath_config(conf);<br>
-
ret
= ev_add_path(pp, vecs);<br>
+
ret
= ev_add_path(pp, vecs, need_do_map);<br>
}
else {<br>
condlog(0, "%s: failed to store path info, "<br>
"dropping
event",<br>
@@ -699,7 +699,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)<br>
* 1: error<br>
*/<br>
int<br>
-ev_add_path (struct path * pp, struct vectors * vecs)<br>
+ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)<br>
{<br>
struct
multipath * mpp;<br>
char
params[PARAMS_SIZE] = {0};<br>
@@ -767,6 +767,13 @@ rescan:<br>
/*
persistent reservation check*/<br>
mpath_pr_event_handle(pp);<br>
<br>
+
if (!need_do_map)<br>
+
return
0;<br>
+<br>
+
if (!dm_map_present(mpp->alias)) {<br>
+
mpp->action
= ACT_CREATE;<br>
+
start_waiter
= 1;<br>
+
}<br>
/*<br>
* push the map to the device-mapper<br>
*/<br>
@@ -833,7 +840,7 @@ fail:<br>
}<br>
<br>
static int<br>
-uev_remove_path (struct uevent *uev, struct vectors * vecs)<br>
+uev_remove_path (struct uevent *uev, struct vectors * vecs, int need_do_map)<br>
{<br>
struct
path *pp;<br>
int
ret;<br>
@@ -844,7 +851,7 @@ uev_remove_path (struct uevent *uev, struct vectors
* vecs)<br>
pthread_testcancel();<br>
pp
= find_path_by_dev(vecs->pathvec, uev->kernel);<br>
if
(pp)<br>
-
ret
= ev_remove_path(pp, vecs);<br>
+
ret
= ev_remove_path(pp, vecs, need_do_map);<br>
lock_cleanup_pop(vecs->lock);<br>
if
(!pp) {<br>
/* Not an error; path might have been purged earlier */<br>
@@ -855,7 +862,7 @@ uev_remove_path (struct uevent *uev, struct vectors
* vecs)<br>
}<br>
<br>
int<br>
-ev_remove_path (struct path *pp, struct vectors * vecs)<br>
+ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map)<br>
{<br>
struct
multipath * mpp;<br>
int
i, retval = 0;<br>
@@ -918,6 +925,8 @@ ev_remove_path (struct path *pp, struct vectors * vecs)<br>
goto
out;<br>
}<br>
<br>
+
if
(!need_do_map)<br>
+
goto out;<br>
/*<br>
* reload the map<br>
*/<br>
@@ -995,7 +1004,7 @@ uev_update_path (struct uevent *uev, struct vectors
* vecs)<br>
}<br>
<br>
if (pp->initialized == INIT_REQUESTED_UDEV)<br>
-
retval = uev_add_path(uev, vecs);<br>
+
retval = uev_add_path(uev, vecs, 1);<br>
else if (mpp && ro >= 0) {<br>
condlog(2,
"%s: update path write_protect to '%d' (uevent)", uev->kernel,
ro);<br>
<br>
@@ -1016,7 +1025,7 @@ out:<br>
int
flag = DI_SYSFS | DI_WWID;<br>
<br>
conf
= get_multipath_config();<br>
-
retval = alloc_path_with_pathinfo(conf, uev->udev, flag, NULL);<br>
+
retval = alloc_path_with_pathinfo(conf, uev->udev, uev->wwid, flag,
NULL);<br>
put_multipath_config(conf);<br>
<br>
if
(retval == PATHINFO_SKIPPED) {<br>
@@ -1077,40 +1086,15 @@ uxsock_trigger (char * str, char ** reply, int
* len, void * trigger_data)<br>
return
r;<br>
}<br>
<br>
-static int<br>
-uev_discard(char * devpath)<br>
-{<br>
-
char *tmp;<br>
-
char a[11], b[11];<br>
-<br>
-
/*<br>
-
* keep only block devices, discard partitions<br>
-
*/<br>
-
tmp = strstr(devpath, "/block/");<br>
-
if (tmp == NULL){<br>
-
condlog(4,
"no /block/ in '%s'", devpath);<br>
-
return
1;<br>
-
}<br>
-
if (sscanf(tmp, "/block/%10s", a) != 1 ||<br>
-
sscanf(tmp, "/block/%10[^/]/%10s", a, b) == 2)
{<br>
-
condlog(4,
"discard event on %s", devpath);<br>
-
return
1;<br>
-
}<br>
-
return 0;<br>
-}<br>
-<br>
int<br>
uev_trigger (struct uevent * uev, void * trigger_data)<br>
{<br>
int
r = 0;<br>
struct
vectors * vecs;<br>
-
struct config *conf;<br>
+
struct uevent *merge_uev, *tmp;<br>
<br>
vecs
= (struct vectors *)trigger_data;<br>
<br>
-
if (uev_discard(uev->devpath))<br>
-
return
0;<br>
-<br>
pthread_cleanup_push(config_cleanup,
NULL);<br>
pthread_mutex_lock(&config_lock);<br>
if
(running_state != DAEMON_IDLE &&<br>
@@ -1139,28 +1123,21 @@ uev_trigger (struct uevent * uev, void * trigger_data)<br>
}<br>
<br>
/*<br>
-
* path add/remove event<br>
+
* path add/remove/change event, add/remove maybe merged<br>
*/<br>
-
conf = get_multipath_config();<br>
-
if (filter_devnode(conf->blist_devnode, conf->elist_devnode,<br>
-
uev->kernel) > 0) {<br>
-
put_multipath_config(conf);<br>
-
goto
out;<br>
+
list_for_each_entry_safe(merge_uev, tmp, &uev->merge_node, node)
{<br>
+
if
(!strncmp(merge_uev->action, "add", 3))<br>
+
r += uev_add_path(merge_uev, vecs, 0);<br>
+
if
(!strncmp(merge_uev->action, "remove", 6))<br>
+
r += uev_remove_path(merge_uev, vecs, 0);<br>
}<br>
-
put_multipath_config(conf);<br>
<br>
-
if (!strncmp(uev->action, "add", 3)) {<br>
-
r
= uev_add_path(uev, vecs);<br>
-
goto
out;<br>
-
}<br>
-
if (!strncmp(uev->action, "remove", 6)) {<br>
-
r
= uev_remove_path(uev, vecs);<br>
-
goto
out;<br>
-
}<br>
-
if (!strncmp(uev->action, "change", 6)) {<br>
-
r
= uev_update_path(uev, vecs);<br>
-
goto
out;<br>
-
}<br>
+
if (!strncmp(uev->action, "add", 3))<br>
+
r
+= uev_add_path(uev, vecs, 1);<br>
+
if (!strncmp(uev->action, "remove", 6))<br>
+
r
+= uev_remove_path(uev, vecs, 1);<br>
+
if (!strncmp(uev->action, "change", 6))<br>
+
r
+= uev_update_path(uev, vecs);<br>
<br>
out:<br>
return
r;<br>
@@ -1570,7 +1547,7 @@ check_path (struct vectors * vecs, struct path *
pp, int ticks)<br>
conf
= get_multipath_config();<br>
ret
= pathinfo(pp, conf, DI_ALL | DI_BLACKLIST);<br>
if
(ret == PATHINFO_OK) {<br>
-
ev_add_path(pp,
vecs);<br>
+
ev_add_path(pp,
vecs, 1);<br>
pp->tick = 1;<br>
}
else if (ret == PATHINFO_SKIPPED) {<br>
put_multipath_config(conf);<br>
@@ -1686,7 +1663,7 @@ check_path (struct vectors * vecs, struct path *
pp, int ticks)<br>
}<br>
if (!disable_reinstate && reinstate_path(pp, add_active)) {<br>
condlog(3,
"%s: reload map", pp->dev);<br>
-
ev_add_path(pp, vecs);<br>
+
ev_add_path(pp, vecs, 1);<br>
pp->tick
= 1;<br>
return
0;<br>
}<br>
@@ -1709,7 +1686,7 @@ check_path (struct vectors * vecs, struct path *
pp, int ticks)<br>
/*
Clear IO errors */<br>
if
(reinstate_path(pp, 0)) {<br>
condlog(3, "%s: reload map", pp->dev);<br>
-
ev_add_path(pp,
vecs);<br>
+
ev_add_path(pp,
vecs, 1);<br>
pp->tick = 1;<br>
return 0;<br>
}<br>
diff --git a/multipathd/main.h b/multipathd/main.h<br>
index f72580d..094b04f 100644<br>
--- a/multipathd/main.h<br>
+++ b/multipathd/main.h<br>
@@ -22,8 +22,8 @@ void exit_daemon(void);<br>
const char * daemon_status(void);<br>
int need_to_delay_reconfig (struct vectors *);<br>
int reconfigure (struct vectors *);<br>
-int ev_add_path (struct path *, struct vectors *);<br>
-int ev_remove_path (struct path *, struct vectors *);<br>
+int ev_add_path (struct path *, struct vectors *, int);<br>
+int ev_remove_path (struct path *, struct vectors *, int);<br>
int ev_add_map (char *, char *, struct vectors *);<br>
int ev_remove_map (char *, char *, int, struct vectors *);<br>
void sync_map_state (struct multipath *);<br>
-- <br>
2.8.1.windows.1<br>
<br>
</font></tt>
<br>