[libvirt] [PATCH] nwfilter: fix learning address thread shutdown
Nikolay Shirokovskiy
nshirokovskiy at virtuozzo.com
Thu Oct 18 06:58:01 UTC 2018
On 18.10.2018 03:26, John Ferlan wrote:
>
>
> On 10/17/18 4:25 AM, Nikolay Shirokovskiy wrote:
>>
>>
>> On 17.10.2018 01:28, John Ferlan wrote:
>>>
>>>
>>> On 10/12/18 3:23 AM, Nikolay Shirokovskiy wrote:
>>>> If learning thread is configured to learn on all ethernet frames (which is
>>>> hardcoded) then chances are big that there is packet on every iteration of
>>>> inspecting frames loop. As result we will hang on shutdown because we don't
>>>> check threadsTerminate if there is packet.
>>>>
>>>> Let's just check termination conditions on every iteration.
>>>>
>>>> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
>>>> ---
>>>> src/nwfilter/nwfilter_learnipaddr.c | 22 +++++++---------------
>>>> 1 file changed, 7 insertions(+), 15 deletions(-)
>>>>
>>>> diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c
>>>> index 008c24b..e6cb996 100644
>>>> --- a/src/nwfilter/nwfilter_learnipaddr.c
>>>> +++ b/src/nwfilter/nwfilter_learnipaddr.c
>>>> @@ -483,6 +483,12 @@ learnIPAddressThread(void *arg)
>>>> while (req->status == 0 && vmaddr == 0) {
>>>> int n = poll(fds, ARRAY_CARDINALITY(fds), PKT_TIMEOUT_MS);
>>>>
>>>> + if (threadsTerminate || req->terminate) {
>>>> + req->status = ECANCELED;
>>>> + showError = false;
>>>> + break;
>>>> + }
>>>> +
>>>
>>> So the theory is that regardless of whether there is a timeout or not,
>>> let's check for termination markers before checking poll call return
>>> status. Which is fine; however, ...
>>>
>>>> if (n < 0) {
>>>> if (errno == EAGAIN || errno == EINTR)
>>>> continue;
>>>> @@ -492,15 +498,8 @@ learnIPAddressThread(void *arg)
>>>> break;
>>>> }
>>>>
>>>> - if (n == 0) {
>>>> - if (threadsTerminate || req->terminate) {
>>>> - VIR_DEBUG("Terminate request seen, cancelling pcap");
>>>> - req->status = ECANCELED;
>>>> - showError = false;
>>>> - break;
>>>> - }
>>>> + if (n == 0)
>>>> continue;
>>>> - }
>>>>
>>>> if (fds[0].revents & (POLLHUP | POLLERR)) {
>>>> VIR_DEBUG("Error from FD probably dev deleted");
>>>> @@ -512,13 +511,6 @@ learnIPAddressThread(void *arg)
>>>> packet = pcap_next(handle, &header);
>>>>
>>>> if (!packet) {
>>>> - /* Already handled with poll, but lets be sure */
>>>> - if (threadsTerminate || req->terminate) {
>>>> - req->status = ECANCELED;
>>>> - showError = false;
>>>> - break;
>>>> - }
>>>> -
>>>
>>> Why remove this one? Is it possible termination was set after the poll
>>> and if fetching the packet fails, then if these are true let's get out
>>> before possibly continuing back to the poll (which I assume would
>>> timeout and fail). Secondary question would be should this be separated
>>> from the other part?
>>
>> I guess pcap_next does not takes much time (as it does not wait for IO)
>> so there is a little chance things change after the above check. And
>> even if they are timeout is small and we terminate with little delay
>> right after poll.
>>
>> As to the second question I'm not sure why separation is useful.
>>
>> Nikolay
>>
>
> OK - I left things as is, slightly edited the commit message w/r/t
> grammar stuff...
>
> Reviewed-by: John Ferlan <jferlan at redhat.com>
> (and pushed)
>
Thanx!
Nikolay
>
>>>
>>> Just need to ask - maybe the answer alters the commit message a little
>>> bit too.
>>>
>>> John
>>>
>>>> /* Again, already handled above, but lets be sure */
>>>> if (virNetDevValidateConfig(req->binding->portdevname, NULL, req->ifindex) <= 0) {
>>>> virResetLastError();
>>>>
More information about the libvir-list
mailing list