Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package firecracker for openSUSE:Factory 
checked in at 2026-03-04 21:09:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/firecracker (Old)
 and      /work/SRC/openSUSE:Factory/.firecracker.new.561 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "firecracker"

Wed Mar  4 21:09:04 2026 rev:20 rq:1336277 version:1.14.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/firecracker/firecracker.changes  2026-01-22 
15:18:11.376256124 +0100
+++ /work/SRC/openSUSE:Factory/.firecracker.new.561/firecracker.changes 
2026-03-04 21:10:07.872631417 +0100
@@ -1,0 +2,13 @@
+Fri Feb 27 07:16:00 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 1.14.2:
+  * Fixed
+    - #5698: Fixed the possible ENXIO error which could occur
+      during file open operation if the underlying file is FIFO
+      without active readers already attached.
+    - #5705: Fixed a bug that caused Firecracker to corrupt the
+      memory files of differential snapshots for VMs with multiple
+      memory slots. This affected VMs using memory hot-plugging or
+      any x86 VMs with a memory size larger than 3GiB.
+
+-------------------------------------------------------------------
@@ -6 +19,3 @@
-    - #5631: Update binary copy process inside Jailer to disallow symlinks and 
hardlinks at the destination path and change ownership of the copied binary to 
the specified uid/gid.
+    - #5631: Update binary copy process inside Jailer to disallow
+      symlinks and hardlinks at the destination path and change
+      ownership of the copied binary to the specified uid/gid.

Old:
----
  firecracker-1.14.1.obscpio

New:
----
  firecracker-1.14.2.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ firecracker.spec ++++++
--- /var/tmp/diff_new_pack.tLJGPM/_old  2026-03-04 21:10:08.896673741 +0100
+++ /var/tmp/diff_new_pack.tLJGPM/_new  2026-03-04 21:10:08.896673741 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           firecracker
-Version:        1.14.1
+Version:        1.14.2
 Release:        0
 Summary:        Virtual Machine Monitor for creating microVMs
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.tLJGPM/_old  2026-03-04 21:10:08.936675394 +0100
+++ /var/tmp/diff_new_pack.tLJGPM/_new  2026-03-04 21:10:08.952676055 +0100
@@ -2,7 +2,7 @@
   <service name="obs_scm" mode="manual">
     <param 
name="url">https://github.com/firecracker-microvm/firecracker.git</param>
     <param name="scm">git</param>
-    <param name="revision">v1.14.1</param>
+    <param name="revision">v1.14.2</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.tLJGPM/_old  2026-03-04 21:10:08.976677047 +0100
+++ /var/tmp/diff_new_pack.tLJGPM/_new  2026-03-04 21:10:08.976677047 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/firecracker-microvm/firecracker.git</param>
-              <param 
name="changesrevision">37593df439aeb19fc70b292e618770108e563e7e</param></service></servicedata>
+              <param 
name="changesrevision">26b4c55f14f02fbb7dd3353769e608fa90d22445</param></service></servicedata>
 (No newline at EOF)
 

++++++ firecracker-1.14.1.obscpio -> firecracker-1.14.2.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/CHANGELOG.md 
new/firecracker-1.14.2/CHANGELOG.md
--- old/firecracker-1.14.1/CHANGELOG.md 2026-01-19 13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/CHANGELOG.md 2026-02-26 18:19:34.000000000 +0100
@@ -6,6 +6,18 @@
 and this project adheres to
 [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [1.14.2]
+
+### Fixed
+
+- [#5698](https://github.com/firecracker-microvm/firecracker/pull/5698): Fixed
+  the possible ENXIO error which could occur during file open operation if the
+  underlying file is FIFO without active readers already attached.
+- [#5705](https://github.com/firecracker-microvm/firecracker/pull/5705): Fixed 
a
+  bug that caused Firecracker to corrupt the memory files of differential
+  snapshots for VMs with multiple memory slots. This affected VMs using memory
+  hot-plugging or any x86 VMs with a memory size larger than 3GiB.
+
 ## [1.14.1]
 
 ### Changed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/CREDITS.md 
new/firecracker-1.14.2/CREDITS.md
--- old/firecracker-1.14.1/CREDITS.md   2026-01-19 13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/CREDITS.md   2026-02-26 18:19:34.000000000 +0100
@@ -130,6 +130,7 @@
 - huang-jl <[email protected]>
 - Iggy Jackson <[email protected]>
 - ihciah <[email protected]>
+- Ilias Stamatis <[email protected]>
 - Ioana Chirca <[email protected]>
 - Ishwor Gurung <[email protected]>
 - Iulian Barbu <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/Cargo.lock 
new/firecracker-1.14.2/Cargo.lock
--- old/firecracker-1.14.1/Cargo.lock   2026-01-19 13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/Cargo.lock   2026-02-26 18:19:34.000000000 +0100
@@ -391,7 +391,7 @@
 
 [[package]]
 name = "cpu-template-helper"
-version = "1.14.1"
+version = "1.14.2"
 dependencies = [
  "clap",
  "displaydoc",
@@ -554,7 +554,7 @@
 
 [[package]]
 name = "firecracker"
-version = "1.14.1"
+version = "1.14.2"
 dependencies = [
  "cargo_toml",
  "displaydoc",
@@ -703,7 +703,7 @@
 
 [[package]]
 name = "jailer"
-version = "1.14.1"
+version = "1.14.2"
 dependencies = [
  "libc",
  "log-instrument",
@@ -1078,7 +1078,7 @@
 
 [[package]]
 name = "rebase-snap"
-version = "1.14.1"
+version = "1.14.2"
 dependencies = [
  "displaydoc",
  "libc",
@@ -1178,7 +1178,7 @@
 
 [[package]]
 name = "seccompiler"
-version = "1.14.1"
+version = "1.14.2"
 dependencies = [
  "bincode",
  "clap",
@@ -1275,7 +1275,7 @@
 
 [[package]]
 name = "snapshot-editor"
-version = "1.14.1"
+version = "1.14.2"
 dependencies = [
  "clap",
  "clap-num",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/docs/RELEASE_POLICY.md 
new/firecracker-1.14.2/docs/RELEASE_POLICY.md
--- old/firecracker-1.14.1/docs/RELEASE_POLICY.md       2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/docs/RELEASE_POLICY.md       2026-02-26 
18:19:34.000000000 +0100
@@ -90,8 +90,8 @@
 
 | Release | Release Date | Latest Patch | Min. end of support | Official end 
of Support         |
 | ------: | -----------: | -----------: | ------------------: | 
:------------------------------ |
-|   v1.14 |   2025-12-17 |      v1.14.0 |          2026-06-17 | Supported      
                 |
-|   v1.13 |   2025-08-28 |      v1.13.1 |          2026-02-28 | Supported      
                 |
+|   v1.14 |   2025-12-17 |      v1.14.2 |          2026-06-17 | Supported      
                 |
+|   v1.13 |   2025-08-28 |      v1.13.2 |          2026-02-28 | Supported      
                 |
 |   v1.12 |   2025-05-07 |      v1.12.1 |          2025-11-07 | 2025-12-17 
(v1.14 released)     |
 |   v1.11 |   2025-03-18 |      v1.11.0 |          2025-09-18 | 2025-09-18 
(end of 6mo support) |
 |   v1.10 |   2024-11-07 |      v1.10.1 |          2025-05-07 | 2025-05-07 
(v1.12 released)     |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.14.1/src/cpu-template-helper/Cargo.toml 
new/firecracker-1.14.2/src/cpu-template-helper/Cargo.toml
--- old/firecracker-1.14.1/src/cpu-template-helper/Cargo.toml   2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/cpu-template-helper/Cargo.toml   2026-02-26 
18:19:34.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "cpu-template-helper"
-version = "1.14.1"
+version = "1.14.2"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 license = "Apache-2.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/firecracker/Cargo.toml 
new/firecracker-1.14.2/src/firecracker/Cargo.toml
--- old/firecracker-1.14.1/src/firecracker/Cargo.toml   2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/firecracker/Cargo.toml   2026-02-26 
18:19:34.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "firecracker"
-version = "1.14.1"
+version = "1.14.2"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 build = "build.rs"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.14.1/src/firecracker/swagger/firecracker.yaml 
new/firecracker-1.14.2/src/firecracker/swagger/firecracker.yaml
--- old/firecracker-1.14.1/src/firecracker/swagger/firecracker.yaml     
2026-01-19 13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/firecracker/swagger/firecracker.yaml     
2026-02-26 18:19:34.000000000 +0100
@@ -5,7 +5,7 @@
     The API is accessible through HTTP calls on specific URLs
     carrying JSON modeled data.
     The transport medium is a Unix Domain Socket.
-  version: 1.14.1
+  version: 1.14.2
   termsOfService: ""
   contact:
     email: "[email protected]"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/jailer/Cargo.toml 
new/firecracker-1.14.2/src/jailer/Cargo.toml
--- old/firecracker-1.14.1/src/jailer/Cargo.toml        2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/jailer/Cargo.toml        2026-02-26 
18:19:34.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "jailer"
-version = "1.14.1"
+version = "1.14.2"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 description = "Process for starting Firecracker in production scenarios; 
applies a cgroup/namespace isolation barrier and then drops privileges."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/rebase-snap/Cargo.toml 
new/firecracker-1.14.2/src/rebase-snap/Cargo.toml
--- old/firecracker-1.14.1/src/rebase-snap/Cargo.toml   2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/rebase-snap/Cargo.toml   2026-02-26 
18:19:34.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "rebase-snap"
-version = "1.14.1"
+version = "1.14.2"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 license = "Apache-2.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/seccompiler/Cargo.toml 
new/firecracker-1.14.2/src/seccompiler/Cargo.toml
--- old/firecracker-1.14.1/src/seccompiler/Cargo.toml   2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/seccompiler/Cargo.toml   2026-02-26 
18:19:34.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "seccompiler"
-version = "1.14.1"
+version = "1.14.2"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 description = "Program that compiles multi-threaded seccomp-bpf filters 
expressed as JSON into raw BPF programs, serializing them and outputting them 
to a file."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/snapshot-editor/Cargo.toml 
new/firecracker-1.14.2/src/snapshot-editor/Cargo.toml
--- old/firecracker-1.14.1/src/snapshot-editor/Cargo.toml       2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/snapshot-editor/Cargo.toml       2026-02-26 
18:19:34.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "snapshot-editor"
-version = "1.14.1"
+version = "1.14.2"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 license = "Apache-2.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/vmm/src/device_manager/mod.rs 
new/firecracker-1.14.2/src/vmm/src/device_manager/mod.rs
--- old/firecracker-1.14.1/src/vmm/src/device_manager/mod.rs    2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/vmm/src/device_manager/mod.rs    2026-02-26 
18:19:34.000000000 +0100
@@ -35,7 +35,7 @@
 use crate::devices::virtio::transport::mmio::{IrqTrigger, MmioTransport};
 use crate::resources::VmResources;
 use crate::snapshot::Persist;
-use crate::utils::open_file_write_nonblock;
+use crate::utils::open_file_nonblock;
 use crate::vstate::bus::BusError;
 use crate::vstate::memory::GuestMemoryMmap;
 use crate::{EmulateSerialInitError, EventManager, Vm};
@@ -125,7 +125,7 @@
         output: Option<&PathBuf>,
     ) -> Result<Arc<Mutex<SerialDevice>>, std::io::Error> {
         let (serial_in, serial_out) = match output {
-            Some(path) => (None, 
open_file_write_nonblock(path).map(SerialOut::File)?),
+            Some(path) => (None, 
open_file_nonblock(path).map(SerialOut::File)?),
             None => {
                 Self::set_stdout_nonblocking();
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/vmm/src/logger/logging.rs 
new/firecracker-1.14.2/src/vmm/src/logger/logging.rs
--- old/firecracker-1.14.1/src/vmm/src/logger/logging.rs        2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/vmm/src/logger/logging.rs        2026-02-26 
18:19:34.000000000 +0100
@@ -13,7 +13,7 @@
 use utils::time::LocalTime;
 
 use super::metrics::{IncMetric, METRICS};
-use crate::utils::open_file_write_nonblock;
+use crate::utils::open_file_nonblock;
 
 /// Default level filter for logger matching the swagger specification
 /// (`src/firecracker/swagger/firecracker.yaml`).
@@ -62,7 +62,7 @@
         );
 
         if let Some(log_path) = config.log_path {
-            let file = 
open_file_write_nonblock(&log_path).map_err(LoggerUpdateError)?;
+            let file = 
open_file_nonblock(&log_path).map_err(LoggerUpdateError)?;
 
             guard.target = Some(file);
         };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/vmm/src/utils/mod.rs 
new/firecracker-1.14.2/src/vmm/src/utils/mod.rs
--- old/firecracker-1.14.1/src/vmm/src/utils/mod.rs     2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/vmm/src/utils/mod.rs     2026-02-26 
18:19:34.000000000 +0100
@@ -14,7 +14,6 @@
 use std::num::Wrapping;
 use std::os::unix::fs::OpenOptionsExt;
 use std::path::Path;
-use std::result::Result;
 
 use libc::O_NONBLOCK;
 
@@ -76,14 +75,16 @@
     addr & !(align - 1)
 }
 
-/// Create and open a File for writing to it.
-/// In case we open a FIFO, in order to not block the instance if nobody is 
consuming the message
-/// that is flushed to it, we are opening it with `O_NONBLOCK` flag.
-/// In this case, writing to a pipe will start failing when reaching 64K of 
unconsumed content.
-pub fn open_file_write_nonblock(path: &Path) -> Result<File, std::io::Error> {
+/// Create and open a file for both reading and writing to it with a 
O_NONBLOCK flag.
+/// In case we open a FIFO, we need all READ, WRITE and O_NONBLOCK in order to 
not block the process
+/// if nobody is consuming the message. Otherwise opening the FIFO with only 
WRITE and O_NONBLOCK
+/// will fail with ENXIO if there is no reader already attached to it.
+/// NOTE: writing to a pipe will start failing when reaching 64K of unconsumed 
content.
+pub fn open_file_nonblock(path: &Path) -> Result<File, std::io::Error> {
     OpenOptions::new()
         .custom_flags(O_NONBLOCK)
         .create(true)
+        .read(true)
         .write(true)
         .open(path)
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/vmm/src/vmm_config/metrics.rs 
new/firecracker-1.14.2/src/vmm/src/vmm_config/metrics.rs
--- old/firecracker-1.14.1/src/vmm/src/vmm_config/metrics.rs    2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/vmm/src/vmm_config/metrics.rs    2026-02-26 
18:19:34.000000000 +0100
@@ -7,7 +7,7 @@
 use serde::{Deserialize, Serialize};
 
 use crate::logger::{FcLineWriter, METRICS};
-use crate::utils::open_file_write_nonblock;
+use crate::utils::open_file_nonblock;
 
 /// Strongly typed structure used to describe the metrics system.
 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
@@ -26,7 +26,7 @@
 /// Configures the metrics as described in `metrics_cfg`.
 pub fn init_metrics(metrics_cfg: MetricsConfig) -> Result<(), 
MetricsConfigError> {
     let writer = FcLineWriter::new(
-        open_file_write_nonblock(&metrics_cfg.metrics_path)
+        open_file_nonblock(&metrics_cfg.metrics_path)
             .map_err(|err| 
MetricsConfigError::InitializationFailure(err.to_string()))?,
     );
     METRICS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/vmm/src/vstate/interrupts.rs 
new/firecracker-1.14.2/src/vmm/src/vstate/interrupts.rs
--- old/firecracker-1.14.1/src/vmm/src/vstate/interrupts.rs     2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/vmm/src/vstate/interrupts.rs     2026-02-26 
18:19:34.000000000 +0100
@@ -187,7 +187,7 @@
     fn restore(
         constructor_args: Self::ConstructorArgs,
         state: &Self::State,
-    ) -> std::result::Result<Self, Self::Error> {
+    ) -> Result<Self, Self::Error> {
         let mut vectors = Vec::with_capacity(state.len());
 
         for gsi in state {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/src/vmm/src/vstate/memory.rs 
new/firecracker-1.14.2/src/vmm/src/vstate/memory.rs
--- old/firecracker-1.14.1/src/vmm/src/vstate/memory.rs 2026-01-19 
13:55:20.000000000 +0100
+++ new/firecracker-1.14.2/src/vmm/src/vstate/memory.rs 2026-02-26 
18:19:34.000000000 +0100
@@ -59,6 +59,24 @@
     Unaligned,
     /// Error protecting memory slot: {0}
     Mprotect(std::io::Error),
+    /// Size too large for i64 conversion
+    SlotSizeTooLarge,
+    /// Dirty bitmap not found for memory slot {0}
+    DirtyBitmapNotFound(u32),
+    /// Dirty bitmap is larger than the slot size
+    DirtyBitmapTooLarge,
+    /// Dirty bitmap is smaller than the slot size
+    DirtyBitmapTooSmall,
+    /// Seek error: {0}
+    SeekError(std::io::Error),
+    /// Volatile memory error: {0}
+    VolatileMemoryError(vm_memory::VolatileMemoryError),
+}
+
+impl From<vm_memory::VolatileMemoryError> for MemoryError {
+    fn from(e: vm_memory::VolatileMemoryError) -> Self {
+        MemoryError::VolatileMemoryError(e)
+    }
 }
 
 /// Type of the guest region
@@ -121,25 +139,47 @@
         writer: &mut T,
         kvm_bitmap: &[u64],
         page_size: usize,
-    ) -> Result<(), GuestMemoryError> {
+    ) -> Result<(), MemoryError> {
         let firecracker_bitmap = self.slice.bitmap();
         let mut write_size = 0;
         let mut skip_size = 0;
         let mut dirty_batch_start = 0;
 
+        let expected_bitmap_array_len = (self.slice.len() / 
page_size).div_ceil(64);
+        if kvm_bitmap.len() > expected_bitmap_array_len {
+            return Err(MemoryError::DirtyBitmapTooLarge);
+        } else if kvm_bitmap.len() < expected_bitmap_array_len {
+            return Err(MemoryError::DirtyBitmapTooSmall);
+        }
+
         for (i, v) in kvm_bitmap.iter().enumerate() {
             for j in 0..64 {
                 let is_kvm_page_dirty = ((v >> j) & 1u64) != 0u64;
                 let page_offset = ((i * 64) + j) * page_size;
                 let is_firecracker_page_dirty = 
firecracker_bitmap.dirty_at(page_offset);
 
+                // We process 64 pages at a time, however the number of pages
+                // in the slot might not be a multiple of 64. We need to break
+                // once we go past the last page that is actually part of the
+                // region.
+                if page_offset >= self.slice.len() {
+                    // Ensure there are no more dirty bits after this point
+                    if (v >> j) != 0 {
+                        return Err(MemoryError::DirtyBitmapTooLarge);
+                    }
+                    break;
+                }
+
                 if is_kvm_page_dirty || is_firecracker_page_dirty {
                     // We are at the start of a new batch of dirty pages.
                     if skip_size > 0 {
                         // Seek forward over the unmodified pages.
+                        let offset = skip_size
+                            .try_into()
+                            .map_err(|_| MemoryError::SlotSizeTooLarge)?;
                         writer
-                            
.seek(SeekFrom::Current(skip_size.try_into().unwrap()))
-                            .unwrap();
+                            .seek(SeekFrom::Current(offset))
+                            .map_err(MemoryError::SeekError)?;
                         dirty_batch_start = page_offset;
                         skip_size = 0;
                     }
@@ -161,6 +201,14 @@
             writer.write_all_volatile(&self.slice.subslice(dirty_batch_start, 
write_size)?)?;
         }
 
+        // Advance the cursor even if the trailing pages are clean, so that the
+        // next slot starts writing at the correct offset.
+        if skip_size > 0 {
+            writer
+                .seek(SeekFrom::Current(skip_size.try_into().unwrap()))
+                .map_err(MemoryError::SeekError)?;
+        }
+
         Ok(())
     }
 
@@ -668,10 +716,15 @@
                 .flat_map(|region| region.slots())
                 .try_for_each(|(mem_slot, plugged)| {
                     if !plugged {
-                        let ilen = 
i64::try_from(mem_slot.slice.len()).unwrap();
-                        writer.seek(SeekFrom::Current(ilen)).unwrap();
+                        let ilen = i64::try_from(mem_slot.slice.len())
+                            .map_err(|_| MemoryError::SlotSizeTooLarge)?;
+                        writer
+                            .seek(SeekFrom::Current(ilen))
+                            .map_err(MemoryError::SeekError)?;
                     } else {
-                        let kvm_bitmap = 
dirty_bitmap.get(&mem_slot.slot).unwrap();
+                        let kvm_bitmap = dirty_bitmap
+                            .get(&mem_slot.slot)
+                            
.ok_or(MemoryError::DirtyBitmapNotFound(mem_slot.slot))?;
                         mem_slot.dump_dirty(writer, kvm_bitmap, page_size)?;
                     }
                     Ok(())
@@ -683,7 +736,7 @@
             self.reset_dirty();
         }
 
-        write_result.map_err(MemoryError::WriteMemory)
+        write_result
     }
 
     /// Resets all the memory region bitmaps
@@ -814,6 +867,7 @@
 
     use std::collections::HashMap;
     use std::io::{Read, Seek, Write};
+    use std::os::unix::fs::MetadataExt;
 
     use vmm_sys_util::tempfile::TempFile;
 
@@ -1123,17 +1177,23 @@
             .write(&second_region, region_2_address)
             .unwrap();
 
+        // Firecracker Dirty Bitmap after the writes:
+        // First region pages: [dirty, dirty]
+        // Second region pages: [dirty, dirty]
+
         let memory_state = guest_memory.describe();
 
-        // Dump only the dirty pages.
+        // KVM dirty bitmap:
         // First region pages: [dirty, clean]
         // Second region pages: [clean, dirty]
-        let mut dirty_bitmap: DirtyBitmap = HashMap::new();
-        dirty_bitmap.insert(0, vec![0b01]);
-        dirty_bitmap.insert(1, vec![0b10]);
+        let mut kvm_dirty_bitmap: DirtyBitmap = HashMap::new();
+        kvm_dirty_bitmap.insert(0, vec![0b01]);
+        kvm_dirty_bitmap.insert(1, vec![0b10]);
 
         let mut file = TempFile::new().unwrap().into_file();
-        guest_memory.dump_dirty(&mut file, &dirty_bitmap).unwrap();
+        guest_memory
+            .dump_dirty(&mut file, &kvm_dirty_bitmap)
+            .unwrap();
 
         // We can restore from this because this is the first dirty dump.
         let restored_guest_memory =
@@ -1158,18 +1218,25 @@
         let ones = vec![1u8; page_size];
         let twos = vec![2u8; page_size];
 
-        // Firecracker Bitmap
-        // First region pages: [dirty, clean]
+        // Firecracker Dirty Bitmap:
+        // First region pages: [clean, dirty]
         // Second region pages: [clean, clean]
         guest_memory
             .write(&twos, GuestAddress(page_size as u64))
             .unwrap();
+        // KVM dirty bitmap:
+        // First region pages: [dirty, clean]
+        // Second region pages: [clean, dirty]
+        kvm_dirty_bitmap.insert(0, vec![0b01]);
+        kvm_dirty_bitmap.insert(1, vec![0b10]);
 
-        guest_memory.dump_dirty(&mut reader, &dirty_bitmap).unwrap();
+        guest_memory
+            .dump_dirty(&mut reader, &kvm_dirty_bitmap)
+            .unwrap();
 
         // Check that only the dirty regions are dumped.
         let mut diff_file_content = Vec::new();
-        let expected_first_region = [
+        let expected_file_contents = [
             ones.as_slice(),
             twos.as_slice(),
             zeros.as_slice(),
@@ -1178,7 +1245,71 @@
         .concat();
         reader.seek(SeekFrom::Start(0)).unwrap();
         reader.read_to_end(&mut diff_file_content).unwrap();
-        assert_eq!(expected_first_region, diff_file_content);
+        assert_eq!(expected_file_contents, diff_file_content);
+
+        // Take a 3rd snapshot
+
+        // Firecracker Dirty Bitmap:
+        // First region pages: [dirty, clean]
+        // Second region pages: [dirty, clean]
+        guest_memory.write(&twos, region_1_address).unwrap();
+        guest_memory.write(&ones, region_2_address).unwrap();
+        // KVM dirty bitmap:
+        // First region pages: [clean, clean]
+        // Second region pages: [clean, clean]
+        kvm_dirty_bitmap.insert(0, vec![0b00]);
+        kvm_dirty_bitmap.insert(1, vec![0b00]);
+
+        let file = TempFile::new().unwrap();
+        let logical_size = page_size as u64 * 4;
+        file.as_file().set_len(logical_size).unwrap();
+
+        let mut reader = file.into_file();
+        guest_memory
+            .dump_dirty(&mut reader, &kvm_dirty_bitmap)
+            .unwrap();
+
+        // Check that only the dirty regions are dumped.
+        let mut diff_file_content = Vec::new();
+        // The resulting file is a sparse file with holes.
+        let expected_file_contents = [
+            twos.as_slice(),
+            zeros.as_slice(), // hole
+            ones.as_slice(),
+            zeros.as_slice(), // hole
+        ]
+        .concat();
+        reader.seek(SeekFrom::Start(0)).unwrap();
+        reader.read_to_end(&mut diff_file_content).unwrap();
+
+        assert_eq!(expected_file_contents, diff_file_content);
+
+        // Make sure that only 2 of the pages are written in the file and the
+        // other two are holes.
+        let metadata = reader.metadata().unwrap();
+        let physical_size = metadata.blocks() * 512;
+        assert_eq!(physical_size, 2 * page_size as u64);
+        assert_ne!(physical_size, logical_size);
+
+        // Test with bitmaps that are too large or too small
+        kvm_dirty_bitmap.insert(0, vec![0b1, 0b01]);
+        kvm_dirty_bitmap.insert(1, vec![0b10]);
+        assert!(matches!(
+            guest_memory.dump_dirty(&mut reader, &kvm_dirty_bitmap),
+            Err(MemoryError::DirtyBitmapTooLarge)
+        ));
+        kvm_dirty_bitmap.insert(0, vec![0b01]);
+        kvm_dirty_bitmap.insert(1, vec![0b110]);
+        assert!(matches!(
+            guest_memory.dump_dirty(&mut reader, &kvm_dirty_bitmap),
+            Err(MemoryError::DirtyBitmapTooLarge)
+        ));
+        kvm_dirty_bitmap.insert(0, vec![]);
+        kvm_dirty_bitmap.insert(1, vec![0b10]);
+        assert!(matches!(
+            guest_memory.dump_dirty(&mut reader, &kvm_dirty_bitmap),
+            Err(MemoryError::DirtyBitmapTooSmall)
+        ));
     }
 
     #[test]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.14.1/tests/integration_tests/functional/test_snapshot_basic.py
 
new/firecracker-1.14.2/tests/integration_tests/functional/test_snapshot_basic.py
--- 
old/firecracker-1.14.1/tests/integration_tests/functional/test_snapshot_basic.py
    2026-01-19 13:55:20.000000000 +0100
+++ 
new/firecracker-1.14.2/tests/integration_tests/functional/test_snapshot_basic.py
    2026-02-26 18:19:34.000000000 +0100
@@ -410,14 +410,15 @@
     # process would have been taken down.
 
 
-def test_diff_snapshot_overlay(uvm_plain_any, microvm_factory):
[email protected]("mem_size", [256, 4096])
+def test_diff_snapshot_overlay(uvm_plain_any, microvm_factory, mem_size):
     """
     Tests that if we take a diff snapshot and direct firecracker to write it on
     top of an existing snapshot file, it will successfully merge them.
     """
     basevm = uvm_plain_any
     basevm.spawn()
-    basevm.basic_config(track_dirty_pages=True)
+    basevm.basic_config(track_dirty_pages=True, mem_size_mib=mem_size)
     basevm.add_net_iface()
     basevm.start()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/tools/devtool 
new/firecracker-1.14.2/tools/devtool
--- old/firecracker-1.14.1/tools/devtool        2026-01-19 13:55:20.000000000 
+0100
+++ new/firecracker-1.14.2/tools/devtool        2026-02-26 18:19:34.000000000 
+0100
@@ -133,6 +133,9 @@
 # Container path to directory where we store built CI artifacts.
 CTR_CI_ARTIFACTS_PATH="${CTR_FC_ROOT_DIR}/resources/$(uname -m)"
 
+# Lockfile used while modifying KVM modules
+KVM_MODULE_LOCKFILE="/tmp/.kvm_module_lock"
+
 # Check if Docker is available and exit if it's not.
 # Upon returning from this call, the caller can be certain Docker is available.
 #
@@ -583,52 +586,127 @@
     fi
 }
 
-apply_linux_61_tweaks() {
-    KV=$(uname -r)
-    if [[ $KV != 6.1.* ]] || [ $(uname -m) != x86_64 ]; then
-        return
-    fi
-    say "Applying Linux 6.1 boot-time regression mitigations"
-
-    KVM_VENDOR_MOD=$(lsmod |grep -P "^kvm_(amd|intel)" | awk '{print $1}')
-    ITLB_MULTIHIT=/sys/devices/system/cpu/vulnerabilities/itlb_multihit
-    NX_HUGEPAGES=/sys/module/kvm/parameters/nx_huge_pages
-
-    # If m6a/m6i
-    if grep -q "Not affected" $ITLB_MULTIHIT; then
-        echo -e "CPU not vulnerable to iTLB multihit, using 
kvm.nx_huge_pages=never mitigation"
-        # we need a lock so another process is not running the same thing and 
to
-        # avoid race conditions.
-        lockfile="/tmp/.linux61_tweaks.lock"
-        set -C # noclobber
-        while true; do
-            if echo "$$" > "$lockfile"; then
-                echo "Successfully acquired lock"
-                if ! grep -q "never" $NX_HUGEPAGES; then
-                    echo "Reloading KVM modules with nx_huge_pages=never"
-                    sudo modprobe -r $KVM_VENDOR_MOD kvm
-                    sudo modprobe kvm nx_huge_pages=never
-                    sudo modprobe $KVM_VENDOR_MOD
-                fi
-                rm "$lockfile"
-                break
-            else
-                sleep 5s
-            fi
-        done
-        tail -v $ITLB_MULTIHIT $NX_HUGEPAGES
-    # else (m5d Skylake and CascadeLake)
+# Acquire the KVM module lock and run the given command.
+# Uses flock with a timeout for safe, automatic lock management.
+# Usage: with_kvm_module_lock <command> [args...]
+with_kvm_module_lock() {
+    local LOCK_TIMEOUT=120
+    (
+        if ! flock -w "$LOCK_TIMEOUT" 9; then
+            say_warn "Timed out waiting for KVM module lock after: 
${LOCK_TIMEOUT}s"
+            exit 1
+        fi
+        echo "Successfully acquired lock"
+        "$@"
+    ) 9>"$KVM_MODULE_LOCKFILE"
+}
+
+# Reload KVM modules with the given vendor module and kvm params.
+# Always enables avic=1 on AMD. Unloads first if already loaded.
+# Usage: reload_kvm_modules <vendor_mod> [kvm_param...]
+#   e.g. reload_kvm_modules kvm_intel nx_huge_pages=never
+reload_kvm_modules() {
+    local vendor_mod=$1; shift
+
+    # Unload if already loaded
+    if lsmod | grep -qP "^kvm_(amd|intel)"; then
+        if ! sudo modprobe -r $vendor_mod kvm; then
+            say_warn "Failed to unload KVM modules (${vendor_mod}, kvm) (may 
be in use)"
+            return 1
+        fi
+    fi
+
+    if ! sudo modprobe kvm "$@"; then
+        say_warn "Failed to load kvm module"
+        return 1
+    fi
+    if [[ $vendor_mod == "kvm_amd" ]]; then
+        if ! sudo modprobe kvm_amd avic=1; then
+            say_warn "Failed to load kvm_amd module"
+            return 1
+        fi
     else
-        echo "CPU vulnerable to iTLB_multihit, checking if favordynmods is 
enabled"
-        mount |grep cgroup |grep -q favordynmods
-        if [ $? -ne 0 ]; then
-            say_warn "cgroups' favordynmods option not enabled; VM creation 
performance may be impacted"
-        else
-            echo "favordynmods is enabled"
+        if ! sudo modprobe $vendor_mod; then
+            say_warn "Failed to load $vendor_mod module"
+            return 1
         fi
     fi
 }
 
+# Determine the KVM vendor module for the current CPU.
+kvm_vendor_mod() {
+    if grep -q "vmx" /proc/cpuinfo; then
+        echo kvm_intel
+    elif grep -q "svm" /proc/cpuinfo; then
+        echo kvm_amd
+    else
+        # aarch64
+        echo kvm
+    fi
+}
+
+# Ensure /dev/kvm is available and apply platform-specific KVM tweaks.
+# - Loads KVM modules if not present
+# - On Linux 6.1 x86_64: applies nx_huge_pages=never for non-vulnerable CPUs,
+#   checks favordynmods for vulnerable ones
+# - On AMD: ensures AVIC is enabled
+setup_kvm() {
+    local kernel_version=$(uname -r)
+    local arch=$(uname -m)
+    local vendor_mod=$(kvm_vendor_mod)
+
+    local need_kvm_reload=0
+    local kvm_extra_params=()
+
+    # Load KVM if not already available
+    if [[ ! -c /dev/kvm ]]; then
+        need_kvm_reload=1
+    fi
+
+    local itlb_multihit=/sys/devices/system/cpu/vulnerabilities/itlb_multihit
+    local nx_huge_pages=/sys/module/kvm/parameters/nx_huge_pages
+    # Linux 6.1 x86_64: mitigate boot-time regression
+    if [[ $kernel_version == 6.1.* ]] && [[ $arch == x86_64 ]]; then
+
+        say "Applying Linux 6.1 boot-time regression mitigations"
+        if grep -q "Not affected" $itlb_multihit; then
+            echo "CPU not vulnerable to iTLB multihit, using 
kvm.nx_huge_pages=never mitigation"
+            if ! grep -q "never" $nx_huge_pages 2>/dev/null; then
+                kvm_extra_params+=(nx_huge_pages=never)
+                need_kvm_reload=1
+            fi
+        else
+            echo "CPU vulnerable to iTLB_multihit, checking if favordynmods is 
enabled"
+            if mount | grep cgroup | grep -q favordynmods; then
+                echo "favordynmods is enabled"
+            else
+                say_warn "cgroups' favordynmods option not enabled; VM 
creation performance may be impacted"
+            fi
+        fi
+    fi
+
+    # AMD: ensure AVIC is enabled
+    local avic_param=/sys/module/kvm_amd/parameters/avic
+    if [[ $vendor_mod == "kvm_amd" ]]; then
+        if ! grep -q "Y\|1" $avic_param; then
+            echo "AVIC not enabled, will reload kvm_amd with avic=1"
+            need_kvm_reload=1
+        fi
+    fi
+
+    if [[ $need_kvm_reload -eq 1 ]]; then
+        echo "Reloading KVM modules"
+        reload_kvm_modules "$vendor_mod" "${kvm_extra_params[@]}"
+        ok_or_die "Could not reload kvm modules"
+    fi
+
+    tail -v $itlb_multihit $nx_huge_pages
+    if [[ $vendor_mod == "kvm_amd" ]]; then
+        tail -v $avic_param
+    fi
+
+    [[ -c /dev/kvm ]] || die "/dev/kvm not found. Aborting."
+}
 
 # Modifies the processors CPU governor and P-state configuration (x86_64 only) 
for consistent performance. This means
 # - Disable turbo boost (Intel only) by writing 1 to 
/sys/devices/system/cpu/intel_pstate/no_turbo
@@ -722,7 +800,7 @@
     done
 
     # Check prerequisites.
-    [ $do_kvm_check != 0 ] && ensure_kvm
+    [ $do_kvm_check != 0 ] && with_kvm_module_lock setup_kvm
     ensure_devctr
     ensure_build_dir
     ensure_ci_artifacts
@@ -734,8 +812,6 @@
       fi
     fi
 
-    apply_linux_61_tweaks
-
     # If we got to here, we've got all we need to continue.
     say "Kernel version: $(uname -r)"
     say "$(sed '/^processor.*: 0$/,/^processor.*: 1$/!d; /^processor.*: 1$/d' 
/proc/cpuinfo)"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.14.1/tools/functions 
new/firecracker-1.14.2/tools/functions
--- old/firecracker-1.14.1/tools/functions      2026-01-19 13:55:20.000000000 
+0100
+++ new/firecracker-1.14.2/tools/functions      2026-02-26 18:19:34.000000000 
+0100
@@ -125,15 +125,3 @@
         die "Invalid version number: $version. Version should not contain 
\`wip\` or \`dirty\`."
     fi
 }
-
-#########################
-# Firecracker functions #
-#########################
-
-# Check if /dev/kvm exists. Exit if it doesn't.
-# Upon returning from this call, the caller can be certain /dev/kvm is
-# available.
-#
-ensure_kvm() {
-    [[ -c /dev/kvm ]] || die "/dev/kvm not found. Aborting."
-}

++++++ firecracker.obsinfo ++++++
--- /var/tmp/diff_new_pack.tLJGPM/_old  2026-03-04 21:10:10.948758551 +0100
+++ /var/tmp/diff_new_pack.tLJGPM/_new  2026-03-04 21:10:10.960759047 +0100
@@ -1,5 +1,5 @@
 name: firecracker
-version: 1.14.1
-mtime: 1768827320
-commit: 37593df439aeb19fc70b292e618770108e563e7e
+version: 1.14.2
+mtime: 1772126374
+commit: 26b4c55f14f02fbb7dd3353769e608fa90d22445
 

++++++ vendor.tar.xz ++++++
/work/SRC/openSUSE:Factory/firecracker/vendor.tar.xz 
/work/SRC/openSUSE:Factory/.firecracker.new.561/vendor.tar.xz differ: char 15, 
line 1

Reply via email to