/*
 * QEMU migration vmstate registration
 *
 * Copyright IBM, Corp. 2008
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
 */

#ifndef MIGRATION_REGISTER_H
#define MIGRATION_REGISTER_H

#include "hw/vmstate-if.h"

/**
 * struct SaveVMHandlers: handler structure to finely control
 * migration of complex subsystems and devices, such as RAM, block and
 * VFIO.
 */
typedef struct SaveVMHandlers {

    /* The following handlers run inside the BQL. */

    /**
     * @save_state
     *
     * Saves state section on the source using the latest state format
     * version.
     *
     * Legacy method. Should be deprecated when all users are ported
     * to VMStateDescription.
     *
     * @f: QEMUFile where to send the data
     * @opaque: data pointer passed to register_savevm_live()
     */
    void (*save_state)(QEMUFile *f, void *opaque);

    /**
     * @save_prepare
     *
     * Called early, even before migration starts, and can be used to
     * perform early checks.
     *
     * @opaque: data pointer passed to register_savevm_live()
     * @errp: pointer to Error*, to store an error if it happens.
     *
     * Returns zero to indicate success and negative for error
     */
    int (*save_prepare)(void *opaque, Error **errp);

    /**
     * @save_setup
     *
     * Initializes the data structures on the source and transmits
     * first section containing information on the device
     *
     * @f: QEMUFile where to send the data
     * @opaque: data pointer passed to register_savevm_live()
     * @errp: pointer to Error*, to store an error if it happens.
     *
     * Returns zero to indicate success and negative for error
     */
    int (*save_setup)(QEMUFile *f, void *opaque, Error **errp);

    /**
     * @save_cleanup
     *
     * Uninitializes the data structures on the source.
     * Note that this handler can be called even if save_setup
     * wasn't called earlier.
     *
     * @opaque: data pointer passed to register_savevm_live()
     */
    void (*save_cleanup)(void *opaque);

    /**
     * @save_complete
     *
     * Transmits the last section for the device containing any
     * remaining data at the end phase of migration.
     *
     * For precopy, this will be invoked _during_ the switchover phase
     * after source VM is stopped.
     *
     * For postcopy, this will be invoked _after_ the switchover phase
     * (except some very unusual cases, like PMEM ramblocks), while
     * destination VM can be running.
     *
     * @f: QEMUFile where to send the data
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns zero to indicate success and negative for error
     */
    int (*save_complete)(QEMUFile *f, void *opaque);

    /**
     * @save_complete_precopy_thread (invoked in a separate thread)
     *
     * Called at the end of a precopy phase from a separate worker thread
     * in configurations where multifd device state transfer is supported
     * in order to perform asynchronous transmission of the remaining data in
     * parallel with @save_complete handlers.
     * When postcopy is enabled, devices that support postcopy will skip this
     * step.
     *
     * @d: a #SaveCompletePrecopyThreadData containing parameters that the
     * handler may need, including this device section idstr and instance_id,
     * and opaque data pointer passed to register_savevm_live().
     * @errp: pointer to Error*, to store an error if it happens.
     *
     * Returns true to indicate success and false for errors.
     */
    SaveCompletePrecopyThreadHandler save_complete_precopy_thread;

    /* This runs both outside and inside the BQL.  */

    /**
     * @is_active
     *
     * Will skip a state section if not active
     *
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns true if state section is active else false
     */
    bool (*is_active)(void *opaque);

    /**
     * @has_postcopy
     *
     * Checks if a device supports postcopy
     *
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns true for postcopy support else false
     */
    bool (*has_postcopy)(void *opaque);

    /**
     * @is_active_iterate
     *
     * As #SaveVMHandlers.is_active(), will skip an inactive state
     * section in qemu_savevm_state_iterate.
     *
     * For example, it is needed for only-postcopy-states, which needs
     * to be handled by qemu_savevm_state_setup() and
     * qemu_savevm_state_pending(), but do not need iterations until
     * not in postcopy stage.
     *
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns true if state section is active else false
     */
    bool (*is_active_iterate)(void *opaque);

    /* This runs outside the BQL in the migration case, and
     * within the lock in the savevm case.  The callback had better only
     * use data that is local to the migration thread or protected
     * by other locks.
     */

    /**
     * @save_live_iterate
     *
     * Should send a chunk of data until the point that stream
     * bandwidth limits tell it to stop. Each call generates one
     * section.
     *
     * @f: QEMUFile where to send the data
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns 0 to indicate that there is still more data to send,
     *         1 that there is no more data to send and
     *         negative to indicate an error.
     */
    int (*save_live_iterate)(QEMUFile *f, void *opaque);

    /* This runs outside the BQL!  */

    /**
     * @save_postcopy_prepare
     *
     * This hook will be invoked on the source side right before switching
     * to postcopy (before VM stopped).
     *
     * @f:      QEMUFile where to send the data
     * @opaque: Data pointer passed to register_savevm_live()
     * @errp:   Error** used to report error message
     *
     * Returns: true if succeeded, false if error occured.  When false is
     * returned, @errp must be set.
     */
    bool (*save_postcopy_prepare)(QEMUFile *f, void *opaque, Error **errp);

    /**
     * @state_pending_estimate
     *
     * This estimates the remaining data to transfer
     *
     * Sum of @can_postcopy and @must_postcopy is the whole amount of
     * pending data.
     *
     * @opaque: data pointer passed to register_savevm_live()
     * @must_precopy: amount of data that must be migrated in precopy
     *                or in stopped state, i.e. that must be migrated
     *                before target start.
     * @can_postcopy: amount of data that can be migrated in postcopy
     *                or in stopped state, i.e. after target start.
     *                Some can also be migrated during precopy (RAM).
     *                Some must be migrated after source stops
     *                (block-dirty-bitmap)
     */
    void (*state_pending_estimate)(void *opaque, uint64_t *must_precopy,
                                   uint64_t *can_postcopy);

    /**
     * @state_pending_exact
     *
     * This calculates the exact remaining data to transfer
     *
     * Sum of @can_postcopy and @must_postcopy is the whole amount of
     * pending data.
     *
     * @opaque: data pointer passed to register_savevm_live()
     * @must_precopy: amount of data that must be migrated in precopy
     *                or in stopped state, i.e. that must be migrated
     *                before target start.
     * @can_postcopy: amount of data that can be migrated in postcopy
     *                or in stopped state, i.e. after target start.
     *                Some can also be migrated during precopy (RAM).
     *                Some must be migrated after source stops
     *                (block-dirty-bitmap)
     */
    void (*state_pending_exact)(void *opaque, uint64_t *must_precopy,
                                uint64_t *can_postcopy);

    /**
     * @load_state
     *
     * Load sections generated by any of the save functions that
     * generate sections.
     *
     * Legacy method. Should be deprecated when all users are ported
     * to VMStateDescription.
     *
     * @f: QEMUFile where to receive the data
     * @opaque: data pointer passed to register_savevm_live()
     * @version_id: the maximum version_id supported
     *
     * Returns zero to indicate success and negative for error
     */
    int (*load_state)(QEMUFile *f, void *opaque, int version_id);

    /**
     * @load_state_buffer (invoked outside the BQL)
     *
     * Load device state buffer provided to qemu_loadvm_load_state_buffer().
     *
     * @opaque: data pointer passed to register_savevm_live()
     * @buf: the data buffer to load
     * @len: the data length in buffer
     * @errp: pointer to Error*, to store an error if it happens.
     *
     * Returns true to indicate success and false for errors.
     */
    bool (*load_state_buffer)(void *opaque, char *buf, size_t len,
                              Error **errp);

    /**
     * @load_setup
     *
     * Initializes the data structures on the destination.
     *
     * @f: QEMUFile where to receive the data
     * @opaque: data pointer passed to register_savevm_live()
     * @errp: pointer to Error*, to store an error if it happens.
     *
     * Returns zero to indicate success and negative for error
     */
    int (*load_setup)(QEMUFile *f, void *opaque, Error **errp);

    /**
     * @load_cleanup
     *
     * Uninitializes the data structures on the destination.
     * Note that this handler can be called even if load_setup
     * wasn't called earlier.
     *
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns zero to indicate success and negative for error
     */
    int (*load_cleanup)(void *opaque);

    /**
     * @resume_prepare
     *
     * Called when postcopy migration wants to resume from failure
     *
     * @s: Current migration state
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns zero to indicate success and negative for error
     */
    int (*resume_prepare)(MigrationState *s, void *opaque);

    /**
     * @switchover_ack_needed
     *
     * Checks if switchover ack should be used. Called only on
     * destination.
     *
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns true if switchover ack should be used and false
     * otherwise
     */
    bool (*switchover_ack_needed)(void *opaque);

    /**
     * @switchover_start
     *
     * Notifies that the switchover has started. Called only on
     * the destination.
     *
     * @opaque: data pointer passed to register_savevm_live()
     *
     * Returns zero to indicate success and negative for error
     */
    int (*switchover_start)(void *opaque);
} SaveVMHandlers;

/**
 * register_savevm_live: Register a set of custom migration handlers
 *
 * @idstr: state section identifier
 * @instance_id: instance id
 * @version_id: version id supported
 * @ops: SaveVMHandlers structure
 * @opaque: data pointer passed to SaveVMHandlers handlers
 */
int register_savevm_live(const char *idstr,
                         uint32_t instance_id,
                         int version_id,
                         const SaveVMHandlers *ops,
                         void *opaque);

/**
 * unregister_savevm: Unregister custom migration handlers
 *
 * @obj: object associated with state section
 * @idstr:  state section identifier
 * @opaque: data pointer passed to register_savevm_live()
 */
void unregister_savevm(VMStateIf *obj, const char *idstr, void *opaque);

#endif
