@@ -144,6 +144,40 @@ uevent_can_discard(struct uevent *uev)
}
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)
{
/*
@@ -215,6 +249,29 @@ uevent_discard(struct list_head *tmpq)
}
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;
@@ -242,6 +299,7 @@ merge_uevq(struct list_head *tmpq)
uevent_discard(tmpq);
list_for_each_entry_reverse(later, tmpq, node) {
+ uevent_filter(later, tmpq);
uevent_merge(later, tmpq);
}
}