From: tang.junhui <tang.jun...@zte.com.cn>

These uevents are going to be merged:
1) uevents come from paths and
2) uevents type is same and
3) uevents type is addition or deletion and
4) uevents merge_id is same.

Change-Id: I05ee057391c092aa0c5f989b7a4f9cb550bb4d98
Signed-off-by: tang.junhui <tang.jun...@zte.com.cn>
---
 libmultipath/uevent.c | 117 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 105 insertions(+), 12 deletions(-)

diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index f231dad..7282a51 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -89,6 +89,20 @@ struct uevent * alloc_uevent (void)
        return uev;
 }
 
+void
+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 (uev->udev)
+                       udev_device_unref(uev->udev);
+               FREE(uev);
+       }
+}
+
 bool
 uevent_can_discard(struct uevent *uev)
 {
@@ -129,6 +143,62 @@ uevent_can_discard(struct uevent *uev)
        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 merge_id,
+        * so it is sensible to stop merging
+        */
+       if (!earlier->merge_id || !later->merge_id)
+               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 merge_id and different action
+        * it would be better to stop merging.
+        */
+       if (!strcmp(earlier->merge_id, later->merge_id) &&
+           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 merge_ids exsit and are same
+        * and actions are same,
+        * and actions are addition or deletion
+        */
+       if (earlier->merge_id && later->merge_id &&
+           !strcmp(earlier->merge_id, later->merge_id) &&
+           !strcmp(earlier->action, later->action) &&
+           strncmp(earlier->action, "change", 6) &&
+           strncmp(earlier->kernel, "dm-", 3)) {
+               return true;
+       }
+
+       return false;
+}
+
 void
 uevent_discard(struct list_head *tmpq)
 {
@@ -145,6 +215,38 @@ uevent_discard(struct list_head *tmpq)
 }
 
 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(3, "merged uevent: %s-%s-%s with uevent: 
%s-%s-%s",
+                               earlier->action, earlier->kernel, 
earlier->merge_id,
+                               later->action, later->kernel, later->merge_id);
+
+                       list_move(&earlier->node, &later->merge_node);
+               }
+       }
+}
+
+void
+merge_uevq(struct list_head *tmpq)
+{
+       struct uevent *later;
+
+       uevent_discard(tmpq);
+       list_for_each_entry_reverse(later, tmpq, node) {
+               uevent_merge(later, tmpq);
+       }
+}
+
+void
 service_uevq(struct list_head *tmpq)
 {
        struct uevent *uev, *tmp;
@@ -155,6 +257,8 @@ service_uevq(struct list_head *tmpq)
                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);
@@ -169,17 +273,6 @@ static void uevent_cleanup(void *arg)
        udev_unref(udev);
 }
 
-void
-uevq_cleanup(struct list_head *tmpq)
-{
-       struct uevent *uev, *tmp;
-
-       list_for_each_entry_safe(uev, tmp, tmpq, node) {
-               list_del_init(&uev->node);
-               FREE(uev);
-       }
-}
-
 /*
  * Service the uevent queue.
  */
@@ -208,7 +301,7 @@ int uevent_dispatch(int (*uev_trigger)(struct uevent *, 
void * trigger_data),
                pthread_mutex_unlock(uevq_lockp);
                if (!my_uev_trigger)
                        break;
-               uevent_discard(&uevq_tmp);
+               merge_uevq(&uevq_tmp);
                service_uevq(&uevq_tmp);
        }
        condlog(3, "Terminating uev service queue");
-- 
2.8.1.windows.1


--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

Reply via email to