@@ -488,6 +488,9 @@ free_config (struct config * conf)
if (conf->uid_attribute)
FREE(conf->uid_attribute);
+ if (conf->uid_attrs)
+ FREE(conf->uid_attrs);
+
if (conf->getuid)
FREE(conf->getuid);
@@ -153,6 +153,7 @@ struct config {
char * multipath_dir;
char * selector;
+ char * uid_attrs;
char * uid_attribute;
char * getuid;
char * features;
@@ -249,6 +249,8 @@ declare_ovr_snprint(selector, print_str)
declare_mp_handler(selector, set_str)
declare_mp_snprint(selector, print_str)
+declare_def_handler(uid_attrs, set_str)
+declare_def_snprint(uid_attrs, print_str)
declare_def_handler(uid_attribute, set_str)
declare_def_snprint_defstr(uid_attribute, print_str,
DEFAULT_UID_ATTRIBUTE)
declare_ovr_handler(uid_attribute, set_str)
@@ -1367,6 +1369,7 @@ init_keywords(vector keywords)
install_keyword("multipath_dir",
&def_multipath_dir_handler, &snprint_def_multipath_dir);
install_keyword("path_selector", &def_selector_handler,
&snprint_def_selector);
install_keyword("path_grouping_policy",
&def_pgpolicy_handler, &snprint_def_pgpolicy);
+ install_keyword("uid_attrs", &def_uid_attrs_handler,
&snprint_def_uid_attrs);
install_keyword("uid_attribute",
&def_uid_attribute_handler, &snprint_def_uid_attribute);
install_keyword("getuid_callout", &def_getuid_handler,
&snprint_def_getuid);
install_keyword("prio", &def_prio_name_handler,
&snprint_def_prio_name);
@@ -33,7 +33,7 @@
int
alloc_path_with_pathinfo (struct config *conf, struct udev_device
*udevice,
- int flag, struct path
**pp_ptr)
+ char *wwid, int flag,
struct path **pp_ptr)
{
int err = PATHINFO_FAILED;
struct path * pp;
@@ -51,6 +51,9 @@ alloc_path_with_pathinfo (struct config *conf, struct
udev_device *udevice,
if (!pp)
return PATHINFO_FAILED;
+ if(wwid)
+ strncpy(pp->wwid, wwid,
sizeof(pp->wwid));
+
if (safe_sprintf(pp->dev, "%s", devname)) {
condlog(0, "pp->dev too small");
} else {
@@ -37,7 +37,7 @@ int path_offline (struct path *);
int get_state (struct path * pp, struct config * conf, int daemon);
int pathinfo (struct path * pp, struct config * conf, int mask);
int alloc_path_with_pathinfo (struct config *conf, struct udev_device
*udevice,
- int flag, struct
path **pp_ptr);
+ char *wwid, int
flag, struct path **pp_ptr);
int store_pathinfo (vector pathvec, struct config *conf,
struct udev_device *udevice, int
flag,
struct path **pp_ptr);
@@ -317,4 +317,45 @@ static inline void list_splice_tail_init(struct
list_head *list,
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n),
member))
+/**
+ * list_for_each_entry_reverse_safe - iterate backwards over list of
given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary
storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos),
member), \
+ n = list_entry(pos->member.prev,
typeof(*pos), member);\
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n),
member))
+
+/**
+ * list_for_some_entry_safe - iterate list from the given begin node to
the given end node safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary
storage
+ * @from: the begin node of the iteration.
+ * @to: the end node of the iteration.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_some_entry_safe(pos, n, from, to, member) \
+ for (pos = list_entry((from)->next, typeof(*pos),
member), \
+ n = list_entry(pos->member.next, typeof(*pos),
member); \
+ &pos->member != (to); \
+ pos = n, n = list_entry(n->member.next, typeof(*n),
member))
+
+/**
+ * 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
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary
storage
+ * @from: the begin node of the iteration.
+ * @to: the end node of the iteration.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_some_entry_reverse_safe(pos, n, from, to, member) \
+ for (pos = list_entry((from)->prev, typeof(*pos),
member), \
+ n = list_entry(pos->member.prev, typeof(*pos),
member); \
+ &pos->member != (to); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n),
member))
+
#endif /* _LIST_H */
@@ -18,6 +18,7 @@
#include "prio.h"
#include "discovery.h"
#include "dict.h"
+#include "util.h"
#include "prioritizers/alua_rtpg.h"
#include <inttypes.h>
@@ -339,6 +340,12 @@ int select_getuid(struct config *conf, struct path
*pp)
{
char *origin;
+ pp->uid_attribute =
parse_uid_attribute_by_attrs(conf->uid_attrs, pp->dev);
+ if (pp->uid_attribute) {
+ origin = "(config file default)";
+ goto out;
+ }
+
pp_set_ovr(getuid);
pp_set_ovr(uid_attribute);
pp_set_hwe(getuid);
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <stdio.h>
+#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <stddef.h>
@@ -38,6 +39,7 @@
#include <linux/netlink.h>
#include <pthread.h>
#include <sys/mman.h>
+#include <sys/time.h>
#include <libudev.h>
#include <errno.h>
@@ -46,6 +48,14 @@
#include "list.h"
#include "uevent.h"
#include "vector.h"
+#include "structs.h"
+#include "util.h"
+#include "config.h"
+#include "blacklist.h"
+
+#define MAX_ACCUMULATION_COUNT 2048
+#define MAX_ACCUMULATION_TIME 30*1000
+#define MIN_BURST_SPEED 10
typedef int (uev_trigger)(struct uevent *, void * trigger_data);
@@ -72,48 +82,300 @@ struct uevent * alloc_uevent (void)
{
struct uevent *uev = MALLOC(sizeof(struct uevent));
- if (uev)
+ if (uev) {
INIT_LIST_HEAD(&uev->node);
+ INIT_LIST_HEAD(&uev->merge_node);
+ }
return uev;
}
void
-service_uevq(struct list_head *tmpq)
+uevq_cleanup(struct list_head *tmpq)
{
struct uevent *uev, *tmp;
list_for_each_entry_safe(uev, tmp, tmpq, node) {
list_del_init(&uev->node);
- if (my_uev_trigger && my_uev_trigger(uev,
my_trigger_data))
- condlog(0, "uevent
trigger error");
-
if (uev->udev)
udev_device_unref(uev->udev);
FREE(uev);
}
}
-static void uevent_cleanup(void *arg)
+void
+uevent_get_wwid(struct uevent *uev)
{
- struct udev *udev = arg;
+ int i;
+ char *uid_attribute;
+ struct config * conf;
+
+ conf = get_multipath_config();
+ uid_attribute =
parse_uid_attribute_by_attrs(conf->uid_attrs, uev->kernel);
+ put_multipath_config(conf);
+
+ if (!uid_attribute)
+ return;
+
+ for (i = 0; uev->envp[i] != NULL; i++) {
+ if (!strncmp(uev->envp[i], uid_attribute,
strlen(uid_attribute)) &&
+ strlen(uev->envp[i]) >
strlen(uid_attribute)) {
+ uev->wwid = uev->envp[i]
+ strlen(uid_attribute) + 1;
+ break;
+ }
+ }
+ free(uid_attribute);
+}
- condlog(3, "Releasing uevent_listen() resources");
- udev_unref(udev);
+bool
+uevent_need_merge(void)
+{
+ struct config * conf;
+ bool need_merge = false;
+
+ conf = get_multipath_config();
+ if (conf->uid_attrs)
+ need_merge = true;
+ put_multipath_config(conf);
+
+ return need_merge;
+}
+
+bool
+uevent_can_discard(struct uevent *uev)
+{
+ char *tmp;
+ char a[11], b[11];
+ struct config * conf;
+
+ /*
+ * keep only block devices, discard partitions
+ */
+ tmp = strstr(uev->devpath, "/block/");
+ if (tmp == NULL){
+ condlog(4, "no /block/ in '%s'",
uev->devpath);
+ return true;
+ }
+ if (sscanf(tmp, "/block/%10s", a) != 1 ||
+ sscanf(tmp, "/block/%10[^/]/%10s", a, b) == 2) {
+ condlog(4, "discard event on %s",
uev->devpath);
+ return true;
+ }
+
+ /*
+ * do not filter dm devices by devnode
+ */
+ if (!strncmp(uev->kernel, "dm-", 3))
+ return false;
+ /*
+ * filter paths devices by devnode
+ */
+ conf = get_multipath_config();
+ if (filter_devnode(conf->blist_devnode,
conf->elist_devnode,
+ uev->kernel) > 0) {
+ put_multipath_config(conf);
+ return true;
+ }
+ put_multipath_config(conf);
+
+ return false;
+}
+
+bool
+uevent_can_filter(struct uevent *earlier, struct uevent *later)
+{
+
+ /*
+ * filter earlier uvents if path has removed later. Eg:
+ * "add path1 |chang path1 |add path2 |remove path1"
+ * can filter as:
+ * "add path2 |remove path1"
+ * uevents "add path1" and "chang path1" are filtered out
+ */
+ if (!strcmp(earlier->kernel, later->kernel) &&
+ !strcmp(later->action, "remove") &&
+ strncmp(later->kernel, "dm-", 3)) {
+ return true;
+ }
+
+ /*
+ * filter change uvents if add uevents exist. Eg:
+ * "change path1| add path1 |add path2"
+ * can filter as:
+ * "add path1 |add path2"
+ * uevent "chang path1" is filtered out
+ */
+ if (!strcmp(earlier->kernel, later->kernel) &&
+ !strcmp(earlier->action, "change") &&
+ !strcmp(later->action, "add") &&
+ strncmp(later->kernel, "dm-", 3)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool
+merge_need_stop(struct uevent *earlier, struct uevent *later)
+{
+ /*
+ * dm uevent do not try to merge with left uevents
+ */
+ if (!strncmp(later->kernel, "dm-", 3))
+ return true;
+
+ /*
+ * we can not make a jugement without wwid,
+ * so it is sensible to stop merging
+ */
+ if (!earlier->wwid || !later->wwid)
+ return true;
+ /*
+ * uevents merging stoped
+ * when we meet an opposite action uevent from the same
LUN to AVOID
+ * "add path1 |remove path1 |add path2 |remove path2 |add
path3"
+ * to merge as "remove path1, path2" and "add path1,
path2, path3"
+ * OR
+ * "remove path1 |add path1 |remove path2 |add path2
|remove path3"
+ * to merge as "add path1, path2" and "remove path1,
path2, path3"
+ * SO
+ * when we meet a non-change uevent from the same LUN
+ * with the same wwid and different action
+ * it would be better to stop merging.
+ */
+ if (!strcmp(earlier->wwid, later->wwid) &&
+ strcmp(earlier->action, later->action) &&
+ strcmp(earlier->action, "change") &&
+ strcmp(later->action, "change"))
+ return true;
+
+ return false;
+}
+
+bool
+uevent_can_merge(struct uevent *earlier, struct uevent *later)
+{
+ /* merge paths uevents
+ * whose wwids exsit and are same
+ * and actions are same,
+ * and actions are addition or deletion
+ */
+ if (earlier->wwid && later->wwid &&
+ !strcmp(earlier->wwid, later->wwid) &&
+ !strcmp(earlier->action, later->action) &&
+ strncmp(earlier->action, "change", 6) &&
+ strncmp(earlier->kernel, "dm-", 3)) {
+ return true;
+ }
+
+ return false;
}
void
-uevq_cleanup(struct list_head *tmpq)
+uevent_prepare(struct list_head *tmpq)
+{
+ struct uevent *uev, *tmp;
+
+ list_for_each_entry_reverse_safe(uev, tmp, tmpq, node) {
+ if (uevent_can_discard(uev)) {
+ list_del_init(&uev->node);
+ if (uev->udev)
+ udev_device_unref(uev->udev);
+ FREE(uev);
+ continue;
+ }
+
+ if (strncmp(uev->kernel, "dm-", 3) &&
+ uevent_need_merge())
+ uevent_get_wwid(uev);
+ }
+}
+
+void
+uevent_filter(struct uevent *later, struct list_head *tmpq)
+{
+ struct uevent *earlier, *tmp;
+
+ list_for_some_entry_reverse_safe(earlier, tmp,
&later->node, tmpq, node) {
+ /*
+ * filter unnessary earlier uevents
+ * by the later uevent
+ */
+ if (uevent_can_filter(earlier, later)) {
+ condlog(2, "uevent: %s-%s
has filtered by uevent: %s-%s",
+ earlier->kernel, earlier->action,
+ later->kernel, later->action);
+
+ list_del_init(&earlier->node);
+ if (earlier->udev)
+ udev_device_unref(earlier->udev);
+ FREE(earlier);
+ }
+ }
+}
+
+void
+uevent_merge(struct uevent *later, struct list_head *tmpq)
+{
+ struct uevent *earlier, *tmp;
+
+ list_for_some_entry_reverse_safe(earlier, tmp,
&later->node, tmpq, node) {
+ if (merge_need_stop(earlier, later))
+ break;
+ /*
+ * merge earlier uevents to the later
uevent
+ */
+ if (uevent_can_merge(earlier, later)) {
+ condlog(2, "merged
uevent: %s-%s-%s with uevent: %s-%s-%s",
+ earlier->action, earlier->kernel, earlier->wwid,
+ later->action, later->kernel, later->wwid);
+
+ list_move(&earlier->node,
&later->merge_node);
+ }
+ }
+}
+
+void
+merge_uevq(struct list_head *tmpq)
+{
+ struct uevent *later;
+
+ uevent_prepare(tmpq);
+ list_for_each_entry_reverse(later, tmpq, node) {
+ uevent_filter(later, tmpq);
+ if(uevent_need_merge())
+ uevent_merge(later,
tmpq);
+ }
+}
+
+void
+service_uevq(struct list_head *tmpq)
{
struct uevent *uev, *tmp;
list_for_each_entry_safe(uev, tmp, tmpq, node) {
list_del_init(&uev->node);
+
+ if (my_uev_trigger && my_uev_trigger(uev,
my_trigger_data))
+ condlog(0, "uevent
trigger error");
+
+ uevq_cleanup(&uev->merge_node);
+
+ if (uev->udev)
+ udev_device_unref(uev->udev);
FREE(uev);
}
}
+static void uevent_cleanup(void *arg)
+{
+ struct udev *udev = arg;
+
+ condlog(3, "Releasing uevent_listen() resources");
+ udev_unref(udev);
+}
+
/*
* Service the uevent queue.
*/
@@ -142,6 +404,7 @@ int uevent_dispatch(int (*uev_trigger)(struct uevent
*, void * trigger_data),
pthread_mutex_unlock(uevq_lockp);
if (!my_uev_trigger)
break;
+ merge_uevq(&uevq_tmp);
service_uevq(&uevq_tmp);
}
condlog(3, "Terminating uev service queue");
@@ -442,11 +705,43 @@ struct uevent *uevent_from_udev_device(struct
udev_device *dev)
return uev;
}
+bool uevent_burst(struct timeval *start_time, int events)
+{
+ struct timeval diff_time, end_time;
+ unsigned long speed;
+ unsigned long eclipse_ms;
+
+ if(events > MAX_ACCUMULATION_COUNT) {
+ condlog(2, "burst got %u uevents, too
much uevents, stopped", events);
+ return false;
+ }
+
+ gettimeofday(&end_time, NULL);
+ timersub(&end_time, start_time, &diff_time);
+
+ eclipse_ms = diff_time.tv_sec * 1000 + diff_time.tv_usec
/ 1000;
+
+ if (eclipse_ms == 0)
+ return true;
+
+ if (eclipse_ms > MAX_ACCUMULATION_TIME) {
+ condlog(2, "burst continued %lu ms, too
long time, stopped", eclipse_ms);
+ return false;
+ }
+
+ speed = (events * 1000) / eclipse_ms;
+ if (speed > MIN_BURST_SPEED)
+ return true;
+
+ return false;
+}
+
int uevent_listen(struct udev *udev)
{
int err = 2;
struct udev_monitor *monitor = NULL;
int fd, socket_flags, events;
+ struct timeval start_time;
int need_failback = 1;
int timeout = 30;
LIST_HEAD(uevlisten_tmp);
@@ -500,6 +795,7 @@ int uevent_listen(struct udev *udev)
}
events = 0;
+ gettimeofday(&start_time, NULL);
while (1) {
struct uevent *uev;
struct udev_device *dev;
@@ -514,7 +810,7 @@ int uevent_listen(struct udev *udev)
errno = 0;
fdcount = poll(&ev_poll, 1,
poll_timeout);
if (fdcount && ev_poll.revents & POLLIN)
{
- timeout = 0;
+ timeout =
uevent_burst(&start_time, events + 1) ? 1 : 0;
dev =
udev_monitor_receive_device(monitor);
if (!dev) {
condlog(0, "failed getting udev device");
@@ -547,6 +843,7 @@ int uevent_listen(struct udev *udev)
pthread_mutex_unlock(uevq_lockp);
events = 0;
}
+ gettimeofday(&start_time, NULL);
timeout = 30;
}
need_failback = 0;
@@ -17,11 +17,13 @@ struct udev;
struct uevent {
struct list_head node;
+ struct list_head merge_node;
struct udev_device *udev;
char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
char *devpath;
char *action;
char *kernel;
+ char *wwid;
unsigned long seqnum;
char *envp[HOTPLUG_NUM_ENVP];
};
@@ -261,6 +261,46 @@ dev_t parse_devt(const char *dev_t)
return makedev(maj, min);
}
+char *parse_uid_attribute_by_attrs(char *uid_attrs, char *path_dev)
+{
+ char *uid_attribute;
+ char *uid_attr_record;
+ char *dev;
+ char *attr;
+ char *tmp;
+ int count;
+
+ if(!uid_attrs || !path_dev)
+ return NULL;
+
+ count = get_word(uid_attrs, &uid_attr_record);
+ while (uid_attr_record) {
+ tmp = strrchr(uid_attr_record, ':');
+ if (!tmp) {
+ free(uid_attr_record);
+ if (!count)
+ break;
+ count =
get_word(uid_attrs + count, &uid_attr_record);
+ continue;
+ }
+ dev = uid_attr_record;
+ attr = tmp + 1;
+ *tmp = '\0';
+
+ if(!strncmp(path_dev, dev, strlen(dev)))
{
+ uid_attribute =
STRDUP(attr);
+ free(uid_attr_record);
+ return uid_attribute;
+ }
+
+ free(uid_attr_record);
+ if (!count)
+ break;
+ count = get_word(uid_attrs + count,
&uid_attr_record);
+ }
+ return NULL;
+}
+
void
setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached)
{
@@ -12,6 +12,7 @@ size_t strlcat(char *dst, const char *src, size_t size);
int devt2devname (char *, int, char *);
dev_t parse_devt(const char *dev_t);
char *convert_dev(char *dev, int is_path_device);
+char *parse_uid_attribute_by_attrs(char *uid_attrs, char *path_dev);
void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int
detached);
#define safe_sprintf(var, format, args...) \
@@ -209,6 +209,24 @@ The default is: \fBfailover\fR
.
.
.TP
+.B uid_attrs
+The udev attribute providing a unique path identifier for corresponding
+type of path devices. If this field is configured and matched with type
+of device, it would override any other methods providing for device
+unique identifier in config file, and it would activate merging uevents
+according to the identifier to promote effiecncy in processing uevents.
+Tt has no default value, if you want to identify path by udev attribute
+and to activate merging uevents for SCSI and DAS device, you can set
+it's value as:
+.RS
+.TP
+\fBuid_attrs "sd:ID_SERIAL dasd:ID_UID"\fR
+.TP
+The default is: \fB<unset>\fR
+.RE
+.
+.
+.TP
.B uid_attribute
The udev attribute providing a unique path identifier.
.RS
@@ -670,7 +670,7 @@ cli_add_path (void * v, char ** reply, int * len, void
* data)
pp->checkint = conf->checkint;
}
put_multipath_config(conf);
- return ev_add_path(pp, vecs);
+ return ev_add_path(pp, vecs, 1);
blacklisted:
*reply = strdup("blacklisted\n");
*len = strlen(*reply) + 1;
@@ -692,7 +692,7 @@ cli_del_path (void * v, char ** reply, int * len, void
* data)
condlog(0, "%s: path already removed",
param);
return 1;
}
- return ev_remove_path(pp, vecs);
+ return ev_remove_path(pp, vecs, 1);
}
int
@@ -608,7 +608,7 @@ ev_remove_map (char * devname, char * alias, int
minor, struct vectors * vecs)
}
static int
-uev_add_path (struct uevent *uev, struct vectors * vecs)
+uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
{
struct path *pp;
int ret = 0, i;
@@ -641,7 +641,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)
DI_ALL | DI_BLACKLIST);
put_multipath_config(conf);
if (r == PATHINFO_OK)
- ret =
ev_add_path(pp, vecs);
+ ret =
ev_add_path(pp, vecs, need_do_map);
else if (r ==
PATHINFO_SKIPPED) {
condlog(3, "%s: remove blacklisted path",
uev->kernel);
@@ -665,7 +665,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)
*/
conf = get_multipath_config();
ret = alloc_path_with_pathinfo(conf, uev->udev,
- DI_ALL, &pp);
+ uev->wwid, DI_ALL, &pp);
put_multipath_config(conf);
if (!pp) {
if (ret == PATHINFO_SKIPPED)
@@ -681,7 +681,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)
conf = get_multipath_config();
pp->checkint = conf->checkint;
put_multipath_config(conf);
- ret = ev_add_path(pp, vecs);
+ ret = ev_add_path(pp, vecs, need_do_map);
} else {
condlog(0, "%s: failed to store path
info, "
"dropping event",
@@ -699,7 +699,7 @@ uev_add_path (struct uevent *uev, struct vectors *
vecs)
* 1: error
*/
int
-ev_add_path (struct path * pp, struct vectors * vecs)
+ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
{
struct multipath * mpp;
char params[PARAMS_SIZE] = {0};
@@ -767,6 +767,13 @@ rescan:
/* persistent reservation check*/
mpath_pr_event_handle(pp);
+ if (!need_do_map)
+ return 0;
+
+ if (!dm_map_present(mpp->alias)) {
+ mpp->action = ACT_CREATE;
+ start_waiter = 1;
+ }
/*
* push the map to the device-mapper
*/
@@ -833,7 +840,7 @@ fail:
}
static int
-uev_remove_path (struct uevent *uev, struct vectors * vecs)
+uev_remove_path (struct uevent *uev, struct vectors * vecs, int
need_do_map)
{
struct path *pp;
int ret;
@@ -844,7 +851,7 @@ uev_remove_path (struct uevent *uev, struct vectors *
vecs)
pthread_testcancel();
pp = find_path_by_dev(vecs->pathvec, uev->kernel);
if (pp)
- ret = ev_remove_path(pp, vecs);
+ ret = ev_remove_path(pp, vecs,
need_do_map);
lock_cleanup_pop(vecs->lock);
if (!pp) {
/* Not an error; path might have been
purged earlier */
@@ -855,7 +862,7 @@ uev_remove_path (struct uevent *uev, struct vectors *
vecs)
}
int
-ev_remove_path (struct path *pp, struct vectors * vecs)
+ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map)
{
struct multipath * mpp;
int i, retval = 0;
@@ -918,6 +925,8 @@ ev_remove_path (struct path *pp, struct vectors *
vecs)
goto out;
}
+ if (!need_do_map)
+ goto out;
/*
* reload the map
*/
@@ -995,7 +1004,7 @@ uev_update_path (struct uevent *uev, struct vectors *
vecs)
}
if (pp->initialized ==
INIT_REQUESTED_UDEV)
- retval =
uev_add_path(uev, vecs);
+ retval =
uev_add_path(uev, vecs, 1);
else if (mpp && ro >= 0) {
condlog(2, "%s: update
path write_protect to '%d' (uevent)", uev->kernel, ro);
@@ -1016,7 +1025,7 @@ out:
int flag = DI_SYSFS |
DI_WWID;
conf =
get_multipath_config();
- retval =
alloc_path_with_pathinfo(conf, uev->udev, flag, NULL);
+ retval =
alloc_path_with_pathinfo(conf, uev->udev, uev->wwid, flag, NULL);
put_multipath_config(conf);
if (retval ==
PATHINFO_SKIPPED) {
@@ -1077,40 +1086,15 @@ uxsock_trigger (char * str, char ** reply, int *
len, void * trigger_data)
return r;
}
-static int
-uev_discard(char * devpath)
-{
- char *tmp;
- char a[11], b[11];
-
- /*
- * keep only block devices, discard partitions
- */
- tmp = strstr(devpath, "/block/");
- if (tmp == NULL){
- condlog(4, "no /block/ in '%s'",
devpath);
- return 1;
- }
- if (sscanf(tmp, "/block/%10s", a) != 1 ||
- sscanf(tmp, "/block/%10[^/]/%10s", a, b) == 2) {
- condlog(4, "discard event on %s",
devpath);
- return 1;
- }
- return 0;
-}
-
int
uev_trigger (struct uevent * uev, void * trigger_data)
{
int r = 0;
struct vectors * vecs;
- struct config *conf;
+ struct uevent *merge_uev, *tmp;
vecs = (struct vectors *)trigger_data;
- if (uev_discard(uev->devpath))
- return 0;
-
pthread_cleanup_push(config_cleanup, NULL);
pthread_mutex_lock(&config_lock);
if (running_state != DAEMON_IDLE &&
@@ -1139,28 +1123,21 @@ uev_trigger (struct uevent * uev, void *
trigger_data)
}
/*
- * path add/remove event
+ * path add/remove/change event, add/remove maybe merged
*/
- conf = get_multipath_config();
- if (filter_devnode(conf->blist_devnode,
conf->elist_devnode,
- uev->kernel) > 0) {
- put_multipath_config(conf);
- goto out;
+ list_for_each_entry_safe(merge_uev, tmp,
&uev->merge_node, node) {
+ if (!strncmp(merge_uev->action, "add",
3))
+ r +=
uev_add_path(merge_uev, vecs, 0);
+ if (!strncmp(merge_uev->action, "remove",
6))
+ r +=
uev_remove_path(merge_uev, vecs, 0);
}
- put_multipath_config(conf);
- if (!strncmp(uev->action, "add", 3)) {
- r = uev_add_path(uev, vecs);
- goto out;
- }
- if (!strncmp(uev->action, "remove", 6)) {
- r = uev_remove_path(uev, vecs);
- goto out;
- }
- if (!strncmp(uev->action, "change", 6)) {
- r = uev_update_path(uev, vecs);
- goto out;
- }
+ if (!strncmp(uev->action, "add", 3))
+ r += uev_add_path(uev, vecs, 1);
+ if (!strncmp(uev->action, "remove", 6))
+ r += uev_remove_path(uev, vecs, 1);
+ if (!strncmp(uev->action, "change", 6))
+ r += uev_update_path(uev, vecs);
out:
return r;
@@ -1570,7 +1547,7 @@ check_path (struct vectors * vecs, struct path * pp,
int ticks)
conf =
get_multipath_config();
ret = pathinfo(pp, conf,
DI_ALL | DI_BLACKLIST);
if (ret == PATHINFO_OK) {
- ev_add_path(pp, vecs);
+ ev_add_path(pp, vecs, 1);
pp->tick
= 1;
} else if (ret ==
PATHINFO_SKIPPED) {
put_multipath_config(conf);
@@ -1686,7 +1663,7 @@ check_path (struct vectors * vecs, struct path * pp,
int ticks)
}
if (!disable_reinstate &&
reinstate_path(pp, add_active)) {
condlog(3, "%s: reload
map", pp->dev);
- ev_add_path(pp, vecs);
+ ev_add_path(pp, vecs, 1);
pp->tick = 1;
return 0;
}
@@ -1709,7 +1686,7 @@ check_path (struct vectors * vecs, struct path * pp,
int ticks)
/* Clear IO errors */
if (reinstate_path(pp,
0)) {
condlog(3, "%s: reload map", pp->dev);
- ev_add_path(pp, vecs);
+ ev_add_path(pp, vecs, 1);
pp->tick
= 1;
return 0;
}
@@ -22,8 +22,8 @@ void exit_daemon(void);
const char * daemon_status(void);
int need_to_delay_reconfig (struct vectors *);
int reconfigure (struct vectors *);
-int ev_add_path (struct path *, struct vectors *);
-int ev_remove_path (struct path *, struct vectors *);
+int ev_add_path (struct path *, struct vectors *, int);
+int ev_remove_path (struct path *, struct vectors *, int);
int ev_add_map (char *, char *, struct vectors *);
int ev_remove_map (char *, char *, int, struct vectors *);
void sync_map_state (struct multipath *);