]>
Commit | Line | Data |
---|---|---|
fda19dcc DM |
1 | //! Memory based communication channel between proxy & daemon for things such as cache |
2 | //! invalidation. | |
3 | ||
fda19dcc DM |
4 | use std::os::unix::io::AsRawFd; |
5 | use std::sync::atomic::{AtomicUsize, Ordering}; | |
6 | use std::sync::Arc; | |
7 | ||
7526d864 | 8 | use anyhow::Error; |
fda19dcc DM |
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 | ||
7526d864 | 14 | use proxmox::tools::fs::CreateOptions; |
fda19dcc DM |
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 | ||
835d0e5d | 28 | static INSTANCE: OnceCell<Arc<Memcom>> = OnceCell::new(); |
fda19dcc | 29 | |
af06decd | 30 | const MEMCOM_FILE_PATH: &str = pbs_buildcfg::rundir!("/proxmox-backup-memcom"); |
7526d864 | 31 | const EMPTY_PAGE: [u8; 4096] = [0u8; 4096]; |
fda19dcc DM |
32 | |
33 | impl Memcom { | |
fda19dcc | 34 | /// Open the memory based communication channel singleton. |
835d0e5d | 35 | pub fn new() -> Result<Arc<Self>, Error> { |
fda19dcc DM |
36 | INSTANCE.get_or_try_init(Self::open).map(Arc::clone) |
37 | } | |
38 | ||
39 | // Actual work of `new`: | |
835d0e5d | 40 | fn open() -> Result<Arc<Self>, Error> { |
21211748 | 41 | let user = pbs_config::backup_user()?; |
7526d864 DM |
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)?; | |
fda19dcc DM |
51 | |
52 | let mmap = unsafe { | |
53 | Mmap::<u8>::map_fd( | |
7526d864 | 54 | file.as_raw_fd(), |
fda19dcc DM |
55 | 0, |
56 | 4096, | |
57 | ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, | |
58 | MapFlags::MAP_SHARED | MapFlags::MAP_NORESERVE | MapFlags::MAP_POPULATE, | |
59 | )? | |
60 | }; | |
835d0e5d | 61 | |
fda19dcc DM |
62 | Ok(Arc::new(Self { mmap })) |
63 | } | |
64 | ||
65 | // Shortcut to get the mapped `Head` as a `Head`. | |
835d0e5d | 66 | fn head(&self) -> &Head { |
fda19dcc DM |
67 | unsafe { &*(self.mmap.as_ptr() as *const u8 as *const Head) } |
68 | } | |
69 | ||
70 | /// Returns the user cache generation number. | |
835d0e5d | 71 | pub fn user_cache_generation(&self) -> usize { |
fda19dcc DM |
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 | } |