[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC PATCH 3/8] RFC: block: use transactions as a replacement of ->{
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
Re: [RFC PATCH 3/8] RFC: block: use transactions as a replacement of ->{can_}set_aio_context() |
Date: |
Wed, 20 Jul 2022 17:09:48 +0300 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.1 |
On 7/13/22 00:19, Emanuele Giuseppe Esposito wrote:
+/*
+ * @visited will accumulate all visited BdrvChild object. The caller is
+ * responsible for freeing the list afterwards.
+ */
+bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx,
+ GSList **visited, Transaction *tran,
+ Error **errp)
+{
+ BdrvChild *c;
+ BdrvStateSetAioContext *state;
+
+ GLOBAL_STATE_CODE();
+
+ if (bdrv_get_aio_context(bs) == ctx) {
+ return true;
+ }
+
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
+ if (!bdrv_parent_change_aio_context(c, ctx, visited, tran, errp)) {
+ return false;
+ }
+ }
+
+ QLIST_FOREACH(c, &bs->children, next) {
+ if (!bdrv_child_change_aio_context(c, ctx, visited, tran, errp)) {
+ return false;
+ }
+ }
+
+ state = g_new(BdrvStateSetAioContext, 1);
+ *state = (BdrvStateSetAioContext) {
+ .new_ctx = ctx,
+ .bs = bs,
+ };
+
+ /* First half of transactions are drains */
+ tran_add(tran, &drained_begin_end, state);
+ /*
+ * Second half of transactions takes care of setting the
+ * AioContext and free the state
+ */
+ tran_add_tail(tran, &set_aio_context, state);
+
+ return true;
+}
First, it looks like you want to use .commit() as .prepare(), .clean() as
commit(), and .prepare() as something that just schedule other actions.
In block transaction any effect that is visible to other transaction actions
should be done in .prepare(). (and .prepare is the main function of the action
with *tran parameter, i.e. bdrv_change_aio_context() function is actually
.prepare() phase).
So, ideally, the action:
- does the complete thing in .prepare (i.e. in the main function of the action)
- rollback it in .abort
- nothing in .commit
Usually we still need a .commit phase for irreversible part of the action (like
calling free() on the object). But that should be transparent for other actions.
So, generally we do:
tran = tran_new()
action_a(..., tran);
action_b(..., tran);
action_c(..., tran);
And we expect, that action_b() operates on top of action_a() already done. And
action_c() operate on top of action_b() done. So we cannot postpone visible (to
other actions) effect of the action to .commit phase.
So, for example, if you want a kind of smart drained section in transaction,
you may add simple
bdrv_drain_tran(..., tran);
that just call drained_begin(), and have only .clean() handler that call
drained_end(). This way you may do
bdrv_drain_tran(...., tran);
action_a(..., tran);
action_b(..., tran);
And be sure that both actions and all their .abort/.commit/.clean handlers are
called inside drained seaction. Isn't it what you need?
Second, this all becomes extremely difficult when we mix transactions and
recursion. When I moved permission system to transactions, I've introduced
topological dfs search to just get a list of nodes to handle. I think, if we
want to rework aio context change, we should first get rid of recursion.
--
Best regards,
Vladimir
- Re: [RFC PATCH 7/8] block: use the new _change_ API instead of _can_set_ and _set_, (continued)
[RFC PATCH 8/8] block: remove all unused ->can_set_aio_ctx and ->set_aio_ctx callbacks, Emanuele Giuseppe Esposito, 2022/07/12
[RFC PATCH 3/8] RFC: block: use transactions as a replacement of ->{can_}set_aio_context(), Emanuele Giuseppe Esposito, 2022/07/12
[RFC PATCH 6/8] block-backend: implement .change_aio_ctx in child_root, Emanuele Giuseppe Esposito, 2022/07/12
[RFC PATCH 4/8] blockjob: implement .change_aio_ctx in child_job, Emanuele Giuseppe Esposito, 2022/07/12