mirror of
https://git.proxmox.com/git/proxmox-backup-qemu
synced 2025-10-04 22:11:27 +00: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" }
|
#proxmox-backup = { path = "../proxmox-backup" }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tokio = { version = "0.2.9", features = [ "blocking", "fs", "io-util", "macros", "rt-threaded", "signal", "stream", "tcp", "time", "uds" ] }
|
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,
|
int *result,
|
||||||
char **error);
|
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)
|
* Open connection to the backup server (sync)
|
||||||
*
|
*
|
||||||
|
@ -16,6 +16,9 @@ use crate::upload_queue::*;
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::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]>> = {
|
static ref PREVIOUS_CSUMS: Mutex<HashMap<String, [u8;32]>> = {
|
||||||
Mutex::new(HashMap::new())
|
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
|
// Note: We alway register/upload a chunk containing zeros
|
||||||
async fn register_zero_chunk(
|
async fn register_zero_chunk(
|
||||||
client: Arc<BackupWriter>,
|
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);
|
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…
Reference in New Issue
Block a user