qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 2/9] block-copy: add missing coroutine_fn annotations


From: Vladimir Sementsov-Ogievskiy
Subject: Re: [PATCH v2 2/9] block-copy: add missing coroutine_fn annotations
Date: Tue, 8 Nov 2022 19:19:19 +0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.2.2

[add Stefan]


On 11/8/22 18:09, Emanuele Giuseppe Esposito wrote:


Am 08/11/2022 um 15:48 schrieb Vladimir Sementsov-Ogievskiy:
On 11/4/22 12:56, Emanuele Giuseppe Esposito wrote:
These functions end up calling bdrv_common_block_status_above(), a
generated_co_wrapper function.

generated_co_wrapper is not a coroutine_fn. Сonversely it's a function
that do a class coroutine wrapping - start a coroutine and do POLL to
wait for the coroutine to finish.

In addition, they also happen to be always called in coroutine context,
meaning all callers are coroutine_fn.

That's also not a reason for marking them coroutine_fn. "coroutine_fn"
means that the function can be called only from coroutine context.

This means that the g_c_w function will enter the qemu_in_coroutine()
case and eventually suspend (or in other words call
qemu_coroutine_yield()).
Therefore we need to mark such functions coroutine_fn too.

I don't think so. Moreover, this breaks the concept, as your new
coroutine_fn functions will call generated_co_wrapper functions which
are not marked coroutine_fn and never was.

Theoretically not,

Agree, I was wrong in this point

because marking it coroutine_fn we know that we are
going in the if(qemu_in_coroutine()) branch of the g_c_w, so we could
directly replace it with the actual function. Because it's a pain to do
it with hand, and at some point I/someone should use Alberto static
analyzer to get rid of that, I decided to leave g_c_w there.

As I understand it, it seems that you and Paolo have a different
understanding on what coroutine_fn means and where it should be used.

Looks so...

But we have a documentation in coroutine.h, let's check:

 * Mark a function that executes in coroutine context
 *
 * Functions that execute in coroutine context cannot be called directly from
 * normal functions.  In the future it would be nice to enable compiler or
 * static checker support for catching such errors.  This annotation might make
 * it possible and in the meantime it serves as documentation.

Not very clear, but still it say:

 coroutine_fn = "function that executes in coroutine context"
 "functions that execute in coroutine context"  =  "cannot be called directly from 
normal functions"

So, IMHO that corresponds to my point of view: we shouldn't mark by 
coroutine_fn functions that can be called from both coroutine context and not.

If we want to change the concept, we should start with rewriting this 
documentation.

Honestly I don't understand your point, as you said

"coroutine_fn"
means that the function can be called only from coroutine context.

which is the case for these functions. So could you please clarify?

What I do know is that it's extremely confusing to understand if a
function that is *not* marked as coroutine_fn is actually being called
also from coroutines or not.

Which complicates A LOT whatever change or operation I want to perform
on the BlockDriver callbacks or any other function in the block layer,
because in the current approach for the AioContext lock removal (which
you are not aware of, I understand) we need to distinguish between
functions running in coroutine context and not, and throwing g_c_w
functions everywhere makes my work much harder that it already is.

OK, I understand the problem.

Hmm. Formally marking by "coroutine_fn" a function that theoretically can be 
called from any context doesn't break things. We just say that since that moment we don't 
allow to call this function from non-coroutine context.

OK, I tend to agree that you are on the right way, sorry for my skepticism)

PS: you recently introduced a lot of IO_CODE() / GLOBAL_STATE_CODE() marks, 
which (will be/already) turned into assertions.

This is a lot better than our "coroutine_fn" sign, which actually do no check (and can't 
do). Don't you plan to swap a "coroutine_fn" noop marker with more meaningful 
IN_COROUTINE(); (or something like this, which just do assert(qemu_in_coroutine())) at start of the 
function? It would be a lot safer.



Thank you,
Emanuele



Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
---
   block/block-copy.c | 15 +++++++++------
   1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/block/block-copy.c b/block/block-copy.c
index bb947afdda..f33ab1d0b6 100644
--- a/block/block-copy.c
+++ b/block/block-copy.c
@@ -577,8 +577,9 @@ static coroutine_fn int
block_copy_task_entry(AioTask *task)
       return ret;
   }
   -static int block_copy_block_status(BlockCopyState *s, int64_t offset,
-                                   int64_t bytes, int64_t *pnum)
+static coroutine_fn int block_copy_block_status(BlockCopyState *s,
+                                                int64_t offset,
+                                                int64_t bytes,
int64_t *pnum)
   {
       int64_t num;
       BlockDriverState *base;
@@ -613,8 +614,9 @@ static int block_copy_block_status(BlockCopyState
*s, int64_t offset,
    * Check if the cluster starting at offset is allocated or not.
    * return via pnum the number of contiguous clusters sharing this
allocation.
    */
-static int block_copy_is_cluster_allocated(BlockCopyState *s, int64_t
offset,
-                                           int64_t *pnum)
+static int coroutine_fn
block_copy_is_cluster_allocated(BlockCopyState *s,
+                                                        int64_t offset,
+                                                        int64_t *pnum)
   {
       BlockDriverState *bs = s->source->bs;
       int64_t count, total_count = 0;
@@ -669,8 +671,9 @@ void block_copy_reset(BlockCopyState *s, int64_t
offset, int64_t bytes)
    * @return 0 when the cluster at @offset was unallocated,
    *         1 otherwise, and -ret on error.
    */
-int64_t block_copy_reset_unallocated(BlockCopyState *s,
-                                     int64_t offset, int64_t *count)
+int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s,
+                                                  int64_t offset,
+                                                  int64_t *count)
   {
       int ret;
       int64_t clusters, bytes;



--
Best regards,
Vladimir




reply via email to

[Prev in Thread] Current Thread [Next in Thread]