Patchwork [1/3] blockdev: abort transactions in reverse order

login
register
mail settings
Submitter John Snow
Date Dec. 6, 2018, 7:25 p.m.
Message ID <20181206192544.3987-2-jsnow@redhat.com>
Download mbox | patch
Permalink /patch/674569/
State New
Headers show

Comments

John Snow - Dec. 6, 2018, 7:25 p.m.
Presently, we abort transactions in the same order they were processed in.
Bitmap commands, though, attempt to restore backup data structures on abort.
To that end, though, they need to be aborted in reverse chronological order.

Replace the QSIMPLEQ data structure with a QTAILQ one, so we can iterate
in reverse for the abort phase of the transaction.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 blockdev.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
Eric Blake - Dec. 6, 2018, 8:37 p.m.
On 12/6/18 1:25 PM, John Snow wrote:
> Presently, we abort transactions in the same order they were processed in.
> Bitmap commands, though, attempt to restore backup data structures on abort.
> To that end, though, they need to be aborted in reverse chronological order.
> 
> Replace the QSIMPLEQ data structure with a QTAILQ one, so we can iterate
> in reverse for the abort phase of the transaction.
> 
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   blockdev.c | 14 +++++++-------
>   1 file changed, 7 insertions(+), 7 deletions(-)

Does this need to cc qemu-stable? I'm trying to figure out if it affects 
any of the transactions issued by my libvirt code demo'd at KVM Forum.

Reviewed-by: Eric Blake <eblake@redhat.com>
John Snow - Dec. 6, 2018, 8:43 p.m.
On 12/6/18 3:37 PM, Eric Blake wrote:
> On 12/6/18 1:25 PM, John Snow wrote:
>> Presently, we abort transactions in the same order they were processed
>> in.
>> Bitmap commands, though, attempt to restore backup data structures on
>> abort.
>> To that end, though, they need to be aborted in reverse chronological
>> order.
>>
>> Replace the QSIMPLEQ data structure with a QTAILQ one, so we can iterate
>> in reverse for the abort phase of the transaction.
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   blockdev.c | 14 +++++++-------
>>   1 file changed, 7 insertions(+), 7 deletions(-)
> 
> Does this need to cc qemu-stable? I'm trying to figure out if it affects
> any of the transactions issued by my libvirt code demo'd at KVM Forum.
> 
> Reviewed-by: Eric Blake <eblake@redhat.com>
> 

Hmm, possibly. merge is of course an x-prefix, but "clear" uses the same
restoration technique. I suppose if you cleared the same bitmap multiple
times and tried to roll it back you could see trouble where we restore
an already cleared bitmap.

I'll say that patch 01/03 here should be considered a bugfix, yes, but I
wanted to see if anyone thought this had consequences I hadn't
considered yet.

--js
Vladimir Sementsov-Ogievskiy - Dec. 7, 2018, 8:38 a.m.
06.12.2018 22:25, John Snow wrote:
> Presently, we abort transactions in the same order they were processed in.

> Bitmap commands, though, attempt to restore backup data structures on abort.

> To that end, though, they need to be aborted in reverse chronological order.

> 

> Replace the QSIMPLEQ data structure with a QTAILQ one, so we can iterate

> in reverse for the abort phase of the transaction.


aha, so, abort for
   add
   disable
should be
   enable
   del
and not visa-versa

Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>


> 

> Signed-off-by: John Snow <jsnow@redhat.com>

> ---

>   blockdev.c | 14 +++++++-------

>   1 file changed, 7 insertions(+), 7 deletions(-)

> 

> diff --git a/blockdev.c b/blockdev.c

> index 81f95d920b..1ba706df8b 100644

> --- a/blockdev.c

> +++ b/blockdev.c

> @@ -1341,7 +1341,7 @@ struct BlkActionState {

>       const BlkActionOps *ops;

>       JobTxn *block_job_txn;

>       TransactionProperties *txn_props;

> -    QSIMPLEQ_ENTRY(BlkActionState) entry;

> +    QTAILQ_ENTRY(BlkActionState) entry;

>   };

>   

>   /* internal snapshot private data */

> @@ -2269,8 +2269,8 @@ void qmp_transaction(TransactionActionList *dev_list,

>       BlkActionState *state, *next;

>       Error *local_err = NULL;

>   

> -    QSIMPLEQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;

> -    QSIMPLEQ_INIT(&snap_bdrv_states);

> +    QTAILQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;

> +    QTAILQ_INIT(&snap_bdrv_states);

>   

>       /* Does this transaction get canceled as a group on failure?

>        * If not, we don't really need to make a JobTxn.

> @@ -2301,7 +2301,7 @@ void qmp_transaction(TransactionActionList *dev_list,

>           state->action = dev_info;

>           state->block_job_txn = block_job_txn;

>           state->txn_props = props;

> -        QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);

> +        QTAILQ_INSERT_TAIL(&snap_bdrv_states, state, entry);

>   

>           state->ops->prepare(state, &local_err);

>           if (local_err) {

> @@ -2310,7 +2310,7 @@ void qmp_transaction(TransactionActionList *dev_list,

>           }

>       }

>   

> -    QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {

> +    QTAILQ_FOREACH(state, &snap_bdrv_states, entry) {

>           if (state->ops->commit) {

>               state->ops->commit(state);

>           }

> @@ -2321,13 +2321,13 @@ void qmp_transaction(TransactionActionList *dev_list,

>   

>   delete_and_fail:

>       /* failure, and it is all-or-none; roll back all operations */

> -    QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {

> +    QTAILQ_FOREACH_REVERSE(state, &snap_bdrv_states, snap_bdrv_states, entry) {

>           if (state->ops->abort) {

>               state->ops->abort(state);

>           }

>       }

>   exit:

> -    QSIMPLEQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {

> +    QTAILQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {

>           if (state->ops->clean) {

>               state->ops->clean(state);

>           }

> 



-- 
Best regards,
Vladimir

Patch

diff --git a/blockdev.c b/blockdev.c
index 81f95d920b..1ba706df8b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1341,7 +1341,7 @@  struct BlkActionState {
     const BlkActionOps *ops;
     JobTxn *block_job_txn;
     TransactionProperties *txn_props;
-    QSIMPLEQ_ENTRY(BlkActionState) entry;
+    QTAILQ_ENTRY(BlkActionState) entry;
 };
 
 /* internal snapshot private data */
@@ -2269,8 +2269,8 @@  void qmp_transaction(TransactionActionList *dev_list,
     BlkActionState *state, *next;
     Error *local_err = NULL;
 
-    QSIMPLEQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;
-    QSIMPLEQ_INIT(&snap_bdrv_states);
+    QTAILQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;
+    QTAILQ_INIT(&snap_bdrv_states);
 
     /* Does this transaction get canceled as a group on failure?
      * If not, we don't really need to make a JobTxn.
@@ -2301,7 +2301,7 @@  void qmp_transaction(TransactionActionList *dev_list,
         state->action = dev_info;
         state->block_job_txn = block_job_txn;
         state->txn_props = props;
-        QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
+        QTAILQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
 
         state->ops->prepare(state, &local_err);
         if (local_err) {
@@ -2310,7 +2310,7 @@  void qmp_transaction(TransactionActionList *dev_list,
         }
     }
 
-    QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
+    QTAILQ_FOREACH(state, &snap_bdrv_states, entry) {
         if (state->ops->commit) {
             state->ops->commit(state);
         }
@@ -2321,13 +2321,13 @@  void qmp_transaction(TransactionActionList *dev_list,
 
 delete_and_fail:
     /* failure, and it is all-or-none; roll back all operations */
-    QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
+    QTAILQ_FOREACH_REVERSE(state, &snap_bdrv_states, snap_bdrv_states, entry) {
         if (state->ops->abort) {
             state->ops->abort(state);
         }
     }
 exit:
-    QSIMPLEQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
+    QTAILQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
         if (state->ops->clean) {
             state->ops->clean(state);
         }