pbs-config: use new SharedMemory helpers from proxmox-shared-memory crate
depend on proxmox-shared-memory crate. Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
		
							
								
								
									
										1
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@ -62,6 +62,7 @@ Build-Depends: debhelper (>= 12),
 | 
			
		||||
 librust-proxmox-schema-1+default-dev,
 | 
			
		||||
 librust-proxmox-schema-1+upid-api-impl-dev,
 | 
			
		||||
 librust-proxmox-section-config-1+default-dev,
 | 
			
		||||
 librust-proxmox-shared-memory-dev,
 | 
			
		||||
 librust-proxmox-tfa-1+default-dev,
 | 
			
		||||
 librust-proxmox-tfa-1+u2f-dev,
 | 
			
		||||
 librust-proxmox-time-1+default-dev,
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ proxmox-router = { version = "1.1", default-features = false }
 | 
			
		||||
proxmox-schema = "1"
 | 
			
		||||
proxmox-section-config = "1"
 | 
			
		||||
proxmox-time = "1"
 | 
			
		||||
proxmox-shared-memory = "0.1.0"
 | 
			
		||||
 | 
			
		||||
pbs-api-types = { path = "../pbs-api-types" }
 | 
			
		||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ use proxmox_time::epoch_i64;
 | 
			
		||||
use pbs_api_types::{Authid, Userid, User, ApiToken, ROLE_ADMIN};
 | 
			
		||||
 | 
			
		||||
use crate::acl::{AclTree, ROLE_NAMES};
 | 
			
		||||
use crate::memcom::Memcom;
 | 
			
		||||
use crate::ConfigVersionCache;
 | 
			
		||||
 | 
			
		||||
/// Cache User/Group/Token/Acl configuration data for fast permission tests
 | 
			
		||||
pub struct CachedUserInfo {
 | 
			
		||||
@ -38,8 +38,8 @@ impl CachedUserInfo {
 | 
			
		||||
    pub fn new() -> Result<Arc<Self>, Error> {
 | 
			
		||||
        let now = epoch_i64();
 | 
			
		||||
 | 
			
		||||
        let memcom = Memcom::new()?;
 | 
			
		||||
        let user_cache_generation = memcom.user_cache_generation();
 | 
			
		||||
        let version_cache = ConfigVersionCache::new()?;
 | 
			
		||||
        let user_cache_generation = version_cache.user_cache_generation();
 | 
			
		||||
 | 
			
		||||
        { // limit scope
 | 
			
		||||
            let cache = CACHED_CONFIG.read().unwrap();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										121
									
								
								pbs-config/src/config_version_cache.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								pbs-config/src/config_version_cache.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use std::sync::atomic::{AtomicUsize, Ordering};
 | 
			
		||||
use std::mem::MaybeUninit;
 | 
			
		||||
 | 
			
		||||
use anyhow::{bail, Error};
 | 
			
		||||
use once_cell::sync::OnceCell;
 | 
			
		||||
use nix::sys::stat::Mode;
 | 
			
		||||
 | 
			
		||||
use proxmox::tools::fs::{create_path, CreateOptions};
 | 
			
		||||
 | 
			
		||||
// openssl::sha::sha256(b"Proxmox Backup ConfigVersionCache v1.0")[0..8];
 | 
			
		||||
pub const PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0: [u8; 8] = [25, 198, 168, 230, 154, 132, 143, 131];
 | 
			
		||||
 | 
			
		||||
const FILE_PATH: &str = pbs_buildcfg::rundir!("/shmem/config-versions");
 | 
			
		||||
 | 
			
		||||
use proxmox_shared_memory::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct ConfigVersionCacheData {
 | 
			
		||||
    magic: [u8; 8],
 | 
			
		||||
    // User (user.cfg) cache generation/version.
 | 
			
		||||
    user_cache_generation: AtomicUsize,
 | 
			
		||||
    // Traffic control (traffic-control.cfg) generation/version.
 | 
			
		||||
    traffic_control_generation: AtomicUsize,
 | 
			
		||||
 | 
			
		||||
    // Add further atomics here (and reduce padding size)
 | 
			
		||||
 | 
			
		||||
    padding: [u8; 4096 - 3*8],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl Init for ConfigVersionCacheData {
 | 
			
		||||
    fn initialize(this: &mut MaybeUninit<Self>) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let me = &mut *this.as_mut_ptr();
 | 
			
		||||
            me.magic = PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn check_type_magic(this: &MaybeUninit<Self>) -> Result<(), Error> {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let me = &*this.as_ptr();
 | 
			
		||||
            if me.magic != PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0 {
 | 
			
		||||
                bail!("ConfigVersionCache: wrong magic number");
 | 
			
		||||
            }
 | 
			
		||||
            Ok(())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub struct ConfigVersionCache {
 | 
			
		||||
    shmem: SharedMemory<ConfigVersionCacheData>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static INSTANCE: OnceCell<Arc< ConfigVersionCache>> = OnceCell::new();
 | 
			
		||||
 | 
			
		||||
impl ConfigVersionCache {
 | 
			
		||||
 | 
			
		||||
    /// Open the memory based communication channel singleton.
 | 
			
		||||
    pub fn new() -> Result<Arc<Self>, Error> {
 | 
			
		||||
        INSTANCE.get_or_try_init(Self::open).map(Arc::clone)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Actual work of `new`:
 | 
			
		||||
    fn open() -> Result<Arc<Self>, Error> {
 | 
			
		||||
        let user = crate::backup_user()?;
 | 
			
		||||
 | 
			
		||||
        let dir_opts = CreateOptions::new()
 | 
			
		||||
            .perm(Mode::from_bits_truncate(0o770))
 | 
			
		||||
            .owner(user.uid)
 | 
			
		||||
            .group(user.gid);
 | 
			
		||||
 | 
			
		||||
        let file_path = Path::new(FILE_PATH);
 | 
			
		||||
        let dir_path = file_path.parent().unwrap();
 | 
			
		||||
        
 | 
			
		||||
        create_path(
 | 
			
		||||
            dir_path,
 | 
			
		||||
            Some(dir_opts.clone()),
 | 
			
		||||
            Some(dir_opts))?;
 | 
			
		||||
 | 
			
		||||
        let file_opts = CreateOptions::new()
 | 
			
		||||
            .perm(Mode::from_bits_truncate(0o660))
 | 
			
		||||
            .owner(user.uid)
 | 
			
		||||
            .group(user.gid);
 | 
			
		||||
 | 
			
		||||
        let shmem: SharedMemory<ConfigVersionCacheData> =
 | 
			
		||||
            SharedMemory::open(file_path, file_opts)?;
 | 
			
		||||
 | 
			
		||||
        Ok(Arc::new(Self { shmem }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the user cache generation number.
 | 
			
		||||
    pub fn user_cache_generation(&self) -> usize {
 | 
			
		||||
        self.shmem.data()
 | 
			
		||||
            .user_cache_generation.load(Ordering::Acquire)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Increase the user cache generation number.
 | 
			
		||||
    pub fn increase_user_cache_generation(&self) {
 | 
			
		||||
        self.shmem.data()
 | 
			
		||||
            .user_cache_generation
 | 
			
		||||
            .fetch_add(1, Ordering::AcqRel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the traffic control generation number.
 | 
			
		||||
    pub fn traffic_control_generation(&self) -> usize {
 | 
			
		||||
        self.shmem.data()
 | 
			
		||||
            .traffic_control_generation.load(Ordering::Acquire)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Increase the traffic control generation number.
 | 
			
		||||
    pub fn increase_traffic_control_generation(&self) {
 | 
			
		||||
        self.shmem.data()
 | 
			
		||||
            .traffic_control_generation
 | 
			
		||||
            .fetch_add(1, Ordering::AcqRel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -16,7 +16,8 @@ pub mod traffic_control;
 | 
			
		||||
pub mod user;
 | 
			
		||||
pub mod verify;
 | 
			
		||||
 | 
			
		||||
pub mod memcom;
 | 
			
		||||
mod config_version_cache;
 | 
			
		||||
pub use config_version_cache::ConfigVersionCache;
 | 
			
		||||
 | 
			
		||||
use anyhow::{format_err, Error};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,98 +0,0 @@
 | 
			
		||||
//! Memory based communication channel between proxy & daemon for things such as cache
 | 
			
		||||
//! invalidation.
 | 
			
		||||
 | 
			
		||||
use std::os::unix::io::AsRawFd;
 | 
			
		||||
use std::sync::atomic::{AtomicUsize, Ordering};
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use anyhow::Error;
 | 
			
		||||
use nix::fcntl::OFlag;
 | 
			
		||||
use nix::sys::mman::{MapFlags, ProtFlags};
 | 
			
		||||
use nix::sys::stat::Mode;
 | 
			
		||||
use once_cell::sync::OnceCell;
 | 
			
		||||
 | 
			
		||||
use proxmox::tools::fs::CreateOptions;
 | 
			
		||||
use proxmox::tools::mmap::Mmap;
 | 
			
		||||
 | 
			
		||||
/// In-memory communication channel.
 | 
			
		||||
pub struct Memcom {
 | 
			
		||||
    mmap: Mmap<u8>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct Head {
 | 
			
		||||
    // User (user.cfg) cache generation/version.
 | 
			
		||||
    user_cache_generation: AtomicUsize,
 | 
			
		||||
    // Traffic control (traffic-control.cfg) generation/version.
 | 
			
		||||
    traffic_control_generation: AtomicUsize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static INSTANCE: OnceCell<Arc<Memcom>> = OnceCell::new();
 | 
			
		||||
 | 
			
		||||
const MEMCOM_FILE_PATH: &str = pbs_buildcfg::rundir!("/proxmox-backup-memcom");
 | 
			
		||||
const EMPTY_PAGE: [u8; 4096] = [0u8; 4096];
 | 
			
		||||
 | 
			
		||||
impl Memcom {
 | 
			
		||||
    /// Open the memory based communication channel singleton.
 | 
			
		||||
    pub fn new() -> Result<Arc<Self>, Error> {
 | 
			
		||||
        INSTANCE.get_or_try_init(Self::open).map(Arc::clone)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Actual work of `new`:
 | 
			
		||||
    fn open() -> Result<Arc<Self>, Error> {
 | 
			
		||||
        let user = crate::backup_user()?;
 | 
			
		||||
        let options = CreateOptions::new()
 | 
			
		||||
            .perm(Mode::from_bits_truncate(0o660))
 | 
			
		||||
            .owner(user.uid)
 | 
			
		||||
            .group(user.gid);
 | 
			
		||||
 | 
			
		||||
        let file = proxmox::tools::fs::atomic_open_or_create_file(
 | 
			
		||||
            MEMCOM_FILE_PATH,
 | 
			
		||||
            OFlag::O_RDWR | OFlag::O_CLOEXEC,
 | 
			
		||||
            &EMPTY_PAGE,
 | 
			
		||||
            options,
 | 
			
		||||
            true,
 | 
			
		||||
        )?;
 | 
			
		||||
 | 
			
		||||
        let mmap = unsafe {
 | 
			
		||||
            Mmap::<u8>::map_fd(
 | 
			
		||||
                file.as_raw_fd(),
 | 
			
		||||
                0,
 | 
			
		||||
                4096,
 | 
			
		||||
                ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
 | 
			
		||||
                MapFlags::MAP_SHARED | MapFlags::MAP_NORESERVE | MapFlags::MAP_POPULATE,
 | 
			
		||||
            )?
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Ok(Arc::new(Self { mmap }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shortcut to get the mapped `Head` as a `Head`.
 | 
			
		||||
    fn head(&self) -> &Head {
 | 
			
		||||
        unsafe { &*(self.mmap.as_ptr() as *const u8 as *const Head) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the user cache generation number.
 | 
			
		||||
    pub fn user_cache_generation(&self) -> usize {
 | 
			
		||||
        self.head().user_cache_generation.load(Ordering::Acquire)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Increase the user cache generation number.
 | 
			
		||||
    pub fn increase_user_cache_generation(&self) {
 | 
			
		||||
        self.head()
 | 
			
		||||
            .user_cache_generation
 | 
			
		||||
            .fetch_add(1, Ordering::AcqRel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the traffic control generation number.
 | 
			
		||||
    pub fn traffic_control_generation(&self) -> usize {
 | 
			
		||||
        self.head().traffic_control_generation.load(Ordering::Acquire)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Increase the traffic control generation number.
 | 
			
		||||
    pub fn increase_traffic_control_generation(&self) {
 | 
			
		||||
        self.head()
 | 
			
		||||
            .traffic_control_generation
 | 
			
		||||
            .fetch_add(1, Ordering::AcqRel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -10,7 +10,7 @@ use pbs_api_types::{TrafficControlRule, TRAFFIC_CONTROL_ID_SCHEMA};
 | 
			
		||||
 | 
			
		||||
use proxmox_section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin};
 | 
			
		||||
 | 
			
		||||
use crate::memcom::Memcom;
 | 
			
		||||
use crate::ConfigVersionCache;
 | 
			
		||||
use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard};
 | 
			
		||||
 | 
			
		||||
lazy_static! {
 | 
			
		||||
@ -57,10 +57,10 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
 | 
			
		||||
    let raw = CONFIG.write(TRAFFIC_CONTROL_CFG_FILENAME, &config)?;
 | 
			
		||||
    replace_backup_config(TRAFFIC_CONTROL_CFG_FILENAME, raw.as_bytes())?;
 | 
			
		||||
 | 
			
		||||
    // increase traffic control generation
 | 
			
		||||
    // increase traffic control version
 | 
			
		||||
    // We use this in TrafficControlCache
 | 
			
		||||
    let memcom = Memcom::new()?;
 | 
			
		||||
    memcom.increase_traffic_control_generation();
 | 
			
		||||
    let version_cache = ConfigVersionCache::new()?;
 | 
			
		||||
    version_cache.increase_traffic_control_generation();
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ use pbs_api_types::{
 | 
			
		||||
    Authid, Userid, ApiToken, User,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::memcom::Memcom;
 | 
			
		||||
use crate::ConfigVersionCache;
 | 
			
		||||
 | 
			
		||||
use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard};
 | 
			
		||||
 | 
			
		||||
@ -120,10 +120,10 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
 | 
			
		||||
    let raw = CONFIG.write(USER_CFG_FILENAME, &config)?;
 | 
			
		||||
    replace_backup_config(USER_CFG_FILENAME, raw.as_bytes())?;
 | 
			
		||||
 | 
			
		||||
    // increase user cache generation
 | 
			
		||||
    // increase user version
 | 
			
		||||
    // We use this in CachedUserInfo
 | 
			
		||||
    let memcom = Memcom::new()?;
 | 
			
		||||
    memcom.increase_user_cache_generation();
 | 
			
		||||
    let version_cache = ConfigVersionCache::new()?;
 | 
			
		||||
    version_cache.increase_user_cache_generation();
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ use proxmox_time::TmEditor;
 | 
			
		||||
 | 
			
		||||
use pbs_api_types::TrafficControlRule;
 | 
			
		||||
 | 
			
		||||
use pbs_config::memcom::Memcom;
 | 
			
		||||
use pbs_config::ConfigVersionCache;
 | 
			
		||||
 | 
			
		||||
struct ParsedTcRule {
 | 
			
		||||
    config: TrafficControlRule, // original rule config
 | 
			
		||||
@ -97,15 +97,15 @@ impl TrafficControlCache {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn reload(&mut self, now: i64) {
 | 
			
		||||
        let memcom = match Memcom::new() {
 | 
			
		||||
            Ok(memcom) => memcom,
 | 
			
		||||
        let version_cache = match ConfigVersionCache::new() {
 | 
			
		||||
            Ok(cache) => cache,
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                log::error!("TrafficControlCache::reload failed in Memcom::new: {}", err);
 | 
			
		||||
                log::error!("TrafficControlCache::reload failed in ConfigVersionCache::new: {}", err);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let traffic_control_generation = memcom.traffic_control_generation();
 | 
			
		||||
        let traffic_control_generation = version_cache.traffic_control_generation();
 | 
			
		||||
 | 
			
		||||
        if (self.last_update != 0) &&
 | 
			
		||||
            (traffic_control_generation == self.last_traffic_control_generation) &&
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user