From mboxrd@z Thu Jan 1 00:00:00 1970 From: Subject: Re: =?utf-8?q?=5BPATCH=5D_multipath-tools=3A_improve_proce?= =?utf-8?q?ssing_efficiency_for_addition_and_deletion_of_multipath_?= =?utf-8?q?devices?= Date: Thu, 16 Feb 2017 15:07:21 +0800 (CST) Message-ID: <201702161507215542733@zte.com.cn> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====_001_next=====" Return-path: References: 1484725113-5400-1-git-send-email-tang.junhui@zte.com.cn, 20170215210805.GS22981@octiron.msp.redhat.com List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com To: bmarzins@redhat.com Cc: zhang.kai16@zte.com.cn, dm-devel@redhat.com, mwilck@suse.com, tang.wenjun3@zte.com.cn, bart.vanassche@sandisk.com List-Id: dm-devel.ids --=====_001_next===== Content-Type: multipart/related; boundary="=====_002_next=====" --=====_002_next===== Content-Type: multipart/alternative; boundary="=====_003_next=====" --=====_003_next===== Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello Ben, Good catch, you are so nice and responsible person. I have modified those bugs and resended the patch just now, Please have a review for it. Thanks, Tang Junhui =E5=8E=9F=E5=A7=8B=E9=82=AE=E4=BB=B6 =E5=8F=91=E4=BB=B6=E4=BA=BA=EF=BC=9A =EF=BC=9Cbmarzins@redhat.com=EF=BC=9E =E6=94=B6=E4=BB=B6=E4=BA=BA=EF=BC=9A=E5=94=90=E5=86=9B=E8=BE=8910074136 =E6=8A=84=E9=80=81=E4=BA=BA=EF=BC=9A=E5=94=90=E6=96=87=E4=BF=8A10144149=E5= =BC=A0=E5=87=AF10072500 =EF=BC=9Cdm-devel@redhat.com=EF=BC=9E =EF=BC=9Cbart= .vanassche@sandisk.com=EF=BC=9E =EF=BC=9Cmwilck@suse.com=EF=BC=9E =E6=97=A5 =E6=9C=9F =EF=BC=9A2017=E5=B9=B402=E6=9C=8816=E6=97=A5 05:15 =E4=B8=BB =E9=A2=98 =EF=BC=9ARe: [dm-devel] [PATCH] multipath-tools: improv= e processing efficiency for addition and deletion of multipath devices On Wed, Jan 18, 2017 at 03:38:33PM +0800, tang.junhui@zte.com.cn wrote: =EF=BC=9E From: "tang.junhui" =EF=BC=9Ctang.junhui@zte.com.cn=EF=BC=9E =EF=BC=9E=20 =EF=BC=9E Change-Id: I3f81a55fff389f991f915927000b281d7e263cc5 =EF=BC=9E Signed-off-by: tang.junhui =EF=BC=9Ctang.junhui@zte.com.cn=EF=BC= =9E =EF=BC=9E=20 =EF=BC=9E This patch used to improve processing efficiency for addition and= deletion =EF=BC=9E of multipath devices. =EF=BC=9E=20 =EF=BC=9E This patch is tested pass by ZTE multipath automatic testing syst= em. =EF=BC=9E The modification reduces the system consumption(such as CPU) and = shortens =EF=BC=9E the processing time obviously in scene of massive multipath devic= es =EF=BC=9E addition or deletion. =EF=BC=9E=20 =EF=BC=9E The main processing flow of code is: =EF=BC=9E 1) add uid=5Fattrs configuration in the defaults section: =EF=BC=9E It is configured udev attribute which providing a unique path = identifier =EF=BC=9E for corresponding type of path devices. If this field is confi= gured and =EF=BC=9E matched with type of device, it would override any other metho= ds providing =EF=BC=9E for device unique identifier in config file, and it would acti= vate merging =EF=BC=9E uevents according to the identifier to promote effiecncy in pr= ocessing =EF=BC=9E uevents. Tt has no default value, so defaultly only uevents fi= ltering =EF=BC=9E works, and uevents merging does not works, if users want to id= entify path =EF=BC=9E by udev attribute and to activate merging uevents for SCSI and= DAS device, =EF=BC=9E they can set it's value as: =EF=BC=9E "sd:ID=5FSERIAL dasd:ID=5FUID" =EF=BC=9E 2) uevents accumulation in uevents burst scene: =EF=BC=9E wait one seconds for more uevents in uevent=5Flisten() in ueve= nts burst =EF=BC=9E situations =EF=BC=9E 3) uevents preparing, filtering and merging: =EF=BC=9E discard unuse uevents and fetch path idendifier from uevents =EF=BC=9E filter uevents =EF=BC=9E merge uevents. =EF=BC=9E 4) uevents proccessing: =EF=BC=9E proccess the merged uevents in uev-=EF=BC=9Emerge=5Fnode list = without calling =EF=BC=9E domap() =EF=BC=9E proccess the last uevents uev with calling domap(). =EF=BC=9E=20 =EF=BC=9E Any comment will be welcome, and it would be appreciated if these =EF=BC=9E patches would be considered for inclusion in the upstream =EF=BC=9E multipath-tools. Sorry for letting this slip through the cracks. This patch is really close. I just have a few issues. First off, this is completely superficial, but select=5Fgetuid() should use the new style of origin messages. instead of origin =3D "(config file default)" it should probably be origin =3D "(setting: multipath.conf defaults/devices section)" to match the other messages. Second, there is a bug in parse=5Fuid=5Fattribute=5Fby=5Fattrs(). get=5Fwor= d() returns the number of characters that the returned word takes up in the sentence, but you keep using it as the offset from the start of uid=5Fattrs. This doesn't effect the first call to get=5Fword(), since it doesn't use count. The second time you call get=5Fword(), everything still works because the number of characters that the first word took up is also the offset from the start of uid=5Fattrs. However, on a (hypothetical) third call, count is just the size of the second word, but you use are using it as the offset from the start of uid=5Fattrs (the size of the first and second word combined). This means that the a third call won't start at the correct place, and can get stuck in an endless loop. Obviously, as long as uid=5Fattrs only has two words in the value, this isn't a problem. But if we ever add another uid attribute to the list, it will break. Finally, in uevent=5Fget=5Fwwid, the goal is to see an environment variable like ID=5FSERIAL=3D3600d0230000000000e13955cc3757800 and correctly grab "3600d0230000000000e13955cc3757800" as the wwid. Unfortunately in the list of environment variables for scsi devices, there is also ID=5FSERIAL=5FSHORT=3D600d0230000000000e13955cc3757800 If multipath happened to see this environment variable first, it would grab "SHORT=3D600d0230000000000e13955cc3757800" as the wwid. It needs to check that the character after strlen(uid=5Fattribute) is an equals sign. Now, I realize that code all over multipath-tools doesn't bother checking for an equals sign, but in this specific case there is a known evironment variable that could cause problems if we don't check (not that those other cases don't need fixing eventually). otherwise, it looks great. Thanks -Ben =EF=BC=9E Thank you all, =EF=BC=9E Tang Junhui =EF=BC=9E --- =EF=BC=9E libmultipath/config.c | 3 + =EF=BC=9E libmultipath/config.h | 1 + =EF=BC=9E libmultipath/dict.c | 3 + =EF=BC=9E libmultipath/discovery.c | 5 +- =EF=BC=9E libmultipath/discovery.h | 2 +- =EF=BC=9E libmultipath/list.h | 41 ++++++ =EF=BC=9E libmultipath/propsel.c | 7 + =EF=BC=9E libmultipath/uevent.c | 319 +++++++++++++++++++++++++++++++= ++++++++++++-- =EF=BC=9E libmultipath/uevent.h | 2 + =EF=BC=9E libmultipath/util.c | 40 ++++++ =EF=BC=9E libmultipath/util.h | 1 + =EF=BC=9E multipath/multipath.conf.5 | 18 +++ =EF=BC=9E multipathd/cli=5Fhandlers.c | 4 +- =EF=BC=9E multipathd/main.c | 93 +++++-------- =EF=BC=9E multipathd/main.h | 4 +- =EF=BC=9E 15 files changed, 468 insertions(+), 75 deletions(-) =EF=BC=9E=20 =EF=BC=9E diff --git a/libmultipath/config.c b/libmultipath/config.c =EF=BC=9E index 15ddbd8..765e91d 100644 =EF=BC=9E --- a/libmultipath/config.c =EF=BC=9E +++ b/libmultipath/config.c =EF=BC=9E @@ -488,6 +488,9 @@ free=5Fconfig (struct config * conf) =EF=BC=9E if (conf-=EF=BC=9Euid=5Fattribute) =EF=BC=9E FREE(conf-=EF=BC=9Euid=5Fattribute) =EF=BC=9E =20 =EF=BC=9E + if (conf-=EF=BC=9Euid=5Fattrs) =EF=BC=9E + FREE(conf-=EF=BC=9Euid=5Fattrs) =EF=BC=9E + =EF=BC=9E if (conf-=EF=BC=9Egetuid) =EF=BC=9E FREE(conf-=EF=BC=9Egetuid) =EF=BC=9E =20 =EF=BC=9E diff --git a/libmultipath/config.h b/libmultipath/config.h =EF=BC=9E index 9670020..ab85930 100644 =EF=BC=9E --- a/libmultipath/config.h =EF=BC=9E +++ b/libmultipath/config.h =EF=BC=9E @@ -153,6 +153,7 @@ struct config { =EF=BC=9E =20 =EF=BC=9E char * multipath=5Fdir =EF=BC=9E char * selector =EF=BC=9E + char * uid=5Fattrs =EF=BC=9E char * uid=5Fattribute =EF=BC=9E char * getuid =EF=BC=9E char * features =EF=BC=9E diff --git a/libmultipath/dict.c b/libmultipath/dict.c =EF=BC=9E index dc21846..0a531d1 100644 =EF=BC=9E --- a/libmultipath/dict.c =EF=BC=9E +++ b/libmultipath/dict.c =EF=BC=9E @@ -249,6 +249,8 @@ declare=5Fovr=5Fsnprint(selector, print=5Fstr) =EF=BC=9E declare=5Fmp=5Fhandler(selector, set=5Fstr) =EF=BC=9E declare=5Fmp=5Fsnprint(selector, print=5Fstr) =EF=BC=9E =20 =EF=BC=9E +declare=5Fdef=5Fhandler(uid=5Fattrs, set=5Fstr) =EF=BC=9E +declare=5Fdef=5Fsnprint(uid=5Fattrs, print=5Fstr) =EF=BC=9E declare=5Fdef=5Fhandler(uid=5Fattribute, set=5Fstr) =EF=BC=9E declare=5Fdef=5Fsnprint=5Fdefstr(uid=5Fattribute, print=5Fstr, D= EFAULT=5FUID=5FATTRIBUTE) =EF=BC=9E declare=5Fovr=5Fhandler(uid=5Fattribute, set=5Fstr) =EF=BC=9E @@ -1367,6 +1369,7 @@ init=5Fkeywords(vector keywords) =EF=BC=9E install=5Fkeyword("multipath=5Fdir", &def=5Fmultipath=5Fdir= =5Fhandler, &snprint=5Fdef=5Fmultipath=5Fdir) =EF=BC=9E install=5Fkeyword("path=5Fselector", &def=5Fselector=5Fhandl= er, &snprint=5Fdef=5Fselector) =EF=BC=9E install=5Fkeyword("path=5Fgrouping=5Fpolicy", &def=5Fpgpolic= y=5Fhandler, &snprint=5Fdef=5Fpgpolicy) =EF=BC=9E + install=5Fkeyword("uid=5Fattrs", &def=5Fuid=5Fattrs=5Fhandle= r, &snprint=5Fdef=5Fuid=5Fattrs) =EF=BC=9E install=5Fkeyword("uid=5Fattribute", &def=5Fuid=5Fattribute= =5Fhandler, &snprint=5Fdef=5Fuid=5Fattribute) =EF=BC=9E install=5Fkeyword("getuid=5Fcallout", &def=5Fgetuid=5Fhandle= r, &snprint=5Fdef=5Fgetuid) =EF=BC=9E install=5Fkeyword("prio", &def=5Fprio=5Fname=5Fhandler, &snp= rint=5Fdef=5Fprio=5Fname) =EF=BC=9E diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c =EF=BC=9E index d1aec31..14904f2 100644 =EF=BC=9E --- a/libmultipath/discovery.c =EF=BC=9E +++ b/libmultipath/discovery.c =EF=BC=9E @@ -33,7 +33,7 @@ =EF=BC=9E =20 =EF=BC=9E int =EF=BC=9E alloc=5Fpath=5Fwith=5Fpathinfo (struct config *conf, struct udev= =5Fdevice *udevice, =EF=BC=9E - int flag, struct path **pp=5Fptr) =EF=BC=9E + char *wwid, int flag, struct path **pp=5Fptr) =EF=BC=9E { =EF=BC=9E int err =3D PATHINFO=5FFAILED =EF=BC=9E struct path * pp =EF=BC=9E @@ -51,6 +51,9 @@ alloc=5Fpath=5Fwith=5Fpathinfo (struct config *= conf, struct udev=5Fdevice *udevice, =EF=BC=9E if (!pp) =EF=BC=9E return PATHINFO=5FFAILED =EF=BC=9E =20 =EF=BC=9E + if(wwid) =EF=BC=9E + strncpy(pp-=EF=BC=9Ewwid, wwid, sizeof(pp-=EF=BC=9Ewwid)) =EF=BC=9E + =EF=BC=9E if (safe=5Fsprintf(pp-=EF=BC=9Edev, "%s", devname)) { =EF=BC=9E condlog(0, "pp-=EF=BC=9Edev too small") =EF=BC=9E } else { =EF=BC=9E diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h =EF=BC=9E index 3039268..d16a69a 100644 =EF=BC=9E --- a/libmultipath/discovery.h =EF=BC=9E +++ b/libmultipath/discovery.h =EF=BC=9E @@ -37,7 +37,7 @@ int path=5Foffline (struct path *) =EF=BC=9E int get=5Fstate (struct path * pp, struct config * conf, int dae= mon) =EF=BC=9E int pathinfo (struct path * pp, struct config * conf, int mask) =EF=BC=9E int alloc=5Fpath=5Fwith=5Fpathinfo (struct config *conf, struct = udev=5Fdevice *udevice, =EF=BC=9E - int flag, struct path **pp=5Fptr) =EF=BC=9E + char *wwid, int flag, struct path **pp=5Fptr) =EF=BC=9E int store=5Fpathinfo (vector pathvec, struct config *conf, =EF=BC=9E struct udev=5Fdevice *udevice, int flag, =EF=BC=9E struct path **pp=5Fptr) =EF=BC=9E diff --git a/libmultipath/list.h b/libmultipath/list.h =EF=BC=9E index ceaa381..2b1dcf3 100644 =EF=BC=9E --- a/libmultipath/list.h =EF=BC=9E +++ b/libmultipath/list.h =EF=BC=9E @@ -317,4 +317,45 @@ static inline void list=5Fsplice=5Ftail=5Fin= it(struct list=5Fhead *list, =EF=BC=9E &pos-=EF=BC=9Emember !=3D (head) \ =EF=BC=9E pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.next, t= ypeof(*n), member)) =EF=BC=9E =20 =EF=BC=9E +/** =EF=BC=9E + * list=5Ffor=5Feach=5Fentry=5Freverse=5Fsafe - iterate backward= s over list of given type safe against removal of list entry =EF=BC=9E + * @pos: the type * to use as a loop counter. =EF=BC=9E + * @n: another type * to use as temporary storage =EF=BC=9E + * @head: the head for your list. =EF=BC=9E + * @member: the name of the list=5Fstruct within the struct. =EF=BC=9E + */ =EF=BC=9E +#define list=5Ffor=5Feach=5Fentry=5Freverse=5Fsafe(pos, n, head,= member) \ =EF=BC=9E + for (pos =3D list=5Fentry((head)-=EF=BC=9Eprev, typeof(*pos)= , member), \ =EF=BC=9E + n =3D list=5Fentry(pos-=EF=BC=9Emember.prev, typeof(*po= s), member)\ =EF=BC=9E + &pos-=EF=BC=9Emember !=3D (head) = \ =EF=BC=9E + pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.prev, t= ypeof(*n), member)) =EF=BC=9E + =EF=BC=9E +/** =EF=BC=9E + * list=5Ffor=5Fsome=5Fentry=5Fsafe - iterate list from the give= n begin node to the given end node safe against removal of list entry =EF=BC=9E + * @pos: the type * to use as a loop counter. =EF=BC=9E + * @n: another type * to use as temporary storage =EF=BC=9E + * @from: the begin node of the iteration. =EF=BC=9E + * @to: the end node of the iteration. =EF=BC=9E + * @member: the name of the list=5Fstruct within the struct. =EF=BC=9E + */ =EF=BC=9E +#define list=5Ffor=5Fsome=5Fentry=5Fsafe(pos, n, from, to, membe= r) \ =EF=BC=9E + for (pos =3D list=5Fentry((from)-=EF=BC=9Enext, typeof(*pos)= , member), \ =EF=BC=9E + n =3D list=5Fentry(pos-=EF=BC=9Emember.next, typeof(*po= s), member) \ =EF=BC=9E + &pos-=EF=BC=9Emember !=3D (to) = \ =EF=BC=9E + pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.next, t= ypeof(*n), member)) =EF=BC=9E + =EF=BC=9E +/** =EF=BC=9E + * list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe - iterate backward= s list from the given begin node to the given end node safe against removal= of list entry =EF=BC=9E + * @pos: the type * to use as a loop counter. =EF=BC=9E + * @n: another type * to use as temporary storage =EF=BC=9E + * @from: the begin node of the iteration. =EF=BC=9E + * @to: the end node of the iteration. =EF=BC=9E + * @member: the name of the list=5Fstruct within the struct. =EF=BC=9E + */ =EF=BC=9E +#define list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe(pos, n, from,= to, member) \ =EF=BC=9E + for (pos =3D list=5Fentry((from)-=EF=BC=9Eprev, typeof(*pos)= , member), \ =EF=BC=9E + n =3D list=5Fentry(pos-=EF=BC=9Emember.prev, typeof(*po= s), member) \ =EF=BC=9E + &pos-=EF=BC=9Emember !=3D (to) = \ =EF=BC=9E + pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.prev, t= ypeof(*n), member)) =EF=BC=9E + =EF=BC=9E #endif /* =5FLIST=5FH */ =EF=BC=9E diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c =EF=BC=9E index c0bc616..5a58dc0 100644 =EF=BC=9E --- a/libmultipath/propsel.c =EF=BC=9E +++ b/libmultipath/propsel.c =EF=BC=9E @@ -18,6 +18,7 @@ =EF=BC=9E #include "prio.h" =EF=BC=9E #include "discovery.h" =EF=BC=9E #include "dict.h" =EF=BC=9E +#include "util.h" =EF=BC=9E #include "prioritizers/alua=5Frtpg.h" =EF=BC=9E #include =EF=BC=9Cinttypes.h=EF=BC=9E =EF=BC=9E =20 =EF=BC=9E @@ -339,6 +340,12 @@ int select=5Fgetuid(struct config *conf, str= uct path *pp) =EF=BC=9E { =EF=BC=9E char *origin =EF=BC=9E =20 =EF=BC=9E + pp-=EF=BC=9Euid=5Fattribute =3D parse=5Fuid=5Fattribute=5Fby= =5Fattrs(conf-=EF=BC=9Euid=5Fattrs, pp-=EF=BC=9Edev) =EF=BC=9E + if (pp-=EF=BC=9Euid=5Fattribute) { =EF=BC=9E + origin =3D "(config file default)" =EF=BC=9E + goto out =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E pp=5Fset=5Fovr(getuid) =EF=BC=9E pp=5Fset=5Fovr(uid=5Fattribute) =EF=BC=9E pp=5Fset=5Fhwe(getuid) =EF=BC=9E diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c =EF=BC=9E index 7edcce1..7e4ac04 100644 =EF=BC=9E --- a/libmultipath/uevent.c =EF=BC=9E +++ b/libmultipath/uevent.c =EF=BC=9E @@ -24,6 +24,7 @@ =EF=BC=9E =20 =EF=BC=9E #include =EF=BC=9Cunistd.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Cstdio.h=EF=BC=9E =EF=BC=9E +#include =EF=BC=9Cstdbool.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Cerrno.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Cstdlib.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Cstddef.h=EF=BC=9E =EF=BC=9E @@ -38,6 +39,7 @@ =EF=BC=9E #include =EF=BC=9Clinux/netlink.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Cpthread.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Csys/mman.h=EF=BC=9E =EF=BC=9E +#include =EF=BC=9Csys/time.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Clibudev.h=EF=BC=9E =EF=BC=9E #include =EF=BC=9Cerrno.h=EF=BC=9E =EF=BC=9E =20 =EF=BC=9E @@ -46,6 +48,14 @@ =EF=BC=9E #include "list.h" =EF=BC=9E #include "uevent.h" =EF=BC=9E #include "vector.h" =EF=BC=9E +#include "structs.h" =EF=BC=9E +#include "util.h" =EF=BC=9E +#include "config.h" =EF=BC=9E +#include "blacklist.h" =EF=BC=9E + =EF=BC=9E +#define MAX=5FACCUMULATION=5FCOUNT 2048 =EF=BC=9E +#define MAX=5FACCUMULATION=5FTIME 30*1000 =EF=BC=9E +#define MIN=5FBURST=5FSPEED 10 =EF=BC=9E =20 =EF=BC=9E typedef int (uev=5Ftrigger)(struct uevent *, void * trigger=5Fda= ta) =EF=BC=9E =20 =EF=BC=9E @@ -72,48 +82,300 @@ struct uevent * alloc=5Fuevent (void) =EF=BC=9E { =EF=BC=9E struct uevent *uev =3D MALLOC(sizeof(struct uevent)) =EF=BC=9E =20 =EF=BC=9E - if (uev) =EF=BC=9E + if (uev) { =EF=BC=9E INIT=5FLIST=5FHEAD(&uev-=EF=BC=9Enode) =EF=BC=9E + INIT=5FLIST=5FHEAD(&uev-=EF=BC=9Emerge=5Fnode) =EF=BC=9E + } =EF=BC=9E =20 =EF=BC=9E return uev =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E void =EF=BC=9E -service=5Fuevq(struct list=5Fhead *tmpq) =EF=BC=9E +uevq=5Fcleanup(struct list=5Fhead *tmpq) =EF=BC=9E { =EF=BC=9E struct uevent *uev, *tmp =EF=BC=9E =20 =EF=BC=9E list=5Ffor=5Feach=5Fentry=5Fsafe(uev, tmp, tmpq, node) { =EF=BC=9E list=5Fdel=5Finit(&uev-=EF=BC=9Enode) =EF=BC=9E =20 =EF=BC=9E - if (my=5Fuev=5Ftrigger && my=5Fuev=5Ftrigger(uev, my=5Ft= rigger=5Fdata)) =EF=BC=9E - condlog(0, "uevent trigger error") =EF=BC=9E - =EF=BC=9E if (uev-=EF=BC=9Eudev) =EF=BC=9E udev=5Fdevice=5Funref(uev-=EF=BC=9Eudev) =EF=BC=9E FREE(uev) =EF=BC=9E } =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E -static void uevent=5Fcleanup(void *arg) =EF=BC=9E +void =EF=BC=9E +uevent=5Fget=5Fwwid(struct uevent *uev) =EF=BC=9E { =EF=BC=9E - struct udev *udev =3D arg =EF=BC=9E + int i =EF=BC=9E + char *uid=5Fattribute =EF=BC=9E + struct config * conf =EF=BC=9E + =20 =EF=BC=9E + conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E + uid=5Fattribute =3D parse=5Fuid=5Fattribute=5Fby=5Fattrs(con= f-=EF=BC=9Euid=5Fattrs, uev-=EF=BC=9Ekernel) =EF=BC=9E + put=5Fmultipath=5Fconfig(conf) =20 =EF=BC=9E + =20 =EF=BC=9E + if (!uid=5Fattribute) =EF=BC=9E + return =EF=BC=9E + =20 =EF=BC=9E + for (i =3D 0 uev-=EF=BC=9Eenvp[i] !=3D NULL i++) { =EF=BC=9E + if (!strncmp(uev-=EF=BC=9Eenvp[i], uid=5Fattribute, strl= en(uid=5Fattribute)) && =EF=BC=9E + strlen(uev-=EF=BC=9Eenvp[i]) =EF=BC=9E strlen(uid=5F= attribute)) { =EF=BC=9E + uev-=EF=BC=9Ewwid =3D uev-=EF=BC=9Eenvp[i] + strlen(= uid=5Fattribute) + 1 =EF=BC=9E + break =EF=BC=9E + } =EF=BC=9E + } =EF=BC=9E + free(uid=5Fattribute) =EF=BC=9E +} =EF=BC=9E =20 =EF=BC=9E - condlog(3, "Releasing uevent=5Flisten() resources") =EF=BC=9E - udev=5Funref(udev) =EF=BC=9E +bool =EF=BC=9E +uevent=5Fneed=5Fmerge(void) =EF=BC=9E +{ =EF=BC=9E + struct config * conf =EF=BC=9E + bool need=5Fmerge =3D false =EF=BC=9E + =EF=BC=9E + conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E + if (conf-=EF=BC=9Euid=5Fattrs) =EF=BC=9E + need=5Fmerge =3D true =EF=BC=9E + put=5Fmultipath=5Fconfig(conf) =20 =EF=BC=9E + =EF=BC=9E + return need=5Fmerge =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +bool =EF=BC=9E +uevent=5Fcan=5Fdiscard(struct uevent *uev) =EF=BC=9E +{ =EF=BC=9E + char *tmp =EF=BC=9E + char a[11], b[11] =EF=BC=9E + struct config * conf =EF=BC=9E + =EF=BC=9E + /* =EF=BC=9E + * keep only block devices, discard partitions =EF=BC=9E + */ =EF=BC=9E + tmp =3D strstr(uev-=EF=BC=9Edevpath, "/block/") =EF=BC=9E + if (tmp =3D=3D NULL){ =EF=BC=9E + condlog(4, "no /block/ in '%s'", uev-=EF=BC=9Edevpath) =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + if (sscanf(tmp, "/block/%10s", a) !=3D 1 || =EF=BC=9E + sscanf(tmp, "/block/%10[^/]/%10s", a, b) =3D=3D 2) { =EF=BC=9E + condlog(4, "discard event on %s", uev-=EF=BC=9Edevpath) =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + /*=20 =EF=BC=9E + * do not filter dm devices by devnode =EF=BC=9E + */ =EF=BC=9E + if (!strncmp(uev-=EF=BC=9Ekernel, "dm-", 3)) =EF=BC=9E + return false =EF=BC=9E + /*=20 =EF=BC=9E + * filter paths devices by devnode =EF=BC=9E + */ =EF=BC=9E + conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E + if (filter=5Fdevnode(conf-=EF=BC=9Eblist=5Fdevnode, conf-=EF= =BC=9Eelist=5Fdevnode, =EF=BC=9E + uev-=EF=BC=9Ekernel) =EF=BC=9E 0) { =EF=BC=9E + put=5Fmultipath=5Fconfig(conf) =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + put=5Fmultipath=5Fconfig(conf) =EF=BC=9E + =EF=BC=9E + return false =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +bool =EF=BC=9E +uevent=5Fcan=5Ffilter(struct uevent *earlier, struct uevent *lat= er) =EF=BC=9E +{ =EF=BC=9E + =EF=BC=9E + /* =EF=BC=9E + * filter earlier uvents if path has removed later. Eg: =EF=BC=9E + * "add path1 |chang path1 |add path2 |remove path1" =EF=BC=9E + * can filter as: =EF=BC=9E + * "add path2 |remove path1" =EF=BC=9E + * uevents "add path1" and "chang path1" are filtered out =EF=BC=9E + */ =EF=BC=9E + if (!strcmp(earlier-=EF=BC=9Ekernel, later-=EF=BC=9Ekernel) = && =EF=BC=9E + !strcmp(later-=EF=BC=9Eaction, "remove") && =EF=BC=9E + strncmp(later-=EF=BC=9Ekernel, "dm-", 3)) { =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + /* =EF=BC=9E + * filter change uvents if add uevents exist. Eg: =EF=BC=9E + * "change path1| add path1 |add path2" =EF=BC=9E + * can filter as: =EF=BC=9E + * "add path1 |add path2" =EF=BC=9E + * uevent "chang path1" is filtered out =EF=BC=9E + */ =EF=BC=9E + if (!strcmp(earlier-=EF=BC=9Ekernel, later-=EF=BC=9Ekernel) = && =EF=BC=9E + !strcmp(earlier-=EF=BC=9Eaction, "change") && =EF=BC=9E + !strcmp(later-=EF=BC=9Eaction, "add") && =EF=BC=9E + strncmp(later-=EF=BC=9Ekernel, "dm-", 3)) { =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + return false =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +bool =EF=BC=9E +merge=5Fneed=5Fstop(struct uevent *earlier, struct uevent *later) =EF=BC=9E +{ =EF=BC=9E + /* =EF=BC=9E + * dm uevent do not try to merge with left uevents =EF=BC=9E + */ =EF=BC=9E + if (!strncmp(later-=EF=BC=9Ekernel, "dm-", 3)) =EF=BC=9E + return true =EF=BC=9E + =EF=BC=9E + /* =EF=BC=9E + * we can not make a jugement without wwid, =EF=BC=9E + * so it is sensible to stop merging =EF=BC=9E + */ =EF=BC=9E + if (!earlier-=EF=BC=9Ewwid || !later-=EF=BC=9Ewwid) =EF=BC=9E + return true =EF=BC=9E + /* =EF=BC=9E + * uevents merging stoped =EF=BC=9E + * when we meet an opposite action uevent from the same LUN = to AVOID =EF=BC=9E + * "add path1 |remove path1 |add path2 |remove path2 |add pa= th3" =EF=BC=9E + * to merge as "remove path1, path2" and "add path1, path2, = path3" =EF=BC=9E + * OR =EF=BC=9E + * "remove path1 |add path1 |remove path2 |add path2 |remove= path3" =EF=BC=9E + * to merge as "add path1, path2" and "remove path1, path2, = path3" =EF=BC=9E + * SO =EF=BC=9E + * when we meet a non-change uevent from the same LUN =EF=BC=9E + * with the same wwid and different action =EF=BC=9E + * it would be better to stop merging. =EF=BC=9E + */ =EF=BC=9E + if (!strcmp(earlier-=EF=BC=9Ewwid, later-=EF=BC=9Ewwid) && =EF=BC=9E + strcmp(earlier-=EF=BC=9Eaction, later-=EF=BC=9Eaction) && =EF=BC=9E + strcmp(earlier-=EF=BC=9Eaction, "change") && =EF=BC=9E + strcmp(later-=EF=BC=9Eaction, "change")) =EF=BC=9E + return true =EF=BC=9E + =EF=BC=9E + return false =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +bool =EF=BC=9E +uevent=5Fcan=5Fmerge(struct uevent *earlier, struct uevent *late= r) =EF=BC=9E +{ =EF=BC=9E + /* merge paths uevents =EF=BC=9E + * whose wwids exsit and are same =EF=BC=9E + * and actions are same, =EF=BC=9E + * and actions are addition or deletion =EF=BC=9E + */ =EF=BC=9E + if (earlier-=EF=BC=9Ewwid && later-=EF=BC=9Ewwid && =EF=BC=9E + !strcmp(earlier-=EF=BC=9Ewwid, later-=EF=BC=9Ewwid) && =EF=BC=9E + !strcmp(earlier-=EF=BC=9Eaction, later-=EF=BC=9Eaction) = && =EF=BC=9E + strncmp(earlier-=EF=BC=9Eaction, "change", 6) && =EF=BC=9E + strncmp(earlier-=EF=BC=9Ekernel, "dm-", 3)) { =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + return false =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E void =EF=BC=9E -uevq=5Fcleanup(struct list=5Fhead *tmpq) =EF=BC=9E +uevent=5Fprepare(struct list=5Fhead *tmpq) =EF=BC=9E +{ =EF=BC=9E + struct uevent *uev, *tmp =EF=BC=9E + =EF=BC=9E + list=5Ffor=5Feach=5Fentry=5Freverse=5Fsafe(uev, tmp, tmpq, n= ode) { =EF=BC=9E + if (uevent=5Fcan=5Fdiscard(uev)) { =EF=BC=9E + list=5Fdel=5Finit(&uev-=EF=BC=9Enode) =EF=BC=9E + if (uev-=EF=BC=9Eudev) =EF=BC=9E + udev=5Fdevice=5Funref(uev-=EF=BC=9Eudev) =EF=BC=9E + FREE(uev) =EF=BC=9E + continue =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + if (strncmp(uev-=EF=BC=9Ekernel, "dm-", 3) && =EF=BC=9E + uevent=5Fneed=5Fmerge()) =EF=BC=9E + uevent=5Fget=5Fwwid(uev) =EF=BC=9E + } =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +void =EF=BC=9E +uevent=5Ffilter(struct uevent *later, struct list=5Fhead *tmpq) =EF=BC=9E +{ =EF=BC=9E + struct uevent *earlier, *tmp =EF=BC=9E + =EF=BC=9E + list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe(earlier, tmp, &la= ter-=EF=BC=9Enode, tmpq, node) { =EF=BC=9E + /* =EF=BC=9E + * filter unnessary earlier uevents=20 =EF=BC=9E + * by the later uevent =EF=BC=9E + */ =EF=BC=9E + if (uevent=5Fcan=5Ffilter(earlier, later)) { =EF=BC=9E + condlog(2, "uevent: %s-%s has filtered by uevent: %s= -%s", =EF=BC=9E + earlier-=EF=BC=9Ekernel, earlier-=EF=BC=9Eaction= ,=20 =EF=BC=9E + later-=EF=BC=9Ekernel, later-=EF=BC=9Eaction) =EF=BC=9E + =EF=BC=9E + list=5Fdel=5Finit(&earlier-=EF=BC=9Enode) =EF=BC=9E + if (earlier-=EF=BC=9Eudev) =EF=BC=9E + udev=5Fdevice=5Funref(earlier-=EF=BC=9Eudev) =EF=BC=9E + FREE(earlier) =EF=BC=9E + } =EF=BC=9E + } =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +void =EF=BC=9E +uevent=5Fmerge(struct uevent *later, struct list=5Fhead *tmpq) =EF=BC=9E +{ =EF=BC=9E + struct uevent *earlier, *tmp =EF=BC=9E + =EF=BC=9E + list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe(earlier, tmp, &la= ter-=EF=BC=9Enode, tmpq, node) { =EF=BC=9E + if (merge=5Fneed=5Fstop(earlier, later)) =EF=BC=9E + break =EF=BC=9E + /* =EF=BC=9E + * merge earlier uevents to the later uevent =EF=BC=9E + */ =EF=BC=9E + if (uevent=5Fcan=5Fmerge(earlier, later)) { =EF=BC=9E + condlog(2, "merged uevent: %s-%s-%s with uevent: %s-= %s-%s", =EF=BC=9E + earlier-=EF=BC=9Eaction, earlier-=EF=BC=9Ekernel= , earlier-=EF=BC=9Ewwid, =EF=BC=9E + later-=EF=BC=9Eaction, later-=EF=BC=9Ekernel, la= ter-=EF=BC=9Ewwid) =EF=BC=9E + =EF=BC=9E + list=5Fmove(&earlier-=EF=BC=9Enode, &later-=EF=BC=9E= merge=5Fnode) =EF=BC=9E + } =EF=BC=9E + } =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +void =EF=BC=9E +merge=5Fuevq(struct list=5Fhead *tmpq) =EF=BC=9E +{ =EF=BC=9E + struct uevent *later =EF=BC=9E + =EF=BC=9E + uevent=5Fprepare(tmpq) =EF=BC=9E + list=5Ffor=5Feach=5Fentry=5Freverse(later, tmpq, node) { =EF=BC=9E + uevent=5Ffilter(later, tmpq) =EF=BC=9E + if(uevent=5Fneed=5Fmerge()) =EF=BC=9E + uevent=5Fmerge(later, tmpq) =EF=BC=9E + } =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E +void =EF=BC=9E +service=5Fuevq(struct list=5Fhead *tmpq) =EF=BC=9E { =EF=BC=9E struct uevent *uev, *tmp =EF=BC=9E =20 =EF=BC=9E list=5Ffor=5Feach=5Fentry=5Fsafe(uev, tmp, tmpq, node) { =EF=BC=9E list=5Fdel=5Finit(&uev-=EF=BC=9Enode) =EF=BC=9E + =EF=BC=9E + if (my=5Fuev=5Ftrigger && my=5Fuev=5Ftrigger(uev, my=5Ft= rigger=5Fdata)) =EF=BC=9E + condlog(0, "uevent trigger error") =EF=BC=9E + =EF=BC=9E + uevq=5Fcleanup(&uev-=EF=BC=9Emerge=5Fnode) =EF=BC=9E + =EF=BC=9E + if (uev-=EF=BC=9Eudev) =EF=BC=9E + udev=5Fdevice=5Funref(uev-=EF=BC=9Eudev) =EF=BC=9E FREE(uev) =EF=BC=9E } =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E +static void uevent=5Fcleanup(void *arg) =EF=BC=9E +{ =EF=BC=9E + struct udev *udev =3D arg =EF=BC=9E + =EF=BC=9E + condlog(3, "Releasing uevent=5Flisten() resources") =EF=BC=9E + udev=5Funref(udev) =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E /* =EF=BC=9E * Service the uevent queue. =EF=BC=9E */ =EF=BC=9E @@ -142,6 +404,7 @@ int uevent=5Fdispatch(int (*uev=5Ftrigger)(st= ruct uevent *, void * trigger=5Fdata), =EF=BC=9E pthread=5Fmutex=5Funlock(uevq=5Flockp) =EF=BC=9E if (!my=5Fuev=5Ftrigger) =EF=BC=9E break =EF=BC=9E + merge=5Fuevq(&uevq=5Ftmp) =EF=BC=9E service=5Fuevq(&uevq=5Ftmp) =EF=BC=9E } =EF=BC=9E condlog(3, "Terminating uev service queue") =EF=BC=9E @@ -442,11 +705,43 @@ struct uevent *uevent=5Ffrom=5Fudev=5Fdevic= e(struct udev=5Fdevice *dev) =EF=BC=9E return uev =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E +bool uevent=5Fburst(struct timeval *start=5Ftime, int events) =EF=BC=9E +{ =EF=BC=9E + struct timeval diff=5Ftime, end=5Ftime =EF=BC=9E + unsigned long speed =EF=BC=9E + unsigned long eclipse=5Fms =EF=BC=9E + =EF=BC=9E + if(events =EF=BC=9E MAX=5FACCUMULATION=5FCOUNT) { =EF=BC=9E + condlog(2, "burst got %u uevents, too much uevents, stop= ped", events) =EF=BC=9E + return false =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + gettimeofday(&end=5Ftime, NULL) =EF=BC=9E + timersub(&end=5Ftime, start=5Ftime, &diff=5Ftime) =EF=BC=9E + =EF=BC=9E + eclipse=5Fms =3D diff=5Ftime.tv=5Fsec * 1000 + diff=5Ftime.t= v=5Fusec / 1000 =EF=BC=9E + =EF=BC=9E + if (eclipse=5Fms =3D=3D 0) =EF=BC=9E + return true =EF=BC=9E + =EF=BC=9E + if (eclipse=5Fms =EF=BC=9E MAX=5FACCUMULATION=5FTIME) { =EF=BC=9E + condlog(2, "burst continued %lu ms, too long time, stopp= ed", eclipse=5Fms) =EF=BC=9E + return false =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + speed =3D (events * 1000) / eclipse=5Fms =EF=BC=9E + if (speed =EF=BC=9E MIN=5FBURST=5FSPEED) =EF=BC=9E + return true =EF=BC=9E + =EF=BC=9E + return false =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E int uevent=5Flisten(struct udev *udev) =EF=BC=9E { =EF=BC=9E int err =3D 2 =EF=BC=9E struct udev=5Fmonitor *monitor =3D NULL =EF=BC=9E int fd, socket=5Fflags, events =EF=BC=9E + struct timeval start=5Ftime =EF=BC=9E int need=5Ffailback =3D 1 =EF=BC=9E int timeout =3D 30 =EF=BC=9E LIST=5FHEAD(uevlisten=5Ftmp) =EF=BC=9E @@ -500,6 +795,7 @@ int uevent=5Flisten(struct udev *udev) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E events =3D 0 =EF=BC=9E + gettimeofday(&start=5Ftime, NULL) =EF=BC=9E while (1) { =EF=BC=9E struct uevent *uev =EF=BC=9E struct udev=5Fdevice *dev =EF=BC=9E @@ -514,7 +810,7 @@ int uevent=5Flisten(struct udev *udev) =EF=BC=9E errno =3D 0 =EF=BC=9E fdcount =3D poll(&ev=5Fpoll, 1, poll=5Ftimeout) =EF=BC=9E if (fdcount && ev=5Fpoll.revents & POLLIN) { =EF=BC=9E - timeout =3D 0 =EF=BC=9E + timeout =3D uevent=5Fburst(&start=5Ftime, events + 1= ) ? 1 : 0 =EF=BC=9E dev =3D udev=5Fmonitor=5Freceive=5Fdevice(monitor) =EF=BC=9E if (!dev) { =EF=BC=9E condlog(0, "failed getting udev device") =EF=BC=9E @@ -547,6 +843,7 @@ int uevent=5Flisten(struct udev *udev) =EF=BC=9E pthread=5Fmutex=5Funlock(uevq=5Flockp) =EF=BC=9E events =3D 0 =EF=BC=9E } =EF=BC=9E + gettimeofday(&start=5Ftime, NULL) =EF=BC=9E timeout =3D 30 =EF=BC=9E } =EF=BC=9E need=5Ffailback =3D 0 =EF=BC=9E diff --git a/libmultipath/uevent.h b/libmultipath/uevent.h =EF=BC=9E index 9d22dcd..61a4207 100644 =EF=BC=9E --- a/libmultipath/uevent.h =EF=BC=9E +++ b/libmultipath/uevent.h =EF=BC=9E @@ -17,11 +17,13 @@ struct udev =EF=BC=9E =20 =EF=BC=9E struct uevent { =EF=BC=9E struct list=5Fhead node =EF=BC=9E + struct list=5Fhead merge=5Fnode =EF=BC=9E struct udev=5Fdevice *udev =EF=BC=9E char buffer[HOTPLUG=5FBUFFER=5FSIZE + OBJECT=5FSIZE] =EF=BC=9E char *devpath =EF=BC=9E char *action =EF=BC=9E char *kernel =EF=BC=9E + char *wwid =EF=BC=9E unsigned long seqnum =EF=BC=9E char *envp[HOTPLUG=5FNUM=5FENVP] =EF=BC=9E } =EF=BC=9E diff --git a/libmultipath/util.c b/libmultipath/util.c =EF=BC=9E index 03a5738..e5a4a28 100644 =EF=BC=9E --- a/libmultipath/util.c =EF=BC=9E +++ b/libmultipath/util.c =EF=BC=9E @@ -261,6 +261,46 @@ dev=5Ft parse=5Fdevt(const char *dev=5Ft) =EF=BC=9E return makedev(maj, min) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E +char *parse=5Fuid=5Fattribute=5Fby=5Fattrs(char *uid=5Fattrs, ch= ar *path=5Fdev) =EF=BC=9E +{ =EF=BC=9E + char *uid=5Fattribute =EF=BC=9E + char *uid=5Fattr=5Frecord =EF=BC=9E + char *dev =EF=BC=9E + char *attr =EF=BC=9E + char *tmp =EF=BC=9E + int count =EF=BC=9E + =EF=BC=9E + if(!uid=5Fattrs || !path=5Fdev) =EF=BC=9E + return NULL =EF=BC=9E + =EF=BC=9E + count =3D get=5Fword(uid=5Fattrs, &uid=5Fattr=5Frecord) =EF=BC=9E + while (uid=5Fattr=5Frecord) { =EF=BC=9E + tmp =3D strrchr(uid=5Fattr=5Frecord, ':') =EF=BC=9E + if (!tmp) { =EF=BC=9E + free(uid=5Fattr=5Frecord) =EF=BC=9E + if (!count) =EF=BC=9E + break =EF=BC=9E + count =3D get=5Fword(uid=5Fattrs + count, &uid=5Fatt= r=5Frecord) =EF=BC=9E + continue =EF=BC=9E + } =EF=BC=9E + dev =3D uid=5Fattr=5Frecord =EF=BC=9E + attr =3D tmp + 1 =EF=BC=9E + *tmp =3D '\0' =EF=BC=9E + =EF=BC=9E + if(!strncmp(path=5Fdev, dev, strlen(dev))) { =EF=BC=9E + uid=5Fattribute =3D STRDUP(attr) =EF=BC=9E + free(uid=5Fattr=5Frecord) =EF=BC=9E + return uid=5Fattribute =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + free(uid=5Fattr=5Frecord) =EF=BC=9E + if (!count) =EF=BC=9E + break =EF=BC=9E + count =3D get=5Fword(uid=5Fattrs + count, &uid=5Fattr=5F= record) =EF=BC=9E + } =EF=BC=9E + return NULL =EF=BC=9E +} =EF=BC=9E + =EF=BC=9E void =EF=BC=9E setup=5Fthread=5Fattr(pthread=5Fattr=5Ft *attr, size=5Ft stacksi= ze, int detached) =EF=BC=9E { =EF=BC=9E diff --git a/libmultipath/util.h b/libmultipath/util.h =EF=BC=9E index f3b37ee..793f2b7 100644 =EF=BC=9E --- a/libmultipath/util.h =EF=BC=9E +++ b/libmultipath/util.h =EF=BC=9E @@ -12,6 +12,7 @@ size=5Ft strlcat(char *dst, const char *src, si= ze=5Ft size) =EF=BC=9E int devt2devname (char *, int, char *) =EF=BC=9E dev=5Ft parse=5Fdevt(const char *dev=5Ft) =EF=BC=9E char *convert=5Fdev(char *dev, int is=5Fpath=5Fdevice) =EF=BC=9E +char *parse=5Fuid=5Fattribute=5Fby=5Fattrs(char *uid=5Fattrs, ch= ar *path=5Fdev) =EF=BC=9E void setup=5Fthread=5Fattr(pthread=5Fattr=5Ft *attr, size=5Ft st= acksize, int detached) =EF=BC=9E =20 =EF=BC=9E #define safe=5Fsprintf(var, format, args...) \ =EF=BC=9E diff --git a/multipath/multipath.conf.5 b/multipath/multipath.con= f.5 =EF=BC=9E index 36589f5..63c63c2 100644 =EF=BC=9E --- a/multipath/multipath.conf.5 =EF=BC=9E +++ b/multipath/multipath.conf.5 =EF=BC=9E @@ -209,6 +209,24 @@ The default is: \fBfailover\fR =EF=BC=9E . =EF=BC=9E . =EF=BC=9E .TP =EF=BC=9E +.B uid=5Fattrs =EF=BC=9E +The udev attribute providing a unique path identifier for corres= ponding=20 =EF=BC=9E +type of path devices. If this field is configured and matched wi= th type =EF=BC=9E +of device, it would override any other methods providing for dev= ice =EF=BC=9E +unique identifier in config file, and it would activate merging = uevents =EF=BC=9E +according to the identifier to promote effiecncy in processing u= events. =EF=BC=9E +Tt has no default value, if you want to identify path by udev at= tribute =EF=BC=9E +and to activate merging uevents for SCSI and DAS device, you can= set =EF=BC=9E +it's value as: =EF=BC=9E +.RS =EF=BC=9E +.TP =EF=BC=9E +\fBuid=5Fattrs "sd:ID=5FSERIAL dasd:ID=5FUID"\fR =EF=BC=9E +.TP =EF=BC=9E +The default is: \fB=EF=BC=9Cunset=EF=BC=9E\fR =EF=BC=9E +.RE =EF=BC=9E +. =EF=BC=9E +. =EF=BC=9E +.TP =EF=BC=9E .B uid=5Fattribute =EF=BC=9E The udev attribute providing a unique path identifier. =EF=BC=9E .RS =EF=BC=9E diff --git a/multipathd/cli=5Fhandlers.c b/multipathd/cli=5Fhandl= ers.c =EF=BC=9E index b0eeca6..12f85de 100644 =EF=BC=9E --- a/multipathd/cli=5Fhandlers.c =EF=BC=9E +++ b/multipathd/cli=5Fhandlers.c =EF=BC=9E @@ -670,7 +670,7 @@ cli=5Fadd=5Fpath (void * v, char ** reply, in= t * len, void * data) =EF=BC=9E pp-=EF=BC=9Echeckint =3D conf-=EF=BC=9Echeckint =EF=BC=9E } =EF=BC=9E put=5Fmultipath=5Fconfig(conf) =EF=BC=9E - return ev=5Fadd=5Fpath(pp, vecs) =EF=BC=9E + return ev=5Fadd=5Fpath(pp, vecs, 1) =EF=BC=9E blacklisted: =EF=BC=9E *reply =3D strdup("blacklisted\n") =EF=BC=9E *len =3D strlen(*reply) + 1 =EF=BC=9E @@ -692,7 +692,7 @@ cli=5Fdel=5Fpath (void * v, char ** reply, in= t * len, void * data) =EF=BC=9E condlog(0, "%s: path already removed", param) =EF=BC=9E return 1 =EF=BC=9E } =EF=BC=9E - return ev=5Fremove=5Fpath(pp, vecs) =EF=BC=9E + return ev=5Fremove=5Fpath(pp, vecs, 1) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E int =EF=BC=9E diff --git a/multipathd/main.c b/multipathd/main.c =EF=BC=9E index adc3258..e513f7d 100644 =EF=BC=9E --- a/multipathd/main.c =EF=BC=9E +++ b/multipathd/main.c =EF=BC=9E @@ -608,7 +608,7 @@ ev=5Fremove=5Fmap (char * devname, char * ali= as, int minor, struct vectors * vecs) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E static int =EF=BC=9E -uev=5Fadd=5Fpath (struct uevent *uev, struct vectors * vecs) =EF=BC=9E +uev=5Fadd=5Fpath (struct uevent *uev, struct vectors * vecs, int= need=5Fdo=5Fmap) =EF=BC=9E { =EF=BC=9E struct path *pp =EF=BC=9E int ret =3D 0, i =EF=BC=9E @@ -641,7 +641,7 @@ uev=5Fadd=5Fpath (struct uevent *uev, struct = vectors * vecs) =EF=BC=9E DI=5FALL | DI=5FBLACKLIST) =EF=BC=9E put=5Fmultipath=5Fconfig(conf) =EF=BC=9E if (r =3D=3D PATHINFO=5FOK) =EF=BC=9E - ret =3D ev=5Fadd=5Fpath(pp, vecs) =EF=BC=9E + ret =3D ev=5Fadd=5Fpath(pp, vecs, need=5Fdo=5Fma= p) =EF=BC=9E else if (r =3D=3D PATHINFO=5FSKIPPED) { =EF=BC=9E condlog(3, "%s: remove blacklisted path", =EF=BC=9E uev-=EF=BC=9Ekernel) =EF=BC=9E @@ -665,7 +665,7 @@ uev=5Fadd=5Fpath (struct uevent *uev, struct = vectors * vecs) =EF=BC=9E */ =EF=BC=9E conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E ret =3D alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-=EF=BC=9Eud= ev, =EF=BC=9E - DI=5FALL, &pp) =EF=BC=9E + uev-=EF=BC=9Ewwid, DI=5FALL, &pp) =EF=BC=9E put=5Fmultipath=5Fconfig(conf) =EF=BC=9E if (!pp) { =EF=BC=9E if (ret =3D=3D PATHINFO=5FSKIPPED) =EF=BC=9E @@ -681,7 +681,7 @@ uev=5Fadd=5Fpath (struct uevent *uev, struct = vectors * vecs) =EF=BC=9E conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E pp-=EF=BC=9Echeckint =3D conf-=EF=BC=9Echeckint =EF=BC=9E put=5Fmultipath=5Fconfig(conf) =EF=BC=9E - ret =3D ev=5Fadd=5Fpath(pp, vecs) =EF=BC=9E + ret =3D ev=5Fadd=5Fpath(pp, vecs, need=5Fdo=5Fmap) =EF=BC=9E } else { =EF=BC=9E condlog(0, "%s: failed to store path info, " =EF=BC=9E "dropping event", =EF=BC=9E @@ -699,7 +699,7 @@ uev=5Fadd=5Fpath (struct uevent *uev, struct = vectors * vecs) =EF=BC=9E * 1: error =EF=BC=9E */ =EF=BC=9E int =EF=BC=9E -ev=5Fadd=5Fpath (struct path * pp, struct vectors * vecs) =EF=BC=9E +ev=5Fadd=5Fpath (struct path * pp, struct vectors * vecs, int ne= ed=5Fdo=5Fmap) =EF=BC=9E { =EF=BC=9E struct multipath * mpp =EF=BC=9E char params[PARAMS=5FSIZE] =3D {0} =EF=BC=9E @@ -767,6 +767,13 @@ rescan: =EF=BC=9E /* persistent reservation check*/ =EF=BC=9E mpath=5Fpr=5Fevent=5Fhandle(pp) =EF=BC=9E =20 =EF=BC=9E + if (!need=5Fdo=5Fmap) =EF=BC=9E + return 0 =EF=BC=9E + =EF=BC=9E + if (!dm=5Fmap=5Fpresent(mpp-=EF=BC=9Ealias)) { =EF=BC=9E + mpp-=EF=BC=9Eaction =3D ACT=5FCREATE =EF=BC=9E + start=5Fwaiter =3D 1 =EF=BC=9E + } =EF=BC=9E /* =EF=BC=9E * push the map to the device-mapper =EF=BC=9E */ =EF=BC=9E @@ -833,7 +840,7 @@ fail: =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E static int =EF=BC=9E -uev=5Fremove=5Fpath (struct uevent *uev, struct vectors * vecs) =EF=BC=9E +uev=5Fremove=5Fpath (struct uevent *uev, struct vectors * vecs, = int need=5Fdo=5Fmap) =EF=BC=9E { =EF=BC=9E struct path *pp =EF=BC=9E int ret =EF=BC=9E @@ -844,7 +851,7 @@ uev=5Fremove=5Fpath (struct uevent *uev, stru= ct vectors * vecs) =EF=BC=9E pthread=5Ftestcancel() =EF=BC=9E pp =3D find=5Fpath=5Fby=5Fdev(vecs-=EF=BC=9Epathvec, uev-=EF= =BC=9Ekernel) =EF=BC=9E if (pp) =EF=BC=9E - ret =3D ev=5Fremove=5Fpath(pp, vecs) =EF=BC=9E + ret =3D ev=5Fremove=5Fpath(pp, vecs, need=5Fdo=5Fmap) =EF=BC=9E lock=5Fcleanup=5Fpop(vecs-=EF=BC=9Elock) =EF=BC=9E if (!pp) { =EF=BC=9E /* Not an error path might have been purged earlier */ =EF=BC=9E @@ -855,7 +862,7 @@ uev=5Fremove=5Fpath (struct uevent *uev, stru= ct vectors * vecs) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E int =EF=BC=9E -ev=5Fremove=5Fpath (struct path *pp, struct vectors * vecs) =EF=BC=9E +ev=5Fremove=5Fpath (struct path *pp, struct vectors * vecs, int = need=5Fdo=5Fmap) =EF=BC=9E { =EF=BC=9E struct multipath * mpp =EF=BC=9E int i, retval =3D 0 =EF=BC=9E @@ -918,6 +925,8 @@ ev=5Fremove=5Fpath (struct path *pp, struct v= ectors * vecs) =EF=BC=9E goto out =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E + if (!need=5Fdo=5Fmap) =EF=BC=9E + goto out =EF=BC=9E /* =EF=BC=9E * reload the map =EF=BC=9E */ =EF=BC=9E @@ -995,7 +1004,7 @@ uev=5Fupdate=5Fpath (struct uevent *uev, str= uct vectors * vecs) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E if (pp-=EF=BC=9Einitialized =3D=3D INIT=5FREQUESTED=5FUD= EV) =EF=BC=9E - retval =3D uev=5Fadd=5Fpath(uev, vecs) =EF=BC=9E + retval =3D uev=5Fadd=5Fpath(uev, vecs, 1) =EF=BC=9E else if (mpp && ro =EF=BC=9E=3D 0) { =EF=BC=9E condlog(2, "%s: update path write=5Fprotect to '%d' = (uevent)", uev-=EF=BC=9Ekernel, ro) =EF=BC=9E =20 =EF=BC=9E @@ -1016,7 +1025,7 @@ out: =EF=BC=9E int flag =3D DI=5FSYSFS | DI=5FWWID =EF=BC=9E =20 =EF=BC=9E conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E - retval =3D alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-= =EF=BC=9Eudev, flag, NULL) =EF=BC=9E + retval =3D alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-= =EF=BC=9Eudev, uev-=EF=BC=9Ewwid, flag, NULL) =EF=BC=9E put=5Fmultipath=5Fconfig(conf) =EF=BC=9E =20 =EF=BC=9E if (retval =3D=3D PATHINFO=5FSKIPPED) { =EF=BC=9E @@ -1077,40 +1086,15 @@ uxsock=5Ftrigger (char * str, char ** rep= ly, int * len, void * trigger=5Fdata) =EF=BC=9E return r =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E -static int =EF=BC=9E -uev=5Fdiscard(char * devpath) =EF=BC=9E -{ =EF=BC=9E - char *tmp =EF=BC=9E - char a[11], b[11] =EF=BC=9E - =EF=BC=9E - /* =EF=BC=9E - * keep only block devices, discard partitions =EF=BC=9E - */ =EF=BC=9E - tmp =3D strstr(devpath, "/block/") =EF=BC=9E - if (tmp =3D=3D NULL){ =EF=BC=9E - condlog(4, "no /block/ in '%s'", devpath) =EF=BC=9E - return 1 =EF=BC=9E - } =EF=BC=9E - if (sscanf(tmp, "/block/%10s", a) !=3D 1 || =EF=BC=9E - sscanf(tmp, "/block/%10[^/]/%10s", a, b) =3D=3D 2) { =EF=BC=9E - condlog(4, "discard event on %s", devpath) =EF=BC=9E - return 1 =EF=BC=9E - } =EF=BC=9E - return 0 =EF=BC=9E -} =EF=BC=9E - =EF=BC=9E int =EF=BC=9E uev=5Ftrigger (struct uevent * uev, void * trigger=5Fdata) =EF=BC=9E { =EF=BC=9E int r =3D 0 =EF=BC=9E struct vectors * vecs =EF=BC=9E - struct config *conf =EF=BC=9E + struct uevent *merge=5Fuev, *tmp =EF=BC=9E =20 =EF=BC=9E vecs =3D (struct vectors *)trigger=5Fdata =EF=BC=9E =20 =EF=BC=9E - if (uev=5Fdiscard(uev-=EF=BC=9Edevpath)) =EF=BC=9E - return 0 =EF=BC=9E - =EF=BC=9E pthread=5Fcleanup=5Fpush(config=5Fcleanup, NULL) =EF=BC=9E pthread=5Fmutex=5Flock(&config=5Flock) =EF=BC=9E if (running=5Fstate !=3D DAEMON=5FIDLE && =EF=BC=9E @@ -1139,28 +1123,21 @@ uev=5Ftrigger (struct uevent * uev, void = * trigger=5Fdata) =EF=BC=9E } =EF=BC=9E =20 =EF=BC=9E /* =EF=BC=9E - * path add/remove event =EF=BC=9E + * path add/remove/change event, add/remove maybe merged =EF=BC=9E */ =EF=BC=9E - conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E - if (filter=5Fdevnode(conf-=EF=BC=9Eblist=5Fdevnode, conf-=EF= =BC=9Eelist=5Fdevnode, =EF=BC=9E - uev-=EF=BC=9Ekernel) =EF=BC=9E 0) { =EF=BC=9E - put=5Fmultipath=5Fconfig(conf) =EF=BC=9E - goto out =EF=BC=9E + list=5Ffor=5Feach=5Fentry=5Fsafe(merge=5Fuev, tmp, &uev-=EF= =BC=9Emerge=5Fnode, node) { =EF=BC=9E + if (!strncmp(merge=5Fuev-=EF=BC=9Eaction, "add", 3)) =EF=BC=9E + r +=3D uev=5Fadd=5Fpath(merge=5Fuev, vecs, 0) =EF=BC=9E + if (!strncmp(merge=5Fuev-=EF=BC=9Eaction, "remove", 6)) =EF=BC=9E + r +=3D uev=5Fremove=5Fpath(merge=5Fuev, vecs, 0) =EF=BC=9E } =EF=BC=9E - put=5Fmultipath=5Fconfig(conf) =EF=BC=9E =20 =EF=BC=9E - if (!strncmp(uev-=EF=BC=9Eaction, "add", 3)) { =EF=BC=9E - r =3D uev=5Fadd=5Fpath(uev, vecs) =EF=BC=9E - goto out =EF=BC=9E - } =EF=BC=9E - if (!strncmp(uev-=EF=BC=9Eaction, "remove", 6)) { =EF=BC=9E - r =3D uev=5Fremove=5Fpath(uev, vecs) =EF=BC=9E - goto out =EF=BC=9E - } =EF=BC=9E - if (!strncmp(uev-=EF=BC=9Eaction, "change", 6)) { =EF=BC=9E - r =3D uev=5Fupdate=5Fpath(uev, vecs) =EF=BC=9E - goto out =EF=BC=9E - } =EF=BC=9E + if (!strncmp(uev-=EF=BC=9Eaction, "add", 3)) =EF=BC=9E + r +=3D uev=5Fadd=5Fpath(uev, vecs, 1) =EF=BC=9E + if (!strncmp(uev-=EF=BC=9Eaction, "remove", 6)) =EF=BC=9E + r +=3D uev=5Fremove=5Fpath(uev, vecs, 1) =EF=BC=9E + if (!strncmp(uev-=EF=BC=9Eaction, "change", 6)) =EF=BC=9E + r +=3D uev=5Fupdate=5Fpath(uev, vecs) =EF=BC=9E =20 =EF=BC=9E out: =EF=BC=9E return r =EF=BC=9E @@ -1570,7 +1547,7 @@ check=5Fpath (struct vectors * vecs, struct= path * pp, int ticks) =EF=BC=9E conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E ret =3D pathinfo(pp, conf, DI=5FALL | DI=5FBLACKLIST) =EF=BC=9E if (ret =3D=3D PATHINFO=5FOK) { =EF=BC=9E - ev=5Fadd=5Fpath(pp, vecs) =EF=BC=9E + ev=5Fadd=5Fpath(pp, vecs, 1) =EF=BC=9E pp-=EF=BC=9Etick =3D 1 =EF=BC=9E } else if (ret =3D=3D PATHINFO=5FSKIPPED) { =EF=BC=9E put=5Fmultipath=5Fconfig(conf) =EF=BC=9E @@ -1686,7 +1663,7 @@ check=5Fpath (struct vectors * vecs, struct= path * pp, int ticks) =EF=BC=9E } =EF=BC=9E if (!disable=5Freinstate && reinstate=5Fpath(pp, add=5Fa= ctive)) { =EF=BC=9E condlog(3, "%s: reload map", pp-=EF=BC=9Edev) =EF=BC=9E - ev=5Fadd=5Fpath(pp, vecs) =EF=BC=9E + ev=5Fadd=5Fpath(pp, vecs, 1) =EF=BC=9E pp-=EF=BC=9Etick =3D 1 =EF=BC=9E return 0 =EF=BC=9E } =EF=BC=9E @@ -1709,7 +1686,7 @@ check=5Fpath (struct vectors * vecs, struct= path * pp, int ticks) =EF=BC=9E /* Clear IO errors */ =EF=BC=9E if (reinstate=5Fpath(pp, 0)) { =EF=BC=9E condlog(3, "%s: reload map", pp-=EF=BC=9Edev) =EF=BC=9E - ev=5Fadd=5Fpath(pp, vecs) =EF=BC=9E + ev=5Fadd=5Fpath(pp, vecs, 1) =EF=BC=9E pp-=EF=BC=9Etick =3D 1 =EF=BC=9E return 0 =EF=BC=9E } =EF=BC=9E diff --git a/multipathd/main.h b/multipathd/main.h =EF=BC=9E index f72580d..094b04f 100644 =EF=BC=9E --- a/multipathd/main.h =EF=BC=9E +++ b/multipathd/main.h =EF=BC=9E @@ -22,8 +22,8 @@ void exit=5Fdaemon(void) =EF=BC=9E const char * daemon=5Fstatus(void) =EF=BC=9E int need=5Fto=5Fdelay=5Freconfig (struct vectors *) =EF=BC=9E int reconfigure (struct vectors *) =EF=BC=9E -int ev=5Fadd=5Fpath (struct path *, struct vectors *) =EF=BC=9E -int ev=5Fremove=5Fpath (struct path *, struct vectors *) =EF=BC=9E +int ev=5Fadd=5Fpath (struct path *, struct vectors *, int) =EF=BC=9E +int ev=5Fremove=5Fpath (struct path *, struct vectors *, int) =EF=BC=9E int ev=5Fadd=5Fmap (char *, char *, struct vectors *) =EF=BC=9E int ev=5Fremove=5Fmap (char *, char *, int, struct vectors *) =EF=BC=9E void sync=5Fmap=5Fstate (struct multipath *) =EF=BC=9E --=20 =EF=BC=9E 2.8.1.windows.1 =EF=BC=9E=20 -- dm-devel mailing list dm-devel@redhat.com https://www.redhat.com/mailman/listinfo/dm-devel --=====_003_next===== Content-Type: text/html ; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

Hello Ben,


Good catch, you = are so nice and responsible person.

I have modified those bugs and re= sended the patch just now,

Please have a review for it.


Thanks,

Tang Junhui





=E5=8E=9F=E5=A7=8B=E9=82=AE=E4=BB=B6
=E5=8F=91=E4=BB=B6=E4=BA=BA=EF=BC=9A =EF=BC=9Cbmarzins@redhat.com=EF=BC=9E;<= /span>
=E6=94=B6=E4=BB=B6= =E4=BA=BA=EF=BC=9A=E5=94=90=E5=86=9B=E8=BE=8910074136;
=E6=8A=84=E9=80=81=E4=BA=BA=EF=BC=9A=E5=94=90= =E6=96=87=E4=BF=8A10144149;=E5=BC=A0=E5=87=AF10072500; =EF=BC=9Cdm-devel@redhat.com= =EF=BC=9E; =EF=BC=9Cbart.vanassche@sandisk.com=EF=BC=9E; =EF=BC=9Cmwilck@suse.com=EF= =BC=9E;
=E6=97=A5= =E6=9C=9F =EF=BC=9A2017=E5=B9=B402=E6=9C=8816=E6= =97=A5 05:15
= =E4=B8=BB =E9=A2=98 =EF=BC=9ARe= : [dm-devel] [PATCH] multipath-tools: improve processing efficiency for add= ition and deletion of multipath devices


On Wed, Jan 18, 2017&= nbsp;at 03:38:33PM +0800, tang.junhui@zte.com.cn wrote:=
=EF=BC=9E From: "tang.junhui" =EF=BC=9Ctang.junhui@zte.c= om.cn=EF=BC=9E
=EF=BC=9E 
=EF=BC=9E Change-Id: I3f81a5= 5fff389f991f915927000b281d7e263cc5
=EF=BC=9E Signed-off-by: ta= ng.junhui =EF=BC=9Ctang.junhui@zte.com.cn=EF=BC=9E
=EF=BC=9E <= br>=EF=BC=9E This patch used to improve proce= ssing efficiency for addition and deletion
=EF= =BC=9E of multipath devices.
=EF=BC=9E 
=EF=BC=9E=  This patch is tested pass by ZTE m= ultipath automatic testing system.
=EF=BC=9E The&nbs= p;modification reduces the system consumption(such = ;as CPU) and shortens
=EF=BC=9E the processing&= nbsp;time obviously in scene of massive multi= path devices
=EF=BC=9E addition or deletion.
=EF= =BC=9E 
=EF=BC=9E The main processing flow = ;of code is:
=EF=BC=9E 1) add uid=5Fattrs = configuration in the defaults section:
=EF=BC=9E&nbs= p;   It is configured udev attribute&nbs= p;which providing a unique path identifier
=EF= =BC=9E    for corresponding type of = ;path devices. If this field is configured&nb= sp;and
=EF=BC=9E    matched with type = ;of device, it would override any other = methods providing
=EF=BC=9E    for device&= nbsp;unique identifier in config file, and it=  would activate merging
=EF=BC=9E    = uevents according to the identifier to promot= e effiecncy in processing
=EF=BC=9E   &nbs= p;uevents. Tt has no default value, so d= efaultly only uevents filtering
=EF=BC=9E  &nbs= p; works, and uevents merging does not w= orks, if users want to identify path
=EF= =BC=9E    by udev attribute and to&= nbsp;activate merging uevents for SCSI and DA= S device,
=EF=BC=9E    they can set&n= bsp;it's value as:
=EF=BC=9E    "sd:ID=5FS= ERIAL dasd:ID=5FUID"
=EF=BC=9E 2) uevents accumulati= on in uevents burst scene:
=EF=BC=9E  &nbs= p; wait one seconds for more uevents in&= nbsp;uevent=5Flisten() in uevents burst
=EF=BC=9E &n= bsp;  situations
=EF=BC=9E 3) uevents preparing= , filtering and merging:
=EF=BC=9E    = ;discard unuse uevents and fetch path idendif= ier from uevents;
=EF=BC=9E    filter = ;uevents;
=EF=BC=9E    merge uevents.
=EF=BC= =9E 4) uevents proccessing:
=EF=BC=9E   &n= bsp;proccess the merged uevents in uev-=EF=BC=9Eme= rge=5Fnode list without calling
=EF=BC=9E  &nbs= p; domap();
=EF=BC=9E    proccess the = ;last uevents uev with calling domap().
=EF=BC= =9E 
=EF=BC=9E Any comment will be welcome= , and it would be appreciated if these=EF=BC=9E patches would be considered for i= nclusion in the upstream
=EF=BC=9E multipath-tools.<= br>
Sorry for letting this slip through th= e cracks. This patch is really
close. I&nb= sp;just have a few issues. First off, th= is is completely
superficial, but select=5Fgetuid()&= nbsp;should use the new style of origin
me= ssages. instead of

origin =3D "(config file=  default)";

it should probably be

origin&= nbsp;=3D "(setting: multipath.conf defaults/devices sec= tion)"

to match the other messages.


S= econd, there is a bug in parse=5Fuid=5Fattrib= ute=5Fby=5Fattrs(). get=5Fword()
returns the number = of characters that the returned word takes&nb= sp;up in the
sentence, but you keep using&= nbsp;it as the offset from the start of<= br>uid=5Fattrs.  This doesn't effect the firs= t call to get=5Fword(), since it
doesn't u= se count. The second time you call get= =5Fword(), everything still
works because the n= umber of characters that the first word = took up is
also the offset from the s= tart of uid=5Fattrs.  However, on a
(hypot= hetical) third call, count is just the s= ize of the second word,
but you use a= re using it as the offset from the = start of uid=5Fattrs (the
size of the firs= t and second word combined). This means = that the a third
call won't start at = the correct place, and can get stuck in&= nbsp;an endless
loop. Obviously, as long as&nbs= p;uid=5Fattrs only has two words in the = value,
this isn't a problem.  But if = we ever add another uid attribute to the=
list, it will break.


Finally, in ue= vent=5Fget=5Fwwid, the goal is to see an = ;environment variable
like

ID=5FSERIAL=3D3600d0230000000000e= 13955cc3757800

and correctly grab "3600d0230000000000= e13955cc3757800" as the wwid.
Unfortunately in = the list of environment variables for scsi&nb= sp;devices,
there is also

ID=5FSERIAL=5FSHORT=3D600d023= 0000000000e13955cc3757800

If multipath happened to&nb= sp;see this environment variable first, it wo= uld
grab "SHORT=3D600d0230000000000e13955cc3757800" as th= e wwid. It needs to
check that the ch= aracter after strlen(uid=5Fattribute) is an equals=  sign.
Now, I realize that code all o= ver multipath-tools doesn't bother
checking for = ;an equals sign, but in this specific ca= se there is a known
evironment variable th= at could cause problems if we don't chec= k (not
that those other cases don't need&n= bsp;fixing eventually).

otherwise, it looks grea= t.

Thanks
-Ben

=EF=BC=9E Thank you all,
= =EF=BC=9E Tang Junhui
=EF=BC=9E ---
=EF=BC=9E &nb= sp;libmultipath/config.c      |  &n= bsp;3 +
=EF=BC=9E  libmultipath/config.h   = ;   |   1 +
=EF=BC=9E  libm= ultipath/dict.c        |  = ; 3 +
=EF=BC=9E  libmultipath/discovery.c  = ; |   5 +-
=EF=BC=9E  libmultipath/di= scovery.h   |   2 +-
=EF=BC=9E &= nbsp;libmultipath/list.h        |&n= bsp; 41 ++++++
=EF=BC=9E  libmultipath/propsel.c&nbs= p;    |   7 +
=EF=BC=9E &nb= sp;libmultipath/uevent.c      | 319 = ;+++++++++++++++++++++++++++++++++++++++++++--
=EF=BC=9E  libm= ultipath/uevent.h      |   2&n= bsp;+
=EF=BC=9E  libmultipath/util.c    &n= bsp;   |  40 ++++++
=EF=BC=9E  l= ibmultipath/util.h        | &n= bsp; 1 +
=EF=BC=9E  multipath/multipath.conf.5 = |  18 +++
=EF=BC=9E  multipathd/cli=5Fhandlers.= c  |   4 +-
=EF=BC=9E  multipath= d/main.c          | =  93 +++++--------
=EF=BC=9E  multipathd/main.h =          |   4&= nbsp;+-
=EF=BC=9E  15 files changed, 468 i= nsertions(+), 75 deletions(-)
=EF=BC=9E 
=EF=BC=9E&nbs= p;diff --git a/libmultipath/config.c b/libmultipath/config.c=
=EF=BC=9E index 15ddbd8..765e91d 100644
=EF=BC=9E&nbs= p;--- a/libmultipath/config.c
=EF=BC=9E +++ b/libmultipat= h/config.c
=EF=BC=9E @@ -488,6 +488,9 @@ free= =5Fconfig (struct config * conf)
=EF=BC=9E &nbs= p;    if (conf-=EF=BC=9Euid=5Fattribute)
=EF=BC= =9E          FREE(conf-= =EF=BC=9Euid=5Fattribute);
=EF=BC=9E  
=EF=BC=9E +&nbs= p;   if (conf-=EF=BC=9Euid=5Fattrs)
=EF=BC=9E +=         FREE(conf-=EF=BC=9Euid=5Fat= trs);
=EF=BC=9E +
=EF=BC=9E      i= f (conf-=EF=BC=9Egetuid)
=EF=BC=9E     &nb= sp;    FREE(conf-=EF=BC=9Egetuid);
=EF=BC=9E &n= bsp;
=EF=BC=9E diff --git a/libmultipath/config.h b/= libmultipath/config.h
=EF=BC=9E index 9670020..ab85930 10= 0644
=EF=BC=9E --- a/libmultipath/config.h
=EF=BC=9E += ++ b/libmultipath/config.h
=EF=BC=9E @@ -153,6 +153,= 7 @@ struct config {
=EF=BC=9E  
=EF=BC= =9E      char * multipath=5Fdir;=EF=BC=9E      char * selector;=EF=BC=9E +    char * uid=5Fattrs;
= =EF=BC=9E      char * uid=5Fattribu= te;
=EF=BC=9E      char * getuid= ;
=EF=BC=9E      char * features= ;
=EF=BC=9E diff --git a/libmultipath/dict.c b/libmu= ltipath/dict.c
=EF=BC=9E index dc21846..0a531d1 100644=EF=BC=9E --- a/libmultipath/dict.c
=EF=BC=9E +++ b= /libmultipath/dict.c
=EF=BC=9E @@ -249,6 +249,8 @@&n= bsp;declare=5Fovr=5Fsnprint(selector, print=5Fstr)
=EF=BC=9E &= nbsp;declare=5Fmp=5Fhandler(selector, set=5Fstr)
=EF=BC=9E &nb= sp;declare=5Fmp=5Fsnprint(selector, print=5Fstr)
=EF=BC=9E &nb= sp;
=EF=BC=9E +declare=5Fdef=5Fhandler(uid=5Fattrs, set=5Fstr)=
=EF=BC=9E +declare=5Fdef=5Fsnprint(uid=5Fattrs, print=5Fstr)<= br>=EF=BC=9E  declare=5Fdef=5Fhandler(uid=5Fattribute, set= =5Fstr)
=EF=BC=9E  declare=5Fdef=5Fsnprint=5Fdefstr(uid=5Fattr= ibute, print=5Fstr, DEFAULT=5FUID=5FATTRIBUTE)
=EF=BC=9E =  declare=5Fovr=5Fhandler(uid=5Fattribute, set=5Fstr)
=EF=BC=9E=  @@ -1367,6 +1369,7 @@ init=5Fkeywords(vector = ;keywords)
=EF=BC=9E      install=5Fkeywor= d("multipath=5Fdir", &def=5Fmultipath=5Fdir=5Fhandler, &s= nprint=5Fdef=5Fmultipath=5Fdir);
=EF=BC=9E     =  install=5Fkeyword("path=5Fselector", &def=5Fselector=5Fhandl= er, &snprint=5Fdef=5Fselector);
=EF=BC=9E   &nbs= p;  install=5Fkeyword("path=5Fgrouping=5Fpolicy", &def= =5Fpgpolicy=5Fhandler, &snprint=5Fdef=5Fpgpolicy);
=EF=BC=9E&nb= sp;+    install=5Fkeyword("uid=5Fattrs", &def= =5Fuid=5Fattrs=5Fhandler, &snprint=5Fdef=5Fuid=5Fattrs);
=EF=BC= =9E      install=5Fkeyword("uid=5Fattribute",=  &def=5Fuid=5Fattribute=5Fhandler, &snprint=5Fdef=5Fuid= =5Fattribute);
=EF=BC=9E      install=5Fke= yword("getuid=5Fcallout", &def=5Fgetuid=5Fhandler, &snpri= nt=5Fdef=5Fgetuid);
=EF=BC=9E      install= =5Fkeyword("prio", &def=5Fprio=5Fname=5Fhandler, &snprint= =5Fdef=5Fprio=5Fname);
=EF=BC=9E diff --git a/libmultipat= h/discovery.c b/libmultipath/discovery.c
=EF=BC=9E index = d1aec31..14904f2 100644
=EF=BC=9E --- a/libmultipath/disc= overy.c
=EF=BC=9E +++ b/libmultipath/discovery.c
=EF=BC=9E&= nbsp;@@ -33,7 +33,7 @@
=EF=BC=9E  
=EF=BC=9E=   int
=EF=BC=9E  alloc=5Fpath=5Fwith=5Fpathinfo = ;(struct config *conf, struct udev=5Fdevice *udevi= ce,
=EF=BC=9E -        &nbs= p;     int flag, struct path *= *pp=5Fptr)
=EF=BC=9E +       &nb= sp;      char *wwid, int flag,=  struct path **pp=5Fptr)
=EF=BC=9E  {
=EF=BC= =9E      int err =3D PATHINFO= =5FFAILED;
=EF=BC=9E      struct path=  * pp;
=EF=BC=9E @@ -51,6 +51,9 @@ al= loc=5Fpath=5Fwith=5Fpathinfo (struct config *conf, stru= ct udev=5Fdevice *udevice,
=EF=BC=9E    &n= bsp; if (!pp)
=EF=BC=9E      &nb= sp;   return PATHINFO=5FFAILED;
=EF=BC=9E  = ;
=EF=BC=9E +    if(wwid)
=EF=BC=9E +&n= bsp;       strncpy(pp-=EF=BC=9Ewwid,&nbs= p;wwid, sizeof(pp-=EF=BC=9Ewwid));
=EF=BC=9E +
=EF=BC=9E&nb= sp;     if (safe=5Fsprintf(pp-=EF=BC=9Edev,&n= bsp;"%s", devname)) {
=EF=BC=9E     &= nbsp;    condlog(0, "pp-=EF=BC=9Edev too = ;small");
=EF=BC=9E      } else = {
=EF=BC=9E diff --git a/libmultipath/discovery.h b/= libmultipath/discovery.h
=EF=BC=9E index 3039268..d16a69a = ;100644
=EF=BC=9E --- a/libmultipath/discovery.h
=EF=BC=9E&= nbsp;+++ b/libmultipath/discovery.h
=EF=BC=9E @@ -37,7&nb= sp;+37,7 @@ int path=5Foffline (struct path *= );
=EF=BC=9E  int get=5Fstate (struct path = ;* pp, struct config * conf, int daemon)= ;
=EF=BC=9E  int pathinfo (struct path *&n= bsp;pp, struct config * conf, int mask);
= =EF=BC=9E  int alloc=5Fpath=5Fwith=5Fpathinfo (struct&n= bsp;config *conf, struct udev=5Fdevice *udevice,
=EF= =BC=9E -          &n= bsp;       int flag, struct&nb= sp;path **pp=5Fptr);
=EF=BC=9E +     =             &nb= sp;char *wwid, int flag, struct path **pp=5Fp= tr);
=EF=BC=9E  int store=5Fpathinfo (vector pa= thvec, struct config *conf,
=EF=BC=9E   &n= bsp;          struct = ;udev=5Fdevice *udevice, int flag,
=EF=BC=9E  &= nbsp;           stru= ct path **pp=5Fptr);
=EF=BC=9E diff --git a/lib= multipath/list.h b/libmultipath/list.h
=EF=BC=9E index ce= aa381..2b1dcf3 100644
=EF=BC=9E --- a/libmultipath/list.h=
=EF=BC=9E +++ b/libmultipath/list.h
=EF=BC=9E @@ = ;-317,4 +317,45 @@ static inline void list=5F= splice=5Ftail=5Finit(struct list=5Fhead *list,
=EF=BC=9E =           &pos-=EF=BC= =9Emember !=3D (head);       &= nbsp;           &nbs= p;\
=EF=BC=9E          = ; pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Eme= mber.next, typeof(*n), member))
=EF=BC=9E  
=EF= =BC=9E +/**
=EF=BC=9E + * list=5Ffor=5Feach=5Fentry= =5Freverse=5Fsafe - iterate backwards over list&nb= sp;of given type safe against removal of = ;list entry
=EF=BC=9E + * @pos:   &nb= sp;the type * to use as a loop coun= ter.
=EF=BC=9E + * @n:      = ;  another type * to use as tempora= ry storage
=EF=BC=9E + * @head:   &nb= sp;the head for your list.
=EF=BC=9E + *&n= bsp;@member:    the name of the lis= t=5Fstruct within the struct.
=EF=BC=9E + */=EF=BC=9E +#define list=5Ffor=5Feach=5Fentry=5Freverse=5Fsafe(po= s, n, head, member)       = ;   \
=EF=BC=9E +    for (p= os =3D list=5Fentry((head)-=EF=BC=9Eprev, typeof(*pos), = ;member),      \
=EF=BC=9E + &nb= sp;       n =3D list=5Fentry(p= os-=EF=BC=9Emember.prev, typeof(*pos), member);\
=EF=BC=9E&nbs= p;+         &pos-=EF=BC=9E= member !=3D (head);       &nbs= p;            &= nbsp;           &nbs= p;   \
=EF=BC=9E +     &nbs= p;   pos =3D n, n =3D list=5Fentry(= n-=EF=BC=9Emember.prev, typeof(*n), member))
=EF=BC=9E +<= br>=EF=BC=9E +/**
=EF=BC=9E + * list=5Ffor=5Fsome=5F= entry=5Fsafe - iterate list from the given&nb= sp;begin node to the given end node safe=  against removal of list entry
=EF=BC=9E +=  * @pos:    the type * to = ;use as a loop counter.
=EF=BC=9E + * = ;@n:        another type = * to use as temporary storage
=EF=BC=9E +&= nbsp;* @from:    the begin node of&= nbsp;the iteration.
=EF=BC=9E + * @to:  &n= bsp;     the end node of the&n= bsp;iteration.
=EF=BC=9E + * @member:   &n= bsp;the name of the list=5Fstruct within the&= nbsp;struct.
=EF=BC=9E + */
=EF=BC=9E +#define li= st=5Ffor=5Fsome=5Fentry=5Fsafe(pos, n, from, to, member= )            &n= bsp; \
=EF=BC=9E +    for (pos = =3D list=5Fentry((from)-=EF=BC=9Enext, typeof(*pos), member)= ,      \
=EF=BC=9E +   = ;      n =3D list=5Fentry(pos-=EF= =BC=9Emember.next, typeof(*pos), member);    = \
=EF=BC=9E +         = &pos-=EF=BC=9Emember !=3D (to);     =             &nb= sp;            =         \
=EF=BC=9E + =         pos =3D n, n=  =3D list=5Fentry(n-=EF=BC=9Emember.next, typeof(*n), m= ember))
=EF=BC=9E +
=EF=BC=9E +/**
=EF=BC=9E + = ;* list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe - iterate = ;backwards list from the given begin node&nbs= p;to the given end node safe against rem= oval of list entry
=EF=BC=9E + * @pos:&nbs= p;   the type * to use as a&nb= sp;loop counter.
=EF=BC=9E + * @n:   =      another type * to use&nbs= p;as temporary storage
=EF=BC=9E + * @from:&nbs= p;   the begin node of the iteratio= n.
=EF=BC=9E + * @to:      =   the end node of the iteration.
=EF= =BC=9E + * @member:    the name&nbs= p;of the list=5Fstruct within the struct.
=EF= =BC=9E + */
=EF=BC=9E +#define list=5Ffor=5Fsome=5Fe= ntry=5Freverse=5Fsafe(pos, n, from, to, member) &n= bsp;    \
=EF=BC=9E +    fo= r (pos =3D list=5Fentry((from)-=EF=BC=9Eprev, typeof(*p= os), member),      \
=EF=BC=9E +=          n =3D list= =5Fentry(pos-=EF=BC=9Emember.prev, typeof(*pos), member); &n= bsp;  \
=EF=BC=9E +      &n= bsp;  &pos-=EF=BC=9Emember !=3D (to);  &n= bsp;            = ;            &n= bsp;          \
=EF=BC= =9E +         pos = =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.prev, = typeof(*n), member))
=EF=BC=9E +
=EF=BC=9E  #endi= f /* =5FLIST=5FH */
=EF=BC=9E diff --git a= /libmultipath/propsel.c b/libmultipath/propsel.c
=EF=BC=9E ind= ex c0bc616..5a58dc0 100644
=EF=BC=9E --- a/libmultip= ath/propsel.c
=EF=BC=9E +++ b/libmultipath/propsel.c
=EF=BC= =9E @@ -18,6 +18,7 @@
=EF=BC=9E  #include&= nbsp;"prio.h"
=EF=BC=9E  #include "discovery.h"
=EF=BC= =9E  #include "dict.h"
=EF=BC=9E +#include "uti= l.h"
=EF=BC=9E  #include "prioritizers/alua=5Frtpg.h"
= =EF=BC=9E  #include =EF=BC=9Cinttypes.h=EF=BC=9E
=EF=BC= =9E  
=EF=BC=9E @@ -339,6 +340,12 @@ = int select=5Fgetuid(struct config *conf, struct pa= th *pp)
=EF=BC=9E  {
=EF=BC=9E    =   char *origin;
=EF=BC=9E  
=EF=BC=9E +=     pp-=EF=BC=9Euid=5Fattribute =3D parse=5Fu= id=5Fattribute=5Fby=5Fattrs(conf-=EF=BC=9Euid=5Fattrs, pp-=EF=BC=9Edev= );
=EF=BC=9E +    if (pp-=EF=BC=9Euid=5Fat= tribute) {
=EF=BC=9E +      &nbs= p; origin =3D "(config file default)";
=EF=BC= =9E +        goto out;=EF=BC=9E +    }
=EF=BC=9E +
=EF=BC=9E=       pp=5Fset=5Fovr(getuid);
=EF=BC=9E&nb= sp;     pp=5Fset=5Fovr(uid=5Fattribute);
=EF=BC= =9E      pp=5Fset=5Fhwe(getuid);
=EF=BC=9E=  diff --git a/libmultipath/uevent.c b/libmultipath/ueve= nt.c
=EF=BC=9E index 7edcce1..7e4ac04 100644
=EF=BC=9E=  --- a/libmultipath/uevent.c
=EF=BC=9E +++ b/libmult= ipath/uevent.c
=EF=BC=9E @@ -24,6 +24,7 @@
=EF=BC= =9E  
=EF=BC=9E  #include =EF=BC=9Cunistd.h=EF= =BC=9E
=EF=BC=9E  #include =EF=BC=9Cstdio.h=EF=BC=9E
= =EF=BC=9E +#include =EF=BC=9Cstdbool.h=EF=BC=9E
=EF=BC=9E = ; #include =EF=BC=9Cerrno.h=EF=BC=9E
=EF=BC=9E  #inc= lude =EF=BC=9Cstdlib.h=EF=BC=9E
=EF=BC=9E  #include = =EF=BC=9Cstddef.h=EF=BC=9E
=EF=BC=9E @@ -38,6 +39,7 = @@
=EF=BC=9E  #include =EF=BC=9Clinux/netlink.h=EF=BC=9E<= br>=EF=BC=9E  #include =EF=BC=9Cpthread.h=EF=BC=9E
=EF=BC= =9E  #include =EF=BC=9Csys/mman.h=EF=BC=9E
=EF=BC=9E = ;+#include =EF=BC=9Csys/time.h=EF=BC=9E
=EF=BC=9E  #inclu= de =EF=BC=9Clibudev.h=EF=BC=9E
=EF=BC=9E  #include = =EF=BC=9Cerrno.h=EF=BC=9E
=EF=BC=9E  
=EF=BC=9E @@&nbs= p;-46,6 +48,14 @@
=EF=BC=9E  #include "list.h"<= br>=EF=BC=9E  #include "uevent.h"
=EF=BC=9E  #i= nclude "vector.h"
=EF=BC=9E +#include "structs.h"
=EF= =BC=9E +#include "util.h"
=EF=BC=9E +#include "confi= g.h"
=EF=BC=9E +#include "blacklist.h"
=EF=BC=9E +
= =EF=BC=9E +#define MAX=5FACCUMULATION=5FCOUNT 2048
=EF=BC= =9E +#define MAX=5FACCUMULATION=5FTIME 30*1000
=EF=BC=9E&= nbsp;+#define MIN=5FBURST=5FSPEED 10
=EF=BC=9E  
= =EF=BC=9E  typedef int (uev=5Ftrigger)(struct ueve= nt *, void * trigger=5Fdata);
=EF=BC=9E  <= br>=EF=BC=9E @@ -72,48 +82,300 @@ struct ueve= nt * alloc=5Fuevent (void)
=EF=BC=9E  {
=EF= =BC=9E      struct uevent *uev = ;=3D MALLOC(sizeof(struct uevent));
=EF=BC=9E  
= =EF=BC=9E -    if (uev)
=EF=BC=9E +&n= bsp;   if (uev) {
=EF=BC=9E   &n= bsp;      INIT=5FLIST=5FHEAD(&uev-=EF=BC= =9Enode);
=EF=BC=9E +       &nbs= p;INIT=5FLIST=5FHEAD(&uev-=EF=BC=9Emerge=5Fnode);
=EF=BC=9E +&n= bsp;   }
=EF=BC=9E  
=EF=BC=9E  &n= bsp;   return uev;
=EF=BC=9E  }
=EF=BC= =9E  
=EF=BC=9E  void
=EF=BC=9E -service=5Fu= evq(struct list=5Fhead *tmpq)
=EF=BC=9E +uevq=5Fcleanup(s= truct list=5Fhead *tmpq)
=EF=BC=9E  {
=EF=BC=9E&n= bsp;     struct uevent *uev, *tmp;<= br>=EF=BC=9E  
=EF=BC=9E      li= st=5Ffor=5Feach=5Fentry=5Fsafe(uev, tmp, tmpq, node) {<= br>=EF=BC=9E          lis= t=5Fdel=5Finit(&uev-=EF=BC=9Enode);
=EF=BC=9E  
=EF=BC= =9E -        if (my=5Fuev= =5Ftrigger && my=5Fuev=5Ftrigger(uev, my=5Ftrigger= =5Fdata))
=EF=BC=9E -       &nbs= p;    condlog(0, "uevent trigger error")= ;
=EF=BC=9E -
=EF=BC=9E       = ;   if (uev-=EF=BC=9Eudev)
=EF=BC=9E  &nbs= p;           udev=5F= device=5Funref(uev-=EF=BC=9Eudev);
=EF=BC=9E    &nbs= p;     FREE(uev);
=EF=BC=9E   &n= bsp;  }
=EF=BC=9E  }
=EF=BC=9E  
=EF= =BC=9E -static void uevent=5Fcleanup(void *arg)
=EF= =BC=9E +void
=EF=BC=9E +uevent=5Fget=5Fwwid(struct uevent=  *uev)
=EF=BC=9E  {
=EF=BC=9E -   =  struct udev *udev =3D arg;
=EF=BC=9E +&nb= sp;   int i;
=EF=BC=9E +    = ;char *uid=5Fattribute;
=EF=BC=9E +    str= uct config * conf;
=EF=BC=9E +   &nbs= p;
=EF=BC=9E +    conf =3D get=5Fmult= ipath=5Fconfig();
=EF=BC=9E +    uid=5Fattribut= e =3D parse=5Fuid=5Fattribute=5Fby=5Fattrs(conf-=EF=BC=9Euid=5Fat= trs, uev-=EF=BC=9Ekernel);
=EF=BC=9E +    = put=5Fmultipath=5Fconfig(conf);    
=EF=BC=9E +=     
=EF=BC=9E +    if = ;(!uid=5Fattribute)
=EF=BC=9E +      =   return;
=EF=BC=9E +    
=EF=BC= =9E +    for (i =3D 0; uev-=EF= =BC=9Eenvp[i] !=3D NULL; i++) {
=EF=BC=9E +&nbs= p;       if (!strncmp(uev-=EF=BC=9E= envp[i], uid=5Fattribute, strlen(uid=5Fattribute)) &&= ;
=EF=BC=9E +         =    strlen(uev-=EF=BC=9Eenvp[i]) =EF=BC=9E strlen(u= id=5Fattribute)) {
=EF=BC=9E +     &n= bsp;      uev-=EF=BC=9Ewwid =3D uev= -=EF=BC=9Eenvp[i] + strlen(uid=5Fattribute) + 1;
=EF= =BC=9E +          &n= bsp; break;
=EF=BC=9E +      &nb= sp; }
=EF=BC=9E +    }
=EF=BC=9E +=     free(uid=5Fattribute);
=EF=BC=9E +}
=EF= =BC=9E  
=EF=BC=9E -    condlog(3,&nb= sp;"Releasing uevent=5Flisten() resources");
=EF=BC=9E -&= nbsp;   udev=5Funref(udev);
=EF=BC=9E +bool
=EF= =BC=9E +uevent=5Fneed=5Fmerge(void)
=EF=BC=9E +{
=EF=BC=9E&= nbsp;+    struct config * conf;
=EF= =BC=9E +    bool need=5Fmerge =3D f= alse;
=EF=BC=9E +
=EF=BC=9E +    conf&n= bsp;=3D get=5Fmultipath=5Fconfig();
=EF=BC=9E +  &nb= sp; if (conf-=EF=BC=9Euid=5Fattrs)
=EF=BC=9E +  = ;      need=5Fmerge =3D true;
= =EF=BC=9E +    put=5Fmultipath=5Fconfig(conf);&nbs= p;   
=EF=BC=9E +
=EF=BC=9E +  &nb= sp; return need=5Fmerge;
=EF=BC=9E +}
=EF=BC=9E +=
=EF=BC=9E +bool
=EF=BC=9E +uevent=5Fcan=5Fdiscard(struct&n= bsp;uevent *uev)
=EF=BC=9E +{
=EF=BC=9E +  &= nbsp; char *tmp;
=EF=BC=9E +    char&= nbsp;a[11], b[11];
=EF=BC=9E +    struct&n= bsp;config * conf;
=EF=BC=9E +
=EF=BC=9E + &= nbsp;  /*
=EF=BC=9E +     * = ;keep only block devices, discard partitions
= =EF=BC=9E +     */
=EF=BC=9E + &= nbsp;  tmp =3D strstr(uev-=EF=BC=9Edevpath, "/bloc= k/");
=EF=BC=9E +    if (tmp =3D=3D&n= bsp;NULL){
=EF=BC=9E +       &nb= sp;condlog(4, "no /block/ in '%s'", uev-=EF=BC=9Ed= evpath);
=EF=BC=9E +        = ;return true;
=EF=BC=9E +    }
=EF=BC= =9E +    if (sscanf(tmp, "/block/%10s",&= nbsp;a) !=3D 1 ||
=EF=BC=9E +    = ;    sscanf(tmp, "/block/%10[^/]/%10s", a,&nb= sp;b) =3D=3D 2) {
=EF=BC=9E +    = ;    condlog(4, "discard event on %= s", uev-=EF=BC=9Edevpath);
=EF=BC=9E +    =     return true;
=EF=BC=9E +  &n= bsp; }
=EF=BC=9E +
=EF=BC=9E +    = /* 
=EF=BC=9E +     * do no= t filter dm devices by devnode
=EF=BC=9E +=      */
=EF=BC=9E +    = ;if (!strncmp(uev-=EF=BC=9Ekernel, "dm-", 3))
=EF=BC=9E&n= bsp;+        return false;
= =EF=BC=9E +    /* 
=EF=BC=9E + &= nbsp;   * filter paths devices by d= evnode
=EF=BC=9E +     */
=EF=BC=9E&nbs= p;+    conf =3D get=5Fmultipath=5Fconfig();=EF=BC=9E +    if (filter=5Fdevnode(conf-= =EF=BC=9Eblist=5Fdevnode, conf-=EF=BC=9Eelist=5Fdevnode,
=EF=BC=9E&= nbsp;+           &nb= sp;   uev-=EF=BC=9Ekernel) =EF=BC=9E 0) {
= =EF=BC=9E +        put=5Fmulti= path=5Fconfig(conf);
=EF=BC=9E +      = ;  return true;
=EF=BC=9E +    }=
=EF=BC=9E +    put=5Fmultipath=5Fconfig(conf);=
=EF=BC=9E +
=EF=BC=9E +    return = ;false;
=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +bool=EF=BC=9E +uevent=5Fcan=5Ffilter(struct uevent *earlier,&nb= sp;struct uevent *later)
=EF=BC=9E +{
=EF=BC=9E +=
=EF=BC=9E +    /*
=EF=BC=9E + &nb= sp;   * filter earlier uvents if pa= th has removed later. Eg:
=EF=BC=9E + &nbs= p;   * "add path1 |chang path1 |add=  path2 |remove path1"
=EF=BC=9E +   &= nbsp; * can filter as:
=EF=BC=9E +  &= nbsp;  * "add path2 |remove path1"
=EF=BC= =9E +     * uevents "add path1= " and "chang path1" are filtered out
=EF= =BC=9E +     */
=EF=BC=9E + &nbs= p;  if (!strcmp(earlier-=EF=BC=9Ekernel, later-=EF=BC= =9Ekernel) &&
=EF=BC=9E +     = ;   !strcmp(later-=EF=BC=9Eaction, "remove") &= &
=EF=BC=9E +        st= rncmp(later-=EF=BC=9Ekernel, "dm-", 3)) {
=EF=BC=9E = +        return true;
=EF= =BC=9E +    }
=EF=BC=9E +
=EF=BC=9E&nbs= p;+    /*
=EF=BC=9E +    &n= bsp;* filter change uvents if add uevents&nbs= p;exist. Eg:
=EF=BC=9E +     * "= change path1| add path1 |add path2"
=EF=BC=9E&n= bsp;+     * can filter as:
=EF= =BC=9E +     * "add path1 |add=  path2"
=EF=BC=9E +     * uevent=  "chang path1" is filtered out
=EF=BC=9E +=      */
=EF=BC=9E +    = ;if (!strcmp(earlier-=EF=BC=9Ekernel, later-=EF=BC=9Ekernel) = ;&&
=EF=BC=9E +       &n= bsp;!strcmp(earlier-=EF=BC=9Eaction, "change") &&
=EF= =BC=9E +        !strcmp(later-= =EF=BC=9Eaction, "add") &&
=EF=BC=9E +  = ;      strncmp(later-=EF=BC=9Ekernel, "d= m-", 3)) {
=EF=BC=9E +      = ;  return true;
=EF=BC=9E +    }=
=EF=BC=9E +
=EF=BC=9E +    return = ;false;
=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +bool=EF=BC=9E +merge=5Fneed=5Fstop(struct uevent *earlier, = ;struct uevent *later)
=EF=BC=9E +{
=EF=BC=9E +&n= bsp;   /*
=EF=BC=9E +     *=  dm uevent do not try to merge with=  left uevents
=EF=BC=9E +     */=
=EF=BC=9E +    if (!strncmp(later-=EF=BC= =9Ekernel, "dm-", 3))
=EF=BC=9E +    =     return true;
=EF=BC=9E +
=EF=BC=9E&= nbsp;+    /*
=EF=BC=9E +    = ; * we can not make a jugement with= out wwid,
=EF=BC=9E +     * so&n= bsp;it is sensible to stop merging
=EF=BC=9E&nb= sp;+     */
=EF=BC=9E +   &= nbsp;if (!earlier-=EF=BC=9Ewwid || !later-=EF=BC=9Ewwid)
= =EF=BC=9E +        return = ;true;
=EF=BC=9E +    /*
=EF=BC=9E +&nb= sp;    * uevents merging stoped
=EF= =BC=9E +     * when we meet&nb= sp;an opposite action uevent from the same&nb= sp;LUN to AVOID
=EF=BC=9E +     = * "add path1 |remove path1 |add path2 |r= emove path2 |add path3"
=EF=BC=9E +   = ;  * to merge as "remove path1, pat= h2" and "add path1, path2, path3"
=EF=BC=9E&nbs= p;+     * OR
=EF=BC=9E +  &= nbsp;  * "remove path1 |add path1 |remov= e path2 |add path2 |remove path3"
=EF=BC=9E&nbs= p;+     * to merge as "add&nbs= p;path1, path2" and "remove path1, path2, pat= h3"
=EF=BC=9E +     * SO
=EF=BC=9E=  +     * when we meet a&n= bsp;non-change uevent from the same LUN
=EF=BC= =9E +     * with the same = ;wwid and different action
=EF=BC=9E +  &n= bsp;  * it would be better to stop&= nbsp;merging.
=EF=BC=9E +     */
=EF=BC= =9E +    if (!strcmp(earlier-=EF=BC=9Ewwid,&n= bsp;later-=EF=BC=9Ewwid) &&
=EF=BC=9E +  &nb= sp;     strcmp(earlier-=EF=BC=9Eaction, later= -=EF=BC=9Eaction) &&
=EF=BC=9E +   &nbs= p;    strcmp(earlier-=EF=BC=9Eaction, "change")&nb= sp;&&
=EF=BC=9E +       =  strcmp(later-=EF=BC=9Eaction, "change"))
=EF=BC=9E +&nbs= p;       return true;
=EF=BC=9E&= nbsp;+
=EF=BC=9E +    return false;
=EF= =BC=9E +}
=EF=BC=9E +
=EF=BC=9E +bool
=EF=BC=9E&nbs= p;+uevent=5Fcan=5Fmerge(struct uevent *earlier, struct = uevent *later)
=EF=BC=9E +{
=EF=BC=9E +  &nb= sp; /* merge paths uevents
=EF=BC=9E + &nb= sp;   * whose wwids exsit and are&n= bsp;same
=EF=BC=9E +     * and a= ctions are same,
=EF=BC=9E +     = ;* and actions are addition or deletion
= =EF=BC=9E +     */
=EF=BC=9E + &= nbsp;  if (earlier-=EF=BC=9Ewwid && later-= =EF=BC=9Ewwid &&
=EF=BC=9E +    &n= bsp;   !strcmp(earlier-=EF=BC=9Ewwid, later-=EF=BC=9Eww= id) &&
=EF=BC=9E +      =   !strcmp(earlier-=EF=BC=9Eaction, later-=EF=BC=9Eaction)&nb= sp;&&
=EF=BC=9E +       =  strncmp(earlier-=EF=BC=9Eaction, "change", 6) &&am= p;
=EF=BC=9E +        strnc= mp(earlier-=EF=BC=9Ekernel, "dm-", 3)) {
=EF=BC=9E +=         return true;
=EF=BC= =9E +    }
=EF=BC=9E +
=EF=BC=9E +=     return false;
=EF=BC=9E  }
=EF= =BC=9E  
=EF=BC=9E  void
=EF=BC=9E -uevq=5Fc= leanup(struct list=5Fhead *tmpq)
=EF=BC=9E +uevent=5Fprep= are(struct list=5Fhead *tmpq)
=EF=BC=9E +{
=EF=BC=9E&n= bsp;+    struct uevent *uev, *tmp;
= =EF=BC=9E +
=EF=BC=9E +    list=5Ffor=5Fea= ch=5Fentry=5Freverse=5Fsafe(uev, tmp, tmpq, node) {
= =EF=BC=9E +        if (ue= vent=5Fcan=5Fdiscard(uev)) {
=EF=BC=9E +   &nbs= p;        list=5Fdel=5Finit(&ue= v-=EF=BC=9Enode);
=EF=BC=9E +      &n= bsp;     if (uev-=EF=BC=9Eudev)
=EF=BC=9E&= nbsp;+           &nb= sp;    udev=5Fdevice=5Funref(uev-=EF=BC=9Eudev);
=EF= =BC=9E +          &n= bsp; FREE(uev);
=EF=BC=9E +      = ;      continue;
=EF=BC=9E + &nb= sp;      }
=EF=BC=9E +
=EF=BC=9E&n= bsp;+        if (strncmp(uev-= =EF=BC=9Ekernel, "dm-", 3) &&
=EF=BC=9E +&nb= sp;           uevent= =5Fneed=5Fmerge())
=EF=BC=9E +      &= nbsp;     uevent=5Fget=5Fwwid(uev);
=EF=BC=9E&n= bsp;+    }
=EF=BC=9E +}
=EF=BC=9E +
= =EF=BC=9E +void
=EF=BC=9E +uevent=5Ffilter(struct uevent&= nbsp;*later, struct list=5Fhead *tmpq)
=EF=BC=9E +{<= br>=EF=BC=9E +    struct uevent *earlier= , *tmp;
=EF=BC=9E +
=EF=BC=9E +    = ;list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe(earlier, tmp, &la= ter-=EF=BC=9Enode, tmpq, node) {
=EF=BC=9E + &n= bsp;      /*
=EF=BC=9E +  &= nbsp;      * filter unnessary = earlier uevents 
=EF=BC=9E +     = ;    * by the later uevent
=EF= =BC=9E +         */
= =EF=BC=9E +        if (ue= vent=5Fcan=5Ffilter(earlier, later)) {
=EF=BC=9E + &= nbsp;          condlog(2,=  "uevent: %s-%s has filtered by uevent: = %s-%s",
=EF=BC=9E +        =         earlier-=EF=BC=9Ekernel,&nb= sp;earlier-=EF=BC=9Eaction, 
=EF=BC=9E +   &nbs= p;            l= ater-=EF=BC=9Ekernel, later-=EF=BC=9Eaction);
=EF=BC=9E +
= =EF=BC=9E +          = ;  list=5Fdel=5Finit(&earlier-=EF=BC=9Enode);
=EF=BC=9E&nb= sp;+            = ;if (earlier-=EF=BC=9Eudev)
=EF=BC=9E +    = ;            ud= ev=5Fdevice=5Funref(earlier-=EF=BC=9Eudev);
=EF=BC=9E +  =           FREE(earlier);<= br>=EF=BC=9E +        }
=EF= =BC=9E +    }
=EF=BC=9E +}
=EF=BC=9E&nb= sp;+
=EF=BC=9E +void
=EF=BC=9E +uevent=5Fmerge(struct = uevent *later, struct list=5Fhead *tmpq)
=EF=BC=9E&n= bsp;+{
=EF=BC=9E +    struct uevent *= earlier, *tmp;
=EF=BC=9E +
=EF=BC=9E +  &nbs= p; list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe(earlier, tmp, = &later-=EF=BC=9Enode, tmpq, node) {
=EF=BC=9E +&= nbsp;       if (merge=5Fneed=5Fstop= (earlier, later))
=EF=BC=9E +     &nb= sp;      break;
=EF=BC=9E + &nbs= p;      /*
=EF=BC=9E +  &nb= sp;      * merge earlier ueven= ts to the later uevent
=EF=BC=9E +  &= nbsp;      */
=EF=BC=9E +  =       if (uevent=5Fcan=5Fmerge(earlier,&= nbsp;later)) {
=EF=BC=9E +      =       condlog(2, "merged uevent:&nb= sp;%s-%s-%s with uevent: %s-%s-%s",
=EF=BC=9E + = ;            &n= bsp;  earlier-=EF=BC=9Eaction, earlier-=EF=BC=9Ekernel, = ;earlier-=EF=BC=9Ewwid,
=EF=BC=9E +     &n= bsp;          later-=EF= =BC=9Eaction, later-=EF=BC=9Ekernel, later-=EF=BC=9Ewwid);
=EF= =BC=9E +
=EF=BC=9E +       =      list=5Fmove(&earlier-=EF=BC=9Enode, = &later-=EF=BC=9Emerge=5Fnode);
=EF=BC=9E +   &nb= sp;    }
=EF=BC=9E +    }=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +void
=EF=BC= =9E +merge=5Fuevq(struct list=5Fhead *tmpq)
=EF=BC=9E&nbs= p;+{
=EF=BC=9E +    struct uevent *la= ter;
=EF=BC=9E +
=EF=BC=9E +    uevent= =5Fprepare(tmpq);
=EF=BC=9E +    list=5Ffor=5Fe= ach=5Fentry=5Freverse(later, tmpq, node) {
=EF=BC=9E = ;+        uevent=5Ffilter(later,&nb= sp;tmpq);
=EF=BC=9E +       &nbs= p;if(uevent=5Fneed=5Fmerge())
=EF=BC=9E +    &n= bsp;       uevent=5Fmerge(later, tm= pq);
=EF=BC=9E +    }
=EF=BC=9E +}
= =EF=BC=9E +
=EF=BC=9E +void
=EF=BC=9E +service=5Fuevq(= struct list=5Fhead *tmpq)
=EF=BC=9E  {
=EF=BC=9E&= nbsp;     struct uevent *uev, *tmp;=
=EF=BC=9E  
=EF=BC=9E      l= ist=5Ffor=5Feach=5Fentry=5Fsafe(uev, tmp, tmpq, node) {=
=EF=BC=9E          li= st=5Fdel=5Finit(&uev-=EF=BC=9Enode);
=EF=BC=9E +
=EF=BC=9E&n= bsp;+        if (my=5Fuev=5Ftr= igger && my=5Fuev=5Ftrigger(uev, my=5Ftrigger=5Fdata= ))
=EF=BC=9E +         = ;   condlog(0, "uevent trigger error");
= =EF=BC=9E +
=EF=BC=9E +      &nb= sp; uevq=5Fcleanup(&uev-=EF=BC=9Emerge=5Fnode);
=EF=BC=9E = +
=EF=BC=9E +        if&nbs= p;(uev-=EF=BC=9Eudev)
=EF=BC=9E +     &nbs= p;      udev=5Fdevice=5Funref(uev-=EF=BC=9Eud= ev);
=EF=BC=9E         &nbs= p;FREE(uev);
=EF=BC=9E      }
=EF=BC=9E=   }
=EF=BC=9E  
=EF=BC=9E +static void&= nbsp;uevent=5Fcleanup(void *arg)
=EF=BC=9E +{
=EF=BC=9E&nbs= p;+    struct udev *udev =3D arg;=EF=BC=9E +
=EF=BC=9E +    condlog(3,&nb= sp;"Releasing uevent=5Flisten() resources");
=EF=BC=9E +&= nbsp;   udev=5Funref(udev);
=EF=BC=9E +}
=EF=BC= =9E +
=EF=BC=9E  /*
=EF=BC=9E   * = Service the uevent queue.
=EF=BC=9E   */=EF=BC=9E @@ -142,6 +404,7 @@ int uevent=5F= dispatch(int (*uev=5Ftrigger)(struct uevent *, void&nbs= p;* trigger=5Fdata),
=EF=BC=9E      &= nbsp;   pthread=5Fmutex=5Funlock(uevq=5Flockp);
=EF=BC=9E=           if (!my=5F= uev=5Ftrigger)
=EF=BC=9E        =       break;
=EF=BC=9E +  &= nbsp;     merge=5Fuevq(&uevq=5Ftmp);
=EF=BC= =9E          service=5Fue= vq(&uevq=5Ftmp);
=EF=BC=9E      }
= =EF=BC=9E      condlog(3, "Terminating&n= bsp;uev service queue");
=EF=BC=9E @@ -442,11 += 705,43 @@ struct uevent *uevent=5Ffrom=5Fudev=5Fdevice(= struct udev=5Fdevice *dev)
=EF=BC=9E    &n= bsp; return uev;
=EF=BC=9E  }
=EF=BC=9E &nbs= p;
=EF=BC=9E +bool uevent=5Fburst(struct timeval *st= art=5Ftime, int events)
=EF=BC=9E +{
=EF=BC=9E +&= nbsp;   struct timeval diff=5Ftime, end=5Ftim= e;
=EF=BC=9E +    unsigned long speed= ;
=EF=BC=9E +    unsigned long eclips= e=5Fms;
=EF=BC=9E +
=EF=BC=9E +    if(e= vents =EF=BC=9E MAX=5FACCUMULATION=5FCOUNT) {
=EF=BC=9E&n= bsp;+        condlog(2, "burst=  got %u uevents, too much uevents, stopp= ed", events);
=EF=BC=9E +      &= nbsp; return false;
=EF=BC=9E +    }<= br>=EF=BC=9E +
=EF=BC=9E +    gettimeofday= (&end=5Ftime, NULL);
=EF=BC=9E +    ti= mersub(&end=5Ftime, start=5Ftime, &diff=5Ftime);
=EF= =BC=9E +
=EF=BC=9E +    eclipse=5Fms = =3D diff=5Ftime.tv=5Fsec * 1000 + diff=5Ftime.tv= =5Fusec / 1000;
=EF=BC=9E +
=EF=BC=9E + &nbs= p;  if (eclipse=5Fms =3D=3D 0)
=EF=BC=9E +=         return true;
=EF=BC= =9E +
=EF=BC=9E +    if (eclipse=5Fms=  =EF=BC=9E MAX=5FACCUMULATION=5FTIME) {
=EF=BC=9E +&= nbsp;       condlog(2, "burst = continued %lu ms, too long time, stopped",&nb= sp;eclipse=5Fms);
=EF=BC=9E +      &n= bsp; return false;
=EF=BC=9E +    }=EF=BC=9E +
=EF=BC=9E +    speed = =3D (events * 1000) / eclipse=5Fms;
=EF=BC=9E&n= bsp;+    if (speed =EF=BC=9E MIN=5FBURST= =5FSPEED)
=EF=BC=9E +       &nbs= p;return true;
=EF=BC=9E +
=EF=BC=9E +  &nbs= p; return false;
=EF=BC=9E +}
=EF=BC=9E +
=EF= =BC=9E  int uevent=5Flisten(struct udev *udev)
= =EF=BC=9E  {
=EF=BC=9E      int&= nbsp;err =3D 2;
=EF=BC=9E      s= truct udev=5Fmonitor *monitor =3D NULL;
=EF=BC=9E&nb= sp;     int fd, socket=5Fflags, eve= nts;
=EF=BC=9E +    struct timeval st= art=5Ftime;
=EF=BC=9E      int need= =5Ffailback =3D 1;
=EF=BC=9E     &nbs= p;int timeout =3D 30;
=EF=BC=9E    &n= bsp; LIST=5FHEAD(uevlisten=5Ftmp);
=EF=BC=9E @@ -500,6&nb= sp;+795,7 @@ int uevent=5Flisten(struct udev *udev= )
=EF=BC=9E      }
=EF=BC=9E  = ;
=EF=BC=9E      events =3D 0;=EF=BC=9E +    gettimeofday(&start=5Ftime,&n= bsp;NULL);
=EF=BC=9E      while (1)&n= bsp;{
=EF=BC=9E         &nb= sp;struct uevent *uev;
=EF=BC=9E     =      struct udev=5Fdevice *dev;
=EF= =BC=9E @@ -514,7 +810,7 @@ int uevent=5Fliste= n(struct udev *udev)
=EF=BC=9E     &n= bsp;    errno =3D 0;
=EF=BC=9E  =         fdcount =3D poll(= &ev=5Fpoll, 1, poll=5Ftimeout);
=EF=BC=9E   = ;       if (fdcount &&=  ev=5Fpoll.revents & POLLIN) {
=EF=BC=9E -&= nbsp;           time= out =3D 0;
=EF=BC=9E +      = ;      timeout =3D uevent=5Fburst(&= amp;start=5Ftime, events + 1) ? 1 : 0;=EF=BC=9E          &nbs= p;   dev =3D udev=5Fmonitor=5Freceive=5Fdevice(mon= itor);
=EF=BC=9E         &n= bsp;    if (!dev) {
=EF=BC=9E  &= nbsp;           &nbs= p;   condlog(0, "failed getting udev dev= ice");
=EF=BC=9E @@ -547,6 +843,7 @@ int u= event=5Flisten(struct udev *udev)
=EF=BC=9E   &= nbsp;          pthread=5F= mutex=5Funlock(uevq=5Flockp);
=EF=BC=9E     &nb= sp;        events =3D 0;<= br>=EF=BC=9E          }=EF=BC=9E +        gettimeof= day(&start=5Ftime, NULL);
=EF=BC=9E    &nbs= p;     timeout =3D 30;
=EF=BC=9E = ;     }
=EF=BC=9E     =  need=5Ffailback =3D 0;
=EF=BC=9E diff --git&nb= sp;a/libmultipath/uevent.h b/libmultipath/uevent.h
=EF=BC=9E i= ndex 9d22dcd..61a4207 100644
=EF=BC=9E --- a/libmult= ipath/uevent.h
=EF=BC=9E +++ b/libmultipath/uevent.h
=EF=BC= =9E @@ -17,11 +17,13 @@ struct udev;
=EF= =BC=9E  
=EF=BC=9E  struct uevent {
=EF= =BC=9E      struct list=5Fhead node= ;
=EF=BC=9E +    struct list=5Fhead m= erge=5Fnode;
=EF=BC=9E      struct ud= ev=5Fdevice *udev;
=EF=BC=9E      cha= r buffer[HOTPLUG=5FBUFFER=5FSIZE + OBJECT=5FSIZE];
=EF=BC= =9E      char *devpath;
=EF=BC=9E&nbs= p;     char *action;
=EF=BC=9E  =     char *kernel;
=EF=BC=9E +  &= nbsp; char *wwid;
=EF=BC=9E      = ;unsigned long seqnum;
=EF=BC=9E     =  char *envp[HOTPLUG=5FNUM=5FENVP];
=EF=BC=9E  };
= =EF=BC=9E diff --git a/libmultipath/util.c b/libmultipa= th/util.c
=EF=BC=9E index 03a5738..e5a4a28 100644
=EF= =BC=9E --- a/libmultipath/util.c
=EF=BC=9E +++ b/lib= multipath/util.c
=EF=BC=9E @@ -261,6 +261,46 @@ = ;dev=5Ft parse=5Fdevt(const char *dev=5Ft)
=EF=BC=9E = ;     return makedev(maj, min);
=EF= =BC=9E  }
=EF=BC=9E  
=EF=BC=9E +char *= parse=5Fuid=5Fattribute=5Fby=5Fattrs(char *uid=5Fattrs, char = ;*path=5Fdev)
=EF=BC=9E +{
=EF=BC=9E +   &nb= sp;char *uid=5Fattribute;
=EF=BC=9E +    c= har *uid=5Fattr=5Frecord;
=EF=BC=9E +    c= har *dev;
=EF=BC=9E +    char *attr;<= br>=EF=BC=9E +    char *tmp;
=EF=BC=9E&nbs= p;+    int  count;
=EF=BC=9E +
=EF= =BC=9E +    if(!uid=5Fattrs || !path=5Fd= ev)
=EF=BC=9E +        retu= rn NULL;
=EF=BC=9E +
=EF=BC=9E +   &nbs= p;count =3D get=5Fword(uid=5Fattrs, &uid=5Fattr=5Frecord= );
=EF=BC=9E +    while (uid=5Fattr=5Freco= rd) {
=EF=BC=9E +       &nb= sp;tmp =3D strrchr(uid=5Fattr=5Frecord, ':');
=EF=BC=9E&n= bsp;+        if (!tmp) {<= br>=EF=BC=9E +         &n= bsp;  free(uid=5Fattr=5Frecord);
=EF=BC=9E +  &= nbsp;         if (!count)=
=EF=BC=9E +         &= nbsp;      break;
=EF=BC=9E + &n= bsp;          count = =3D get=5Fword(uid=5Fattrs + count, &uid=5Fattr=5Fr= ecord);
=EF=BC=9E +        =     continue;
=EF=BC=9E +   &nbs= p;    }
=EF=BC=9E +    &nbs= p;   dev =3D uid=5Fattr=5Frecord;
=EF=BC=9E&nbs= p;+        attr =3D tmp&n= bsp;+ 1;
=EF=BC=9E +       =  *tmp =3D '\0';
=EF=BC=9E +
=EF=BC=9E + = ;       if(!strncmp(path=5Fdev, dev= , strlen(dev))) {
=EF=BC=9E +    &nbs= p;       uid=5Fattribute =3D S= TRDUP(attr);
=EF=BC=9E +       &= nbsp;    free(uid=5Fattr=5Frecord);
=EF=BC=9E +=             ret= urn uid=5Fattribute;
=EF=BC=9E +     =    }
=EF=BC=9E +
=EF=BC=9E +  &nbs= p;     free(uid=5Fattr=5Frecord);
=EF=BC=9E&nbs= p;+        if (!count)
=EF= =BC=9E +          &n= bsp; break;
=EF=BC=9E +      &nb= sp; count =3D get=5Fword(uid=5Fattrs + count, = ;&uid=5Fattr=5Frecord);
=EF=BC=9E +    }=EF=BC=9E +    return NULL;
=EF=BC=9E&nbs= p;+}
=EF=BC=9E +
=EF=BC=9E  void
=EF=BC=9E &nb= sp;setup=5Fthread=5Fattr(pthread=5Fattr=5Ft *attr, size=5Ft = stacksize, int detached)
=EF=BC=9E  {
=EF=BC=9E&n= bsp;diff --git a/libmultipath/util.h b/libmultipath/util.h=EF=BC=9E index f3b37ee..793f2b7 100644
=EF=BC=9E = --- a/libmultipath/util.h
=EF=BC=9E +++ b/libmultipath/ut= il.h
=EF=BC=9E @@ -12,6 +12,7 @@ size=5Ft = strlcat(char *dst, const char *src, size=5Ft = size);
=EF=BC=9E  int devt2devname (char *,&nbs= p;int, char *);
=EF=BC=9E  dev=5Ft parse=5Fdevt= (const char *dev=5Ft);
=EF=BC=9E  char *convert= =5Fdev(char *dev, int is=5Fpath=5Fdevice);
=EF=BC=9E = ;+char *parse=5Fuid=5Fattribute=5Fby=5Fattrs(char *uid=5Fattrs,&n= bsp;char *path=5Fdev);
=EF=BC=9E  void setup=5Fthrea= d=5Fattr(pthread=5Fattr=5Ft *attr, size=5Ft stacksize, = int detached);
=EF=BC=9E  
=EF=BC=9E  #defin= e safe=5Fsprintf(var, format, args...)   &nbs= p;\
=EF=BC=9E diff --git a/multipath/multipath.conf.5&nbs= p;b/multipath/multipath.conf.5
=EF=BC=9E index 36589f5..63c63c= 2 100644
=EF=BC=9E --- a/multipath/multipath.conf.5
= =EF=BC=9E +++ b/multipath/multipath.conf.5
=EF=BC=9E @@&n= bsp;-209,6 +209,24 @@ The default is: \fBfail= over\fR
=EF=BC=9E  .
=EF=BC=9E  .
=EF=BC=9E&nb= sp; .TP
=EF=BC=9E +.B uid=5Fattrs
=EF=BC=9E +The&= nbsp;udev attribute providing a unique path i= dentifier for corresponding 
=EF=BC=9E +type of=  path devices. If this field is configur= ed and matched with type
=EF=BC=9E +of dev= ice, it would override any other methods = ;providing for device
=EF=BC=9E +unique identifier&n= bsp;in config file, and it would activate&nbs= p;merging uevents
=EF=BC=9E +according to the i= dentifier to promote effiecncy in processing = uevents.
=EF=BC=9E +Tt has no default value,&nb= sp;if you want to identify path by udev&= nbsp;attribute
=EF=BC=9E +and to activate merging&nb= sp;uevents for SCSI and DAS device, you = can set
=EF=BC=9E +it's value as:
=EF=BC=9E = +.RS
=EF=BC=9E +.TP
=EF=BC=9E +\fBuid=5Fattrs "sd:ID= =5FSERIAL dasd:ID=5FUID"\fR
=EF=BC=9E +.TP
=EF=BC=9E += The default is: \fB=EF=BC=9Cunset=EF=BC=9E\fR
=EF=BC=9E&n= bsp;+.RE
=EF=BC=9E +.
=EF=BC=9E +.
=EF=BC=9E +.TP=EF=BC=9E  .B uid=5Fattribute
=EF=BC=9E  The&= nbsp;udev attribute providing a unique path i= dentifier.
=EF=BC=9E  .RS
=EF=BC=9E diff --git&nb= sp;a/multipathd/cli=5Fhandlers.c b/multipathd/cli=5Fhandlers.c
=EF= =BC=9E index b0eeca6..12f85de 100644
=EF=BC=9E ---&n= bsp;a/multipathd/cli=5Fhandlers.c
=EF=BC=9E +++ b/multipathd/c= li=5Fhandlers.c
=EF=BC=9E @@ -670,7 +670,7 @@ c= li=5Fadd=5Fpath (void * v, char ** reply,&nbs= p;int * len, void * data)
=EF=BC=9E  =         pp-=EF=BC=9Echeckint = =3D conf-=EF=BC=9Echeckint;
=EF=BC=9E     =  }
=EF=BC=9E      put=5Fmultipath=5Fc= onfig(conf);
=EF=BC=9E -    return ev=5Fad= d=5Fpath(pp, vecs);
=EF=BC=9E +    return&= nbsp;ev=5Fadd=5Fpath(pp, vecs, 1);
=EF=BC=9E  blackl= isted:
=EF=BC=9E      *reply =3D = ;strdup("blacklisted\n");
=EF=BC=9E      *= len =3D strlen(*reply) + 1;
=EF=BC=9E @@ -= 692,7 +692,7 @@ cli=5Fdel=5Fpath (void * v,&n= bsp;char ** reply, int * len, void *&nbs= p;data)
=EF=BC=9E         &= nbsp;condlog(0, "%s: path already removed", param)= ;
=EF=BC=9E          r= eturn 1;
=EF=BC=9E      }
=EF=BC= =9E -    return ev=5Fremove=5Fpath(pp, v= ecs);
=EF=BC=9E +    return ev=5Fremove=5F= path(pp, vecs, 1);
=EF=BC=9E  }
=EF=BC=9E &n= bsp;
=EF=BC=9E  int
=EF=BC=9E diff --git a/m= ultipathd/main.c b/multipathd/main.c
=EF=BC=9E index adc3= 258..e513f7d 100644
=EF=BC=9E --- a/multipathd/main.c
= =EF=BC=9E +++ b/multipathd/main.c
=EF=BC=9E @@ -608,= 7 +608,7 @@ ev=5Fremove=5Fmap (char * devname= , char * alias, int minor, struct vector= s * vecs)
=EF=BC=9E  }
=EF=BC=9E  
= =EF=BC=9E  static int
=EF=BC=9E -uev=5Fadd=5Fpath&nb= sp;(struct uevent *uev, struct vectors * vecs= )
=EF=BC=9E +uev=5Fadd=5Fpath (struct uevent *uev,&n= bsp;struct vectors * vecs, int need=5Fdo=5Fmap)=EF=BC=9E  {
=EF=BC=9E      str= uct path *pp;
=EF=BC=9E      int=  ret =3D 0, i;
=EF=BC=9E @@ -641,7 +6= 41,7 @@ uev=5Fadd=5Fpath (struct uevent *uev, = ;struct vectors * vecs)
=EF=BC=9E    =             &nb= sp;      DI=5FALL | DI=5FBLACKLIST)= ;
=EF=BC=9E          &= nbsp;   put=5Fmultipath=5Fconfig(conf);
=EF=BC=9E &n= bsp;            = ;if (r =3D=3D PATHINFO=5FOK)
=EF=BC=9E -  =             &nb= sp; ret =3D ev=5Fadd=5Fpath(pp, vecs);
=EF=BC=9E&nbs= p;+            =     ret =3D ev=5Fadd=5Fpath(pp, vecs,&nb= sp;need=5Fdo=5Fmap);
=EF=BC=9E       =        else if (r =3D=3D&= nbsp;PATHINFO=5FSKIPPED) {
=EF=BC=9E     &= nbsp;           &nbs= p;condlog(3, "%s: remove blacklisted path",
=EF=BC= =9E            =           uev-=EF=BC=9Eke= rnel);
=EF=BC=9E @@ -665,7 +665,7 @@ uev=5Fadd= =5Fpath (struct uevent *uev, struct vectors *=  vecs)
=EF=BC=9E       */
=EF= =BC=9E      conf =3D get=5Fmultipat= h=5Fconfig();
=EF=BC=9E      ret =3D&= nbsp;alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-=EF=BC=9Eudev,
=EF=BC= =9E -           = ;            DI= =5FALL, &pp);
=EF=BC=9E +     &nb= sp;            =      uev-=EF=BC=9Ewwid, DI=5FALL, &p= p);
=EF=BC=9E      put=5Fmultipath=5Fconfi= g(conf);
=EF=BC=9E      if (!pp) = ;{
=EF=BC=9E          = if (ret =3D=3D PATHINFO=5FSKIPPED)
=EF=BC=9E @@ = ;-681,7 +681,7 @@ uev=5Fadd=5Fpath (struct uevent&= nbsp;*uev, struct vectors * vecs)
=EF=BC=9E &nb= sp;        conf =3D get= =5Fmultipath=5Fconfig();
=EF=BC=9E      &n= bsp;   pp-=EF=BC=9Echeckint =3D conf-=EF=BC=9Echec= kint;
=EF=BC=9E         &nb= sp;put=5Fmultipath=5Fconfig(conf);
=EF=BC=9E -   &nb= sp;    ret =3D ev=5Fadd=5Fpath(pp, vecs)= ;
=EF=BC=9E +        ret&nb= sp;=3D ev=5Fadd=5Fpath(pp, vecs, need=5Fdo=5Fmap);
=EF=BC= =9E      } else {
=EF=BC=9E = ;         condlog(0, "%s:=  failed to store path info, "
=EF=BC=9E&nb= sp;            =  "dropping event",
=EF=BC=9E @@ -699,7 +699,7&n= bsp;@@ uev=5Fadd=5Fpath (struct uevent *uev, struc= t vectors * vecs)
=EF=BC=9E   * 1:&nb= sp;error
=EF=BC=9E   */
=EF=BC=9E  int
= =EF=BC=9E -ev=5Fadd=5Fpath (struct path * pp, = ;struct vectors * vecs)
=EF=BC=9E +ev=5Fadd=5Fpath&n= bsp;(struct path * pp, struct vectors * = vecs, int need=5Fdo=5Fmap)
=EF=BC=9E  {
=EF=BC=9E=       struct multipath * mpp;<= br>=EF=BC=9E      char params[PARAMS=5FS= IZE] =3D {0};
=EF=BC=9E @@ -767,6 +767,13 = @@ rescan:
=EF=BC=9E      /* per= sistent reservation check*/
=EF=BC=9E    &= nbsp; mpath=5Fpr=5Fevent=5Fhandle(pp);
=EF=BC=9E  
=EF= =BC=9E +    if (!need=5Fdo=5Fmap)
=EF=BC= =9E +        return 0;=EF=BC=9E +
=EF=BC=9E +    if (!dm= =5Fmap=5Fpresent(mpp-=EF=BC=9Ealias)) {
=EF=BC=9E +  = ;      mpp-=EF=BC=9Eaction =3D ACT= =5FCREATE;
=EF=BC=9E +       &nb= sp;start=5Fwaiter =3D 1;
=EF=BC=9E +   &nb= sp;}
=EF=BC=9E      /*
=EF=BC=9E &= nbsp;     * push the map to&nb= sp;the device-mapper
=EF=BC=9E      &= nbsp;*/
=EF=BC=9E @@ -833,7 +840,7 @@ fail:
= =EF=BC=9E  }
=EF=BC=9E  
=EF=BC=9E  sta= tic int
=EF=BC=9E -uev=5Fremove=5Fpath (struct ueven= t *uev, struct vectors * vecs)
=EF=BC=9E += uev=5Fremove=5Fpath (struct uevent *uev, struct ve= ctors * vecs, int need=5Fdo=5Fmap)
=EF=BC=9E &n= bsp;{
=EF=BC=9E      struct path = ;*pp;
=EF=BC=9E      int ret;
=EF= =BC=9E @@ -844,7 +851,7 @@ uev=5Fremove=5Fpath&nbs= p;(struct uevent *uev, struct vectors * vecs)=
=EF=BC=9E      pthread=5Ftestcancel();=EF=BC=9E      pp =3D find=5Fpath= =5Fby=5Fdev(vecs-=EF=BC=9Epathvec, uev-=EF=BC=9Ekernel);
=EF=BC=9E&= nbsp;     if (pp)
=EF=BC=9E - &n= bsp;      ret =3D ev=5Fremove=5Fpat= h(pp, vecs);
=EF=BC=9E +      &n= bsp; ret =3D ev=5Fremove=5Fpath(pp, vecs, need=5Fd= o=5Fmap);
=EF=BC=9E      lock=5Fcleanup=5F= pop(vecs-=EF=BC=9Elock);
=EF=BC=9E      if=  (!pp) {
=EF=BC=9E       &n= bsp;  /* Not an error; path might h= ave been purged earlier */
=EF=BC=9E @@ -8= 55,7 +862,7 @@ uev=5Fremove=5Fpath (struct uevent&= nbsp;*uev, struct vectors * vecs)
=EF=BC=9E &nb= sp;}
=EF=BC=9E  
=EF=BC=9E  int
=EF=BC=9E = ;-ev=5Fremove=5Fpath (struct path *pp, struct vect= ors * vecs)
=EF=BC=9E +ev=5Fremove=5Fpath (struct&nb= sp;path *pp, struct vectors * vecs, int = need=5Fdo=5Fmap)
=EF=BC=9E  {
=EF=BC=9E   &n= bsp;  struct multipath * mpp;
=EF=BC=9E &n= bsp;    int i, retval =3D 0;
=EF= =BC=9E @@ -918,6 +925,8 @@ ev=5Fremove=5Fpath = ;(struct path *pp, struct vectors * vecs)
= =EF=BC=9E           =    goto out;
=EF=BC=9E     =      }
=EF=BC=9E  
=EF=BC=9E = +        if (!need=5Fdo=5Fmap)=
=EF=BC=9E +         &= nbsp;  goto out;
=EF=BC=9E     &= nbsp;    /*
=EF=BC=9E     &= nbsp;     * reload the map
=EF= =BC=9E           */<= br>=EF=BC=9E @@ -995,7 +1004,7 @@ uev=5Fupdate=5Fp= ath (struct uevent *uev, struct vectors *&nbs= p;vecs)
=EF=BC=9E         &= nbsp;}
=EF=BC=9E  
=EF=BC=9E     &= nbsp;    if (pp-=EF=BC=9Einitialized =3D=3D&n= bsp;INIT=5FREQUESTED=5FUDEV)
=EF=BC=9E -    &nb= sp;       retval =3D uev=5Fadd= =5Fpath(uev, vecs);
=EF=BC=9E +     &= nbsp;      retval =3D uev=5Fadd=5Fp= ath(uev, vecs, 1);
=EF=BC=9E     &nbs= p;    else if (mpp && ro&nb= sp;=EF=BC=9E=3D 0) {
=EF=BC=9E     &n= bsp;        condlog(2, "%s:&nb= sp;update path write=5Fprotect to '%d' (uevent)",&= nbsp;uev-=EF=BC=9Ekernel, ro);
=EF=BC=9E  
=EF=BC=9E&n= bsp;@@ -1016,7 +1025,7 @@ out:
=EF=BC=9E  =             int=  flag =3D DI=5FSYSFS | DI=5FWWID;
=EF=BC=9E&nbs= p; 
=EF=BC=9E         =      conf =3D get=5Fmultipath=5Fconfig()= ;
=EF=BC=9E -         =    retval =3D alloc=5Fpath=5Fwith=5Fpathinfo(conf,=  uev-=EF=BC=9Eudev, flag, NULL);
=EF=BC=9E + &n= bsp;          retval = ;=3D alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-=EF=BC=9Eudev, = ;uev-=EF=BC=9Ewwid, flag, NULL);
=EF=BC=9E   &n= bsp;          put=5Fmulti= path=5Fconfig(conf);
=EF=BC=9E  
=EF=BC=9E   = ;           if = (retval =3D=3D PATHINFO=5FSKIPPED) {
=EF=BC=9E @@&nb= sp;-1077,40 +1086,15 @@ uxsock=5Ftrigger (char *&n= bsp;str, char ** reply, int * len, void&= nbsp;* trigger=5Fdata)
=EF=BC=9E      = ;return r;
=EF=BC=9E  }
=EF=BC=9E  
=EF= =BC=9E -static int
=EF=BC=9E -uev=5Fdiscard(char *&n= bsp;devpath)
=EF=BC=9E -{
=EF=BC=9E -   &nbs= p;char *tmp;
=EF=BC=9E -    char a[11= ], b[11];
=EF=BC=9E -
=EF=BC=9E -   &nb= sp;/*
=EF=BC=9E -     * keep onl= y block devices, discard partitions
=EF=BC=9E -=      */
=EF=BC=9E -    = ;tmp =3D strstr(devpath, "/block/");
=EF=BC=9E -&nbs= p;   if (tmp =3D=3D NULL){
=EF=BC=9E = -        condlog(4, "no /= block/ in '%s'", devpath);
=EF=BC=9E -  &n= bsp;     return 1;
=EF=BC=9E - &= nbsp;  }
=EF=BC=9E -    if (ssca= nf(tmp, "/block/%10s", a) !=3D 1 ||
=EF=BC=9E&n= bsp;-        sscanf(tmp, "/blo= ck/%10[^/]/%10s", a, b) =3D=3D 2) {
=EF=BC=9E&n= bsp;-        condlog(4, "disca= rd event on %s", devpath);
=EF=BC=9E - &nb= sp;      return 1;
=EF=BC=9E -&n= bsp;   }
=EF=BC=9E -    return&n= bsp;0;
=EF=BC=9E -}
=EF=BC=9E -
=EF=BC=9E  int=
=EF=BC=9E  uev=5Ftrigger (struct uevent * = ;uev, void * trigger=5Fdata)
=EF=BC=9E  {
= =EF=BC=9E      int r =3D 0;=EF=BC=9E      struct vectors *&nb= sp;vecs;
=EF=BC=9E -    struct config = ;*conf;
=EF=BC=9E +    struct uevent = *merge=5Fuev, *tmp;
=EF=BC=9E  
=EF=BC=9E  &= nbsp;   vecs =3D (struct vectors *)trigg= er=5Fdata;
=EF=BC=9E  
=EF=BC=9E -   &n= bsp;if (uev=5Fdiscard(uev-=EF=BC=9Edevpath))
=EF=BC=9E - =        return 0;
=EF=BC=9E = -
=EF=BC=9E      pthread=5Fcleanup=5Fpush(= config=5Fcleanup, NULL);
=EF=BC=9E     &nb= sp;pthread=5Fmutex=5Flock(&config=5Flock);
=EF=BC=9E  &nbs= p;   if (running=5Fstate !=3D DAEMON=5FIDLE&n= bsp;&&
=EF=BC=9E @@ -1139,28 +1123,21 @@&nbs= p;uev=5Ftrigger (struct uevent * uev, void *&= nbsp;trigger=5Fdata)
=EF=BC=9E      }
= =EF=BC=9E  
=EF=BC=9E      /*=EF=BC=9E -     * path add/remove&= nbsp;event
=EF=BC=9E +     * path&nbs= p;add/remove/change event, add/remove maybe merged
= =EF=BC=9E       */
=EF=BC=9E -&n= bsp;   conf =3D get=5Fmultipath=5Fconfig();
=EF= =BC=9E -    if (filter=5Fdevnode(conf-=EF=BC= =9Eblist=5Fdevnode, conf-=EF=BC=9Eelist=5Fdevnode,
=EF=BC=9E -=             &nb= sp;  uev-=EF=BC=9Ekernel) =EF=BC=9E 0) {
=EF=BC= =9E -        put=5Fmultipath= =5Fconfig(conf);
=EF=BC=9E -      &nb= sp; goto out;
=EF=BC=9E +    list=5Ff= or=5Feach=5Fentry=5Fsafe(merge=5Fuev, tmp, &uev-=EF=BC=9Emerg= e=5Fnode, node) {
=EF=BC=9E +    &nbs= p;   if (!strncmp(merge=5Fuev-=EF=BC=9Eaction, "ad= d", 3))
=EF=BC=9E +       &= nbsp;    r +=3D uev=5Fadd=5Fpath(merge=5Fuev,=  vecs, 0);
=EF=BC=9E +      = ;  if (!strncmp(merge=5Fuev-=EF=BC=9Eaction, "remove",&= nbsp;6))
=EF=BC=9E +        = ;    r +=3D uev=5Fremove=5Fpath(merge=5Fuev,&= nbsp;vecs, 0);
=EF=BC=9E      }
= =EF=BC=9E -    put=5Fmultipath=5Fconfig(conf);
= =EF=BC=9E  
=EF=BC=9E -    if (!= strncmp(uev-=EF=BC=9Eaction, "add", 3)) {
=EF=BC=9E = -        r =3D uev=5Fadd= =5Fpath(uev, vecs);
=EF=BC=9E -     &= nbsp;  goto out;
=EF=BC=9E -    = }
=EF=BC=9E -    if (!strncmp(uev-=EF=BC= =9Eaction, "remove", 6)) {
=EF=BC=9E -  &n= bsp;     r =3D uev=5Fremove=5Fpath(uev,&= nbsp;vecs);
=EF=BC=9E -       &n= bsp;goto out;
=EF=BC=9E -    }
=EF=BC= =9E -    if (!strncmp(uev-=EF=BC=9Eaction,&nb= sp;"change", 6)) {
=EF=BC=9E -    &nb= sp;   r =3D uev=5Fupdate=5Fpath(uev, vecs);=EF=BC=9E -        goto = ;out;
=EF=BC=9E -    }
=EF=BC=9E + = ;   if (!strncmp(uev-=EF=BC=9Eaction, "add", = 3))
=EF=BC=9E +        r&nb= sp;+=3D uev=5Fadd=5Fpath(uev, vecs, 1);
=EF=BC=9E +&= nbsp;   if (!strncmp(uev-=EF=BC=9Eaction, "remove"= , 6))
=EF=BC=9E +       &nb= sp;r +=3D uev=5Fremove=5Fpath(uev, vecs, 1);
=EF=BC= =9E +    if (!strncmp(uev-=EF=BC=9Eaction,&nb= sp;"change", 6))
=EF=BC=9E +     &nbs= p;  r +=3D uev=5Fupdate=5Fpath(uev, vecs);
=EF= =BC=9E  
=EF=BC=9E  out:
=EF=BC=9E  &nb= sp;   return r;
=EF=BC=9E @@ -1570,7 = +1547,7 @@ check=5Fpath (struct vectors * vec= s, struct path * pp, int ticks)
=EF=BC=9E&= nbsp;           &nbs= p; conf =3D get=5Fmultipath=5Fconfig();
=EF=BC=9E &n= bsp;            = ;ret =3D pathinfo(pp, conf, DI=5FALL | DI=5FB= LACKLIST);
=EF=BC=9E        &nbs= p;     if (ret =3D=3D PATHINFO=5FOK= ) {
=EF=BC=9E -        = ;        ev=5Fadd=5Fpath(pp, v= ecs);
=EF=BC=9E +        &n= bsp;       ev=5Fadd=5Fpath(pp, vecs= , 1);
=EF=BC=9E        &nbs= p;         pp-=EF=BC=9Etick&nb= sp;=3D 1;
=EF=BC=9E        =       } else if (ret =3D= =3D PATHINFO=5FSKIPPED) {
=EF=BC=9E    &nb= sp;            =  put=5Fmultipath=5Fconfig(conf);
=EF=BC=9E @@ -1686,7&nbs= p;+1663,7 @@ check=5Fpath (struct vectors * v= ecs, struct path * pp, int ticks)
=EF=BC= =9E          }
=EF=BC= =9E          if (!di= sable=5Freinstate && reinstate=5Fpath(pp, add=5Facti= ve)) {
=EF=BC=9E        &nb= sp;     condlog(3, "%s: reload map"= , pp-=EF=BC=9Edev);
=EF=BC=9E -     &= nbsp;      ev=5Fadd=5Fpath(pp, vecs);=EF=BC=9E +         &nbs= p;  ev=5Fadd=5Fpath(pp, vecs, 1);
=EF=BC=9E &nb= sp;            = pp-=EF=BC=9Etick =3D 1;
=EF=BC=9E     = ;         return 0;
= =EF=BC=9E          }
= =EF=BC=9E @@ -1709,7 +1686,7 @@ check=5Fpath = (struct vectors * vecs, struct path * pp= , int ticks)
=EF=BC=9E      &nbs= p;       /* Clear IO erro= rs */
=EF=BC=9E        &nbs= p;     if (reinstate=5Fpath(pp, 0)) = ;{
=EF=BC=9E          =         condlog(3, "%s: r= eload map", pp-=EF=BC=9Edev);
=EF=BC=9E -  &nbs= p;            &= nbsp;ev=5Fadd=5Fpath(pp, vecs);
=EF=BC=9E +   &= nbsp;           &nbs= p;ev=5Fadd=5Fpath(pp, vecs, 1);
=EF=BC=9E   &nb= sp;            =   pp-=EF=BC=9Etick =3D 1;
=EF=BC=9E   = ;            &n= bsp;  return 0;
=EF=BC=9E     &n= bsp;        }
=EF=BC=9E dif= f --git a/multipathd/main.h b/multipathd/main.h
=EF=BC=9E=  index f72580d..094b04f 100644
=EF=BC=9E --- a/= multipathd/main.h
=EF=BC=9E +++ b/multipathd/main.h
=EF=BC= =9E @@ -22,8 +22,8 @@ void exit=5Fdaemon(void= );
=EF=BC=9E  const char * daemon=5Fstatus(void= );
=EF=BC=9E  int need=5Fto=5Fdelay=5Freconfig (stru= ct vectors *);
=EF=BC=9E  int reconfigure = (struct vectors *);
=EF=BC=9E -int ev=5Fadd=5Fpath&n= bsp;(struct path *, struct vectors *);
=EF=BC= =9E -int ev=5Fremove=5Fpath (struct path *, s= truct vectors *);
=EF=BC=9E +int ev=5Fadd=5Fpath&nbs= p;(struct path *, struct vectors *, int);
= =EF=BC=9E +int ev=5Fremove=5Fpath (struct path *,&= nbsp;struct vectors *, int);
=EF=BC=9E  int&nbs= p;ev=5Fadd=5Fmap (char *, char *, struct vect= ors *);
=EF=BC=9E  int ev=5Fremove=5Fmap (char&= nbsp;*, char *, int, struct vectors *);
= =EF=BC=9E  void sync=5Fmap=5Fstate (struct multipa= th *);
=EF=BC=9E -- 
=EF=BC=9E 2.8.1.windows.1=EF=BC=9E 

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

<= br>


--=====_003_next=====-- --=====_002_next=====-- --=====_001_next===== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --=====_001_next=====--