[PATCH v1 7/9] colo-compare: safe finalization

Maxim Davydov posted 9 patches 3 years, 10 months ago
Maintainers: "Marc-André Lureau" <marcandre.lureau@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Eduardo Habkost <eduardo@habkost.net>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, "Philippe Mathieu-Daudé" <f4bug@amsat.org>, Yanan Wang <wangyanan55@huawei.com>, "Michael S. Tsirkin" <mst@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, Igor Mammedov <imammedo@redhat.com>, Ani Sinha <ani@anisinha.ca>, Xiao Guangrong <xiaoguangrong.eric@gmail.com>, Zhang Chen <chen.zhang@intel.com>, Li Zhijian <lizhijian@fujitsu.com>, Jason Wang <jasowang@redhat.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>, Alexander Bulekov <alxndr@bu.edu>, Bandan Das <bsd@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>, Thomas Huth <thuth@redhat.com>, Darren Kenny <darren.kenny@oracle.com>, Qiuhao Li <Qiuhao.Li@outlook.com>, Laurent Vivier <lvivier@redhat.com>
[PATCH v1 7/9] colo-compare: safe finalization
Posted by Maxim Davydov 3 years, 10 months ago
Fixes some possible issues with finalization. For example, finalization
immediately after instance_init fails on the assert.

Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
---
 net/colo-compare.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/net/colo-compare.c b/net/colo-compare.c
index 62554b5b3c..81d8de0aaa 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -1426,7 +1426,7 @@ static void colo_compare_finalize(Object *obj)
             break;
         }
     }
-    if (QTAILQ_EMPTY(&net_compares)) {
+    if (QTAILQ_EMPTY(&net_compares) && colo_compare_active) {
         colo_compare_active = false;
         qemu_mutex_destroy(&event_mtx);
         qemu_cond_destroy(&event_complete_cond);
@@ -1442,19 +1442,26 @@ static void colo_compare_finalize(Object *obj)
 
     colo_compare_timer_del(s);
 
-    qemu_bh_delete(s->event_bh);
+    if (s->event_bh) {
+        qemu_bh_delete(s->event_bh);
+    }
 
-    AioContext *ctx = iothread_get_aio_context(s->iothread);
-    aio_context_acquire(ctx);
-    AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
-    if (s->notify_dev) {
-        AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
+    if (s->iothread) {
+        AioContext *ctx = iothread_get_aio_context(s->iothread);
+        aio_context_acquire(ctx);
+        AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
+        if (s->notify_dev) {
+            AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
+        }
+        aio_context_release(ctx);
     }
-    aio_context_release(ctx);
 
     /* Release all unhandled packets after compare thead exited */
     g_queue_foreach(&s->conn_list, colo_flush_packets, s);
-    AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
+    /* Without colo_compare_complete done == false without packets */
+    if (!g_queue_is_empty(&s->out_sendco.send_list)) {
+        AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
+    }
 
     g_queue_clear(&s->conn_list);
     g_queue_clear(&s->out_sendco.send_list);
-- 
2.31.1
Re: [PATCH v1 7/9] colo-compare: safe finalization
Posted by Vladimir Sementsov-Ogievskiy 3 years, 10 months ago
29.03.2022 00:15, Maxim Davydov wrote:
> Fixes some possible issues with finalization. For example, finalization
> immediately after instance_init fails on the assert.
> 
> Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
> ---
>   net/colo-compare.c | 25 ++++++++++++++++---------
>   1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/net/colo-compare.c b/net/colo-compare.c
> index 62554b5b3c..81d8de0aaa 100644
> --- a/net/colo-compare.c
> +++ b/net/colo-compare.c
> @@ -1426,7 +1426,7 @@ static void colo_compare_finalize(Object *obj)
>               break;
>           }
>       }
> -    if (QTAILQ_EMPTY(&net_compares)) {
> +    if (QTAILQ_EMPTY(&net_compares) && colo_compare_active) {
>           colo_compare_active = false;
>           qemu_mutex_destroy(&event_mtx);
>           qemu_cond_destroy(&event_complete_cond);
> @@ -1442,19 +1442,26 @@ static void colo_compare_finalize(Object *obj)
>   
>       colo_compare_timer_del(s);
>   
> -    qemu_bh_delete(s->event_bh);
> +    if (s->event_bh) {
> +        qemu_bh_delete(s->event_bh);
> +    }
>   
> -    AioContext *ctx = iothread_get_aio_context(s->iothread);
> -    aio_context_acquire(ctx);
> -    AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
> -    if (s->notify_dev) {
> -        AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
> +    if (s->iothread) {
> +        AioContext *ctx = iothread_get_aio_context(s->iothread);
> +        aio_context_acquire(ctx);
> +        AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
> +        if (s->notify_dev) {
> +            AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
> +        }
> +        aio_context_release(ctx);
>       }
> -    aio_context_release(ctx);
>   
>       /* Release all unhandled packets after compare thead exited */
>       g_queue_foreach(&s->conn_list, colo_flush_packets, s);
> -    AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
> +    /* Without colo_compare_complete done == false without packets */
> +    if (!g_queue_is_empty(&s->out_sendco.send_list)) {
> +        AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
> +    }

I think, would be good to add more description for this last change. It's not as obvious as previous two changes.

>   
>       g_queue_clear(&s->conn_list);
>       g_queue_clear(&s->out_sendco.send_list);


-- 
Best regards,
Vladimir
Re: [PATCH v1 7/9] colo-compare: safe finalization
Posted by Maxim Davydov 3 years, 10 months ago
The main problem that if we call object_new_with_class() and then 
object_unref(), it fails. First of all, this is due to the fact that 
finalize expects that net/colo-compare.c:colo_compare_complete() has 
been called before.

On 3/30/22 17:54, Vladimir Sementsov-Ogievskiy wrote:
> 29.03.2022 00:15, Maxim Davydov wrote:
>> Fixes some possible issues with finalization. For example, finalization
>> immediately after instance_init fails on the assert.
>>
>> Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
>> ---
>>   net/colo-compare.c | 25 ++++++++++++++++---------
>>   1 file changed, 16 insertions(+), 9 deletions(-)
>>
>> diff --git a/net/colo-compare.c b/net/colo-compare.c
>> index 62554b5b3c..81d8de0aaa 100644
>> --- a/net/colo-compare.c
>> +++ b/net/colo-compare.c
>> @@ -1426,7 +1426,7 @@ static void colo_compare_finalize(Object *obj)
>>               break;
>>           }
>>       }
>> -    if (QTAILQ_EMPTY(&net_compares)) {
if colo_compare_active == false, event_mtx and event_complete_cond 
didn't inited in colo_compare_complete()
>> +    if (QTAILQ_EMPTY(&net_compares) && colo_compare_active) {
>>           colo_compare_active = false;
>>           qemu_mutex_destroy(&event_mtx);
>>           qemu_cond_destroy(&event_complete_cond);
>> @@ -1442,19 +1442,26 @@ static void colo_compare_finalize(Object *obj)
>>         colo_compare_timer_del(s);
>>   -    qemu_bh_delete(s->event_bh);
s->event_bh wasn't allocated in colo_compare_iothread() in 
colo_compare_complete()
>> +    if (s->event_bh) {
>> +        qemu_bh_delete(s->event_bh);
>> +    }
>>   -    AioContext *ctx = iothread_get_aio_context(s->iothread);
>> -    aio_context_acquire(ctx);
>> -    AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
>> -    if (s->notify_dev) {
>> -        AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
s->iothread == NULL after .instance_init (it can be detected in 
colo_compare_complete(), if it has been called)
>> +    if (s->iothread) {
>> +        AioContext *ctx = iothread_get_aio_context(s->iothread);
>> +        aio_context_acquire(ctx);
>> +        AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
>> +        if (s->notify_dev) {
>> +            AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
>> +        }
>> +        aio_context_release(ctx);
>>       }
>> -    aio_context_release(ctx);
>>         /* Release all unhandled packets after compare thead exited */
>>       g_queue_foreach(&s->conn_list, colo_flush_packets, s);
>> -    AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
In normal situation, it flushes all packets and sets s->out_sendco.done 
= true via compare_chr_send (we wait this event). But s->conn_list isn't 
initialized, s->out_sendco.done == false and won't become true. So, it's 
infinite waiting.
>> +    /* Without colo_compare_complete done == false without packets */
>> +    if (!g_queue_is_empty(&s->out_sendco.send_list)) {
>> +        AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
>> +    }
>
> I think, would be good to add more description for this last change. 
> It's not as obvious as previous two changes.
>
>> g_queue_clear(&s->conn_list);
>>       g_queue_clear(&s->out_sendco.send_list);
>
>
-- 
Best regards,
Maxim Davydov