Revision ba0c86a3

b/blockdev.c
779 779

  
780 780

  
781 781
/* New and old BlockDriverState structs for group snapshots */
782
typedef struct BlkTransactionStates {
782

  
783
typedef struct BlkTransactionStates BlkTransactionStates;
784

  
785
/* Only prepare() may fail. In a single transaction, only one of commit() or
786
   abort() will be called, clean() will always be called if it present. */
787
typedef struct BdrvActionOps {
788
    /* Size of state struct, in bytes. */
789
    size_t instance_size;
790
    /* Prepare the work, must NOT be NULL. */
791
    void (*prepare)(BlkTransactionStates *common, Error **errp);
792
    /* Commit the changes, must NOT be NULL. */
793
    void (*commit)(BlkTransactionStates *common);
794
    /* Abort the changes on fail, can be NULL. */
795
    void (*abort)(BlkTransactionStates *common);
796
    /* Clean up resource in the end, can be NULL. */
797
    void (*clean)(BlkTransactionStates *common);
798
} BdrvActionOps;
799

  
800
/*
801
 * This structure must be arranged as first member in child type, assuming
802
 * that compiler will also arrange it to the same address with parent instance.
803
 * Later it will be used in free().
804
 */
805
struct BlkTransactionStates {
806
    BlockdevAction *action;
807
    const BdrvActionOps *ops;
808
    QSIMPLEQ_ENTRY(BlkTransactionStates) entry;
809
};
810

  
811
/* external snapshot private data */
812
typedef struct ExternalSnapshotStates {
813
    BlkTransactionStates common;
783 814
    BlockDriverState *old_bs;
784 815
    BlockDriverState *new_bs;
785
    QSIMPLEQ_ENTRY(BlkTransactionStates) entry;
786
} BlkTransactionStates;
816
} ExternalSnapshotStates;
787 817

  
788
static void external_snapshot_prepare(BlockdevAction *action,
789
                                      BlkTransactionStates *states,
818
static void external_snapshot_prepare(BlkTransactionStates *common,
790 819
                                      Error **errp)
791 820
{
792 821
    BlockDriver *proto_drv;
......
797 826
    const char *new_image_file;
798 827
    const char *format = "qcow2";
799 828
    enum NewImageMode mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
829
    ExternalSnapshotStates *states =
830
                             DO_UPCAST(ExternalSnapshotStates, common, common);
831
    BlockdevAction *action = common->action;
800 832

  
801 833
    /* get parameters */
802 834
    g_assert(action->kind == BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC);
......
871 903
    }
872 904
}
873 905

  
874
static void external_snapshot_commit(BlkTransactionStates *states)
906
static void external_snapshot_commit(BlkTransactionStates *common)
875 907
{
908
    ExternalSnapshotStates *states =
909
                             DO_UPCAST(ExternalSnapshotStates, common, common);
910

  
876 911
    /* This removes our old bs from the bdrv_states, and adds the new bs */
877 912
    bdrv_append(states->new_bs, states->old_bs);
878 913
    /* We don't need (or want) to use the transactional
......
882 917
                NULL);
883 918
}
884 919

  
885
static void external_snapshot_abort(BlkTransactionStates *states)
920
static void external_snapshot_abort(BlkTransactionStates *common)
886 921
{
922
    ExternalSnapshotStates *states =
923
                             DO_UPCAST(ExternalSnapshotStates, common, common);
887 924
    if (states->new_bs) {
888 925
        bdrv_delete(states->new_bs);
889 926
    }
890 927
}
891 928

  
929
static const BdrvActionOps actions[] = {
930
    [BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC] = {
931
        .instance_size = sizeof(ExternalSnapshotStates),
932
        .prepare  = external_snapshot_prepare,
933
        .commit   = external_snapshot_commit,
934
        .abort = external_snapshot_abort,
935
    },
936
};
937

  
892 938
/*
893 939
 * 'Atomic' group snapshots.  The snapshots are taken as a set, and if any fail
894 940
 *  then we do not pivot any of the devices in the group, and abandon the
......
909 955
    /* We don't do anything in this loop that commits us to the snapshot */
910 956
    while (NULL != dev_entry) {
911 957
        BlockdevAction *dev_info = NULL;
958
        const BdrvActionOps *ops;
912 959

  
913 960
        dev_info = dev_entry->value;
914 961
        dev_entry = dev_entry->next;
915 962

  
916
        states = g_malloc0(sizeof(BlkTransactionStates));
963
        assert(dev_info->kind < ARRAY_SIZE(actions));
964

  
965
        ops = &actions[dev_info->kind];
966
        states = g_malloc0(ops->instance_size);
967
        states->ops = ops;
968
        states->action = dev_info;
917 969
        QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry);
918 970

  
919
        switch (dev_info->kind) {
920
        case BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
921
            external_snapshot_prepare(dev_info, states, errp);
922
            if (error_is_set(&local_err)) {
923
                error_propagate(errp, local_err);
924
                goto delete_and_fail;
925
            }
926
            break;
927
        default:
928
            abort();
971
        states->ops->prepare(states, &local_err);
972
        if (error_is_set(&local_err)) {
973
            error_propagate(errp, local_err);
974
            goto delete_and_fail;
929 975
        }
930

  
931 976
    }
932 977

  
933

  
934
    /* Now we are going to do the actual pivot.  Everything up to this point
935
     * is reversible, but we are committed at this point */
936 978
    QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
937
        external_snapshot_commit(states);
979
        states->ops->commit(states);
938 980
    }
939 981

  
940 982
    /* success */
......
946 988
    * the original bs for all images
947 989
    */
948 990
    QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
949
        external_snapshot_abort(states);
991
        if (states->ops->abort) {
992
            states->ops->abort(states);
993
        }
950 994
    }
951 995
exit:
952 996
    QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) {
997
        if (states->ops->clean) {
998
            states->ops->clean(states);
999
        }
953 1000
        g_free(states);
954 1001
    }
955 1002
}

Also available in: Unified diff