<div class="zcontentRow"> <p><br></p><p>Hello Ben,<br></p><p><br></p><p>It's too later now,  I think you'd better go bed, haha.</p><p><br></p><p>> > > The first case should have been reduced to "remove path1 | remove path2</p><p>> > > | add path3" by filtering beforehand. I suppose you want to avoid this</p><p>> > > sequence because it could leave us without paths temporarily, causing</p><p>> > > multipathd to destroy the map. But I don't understand what "stop</p><p>> > > merging" buys you here - if you process the events one-by-one, you may</p><p>> > > also have 0 paths at some point. </p><p>> >   </p><p>> > Well, because of the filtering , you will never actually stop merging</p><p>> > in this case, like you mentioned.</p><p>>   </p><p>> Or, if I actually read better, I would see that you will stop merging.</p><p>> I can't think of any problems in theory with merging adds after removes</p><p>> in the simple case at least.</p><p>Maybe we can merger more uevents without stopping mergering(Like even </p><p>merge "add uevent" and "remove uevent" ),  but what I have right now handles</p><p>the common cases, which are bursts of add/chage events, and bursts of remove</p><p>events. So when we meet the complex scene, we'd better stop  mergering, </p><p>and just let them be processed one by one.  It can reduce abnormal situation, </p><p>and enhance the reliability of the code.</p><p><br></p><p>> > sdb in the add event. If you have</p><p>> > </p><p>> > remove sdb | add sdb</p><p>> > </p><p>> > There is no guarantee that sdb in the add event is referring to the same</p><p>> > LUN as sdb in the remove event. Once the device gets removed that name</p><p>> > can get reused for anything.</p><p>></p><p>> Or you could change the filtering code to verify that the wwids matched.</p><p>> However, while the device would be for the same LUN, it might be a</p><p>> different I_T Nexus, so you still don't want to filter the remove of that</p><p>> specific device. </p><p>We didn't filter such uevent "<span style="line-height: 21px;">remove sdb" in current codes,  as you know, they </span></p><p><span style="line-height: 21px;">are  <span style="line-height: 21px;">quite possibly not the same LUN.</span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;"><br></span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;">Regards,</span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;">Tang Junhui</span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;"><br></span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;"><br></span></span></p><p><br></p><p><br></p><div><div class="zhistoryRow" style="display:block"><div class="zhistoryDes" style="width: 100%; height: 28px; line-height: 28px; background-color: #E0E5E9; color: #1388FF; text-align: center;" language-data="HistoryOrgTxt">原始邮件</div><div id="zwriteHistoryContainer"><div class="control-group zhistoryPanel"><div class="zhistoryHeader" style="padding: 8px; background-color: #F5F6F8;"><div><strong language-data="HistorySenderTxt">发件人:</strong><span class="zreadUserName"> <bmarzins@redhat.com>;</span></div><div><strong language-data="HistoryTOTxt">收件人:</strong><span class="zreadUserName" style="display: inline-block;"> <mwilck@suse.com>;</span></div><div><strong language-data="HistoryCCTxt">抄送人:</strong><span class="zreadUserName" style="display: inline-block;">张凯10072500;</span><span class="zreadUserName" style="display: inline-block;"> <dm-devel@redhat.com>;</span><span class="zreadUserName" style="display: inline-block;">唐军辉10074136;</span><span class="zreadUserName" style="display: inline-block;">唐文俊10144149;</span><span class="zreadUserName" style="display: inline-block;"> <bart.vanassche@sandisk.com>;</span></div><div><strong language-data="HistoryDateTxt">日 期 :</strong><span class="">2017年02月17日 14:27</span></div><div><strong language-data="HistorySubjectTxt">主 题 :</strong><span class="zreadTitle"><strong>Re: [dm-devel] [PATCH] multipath-tools: improve processing efficiency for addition and deletion of multipath devices</strong></span></div></div><p class="zhistoryContent"><br></p><div>On Thu, Feb 16, 2017 at 11:38:36PM -0600, Benjamin Marzinski wrote:<br><br>Quite possibly, I shouldn't try responding to email at 11:30 PM. It<br>appears that my brain has already given up for the day.<br><br>> On Thu, Feb 16, 2017 at 10:17:35PM +0100, Martin Wilck wrote:<br>> > Hello Tang,<br>> > <br>> > I'm sorry to reply so late. Thanks a lot for your work, I agree with<br>> > Ben that the patch is in pretty good shape now. But I have some<br>> > remarks left, please see below. <br>> >  <br>> > > +bool<br>> > > +uevent_can_discard(struct uevent *uev)<br>> > > +{<br>> > > +    char *tmp;<br>> > > +    char a[11], b[11];<br>> > > +    struct config * conf;<br>> > > +<br>> > > +    /*<br>> > > +     * keep only block devices, discard partitions<br>> > > +     */<br>> > > +    tmp = strstr(uev->devpath, "/block/");<br>> > > +    if (tmp == NULL){<br>> > > +        condlog(4, "no /block/ in '%s'", uev->devpath);<br>> > > +        return true;<br>> > > +    }<br>> > > +    if (sscanf(tmp, "/block/%10s", a) != 1 ||<br>> > > +        sscanf(tmp, "/block/%10[^/]/%10s", a, b) == 2) {<br>> > > +        condlog(4, "discard event on %s", uev->devpath);<br>> > > +        return true;<br>> > > +    }<br>> > <br>> > I'd like the following better for this check. It uses much less cycles.<br>> > <br>> > static bool<br>> > can_discard_by_devpath(const char *devpath)<br>> > {<br>> >     static const char BLOCK[] = "/block/";<br>> >     const char *p;<br>> > <br>> >     p = strstr(pathstr, BLOCK);<br>> >     if (p == NULL)<br>> >         /* not a block device */<br>> >         return true;<br>> >     p += sizeof(BLOCK) - 1;<br>> >     p = strchr(p, '/');<br>> >     if (p == NULL)<br>> >         /* exactly one path element after "/block/" */<br>> >         return false;<br>> >     /* If there are more path elements, it's a partition */<br>> >     return true;<br>> > }<br>> > <br>> > > +bool<br>> > > +uevent_can_filter(struct uevent *earlier, struct uevent *later)<br>> > > +{<br>> > > +<br>> > > +    /*<br>> > > +     * filter earlier uvents if path has removed later. Eg:<br>> > > +     * "add path1 |chang path1 |add path2 |remove path1"<br>> > > +     * can filter as:<br>> > > +     * "add path2 |remove path1"<br>> > > +     * uevents "add path1" and "chang path1" are filtered out<br>> > > +     */<br>> > > +    if (!strcmp(earlier->kernel, later->kernel) &&<br>> > > +        !strcmp(later->action, "remove") &&<br>> > > +        strncmp(later->kernel, "dm-", 3)) {<br>> > > +        return true;<br>> > > +    }<br>> > > +<br>> > > +    /*<br>> > > +     * filter change uvents if add uevents exist. Eg:<br>> > > +     * "change path1| add path1 |add path2"<br>> > > +     * can filter as:<br>> > > +     * "add path1 |add path2"<br>> > > +     * uevent "chang path1" is filtered out<br>> > > +     */<br>> > > +    if (!strcmp(earlier->kernel, later->kernel) &&<br>> > > +        !strcmp(earlier->action, "change") &&<br>> > > +        !strcmp(later->action, "add") &&<br>> > > +        strncmp(later->kernel, "dm-", 3)) {<br>> > > +        return true;<br>> > > +    }<br>> > > +<br>> > > +    return false;<br>> > > +}<br>> > <br>> > This would be better readable and faster if you'd put the "kernel"<br>> > tests first so that you need to check only "action" later:<br>> > <br>> >     if (!strncmp(later->kernel, "dm-", 3) ||<br>> >         strcmp(earlier->kernel, later->kernel))<br>> >         return false;<br>> > <br>> > > +<br>> > > +bool<br>> > > +merge_need_stop(struct uevent *earlier, struct uevent *later)<br>> > > +{<br>> > > +    /*<br>> > > +     * dm uevent do not try to merge with left uevents<br>> > > +     */<br>> > > +    if (!strncmp(later->kernel, "dm-", 3))<br>> > > +        return true;<br>> > > +<br>> > > +    /*<br>> > > +     * we can not make a jugement without wwid,<br>> > > +     * so it is sensible to stop merging<br>> > > +     */<br>> > > +    if (!earlier->wwid || !later->wwid)<br>> > > +        return true;<br>> > > +    /*<br>> > > +     * uevents merging stoped<br>> > > +     * when we meet an opposite action uevent from the same LUN<br>> > > to AVOID<br>> > > +     * "add path1 |remove path1 |add path2 |remove path2 |add<br>> > > path3"<br>> > > +     * to merge as "remove path1, path2" and "add path1, path2,<br>> > > path3"<br>> > > +     * OR<br>> > > +     * "remove path1 |add path1 |remove path2 |add path2 |remove<br>> > > path3"<br>> > > +     * to merge as "add path1, path2" and "remove path1, path2,<br>> > > path3"<br>> > > +     * SO<br>> > > +     * when we meet a non-change uevent from the same LUN<br>> > > +     * with the same wwid and different action<br>> > > +     * it would be better to stop merging.<br>> > > +     */<br>> > > +    if (!strcmp(earlier->wwid, later->wwid) &&<br>> > > +        strcmp(earlier->action, later->action) &&<br>> > > +        strcmp(earlier->action, "change") &&<br>> > > +        strcmp(later->action, "change"))<br>> > > +        return true;<br>> > > +<br>> > > +    return false;<br>> > > +}<br>> > <br>> > I know you discussed this with Ben before, but still have some trouble<br>> > with it. <br>> > <br>> > The first case should have been reduced to "remove path1 | remove path2<br>> > | add path3" by filtering beforehand. I suppose you want to avoid this<br>> > sequence because it could leave us without paths temporarily, causing<br>> > multipathd to destroy the map. But I don't understand what "stop<br>> > merging" buys you here - if you process the events one-by-one, you may<br>> > also have 0 paths at some point. <br>> <br>> Well, because of the filtering , you will never actually stop merging<br>> in this case, like you mentioned.<br><br>Or, if I actually read better, I would see that you will stop merging.<br>I can't think of any problems in theory with merging adds after removes<br>in the simple case at least.<br><br>> > In the second case, we know all events in the sequence have the same<br>> > WWID; in this case I think it would be safe to filter away "remove"<br>> > events by subsequent "add" events, ending up with "add path1| add<br>> > path2| remove path3". But I may be overlooking something here.<br>> <br>> We can't filter out the remove path events in this case. If you have<br>> <br>> add sdb | remove sdb<br>> <br>> You know that sdb in the remove event is referring to the same device as<br>> sdb in the add event. If you have<br>> <br>> remove sdb | add sdb<br>> <br>> There is no guarantee that sdb in the add event is referring to the same<br>> LUN as sdb in the remove event. Once the device gets removed that name<br>> can get reused for anything.<br><br>Or you could change the filtering code to verify that the wwids matched.<br>However, while the device would be for the same LUN, it might be a<br>different I_T Nexus, so you still don't want to filter the remove of that<br>specific device. <br> <br>-Ben<br><br>> > <br>> > The dangerous thing if you have simultaneous remove and add events for<br>> > the same LUN is that processing the "add" events is likely to fail in<br>> > domap(). If you get "add path1 | remove path2", once you process "add<br>> > path1", "path2" may not exist in the kernel any more, and "domap" will<br>> > fail if you try to set up both; you may end up removing the map<br>> > completely. IMHO the only safe way to process events in this situation<br>> > is to merge the events into a single domap() call.<br>> > <br>> > I know you want to avoid that in this patch, but I think it will be a<br>> > logical further improvement.<br>> > <br>> > Anyway, AFAICS your patch doesn't introduce a regression wrt the<br>> > current code here; unless I'm overlooking something, my arguments would<br>> > apply to sequential event processing as well.<br>> > <br>> > Regards<br>> > Martin<br>> > <br>> > -- <br>> > Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107<br>> > SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton<br>> > HRB 21284 (AG Nürnberg)<br>> <br>> --<br>> dm-devel mailing list<br>> dm-devel@redhat.com<br>> https://www.redhat.com/mailman/listinfo/dm-devel<br><br>--<br>dm-devel mailing list<br>dm-devel@redhat.com<br>https://www.redhat.com/mailman/listinfo/dm-devel<br></div><p><br></p></div></div></div></div><p><br></p> </div>