all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Kefu Chai <k.chai@proxmox.com>
To: pve-devel@lists.proxmox.com
Cc: Kefu Chai <tchaikov@gmail.com>
Subject: [PATCH pve-cluster v3 01/13] pmxcfs-rs: add pmxcfs-api-types crate
Date: Mon, 23 Mar 2026 19:32:16 +0800	[thread overview]
Message-ID: <20260323113239.942866-2-k.chai@proxmox.com> (raw)
In-Reply-To: <20260323113239.942866-1-k.chai@proxmox.com>

Add pmxcfs-api-types crate which provides foundational shared types:
- PmxcfsError: Error type for startup/configuration errors
  (System and Configuration variants only)
- errno module: io::Error constructors (enoent, eexist, eacces, etc.)
- VmType: VM type enum (Qemu, Lxc)
- VmEntry: VM registry entry (vm_id, vm_type, node, version)
- MemberInfo: Corosync cluster member information
- NodeSyncInfo: Per-node DFSM state snapshot for cluster sync

Also adds workspace root files: Cargo.toml, Makefile, .gitignore,
rustfmt.toml.

All other crates depend on these shared type definitions.

Signed-off-by: Kefu Chai <k.chai@proxmox.com>
---
 src/pmxcfs-rs/.cargo/config.toml            |  8 ++
 src/pmxcfs-rs/.gitignore                    |  2 +
 src/pmxcfs-rs/Cargo.toml                    | 39 +++++++++
 src/pmxcfs-rs/Makefile                      | 39 +++++++++
 src/pmxcfs-rs/pmxcfs-api-types/Cargo.toml   | 19 ++++
 src/pmxcfs-rs/pmxcfs-api-types/README.md    | 17 ++++
 src/pmxcfs-rs/pmxcfs-api-types/src/errno.rs | 75 ++++++++++++++++
 src/pmxcfs-rs/pmxcfs-api-types/src/error.rs | 15 ++++
 src/pmxcfs-rs/pmxcfs-api-types/src/lib.rs   | 97 +++++++++++++++++++++
 src/pmxcfs-rs/rustfmt.toml                  |  1 +
 10 files changed, 312 insertions(+)
 create mode 100644 src/pmxcfs-rs/.cargo/config.toml
 create mode 100644 src/pmxcfs-rs/.gitignore
 create mode 100644 src/pmxcfs-rs/Cargo.toml
 create mode 100644 src/pmxcfs-rs/Makefile
 create mode 100644 src/pmxcfs-rs/pmxcfs-api-types/Cargo.toml
 create mode 100644 src/pmxcfs-rs/pmxcfs-api-types/README.md
 create mode 100644 src/pmxcfs-rs/pmxcfs-api-types/src/errno.rs
 create mode 100644 src/pmxcfs-rs/pmxcfs-api-types/src/error.rs
 create mode 100644 src/pmxcfs-rs/pmxcfs-api-types/src/lib.rs
 create mode 100644 src/pmxcfs-rs/rustfmt.toml

diff --git a/src/pmxcfs-rs/.cargo/config.toml b/src/pmxcfs-rs/.cargo/config.toml
new file mode 100644
index 000000000..a439c97b2
--- /dev/null
+++ b/src/pmxcfs-rs/.cargo/config.toml
@@ -0,0 +1,8 @@
+[source]
+[source.debian-packages]
+directory = "/usr/share/cargo/registry"
+[source.crates-io]
+replace-with = "debian-packages"
+
+[profile.release]
+debug=true
diff --git a/src/pmxcfs-rs/.gitignore b/src/pmxcfs-rs/.gitignore
new file mode 100644
index 000000000..1e7caa9ea
--- /dev/null
+++ b/src/pmxcfs-rs/.gitignore
@@ -0,0 +1,2 @@
+Cargo.lock
+target/
diff --git a/src/pmxcfs-rs/Cargo.toml b/src/pmxcfs-rs/Cargo.toml
new file mode 100644
index 000000000..da2b9440a
--- /dev/null
+++ b/src/pmxcfs-rs/Cargo.toml
@@ -0,0 +1,39 @@
+# Workspace root for pmxcfs Rust implementation
+[workspace]
+members = [
+    "pmxcfs-api-types",  # Shared types and error definitions
+]
+resolver = "2"
+
+[workspace.package]
+version = "9.0.6"
+edition = "2024"
+authors = ["Proxmox Support Team <support@proxmox.com>"]
+license = "AGPL-3.0"
+repository = "https://git.proxmox.com/?p=pve-cluster.git"
+rust-version = "1.85"
+
+[workspace.dependencies]
+# Internal workspace dependencies
+pmxcfs-api-types = { path = "pmxcfs-api-types" }
+
+# Error handling
+thiserror = "2.0"
+
+# System integration
+libc = "0.2"
+
+[workspace.lints.clippy]
+uninlined_format_args = "warn"
+
+[profile.release]
+lto = true
+codegen-units = 1
+opt-level = 3
+strip = true
+
+[profile.dev]
+opt-level = 1
+debug = true
+
+[patch.crates-io]
diff --git a/src/pmxcfs-rs/Makefile b/src/pmxcfs-rs/Makefile
new file mode 100644
index 000000000..eaa96317f
--- /dev/null
+++ b/src/pmxcfs-rs/Makefile
@@ -0,0 +1,39 @@
+.PHONY: all test lint clippy fmt check build clean help
+
+# Default target
+all: check build
+
+# Run all tests
+test:
+	cargo test --workspace
+
+# Lint with clippy (using proxmox-backup style: only fail on correctness issues)
+clippy:
+	cargo clippy --workspace -- -A clippy::all -D clippy::correctness
+
+# Check code formatting
+fmt:
+	cargo fmt --all --check
+
+# Full quality check (format + lint + test)
+check: fmt clippy test
+
+# Build release version
+build:
+	cargo build --workspace --release
+
+# Clean build artifacts
+clean:
+	cargo clean
+
+# Show available targets
+help:
+	@echo "Available targets:"
+	@echo "  all      - Run check and build (default)"
+	@echo "  test     - Run all tests"
+	@echo "  clippy   - Run clippy linter"
+	@echo "  fmt      - Check code formatting"
+	@echo "  check    - Run fmt + clippy + test"
+	@echo "  build    - Build release version"
+	@echo "  clean    - Clean build artifacts"
+	@echo "  help     - Show this help message"
diff --git a/src/pmxcfs-rs/pmxcfs-api-types/Cargo.toml b/src/pmxcfs-rs/pmxcfs-api-types/Cargo.toml
new file mode 100644
index 000000000..cdce7951a
--- /dev/null
+++ b/src/pmxcfs-rs/pmxcfs-api-types/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "pmxcfs-api-types"
+description = "Shared types and error definitions for pmxcfs"
+
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+repository.workspace = true
+
+[lints]
+workspace = true
+
+[dependencies]
+# Error handling
+thiserror.workspace = true
+
+# System integration
+libc.workspace = true
diff --git a/src/pmxcfs-rs/pmxcfs-api-types/README.md b/src/pmxcfs-rs/pmxcfs-api-types/README.md
new file mode 100644
index 000000000..d89902c22
--- /dev/null
+++ b/src/pmxcfs-rs/pmxcfs-api-types/README.md
@@ -0,0 +1,17 @@
+# pmxcfs-api-types
+
+This crate provides shared types used across all pmxcfs crates. Having
+them in a dedicated crate with no internal dependencies avoids circular
+dependencies between the higher-level crates.
+
+`VmType` does not include OpenVZ (historically `VMTYPE_OPENVZ = 2` in
+the C implementation); it was dropped in PVE 4.0 in favour of LXC.
+
+`PmxcfsError` covers startup and configuration errors only. FUSE-layer
+errno values are expressed as `std::io::Error` using the helpers in the
+`errno` submodule.
+
+## References
+
+- [`src/pmxcfs/status.h`](../pmxcfs/status.h) — `VMTYPE_*` constants, `CFS_MAX_STATUS_SIZE`
+- [`src/pmxcfs/dfsm.h`](../pmxcfs/dfsm.h) — `dfsm_node_info_t` (maps to `NodeSyncInfo`)
diff --git a/src/pmxcfs-rs/pmxcfs-api-types/src/errno.rs b/src/pmxcfs-rs/pmxcfs-api-types/src/errno.rs
new file mode 100644
index 000000000..7e735c111
--- /dev/null
+++ b/src/pmxcfs-rs/pmxcfs-api-types/src/errno.rs
@@ -0,0 +1,75 @@
+//! Convenience constructors for POSIX errno values as io::Error.
+//!
+//! Replaces the repeated `std::io::Error::from_raw_os_error(libc::ENOENT).into()`
+//! pattern in operational methods throughout the workspace.
+use std::io;
+
+/// ENOENT — No such file or directory
+#[must_use]
+#[inline]
+pub fn enoent() -> io::Error {
+    io::Error::from_raw_os_error(libc::ENOENT)
+}
+
+/// EEXIST — File already exists
+#[must_use]
+#[inline]
+pub fn eexist() -> io::Error {
+    io::Error::from_raw_os_error(libc::EEXIST)
+}
+
+/// EACCES — Permission denied
+#[must_use]
+#[inline]
+pub fn eacces() -> io::Error {
+    io::Error::from_raw_os_error(libc::EACCES)
+}
+
+/// ENOTEMPTY — Directory not empty
+#[must_use]
+#[inline]
+pub fn enotempty() -> io::Error {
+    io::Error::from_raw_os_error(libc::ENOTEMPTY)
+}
+
+/// EIO — Input/output error
+#[must_use]
+#[inline]
+pub fn eio() -> io::Error {
+    io::Error::from_raw_os_error(libc::EIO)
+}
+
+/// EISDIR — Is a directory
+#[must_use]
+#[inline]
+pub fn eisdir() -> io::Error {
+    io::Error::from_raw_os_error(libc::EISDIR)
+}
+
+/// EINVAL — Invalid argument
+#[must_use]
+#[inline]
+pub fn einval() -> io::Error {
+    io::Error::from_raw_os_error(libc::EINVAL)
+}
+
+/// EPERM — Operation not permitted
+#[must_use]
+#[inline]
+pub fn eperm() -> io::Error {
+    io::Error::from_raw_os_error(libc::EPERM)
+}
+
+/// EFBIG — File too large
+#[must_use]
+#[inline]
+pub fn efbig() -> io::Error {
+    io::Error::from_raw_os_error(libc::EFBIG)
+}
+
+/// Arbitrary errno value
+#[must_use]
+#[inline]
+pub fn os_err(errno: libc::c_int) -> io::Error {
+    io::Error::from_raw_os_error(errno)
+}
diff --git a/src/pmxcfs-rs/pmxcfs-api-types/src/error.rs b/src/pmxcfs-rs/pmxcfs-api-types/src/error.rs
new file mode 100644
index 000000000..1d3ec01f1
--- /dev/null
+++ b/src/pmxcfs-rs/pmxcfs-api-types/src/error.rs
@@ -0,0 +1,15 @@
+use thiserror::Error;
+
+/// Error types for pmxcfs operations
+///
+/// Only variants that are actively used in the codebase are defined here.
+/// Operational/FUSE errors use `std::io::Error` with errno helpers from
+/// `pmxcfs_api_types::errno` instead.
+#[derive(Error, Debug)]
+pub enum PmxcfsError {
+    #[error("Configuration error: {0}")]
+    Configuration(String),
+
+    #[error("System error: {0}")]
+    System(String),
+}
diff --git a/src/pmxcfs-rs/pmxcfs-api-types/src/lib.rs b/src/pmxcfs-rs/pmxcfs-api-types/src/lib.rs
new file mode 100644
index 000000000..76c2cea84
--- /dev/null
+++ b/src/pmxcfs-rs/pmxcfs-api-types/src/lib.rs
@@ -0,0 +1,97 @@
+mod error;
+
+pub mod errno;
+
+pub use error::PmxcfsError;
+
+/// Current unix timestamp in seconds, truncated to u32 to match C's `time_t` usage.
+pub fn unix_now_secs() -> u32 {
+    std::time::SystemTime::now()
+        .duration_since(std::time::UNIX_EPOCH)
+        .unwrap_or_default()
+        .as_secs() as u32
+}
+
+/// Maximum size for status data (matches C implementation)
+/// From status.h: #define CFS_MAX_STATUS_SIZE (32 * 1024)
+pub const CFS_MAX_STATUS_SIZE: usize = 32 * 1024;
+
+/// VM/CT types
+///
+/// Note: OpenVZ was historically supported (VMTYPE_OPENVZ = 2 in C implementation)
+/// but was removed in PVE 4.0 in favor of LXC. Only QEMU and LXC are currently supported.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum VmType {
+    Qemu,
+    Lxc,
+}
+
+impl VmType {
+    /// Returns the directory name where config files are stored
+    #[must_use]
+    #[inline]
+    pub fn config_dir(&self) -> &'static str {
+        match self {
+            Self::Qemu => "qemu-server",
+            Self::Lxc => "lxc",
+        }
+    }
+}
+
+impl std::fmt::Display for VmType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Qemu => write!(f, "qemu"),
+            Self::Lxc => write!(f, "lxc"),
+        }
+    }
+}
+
+impl TryFrom<u32> for VmType {
+    type Error = std::io::Error;
+
+    fn try_from(value: u32) -> std::io::Result<Self> {
+        match value {
+            1 => Ok(VmType::Qemu),
+            3 => Ok(VmType::Lxc),
+            _ => Err(std::io::Error::other(format!("unknown VM type: {value}"))),
+        }
+    }
+}
+
+/// VM/CT entry for vmlist
+#[derive(Debug, Clone)]
+pub struct VmEntry {
+    pub vm_id: u32,
+    pub vm_type: VmType,
+    pub node: String,
+    /// Per-VM version counter (increments when this VM's config changes)
+    pub version: u32,
+}
+
+/// Information about a cluster member
+///
+/// This is a shared type used by both cluster and DFSM modules
+#[derive(Debug, Clone)]
+pub struct MemberInfo {
+    pub node_id: u32,
+    pub pid: u32,
+    pub joined_at: u64,
+}
+
+/// Node synchronization info for DFSM state sync
+///
+/// Used during DFSM synchronization to track which nodes have provided state
+/// and whether synchronization has completed for that node.
+#[derive(Debug, Clone)]
+pub struct NodeSyncInfo {
+    pub node_id: u32,
+    pub pid: u32,
+    /// Serialized DFSM state snapshot for this node, exchanged during cluster synchronization.
+    /// Variable-size; `None` until this node's state has been received.
+    /// Maps to C's `dfsm_node_info_t.state + state_len` in `dfsm.h`.
+    pub state: Option<Vec<u8>>,
+    /// Whether this node has been marked as synchronized.
+    /// Set by the DFSM after `process_state_update` confirms the node is up to date.
+    pub synced: bool,
+}
diff --git a/src/pmxcfs-rs/rustfmt.toml b/src/pmxcfs-rs/rustfmt.toml
new file mode 100644
index 000000000..f216078d9
--- /dev/null
+++ b/src/pmxcfs-rs/rustfmt.toml
@@ -0,0 +1 @@
+edition = "2024"
-- 
2.47.3





  reply	other threads:[~2026-03-23 11:32 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-23 11:32 [PATCH pve-cluster v3 00/13] Rewrite pmxcfs with Rust Kefu Chai
2026-03-23 11:32 ` Kefu Chai [this message]
2026-03-23 11:32 ` [PATCH pve-cluster v3 02/13] pmxcfs-rs: add pmxcfs-config crate Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 03/13] pmxcfs-rs: add pmxcfs-logger crate Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 04/13] pmxcfs-rs: add pmxcfs-rrd crate Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 05/13] pmxcfs-rs: add pmxcfs-memdb crate Kefu Chai
2026-03-23 11:32 ` SPAM: [PATCH pve-cluster v3 06/13] pmxcfs-rs: add pmxcfs-status and pmxcfs-test-utils crates Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 07/13] pmxcfs-rs: add pmxcfs-services crate Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 08/13] pmxcfs-rs: add pmxcfs-ipc crate Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 09/13] pmxcfs-rs: add pmxcfs-dfsm crate Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 10/13] pmxcfs-rs: vendor patched rust-corosync for CPG compatibility Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 11/13] pmxcfs-rs: add pmxcfs main daemon binary Kefu Chai
2026-03-23 11:32 ` [PATCH pve-cluster v3 13/13] pmxcfs-rs: add project documentation Kefu Chai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260323113239.942866-2-k.chai@proxmox.com \
    --to=k.chai@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    --cc=tchaikov@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal