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-07-07 21:03:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/firecracker (Old)
 and      /work/SRC/openSUSE:Factory/.firecracker.new.1982 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "firecracker"

Tue Jul  7 21:03:59 2026 rev:24 rq:1364175 version:1.16.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/firecracker/firecracker.changes  2026-06-23 
17:44:24.317701823 +0200
+++ /work/SRC/openSUSE:Factory/.firecracker.new.1982/firecracker.changes        
2026-07-07 21:06:41.497522844 +0200
@@ -1,0 +2,15 @@
+Fri Jul 03 10:35:14 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 1.16.1:
+  * Fixed
+    - #5959: Reverted the use of O_NOFOLLOW for the jailer's cgroup
+      and network namespace file operations, so symlinks are again
+      allowed in these paths.
+    - #5958: Fixed a bug that caused vsock guest-to-host
+      connections to time out after snapshot restore, triggered by
+      taking a snapshot with a TX descriptor in-flight. On restore
+      the device now replays the TX queue notification so in-flight
+      TX descriptors are re-processed and notification suppression
+      is re-armed.
+
+-------------------------------------------------------------------

Old:
----
  firecracker-1.16.0.obscpio

New:
----
  firecracker-1.16.1.obscpio

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

Other differences:
------------------
++++++ firecracker.spec ++++++
--- /var/tmp/diff_new_pack.ck37OG/_old  2026-07-07 21:06:43.393589216 +0200
+++ /var/tmp/diff_new_pack.ck37OG/_new  2026-07-07 21:06:43.397589355 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           firecracker
-Version:        1.16.0
+Version:        1.16.1
 Release:        0
 Summary:        Virtual Machine Monitor for creating microVMs
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.ck37OG/_old  2026-07-07 21:06:43.453591316 +0200
+++ /var/tmp/diff_new_pack.ck37OG/_new  2026-07-07 21:06:43.457591456 +0200
@@ -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.16.0</param>
+    <param name="revision">refs/tags/v1.16.1</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.ck37OG/_old  2026-07-07 21:06:43.493592716 +0200
+++ /var/tmp/diff_new_pack.ck37OG/_new  2026-07-07 21:06:43.501592996 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/firecracker-microvm/firecracker.git</param>
-              <param 
name="changesrevision">d83d72b710361a10294480131377b1b00b163af8</param></service></servicedata>
+              <param 
name="changesrevision">2038188f145fb81b8d098147a10e9d9f392fd22f</param></service></servicedata>
 (No newline at EOF)
 

++++++ firecracker-1.16.0.obscpio -> firecracker-1.16.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/.buildkite/common.py 
new/firecracker-1.16.1/.buildkite/common.py
--- old/firecracker-1.16.0/.buildkite/common.py 2026-06-03 17:36:09.000000000 
+0200
+++ new/firecracker-1.16.1/.buildkite/common.py 2026-06-29 11:33:24.000000000 
+0200
@@ -205,6 +205,13 @@
     default=1,
     type=int,
 )
+COMMON_PARSER.add_argument(
+    "--max-jobs",
+    help="Max leaf jobs per pipeline chunk. If set, to_json() returns a JSON 
array of pipelines.",
+    required=False,
+    default=None,
+    type=int,
+)
 
 
 def random_str(k: int):
@@ -379,13 +386,61 @@
                 )
         return self.add_step(grp, depends_on_build=depends_on_build)
 
+    def _chunk_steps(self, max_jobs: int):
+        """Split steps into chunks of at most max_jobs leaf jobs each.
+
+        Groups that exceed the remaining space are split to fill each chunk.
+        """
+        chunks = []
+        current_chunk = []
+        current_count = 0
+
+        for step in self.steps:
+            if isinstance(step, dict) and "group" in step:
+                remaining_steps = step["steps"]
+                while remaining_steps:
+                    # -1 to reserve a slot for the group step itself
+                    available = max_jobs - current_count - 1
+                    if available <= 0:
+                        chunks.append(current_chunk)
+                        current_chunk = []
+                        current_count = 0
+                        available = max_jobs - 1
+                    take = remaining_steps[:available]
+                    remaining_steps = remaining_steps[available:]
+                    current_chunk.append({**step, "steps": take})
+                    # +1 for the group step itself
+                    current_count += len(take) + 1
+            else:
+                if current_chunk and current_count + 1 > max_jobs:
+                    chunks.append(current_chunk)
+                    current_chunk = []
+                    current_count = 0
+                current_chunk.append(step)
+                current_count += 1
+
+        if current_chunk:
+            chunks.append(current_chunk)
+        return chunks
+
     def to_dict(self):
         """Render the pipeline as a dictionary."""
         return {"steps": self.steps}
 
     def to_json(self):
-        """Serialize the pipeline to JSON"""
-        return json.dumps(self.to_dict(), indent=4, sort_keys=True, 
ensure_ascii=False)
+        """Serialize the pipeline to JSON.
+
+        If --max-jobs is set, returns a JSON array of pipeline objects,
+        each with at most max_jobs leaf jobs. Otherwise, returns a single
+        pipeline object (legacy behavior).
+        """
+        max_jobs = self.args.max_jobs
+        if max_jobs is None:
+            to_serialize = self.to_dict()
+        else:
+            chunks = self._chunk_steps(max_jobs)
+            to_serialize = [{"steps": chunk} for chunk in chunks]
+        return json.dumps(to_serialize, indent=4, sort_keys=True, 
ensure_ascii=False)
 
     def devtool_download_artifacts(self, artifacts):
         """Generate a `devtool download_ci_artifacts` command"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/.buildkite/pipeline_upload.sh 
new/firecracker-1.16.1/.buildkite/pipeline_upload.sh
--- old/firecracker-1.16.0/.buildkite/pipeline_upload.sh        1970-01-01 
01:00:00.000000000 +0100
+++ new/firecracker-1.16.1/.buildkite/pipeline_upload.sh        2026-06-29 
11:33:24.000000000 +0200
@@ -0,0 +1,22 @@
+#!/bin/bash
+# Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: Apache-2.0
+
+# Proxy script that handles chunked pipeline upload.
+# Usage: .buildkite/pipeline_pr.py --max-jobs 500 | 
.buildkite/pipeline_upload.sh
+#
+# If the input is a JSON array (chunked), uploads each element separately.
+# If it's a single object, uploads it directly (backwards compatible).
+
+set -euo pipefail
+
+pipeline_json=$(cat)
+
+if echo "$pipeline_json" | jq -e 'type == "array"' > /dev/null 2>&1; then
+    count=$(echo "$pipeline_json" | jq 'length')
+    for ((i = 0; i < count; i++)); do
+        echo "$pipeline_json" | jq ".[$i]" | buildkite-agent pipeline upload
+    done
+else
+    echo "$pipeline_json" | buildkite-agent pipeline upload
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/CHANGELOG.md 
new/firecracker-1.16.1/CHANGELOG.md
--- old/firecracker-1.16.0/CHANGELOG.md 2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/CHANGELOG.md 2026-06-29 11:33:24.000000000 +0200
@@ -6,6 +6,19 @@
 and this project adheres to
 [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [1.16.1]
+
+### Fixed
+
+- [#5959](https://github.com/firecracker-microvm/firecracker/pull/5959):
+  Reverted the use of `O_NOFOLLOW` for the jailer's cgroup and network 
namespace
+  file operations, so symlinks are again allowed in these paths.
+- [#5958](https://github.com/firecracker-microvm/firecracker/pull/5958): Fixed 
a
+  bug that caused vsock guest-to-host connections to time out after snapshot
+  restore, triggered by taking a snapshot with a TX descriptor in-flight. On
+  restore the device now replays the TX queue notification so in-flight TX
+  descriptors are re-processed and notification suppression is re-armed.
+
 ## [1.16.0]
 
 ### Added
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/CREDITS.md 
new/firecracker-1.16.1/CREDITS.md
--- old/firecracker-1.16.0/CREDITS.md   2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/CREDITS.md   2026-06-29 11:33:24.000000000 +0200
@@ -189,6 +189,7 @@
 - Manohar Castelino <[email protected]>
 - Marc Brooker <[email protected]>
 - Marco Cali <[email protected]>
+- Marco Marangoni <[email protected]>
 - Marco Vedovati <[email protected]>
 - Markus Ziller <[email protected]>
 - Masatoshi Higuchi <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/Cargo.lock 
new/firecracker-1.16.1/Cargo.lock
--- old/firecracker-1.16.0/Cargo.lock   2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/Cargo.lock   2026-06-29 11:33:24.000000000 +0200
@@ -400,7 +400,7 @@
 
 [[package]]
 name = "cpu-template-helper"
-version = "1.16.0"
+version = "1.16.1"
 dependencies = [
  "clap",
  "displaydoc",
@@ -576,7 +576,7 @@
 
 [[package]]
 name = "firecracker"
-version = "1.16.0"
+version = "1.16.1"
 dependencies = [
  "cargo_toml",
  "displaydoc",
@@ -791,7 +791,7 @@
 
 [[package]]
 name = "jailer"
-version = "1.16.0"
+version = "1.16.1"
 dependencies = [
  "libc",
  "log-instrument",
@@ -1188,7 +1188,7 @@
 
 [[package]]
 name = "rebase-snap"
-version = "1.16.0"
+version = "1.16.1"
 dependencies = [
  "displaydoc",
  "libc",
@@ -1272,7 +1272,7 @@
 
 [[package]]
 name = "seccompiler"
-version = "1.16.0"
+version = "1.16.1"
 dependencies = [
  "bitcode",
  "clap",
@@ -1360,7 +1360,7 @@
 
 [[package]]
 name = "snapshot-editor"
-version = "1.16.0"
+version = "1.16.1"
 dependencies = [
  "clap",
  "clap-num",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/cpu-template-helper/Cargo.toml 
new/firecracker-1.16.1/src/cpu-template-helper/Cargo.toml
--- old/firecracker-1.16.0/src/cpu-template-helper/Cargo.toml   2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/cpu-template-helper/Cargo.toml   2026-06-29 
11:33:24.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "cpu-template-helper"
-version = "1.16.0"
+version = "1.16.1"
 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.16.0/src/firecracker/Cargo.toml 
new/firecracker-1.16.1/src/firecracker/Cargo.toml
--- old/firecracker-1.16.0/src/firecracker/Cargo.toml   2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/firecracker/Cargo.toml   2026-06-29 
11:33:24.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "firecracker"
-version = "1.16.0"
+version = "1.16.1"
 authors = ["Amazon Firecracker team <[email protected]>"]
 edition = "2024"
 build = "build.rs"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/firecracker/swagger/firecracker.yaml 
new/firecracker-1.16.1/src/firecracker/swagger/firecracker.yaml
--- old/firecracker-1.16.0/src/firecracker/swagger/firecracker.yaml     
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/firecracker/swagger/firecracker.yaml     
2026-06-29 11:33:24.000000000 +0200
@@ -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.16.0
+  version: 1.16.1
   termsOfService: ""
   contact:
     email: "[email protected]"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/src/jailer/Cargo.toml 
new/firecracker-1.16.1/src/jailer/Cargo.toml
--- old/firecracker-1.16.0/src/jailer/Cargo.toml        2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/jailer/Cargo.toml        2026-06-29 
11:33:24.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "jailer"
-version = "1.16.0"
+version = "1.16.1"
 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.16.0/src/jailer/src/env.rs 
new/firecracker-1.16.1/src/jailer/src/env.rs
--- old/firecracker-1.16.0/src/jailer/src/env.rs        2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/jailer/src/env.rs        2026-06-29 
11:33:24.000000000 +0200
@@ -519,11 +519,8 @@
 
     fn join_netns(path: &str) -> Result<(), JailerError> {
         // The fd backing the file will be automatically dropped at the end of 
the scope
-        let netns = OpenOptions::new()
-            .read(true)
-            .custom_flags(libc::O_NOFOLLOW)
-            .open(path)
-            .map_err(|err| JailerError::FileOpen(PathBuf::from(path), err))?;
+        let netns =
+            File::open(path).map_err(|err| 
JailerError::FileOpen(PathBuf::from(path), err))?;
 
         // SAFETY: Safe because we are passing valid parameters.
         SyscallReturnCode(unsafe { libc::setns(netns.as_raw_fd(), 
libc::CLONE_NEWNET) })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/src/jailer/src/main.rs 
new/firecracker-1.16.1/src/jailer/src/main.rs
--- old/firecracker-1.16.0/src/jailer/src/main.rs       2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/jailer/src/main.rs       2026-06-29 
11:33:24.000000000 +0200
@@ -3,9 +3,6 @@
 
 use std::ffi::{CString, NulError, OsString};
 use std::fmt::{Debug, Display};
-use std::fs::OpenOptions;
-use std::io::Read;
-use std::os::unix::fs::OpenOptionsExt;
 use std::path::{Path, PathBuf};
 use std::{env as p_env, fs, io};
 
@@ -243,25 +240,12 @@
     T: AsRef<Path> + Debug,
     V: Display + Debug,
 {
-    let mut file = OpenOptions::new()
-        .write(true)
-        .create(true)
-        .truncate(true)
-        .custom_flags(libc::O_NOFOLLOW)
-        .open(file_path.as_ref())
-        .map_err(|err| JailerError::Write(PathBuf::from(file_path.as_ref()), 
err))?;
-    io::Write::write_all(&mut file, format!("{}\n", value).as_bytes())
+    fs::write(file_path, format!("{}\n", value))
         .map_err(|err| JailerError::Write(PathBuf::from(file_path.as_ref()), 
err))
 }
 
 pub fn readln_special<T: AsRef<Path> + Debug>(file_path: &T) -> Result<String, 
JailerError> {
-    let mut file = OpenOptions::new()
-        .read(true)
-        .custom_flags(libc::O_NOFOLLOW)
-        .open(file_path.as_ref())
-        .map_err(|err| 
JailerError::ReadToString(PathBuf::from(file_path.as_ref()), err))?;
-    let mut line = String::new();
-    file.read_to_string(&mut line)
+    let mut line = fs::read_to_string(file_path)
         .map_err(|err| 
JailerError::ReadToString(PathBuf::from(file_path.as_ref()), err))?;
 
     // Remove the newline character at the end (if any).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/src/rebase-snap/Cargo.toml 
new/firecracker-1.16.1/src/rebase-snap/Cargo.toml
--- old/firecracker-1.16.0/src/rebase-snap/Cargo.toml   2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/rebase-snap/Cargo.toml   2026-06-29 
11:33:24.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "rebase-snap"
-version = "1.16.0"
+version = "1.16.1"
 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.16.0/src/seccompiler/Cargo.toml 
new/firecracker-1.16.1/src/seccompiler/Cargo.toml
--- old/firecracker-1.16.0/src/seccompiler/Cargo.toml   2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/seccompiler/Cargo.toml   2026-06-29 
11:33:24.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "seccompiler"
-version = "1.16.0"
+version = "1.16.1"
 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.16.0/src/snapshot-editor/Cargo.toml 
new/firecracker-1.16.1/src/snapshot-editor/Cargo.toml
--- old/firecracker-1.16.0/src/snapshot-editor/Cargo.toml       2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/snapshot-editor/Cargo.toml       2026-06-29 
11:33:24.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "snapshot-editor"
-version = "1.16.0"
+version = "1.16.1"
 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.16.0/src/vmm/src/arch/x86_64/msr.rs 
new/firecracker-1.16.1/src/vmm/src/arch/x86_64/msr.rs
--- old/firecracker-1.16.0/src/vmm/src/arch/x86_64/msr.rs       2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/arch/x86_64/msr.rs       2026-06-29 
11:33:24.000000000 +0200
@@ -225,6 +225,9 @@
     MSR_RANGE!(MSR_MISC_FEATURES_ENABLES),
     MSR_RANGE!(MSR_K7_HWCR),
     MSR_RANGE!(MSR_IA32_TSX_CTRL),
+    // IA32_XSS controls which supervisor XSTATE components are enabled. 
Without it, the guest
+    // kernel's XRSTORS of process FPU state containing CET/PT supervisor 
components triggers #GP.
+    MSR_RANGE!(MSR_IA32_XSS),
     MSR_RANGE!(
         MSR_KVM_RANGE_START,
         MSR_KVM_RANGE_END - MSR_KVM_RANGE_START + 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/csm/connection.rs 
new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/csm/connection.rs
--- old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/csm/connection.rs   
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/csm/connection.rs   
2026-06-29 11:33:24.000000000 +0200
@@ -290,8 +290,9 @@
     /// using them to manage the internal connection state.
     ///
     /// Returns:
-    /// always `Ok(())`: the packet has been consumed;
-    fn send_pkt(&mut self, pkt: &VsockPacketTx) -> Result<(), VsockError> {
+    /// The packet is always consumed: host-side back-pressure is buffered and 
unrecoverable
+    /// stream errors terminate the connection.
+    fn send_pkt(&mut self, pkt: &VsockPacketTx) {
         // Update the peer credit information.
         self.peer_buf_alloc = pkt.hdr.buf_alloc();
         self.peer_fwd_cnt = Wrapping(pkt.hdr.fwd_cnt());
@@ -309,7 +310,7 @@
                         "vsock: dropping empty data packet from guest (lp={}, 
pp={}",
                         self.local_port, self.peer_port
                     );
-                    return Ok(());
+                    return;
                 }
 
                 // Unwrapping here is safe, since we just checked `pkt.buf()` 
above.
@@ -321,7 +322,7 @@
                         self.local_port, self.peer_port, err
                     );
                     self.kill();
-                    return Ok(());
+                    return;
                 }
 
                 // We might've just consumed some data. If that's the case, we 
might need to
@@ -394,8 +395,6 @@
                 );
             }
         };
-
-        Ok(())
     }
 
     /// Check if the connection has any pending packet addressed to the peer.
@@ -922,7 +921,7 @@
         }
 
         fn send(&mut self) {
-            self.conn.send_pkt(&self.tx_pkt).unwrap();
+            self.conn.send_pkt(&self.tx_pkt);
         }
 
         fn recv(&mut self) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/device.rs 
new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/device.rs
--- old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/device.rs   
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/device.rs   
2026-06-29 11:33:24.000000000 +0200
@@ -242,10 +242,7 @@
                 }
             };
 
-            if self.backend.send_pkt(&self.tx_packet).is_err() {
-                queue.undo_pop();
-                break;
-            }
+            self.backend.send_pkt(&self.tx_packet);
 
             have_used = true;
             queue.add_used(index, 0).unwrap_or_else(|err| {
@@ -406,21 +403,47 @@
     }
 
     fn kick(&mut self) {
-        // Vsock has complicated protocol that isn't resilient to any packet 
loss,
-        // so for Vsock we don't support connection persistence through 
snapshot.
-        // Any in-flight packets or events are simply lost.
-        // Vsock is restored 'empty'.
-        // The only reason we still `kick` it is to make guest process
-        // `TRANSPORT_RESET_EVENT` event we sent during snapshot creation.
         if self.is_activated() {
             self.pending_event_ack = true;
 
+            // Vsock has a complicated protocol that isn't resilient to any 
packet loss,
+            // so for Vsock we don't support connection persistence through 
snapshot. Any
+            // in-flight packets or events are simply lost and Vsock is 
restored 'empty'.
+            // We signal the event queue to make the guest process the
+            // `TRANSPORT_RESET_EVENT` event we sent during snapshot creation. 
(We signal
+            // it host->guest rather than writing its eventfd, which would 
invoke the
+            // guest's reset-ack path and clear `pending_event_ack` 
prematurely.)
             info!(
                 "[{:?}:{}] signaling event queue",
                 self.device_type(),
                 self.id()
             );
             self.signal_used_queue(EVQ_INDEX).unwrap();
+
+            // Replay the TX queue notification, like the default 
`VirtioDevice::kick`
+            // does for its data queues, so the device re-processes any TX 
descriptor
+            // that was in-flight at snapshot time and re-arms `avail_event`.
+            //
+            // Without this, `avail_idx` stays ahead of the `avail_event` we 
published.
+            // Under EVENT_IDX the guest only notifies us when `avail_idx` 
crosses
+            // `avail_event`; since it is already past, the guest considers 
itself to
+            // have notified us and stays silent, so we never process the 
queue and
+            // guest-to-host connections hang. RX needs no replay: it is gated 
by
+            // `pending_event_ack` until the guest acks the reset, and the 
host pulls
+            // from the backend rather than waiting on a guest RX notification.
+            info!(
+                "[{:?}:{}] notifying tx queue",
+                self.device_type(),
+                self.id()
+            );
+            if let Err(err) = self.queue_events[TXQ_INDEX].write(1) {
+                error!(
+                    "[{:?}:{}] error notifying tx queue: {}",
+                    self.device_type(),
+                    self.id(),
+                    err
+                );
+            }
         }
     }
 
@@ -619,6 +642,26 @@
     }
 
     #[test]
+    fn test_kick_replays_tx_notification_only() {
+        // On restore, kick() must replay only the TX data queue (to 
re-process in-flight
+        // TX and re-arm avail_event). RX is gated by pending_event_ack so it 
needs no
+        // replay, and the event queue's data eventfd must not be notified -- 
that is the
+        // guest's TRANSPORT_RESET ack path; the event queue is signaled 
host->guest.
+        let test_ctx = TestContext::new();
+        let mut ctx = test_ctx.create_event_handler_context();
+        ctx.mock_activate(test_ctx.mem.clone(), test_ctx.interrupt.clone());
+
+        ctx.device.kick();
+
+        // TX queue eventfd was replayed for re-processing.
+        assert_eq!(ctx.device.queue_events[TXQ_INDEX].read().unwrap(), 1);
+        // RX and the event queue's data eventfd must not be signaled by kick()
+        // (non-blocking read returns an error when the eventfd has no pending 
count).
+        ctx.device.queue_events[RXQ_INDEX].read().unwrap_err();
+        ctx.device.queue_events[EVQ_INDEX].read().unwrap_err();
+    }
+
+    #[test]
     fn test_prepare_save_emits_transport_reset_when_active() {
         // The snapshot path goes through prepare_save -> 
send_transport_reset_event.
         // Both the evq publication and the RX gate must be observable 
afterwards.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/event_handler.rs 
new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/event_handler.rs
--- old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/event_handler.rs    
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/event_handler.rs    
2026-06-29 11:33:24.000000000 +0200
@@ -123,11 +123,8 @@
     pub fn notify_backend(&mut self, evset: EventSet) -> Result<Vec<u16>, 
InvalidAvailIdx> {
         let mut used_queues = Vec::new();
         self.backend.notify(evset);
-        // After the backend has been kicked, it might've freed up some 
resources, so we
-        // can attempt to send it more data to process.
-        // In particular, if `self.backend.send_pkt()` halted the TX queue 
processing (by
-        // returning an error) at some point in the past, now is the time to 
try walking the
-        // TX queue again.
+        // After the backend has been kicked it may have freed up resources, 
so walk the TX
+        // queue again in case there are packets waiting to be forwarded to it.
         if self.process_tx()? {
             used_queues.push(TXQ_INDEX.try_into().unwrap());
         }
@@ -286,23 +283,6 @@
         }
 
         // Test case:
-        // - the driver has something to send (there's data in the TX queue); 
and
-        // - the backend errors out and cannot process the TX queue.
-        {
-            let test_ctx = TestContext::new();
-            let mut ctx = test_ctx.create_event_handler_context();
-            ctx.mock_activate(test_ctx.mem.clone(), 
test_ctx.interrupt.clone());
-
-            ctx.device.backend.set_pending_rx(false);
-            ctx.device.backend.set_tx_err(Some(VsockError::NoData));
-            ctx.signal_txq_event();
-
-            // Both RX and TX queues should be untouched.
-            assert_eq!(ctx.guest_txvq.used.idx.get(), 0);
-            assert_eq!(ctx.guest_rxvq.used.idx.get(), 0);
-        }
-
-        // Test case:
         // - the driver supplied a malformed TX buffer.
         {
             let test_ctx = TestContext::new();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/mod.rs 
new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/mod.rs
--- old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/mod.rs      
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/mod.rs      
2026-06-29 11:33:24.000000000 +0200
@@ -169,7 +169,11 @@
     fn recv_pkt(&mut self, pkt: &mut VsockPacketRx) -> Result<(), VsockError>;
 
     /// Write/send a packet through the channel.
-    fn send_pkt(&mut self, pkt: &VsockPacketTx) -> Result<(), VsockError>;
+    ///
+    /// The packet is always consumed (its virtio TX buffers can be returned 
to the guest):
+    /// host-side back-pressure is absorbed by buffering, and unrecoverable 
errors terminate
+    /// the offending connection rather than halting queue processing.
+    fn send_pkt(&mut self, pkt: &VsockPacketTx);
 
     /// Checks whether there is pending incoming data inside the channel, 
meaning that a subsequent
     /// call to `recv_pkt()` won't fail.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/test_utils.rs 
new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/test_utils.rs
--- old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/test_utils.rs       
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/test_utils.rs       
2026-06-29 11:33:24.000000000 +0200
@@ -27,7 +27,6 @@
 pub struct TestBackend {
     pub evfd: EventFd,
     pub rx_err: Option<VsockError>,
-    pub tx_err: Option<VsockError>,
     pub pending_rx: bool,
     pub rx_ok_cnt: usize,
     pub tx_ok_cnt: usize,
@@ -39,7 +38,6 @@
         Self {
             evfd: EventFd::new(libc::EFD_NONBLOCK).unwrap(),
             rx_err: None,
-            tx_err: None,
             pending_rx: false,
             rx_ok_cnt: 0,
             tx_ok_cnt: 0,
@@ -50,9 +48,6 @@
     pub fn set_rx_err(&mut self, err: Option<VsockError>) {
         self.rx_err = err;
     }
-    pub fn set_tx_err(&mut self, err: Option<VsockError>) {
-        self.tx_err = err;
-    }
     pub fn set_pending_rx(&mut self, prx: bool) {
         self.pending_rx = prx;
     }
@@ -84,14 +79,8 @@
         }
     }
 
-    fn send_pkt(&mut self, _pkt: &VsockPacketTx) -> Result<(), VsockError> {
-        match self.tx_err.take() {
-            None => {
-                self.tx_ok_cnt += 1;
-                Ok(())
-            }
-            Some(err) => Err(err),
-        }
+    fn send_pkt(&mut self, _pkt: &VsockPacketTx) {
+        self.tx_ok_cnt += 1;
     }
 
     fn has_pending_rx(&self) -> bool {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/unix/muxer.rs 
new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/unix/muxer.rs
--- old/firecracker-1.16.0/src/vmm/src/devices/virtio/vsock/unix/muxer.rs       
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/src/vmm/src/devices/virtio/vsock/unix/muxer.rs       
2026-06-29 11:33:24.000000000 +0200
@@ -193,10 +193,9 @@
     /// This absorbs unexpected packets, handles RSTs (by dropping 
connections), and forwards
     /// all the rest to their owning `MuxerConnection`.
     ///
-    /// Returns:
-    /// always `Ok(())` - the packet has been consumed, and its virtio TX 
buffers can be
-    /// returned to the guest vsock driver.
-    fn send_pkt(&mut self, pkt: &VsockPacketTx) -> Result<(), VsockError> {
+    /// The packet is always consumed, and its virtio TX buffers can be 
returned to the guest
+    /// vsock driver.
+    fn send_pkt(&mut self, pkt: &VsockPacketTx) {
         let conn_key = ConnMapKey {
             local_port: pkt.hdr.dst_port(),
             peer_port: pkt.hdr.src_port(),
@@ -212,7 +211,7 @@
         //
         if pkt.hdr.type_() != uapi::VSOCK_TYPE_STREAM {
             self.enq_rst(pkt.hdr.dst_port(), pkt.hdr.src_port());
-            return Ok(());
+            return;
         }
 
         // We don't know how to handle packets addressed to other CIDs. We 
only handle the host
@@ -222,7 +221,7 @@
                 "vsock: dropping guest packet for unknown CID: {:?}",
                 pkt.hdr
             );
-            return Ok(());
+            return;
         }
 
         if !self.conn_map.contains_key(&conn_key) {
@@ -236,7 +235,7 @@
                 // Send back an RST, to let the drive know we weren't 
expecting this packet.
                 self.enq_rst(pkt.hdr.dst_port(), pkt.hdr.src_port());
             }
-            return Ok(());
+            return;
         }
 
         // Right, we know where to send this packet, then (to `conn_key`).
@@ -244,16 +243,13 @@
         // there's no point in forwarding it the packet.
         if pkt.hdr.op() == uapi::VSOCK_OP_RST {
             self.remove_connection(conn_key);
-            return Ok(());
+            return;
         }
 
         // Alright, everything looks in order - forward this packet to its 
owning connection.
-        let mut res: Result<(), VsockError> = Ok(());
         self.apply_conn_mutation(conn_key, |conn| {
-            res = conn.send_pkt(pkt);
+            conn.send_pkt(pkt);
         });
-
-        res
     }
 
     /// Check if the muxer has any pending RX data, with which to fill a 
guest-provided RX
@@ -895,7 +891,7 @@
         }
 
         fn send(&mut self) {
-            self.muxer.send_pkt(&self.tx_pkt).unwrap();
+            self.muxer.send_pkt(&self.tx_pkt);
         }
 
         fn recv(&mut self) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/firecracker-1.16.0/tests/framework/utils_vsock.py 
new/firecracker-1.16.1/tests/framework/utils_vsock.py
--- old/firecracker-1.16.0/tests/framework/utils_vsock.py       2026-06-03 
17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/tests/framework/utils_vsock.py       2026-06-29 
11:33:24.000000000 +0200
@@ -6,7 +6,7 @@
 import os.path
 import re
 import time
-from contextlib import ExitStack
+from contextlib import ExitStack, contextmanager
 from pathlib import Path
 from socket import AF_UNIX, SOCK_STREAM, socket
 from subprocess import Popen
@@ -176,18 +176,18 @@
             assert wrk.hash == blob_hash
 
 
-def check_guest_connections(vm, server_port_path, blob_path, blob_hash):
-    """Test guest-initiated connections.
-
-    This will start an echo server on the host (in its own thread), then
-    start `TEST_CONNECTION_COUNT` workers inside the guest VM, all
-    communicating with the echo server.
+@contextmanager
+def host_echo_server(vm, server_port_path):
+    """Run a host-side echo server reachable by the guest over vsock.
+
+    Starts `socat` listening on the Unix socket `server_port_path`, links it
+    into the VM's jail so Firecracker can reach it, and raises the ssh
+    service's `pids.max` so guest workers can fork freely. Yields the socket
+    path and tears the server down on exit.
     """
-
     echo_server = Popen(
         ["socat", f"UNIX-LISTEN:{server_port_path},fork,backlog=5", 
"exec:'/bin/cat'"]
     )
-
     try:
         # Give socat a bit of time to create the socket
         for attempt in Retrying(
@@ -210,6 +210,23 @@
             f"echo 1024 > 
/sys/fs/cgroup/system.slice/{vm.distro.ssh_service}/pids.max"
         )
 
+        yield server_port_path
+    finally:
+        echo_server.terminate()
+        rc = echo_server.wait()
+        # socat exits with 128 + 15 (SIGTERM)
+        assert rc == 143
+
+
+def check_guest_connections(vm, server_port_path, blob_path, blob_hash):
+    """Test guest-initiated connections.
+
+    This will start an echo server on the host (in its own thread), then
+    start `TEST_CONNECTION_COUNT` workers inside the guest VM, all
+    communicating with the echo server.
+    """
+
+    with host_echo_server(vm, server_port_path):
         # Build the guest worker sub-command.
         # `vsock_helper` will read the blob file from STDIN and send the echo
         # server response to STDOUT. This response is then hashed, and the
@@ -234,11 +251,6 @@
         cmd += "for w in $workers; do wait $w || (wait; exit 1); done"
 
         vm.ssh.check_output(cmd)
-    finally:
-        echo_server.terminate()
-        rc = echo_server.wait()
-        # socat exits with 128 + 15 (SIGTERM)
-        assert rc == 143
 
 
 def make_host_port_path(uds_path, port):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/firecracker-1.16.0/tests/integration_tests/functional/test_vsock.py 
new/firecracker-1.16.1/tests/integration_tests/functional/test_vsock.py
--- old/firecracker-1.16.0/tests/integration_tests/functional/test_vsock.py     
2026-06-03 17:36:09.000000000 +0200
+++ new/firecracker-1.16.1/tests/integration_tests/functional/test_vsock.py     
2026-06-29 11:33:24.000000000 +0200
@@ -34,6 +34,7 @@
     check_guest_connections,
     check_host_connections,
     check_vsock_device,
+    host_echo_server,
     make_blob,
     make_host_port_path,
     start_guest_echo_server,
@@ -474,3 +475,48 @@
                 validate_fc_metrics(metrics)
         finally:
             vm.kill()
+
+
+def test_snapshot_restore_with_inflight_vsock_tx(
+    vsock_uvm, bin_vsock_path, tmp_path, microvm_factory
+):
+    """
+    Guest-initiated vsock connections must still work after a snapshot taken
+    while the guest is actively transmitting.
+
+    If a guest TX descriptor is un-consumed when the snapshot is created, the
+    restored TX queue has avail_idx ahead of avail_event; with EVENT_IDX the
+    guest then suppresses all TX notifications and guest-initiated connections
+    hang. Unlike test_cycled_snapshot_restore (which snapshots after traffic 
has
+    drained, so it only hits this by chance), this test snapshots while a guest
+    worker is streaming, making the in-flight condition reliable.
+    """
+    vm = vsock_uvm
+
+    vm_blob_path = "/tmp/vsock/test.blob"
+    blob_path, blob_hash = make_blob(tmp_path)
+    _copy_vsock_data_to_guest(vm.ssh, blob_path, vm_blob_path, bin_vsock_path)
+
+    server_port_path = os.path.join(
+        vm.path, make_host_port_path(VSOCK_UDS_PATH, ECHO_SERVER_PORT)
+    )
+    with host_echo_server(vm, server_port_path):
+        # Continuously stream guest->host so the TX queue is non-empty when the
+        # snapshot is taken.
+        vm.ssh.check_output(
+            "nohup sh -c 'while true; do "
+            f"cat {vm_blob_path} | /tmp/vsock_helper echo 2 {ECHO_SERVER_PORT} 
"
+            ">/dev/null 2>&1; done' >/dev/null 2>&1 &"
+        )
+        # Let the stream ramp up so traffic is genuinely in-flight.
+        time.sleep(2)
+        snapshot = vm.snapshot_full()
+    vm.kill()
+
+    # Restore and verify a *fresh* guest-initiated connection works -- this is
+    # what hangs when a TX descriptor was in-flight at snapshot time.
+    new_vm = microvm_factory.build_from_snapshot(snapshot)
+    path = os.path.join(
+        new_vm.path, make_host_port_path(VSOCK_UDS_PATH, ECHO_SERVER_PORT)
+    )
+    check_guest_connections(new_vm, path, vm_blob_path, blob_hash)

++++++ firecracker.obsinfo ++++++
--- /var/tmp/diff_new_pack.ck37OG/_old  2026-07-07 21:06:45.349657687 +0200
+++ /var/tmp/diff_new_pack.ck37OG/_new  2026-07-07 21:06:45.361658107 +0200
@@ -1,5 +1,5 @@
 name: firecracker
-version: 1.16.0
-mtime: 1780500969
-commit: d83d72b710361a10294480131377b1b00b163af8
+version: 1.16.1
+mtime: 1782725604
+commit: 2038188f145fb81b8d098147a10e9d9f392fd22f
 

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

Reply via email to