diff mbox series

[v6,31/33] include/qemu/job.h: introduce job->pre_run() and use it in amend

Message ID 20220121170544.2049944-32-eesposit@redhat.com
State New
Headers show
Series block layer: split block APIs in global state and I/O | expand

Commit Message

Emanuele Giuseppe Esposito Jan. 21, 2022, 5:05 p.m. UTC
Introduce .pre_run() job callback. This cb will run in job_start,
before the coroutine is created and runs run() in the job aiocontext.

Therefore, .pre_run() always runs in the main loop.
We can use this function together with clean() cb to replace
bdrv_child_refresh_perms in block_crypto_amend_options_generic_luks(),
since that function can also be called from an iothread via
.bdrv_co_amend().

In addition, doing so we check for permissions in all bdrv
in amend, not only crypto.

.pre_run() and .clean() take care of calling bdrv_amend_pre_run()
and bdrv_amend_clean() respectively, to set up driver-specific flags
and allow the crypto driver to temporarly provide the WRITE
perm to qcrypto_block_amend_options().

.pre_run() is not yet invoked by job_start, but .clean() is.
This is not a problem, since it will just be a redundant check
and crypto will have the update->keys flag == false anyways.

Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
---
 block/amend.c      | 33 +++++++++++++++++++++++++++++++++
 include/qemu/job.h |  9 +++++++++
 2 files changed, 42 insertions(+)

Comments

Hanna Czenczek Jan. 26, 2022, 3:57 p.m. UTC | #1
On 21.01.22 18:05, Emanuele Giuseppe Esposito wrote:
> Introduce .pre_run() job callback. This cb will run in job_start,
> before the coroutine is created and runs run() in the job aiocontext.

I presume this means “before the coroutine is created that will run 
run() in the job aiocontext”?

(The way it’s written here sounds a bit like .pre_run() will run run())

> Therefore, .pre_run() always runs in the main loop.
> We can use this function together with clean() cb to replace
> bdrv_child_refresh_perms in block_crypto_amend_options_generic_luks(),
> since that function can also be called from an iothread via
> .bdrv_co_amend().
>
> In addition, doing so we check for permissions in all bdrv
> in amend, not only crypto.

As I’ve written in my reply to patch 30, I’m not quite sold on this 
part, but disregarding that part (and one typo below), this patch looks 
good to me.

> .pre_run() and .clean() take care of calling bdrv_amend_pre_run()
> and bdrv_amend_clean() respectively, to set up driver-specific flags
> and allow the crypto driver to temporarly provide the WRITE
> perm to qcrypto_block_amend_options().
>
> .pre_run() is not yet invoked by job_start, but .clean() is.
> This is not a problem, since it will just be a redundant check
> and crypto will have the update->keys flag == false anyways.
>
> Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
> ---
>   block/amend.c      | 33 +++++++++++++++++++++++++++++++++
>   include/qemu/job.h |  9 +++++++++
>   2 files changed, 42 insertions(+)

[...]

> diff --git a/include/qemu/job.h b/include/qemu/job.h
> index 4ea7a4a0cd..915ceff425 100644
> --- a/include/qemu/job.h
> +++ b/include/qemu/job.h
> @@ -223,6 +223,15 @@ struct JobDriver {
>        * the GS API.
>        */
>   
> +    /**
> +     * Called in the Main Loop context, before the job coroutine
> +     * is started in the job aiocontext. Useful to perform operations
> +     * that needs to be done under BQL (like permissions setup).

s/needs/need/

> +     * On success, it returns 0. Otherwise the job failed to initialize
> +     * and won't start.
> +     */
> +    int (*pre_run)(Job *job, Error **errp);
> +
>       /**
>        * Called when the job is resumed by the user (i.e. user_paused becomes
>        * false). .user_resume is called before .resume.
Kevin Wolf Feb. 7, 2022, 6:14 p.m. UTC | #2
Am 21.01.2022 um 18:05 hat Emanuele Giuseppe Esposito geschrieben:
> Introduce .pre_run() job callback. This cb will run in job_start,
> before the coroutine is created and runs run() in the job aiocontext.
> 
> Therefore, .pre_run() always runs in the main loop.
> We can use this function together with clean() cb to replace
> bdrv_child_refresh_perms in block_crypto_amend_options_generic_luks(),
> since that function can also be called from an iothread via
> .bdrv_co_amend().

How is this different from having the same code in the function that
creates the job, i.e. qmp_x_blockdev_amend()?

Almost all block jobs have some setup code in the function that creates
the job instead of doing everything in .run(), precisely because they
know this code runs in the main thread.

Is amend really so different from the other block jobs in this respect
that it needs a different solution?

> In addition, doing so we check for permissions in all bdrv
> in amend, not only crypto.
> 
> .pre_run() and .clean() take care of calling bdrv_amend_pre_run()
> and bdrv_amend_clean() respectively, to set up driver-specific flags
> and allow the crypto driver to temporarly provide the WRITE
> perm to qcrypto_block_amend_options().
> 
> .pre_run() is not yet invoked by job_start, but .clean() is.
> This is not a problem, since it will just be a redundant check
> and crypto will have the update->keys flag == false anyways.
> 
> Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>

I find the way how you split the patches a bit confusing because the
patches aren't self-contained, but always refer to what the code will do
in the future, because after the patch it's dead code that isn't even
theoretically called until the final patch comes in.

Can we restructure this a bit? First a patch that adds a new JobDriver
callback (if really needed) along with the actual calls for it and
everything else that needs to be touched in the generic job
infrastructure. Second, new BlockDriver callbacks with all of the
plumbing code. Third, the amend job changes with a patch that doesn't
touch anything but block/amend.c and potentially block/crypto.c (the
latter could also be another separate patch).

This change with three or four patches could also be a candidate to be
split out into a separate smaller series.

Kevin
Emanuele Giuseppe Esposito Feb. 8, 2022, 11:05 a.m. UTC | #3
On 07/02/2022 19:14, Kevin Wolf wrote:
> Am 21.01.2022 um 18:05 hat Emanuele Giuseppe Esposito geschrieben:
>> Introduce .pre_run() job callback. This cb will run in job_start,
>> before the coroutine is created and runs run() in the job aiocontext.
>>
>> Therefore, .pre_run() always runs in the main loop.
>> We can use this function together with clean() cb to replace
>> bdrv_child_refresh_perms in block_crypto_amend_options_generic_luks(),
>> since that function can also be called from an iothread via
>> .bdrv_co_amend().
> 
> How is this different from having the same code in the function that
> creates the job, i.e. qmp_x_blockdev_amend()?
> 
> Almost all block jobs have some setup code in the function that creates
> the job instead of doing everything in .run(), precisely because they
> know this code runs in the main thread.
> 
> Is amend really so different from the other block jobs in this respect
> that it needs a different solution?
> 

Are you suggesting to simply call .bdrv_amend_pre_run before job_start()
and just leave JobDriver .clean() to call .bdrv_amend_clean?

Yes, that will work too. I will delete .pre_run().

>> In addition, doing so we check for permissions in all bdrv
>> in amend, not only crypto.
>>
>> .pre_run() and .clean() take care of calling bdrv_amend_pre_run()
>> and bdrv_amend_clean() respectively, to set up driver-specific flags
>> and allow the crypto driver to temporarly provide the WRITE
>> perm to qcrypto_block_amend_options().
>>
>> .pre_run() is not yet invoked by job_start, but .clean() is.
>> This is not a problem, since it will just be a redundant check
>> and crypto will have the update->keys flag == false anyways.
>>
>> Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
> 
> I find the way how you split the patches a bit confusing because the
> patches aren't self-contained, but always refer to what the code will do
> in the future, because after the patch it's dead code that isn't even
> theoretically called until the final patch comes in.
> 
> Can we restructure this a bit? First a patch that adds a new JobDriver
> callback (if really needed) along with the actual calls for it and
> everything else that needs to be touched in the generic job
> infrastructure. Second, new BlockDriver callbacks with all of the
> plumbing code. Third, the amend job changes with a patch that doesn't
> touch anything but block/amend.c and potentially block/crypto.c (the
> latter could also be another separate patch).

It is more or less what also Hanna suggested, I have it for the next
version.
> 
> This change with three or four patches could also be a candidate to be
> split out into a separate smaller series.

Makes sense.

Emanuele
> 
> Kevin
>
diff mbox series

Patch

diff --git a/block/amend.c b/block/amend.c
index 392df9ef83..1618fd05a6 100644
--- a/block/amend.c
+++ b/block/amend.c
@@ -53,10 +53,43 @@  static int coroutine_fn blockdev_amend_run(Job *job, Error **errp)
     return ret;
 }
 
+static int blockdev_amend_refresh_perms(Job *job, Error **errp)
+{
+    BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
+    return bdrv_child_refresh_perms(s->bs, s->bs->file, errp);
+}
+
+static int blockdev_amend_pre_run(Job *job, Error **errp)
+{
+    BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
+
+    if (s->bs->drv->bdrv_amend_pre_run) {
+        s->bs->drv->bdrv_amend_pre_run(s->bs);
+    }
+    return blockdev_amend_refresh_perms(job, errp);
+}
+
+static void blockdev_amend_clean(Job *job)
+{
+    BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
+    Error *errp = NULL;
+
+    if (s->bs->drv->bdrv_amend_clean) {
+        s->bs->drv->bdrv_amend_clean(s->bs);
+    }
+
+    blockdev_amend_refresh_perms(job, &errp);
+    if (errp) {
+        error_report_err(errp);
+    }
+}
+
 static const JobDriver blockdev_amend_job_driver = {
     .instance_size = sizeof(BlockdevAmendJob),
     .job_type      = JOB_TYPE_AMEND,
     .run           = blockdev_amend_run,
+    .pre_run       = blockdev_amend_pre_run,
+    .clean         = blockdev_amend_clean,
 };
 
 void qmp_x_blockdev_amend(const char *job_id,
diff --git a/include/qemu/job.h b/include/qemu/job.h
index 4ea7a4a0cd..915ceff425 100644
--- a/include/qemu/job.h
+++ b/include/qemu/job.h
@@ -223,6 +223,15 @@  struct JobDriver {
      * the GS API.
      */
 
+    /**
+     * Called in the Main Loop context, before the job coroutine
+     * is started in the job aiocontext. Useful to perform operations
+     * that needs to be done under BQL (like permissions setup).
+     * On success, it returns 0. Otherwise the job failed to initialize
+     * and won't start.
+     */
+    int (*pre_run)(Job *job, Error **errp);
+
     /**
      * Called when the job is resumed by the user (i.e. user_paused becomes
      * false). .user_resume is called before .resume.