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:
parent
1859a0eb8b
commit
cb80ffc1de
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) &&
|
||||
|
Loading…
Reference in New Issue
Block a user