mirror of
git://git.proxmox.com/git/proxmox-backup-qemu.git
synced 2025-02-25 01:57:34 +03:00
add state serializing and loading functions
For dirty-bitmap migration, QEMU also needs to move the static state of the library to the target. proxmox_{import,export}_state provide a means of accessing said data in a serialized fashion. QEMU treats the state as some unknown quantity of bytes and the result does not need to be human-readable, so we encode it with 'bincode', which is based on serde. Since the quantity is only known *after* serialization, we have to allocate the buffer ourselves. This is handled by Box::leak-ing a Rust allocated buffer and cleaning up via the explicit proxmox_free_state_buf function. Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
This commit is contained in:
parent
58437c69e4
commit
c28f578e09
@ -32,3 +32,4 @@ proxmox-backup = { git = "git://git.proxmox.com/git/proxmox-backup.git", tag = "
|
||||
#proxmox-backup = { path = "../proxmox-backup" }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "0.2.9", features = [ "blocking", "fs", "io-util", "macros", "rt-threaded", "signal", "stream", "tcp", "time", "uds" ] }
|
||||
bincode = "1.0"
|
||||
|
@ -263,6 +263,26 @@ void proxmox_backup_write_data_async(ProxmoxBackupHandle *handle,
|
||||
int *result,
|
||||
char **error);
|
||||
|
||||
/**
|
||||
* Serialize all state data into a byte buffer. Can be loaded again with
|
||||
* proxmox_import_state. Use for migration for example.
|
||||
*
|
||||
* Length of the returned buffer is written to buf_size. Returned buffer must
|
||||
* be freed with proxmox_free_state_buf.
|
||||
*/
|
||||
uint8_t *proxmox_export_state(uintptr_t *buf_size);
|
||||
|
||||
/**
|
||||
* Free a buffer acquired from proxmox_export_state.
|
||||
*/
|
||||
void proxmox_free_state_buf(uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Load state serialized by proxmox_export_state. If loading fails, a message
|
||||
* will be logged to stderr, but the function will not fail.
|
||||
*/
|
||||
void proxmox_import_state(const uint8_t *buf, uintptr_t buf_size);
|
||||
|
||||
/**
|
||||
* Open connection to the backup server (sync)
|
||||
*
|
||||
|
@ -16,6 +16,9 @@ use crate::upload_queue::*;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static!{
|
||||
// Note: Any state stored here that needs to be sent along with migration
|
||||
// needs to be specified in (de)serialize_state as well!
|
||||
|
||||
static ref PREVIOUS_CSUMS: Mutex<HashMap<String, [u8;32]>> = {
|
||||
Mutex::new(HashMap::new())
|
||||
};
|
||||
@ -35,6 +38,22 @@ pub struct ImageUploadInfo {
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn serialize_state() -> Vec<u8> {
|
||||
let prev_csums = &*PREVIOUS_CSUMS.lock().unwrap();
|
||||
let prev_crypt_digest = &*PREVIOUS_CRYPT_CONFIG_DIGEST.lock().unwrap();
|
||||
bincode::serialize(&(prev_csums, prev_crypt_digest)).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize_state(data: &[u8]) -> Result<(), Error> {
|
||||
let (prev_csums, prev_crypt_digest) = bincode::deserialize(data)?;
|
||||
let mut prev_csums_guard = PREVIOUS_CSUMS.lock().unwrap();
|
||||
let mut prev_crypt_digest_guard = PREVIOUS_CRYPT_CONFIG_DIGEST.lock().unwrap();
|
||||
*prev_csums_guard = prev_csums;
|
||||
*prev_crypt_digest_guard = prev_crypt_digest;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// Note: We alway register/upload a chunk containing zeros
|
||||
async fn register_zero_chunk(
|
||||
client: Arc<BackupWriter>,
|
||||
|
34
src/lib.rs
34
src/lib.rs
@ -967,3 +967,37 @@ pub extern "C" fn proxmox_restore_read_image_at_async(
|
||||
callback_info.send_result(result);
|
||||
});
|
||||
}
|
||||
|
||||
/// Serialize all state data into a byte buffer. Can be loaded again with
|
||||
/// proxmox_import_state. Use for migration for example.
|
||||
///
|
||||
/// Length of the returned buffer is written to buf_size. Returned buffer must
|
||||
/// be freed with proxmox_free_state_buf.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn proxmox_export_state(buf_size: *mut usize) -> *mut u8 {
|
||||
let data = commands::serialize_state().into_boxed_slice();
|
||||
unsafe { *buf_size = data.len(); }
|
||||
Box::leak(data).as_mut_ptr()
|
||||
}
|
||||
|
||||
/// Load state serialized by proxmox_export_state. If loading fails, a message
|
||||
/// will be logged to stderr, but the function will not fail.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn proxmox_import_state(buf: *const u8, buf_size: usize) {
|
||||
let data = unsafe { std::slice::from_raw_parts(buf, buf_size) };
|
||||
// ignore errors, just log what happened
|
||||
if let Err(err) = commands::deserialize_state(data) {
|
||||
eprintln!("error deserializing PBS state - {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
/// Free a buffer acquired from proxmox_export_state.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn proxmox_free_state_buf(buf: *mut u8) {
|
||||
if !buf.is_null() {
|
||||
unsafe { Box::from_raw(buf); }
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user