]> git.proxmox.com Git - proxmox-backup.git/blob - src/tools/memcom.rs
cleanup User configuration: use Updater
[proxmox-backup.git] / src / tools / memcom.rs
1 //! Memory based communication channel between proxy & daemon for things such as cache
2 //! invalidation.
3
4 use std::os::unix::io::AsRawFd;
5 use std::sync::atomic::{AtomicUsize, Ordering};
6 use std::sync::Arc;
7
8 use anyhow::Error;
9 use nix::fcntl::OFlag;
10 use nix::sys::mman::{MapFlags, ProtFlags};
11 use nix::sys::stat::Mode;
12 use once_cell::sync::OnceCell;
13
14 use proxmox::tools::fs::CreateOptions;
15 use proxmox::tools::mmap::Mmap;
16
17 /// In-memory communication channel.
18 pub struct Memcom {
19 mmap: Mmap<u8>,
20 }
21
22 #[repr(C)]
23 struct Head {
24 // User (user.cfg) cache generation/version.
25 user_cache_generation: AtomicUsize,
26 }
27
28 static INSTANCE: OnceCell<Arc<Memcom>> = OnceCell::new();
29
30 const MEMCOM_FILE_PATH: &str = pbs_buildcfg::rundir!("/proxmox-backup-memcom");
31 const EMPTY_PAGE: [u8; 4096] = [0u8; 4096];
32
33 impl Memcom {
34 /// Open the memory based communication channel singleton.
35 pub fn new() -> Result<Arc<Self>, Error> {
36 INSTANCE.get_or_try_init(Self::open).map(Arc::clone)
37 }
38
39 // Actual work of `new`:
40 fn open() -> Result<Arc<Self>, Error> {
41 let user = pbs_config::backup_user()?;
42 let options = CreateOptions::new()
43 .perm(Mode::from_bits_truncate(0o660))
44 .owner(user.uid)
45 .group(user.gid);
46
47 let file = proxmox::tools::fs::atomic_open_or_create_file(
48 MEMCOM_FILE_PATH,
49 OFlag::O_RDWR | OFlag::O_CLOEXEC,
50 &EMPTY_PAGE, options)?;
51
52 let mmap = unsafe {
53 Mmap::<u8>::map_fd(
54 file.as_raw_fd(),
55 0,
56 4096,
57 ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
58 MapFlags::MAP_SHARED | MapFlags::MAP_NORESERVE | MapFlags::MAP_POPULATE,
59 )?
60 };
61
62 Ok(Arc::new(Self { mmap }))
63 }
64
65 // Shortcut to get the mapped `Head` as a `Head`.
66 fn head(&self) -> &Head {
67 unsafe { &*(self.mmap.as_ptr() as *const u8 as *const Head) }
68 }
69
70 /// Returns the user cache generation number.
71 pub fn user_cache_generation(&self) -> usize {
72 self.head().user_cache_generation.load(Ordering::Acquire)
73 }
74
75 /// Increase the user cache generation number.
76 pub fn increase_user_cache_generation(&self) {
77 self.head()
78 .user_cache_generation
79 .fetch_add(1, Ordering::AcqRel);
80 }
81 }