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: Mon, 27 Feb 2017 17:18:34 +0800 (CST) Message-ID: <201702271718339941089@zte.com.cn> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====_001_next=====" Return-path: References: 1487228041-1228-1-git-send-email-tang.junhui@zte.com.cn, 20170216162700.GU22981@octiron.msp.redhat.com, CABr-GndcizxvxRkB9Qc+YnrQkR8FqeOXHWBNh0c_TgSH2+3LYQ@mail.gmail.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: christophe.varoqui@opensvc.com Cc: tang.wenjun3@zte.com.cn, zhang.kai16@zte.com.cn, dm-devel@redhat.com, bart.vanassche@sandisk.com, mwilck@suse.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 Hi Christophe, OK, I'll post it later. regards, 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=9Cchristophe.varoqui@opensvc.co= m=EF=BC=9E =E6=94=B6=E4=BB=B6=E4=BA=BA=EF=BC=9A =EF=BC=9Cbmarzins@redhat.com=EF=BC=9E =E6=8A=84=E9=80=81=E4=BA=BA=EF=BC=9A=E5=94=90=E6=96=87=E4=BF=8A10144149=E5= =94=90=E5=86=9B=E8=BE=8910074136=E5=BC=A0=E5=87=AF10072500 =EF=BC=9Cdm-deve= l@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=8827=E6=97=A5 14:22 =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 Hi Junhui, It seems I did not receive the patch version Acked by Ben,Can you rebase an= d post please ? Thanks. On Thu, Feb 16, 2017 at 5:27 PM, Benjamin Marzinski =EF=BC=9Cbmarzins@redha= t.com=EF=BC=9E wrote: On Thu, Feb 16, 2017 at 02:54:01PM +0800, tang.junhui@zte.com.cn wrote: =EF=BC=9E From: "tang.junhui" =EF=BC=9Ctang.junhui@zte.com.cn=EF=BC=9E =20 ACK =20 Thanks for all your work on this. -Ben =20 =EF=BC=9E =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 =EF=BC=9E This patch used to improve processing efficiency for addition an= d deletion =EF=BC=9E of multipath devices. =EF=BC=9E =EF=BC=9E This patch is tested pass by ZTE multipath automatic testing sys= tem. =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 devi= ces =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 It is configured udev attribute which providing a unique path= identifier =EF=BC=9E for corresponding type of path devices. If this field is conf= igured and =EF=BC=9E matched with type of device, it would override any other meth= ods providing =EF=BC=9E for device unique identifier in config file, and it would act= ivate merging =EF=BC=9E uevents according to the identifier to promote effiecncy in p= rocessing =EF=BC=9E uevents. Tt has no default value, so defaultly only uevents f= iltering =EF=BC=9E works, and uevents merging does not works, if users want to i= dentify path =EF=BC=9E by udev attribute and to activate merging uevents for SCSI an= d 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 uev= ents 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 --- =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 | 320 ++++++++++++++++++++++++++++++= +++++++++++++-- =EF=BC=9E libmultipath/uevent.h | 2 + =EF=BC=9E libmultipath/util.c | 42 ++++++ =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, 471 insertions(+), 75 deletions(-) =EF=BC=9E =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 =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 =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 =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=5Fst= r) =EF=BC=9E declare=5Fmp=5Fhandler(selector, set=5Fstr) =EF=BC=9E declare=5Fmp=5Fsnprint(selector, print=5Fstr) =EF=BC=9E =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, = 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=5Fkeyword("multipath=5Fdir", &def=5Fmultipath=5Fdi= r=5Fhandler, &snprint=5Fdef=5Fmultipath=5Fdir) =EF=BC=9E install=5Fkeyword("path=5Fselector", &def=5Fselector=5Fhan= dler, &snprint=5Fdef=5Fselector) =EF=BC=9E install=5Fkeyword("path=5Fgrouping=5Fpolicy", &def=5Fpgpol= icy=5Fhandler, &snprint=5Fdef=5Fpgpolicy) =EF=BC=9E + install=5Fkeyword("uid=5Fattrs", &def=5Fuid=5Fattrs=5Fhand= ler, &snprint=5Fdef=5Fuid=5Fattrs) =EF=BC=9E install=5Fkeyword("uid=5Fattribute", &def=5Fuid=5Fattribut= e=5Fhandler, &snprint=5Fdef=5Fuid=5Fattribute) =EF=BC=9E install=5Fkeyword("getuid=5Fcallout", &def=5Fgetuid=5Fhand= ler, &snprint=5Fdef=5Fgetuid) =EF=BC=9E install=5Fkeyword("prio", &def=5Fprio=5Fname=5Fhandler, &s= nprint=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 =EF=BC=9E int =EF=BC=9E alloc=5Fpath=5Fwith=5Fpathinfo (struct config *conf, struct ude= v=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 =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 da= emon) =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=5Fi= nit(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,= typeof(*n), member)) =EF=BC=9E =EF=BC=9E +/** =EF=BC=9E + * list=5Ffor=5Feach=5Fentry=5Freverse=5Fsafe - iterate backwar= ds 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(*po= s), member), \ =EF=BC=9E + n =3D list=5Fentry(pos-=EF=BC=9Emember.prev, type= of(*pos), 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,= typeof(*n), member)) =EF=BC=9E + =EF=BC=9E +/** =EF=BC=9E + * list=5Ffor=5Fsome=5Fentry=5Fsafe - iterate list from the giv= en 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, memb= er) \ =EF=BC=9E + for (pos =3D list=5Fentry((from)-=EF=BC=9Enext, typeof(*po= s), 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) = \ =EF=BC=9E + pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.next,= typeof(*n), member)) =EF=BC=9E + =EF=BC=9E +/** =EF=BC=9E + * list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe - iterate backwar= ds list from the given begin node to the given end node safe against remova= l 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(*po= s), member), \ =EF=BC=9E + n =3D list=5Fentry(pos-=EF=BC=9Emember.prev, typeof(*= pos), 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,= typeof(*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..c47bd08 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 =EF=BC=9E @@ -339,6 +340,12 @@ int select=5Fgetuid(struct config *conf, st= ruct path *pp) =EF=BC=9E { =EF=BC=9E char *origin =EF=BC=9E =EF=BC=9E + pp-=EF=BC=9Euid=5Fattribute =3D parse=5Fuid=5Fattribute=5F= by=5Fattrs(conf-=EF=BC=9Euid=5Fattrs, pp-=EF=BC=9Edev) =EF=BC=9E + if (pp-=EF=BC=9Euid=5Fattribute) { =EF=BC=9E + origin =3D "(setting: multipath.conf defaults sect= ion)" =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..6e2527b 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 =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 =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 =EF=BC=9E typedef int (uev=5Ftrigger)(struct uevent *, void * trigger=5Fd= ata) =EF=BC=9E =EF=BC=9E @@ -72,48 +82,301 @@ struct uevent * 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 + 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 =EF=BC=9E return uev =EF=BC=9E } =EF=BC=9E =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 =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=5Ftrigger=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 =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 =EF=BC=9E - condlog(3, "Releasing uevent=5Flisten() resources") =EF=BC=9E - udev=5Funref(udev) =EF=BC=9E + conf =3D get=5Fmultipath=5Fconfig() =EF=BC=9E + uid=5Fattribute =3D parse=5Fuid=5Fattribute=5Fby=5Fattrs(c= onf-=EF=BC=9Euid=5Fattrs, 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 + if (!strncmp(uev-=EF=BC=9Eenvp[i], uid=5Fattribute= , strlen(uid=5Fattribute)) && =EF=BC=9E + strlen(uev-=EF=BC=9Eenvp[i]) =EF=BC=9E strlen(= uid=5Fattribute) && =EF=BC=9E + uev-=EF=BC=9Eenvp[i][strlen(uid=5Fattribute)] = =3D=3D '=3D') { =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 + =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) =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=9Edevp= ath) =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=9Edev= path) =EF=BC=9E + return true =EF=BC=9E + } =EF=BC=9E + =EF=BC=9E + /* =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 + /* =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 *la= ter) =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 *late= r) =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 LU= N to AVOID =EF=BC=9E + * "add path1 |remove path1 |add path2 |remove path2 |add = path3" =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 |remo= ve 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 *lat= er) =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 =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,= node) { =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, &= later-=EF=BC=9Enode, tmpq, node) { =EF=BC=9E + /* =EF=BC=9E + * filter unnessary earlier uevents =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, =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, &= later-=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 u= event: %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, later-=EF=BC=9Ewwid) =EF=BC=9E + =EF=BC=9E + list=5Fmove(&earlier-=EF=BC=9Enode, &later= -=EF=BC=9Emerge=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 =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=5Ftrigger=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 =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 +405,7 @@ int uevent=5Fdispatch(int (*uev=5Ftrigger)(s= truct 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 +706,43 @@ struct uevent *uevent=5Ffrom=5Fudev=5Fdevi= ce(struct udev=5Fdevice *dev) =EF=BC=9E return uev =EF=BC=9E } =EF=BC=9E =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= , stopped", 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= .tv=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,= stopped", 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 +796,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, NULL) =EF=BC=9E while (1) { =EF=BC=9E struct uevent *uev =EF=BC=9E struct udev=5Fdevice *dev =EF=BC=9E @@ -514,7 +811,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 de= vice") =EF=BC=9E @@ -547,6 +844,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 =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..e1e83cf 100644 =EF=BC=9E --- a/libmultipath/util.c =EF=BC=9E +++ b/libmultipath/util.c =EF=BC=9E @@ -261,6 +261,48 @@ 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, c= har *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 + uid=5Fattrs +=3D count =EF=BC=9E + count =3D get=5Fword(uid=5Fattrs, &uid=5Fa= ttr=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 + uid=5Fattrs +=3D count =EF=BC=9E + count =3D get=5Fword(uid=5Fattrs, &uid=5Fattr=5Fre= cord) =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 stacks= ize, 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, s= ize=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, c= har *path=5Fdev) =EF=BC=9E void setup=5Fthread=5Fattr(pthread=5Fattr=5Ft *attr, size=5Ft s= tacksize, int detached) =EF=BC=9E =EF=BC=9E #define safe=5Fsprintf(var, format, args...) \ =EF=BC=9E diff --git a/multipath/multipath.conf.5 b/multipath/multipath.co= nf.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 corre= sponding =EF=BC=9E +type of path devices. If this field is configured and matched w= ith type =EF=BC=9E +of device, it would override any other methods providing for de= vice =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 = uevents. =EF=BC=9E +Tt has no default value, if you want to identify path by udev a= ttribute =EF=BC=9E +and to activate merging uevents for SCSI and DAS device, you ca= n 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=5Fhand= lers.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, i= nt * 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, i= nt * 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 =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 * al= ias, int minor, struct vectors * vecs) =EF=BC=9E } =EF=BC=9E =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, in= t 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=5Fmap) =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=9E= udev, =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 n= eed=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 =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 =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, str= uct 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=5Fm= ap) =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 earlie= r */ =EF=BC=9E @@ -855,7 +862,7 @@ uev=5Fremove=5Fpath (struct uevent *uev, str= uct vectors * vecs) =EF=BC=9E } =EF=BC=9E =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 = vectors * vecs) =EF=BC=9E goto out =EF=BC=9E } =EF=BC=9E =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, st= ruct vectors * vecs) =EF=BC=9E } =EF=BC=9E =EF=BC=9E if (pp-=EF=BC=9Einitialized =3D=3D INIT=5FREQUESTE= D=5FUDEV) =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=5Fprotec= t to '%d' (uevent)", uev-=EF=BC=9Ekernel, ro) =EF=BC=9E =EF=BC=9E @@ -1016,7 +1025,7 @@ out: =EF=BC=9E int flag =3D DI=5FSYSFS | DI=5FWWID =EF=BC=9E =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 =EF=BC=9E if (retval =3D=3D PATHINFO=5FSKIPPED) { =EF=BC=9E @@ -1077,40 +1086,15 @@ uxsock=5Ftrigger (char * str, char ** re= ply, int * len, void * trigger=5Fdata) =EF=BC=9E return r =EF=BC=9E } =EF=BC=9E =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 =EF=BC=9E vecs =3D (struct vectors *)trigger=5Fdata =EF=BC=9E =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 =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, ve= cs, 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 - 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 =EF=BC=9E out: =EF=BC=9E return r =EF=BC=9E @@ -1570,7 +1547,7 @@ check=5Fpath (struct vectors * vecs, struc= t 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, struc= t path * pp, int ticks) =EF=BC=9E } =EF=BC=9E if (!disable=5Freinstate && reinstate=5Fpath(pp, a= dd=5Factive)) { =EF=BC=9E condlog(3, "%s: reload map", pp-=EF=BC=9Ed= ev) =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, struc= t 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 -- =EF=BC=9E 2.8.1.windows.1 =EF=BC=9E --=====_003_next===== Content-Type: text/html ; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


Hi Christophe,


O= K, I'll post it later.


regards,

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=9Cchristophe.varoqui@opensvc.c= om=EF=BC=9E;
=E6=94= =B6=E4=BB=B6=E4=BA=BA=EF=BC=9A =EF=BC=9Cbmarzins@redhat.com=EF=BC=9E;<= /div>
=E6=8A=84=E9=80=81=E4=BA= =BA=EF=BC=9A=E5=94=90=E6=96=87=E4=BF=8A10144149;=E5=94=90=E5=86=9B=E8=BE=8910074136= ;=E5= =BC=A0=E5=87=AF10072500; =EF=BC=9Cdm-devel@redhat.com=EF=BC=9E; =EF=BC=9Cbart.vanassc= he@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=8827=E6=97=A5 14:22
=E4=B8=BB =E9=A2=98 =EF=BC=9A= Re: [dm-devel] [PATCH] multipat= h-tools: improve processing efficiency for addition and deletion of multipa= th devices


=
Hi Junhui,

It seems I did no= t receive the patch version Acked by Ben,
Can you rebase and post pleas= e ?

Thanks.

On Thu, Feb 16, 2017 at 5:27 PM, Benjami= n Marzinski =EF=BC=9Cbmarzins@redhat.com=EF=BC=9E wrote:
On Thu, Feb 16, 2017 at 02:= 54:01PM +0800, tang.junhui@zte.com.cn wrote:
=EF=BC=9E From: "tang.junhui" =EF= =BC=9Ctang.ju= nhui@zte.com.cn=EF=BC=9E

ACK

Thanks for all yo= ur work on this.
-Ben

= =EF=BC=9E
=EF=BC=9E Change-Id: I3f81a55fff389f991f915927000b281d7e= 263cc5
=EF=BC=9E Signed-off-by: tang.junhui =EF=BC=9Ctang.junhui@zte.com.cn=EF= =BC=9E
=EF=BC=9E
=EF=BC=9E This patch used to improve processing ef= ficiency for addition and deletion
=EF=BC=9E of multipath devices.
= =EF=BC=9E
=EF=BC=9E This patch is tested pass by ZTE multipath automati= c testing system.
=EF=BC=9E The modification reduces the system consump= tion(such as CPU) and shortens
=EF=BC=9E the processing time obviously = in scene of massive multipath 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=     It is configured udev attribute which providing a unique path= identifier
=EF=BC=9E    for corresponding type of path devic= es. If this field is configured and
=EF=BC=9E    matched with= type of device, it would override any other methods providing
=EF=BC= =9E    for device unique identifier in config file, and it would = activate merging
=EF=BC=9E    uevents according to the identi= fier to promote effiecncy in processing
=EF=BC=9E    uevents.= Tt has no default value, so defaultly only uevents filtering
=EF=BC=9E=     works, and uevents merging does not works, if users want to i= dentify path
=EF=BC=9E    by udev attribute and to activate m= erging uevents for SCSI and DAS device,
=EF=BC=9E    they can= set it's value as:
=EF=BC=9E    "sd:ID=5FSERIAL dasd:ID=5FUI= D"
=EF=BC=9E 2) uevents accumulation in uevents burst scene:
=EF=BC= =9E    wait one seconds for more uevents in uevent=5Flisten() in = uevents burst
=EF=BC=9E    situations
=EF=BC=9E 3) uevent= s preparing, filtering and merging:
=EF=BC=9E    discard unus= e 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 ueven= ts in uev-=EF=BC=9Emerge=5Fnode list without calling
=EF=BC=9E  &n= bsp; domap();
=EF=BC=9E    proccess the last uevents uev with= calling domap().
=EF=BC=9E ---
=EF=BC=9E  libmultipath/config= .c      |   3 +
=EF=BC=9E  libmultipath/c= onfig.h      |   1 +
=EF=BC=9E  libmultip= ath/dict.c        |   3 +
=EF=BC=9E = libmultipath/discovery.c   |   5 +-
=EF=BC=9E = ; libmultipath/discovery.h   |   2 +-
=EF=BC=9E&nbs= p; libmultipath/list.h        |  41 ++++++
=EF= =BC=9E  libmultipath/propsel.c     |   7 + =EF=BC=9E  libmultipath/uevent.c      | 320 +++++++++= ++++++++++++++++++++++++++++++++++--
=EF=BC=9E  libmultipath/= uevent.h      |   2 +
=EF=BC=9E  libmulti= path/util.c        |  42 ++++++
=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  mu= ltipathd/main.c          |  93 +++++--------<= br> =EF=BC=9E  multipathd/main.h          |&n= bsp;  4 +-
=EF=BC=9E  15 files changed, 471 insertions(+), 75= deletions(-)
=EF=BC=9E
=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/conf= ig.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(c= onf-=EF=BC=9Euid=5Fattribute);
=EF=BC=9E
=EF=BC=9E +    &= nbsp;if (conf-=EF=BC=9Euid=5Fattrs)
=EF=BC=9E +      &nb= sp;      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
=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
=EF= =BC=9E       char * multipath=5Fdir;
=EF=BC=9E = ;      char * selector;
=EF=BC=9E +     c= har * uid=5Fattrs;
=EF=BC=9E       char * uid=5Fatt= ribute;
=EF=BC=9E       char * getuid;
=EF=BC= =9E       char * features;
=EF=BC=9E diff --git a/l= ibmultipath/dict.c b/libmultipath/dict.c
=EF=BC=9E index dc21846..0a531= d1 100644
=EF=BC=9E --- a/libmultipath/dict.c
=EF=BC=9E +++ b/libmu= ltipath/dict.c
=EF=BC=9E @@ -249,6 +249,8 @@ declare=5Fovr=5Fsnprint(se= lector, print=5Fstr)
=EF=BC=9E  declare=5Fmp=5Fhandler(selector, s= et=5Fstr)
=EF=BC=9E  declare=5Fmp=5Fsnprint(selector, print=5Fstr)=
=EF=BC=9E
=EF=BC=9E +declare=5Fdef=5Fhandler(uid=5Fattrs, set= =5Fstr)
=EF=BC=9E +declare=5Fdef=5Fsnprint(uid=5Fattrs, print=5Fst= r)
=EF=BC=9E  declare=5Fdef=5Fhandler(uid=5Fattribute, set=5F= str)
=EF=BC=9E  declare=5Fdef=5Fsnprint=5Fdefstr(uid=5Fattrib= ute, print=5Fstr, DEFAULT=5FUID=5FATTRIBUTE)
=EF=BC=9E  declare=5F= ovr=5Fhandler(uid=5Fattribute, set=5Fstr)
=EF=BC=9E @@ -1367,6 +13= 69,7 @@ init=5Fkeywords(vector keywords)
=EF=BC=9E      =  install=5Fkeyword("multipath=5Fdir", &def=5Fmultipath=5Fdir= =5Fhandler, &snprint=5Fdef=5Fmultipath=5Fdir);
=EF=BC=9E  &nbs= p;    install=5Fkeyword("path=5Fselector", &def=5Fselect= or=5Fhandler, &snprint=5Fdef=5Fselector);
=EF=BC=9E    &n= bsp;  install=5Fkeyword("path=5Fgrouping=5Fpolicy", &def=5Fpg= policy=5Fhandler, &snprint=5Fdef=5Fpgpolicy);
=EF=BC=9E +  &nb= sp;  install=5Fkeyword("uid=5Fattrs", &def=5Fuid=5Fattrs=5Fhandler= , &snprint=5Fdef=5Fuid=5Fattrs);
=EF=BC=9E      &nbs= p;install=5Fkeyword("uid=5Fattribute", &def=5Fuid=5Fattribute=5Fha= ndler, &snprint=5Fdef=5Fuid=5Fattribute);
=EF=BC=9E    &n= bsp;  install=5Fkeyword("getuid=5Fcallout", &def=5Fgetuid=5Fh= andler, &snprint=5Fdef=5Fgetuid);
=EF=BC=9E      &nb= sp;install=5Fkeyword("prio", &def=5Fprio=5Fname=5Fhandler, &snprint= =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/d= iscovery.c
=EF=BC=9E @@ -33,7 +33,7 @@
=EF=BC=9E
=EF=BC=9E = ; int
=EF=BC=9E  alloc=5Fpath=5Fwith=5Fpathinfo (struct config *co= nf, struct udev=5Fdevice *udevice,
=EF=BC=9E -      &nbs= p;                int flag, struct = path **pp=5Fptr)
=EF=BC=9E +            &= nbsp;          char *wwid, int flag, struct path *= *pp=5Fptr)
=EF=BC=9E  {
=EF=BC=9E       in= t 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  &n= bsp;    if (!pp)
=EF=BC=9E          =      return PATHINFO=5FFAILED;
=EF=BC=9E
=EF=BC=9E +=      if(wwid)
=EF=BC=9E +        &nb= sp;    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/lib= multipath/discovery.h b/libmultipath/discovery.h
=EF=BC=9E index 303926= 8..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 pat= h * pp, struct config * conf, int daemon);
=EF=BC=9E  int pathinfo= (struct path * pp, struct config * conf, int mask);
=EF=BC=9E  in= t alloc=5Fpath=5Fwith=5Fpathinfo (struct config *conf, struct udev=5Fdevice= *udevice,
=EF=BC=9E -              =              int flag, struct path **pp= =5Fptr);
=EF=BC=9E +              &n= bsp;            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                  &nb= sp;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=5F= init(struct list=5Fhead *list,
=EF=BC=9E        &nb= sp;   &pos-=EF=BC=9Emember !=3D (head);       =                     &nbs= p;       \
=EF=BC=9E          &= nbsp; pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.next, typeof(*n), mem= ber))
=EF=BC=9E
=EF=BC=9E +/**
=EF=BC=9E + * list=5Ffor=5Feach= =5Fentry=5Freverse=5Fsafe - iterate backwards over list of given type = safe against removal of list entry
=EF=BC=9E + * @pos:    &nb= sp;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 struc= t.
=EF=BC=9E + */
=EF=BC=9E +#define list=5Ffor=5Feach=5Fentry=5Fre= verse=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=9E= member.prev, typeof(*pos), member);\
=EF=BC=9E +      &n= bsp;   &pos-=EF=BC=9Emember !=3D (head);       = ;                     &nb= sp;       \
=EF=BC=9E +         = ; pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emember.prev, typeof(*n), member)= )
=EF=BC=9E +
=EF=BC=9E +/**
=EF=BC=9E + * list=5Ffor=5Fsome=5F= entry=5Fsafe - iterate list from the given begin node to the given end node= safe against removal of list entry
=EF=BC=9E + * @pos:    &n= bsp;the type * to use as a loop counter.
=EF=BC=9E + * @n:   =            another type * to use as temporar= y storage
=EF=BC=9E + * @from:    the begin node of the itera= tion.
=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, member)  &nb= sp;           \
=EF=BC=9E +     = ;for (pos =3D list=5Fentry((from)-=EF=BC=9Enext, typeof(*pos), member),&nbs= p;     \
=EF=BC=9E +          n =3D = list=5Fentry(pos-=EF=BC=9Emember.next, typeof(*pos), member);    = \
=EF=BC=9E +          &pos-=EF=BC=9Emembe= r !=3D (to);                  =                     \
= =EF=BC=9E +          pos =3D n, n =3D list=5Fentr= y(n-=EF=BC=9Emember.next, typeof(*n), member))
=EF=BC=9E +
=EF=BC= =9E +/**
=EF=BC=9E + * list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe = - iterate backwards list from the given begin node to the given end node sa= fe against removal of list entry
=EF=BC=9E + * @pos:     = ;the type * to use as a loop counter.
=EF=BC=9E + * @n:    &n= bsp;          another type * to use as temporary s= torage
=EF=BC=9E + * @from:    the begin node of the iteratio= n.
=EF=BC=9E + * @to:              t= he end node of the iteration.
=EF=BC=9E + * @member:  the name of = the list=5Fstruct within the struct.
=EF=BC=9E + */
=EF=BC=9E +#def= ine list=5Ffor=5Fsome=5Fentry=5Freverse=5Fsafe(pos, n, from, to, membe= r)      \
=EF=BC=9E +     for (pos =3D li= st=5Fentry((from)-=EF=BC=9Eprev, typeof(*pos), member),     = \
=EF=BC=9E +          n =3D list=5Fentry(pos= -=EF=BC=9Emember.prev, typeof(*pos), member);    \
=EF=BC=9E = +          &pos-=EF=BC=9Emember !=3D (to);&nbs= p;                     &n= bsp;               \
=EF=BC=9E +&nbs= p;         pos =3D n, n =3D list=5Fentry(n-=EF=BC=9Emem= ber.prev, typeof(*n), member))
=EF=BC=9E +
=EF=BC=9E  #endif /= * =5FLIST=5FH */
=EF=BC=9E diff --git a/libmultipath/propsel.c b/libmul= tipath/propsel.c
=EF=BC=9E index c0bc616..c47bd08 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
=EF=BC=9E @@ -339,6 +340,12 @@ int select=5Fgetuid(struct c= onfig *conf, struct path *pp)
=EF=BC=9E  {
=EF=BC=9E  &nb= sp;    char *origin;
=EF=BC=9E
=EF=BC=9E +    &= nbsp;pp-=EF=BC=9Euid=5Fattribute =3D parse=5Fuid=5Fattribute=5Fby=5Fattrs(<= wbr>conf-=EF=BC=9Euid=5Fattrs, pp-=EF=BC=9Edev);
=EF=BC=9E +  &nbs= p;  if (pp-=EF=BC=9Euid=5Fattribute) {
=EF=BC=9E +    &n= bsp;        origin =3D "(setting: multipath.conf defaul= ts section)";
=EF=BC=9E +            &nbs= p;goto out;
=EF=BC=9E +     }
=EF=BC=9E +
=EF=BC= =9E       pp=5Fset=5Fovr(getuid);
=EF=BC=9E  &= nbsp;    pp=5Fset=5Fovr(uid=5Fattribute);
=EF=BC=9E  &nb= sp;    pp=5Fset=5Fhwe(getuid);
=EF=BC=9E diff --git a/libmult= ipath/uevent.c b/libmultipath/uevent.c
=EF=BC=9E index 7edcce1..6e2527b= 100644
=EF=BC=9E --- a/libmultipath/uevent.c
=EF=BC=9E +++ b/libmu= ltipath/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&nb= sp; #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  #i= nclude =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
=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 MA= X=5FACCUMULATION=5FCOUNT 2048
=EF=BC=9E +#define MAX=5FACCUMULATION=5FT= IME 30*1000
=EF=BC=9E +#define MIN=5FBURST=5FSPEED 10
=EF=BC=9E
= =EF=BC=9E  typedef int (uev=5Ftrigger)(struct uevent *, void * trigge= r=5Fdata);
=EF=BC=9E
=EF=BC=9E @@ -72,48 +82,301 @@ struct uevent *= alloc=5Fuevent (void)
=EF=BC=9E  {
=EF=BC=9E    &nb= sp;  struct uevent *uev =3D MALLOC(sizeof(struct uevent));
=EF=BC= =9E
=EF=BC=9E -     if (uev)
=EF=BC=9E +   = ;  if (uev) {
=EF=BC=9E            &= nbsp;  INIT=5FLIST=5FHEAD(&uev-=EF=BC=9Enode);
=EF=BC=9E +&nbs= p;            INIT=5FLIST=5FHEAD(&uev-=EF= =BC=9Emerge=5Fnode);
=EF=BC=9E +     }
=EF=BC= =9E
=EF=BC=9E       return uev;
=EF=BC=9E = }
=EF=BC=9E
=EF=BC=9E  void
=EF=BC=9E -service=5Fuevq(str= uct list=5Fhead *tmpq)
=EF=BC=9E +uevq=5Fcleanup(struct list=5Fhead *tm= pq)
=EF=BC=9E  {
=EF=BC=9E       struct ue= vent *uev, *tmp;
=EF=BC=9E
=EF=BC=9E       list= =5Ffor=5Feach=5Fentry=5Fsafe(uev, tmp, tmpq, node) {
=EF=BC=9E  &n= bsp;            list=5Fdel=5Finit(&uev-= =EF=BC=9Enode);
=EF=BC=9E
=EF=BC=9E -        &n= bsp;    if (my=5Fuev=5Ftrigger && my=5Fuev=5Ftrigger(uev,= my=5Ftrigger=5Fdata))
=EF=BC=9E -          &n= bsp;          condlog(0, "uevent trigger error");<= br> =EF=BC=9E -
=EF=BC=9E            &nbs= p;  if (uev-=EF=BC=9Eudev)
=EF=BC=9E        &n= bsp;              udev=5Fdevice=5Funref(= uev-=EF=BC=9Eudev);
=EF=BC=9E            =    FREE(uev);
=EF=BC=9E       }
=EF= =BC=9E  }
=EF=BC=9E
=EF=BC=9E -static void uevent=5Fcleanup(vo= id *arg)
=EF=BC=9E +void
=EF=BC=9E +uevent=5Fget=5Fwwid(struct ueve= nt *uev)
=EF=BC=9E  {
=EF=BC=9E -     struct ud= ev *udev =3D arg;
=EF=BC=9E +     int i;
=EF=BC=9E +=      char *uid=5Fattribute;
=EF=BC=9E +    &nb= sp;struct config * conf;
=EF=BC=9E
=EF=BC=9E -     c= ondlog(3, "Releasing uevent=5Flisten() resources");
=EF=BC=9E -  &= nbsp;  udev=5Funref(udev);
=EF=BC=9E +     conf =3D= get=5Fmultipath=5Fconfig();
=EF=BC=9E +     uid=5Fattri= bute =3D parse=5Fuid=5Fattribute=5Fby=5Fattrs(conf-=EF=BC=9Euid=5Fattr= s, uev-=EF=BC=9Ekernel);
=EF=BC=9E +     put=5Fmultipath= =5Fconfig(conf);
=EF=BC=9E +
=EF=BC=9E +     if (!ui= d=5Fattribute)
=EF=BC=9E +            &nb= sp;return;
=EF=BC=9E +
=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=5Fattrib= ute, strlen(uid=5Fattribute)) &&
=EF=BC=9E +     = ;            strlen(uev-=EF=BC=9Eenvp[i]) =EF= =BC=9E strlen(uid=5Fattribute) &&
=EF=BC=9E +    &nbs= p;            uev-=EF=BC=9Eenvp[i][strlen(uid= =5Fattribute)] =3D=3D '=3D') {
=EF=BC=9E +      &nb= sp;              uev-=EF=BC=9Ewwid =3D u= ev-=EF=BC=9Eenvp[i] + strlen(uid=5Fattribute) + 1;
=EF=BC=9E +  &n= bsp;                  break; =EF=BC=9E +             }
=EF=BC= =9E +     }
=EF=BC=9E +     free(uid=5Fat= tribute);
=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +bool
=EF=BC= =9E +uevent=5Fneed=5Fmerge(void)
=EF=BC=9E +{
=EF=BC=9E +  &nb= sp;  struct config * conf;
=EF=BC=9E +     bool nee= d=5Fmerge =3D false;
=EF=BC=9E +
=EF=BC=9E +     con= f =3D get=5Fmultipath=5Fconfig();
=EF=BC=9E +     if (co= nf-=EF=BC=9Euid=5Fattrs)
=EF=BC=9E +          =    need=5Fmerge =3D true;
=EF=BC=9E +     put= =5Fmultipath=5Fconfig(conf);
=EF=BC=9E +
=EF=BC=9E +    &= nbsp;return need=5Fmerge;
=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +b= ool
=EF=BC=9E +uevent=5Fcan=5Fdiscard(struct uevent *uev)
=EF=BC=9E= +{
=EF=BC=9E +     char *tmp;
=EF=BC=9E +  &nb= sp;  char a[11], b[11];
=EF=BC=9E +     struct conf= ig * 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 +    &= nbsp;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 (ss= canf(tmp, "/block/%10s", a) !=3D 1 ||
=EF=BC=9E +      &= nbsp;  sscanf(tmp, "/block/%10[^/]/%10s", a, b) =3D=3D 2) {
=EF=BC= =9E +             condlog(4, "discard ev= ent on %s", uev-=EF=BC=9Edevpath);
=EF=BC=9E +      &nbs= p;      return true;
=EF=BC=9E +     } =EF=BC=9E +
=EF=BC=9E +     /*
=EF=BC=9E +  &= nbsp;   * do not filter dm devices by devnode
=EF=BC=9E +  &n= bsp;   */
=EF=BC=9E +     if (!strncmp(uev-=EF=BC= =9Ekernel, "dm-", 3))
=EF=BC=9E +          &nb= sp;  return false;
=EF=BC=9E +     /*
=EF=BC=9E= +      * filter paths devices by devnode
=EF=BC=9E +&nb= sp;     */
=EF=BC=9E +     conf =3D get=5Fmult= ipath=5Fconfig();
=EF=BC=9E +     if (filter=5Fdevnode(c= onf-=EF=BC=9Eblist=5Fdevnode, conf-=EF=BC=9Eelist=5Fdevnode,
=EF= =BC=9E +                  &nbs= p;     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 +    &= nbsp;return false;
=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +bool
= =EF=BC=9E +uevent=5Fcan=5Ffilter(struct uevent *earlier, struct uevent *la= ter)
=EF=BC=9E +{
=EF=BC=9E +
=EF=BC=9E +     /*=
=EF=BC=9E +      * filter earlier uvents if path has re= moved later. Eg:
=EF=BC=9E +      * "add path1 |chang pa= th1 |add path2 |remove path1"
=EF=BC=9E +      * can fil= ter as:
=EF=BC=9E +      * "add path2 |remove path1"
= =EF=BC=9E +      * uevents "add path1" and "chang path1" ar= e filtered out
=EF=BC=9E +      */
=EF=BC=9E + =    if (!strcmp(earlier-=EF=BC=9Ekernel, later-=EF=BC=9Ekernel) &= amp;&
=EF=BC=9E +             !s= trcmp(later-=EF=BC=9Eaction, "remove") &&
=EF=BC=9E +  &nb= sp;          strncmp(later-=EF=BC=9Ekernel, "dm-",= 3)) {
=EF=BC=9E +             retur= n true;
=EF=BC=9E +     }
=EF=BC=9E +
=EF=BC=9E = +     /*
=EF=BC=9E +      * filter change= uvents if add uevents exist. Eg:
=EF=BC=9E +      * "ch= ange 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 +      &nbs= p;      !strcmp(later-=EF=BC=9Eaction, "add") &&
= =EF=BC=9E +             strncmp(later-= =EF=BC=9Ekernel, "dm-", 3)) {
=EF=BC=9E +        &n= bsp;    return true;
=EF=BC=9E +     }
=EF= =BC=9E +
=EF=BC=9E +     return false;
=EF=BC=9E +}<= br> =EF=BC=9E +
=EF=BC=9E +bool
=EF=BC=9E +merge=5Fneed=5Fstop(stru= ct uevent *earlier, struct uevent *later)
=EF=BC=9E +{
=EF=BC=9E +&= nbsp;    /*
=EF=BC=9E +      * dm uevent do no= t try to merge with left uevents
=EF=BC=9E +      */
= =EF=BC=9E +     if (!strncmp(later-=EF=BC=9Ekernel, "dm-", = 3))
=EF=BC=9E +             return t= rue;
=EF=BC=9E +
=EF=BC=9E +     /*
=EF=BC=9E +&= nbsp;     * 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 path3"
=EF=BC=9E +    &n= bsp; * 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 path= 1, path2, path3"
=EF=BC=9E +      * SO
=EF=BC=9E +&n= bsp;     * when we meet a non-change uevent from the same LUN
= =EF=BC=9E +      * with the same wwid and different action<= br> =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, late= r-=EF=BC=9Eaction) &&
=EF=BC=9E +        &n= bsp;strcmp(earlier-=EF=BC=9Eaction, "change") &&
=EF=BC=9E +&nb= sp;        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=5Fme= rge(struct uevent *earlier, struct uevent *later)
=EF=BC=9E +{
=EF= =BC=9E +     /* merge paths uevents
=EF=BC=9E +  &n= bsp;   * whose wwids exsit and are same
=EF=BC=9E +    &= nbsp; * and actions are same,
=EF=BC=9E +      * and act= ions 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 +        &nbs= p;strncmp(earlier-=EF=BC=9Eaction, "change", 6) &&
=EF=BC=9E +&= nbsp;        strncmp(earlier-=EF=BC=9Ekernel, "dm-", 3)= ) {
=EF=BC=9E +             return t= rue;
=EF=BC=9E +     }
=EF=BC=9E +
=EF=BC=9E +&n= bsp;    return false;
=EF=BC=9E  }
=EF=BC=9E
=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=5F<= wbr>safe(uev, tmp, tmpq, node) {
=EF=BC=9E +       =      if (uevent=5Fcan=5Fdiscard(uev)) {
=EF=BC=9E +&nbs= p;                    lis= t=5Fdel=5Finit(&uev-=EF=BC=9Enode);
=EF=BC=9E +     =                if (uev-=EF=BC=9Eud= ev)
=EF=BC=9E +                =              udev=5Fdevice=5Funref(uev-= =EF=BC=9Eudev);
=EF=BC=9E +            &n= bsp;        FREE(uev);
=EF=BC=9E +    &nb= sp;                continue;
= =EF=BC=9E +             }
=EF=BC=9E = +
=EF=BC=9E +             if (strncm= p(uev-=EF=BC=9Ekernel, "dm-", 3) &&
=EF=BC=9E +    &n= bsp;            uevent=5Fneed=5Fmerge())
= =EF=BC=9E +                  &= nbsp;  uevent=5Fget=5Fwwid(uev);
=EF=BC=9E +     }<= br> =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 +{<= br> =EF=BC=9E +     struct uevent *earlier, *tmp;
=EF=BC= =9E +
=EF=BC=9E +     list=5Ffor=5Fsome=5Fentry=5Frevers= e=5Fsafe(earlier, tmp, &later-=EF=BC=9Enode, tmpq, node) {
=EF= =BC=9E +             /*
=EF=BC=9E +&= nbsp;             * filter unnessary earlier = uevents
=EF=BC=9E +              * b= y the later uevent
=EF=BC=9E +           =   */
=EF=BC=9E +             i= f (uevent=5Fcan=5Ffilter(earlier, later)) {
=EF=BC=9E +    &n= bsp;                condlog(2, "uev= ent: %s-%s has filtered by uevent: %s-%s",
=EF=BC=9E +    &nb= sp;                     &= nbsp;  earlier-=EF=BC=9Ekernel, earlier-=EF=BC=9Eaction,
=EF=BC=9E= +                    &nb= sp;        later-=EF=BC=9Ekernel, later-=EF=BC=9Eaction= );
=EF=BC=9E +
=EF=BC=9E +           =          list=5Fdel=5Finit(&earlier-=EF=BC=9E= node);
=EF=BC=9E +              &nbs= p;      if (earlier-=EF=BC=9Eudev)
=EF=BC=9E +  &nb= sp;                     &= nbsp;    udev=5Fdevice=5Funref(earlier-=EF=BC=9Eudev);
= =EF=BC=9E +                  &= nbsp;  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 +  &= nbsp;  struct uevent *earlier, *tmp;
=EF=BC=9E +
=EF=BC=9E +&n= bsp;    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 +                 = ;    break;
=EF=BC=9E +          &nb= sp;  /*
=EF=BC=9E +             = ; * merge earlier uevents to the later uevent
=EF=BC=9E +    =           */
=EF=BC=9E +      &= nbsp;      if (uevent=5Fcan=5Fmerge(earlier, later)) {
= =EF=BC=9E +                  &= nbsp;  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 +     =                     &nbs= p;  later-=EF=BC=9Eaction, later-=EF=BC=9Ekernel, later-=EF=BC=9Ewwid)= ;
=EF=BC=9E +
=EF=BC=9E +            =          list=5Fmove(&earlier-=EF=BC=9Enode, &= amp;later-=EF=BC=9Emerge=5Fnode);
=EF=BC=9E +       = ;      }
=EF=BC=9E +     }
=EF=BC=9E = +}
=EF=BC=9E +
=EF=BC=9E +void
=EF=BC=9E +merge=5Fuevq(struct l= ist=5Fhead *tmpq)
=EF=BC=9E +{
=EF=BC=9E +     struc= t uevent *later;
=EF=BC=9E +
=EF=BC=9E +     uevent= =5Fprepare(tmpq);
=EF=BC=9E +     list=5Ffor=5Feach=5Fen= try=5Freverse(later, tmpq, node) {
=EF=BC=9E +     =        uevent=5Ffilter(later, tmpq);
=EF=BC=9E +&n= bsp;            if(uevent=5Fneed=5Fmerge()) =EF=BC=9E +                 = ;    uevent=5Fmerge(later, tmpq);
=EF=BC=9E +    &n= bsp;}
=EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E +void
=EF=BC=9E +s= ervice=5Fuevq(struct list=5Fhead *tmpq)
=EF=BC=9E  {
=EF=BC=9E=        struct uevent *uev, *tmp;
=EF=BC=9E
=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=5Ftrig= ger && my=5Fuev=5Ftrigger(uev, my=5Ftrigger=5Fdata))
=EF=BC=9E = +                    &nbs= p;condlog(0, "uevent trigger error");
=EF=BC=9E +
=EF=BC=9E + =            uevq=5Fcleanup(&uev-=EF=BC=9E= merge=5Fnode);
=EF=BC=9E +
=EF=BC=9E +      &nb= sp;      if (uev-=EF=BC=9Eudev)
=EF=BC=9E +   =                  udev=5Fdevic= e=5Funref(uev-=EF=BC=9Eudev);
=EF=BC=9E        &nbs= p;      FREE(uev);
=EF=BC=9E       }=
=EF=BC=9E  }
=EF=BC=9E
=EF=BC=9E +static void uevent=5Fcl= eanup(void *arg)
=EF=BC=9E +{
=EF=BC=9E +     struct= udev *udev =3D arg;
=EF=BC=9E +
=EF=BC=9E +     con= dlog(3, "Releasing uevent=5Flisten() resources");
=EF=BC=9E +  &nb= sp;  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 +405,7 @@ int uevent=5Fdispat= ch(int (*uev=5Ftrigger)(struct uevent *, void * trigger=5Fdata),
=EF=BC= =9E               pthread=5Fmutex= =5Funlock(uevq=5Flockp);
=EF=BC=9E        &nbs= p;      if (!my=5Fuev=5Ftrigger)
=EF=BC=9E    =                    break;=
=EF=BC=9E +             merge=5Fuev= q(&uevq=5Ftmp);
=EF=BC=9E            =    service=5Fuevq(&uevq=5Ftmp);
=EF=BC=9E    &n= bsp;  }
=EF=BC=9E       condlog(3, "Terminatin= g uev service queue");
=EF=BC=9E @@ -442,11 +706,43 @@ struct uevent *u= event=5Ffrom=5Fudev=5Fdevice(struct udev=5Fdevice *dev)
=EF=BC=9E&= nbsp;      return uev;
=EF=BC=9E  }
=EF=BC=9E =EF=BC=9E +bool uevent=5Fburst(struct timeval *start=5Ftime, int events)=
=EF=BC=9E +{
=EF=BC=9E +     struct timeval diff=5F= time, 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=5FACCUMULATIO= N=5FCOUNT) {
=EF=BC=9E +             = ;condlog(2, "burst got %u uevents, too much uevents, stopped", events);
= =EF=BC=9E +             return false; =EF=BC=9E +     }
=EF=BC=9E +
=EF=BC=9E +  &= nbsp;  gettimeofday(&end=5Ftime, NULL);
=EF=BC=9E +  &nbs= p;  timersub(&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= +     if (eclipse=5Fms =3D=3D 0)
=EF=BC=9E +  &nbs= p;          return true;
=EF=BC=9E +
=EF= =BC=9E +     if (eclipse=5Fms =EF=BC=9E MAX=5FACCUMULATION= =5FTIME) {
=EF=BC=9E +             c= ondlog(2, "burst continued %lu ms, too long time, stopped", eclipse=5Fms);<= br> =EF=BC=9E +             return false= ;
=EF=BC=9E +     }
=EF=BC=9E +
=EF=BC=9E + = ;    speed =3D (events * 1000) / eclipse=5Fms;
=EF=BC=9E +&nb= sp;    if (speed =EF=BC=9E MIN=5FBURST=5FSPEED)
=EF=BC=9E +&n= bsp;            return true;
=EF=BC=9E +<= br> =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 +796,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, NULL);
= =EF=BC=9E       while (1) {
=EF=BC=9E    =            struct uevent *uev;
=EF=BC=9E&= nbsp;              struct udev=5Fdevice = *dev;
=EF=BC=9E @@ -514,7 +811,7 @@ int uevent=5Flisten(struct udev *ud= ev)
=EF=BC=9E               err= no =3D 0;
=EF=BC=9E              &nb= sp;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                  &= nbsp;    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 += 844,7 @@ int uevent=5Flisten(struct udev *udev)
=EF=BC=9E    =                    pthrea= d=5Fmutex=5Funlock(uevq=5Flockp);
=EF=BC=9E      &n= bsp;                events =3D 0; =EF=BC=9E               }
= =EF=BC=9E +             gettimeofday(&am= p;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 a/libmultipath/uevent.h b/libmultipath/uevent.h
=EF=BC=9E i= ndex 9d22dcd..61a4207 100644
=EF=BC=9E --- a/libmultipath/uevent.h
= =EF=BC=9E +++ b/libmultipath/uevent.h
=EF=BC=9E @@ -17,11 +17,13 @@ str= uct udev;
=EF=BC=9E
=EF=BC=9E  struct uevent {
=EF=BC=9E&n= bsp;      struct list=5Fhead node;
=EF=BC=9E +  &nb= sp;  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      &= nbsp;unsigned long seqnum;
=EF=BC=9E       char *en= vp[HOTPLUG=5FNUM=5FENVP];
=EF=BC=9E  };
=EF=BC=9E diff --git a= /libmultipath/util.c b/libmultipath/util.c
=EF=BC=9E index 03a5738..e1e= 83cf 100644
=EF=BC=9E --- a/libmultipath/util.c
=EF=BC=9E +++ b/lib= multipath/util.c
=EF=BC=9E @@ -261,6 +261,48 @@ dev=5Ft parse=5Fdevt(co= nst char *dev=5Ft)
=EF=BC=9E       return makedev(m= aj, min);
=EF=BC=9E  }
=EF=BC=9E
=EF=BC=9E +char *parse=5F= uid=5Fattribute=5Fby=5Fattrs(char *uid=5Fattrs, char *path=5Fdev)
= =EF=BC=9E +{
=EF=BC=9E +     char *uid=5Fattribute;
= =EF=BC=9E +     char *uid=5Fattr=5Frecord;
=EF=BC=9E +&n= bsp;    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 +  &nbs= p;  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 +            &= nbsp;if (!tmp) {
=EF=BC=9E +            &= nbsp;        free(uid=5Fattr=5Frecord);
=EF=BC=9E +=                      = ;if (!count)
=EF=BC=9E +             = ;                break;
=EF=BC= =9E +                    =  uid=5Fattrs +=3D count;
=EF=BC=9E +        &n= bsp;            count =3D get=5Fword(uid=5Fat= trs, &uid=5Fattr=5Frecord);
=EF=BC=9E +        =              continue;
=EF=BC=9E +&n= bsp;            }
=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 +            &nb= sp;if(!strncmp(path=5Fdev, dev, strlen(dev))) {
=EF=BC=9E +   = ;                  uid=5Fattri= bute =3D STRDUP(attr);
=EF=BC=9E +          &n= bsp;          free(uid=5Fattr=5Frecord);
=EF= =BC=9E +                  &nbs= p;  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 +             uid=5Fattr= s +=3D count;
=EF=BC=9E +            &nbs= p;count =3D get=5Fword(uid=5Fattrs, &uid=5Fattr=5Frecord);
=EF=BC= =9E +     }
=EF=BC=9E +     return NULL;<= br> =EF=BC=9E +}
=EF=BC=9E +
=EF=BC=9E  void
=EF=BC=9E&nbs= p; setup=5Fthread=5Fattr(pthread=5Fattr=5Ft *attr, size=5Ft stacksize,= int detached)
=EF=BC=9E  {
=EF=BC=9E diff --git a/libmultipat= h/util.h b/libmultipath/util.h
=EF=BC=9E index f3b37ee..793f2b7 100644<= br> =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 *, int, c= har *);
=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=5Fatt= rs, char *path=5Fdev);
=EF=BC=9E  void setup=5Fthread=5Fattr(pthre= ad=5Fattr=5Ft *attr, size=5Ft stacksize, int detached);
=EF=BC=9E<= br> =EF=BC=9E  #define safe=5Fsprintf(var, format, args...)  &nbs= p;\
=EF=BC=9E diff --git a/multipath/multipath.conf.5 b/multipath/multi= path.conf.5
=EF=BC=9E index 36589f5..63c63c2 100644
=EF=BC=9E --- a= /multipath/multipath.conf.5
=EF=BC=9E +++ b/multipath/multipath.conf.5<= br> =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 i= dentifier for corresponding
=EF=BC=9E +type of path devices. If this fi= eld is configured and matched with type
=EF=BC=9E +of device, it would = override any other methods providing for device
=EF=BC=9E +unique ident= ifier in config file, and it would activate merging uevents
=EF=BC=9E += according to the identifier to promote effiecncy in processing uevents.
= =EF=BC=9E +Tt has no default value, if you want to identify path by udev a= ttribute
=EF=BC=9E +and to activate merging uevents for SCSI and DAS de= vice, 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 att= ribute providing a unique path identifier.
=EF=BC=9E  .RS
=EF= =BC=9E diff --git a/multipathd/cli=5Fhandlers.c b/multipathd/cli=5Fhandlers= .c
=EF=BC=9E index b0eeca6..12f85de 100644
=EF=BC=9E --- a/multipat= hd/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, int *= len, void * data)
=EF=BC=9E            &= nbsp;  pp-=EF=BC=9Echeckint =3D conf-=EF=BC=9Echeckint;
=EF=BC=9E&= nbsp;      }
=EF=BC=9E       put=5Fm= ultipath=5Fconfig(conf);
=EF=BC=9E -     return ev=5Fadd= =5Fpath(pp, vecs);
=EF=BC=9E +     return ev=5Fadd=5Fpat= h(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, int * len, void * data)
= =EF=BC=9E               condlog(0, = "%s: path already removed", param);
=EF=BC=9E       = ;        return 1;
=EF=BC=9E      &n= bsp;}
=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
=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=5Fma= p (char * devname, char * alias, int minor, struct vectors * vecs)
=EF= =BC=9E  }
=EF=BC=9E
=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       struc= t 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            &nbs= p;                     &n= bsp; DI=5FALL | DI=5FBLACKLIST);
=EF=BC=9E        &= nbsp;              put=5Fmultipath=5Fcon= fig(conf);
=EF=BC=9E              &n= bsp;        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=5F= do=5Fmap);
=EF=BC=9E              &n= bsp;        else if (r =3D=3D PATHINFO=5FSKIPPED) {
= =EF=BC=9E                  &n= bsp;            condlog(3, "%s: remove blackl= isted 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&nbs= p;       */
=EF=BC=9E       conf =3D= get=5Fmultipath=5Fconfig();
=EF=BC=9E       ret = =3D alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-=EF=BC=9Eudev,
=EF=BC=9E -=                      = ;               DI=5FALL, &pp);
= =EF=BC=9E +                  &= nbsp;                 uev-=EF=BC=9E= wwid, DI=5FALL, &pp);
=EF=BC=9E       put=5Fmul= tipath=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=5Fpa= th (struct uevent *uev, struct vectors * vecs)
=EF=BC=9E    &= nbsp;          conf =3D get=5Fmultipath=5Fconfig()= ;
=EF=BC=9E               pp-= =EF=BC=9Echeckint =3D conf-=EF=BC=9Echeckint;
=EF=BC=9E    &n= bsp;          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&nb= sp;      } else {
=EF=BC=9E        &= nbsp;      condlog(0, "%s: failed to store path info, "
= =EF=BC=9E                  &nb= sp;    "dropping event",
=EF=BC=9E @@ -699,7 +699,7 @@ uev=5F= add=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      &nbs= p;struct multipath * mpp;
=EF=BC=9E       char para= ms[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
=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 +            &n= bsp;mpp-=EF=BC=9Eaction =3D ACT=5FCREATE;
=EF=BC=9E +    &nbs= p;        start=5Fwaiter =3D 1;
=EF=BC=9E +  &= nbsp;  }
=EF=BC=9E       /*
=EF=BC=9E = ;       * push the map to the device-mapper
=EF=BC=9E&nb= sp;       */
=EF=BC=9E @@ -833,7 +840,7 @@ fail:
=EF= =BC=9E  }
=EF=BC=9E
=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 ne= ed=5Fdo=5Fmap)
=EF=BC=9E  {
=EF=BC=9E      &nbs= p;struct path *pp;
=EF=BC=9E       int ret;
=EF= =BC=9E @@ -844,7 +851,7 @@ uev=5Fremove=5Fpath (struct uevent *uev, struct = vectors * vecs)
=EF=BC=9E       pthread=5Ftestcance= l();
=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 -          &n= bsp;  ret =3D ev=5Fremove=5Fpath(pp, vecs);
=EF=BC=9E +  &nbs= p;          ret =3D ev=5Fremove=5Fpath(pp, vecs, n= eed=5Fdo=5Fmap);
=EF=BC=9E       lock=5Fcleanup=5Fp= op(vecs-=EF=BC=9Elock);
=EF=BC=9E       if (!pp) {<= br> =EF=BC=9E               /* Not = an error; path might have been purged earlier */
=EF=BC=9E @@ -855,7 +8= 62,7 @@ uev=5Fremove=5Fpath (struct uevent *uev, struct vectors * vecs)
= =EF=BC=9E  }
=EF=BC=9E
=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=5Fm= ap)
=EF=BC=9E  {
=EF=BC=9E       struct mu= ltipath * mpp;
=EF=BC=9E       int i, retval =3D 0;=
=EF=BC=9E @@ -918,6 +925,8 @@ ev=5Fremove=5Fpath (struct path *pp, str= uct vectors * vecs)
=EF=BC=9E            =            goto out;
=EF=BC=9E  &nbs= p;            }
=EF=BC=9E
=EF=BC=9E +=              if (!need=5Fdo=5Fmap)
= =EF=BC=9E +                  &= nbsp;  goto out;
=EF=BC=9E           = ;    /*
=EF=BC=9E            &n= bsp;   * reload the map
=EF=BC=9E         = ;       */
=EF=BC=9E @@ -995,7 +1004,7 @@ uev=5Fupdate= =5Fpath (struct uevent *uev, struct vectors * vecs)
=EF=BC=9E  &nb= sp;            }
=EF=BC=9E
=EF=BC=9E&= nbsp;              if (pp-=EF=BC=9Einiti= alized =3D=3D INIT=5FREQUESTED=5FUDEV)
=EF=BC=9E -      =                retval =3D uev=5Fadd= =5Fpath(uev, vecs);
=EF=BC=9E +           = ;          retval =3D uev=5Fadd=5Fpath(uev, vecs, = 1);
=EF=BC=9E               els= e 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
=EF=BC=9E @@ -1016,7 +1025,7 @@ out:
=EF=BC=9E = ;                     &nb= sp;int flag =3D DI=5FSYSFS | DI=5FWWID;
=EF=BC=9E
=EF=BC=9E  &= nbsp;                    = conf =3D get=5Fmultipath=5Fconfig();
=EF=BC=9E -      &n= bsp;              retval =3D alloc=5Fpat= h=5Fwith=5Fpathinfo(conf, uev-=EF=BC=9Eudev, flag, NULL);
=EF=BC=9E +&n= bsp;                    r= etval =3D alloc=5Fpath=5Fwith=5Fpathinfo(conf, uev-=EF=BC=9Eudev, uev-=EF= =BC=9Ewwid, flag, NULL);
=EF=BC=9E          &n= bsp;            put=5Fmultipath=5Fconfig(conf= );
=EF=BC=9E
=EF=BC=9E            &nb= sp;          if (retval =3D=3D PATHINFO=5FSKIPPED)= {
=EF=BC=9E @@ -1077,40 +1086,15 @@ uxsock=5Ftrigger (char * str, char= ** reply, int * len, void * trigger=5Fdata)
=EF=BC=9E    &nb= sp;  return r;
=EF=BC=9E  }
=EF=BC=9E
=EF=BC=9E -stat= ic int
=EF=BC=9E -uev=5Fdiscard(char * devpath)
=EF=BC=9E -{
= =EF=BC=9E -     char *tmp;
=EF=BC=9E -    &nbs= p;char a[11], b[11];
=EF=BC=9E -
=EF=BC=9E -     /*<= br> =EF=BC=9E -      * keep only block devices, discard part= itions
=EF=BC=9E -      */
=EF=BC=9E -    =  tmp =3D strstr(devpath, "/block/");
=EF=BC=9E -    &nbs= p;if (tmp =3D=3D NULL){
=EF=BC=9E -          &= nbsp;  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 -     re= turn 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 -&= nbsp;    struct config *conf;
=EF=BC=9E +     = struct uevent *merge=5Fuev, *tmp;
=EF=BC=9E
=EF=BC=9E    =    vecs =3D (struct vectors *)trigger=5Fdata;
=EF=BC=9E
= =EF=BC=9E -     if (uev=5Fdiscard(uev-=EF=BC=9Edevpath))
= =EF=BC=9E -             return 0;
= =EF=BC=9E -
=EF=BC=9E       pthread=5Fcleanup=5Fpus= h(config=5Fcleanup, NULL);
=EF=BC=9E       pth= read=5Fmutex=5Flock(&config=5Flock);
=EF=BC=9E    &n= bsp;  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
=EF=BC= =9E       /*
=EF=BC=9E -      * path= add/remove event
=EF=BC=9E +      * path add/remove/cha= nge 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=9Eblis= t=5Fdevnode, conf-=EF=BC=9Eelist=5Fdevnode,
=EF=BC=9E -  &nbs= p;                     ue= v-=EF=BC=9Ekernel) =EF=BC=9E 0) {
=EF=BC=9E -       = ;      put=5Fmultipath=5Fconfig(conf);
=EF=BC=9E - =            goto out;
=EF=BC=9E +  &= nbsp;  list=5Ffor=5Feach=5Fentry=5Fsafe(merge=5Fuev, tmp, &ue= v-=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 +        &= nbsp;            r +=3D uev=5Fremove=5Fpath(m= erge=5Fuev, 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 -         =    goto out;
=EF=BC=9E -     }
=EF=BC=9E = -     if (!strncmp(uev-=EF=BC=9Eaction, "remove", 6)) {
= =EF=BC=9E -             r =3D uev=5Fremo= ve=5Fpath(uev, vecs);
=EF=BC=9E -          &nb= sp;  goto out;
=EF=BC=9E -     }
=EF=BC=9E -&nb= sp;    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=9Eac= tion, "remove", 6))
=EF=BC=9E +           = ;  r +=3D uev=5Fremove=5Fpath(uev, vecs, 1);
=EF=BC=9E +  &nb= sp;  if (!strncmp(uev-=EF=BC=9Eaction, "change", 6))
=EF=BC=9E +&n= bsp;            r +=3D uev=5Fupdate=5Fpath(ue= v, vecs);
=EF=BC=9E
=EF=BC=9E  out:
=EF=BC=9E   =    return r;
=EF=BC=9E @@ -1570,7 +1547,7 @@ check=5Fpath (s= truct vectors * vecs, struct path * pp, int ticks)
=EF=BC=9E  &nbs= p;                    con= f =3D get=5Fmultipath=5Fconfig();
=EF=BC=9E        =                ret =3D pathinfo(pp,= conf, DI=5FALL | DI=5FBLACKLIST);
=EF=BC=9E       =                if (ret =3D=3D PATH= INFO=5FOK) {
=EF=BC=9E -             = ;                ev=5Fadd=5Fpath(pp= , vecs);
=EF=BC=9E +              &n= bsp;              ev=5Fadd=5Fpath(pp, ve= cs, 1);
=EF=BC=9E               = ;                pp-=EF=BC=9Etick = =3D 1;
=EF=BC=9E               =        } else if (ret =3D=3D PATHINFO=5FSKIPPED) {
= =EF=BC=9E                  &n= bsp;            put=5Fmultipath=5Fconfig(conf= );
=EF=BC=9E @@ -1686,7 +1663,7 @@ check=5Fpath (struct vectors * vecs,= struct path * pp, int ticks)
=EF=BC=9E        &nbs= p;      }
=EF=BC=9E          &n= bsp;    if (!disable=5Freinstate && reinstate=5Fpath(pp, = add=5Factive)) {
=EF=BC=9E            &nb= sp;          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                  &= nbsp;    return 0;
=EF=BC=9E         = ;      }
=EF=BC=9E @@ -1709,7 +1686,7 @@ check=5Fpath (s= truct vectors * vecs, struct path * pp, int ticks)
=EF=BC=9E  &nbs= p;                    /* = Clear IO errors */
=EF=BC=9E            &= nbsp;          if (reinstate=5Fpath(pp, 0)) {
= =EF=BC=9E                  &nb= sp;            condlog(3, "%s: reload map", p= p-=EF=BC=9Edev);
=EF=BC=9E -            &= nbsp;                ev=5Fadd=5Fpat= h(pp, vecs);
=EF=BC=9E +             = ;                ev=5Fadd=5Fpath(pp= , vecs, 1);
=EF=BC=9E              &= nbsp;                pp-=EF=BC=9Eti= ck =3D 1;
=EF=BC=9E              &nb= sp;                return 0;
= =EF=BC=9E                  &nb= sp;    }
=EF=BC=9E diff --git a/multipathd/main.h b/multipath= d/main.h
=EF=BC=9E index f72580d..094b04f 100644
=EF=BC=9E --- a/mu= ltipathd/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 * daemo= n=5Fstatus(void);
=EF=BC=9E  int need=5Fto=5Fdelay=5Freconfig (str= uct 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 --
=EF=BC=9E 2.8.1.windows.1
=EF=BC=9E



=

--=====_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=====--